1 // SPDX-License-Identifier: GPL-2.0
4 * Verify that consecutive sends over packet tx_ring are mirrored
5 * with their original content intact.
10 #include <arpa/inet.h>
15 #include <linux/filter.h>
16 #include <linux/if_packet.h>
17 #include <net/ethernet.h>
19 #include <netinet/in.h>
20 #include <netinet/ip.h>
21 #include <netinet/udp.h>
25 #include <sys/ioctl.h>
27 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <sys/utsname.h>
38 const int eth_off
= TPACKET_HDRLEN
- sizeof(struct sockaddr_ll
);
39 const int cfg_frame_size
= 1000;
41 static void build_packet(void *buffer
, size_t blen
, char payload_char
)
48 memset(buffer
, 0, blen
);
51 eth
->h_proto
= htons(ETH_P_IP
);
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
);
66 udph
->dest
= htons(8000);
67 udph
->source
= htons(8001);
68 udph
->len
= htons(blen
- off
);
72 memset(buffer
+ off
, payload_char
, blen
- off
);
75 static int setup_rx(void)
79 fdr
= socket(PF_PACKET
, SOCK_RAW
, htons(ETH_P_IP
));
81 error(1, errno
, "socket r");
86 static int setup_tx(char **ring
)
88 struct sockaddr_ll laddr
= {};
89 struct tpacket_req req
= {};
92 fdt
= socket(PF_PACKET
, SOCK_RAW
, 0);
94 error(1, errno
, "socket t");
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");
102 if (bind(fdt
, (void *)&laddr
, sizeof(laddr
)))
103 error(1, errno
, "bind fdt");
105 req
.tp_block_size
= getpagesize();
107 req
.tp_frame_size
= getpagesize();
110 if (setsockopt(fdt
, SOL_PACKET
, PACKET_TX_RING
,
111 (void *)&req
, sizeof(req
)))
112 error(1, errno
, "setsockopt ring");
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");
122 static void send_pkt(int fdt
, void *slot
, char payload_char
)
124 struct tpacket_hdr
*header
= slot
;
127 while (header
->tp_status
!= TP_STATUS_AVAILABLE
)
130 build_packet(slot
+ eth_off
, cfg_frame_size
, payload_char
);
132 header
->tp_len
= cfg_frame_size
;
133 header
->tp_status
= TP_STATUS_SEND_REQUEST
;
135 ret
= sendto(fdt
, NULL
, 0, 0, NULL
, 0);
137 error(1, errno
, "kick tx");
140 static int read_verify_pkt(int fdr
, char payload_char
)
145 ret
= read(fdr
, buf
, sizeof(buf
));
146 if (ret
!= sizeof(buf
))
147 error(1, errno
, "read");
149 if (buf
[60] != payload_char
) {
150 printf("wrong pattern: 0x%x != 0x%x\n", buf
[60], payload_char
);
154 printf("read: %c (0x%x)\n", buf
[60], buf
[60]);
158 int main(int argc
, char **argv
)
160 const char payload_patterns
[] = "ab";
162 int fdr
, fdt
, ret
= 0;
165 fdt
= setup_tx(&ring
);
167 send_pkt(fdt
, ring
, payload_patterns
[0]);
168 send_pkt(fdt
, ring
, payload_patterns
[1]);
170 ret
|= read_verify_pkt(fdr
, payload_patterns
[0]);
171 ret
|= read_verify_pkt(fdr
, payload_patterns
[1]);
174 error(1, errno
, "close t");
176 error(1, errno
, "close r");