selftests: xsk: Introduce rx_on and tx_on in ifobject
[linux-2.6-microblaze.git] / tools / testing / selftests / bpf / xdpxceiver.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2020 Intel Corporation. */
3
4 /*
5  * Some functions in this program are taken from
6  * Linux kernel samples/bpf/xdpsock* and modified
7  * for use.
8  *
9  * See test_xsk.sh for detailed information on test topology
10  * and prerequisite network setup.
11  *
12  * This test program contains two threads, each thread is single socket with
13  * a unique UMEM. It validates in-order packet delivery and packet content
14  * by sending packets to each other.
15  *
16  * Tests Information:
17  * ------------------
18  * These selftests test AF_XDP SKB and Native/DRV modes using veth
19  * Virtual Ethernet interfaces.
20  *
21  * For each mode, the following tests are run:
22  *    a. nopoll - soft-irq processing
23  *    b. poll - using poll() syscall
24  *    c. Socket Teardown
25  *       Create a Tx and a Rx socket, Tx from one socket, Rx on another. Destroy
26  *       both sockets, then repeat multiple times. Only nopoll mode is used
27  *    d. Bi-directional sockets
28  *       Configure sockets as bi-directional tx/rx sockets, sets up fill and
29  *       completion rings on each socket, tx/rx in both directions. Only nopoll
30  *       mode is used
31  *    e. Statistics
32  *       Trigger some error conditions and ensure that the appropriate statistics
33  *       are incremented. Within this test, the following statistics are tested:
34  *       i.   rx dropped
35  *            Increase the UMEM frame headroom to a value which results in
36  *            insufficient space in the rx buffer for both the packet and the headroom.
37  *       ii.  tx invalid
38  *            Set the 'len' field of tx descriptors to an invalid value (umem frame
39  *            size + 1).
40  *       iii. rx ring full
41  *            Reduce the size of the RX ring to a fraction of the fill ring size.
42  *       iv.  fill queue empty
43  *            Do not populate the fill queue and then try to receive pkts.
44  *    f. bpf_link resource persistence
45  *       Configure sockets at indexes 0 and 1, run a traffic on queue ids 0,
46  *       then remove xsk sockets from queue 0 on both veth interfaces and
47  *       finally run a traffic on queues ids 1
48  *
49  * Total tests: 12
50  *
51  * Flow:
52  * -----
53  * - Single process spawns two threads: Tx and Rx
54  * - Each of these two threads attach to a veth interface within their assigned
55  *   namespaces
56  * - Each thread Creates one AF_XDP socket connected to a unique umem for each
57  *   veth interface
58  * - Tx thread Transmits 10k packets from veth<xxxx> to veth<yyyy>
59  * - Rx thread verifies if all 10k packets were received and delivered in-order,
60  *   and have the right content
61  *
62  * Enable/disable packet dump mode:
63  * --------------------------
64  * To enable L2 - L4 headers and payload dump of each packet on STDOUT, add
65  * parameter -D to params array in test_xsk.sh, i.e. params=("-S" "-D")
66  */
67
68 #define _GNU_SOURCE
69 #include <fcntl.h>
70 #include <errno.h>
71 #include <getopt.h>
72 #include <asm/barrier.h>
73 #include <linux/if_link.h>
74 #include <linux/if_ether.h>
75 #include <linux/ip.h>
76 #include <linux/udp.h>
77 #include <arpa/inet.h>
78 #include <net/if.h>
79 #include <locale.h>
80 #include <poll.h>
81 #include <pthread.h>
82 #include <signal.h>
83 #include <stdbool.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <stddef.h>
88 #include <sys/mman.h>
89 #include <sys/resource.h>
90 #include <sys/types.h>
91 #include <sys/queue.h>
92 #include <time.h>
93 #include <unistd.h>
94 #include <stdatomic.h>
95 #include <bpf/xsk.h>
96 #include "xdpxceiver.h"
97 #include "../kselftest.h"
98
99 static const char *MAC1 = "\x00\x0A\x56\x9E\xEE\x62";
100 static const char *MAC2 = "\x00\x0A\x56\x9E\xEE\x61";
101 static const char *IP1 = "192.168.100.162";
102 static const char *IP2 = "192.168.100.161";
103 static const u16 UDP_PORT1 = 2020;
104 static const u16 UDP_PORT2 = 2121;
105
106 static void __exit_with_error(int error, const char *file, const char *func, int line)
107 {
108         ksft_test_result_fail("[%s:%s:%i]: ERROR: %d/\"%s\"\n", file, func, line, error,
109                               strerror(error));
110         ksft_exit_xfail();
111 }
112
113 #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__)
114
115 #define print_ksft_result(test)\
116         (ksft_test_result_pass("PASS: %s %s\n", configured_mode ? "DRV" : "SKB", \
117                                (test)->name))
118
119 static void memset32_htonl(void *dest, u32 val, u32 size)
120 {
121         u32 *ptr = (u32 *)dest;
122         int i;
123
124         val = htonl(val);
125
126         for (i = 0; i < (size & (~0x3)); i += 4)
127                 ptr[i >> 2] = val;
128 }
129
130 /*
131  * Fold a partial checksum
132  * This function code has been taken from
133  * Linux kernel include/asm-generic/checksum.h
134  */
135 static __u16 csum_fold(__u32 csum)
136 {
137         u32 sum = (__force u32)csum;
138
139         sum = (sum & 0xffff) + (sum >> 16);
140         sum = (sum & 0xffff) + (sum >> 16);
141         return (__force __u16)~sum;
142 }
143
144 /*
145  * This function code has been taken from
146  * Linux kernel lib/checksum.c
147  */
148 static u32 from64to32(u64 x)
149 {
150         /* add up 32-bit and 32-bit for 32+c bit */
151         x = (x & 0xffffffff) + (x >> 32);
152         /* add up carry.. */
153         x = (x & 0xffffffff) + (x >> 32);
154         return (u32)x;
155 }
156
157 /*
158  * This function code has been taken from
159  * Linux kernel lib/checksum.c
160  */
161 static __u32 csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum)
162 {
163         unsigned long long s = (__force u32)sum;
164
165         s += (__force u32)saddr;
166         s += (__force u32)daddr;
167 #ifdef __BIG_ENDIAN__
168         s += proto + len;
169 #else
170         s += (proto + len) << 8;
171 #endif
172         return (__force __u32)from64to32(s);
173 }
174
175 /*
176  * This function has been taken from
177  * Linux kernel include/asm-generic/checksum.h
178  */
179 static __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum)
180 {
181         return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
182 }
183
184 static u16 udp_csum(u32 saddr, u32 daddr, u32 len, u8 proto, u16 *udp_pkt)
185 {
186         u32 csum = 0;
187         u32 cnt = 0;
188
189         /* udp hdr and data */
190         for (; cnt < len; cnt += 2)
191                 csum += udp_pkt[cnt >> 1];
192
193         return csum_tcpudp_magic(saddr, daddr, len, proto, csum);
194 }
195
196 static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr)
197 {
198         memcpy(eth_hdr->h_dest, ifobject->dst_mac, ETH_ALEN);
199         memcpy(eth_hdr->h_source, ifobject->src_mac, ETH_ALEN);
200         eth_hdr->h_proto = htons(ETH_P_IP);
201 }
202
203 static void gen_ip_hdr(struct ifobject *ifobject, struct iphdr *ip_hdr)
204 {
205         ip_hdr->version = IP_PKT_VER;
206         ip_hdr->ihl = 0x5;
207         ip_hdr->tos = IP_PKT_TOS;
208         ip_hdr->tot_len = htons(IP_PKT_SIZE);
209         ip_hdr->id = 0;
210         ip_hdr->frag_off = 0;
211         ip_hdr->ttl = IPDEFTTL;
212         ip_hdr->protocol = IPPROTO_UDP;
213         ip_hdr->saddr = ifobject->src_ip;
214         ip_hdr->daddr = ifobject->dst_ip;
215         ip_hdr->check = 0;
216 }
217
218 static void gen_udp_hdr(u32 payload, void *pkt, struct ifobject *ifobject,
219                         struct udphdr *udp_hdr)
220 {
221         udp_hdr->source = htons(ifobject->src_port);
222         udp_hdr->dest = htons(ifobject->dst_port);
223         udp_hdr->len = htons(UDP_PKT_SIZE);
224         memset32_htonl(pkt + PKT_HDR_SIZE, payload, UDP_PKT_DATA_SIZE);
225 }
226
227 static void gen_udp_csum(struct udphdr *udp_hdr, struct iphdr *ip_hdr)
228 {
229         udp_hdr->check = 0;
230         udp_hdr->check =
231             udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE, IPPROTO_UDP, (u16 *)udp_hdr);
232 }
233
234 static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size, int idx)
235 {
236         struct xsk_umem_config cfg = {
237                 .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
238                 .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
239                 .frame_size = umem->frame_size,
240                 .frame_headroom = umem->frame_headroom,
241                 .flags = XSK_UMEM__DEFAULT_FLAGS
242         };
243         int ret;
244
245         ret = xsk_umem__create(&umem->umem, buffer, size,
246                                &umem->fq, &umem->cq, &cfg);
247         if (ret)
248                 return ret;
249
250         umem->buffer = buffer;
251         return 0;
252 }
253
254 static void xsk_populate_fill_ring(struct xsk_umem_info *umem)
255 {
256         int ret, i;
257         u32 idx = 0;
258
259         ret = xsk_ring_prod__reserve(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
260         if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
261                 exit_with_error(-ret);
262         for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
263                 *xsk_ring_prod__fill_addr(&umem->fq, idx++) = i * umem->frame_size;
264         xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
265 }
266
267 static int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,
268                                 struct ifobject *ifobject, u32 qid)
269 {
270         struct xsk_socket_config cfg;
271         struct xsk_ring_cons *rxr;
272         struct xsk_ring_prod *txr;
273
274         xsk->umem = umem;
275         cfg.rx_size = xsk->rxqsize;
276         cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
277         cfg.libbpf_flags = 0;
278         cfg.xdp_flags = xdp_flags;
279         cfg.bind_flags = xdp_bind_flags;
280
281         txr = ifobject->tx_on ? &xsk->tx : NULL;
282         rxr = ifobject->rx_on ? &xsk->rx : NULL;
283         return xsk_socket__create(&xsk->xsk, ifobject->ifname, qid, umem->umem, rxr, txr, &cfg);
284 }
285
286 static struct option long_options[] = {
287         {"interface", required_argument, 0, 'i'},
288         {"queue", optional_argument, 0, 'q'},
289         {"dump-pkts", optional_argument, 0, 'D'},
290         {"verbose", no_argument, 0, 'v'},
291         {0, 0, 0, 0}
292 };
293
294 static void usage(const char *prog)
295 {
296         const char *str =
297                 "  Usage: %s [OPTIONS]\n"
298                 "  Options:\n"
299                 "  -i, --interface      Use interface\n"
300                 "  -q, --queue=n        Use queue n (default 0)\n"
301                 "  -D, --dump-pkts      Dump packets L2 - L5\n"
302                 "  -v, --verbose        Verbose output\n";
303
304         ksft_print_msg(str, prog);
305 }
306
307 static int switch_namespace(const char *nsname)
308 {
309         char fqns[26] = "/var/run/netns/";
310         int nsfd;
311
312         if (!nsname || strlen(nsname) == 0)
313                 return -1;
314
315         strncat(fqns, nsname, sizeof(fqns) - strlen(fqns) - 1);
316         nsfd = open(fqns, O_RDONLY);
317
318         if (nsfd == -1)
319                 exit_with_error(errno);
320
321         if (setns(nsfd, 0) == -1)
322                 exit_with_error(errno);
323
324         print_verbose("NS switched: %s\n", nsname);
325
326         return nsfd;
327 }
328
329 static bool validate_interface(struct ifobject *ifobj)
330 {
331         if (!strcmp(ifobj->ifname, ""))
332                 return false;
333         return true;
334 }
335
336 static void parse_command_line(struct test_spec *test, int argc, char **argv)
337 {
338         struct ifobject *ifobj;
339         u32 interface_nb = 0;
340         int option_index, c;
341
342         opterr = 0;
343
344         for (;;) {
345                 char *sptr, *token;
346
347                 c = getopt_long(argc, argv, "i:Dv", long_options, &option_index);
348                 if (c == -1)
349                         break;
350
351                 switch (c) {
352                 case 'i':
353                         if (interface_nb == 0)
354                                 ifobj = test->ifobj_tx;
355                         else if (interface_nb == 1)
356                                 ifobj = test->ifobj_rx;
357                         else
358                                 break;
359
360                         sptr = strndupa(optarg, strlen(optarg));
361                         memcpy(ifobj->ifname, strsep(&sptr, ","), MAX_INTERFACE_NAME_CHARS);
362                         token = strsep(&sptr, ",");
363                         if (token)
364                                 memcpy(ifobj->nsname, token, MAX_INTERFACES_NAMESPACE_CHARS);
365                         interface_nb++;
366                         break;
367                 case 'D':
368                         opt_pkt_dump = true;
369                         break;
370                 case 'v':
371                         opt_verbose = true;
372                         break;
373                 default:
374                         usage(basename(argv[0]));
375                         ksft_exit_xfail();
376                 }
377         }
378 }
379
380 static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
381                              struct ifobject *ifobj_rx)
382 {
383         u32 i, j;
384
385         for (i = 0; i < MAX_INTERFACES; i++) {
386                 struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
387
388                 ifobj->umem = &ifobj->umem_arr[0];
389                 ifobj->xsk = &ifobj->xsk_arr[0];
390                 ifobj->use_poll = false;
391
392                 if (i == 0) {
393                         ifobj->rx_on = false;
394                         ifobj->tx_on = true;
395                 } else {
396                         ifobj->rx_on = true;
397                         ifobj->tx_on = false;
398                 }
399
400                 for (j = 0; j < MAX_SOCKETS; j++) {
401                         memset(&ifobj->umem_arr[j], 0, sizeof(ifobj->umem_arr[j]));
402                         memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j]));
403                         ifobj->umem_arr[j].num_frames = DEFAULT_PKT_CNT / 4;
404                         ifobj->umem_arr[j].frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
405                         ifobj->xsk_arr[j].rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
406                 }
407         }
408
409         test->ifobj_tx = ifobj_tx;
410         test->ifobj_rx = ifobj_rx;
411 }
412
413 static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
414                            struct ifobject *ifobj_rx)
415 {
416         memset(test, 0, sizeof(*test));
417         __test_spec_init(test, ifobj_tx, ifobj_rx);
418 }
419
420 static void test_spec_reset(struct test_spec *test)
421 {
422         __test_spec_init(test, test->ifobj_tx, test->ifobj_rx);
423 }
424
425 static void test_spec_set_name(struct test_spec *test, const char *name)
426 {
427         strncpy(test->name, name, MAX_TEST_NAME_SIZE);
428 }
429
430 static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb)
431 {
432         if (pkt_nb >= pkt_stream->nb_pkts)
433                 return NULL;
434
435         return &pkt_stream->pkts[pkt_nb];
436 }
437
438 static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len)
439 {
440         struct pkt_stream *pkt_stream;
441         u32 i;
442
443         pkt_stream = malloc(sizeof(*pkt_stream));
444         if (!pkt_stream)
445                 exit_with_error(ENOMEM);
446
447         pkt_stream->pkts = calloc(nb_pkts, sizeof(*pkt_stream->pkts));
448         if (!pkt_stream->pkts)
449                 exit_with_error(ENOMEM);
450
451         pkt_stream->nb_pkts = nb_pkts;
452         for (i = 0; i < nb_pkts; i++) {
453                 pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size;
454                 pkt_stream->pkts[i].len = pkt_len;
455                 pkt_stream->pkts[i].payload = i;
456         }
457
458         return pkt_stream;
459 }
460
461 static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb)
462 {
463         struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb);
464         struct udphdr *udp_hdr;
465         struct ethhdr *eth_hdr;
466         struct iphdr *ip_hdr;
467         void *data;
468
469         if (!pkt)
470                 return NULL;
471
472         data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr);
473         udp_hdr = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
474         ip_hdr = (struct iphdr *)(data + sizeof(struct ethhdr));
475         eth_hdr = (struct ethhdr *)data;
476
477         gen_udp_hdr(pkt_nb, data, ifobject, udp_hdr);
478         gen_ip_hdr(ifobject, ip_hdr);
479         gen_udp_csum(udp_hdr, ip_hdr);
480         gen_eth_hdr(ifobject, eth_hdr);
481
482         return pkt;
483 }
484
485 static void pkt_dump(void *pkt, u32 len)
486 {
487         char s[INET_ADDRSTRLEN];
488         struct ethhdr *ethhdr;
489         struct udphdr *udphdr;
490         struct iphdr *iphdr;
491         int payload, i;
492
493         ethhdr = pkt;
494         iphdr = pkt + sizeof(*ethhdr);
495         udphdr = pkt + sizeof(*ethhdr) + sizeof(*iphdr);
496
497         /*extract L2 frame */
498         fprintf(stdout, "DEBUG>> L2: dst mac: ");
499         for (i = 0; i < ETH_ALEN; i++)
500                 fprintf(stdout, "%02X", ethhdr->h_dest[i]);
501
502         fprintf(stdout, "\nDEBUG>> L2: src mac: ");
503         for (i = 0; i < ETH_ALEN; i++)
504                 fprintf(stdout, "%02X", ethhdr->h_source[i]);
505
506         /*extract L3 frame */
507         fprintf(stdout, "\nDEBUG>> L3: ip_hdr->ihl: %02X\n", iphdr->ihl);
508         fprintf(stdout, "DEBUG>> L3: ip_hdr->saddr: %s\n",
509                 inet_ntop(AF_INET, &iphdr->saddr, s, sizeof(s)));
510         fprintf(stdout, "DEBUG>> L3: ip_hdr->daddr: %s\n",
511                 inet_ntop(AF_INET, &iphdr->daddr, s, sizeof(s)));
512         /*extract L4 frame */
513         fprintf(stdout, "DEBUG>> L4: udp_hdr->src: %d\n", ntohs(udphdr->source));
514         fprintf(stdout, "DEBUG>> L4: udp_hdr->dst: %d\n", ntohs(udphdr->dest));
515         /*extract L5 frame */
516         payload = *((uint32_t *)(pkt + PKT_HDR_SIZE));
517
518         fprintf(stdout, "DEBUG>> L5: payload: %d\n", payload);
519         fprintf(stdout, "---------------------------------------\n");
520 }
521
522 static bool is_pkt_valid(struct pkt *pkt, void *buffer, const struct xdp_desc *desc)
523 {
524         void *data = xsk_umem__get_data(buffer, desc->addr);
525         struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr));
526
527         if (!pkt) {
528                 ksft_test_result_fail("ERROR: [%s] too many packets received\n", __func__);
529                 return false;
530         }
531
532         if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) {
533                 u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE)));
534
535                 if (opt_pkt_dump && test_type != TEST_TYPE_STATS)
536                         pkt_dump(data, PKT_SIZE);
537
538                 if (pkt->len != desc->len) {
539                         ksft_test_result_fail
540                                 ("ERROR: [%s] expected length [%d], got length [%d]\n",
541                                         __func__, pkt->len, desc->len);
542                         return false;
543                 }
544
545                 if (pkt->payload != seqnum) {
546                         ksft_test_result_fail
547                                 ("ERROR: [%s] expected seqnum [%d], got seqnum [%d]\n",
548                                         __func__, pkt->payload, seqnum);
549                         return false;
550                 }
551         } else {
552                 ksft_print_msg("Invalid frame received: ");
553                 ksft_print_msg("[IP_PKT_VER: %02X], [IP_PKT_TOS: %02X]\n", iphdr->version,
554                                iphdr->tos);
555                 return false;
556         }
557
558         return true;
559 }
560
561 static void kick_tx(struct xsk_socket_info *xsk)
562 {
563         int ret;
564
565         ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0);
566         if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN)
567                 return;
568         exit_with_error(errno);
569 }
570
571 static void complete_pkts(struct xsk_socket_info *xsk, int batch_size)
572 {
573         unsigned int rcvd;
574         u32 idx;
575
576         if (!xsk->outstanding_tx)
577                 return;
578
579         if (xsk_ring_prod__needs_wakeup(&xsk->tx))
580                 kick_tx(xsk);
581
582         rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx);
583         if (rcvd) {
584                 xsk_ring_cons__release(&xsk->umem->cq, rcvd);
585                 xsk->outstanding_tx -= rcvd;
586         }
587 }
588
589 static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *xsk,
590                          struct pollfd *fds)
591 {
592         u32 idx_rx = 0, idx_fq = 0, rcvd, i, pkt_count = 0;
593         struct pkt *pkt;
594         int ret;
595
596         pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
597         while (pkt) {
598                 rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx);
599                 if (!rcvd) {
600                         if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
601                                 ret = poll(fds, 1, POLL_TMOUT);
602                                 if (ret < 0)
603                                         exit_with_error(-ret);
604                         }
605                         continue;
606                 }
607
608                 ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
609                 while (ret != rcvd) {
610                         if (ret < 0)
611                                 exit_with_error(-ret);
612                         if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
613                                 ret = poll(fds, 1, POLL_TMOUT);
614                                 if (ret < 0)
615                                         exit_with_error(-ret);
616                         }
617                         ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
618                 }
619
620                 for (i = 0; i < rcvd; i++) {
621                         const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++);
622                         u64 addr = desc->addr, orig;
623
624                         orig = xsk_umem__extract_addr(addr);
625                         addr = xsk_umem__add_offset_to_addr(addr);
626                         if (!is_pkt_valid(pkt, xsk->umem->buffer, desc))
627                                 return;
628
629                         *xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = orig;
630                         pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
631                 }
632
633                 xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
634                 xsk_ring_cons__release(&xsk->rx, rcvd);
635         }
636 }
637
638 static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb)
639 {
640         struct xsk_socket_info *xsk = ifobject->xsk;
641         u32 i, idx;
642
643         while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE)
644                 complete_pkts(xsk, BATCH_SIZE);
645
646         for (i = 0; i < BATCH_SIZE; i++) {
647                 struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i);
648                 struct pkt *pkt = pkt_generate(ifobject, pkt_nb);
649
650                 if (!pkt)
651                         break;
652
653                 tx_desc->addr = pkt->addr;
654                 tx_desc->len = pkt->len;
655                 pkt_nb++;
656         }
657
658         xsk_ring_prod__submit(&xsk->tx, i);
659         if (stat_test_type != STAT_TEST_TX_INVALID)
660                 xsk->outstanding_tx += i;
661         else if (xsk_ring_prod__needs_wakeup(&xsk->tx))
662                 kick_tx(xsk);
663         complete_pkts(xsk, i);
664
665         return i;
666 }
667
668 static void wait_for_tx_completion(struct xsk_socket_info *xsk)
669 {
670         while (xsk->outstanding_tx)
671                 complete_pkts(xsk, BATCH_SIZE);
672 }
673
674 static void send_pkts(struct ifobject *ifobject)
675 {
676         struct pollfd fds[MAX_SOCKS] = { };
677         u32 pkt_cnt = 0;
678
679         fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
680         fds[0].events = POLLOUT;
681
682         while (pkt_cnt < ifobject->pkt_stream->nb_pkts) {
683                 u32 sent;
684
685                 if (ifobject->use_poll) {
686                         int ret;
687
688                         ret = poll(fds, 1, POLL_TMOUT);
689                         if (ret <= 0)
690                                 continue;
691
692                         if (!(fds[0].revents & POLLOUT))
693                                 continue;
694                 }
695
696                 sent = __send_pkts(ifobject, pkt_cnt);
697                 pkt_cnt += sent;
698                 usleep(10);
699         }
700
701         wait_for_tx_completion(ifobject->xsk);
702 }
703
704 static bool rx_stats_are_valid(struct ifobject *ifobject)
705 {
706         u32 xsk_stat = 0, expected_stat = ifobject->pkt_stream->nb_pkts;
707         struct xsk_socket *xsk = ifobject->xsk->xsk;
708         int fd = xsk_socket__fd(xsk);
709         struct xdp_statistics stats;
710         socklen_t optlen;
711         int err;
712
713         optlen = sizeof(stats);
714         err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
715         if (err) {
716                 ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
717                                       __func__, -err, strerror(-err));
718                 return true;
719         }
720
721         if (optlen == sizeof(struct xdp_statistics)) {
722                 switch (stat_test_type) {
723                 case STAT_TEST_RX_DROPPED:
724                         xsk_stat = stats.rx_dropped;
725                         break;
726                 case STAT_TEST_TX_INVALID:
727                         return true;
728                 case STAT_TEST_RX_FULL:
729                         xsk_stat = stats.rx_ring_full;
730                         expected_stat -= RX_FULL_RXQSIZE;
731                         break;
732                 case STAT_TEST_RX_FILL_EMPTY:
733                         xsk_stat = stats.rx_fill_ring_empty_descs;
734                         break;
735                 default:
736                         break;
737                 }
738
739                 if (xsk_stat == expected_stat)
740                         return true;
741         }
742
743         return false;
744 }
745
746 static void tx_stats_validate(struct ifobject *ifobject)
747 {
748         struct xsk_socket *xsk = ifobject->xsk->xsk;
749         int fd = xsk_socket__fd(xsk);
750         struct xdp_statistics stats;
751         socklen_t optlen;
752         int err;
753
754         optlen = sizeof(stats);
755         err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
756         if (err) {
757                 ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
758                                       __func__, -err, strerror(-err));
759                 return;
760         }
761
762         if (stats.tx_invalid_descs == ifobject->pkt_stream->nb_pkts)
763                 return;
764
765         ksft_test_result_fail("ERROR: [%s] tx_invalid_descs incorrect. Got [%u] expected [%u]\n",
766                               __func__, stats.tx_invalid_descs, ifobject->pkt_stream->nb_pkts);
767 }
768
769 static void thread_common_ops(struct ifobject *ifobject, void *bufs)
770 {
771         u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
772         int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
773         size_t mmap_sz = umem_sz;
774         int ctr = 0, ret;
775
776         ifobject->ns_fd = switch_namespace(ifobject->nsname);
777
778         if (test_type == TEST_TYPE_BPF_RES)
779                 mmap_sz *= 2;
780
781         bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
782         if (bufs == MAP_FAILED)
783                 exit_with_error(errno);
784
785         while (ctr++ < SOCK_RECONF_CTR) {
786                 ret = xsk_configure_umem(&ifobject->umem_arr[0], bufs, umem_sz, 0);
787                 if (ret)
788                         exit_with_error(-ret);
789
790                 ret = xsk_configure_socket(&ifobject->xsk_arr[0], &ifobject->umem_arr[0],
791                                            ifobject, 0);
792                 if (!ret)
793                         break;
794
795                 /* Retry Create Socket if it fails as xsk_socket__create() is asynchronous */
796                 if (ctr >= SOCK_RECONF_CTR)
797                         exit_with_error(-ret);
798                 usleep(USLEEP_MAX);
799         }
800
801         if (test_type == TEST_TYPE_BPF_RES) {
802                 ret = xsk_configure_umem(&ifobject->umem_arr[1], (u8 *)bufs + umem_sz, umem_sz, 1);
803                 if (ret)
804                         exit_with_error(-ret);
805
806                 ret = xsk_configure_socket(&ifobject->xsk_arr[1], &ifobject->umem_arr[1],
807                                            ifobject, 1);
808                 if (ret)
809                         exit_with_error(-ret);
810         }
811
812         ifobject->umem = &ifobject->umem_arr[0];
813         ifobject->xsk = &ifobject->xsk_arr[0];
814 }
815
816 static bool testapp_is_test_two_stepped(void)
817 {
818         return (test_type != TEST_TYPE_BIDI && test_type != TEST_TYPE_BPF_RES) || second_step;
819 }
820
821 static void testapp_cleanup_xsk_res(struct ifobject *ifobj)
822 {
823         if (testapp_is_test_two_stepped()) {
824                 xsk_socket__delete(ifobj->xsk->xsk);
825                 (void)xsk_umem__delete(ifobj->umem->umem);
826         }
827 }
828
829 static void *worker_testapp_validate_tx(void *arg)
830 {
831         struct ifobject *ifobject = (struct ifobject *)arg;
832         void *bufs = NULL;
833
834         if (!second_step)
835                 thread_common_ops(ifobject, bufs);
836
837         print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,
838                       ifobject->ifname);
839         send_pkts(ifobject);
840
841         if (stat_test_type == STAT_TEST_TX_INVALID)
842                 tx_stats_validate(ifobject);
843
844         testapp_cleanup_xsk_res(ifobject);
845         pthread_exit(NULL);
846 }
847
848 static void *worker_testapp_validate_rx(void *arg)
849 {
850         struct ifobject *ifobject = (struct ifobject *)arg;
851         struct pollfd fds[MAX_SOCKS] = { };
852         void *bufs = NULL;
853
854         if (!second_step)
855                 thread_common_ops(ifobject, bufs);
856
857         if (stat_test_type != STAT_TEST_RX_FILL_EMPTY)
858                 xsk_populate_fill_ring(ifobject->umem);
859
860         fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
861         fds[0].events = POLLIN;
862
863         pthread_barrier_wait(&barr);
864
865         if (test_type == TEST_TYPE_STATS)
866                 while (!rx_stats_are_valid(ifobject))
867                         continue;
868         else
869                 receive_pkts(ifobject->pkt_stream, ifobject->xsk, fds);
870
871         if (test_type == TEST_TYPE_TEARDOWN)
872                 print_verbose("Destroying socket\n");
873
874         testapp_cleanup_xsk_res(ifobject);
875         pthread_exit(NULL);
876 }
877
878 static void testapp_validate_traffic(struct test_spec *test)
879 {
880         struct ifobject *ifobj_tx = test->ifobj_tx;
881         struct ifobject *ifobj_rx = test->ifobj_rx;
882         struct pkt_stream *pkt_stream;
883
884         if (pthread_barrier_init(&barr, NULL, 2))
885                 exit_with_error(errno);
886
887         if (stat_test_type == STAT_TEST_TX_INVALID)
888                 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, DEFAULT_PKT_CNT,
889                                                  XSK_UMEM__INVALID_FRAME_SIZE);
890         else
891                 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
892         ifobj_tx->pkt_stream = pkt_stream;
893         ifobj_rx->pkt_stream = pkt_stream;
894
895         /*Spawn RX thread */
896         pthread_create(&t0, NULL, ifobj_rx->func_ptr, ifobj_rx);
897
898         pthread_barrier_wait(&barr);
899         if (pthread_barrier_destroy(&barr))
900                 exit_with_error(errno);
901
902         /*Spawn TX thread */
903         pthread_create(&t1, NULL, ifobj_tx->func_ptr, ifobj_tx);
904
905         pthread_join(t1, NULL);
906         pthread_join(t0, NULL);
907 }
908
909 static void testapp_teardown(struct test_spec *test)
910 {
911         int i;
912
913         test_spec_set_name(test, "TEARDOWN");
914         for (i = 0; i < MAX_TEARDOWN_ITER; i++) {
915                 testapp_validate_traffic(test);
916                 test_spec_reset(test);
917         }
918 }
919
920 static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2)
921 {
922         thread_func_t tmp_func_ptr = (*ifobj1)->func_ptr;
923         struct ifobject *tmp_ifobj = (*ifobj1);
924
925         (*ifobj1)->func_ptr = (*ifobj2)->func_ptr;
926         (*ifobj2)->func_ptr = tmp_func_ptr;
927
928         *ifobj1 = *ifobj2;
929         *ifobj2 = tmp_ifobj;
930 }
931
932 static void testapp_bidi(struct test_spec *test)
933 {
934         test_spec_set_name(test, "BIDIRECTIONAL");
935         test->ifobj_tx->rx_on = true;
936         test->ifobj_rx->tx_on = true;
937         for (int i = 0; i < MAX_BIDI_ITER; i++) {
938                 print_verbose("Creating socket\n");
939                 testapp_validate_traffic(test);
940                 if (!second_step) {
941                         print_verbose("Switching Tx/Rx vectors\n");
942                         swap_directions(&test->ifobj_rx, &test->ifobj_tx);
943                 }
944                 second_step = true;
945         }
946
947         swap_directions(&test->ifobj_rx, &test->ifobj_tx);
948 }
949
950 static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx)
951 {
952         xsk_socket__delete(ifobj_tx->xsk->xsk);
953         xsk_umem__delete(ifobj_tx->umem->umem);
954         xsk_socket__delete(ifobj_rx->xsk->xsk);
955         xsk_umem__delete(ifobj_rx->umem->umem);
956         ifobj_tx->umem = &ifobj_tx->umem_arr[1];
957         ifobj_tx->xsk = &ifobj_tx->xsk_arr[1];
958         ifobj_rx->umem = &ifobj_rx->umem_arr[1];
959         ifobj_rx->xsk = &ifobj_rx->xsk_arr[1];
960 }
961
962 static void testapp_bpf_res(struct test_spec *test)
963 {
964         int i;
965
966         test_spec_set_name(test, "BPF_RES");
967         for (i = 0; i < MAX_BPF_ITER; i++) {
968                 print_verbose("Creating socket\n");
969                 testapp_validate_traffic(test);
970                 if (!second_step)
971                         swap_xsk_resources(test->ifobj_tx, test->ifobj_rx);
972                 second_step = true;
973         }
974 }
975
976 static void testapp_stats(struct test_spec *test)
977 {
978         for (int i = 0; i < STAT_TEST_TYPE_MAX; i++) {
979                 test_spec_reset(test);
980                 stat_test_type = i;
981
982                 switch (stat_test_type) {
983                 case STAT_TEST_RX_DROPPED:
984                         test_spec_set_name(test, "STAT_RX_DROPPED");
985                         test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
986                                 XDP_PACKET_HEADROOM - 1;
987                         break;
988                 case STAT_TEST_RX_FULL:
989                         test_spec_set_name(test, "STAT_RX_FULL");
990                         test->ifobj_rx->xsk->rxqsize = RX_FULL_RXQSIZE;
991                         break;
992                 case STAT_TEST_TX_INVALID:
993                         test_spec_set_name(test, "STAT_TX_INVALID");
994                         continue;
995                 case STAT_TEST_RX_FILL_EMPTY:
996                         test_spec_set_name(test, "STAT_RX_FILL_EMPTY");
997                         break;
998                 default:
999                         break;
1000                 }
1001                 testapp_validate_traffic(test);
1002         }
1003
1004         /* To only see the whole stat set being completed unless an individual test fails. */
1005         test_spec_set_name(test, "STATS");
1006 }
1007
1008 static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac,
1009                        const char *dst_ip, const char *src_ip, const u16 dst_port,
1010                        const u16 src_port, thread_func_t func_ptr)
1011 {
1012         struct in_addr ip;
1013
1014         memcpy(ifobj->dst_mac, dst_mac, ETH_ALEN);
1015         memcpy(ifobj->src_mac, src_mac, ETH_ALEN);
1016
1017         inet_aton(dst_ip, &ip);
1018         ifobj->dst_ip = ip.s_addr;
1019
1020         inet_aton(src_ip, &ip);
1021         ifobj->src_ip = ip.s_addr;
1022
1023         ifobj->dst_port = dst_port;
1024         ifobj->src_port = src_port;
1025
1026         ifobj->func_ptr = func_ptr;
1027 }
1028
1029 static void run_pkt_test(struct test_spec *test, int mode, int type)
1030 {
1031         test_type = type;
1032
1033         /* reset defaults after potential previous test */
1034         xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
1035         second_step = 0;
1036         stat_test_type = -1;
1037
1038         configured_mode = mode;
1039
1040         switch (mode) {
1041         case (TEST_MODE_SKB):
1042                 xdp_flags |= XDP_FLAGS_SKB_MODE;
1043                 break;
1044         case (TEST_MODE_DRV):
1045                 xdp_flags |= XDP_FLAGS_DRV_MODE;
1046                 break;
1047         default:
1048                 break;
1049         }
1050
1051         switch (test_type) {
1052         case TEST_TYPE_STATS:
1053                 testapp_stats(test);
1054                 break;
1055         case TEST_TYPE_TEARDOWN:
1056                 testapp_teardown(test);
1057                 break;
1058         case TEST_TYPE_BIDI:
1059                 testapp_bidi(test);
1060                 break;
1061         case TEST_TYPE_BPF_RES:
1062                 testapp_bpf_res(test);
1063                 break;
1064         case TEST_TYPE_NOPOLL:
1065                 test_spec_set_name(test, "RUN_TO_COMPLETION");
1066                 testapp_validate_traffic(test);
1067                 break;
1068         case TEST_TYPE_POLL:
1069                 test->ifobj_tx->use_poll = true;
1070                 test->ifobj_rx->use_poll = true;
1071                 test_spec_set_name(test, "POLL");
1072                 testapp_validate_traffic(test);
1073                 break;
1074         default:
1075                 break;
1076         }
1077
1078         print_ksft_result(test);
1079 }
1080
1081 static struct ifobject *ifobject_create(void)
1082 {
1083         struct ifobject *ifobj;
1084
1085         ifobj = calloc(1, sizeof(struct ifobject));
1086         if (!ifobj)
1087                 return NULL;
1088
1089         ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr));
1090         if (!ifobj->xsk_arr)
1091                 goto out_xsk_arr;
1092
1093         ifobj->umem_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->umem_arr));
1094         if (!ifobj->umem_arr)
1095                 goto out_umem_arr;
1096
1097         return ifobj;
1098
1099 out_umem_arr:
1100         free(ifobj->xsk_arr);
1101 out_xsk_arr:
1102         free(ifobj);
1103         return NULL;
1104 }
1105
1106 static void ifobject_delete(struct ifobject *ifobj)
1107 {
1108         free(ifobj->umem_arr);
1109         free(ifobj->xsk_arr);
1110         free(ifobj);
1111 }
1112
1113 int main(int argc, char **argv)
1114 {
1115         struct rlimit _rlim = { RLIM_INFINITY, RLIM_INFINITY };
1116         struct ifobject *ifobj_tx, *ifobj_rx;
1117         struct test_spec test;
1118         u32 i, j;
1119
1120         if (setrlimit(RLIMIT_MEMLOCK, &_rlim))
1121                 exit_with_error(errno);
1122
1123         ifobj_tx = ifobject_create();
1124         if (!ifobj_tx)
1125                 exit_with_error(ENOMEM);
1126         ifobj_rx = ifobject_create();
1127         if (!ifobj_rx)
1128                 exit_with_error(ENOMEM);
1129
1130         test_spec_init(&test, ifobj_tx, ifobj_rx);
1131
1132         setlocale(LC_ALL, "");
1133
1134         parse_command_line(&test, argc, argv);
1135
1136         if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx)) {
1137                 usage(basename(argv[0]));
1138                 ksft_exit_xfail();
1139         }
1140
1141         init_iface(ifobj_tx, MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2,
1142                    worker_testapp_validate_tx);
1143         init_iface(ifobj_rx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1,
1144                    worker_testapp_validate_rx);
1145
1146         ksft_set_plan(TEST_MODE_MAX * TEST_TYPE_MAX);
1147
1148         for (i = 0; i < TEST_MODE_MAX; i++)
1149                 for (j = 0; j < TEST_TYPE_MAX; j++) {
1150                         test_spec_init(&test, ifobj_tx, ifobj_rx);
1151                         run_pkt_test(&test, i, j);
1152                         usleep(USLEEP_MAX);
1153                 }
1154
1155         ifobject_delete(ifobj_tx);
1156         ifobject_delete(ifobj_rx);
1157
1158         ksft_exit_pass();
1159         return 0;
1160 }