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