0001
0002
0003
0004
0005
0006
0007
0008 #define _GNU_SOURCE
0009
0010 #include <arpa/inet.h>
0011 #include <assert.h>
0012 #include <error.h>
0013 #include <errno.h>
0014 #include <fcntl.h>
0015 #include <linux/filter.h>
0016 #include <linux/if_packet.h>
0017 #include <net/ethernet.h>
0018 #include <net/if.h>
0019 #include <netinet/in.h>
0020 #include <netinet/ip.h>
0021 #include <netinet/udp.h>
0022 #include <poll.h>
0023 #include <pthread.h>
0024 #include <sched.h>
0025 #include <sys/ioctl.h>
0026 #include <sys/mman.h>
0027 #include <sys/socket.h>
0028 #include <sys/time.h>
0029 #include <sys/types.h>
0030 #include <sys/utsname.h>
0031 #include <stdbool.h>
0032 #include <stdint.h>
0033 #include <stdio.h>
0034 #include <stdlib.h>
0035 #include <string.h>
0036 #include <unistd.h>
0037
0038 const int eth_off = TPACKET_HDRLEN - sizeof(struct sockaddr_ll);
0039 const int cfg_frame_size = 1000;
0040
0041 static void build_packet(void *buffer, size_t blen, char payload_char)
0042 {
0043 struct udphdr *udph;
0044 struct ethhdr *eth;
0045 struct iphdr *iph;
0046 size_t off = 0;
0047
0048 memset(buffer, 0, blen);
0049
0050 eth = buffer;
0051 eth->h_proto = htons(ETH_P_IP);
0052
0053 off += sizeof(*eth);
0054 iph = buffer + off;
0055 iph->ttl = 8;
0056 iph->ihl = 5;
0057 iph->version = 4;
0058 iph->saddr = htonl(INADDR_LOOPBACK);
0059 iph->daddr = htonl(INADDR_LOOPBACK + 1);
0060 iph->protocol = IPPROTO_UDP;
0061 iph->tot_len = htons(blen - off);
0062 iph->check = 0;
0063
0064 off += sizeof(*iph);
0065 udph = buffer + off;
0066 udph->dest = htons(8000);
0067 udph->source = htons(8001);
0068 udph->len = htons(blen - off);
0069 udph->check = 0;
0070
0071 off += sizeof(*udph);
0072 memset(buffer + off, payload_char, blen - off);
0073 }
0074
0075 static int setup_rx(void)
0076 {
0077 int fdr;
0078
0079 fdr = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
0080 if (fdr == -1)
0081 error(1, errno, "socket r");
0082
0083 return fdr;
0084 }
0085
0086 static int setup_tx(char **ring)
0087 {
0088 struct sockaddr_ll laddr = {};
0089 struct tpacket_req req = {};
0090 int fdt;
0091
0092 fdt = socket(PF_PACKET, SOCK_RAW, 0);
0093 if (fdt == -1)
0094 error(1, errno, "socket t");
0095
0096 laddr.sll_family = AF_PACKET;
0097 laddr.sll_protocol = htons(0);
0098 laddr.sll_ifindex = if_nametoindex("lo");
0099 if (!laddr.sll_ifindex)
0100 error(1, errno, "if_nametoindex");
0101
0102 if (bind(fdt, (void *)&laddr, sizeof(laddr)))
0103 error(1, errno, "bind fdt");
0104
0105 req.tp_block_size = getpagesize();
0106 req.tp_block_nr = 1;
0107 req.tp_frame_size = getpagesize();
0108 req.tp_frame_nr = 1;
0109
0110 if (setsockopt(fdt, SOL_PACKET, PACKET_TX_RING,
0111 (void *)&req, sizeof(req)))
0112 error(1, errno, "setsockopt ring");
0113
0114 *ring = mmap(0, req.tp_block_size * req.tp_block_nr,
0115 PROT_READ | PROT_WRITE, MAP_SHARED, fdt, 0);
0116 if (*ring == MAP_FAILED)
0117 error(1, errno, "mmap");
0118
0119 return fdt;
0120 }
0121
0122 static void send_pkt(int fdt, void *slot, char payload_char)
0123 {
0124 struct tpacket_hdr *header = slot;
0125 int ret;
0126
0127 while (header->tp_status != TP_STATUS_AVAILABLE)
0128 usleep(1000);
0129
0130 build_packet(slot + eth_off, cfg_frame_size, payload_char);
0131
0132 header->tp_len = cfg_frame_size;
0133 header->tp_status = TP_STATUS_SEND_REQUEST;
0134
0135 ret = sendto(fdt, NULL, 0, 0, NULL, 0);
0136 if (ret == -1)
0137 error(1, errno, "kick tx");
0138 }
0139
0140 static int read_verify_pkt(int fdr, char payload_char)
0141 {
0142 char buf[100];
0143 int ret;
0144
0145 ret = read(fdr, buf, sizeof(buf));
0146 if (ret != sizeof(buf))
0147 error(1, errno, "read");
0148
0149 if (buf[60] != payload_char) {
0150 printf("wrong pattern: 0x%x != 0x%x\n", buf[60], payload_char);
0151 return 1;
0152 }
0153
0154 printf("read: %c (0x%x)\n", buf[60], buf[60]);
0155 return 0;
0156 }
0157
0158 int main(int argc, char **argv)
0159 {
0160 const char payload_patterns[] = "ab";
0161 char *ring;
0162 int fdr, fdt, ret = 0;
0163
0164 fdr = setup_rx();
0165 fdt = setup_tx(&ring);
0166
0167 send_pkt(fdt, ring, payload_patterns[0]);
0168 send_pkt(fdt, ring, payload_patterns[1]);
0169
0170 ret |= read_verify_pkt(fdr, payload_patterns[0]);
0171 ret |= read_verify_pkt(fdr, payload_patterns[1]);
0172
0173 if (close(fdt))
0174 error(1, errno, "close t");
0175 if (close(fdr))
0176 error(1, errno, "close r");
0177
0178 return ret;
0179 }