selftests: xsx: Introduce test name in test spec
[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         if (test_type != TEST_TYPE_BIDI) {
282                 rxr = (ifobject->fv.vector == rx) ? &xsk->rx : NULL;
283                 txr = (ifobject->fv.vector == tx) ? &xsk->tx : NULL;
284         } else {
285                 rxr = &xsk->rx;
286                 txr = &xsk->tx;
287         }
288
289         return xsk_socket__create(&xsk->xsk, ifobject->ifname, qid, umem->umem, rxr, txr, &cfg);
290 }
291
292 static struct option long_options[] = {
293         {"interface", required_argument, 0, 'i'},
294         {"queue", optional_argument, 0, 'q'},
295         {"dump-pkts", optional_argument, 0, 'D'},
296         {"verbose", no_argument, 0, 'v'},
297         {0, 0, 0, 0}
298 };
299
300 static void usage(const char *prog)
301 {
302         const char *str =
303                 "  Usage: %s [OPTIONS]\n"
304                 "  Options:\n"
305                 "  -i, --interface      Use interface\n"
306                 "  -q, --queue=n        Use queue n (default 0)\n"
307                 "  -D, --dump-pkts      Dump packets L2 - L5\n"
308                 "  -v, --verbose        Verbose output\n";
309
310         ksft_print_msg(str, prog);
311 }
312
313 static int switch_namespace(const char *nsname)
314 {
315         char fqns[26] = "/var/run/netns/";
316         int nsfd;
317
318         if (!nsname || strlen(nsname) == 0)
319                 return -1;
320
321         strncat(fqns, nsname, sizeof(fqns) - strlen(fqns) - 1);
322         nsfd = open(fqns, O_RDONLY);
323
324         if (nsfd == -1)
325                 exit_with_error(errno);
326
327         if (setns(nsfd, 0) == -1)
328                 exit_with_error(errno);
329
330         print_verbose("NS switched: %s\n", nsname);
331
332         return nsfd;
333 }
334
335 static bool validate_interface(struct ifobject *ifobj)
336 {
337         if (!strcmp(ifobj->ifname, ""))
338                 return false;
339         return true;
340 }
341
342 static void parse_command_line(struct test_spec *test, int argc, char **argv)
343 {
344         struct ifobject *ifobj;
345         u32 interface_nb = 0;
346         int option_index, c;
347
348         opterr = 0;
349
350         for (;;) {
351                 char *sptr, *token;
352
353                 c = getopt_long(argc, argv, "i:Dv", long_options, &option_index);
354                 if (c == -1)
355                         break;
356
357                 switch (c) {
358                 case 'i':
359                         if (interface_nb == 0)
360                                 ifobj = test->ifobj_tx;
361                         else if (interface_nb == 1)
362                                 ifobj = test->ifobj_rx;
363                         else
364                                 break;
365
366                         sptr = strndupa(optarg, strlen(optarg));
367                         memcpy(ifobj->ifname, strsep(&sptr, ","), MAX_INTERFACE_NAME_CHARS);
368                         token = strsep(&sptr, ",");
369                         if (token)
370                                 memcpy(ifobj->nsname, token, MAX_INTERFACES_NAMESPACE_CHARS);
371                         interface_nb++;
372                         break;
373                 case 'D':
374                         opt_pkt_dump = true;
375                         break;
376                 case 'v':
377                         opt_verbose = true;
378                         break;
379                 default:
380                         usage(basename(argv[0]));
381                         ksft_exit_xfail();
382                 }
383         }
384 }
385
386 static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
387                              struct ifobject *ifobj_rx)
388 {
389         u32 i, j;
390
391         for (i = 0; i < MAX_INTERFACES; i++) {
392                 struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
393
394                 ifobj->umem = &ifobj->umem_arr[0];
395                 ifobj->xsk = &ifobj->xsk_arr[0];
396
397                 if (i == tx)
398                         ifobj->fv.vector = tx;
399                 else
400                         ifobj->fv.vector = rx;
401
402                 for (j = 0; j < MAX_SOCKETS; j++) {
403                         memset(&ifobj->umem_arr[j], 0, sizeof(ifobj->umem_arr[j]));
404                         memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j]));
405                         ifobj->umem_arr[j].num_frames = DEFAULT_PKT_CNT / 4;
406                         ifobj->umem_arr[j].frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
407                         ifobj->xsk_arr[j].rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
408                 }
409         }
410
411         test->ifobj_tx = ifobj_tx;
412         test->ifobj_rx = ifobj_rx;
413 }
414
415 static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
416                            struct ifobject *ifobj_rx)
417 {
418         memset(test, 0, sizeof(*test));
419         __test_spec_init(test, ifobj_tx, ifobj_rx);
420 }
421
422 static void test_spec_reset(struct test_spec *test)
423 {
424         __test_spec_init(test, test->ifobj_tx, test->ifobj_rx);
425 }
426
427 static void test_spec_set_name(struct test_spec *test, const char *name)
428 {
429         strncpy(test->name, name, MAX_TEST_NAME_SIZE);
430 }
431
432 static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb)
433 {
434         if (pkt_nb >= pkt_stream->nb_pkts)
435                 return NULL;
436
437         return &pkt_stream->pkts[pkt_nb];
438 }
439
440 static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len)
441 {
442         struct pkt_stream *pkt_stream;
443         u32 i;
444
445         pkt_stream = malloc(sizeof(*pkt_stream));
446         if (!pkt_stream)
447                 exit_with_error(ENOMEM);
448
449         pkt_stream->pkts = calloc(nb_pkts, sizeof(*pkt_stream->pkts));
450         if (!pkt_stream->pkts)
451                 exit_with_error(ENOMEM);
452
453         pkt_stream->nb_pkts = nb_pkts;
454         for (i = 0; i < nb_pkts; i++) {
455                 pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size;
456                 pkt_stream->pkts[i].len = pkt_len;
457                 pkt_stream->pkts[i].payload = i;
458         }
459
460         return pkt_stream;
461 }
462
463 static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb)
464 {
465         struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb);
466         struct udphdr *udp_hdr;
467         struct ethhdr *eth_hdr;
468         struct iphdr *ip_hdr;
469         void *data;
470
471         if (!pkt)
472                 return NULL;
473
474         data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr);
475         udp_hdr = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
476         ip_hdr = (struct iphdr *)(data + sizeof(struct ethhdr));
477         eth_hdr = (struct ethhdr *)data;
478
479         gen_udp_hdr(pkt_nb, data, ifobject, udp_hdr);
480         gen_ip_hdr(ifobject, ip_hdr);
481         gen_udp_csum(udp_hdr, ip_hdr);
482         gen_eth_hdr(ifobject, eth_hdr);
483
484         return pkt;
485 }
486
487 static void pkt_dump(void *pkt, u32 len)
488 {
489         char s[INET_ADDRSTRLEN];
490         struct ethhdr *ethhdr;
491         struct udphdr *udphdr;
492         struct iphdr *iphdr;
493         int payload, i;
494
495         ethhdr = pkt;
496         iphdr = pkt + sizeof(*ethhdr);
497         udphdr = pkt + sizeof(*ethhdr) + sizeof(*iphdr);
498
499         /*extract L2 frame */
500         fprintf(stdout, "DEBUG>> L2: dst mac: ");
501         for (i = 0; i < ETH_ALEN; i++)
502                 fprintf(stdout, "%02X", ethhdr->h_dest[i]);
503
504         fprintf(stdout, "\nDEBUG>> L2: src mac: ");
505         for (i = 0; i < ETH_ALEN; i++)
506                 fprintf(stdout, "%02X", ethhdr->h_source[i]);
507
508         /*extract L3 frame */
509         fprintf(stdout, "\nDEBUG>> L3: ip_hdr->ihl: %02X\n", iphdr->ihl);
510         fprintf(stdout, "DEBUG>> L3: ip_hdr->saddr: %s\n",
511                 inet_ntop(AF_INET, &iphdr->saddr, s, sizeof(s)));
512         fprintf(stdout, "DEBUG>> L3: ip_hdr->daddr: %s\n",
513                 inet_ntop(AF_INET, &iphdr->daddr, s, sizeof(s)));
514         /*extract L4 frame */
515         fprintf(stdout, "DEBUG>> L4: udp_hdr->src: %d\n", ntohs(udphdr->source));
516         fprintf(stdout, "DEBUG>> L4: udp_hdr->dst: %d\n", ntohs(udphdr->dest));
517         /*extract L5 frame */
518         payload = *((uint32_t *)(pkt + PKT_HDR_SIZE));
519
520         fprintf(stdout, "DEBUG>> L5: payload: %d\n", payload);
521         fprintf(stdout, "---------------------------------------\n");
522 }
523
524 static bool is_pkt_valid(struct pkt *pkt, void *buffer, const struct xdp_desc *desc)
525 {
526         void *data = xsk_umem__get_data(buffer, desc->addr);
527         struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr));
528
529         if (!pkt) {
530                 ksft_test_result_fail("ERROR: [%s] too many packets received\n", __func__);
531                 return false;
532         }
533
534         if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) {
535                 u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE)));
536
537                 if (opt_pkt_dump && test_type != TEST_TYPE_STATS)
538                         pkt_dump(data, PKT_SIZE);
539
540                 if (pkt->len != desc->len) {
541                         ksft_test_result_fail
542                                 ("ERROR: [%s] expected length [%d], got length [%d]\n",
543                                         __func__, pkt->len, desc->len);
544                         return false;
545                 }
546
547                 if (pkt->payload != seqnum) {
548                         ksft_test_result_fail
549                                 ("ERROR: [%s] expected seqnum [%d], got seqnum [%d]\n",
550                                         __func__, pkt->payload, seqnum);
551                         return false;
552                 }
553         } else {
554                 ksft_print_msg("Invalid frame received: ");
555                 ksft_print_msg("[IP_PKT_VER: %02X], [IP_PKT_TOS: %02X]\n", iphdr->version,
556                                iphdr->tos);
557                 return false;
558         }
559
560         return true;
561 }
562
563 static void kick_tx(struct xsk_socket_info *xsk)
564 {
565         int ret;
566
567         ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0);
568         if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN)
569                 return;
570         exit_with_error(errno);
571 }
572
573 static void complete_pkts(struct xsk_socket_info *xsk, int batch_size)
574 {
575         unsigned int rcvd;
576         u32 idx;
577
578         if (!xsk->outstanding_tx)
579                 return;
580
581         if (xsk_ring_prod__needs_wakeup(&xsk->tx))
582                 kick_tx(xsk);
583
584         rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx);
585         if (rcvd) {
586                 xsk_ring_cons__release(&xsk->umem->cq, rcvd);
587                 xsk->outstanding_tx -= rcvd;
588         }
589 }
590
591 static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *xsk,
592                          struct pollfd *fds)
593 {
594         u32 idx_rx = 0, idx_fq = 0, rcvd, i, pkt_count = 0;
595         struct pkt *pkt;
596         int ret;
597
598         pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
599         while (pkt) {
600                 rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx);
601                 if (!rcvd) {
602                         if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
603                                 ret = poll(fds, 1, POLL_TMOUT);
604                                 if (ret < 0)
605                                         exit_with_error(-ret);
606                         }
607                         continue;
608                 }
609
610                 ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
611                 while (ret != rcvd) {
612                         if (ret < 0)
613                                 exit_with_error(-ret);
614                         if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
615                                 ret = poll(fds, 1, POLL_TMOUT);
616                                 if (ret < 0)
617                                         exit_with_error(-ret);
618                         }
619                         ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
620                 }
621
622                 for (i = 0; i < rcvd; i++) {
623                         const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++);
624                         u64 addr = desc->addr, orig;
625
626                         orig = xsk_umem__extract_addr(addr);
627                         addr = xsk_umem__add_offset_to_addr(addr);
628                         if (!is_pkt_valid(pkt, xsk->umem->buffer, desc))
629                                 return;
630
631                         *xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = orig;
632                         pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
633                 }
634
635                 xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
636                 xsk_ring_cons__release(&xsk->rx, rcvd);
637         }
638 }
639
640 static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb)
641 {
642         struct xsk_socket_info *xsk = ifobject->xsk;
643         u32 i, idx;
644
645         while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE)
646                 complete_pkts(xsk, BATCH_SIZE);
647
648         for (i = 0; i < BATCH_SIZE; i++) {
649                 struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i);
650                 struct pkt *pkt = pkt_generate(ifobject, pkt_nb);
651
652                 if (!pkt)
653                         break;
654
655                 tx_desc->addr = pkt->addr;
656                 tx_desc->len = pkt->len;
657                 pkt_nb++;
658         }
659
660         xsk_ring_prod__submit(&xsk->tx, i);
661         if (stat_test_type != STAT_TEST_TX_INVALID)
662                 xsk->outstanding_tx += i;
663         else if (xsk_ring_prod__needs_wakeup(&xsk->tx))
664                 kick_tx(xsk);
665         complete_pkts(xsk, i);
666
667         return i;
668 }
669
670 static void wait_for_tx_completion(struct xsk_socket_info *xsk)
671 {
672         while (xsk->outstanding_tx)
673                 complete_pkts(xsk, BATCH_SIZE);
674 }
675
676 static void send_pkts(struct ifobject *ifobject)
677 {
678         struct pollfd fds[MAX_SOCKS] = { };
679         u32 pkt_cnt = 0;
680
681         fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
682         fds[0].events = POLLOUT;
683
684         while (pkt_cnt < ifobject->pkt_stream->nb_pkts) {
685                 u32 sent;
686
687                 if (test_type == TEST_TYPE_POLL) {
688                         int ret;
689
690                         ret = poll(fds, 1, POLL_TMOUT);
691                         if (ret <= 0)
692                                 continue;
693
694                         if (!(fds[0].revents & POLLOUT))
695                                 continue;
696                 }
697
698                 sent = __send_pkts(ifobject, pkt_cnt);
699                 pkt_cnt += sent;
700                 usleep(10);
701         }
702
703         wait_for_tx_completion(ifobject->xsk);
704 }
705
706 static bool rx_stats_are_valid(struct ifobject *ifobject)
707 {
708         u32 xsk_stat = 0, expected_stat = ifobject->pkt_stream->nb_pkts;
709         struct xsk_socket *xsk = ifobject->xsk->xsk;
710         int fd = xsk_socket__fd(xsk);
711         struct xdp_statistics stats;
712         socklen_t optlen;
713         int err;
714
715         optlen = sizeof(stats);
716         err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
717         if (err) {
718                 ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
719                                       __func__, -err, strerror(-err));
720                 return true;
721         }
722
723         if (optlen == sizeof(struct xdp_statistics)) {
724                 switch (stat_test_type) {
725                 case STAT_TEST_RX_DROPPED:
726                         xsk_stat = stats.rx_dropped;
727                         break;
728                 case STAT_TEST_TX_INVALID:
729                         return true;
730                 case STAT_TEST_RX_FULL:
731                         xsk_stat = stats.rx_ring_full;
732                         expected_stat -= RX_FULL_RXQSIZE;
733                         break;
734                 case STAT_TEST_RX_FILL_EMPTY:
735                         xsk_stat = stats.rx_fill_ring_empty_descs;
736                         break;
737                 default:
738                         break;
739                 }
740
741                 if (xsk_stat == expected_stat)
742                         return true;
743         }
744
745         return false;
746 }
747
748 static void tx_stats_validate(struct ifobject *ifobject)
749 {
750         struct xsk_socket *xsk = ifobject->xsk->xsk;
751         int fd = xsk_socket__fd(xsk);
752         struct xdp_statistics stats;
753         socklen_t optlen;
754         int err;
755
756         optlen = sizeof(stats);
757         err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
758         if (err) {
759                 ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
760                                       __func__, -err, strerror(-err));
761                 return;
762         }
763
764         if (stats.tx_invalid_descs == ifobject->pkt_stream->nb_pkts)
765                 return;
766
767         ksft_test_result_fail("ERROR: [%s] tx_invalid_descs incorrect. Got [%u] expected [%u]\n",
768                               __func__, stats.tx_invalid_descs, ifobject->pkt_stream->nb_pkts);
769 }
770
771 static void thread_common_ops(struct ifobject *ifobject, void *bufs)
772 {
773         u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
774         int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
775         size_t mmap_sz = umem_sz;
776         int ctr = 0, ret;
777
778         ifobject->ns_fd = switch_namespace(ifobject->nsname);
779
780         if (test_type == TEST_TYPE_BPF_RES)
781                 mmap_sz *= 2;
782
783         bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
784         if (bufs == MAP_FAILED)
785                 exit_with_error(errno);
786
787         while (ctr++ < SOCK_RECONF_CTR) {
788                 ret = xsk_configure_umem(&ifobject->umem_arr[0], bufs, umem_sz, 0);
789                 if (ret)
790                         exit_with_error(-ret);
791
792                 ret = xsk_configure_socket(&ifobject->xsk_arr[0], &ifobject->umem_arr[0],
793                                            ifobject, 0);
794                 if (!ret)
795                         break;
796
797                 /* Retry Create Socket if it fails as xsk_socket__create() is asynchronous */
798                 if (ctr >= SOCK_RECONF_CTR)
799                         exit_with_error(-ret);
800                 usleep(USLEEP_MAX);
801         }
802
803         if (test_type == TEST_TYPE_BPF_RES) {
804                 ret = xsk_configure_umem(&ifobject->umem_arr[1], (u8 *)bufs + umem_sz, umem_sz, 1);
805                 if (ret)
806                         exit_with_error(-ret);
807
808                 ret = xsk_configure_socket(&ifobject->xsk_arr[1], &ifobject->umem_arr[1],
809                                            ifobject, 1);
810                 if (ret)
811                         exit_with_error(-ret);
812         }
813
814         ifobject->umem = &ifobject->umem_arr[0];
815         ifobject->xsk = &ifobject->xsk_arr[0];
816 }
817
818 static bool testapp_is_test_two_stepped(void)
819 {
820         return (test_type != TEST_TYPE_BIDI && test_type != TEST_TYPE_BPF_RES) || second_step;
821 }
822
823 static void testapp_cleanup_xsk_res(struct ifobject *ifobj)
824 {
825         if (testapp_is_test_two_stepped()) {
826                 xsk_socket__delete(ifobj->xsk->xsk);
827                 (void)xsk_umem__delete(ifobj->umem->umem);
828         }
829 }
830
831 static void *worker_testapp_validate_tx(void *arg)
832 {
833         struct ifobject *ifobject = (struct ifobject *)arg;
834         void *bufs = NULL;
835
836         if (!second_step)
837                 thread_common_ops(ifobject, bufs);
838
839         print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,
840                       ifobject->ifname);
841         send_pkts(ifobject);
842
843         if (stat_test_type == STAT_TEST_TX_INVALID)
844                 tx_stats_validate(ifobject);
845
846         testapp_cleanup_xsk_res(ifobject);
847         pthread_exit(NULL);
848 }
849
850 static void *worker_testapp_validate_rx(void *arg)
851 {
852         struct ifobject *ifobject = (struct ifobject *)arg;
853         struct pollfd fds[MAX_SOCKS] = { };
854         void *bufs = NULL;
855
856         if (!second_step)
857                 thread_common_ops(ifobject, bufs);
858
859         if (stat_test_type != STAT_TEST_RX_FILL_EMPTY)
860                 xsk_populate_fill_ring(ifobject->umem);
861
862         fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
863         fds[0].events = POLLIN;
864
865         pthread_barrier_wait(&barr);
866
867         if (test_type == TEST_TYPE_STATS)
868                 while (!rx_stats_are_valid(ifobject))
869                         continue;
870         else
871                 receive_pkts(ifobject->pkt_stream, ifobject->xsk, fds);
872
873         if (test_type == TEST_TYPE_TEARDOWN)
874                 print_verbose("Destroying socket\n");
875
876         testapp_cleanup_xsk_res(ifobject);
877         pthread_exit(NULL);
878 }
879
880 static void testapp_validate_traffic(struct test_spec *test)
881 {
882         struct ifobject *ifobj_tx = test->ifobj_tx;
883         struct ifobject *ifobj_rx = test->ifobj_rx;
884         struct pkt_stream *pkt_stream;
885
886         if (pthread_barrier_init(&barr, NULL, 2))
887                 exit_with_error(errno);
888
889         if (stat_test_type == STAT_TEST_TX_INVALID)
890                 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, DEFAULT_PKT_CNT,
891                                                  XSK_UMEM__INVALID_FRAME_SIZE);
892         else
893                 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
894         ifobj_tx->pkt_stream = pkt_stream;
895         ifobj_rx->pkt_stream = pkt_stream;
896
897         /*Spawn RX thread */
898         pthread_create(&t0, NULL, ifobj_rx->func_ptr, ifobj_rx);
899
900         pthread_barrier_wait(&barr);
901         if (pthread_barrier_destroy(&barr))
902                 exit_with_error(errno);
903
904         /*Spawn TX thread */
905         pthread_create(&t1, NULL, ifobj_tx->func_ptr, ifobj_tx);
906
907         pthread_join(t1, NULL);
908         pthread_join(t0, NULL);
909 }
910
911 static void testapp_teardown(struct test_spec *test)
912 {
913         int i;
914
915         test_spec_set_name(test, "TEARDOWN");
916         for (i = 0; i < MAX_TEARDOWN_ITER; i++) {
917                 testapp_validate_traffic(test);
918                 test_spec_reset(test);
919         }
920 }
921
922 static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2)
923 {
924         thread_func_t tmp_func_ptr = (*ifobj1)->func_ptr;
925         enum fvector tmp_vector = (*ifobj1)->fv.vector;
926         struct ifobject *tmp_ifobj = (*ifobj1);
927
928         (*ifobj1)->func_ptr = (*ifobj2)->func_ptr;
929         (*ifobj1)->fv.vector = (*ifobj2)->fv.vector;
930
931         (*ifobj2)->func_ptr = tmp_func_ptr;
932         (*ifobj2)->fv.vector = tmp_vector;
933
934         *ifobj1 = *ifobj2;
935         *ifobj2 = tmp_ifobj;
936 }
937
938 static void testapp_bidi(struct test_spec *test)
939 {
940         test_spec_set_name(test, "BIDIRECTIONAL");
941         for (int i = 0; i < MAX_BIDI_ITER; i++) {
942                 print_verbose("Creating socket\n");
943                 testapp_validate_traffic(test);
944                 if (!second_step) {
945                         print_verbose("Switching Tx/Rx vectors\n");
946                         swap_directions(&test->ifobj_rx, &test->ifobj_tx);
947                 }
948                 second_step = true;
949         }
950
951         swap_directions(&test->ifobj_rx, &test->ifobj_tx);
952 }
953
954 static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx)
955 {
956         xsk_socket__delete(ifobj_tx->xsk->xsk);
957         xsk_umem__delete(ifobj_tx->umem->umem);
958         xsk_socket__delete(ifobj_rx->xsk->xsk);
959         xsk_umem__delete(ifobj_rx->umem->umem);
960         ifobj_tx->umem = &ifobj_tx->umem_arr[1];
961         ifobj_tx->xsk = &ifobj_tx->xsk_arr[1];
962         ifobj_rx->umem = &ifobj_rx->umem_arr[1];
963         ifobj_rx->xsk = &ifobj_rx->xsk_arr[1];
964 }
965
966 static void testapp_bpf_res(struct test_spec *test)
967 {
968         int i;
969
970         test_spec_set_name(test, "BPF_RES");
971         for (i = 0; i < MAX_BPF_ITER; i++) {
972                 print_verbose("Creating socket\n");
973                 testapp_validate_traffic(test);
974                 if (!second_step)
975                         swap_xsk_resources(test->ifobj_tx, test->ifobj_rx);
976                 second_step = true;
977         }
978 }
979
980 static void testapp_stats(struct test_spec *test)
981 {
982         for (int i = 0; i < STAT_TEST_TYPE_MAX; i++) {
983                 test_spec_reset(test);
984                 stat_test_type = i;
985
986                 switch (stat_test_type) {
987                 case STAT_TEST_RX_DROPPED:
988                         test_spec_set_name(test, "STAT_RX_DROPPED");
989                         test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
990                                 XDP_PACKET_HEADROOM - 1;
991                         break;
992                 case STAT_TEST_RX_FULL:
993                         test_spec_set_name(test, "STAT_RX_FULL");
994                         test->ifobj_rx->xsk->rxqsize = RX_FULL_RXQSIZE;
995                         break;
996                 case STAT_TEST_TX_INVALID:
997                         test_spec_set_name(test, "STAT_TX_INVALID");
998                         continue;
999                 case STAT_TEST_RX_FILL_EMPTY:
1000                         test_spec_set_name(test, "STAT_RX_FILL_EMPTY");
1001                         break;
1002                 default:
1003                         break;
1004                 }
1005                 testapp_validate_traffic(test);
1006         }
1007
1008         /* To only see the whole stat set being completed unless an individual test fails. */
1009         test_spec_set_name(test, "STATS");
1010 }
1011
1012 static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac,
1013                        const char *dst_ip, const char *src_ip, const u16 dst_port,
1014                        const u16 src_port, enum fvector vector, thread_func_t func_ptr)
1015 {
1016         struct in_addr ip;
1017
1018         memcpy(ifobj->dst_mac, dst_mac, ETH_ALEN);
1019         memcpy(ifobj->src_mac, src_mac, ETH_ALEN);
1020
1021         inet_aton(dst_ip, &ip);
1022         ifobj->dst_ip = ip.s_addr;
1023
1024         inet_aton(src_ip, &ip);
1025         ifobj->src_ip = ip.s_addr;
1026
1027         ifobj->dst_port = dst_port;
1028         ifobj->src_port = src_port;
1029
1030         ifobj->fv.vector = vector;
1031         ifobj->func_ptr = func_ptr;
1032 }
1033
1034 static void run_pkt_test(struct test_spec *test, int mode, int type)
1035 {
1036         test_type = type;
1037
1038         /* reset defaults after potential previous test */
1039         xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
1040         second_step = 0;
1041         stat_test_type = -1;
1042
1043         configured_mode = mode;
1044
1045         switch (mode) {
1046         case (TEST_MODE_SKB):
1047                 xdp_flags |= XDP_FLAGS_SKB_MODE;
1048                 break;
1049         case (TEST_MODE_DRV):
1050                 xdp_flags |= XDP_FLAGS_DRV_MODE;
1051                 break;
1052         default:
1053                 break;
1054         }
1055
1056         switch (test_type) {
1057         case TEST_TYPE_STATS:
1058                 testapp_stats(test);
1059                 break;
1060         case TEST_TYPE_TEARDOWN:
1061                 testapp_teardown(test);
1062                 break;
1063         case TEST_TYPE_BIDI:
1064                 testapp_bidi(test);
1065                 break;
1066         case TEST_TYPE_BPF_RES:
1067                 testapp_bpf_res(test);
1068                 break;
1069         case TEST_TYPE_NOPOLL:
1070                 test_spec_set_name(test, "RUN_TO_COMPLETION");
1071                 testapp_validate_traffic(test);
1072                 break;
1073         case TEST_TYPE_POLL:
1074                 test_spec_set_name(test, "POLL");
1075                 testapp_validate_traffic(test);
1076                 break;
1077         default:
1078                 break;
1079         }
1080
1081         print_ksft_result(test);
1082 }
1083
1084 static struct ifobject *ifobject_create(void)
1085 {
1086         struct ifobject *ifobj;
1087
1088         ifobj = calloc(1, sizeof(struct ifobject));
1089         if (!ifobj)
1090                 return NULL;
1091
1092         ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr));
1093         if (!ifobj->xsk_arr)
1094                 goto out_xsk_arr;
1095
1096         ifobj->umem_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->umem_arr));
1097         if (!ifobj->umem_arr)
1098                 goto out_umem_arr;
1099
1100         return ifobj;
1101
1102 out_umem_arr:
1103         free(ifobj->xsk_arr);
1104 out_xsk_arr:
1105         free(ifobj);
1106         return NULL;
1107 }
1108
1109 static void ifobject_delete(struct ifobject *ifobj)
1110 {
1111         free(ifobj->umem_arr);
1112         free(ifobj->xsk_arr);
1113         free(ifobj);
1114 }
1115
1116 int main(int argc, char **argv)
1117 {
1118         struct rlimit _rlim = { RLIM_INFINITY, RLIM_INFINITY };
1119         struct ifobject *ifobj_tx, *ifobj_rx;
1120         struct test_spec test;
1121         u32 i, j;
1122
1123         if (setrlimit(RLIMIT_MEMLOCK, &_rlim))
1124                 exit_with_error(errno);
1125
1126         ifobj_tx = ifobject_create();
1127         if (!ifobj_tx)
1128                 exit_with_error(ENOMEM);
1129         ifobj_rx = ifobject_create();
1130         if (!ifobj_rx)
1131                 exit_with_error(ENOMEM);
1132
1133         test_spec_init(&test, ifobj_tx, ifobj_rx);
1134
1135         setlocale(LC_ALL, "");
1136
1137         parse_command_line(&test, argc, argv);
1138
1139         if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx)) {
1140                 usage(basename(argv[0]));
1141                 ksft_exit_xfail();
1142         }
1143
1144         init_iface(ifobj_tx, MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2, tx,
1145                    worker_testapp_validate_tx);
1146         init_iface(ifobj_rx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1, rx,
1147                    worker_testapp_validate_rx);
1148
1149         ksft_set_plan(TEST_MODE_MAX * TEST_TYPE_MAX);
1150
1151         for (i = 0; i < TEST_MODE_MAX; i++)
1152                 for (j = 0; j < TEST_TYPE_MAX; j++) {
1153                         test_spec_init(&test, ifobj_tx, ifobj_rx);
1154                         run_pkt_test(&test, i, j);
1155                         usleep(USLEEP_MAX);
1156                 }
1157
1158         ifobject_delete(ifobj_tx);
1159         ifobject_delete(ifobj_rx);
1160
1161         ksft_exit_pass();
1162         return 0;
1163 }