brintos

brintos / linux-shallow public Read only

0
0
Text · 3.7 KiB · 7d9ea03 Raw
180 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Verify that consecutive sends over packet tx_ring are mirrored5 * with their original content intact.6 */7 8#define _GNU_SOURCE9 10#include <arpa/inet.h>11#include <assert.h>12#include <error.h>13#include <errno.h>14#include <fcntl.h>15#include <linux/filter.h>16#include <linux/if_packet.h>17#include <net/ethernet.h>18#include <net/if.h>19#include <netinet/in.h>20#include <netinet/ip.h>21#include <netinet/udp.h>22#include <poll.h>23#include <pthread.h>24#include <sched.h>25#include <sys/ioctl.h>26#include <sys/mman.h>27#include <sys/socket.h>28#include <sys/time.h>29#include <sys/types.h>30#include <sys/utsname.h>31#include <stdbool.h>32#include <stdint.h>33#include <stdio.h>34#include <stdlib.h>35#include <string.h>36#include <unistd.h>37 38const int eth_off = TPACKET_HDRLEN - sizeof(struct sockaddr_ll);39const int cfg_frame_size = 1000;40 41static void build_packet(void *buffer, size_t blen, char payload_char)42{43	struct udphdr *udph;44	struct ethhdr *eth;45	struct iphdr *iph;46	size_t off = 0;47 48	memset(buffer, 0, blen);49 50	eth = buffer;51	eth->h_proto = htons(ETH_P_IP);52 53	off += sizeof(*eth);54	iph = buffer + off;55	iph->ttl	= 8;56	iph->ihl	= 5;57	iph->version	= 4;58	iph->saddr	= htonl(INADDR_LOOPBACK);59	iph->daddr	= htonl(INADDR_LOOPBACK + 1);60	iph->protocol	= IPPROTO_UDP;61	iph->tot_len	= htons(blen - off);62	iph->check	= 0;63 64	off += sizeof(*iph);65	udph = buffer + off;66	udph->dest	= htons(8000);67	udph->source	= htons(8001);68	udph->len	= htons(blen - off);69	udph->check	= 0;70 71	off += sizeof(*udph);72	memset(buffer + off, payload_char, blen - off);73}74 75static int setup_rx(void)76{77	int fdr;78 79	fdr = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));80	if (fdr == -1)81		error(1, errno, "socket r");82 83	return fdr;84}85 86static int setup_tx(char **ring)87{88	struct sockaddr_ll laddr = {};89	struct tpacket_req req = {};90	int fdt;91 92	fdt = socket(PF_PACKET, SOCK_RAW, 0);93	if (fdt == -1)94		error(1, errno, "socket t");95 96	laddr.sll_family = AF_PACKET;97	laddr.sll_protocol = htons(0);98	laddr.sll_ifindex = if_nametoindex("lo");99	if (!laddr.sll_ifindex)100		error(1, errno, "if_nametoindex");101 102	if (bind(fdt, (void *)&laddr, sizeof(laddr)))103		error(1, errno, "bind fdt");104 105	req.tp_block_size = getpagesize();106	req.tp_block_nr   = 1;107	req.tp_frame_size = getpagesize();108	req.tp_frame_nr   = 1;109 110	if (setsockopt(fdt, SOL_PACKET, PACKET_TX_RING,111		       (void *)&req, sizeof(req)))112		error(1, errno, "setsockopt ring");113 114	*ring = mmap(0, req.tp_block_size * req.tp_block_nr,115		     PROT_READ | PROT_WRITE, MAP_SHARED, fdt, 0);116	if (*ring == MAP_FAILED)117		error(1, errno, "mmap");118 119	return fdt;120}121 122static void send_pkt(int fdt, void *slot, char payload_char)123{124	struct tpacket_hdr *header = slot;125	int ret;126 127	while (header->tp_status != TP_STATUS_AVAILABLE)128		usleep(1000);129 130	build_packet(slot + eth_off, cfg_frame_size, payload_char);131 132	header->tp_len = cfg_frame_size;133	header->tp_status = TP_STATUS_SEND_REQUEST;134 135	ret = sendto(fdt, NULL, 0, 0, NULL, 0);136	if (ret == -1)137		error(1, errno, "kick tx");138}139 140static int read_verify_pkt(int fdr, char payload_char)141{142	char buf[100];143	int ret;144 145	ret = read(fdr, buf, sizeof(buf));146	if (ret != sizeof(buf))147		error(1, errno, "read");148 149	if (buf[60] != payload_char) {150		printf("wrong pattern: 0x%x != 0x%x\n", buf[60], payload_char);151		return 1;152	}153 154	printf("read: %c (0x%x)\n", buf[60], buf[60]);155	return 0;156}157 158int main(int argc, char **argv)159{160	const char payload_patterns[] = "ab";161	char *ring;162	int fdr, fdt, ret = 0;163 164	fdr = setup_rx();165	fdt = setup_tx(&ring);166 167	send_pkt(fdt, ring, payload_patterns[0]);168	send_pkt(fdt, ring, payload_patterns[1]);169 170	ret |= read_verify_pkt(fdr, payload_patterns[0]);171	ret |= read_verify_pkt(fdr, payload_patterns[1]);172 173	if (close(fdt))174		error(1, errno, "close t");175	if (close(fdr))176		error(1, errno, "close r");177 178	return ret;179}180