b65e0645b0cd1d6e60aba180fb4acd41f7da1f85
[platform/kernel/linux-starfive.git] / tools / testing / selftests / bpf / xskxceiver.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 in run-to-completion mode
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  *    g. unaligned mode
49  *    h. tests for invalid and corner case Tx descriptors so that the correct ones
50  *       are discarded and let through, respectively.
51  *    i. 2K frame size tests
52  *
53  * Total tests: 12
54  *
55  * Flow:
56  * -----
57  * - Single process spawns two threads: Tx and Rx
58  * - Each of these two threads attach to a veth interface
59  * - Each thread creates one AF_XDP socket connected to a unique umem for each
60  *   veth interface
61  * - Tx thread Transmits a number of packets from veth<xxxx> to veth<yyyy>
62  * - Rx thread verifies if all packets were received and delivered in-order,
63  *   and have the right content
64  *
65  * Enable/disable packet dump mode:
66  * --------------------------
67  * To enable L2 - L4 headers and payload dump of each packet on STDOUT, add
68  * parameter -D to params array in test_xsk.sh, i.e. params=("-S" "-D")
69  */
70
71 #define _GNU_SOURCE
72 #include <fcntl.h>
73 #include <errno.h>
74 #include <getopt.h>
75 #include <asm/barrier.h>
76 #include <linux/if_link.h>
77 #include <linux/if_ether.h>
78 #include <linux/ip.h>
79 #include <linux/udp.h>
80 #include <arpa/inet.h>
81 #include <net/if.h>
82 #include <locale.h>
83 #include <poll.h>
84 #include <pthread.h>
85 #include <signal.h>
86 #include <stdbool.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <stddef.h>
91 #include <sys/mman.h>
92 #include <sys/socket.h>
93 #include <sys/time.h>
94 #include <sys/types.h>
95 #include <sys/queue.h>
96 #include <time.h>
97 #include <unistd.h>
98 #include <stdatomic.h>
99
100 #include "xsk_xdp_progs.skel.h"
101 #include "xsk.h"
102 #include "xskxceiver.h"
103 #include <bpf/bpf.h>
104 #include <linux/filter.h>
105 #include "../kselftest.h"
106 #include "xsk_xdp_metadata.h"
107
108 static const char *MAC1 = "\x00\x0A\x56\x9E\xEE\x62";
109 static const char *MAC2 = "\x00\x0A\x56\x9E\xEE\x61";
110 static const char *IP1 = "192.168.100.162";
111 static const char *IP2 = "192.168.100.161";
112 static const u16 UDP_PORT1 = 2020;
113 static const u16 UDP_PORT2 = 2121;
114
115 static void __exit_with_error(int error, const char *file, const char *func, int line)
116 {
117         ksft_test_result_fail("[%s:%s:%i]: ERROR: %d/\"%s\"\n", file, func, line, error,
118                               strerror(error));
119         ksft_exit_xfail();
120 }
121
122 #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__)
123 #define busy_poll_string(test) (test)->ifobj_tx->busy_poll ? "BUSY-POLL " : ""
124 static char *mode_string(struct test_spec *test)
125 {
126         switch (test->mode) {
127         case TEST_MODE_SKB:
128                 return "SKB";
129         case TEST_MODE_DRV:
130                 return "DRV";
131         case TEST_MODE_ZC:
132                 return "ZC";
133         default:
134                 return "BOGUS";
135         }
136 }
137
138 static void report_failure(struct test_spec *test)
139 {
140         if (test->fail)
141                 return;
142
143         ksft_test_result_fail("FAIL: %s %s%s\n", mode_string(test), busy_poll_string(test),
144                               test->name);
145         test->fail = true;
146 }
147
148 static void memset32_htonl(void *dest, u32 val, u32 size)
149 {
150         u32 *ptr = (u32 *)dest;
151         int i;
152
153         val = htonl(val);
154
155         for (i = 0; i < (size & (~0x3)); i += 4)
156                 ptr[i >> 2] = val;
157 }
158
159 /*
160  * Fold a partial checksum
161  * This function code has been taken from
162  * Linux kernel include/asm-generic/checksum.h
163  */
164 static __u16 csum_fold(__u32 csum)
165 {
166         u32 sum = (__force u32)csum;
167
168         sum = (sum & 0xffff) + (sum >> 16);
169         sum = (sum & 0xffff) + (sum >> 16);
170         return (__force __u16)~sum;
171 }
172
173 /*
174  * This function code has been taken from
175  * Linux kernel lib/checksum.c
176  */
177 static u32 from64to32(u64 x)
178 {
179         /* add up 32-bit and 32-bit for 32+c bit */
180         x = (x & 0xffffffff) + (x >> 32);
181         /* add up carry.. */
182         x = (x & 0xffffffff) + (x >> 32);
183         return (u32)x;
184 }
185
186 /*
187  * This function code has been taken from
188  * Linux kernel lib/checksum.c
189  */
190 static __u32 csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum)
191 {
192         unsigned long long s = (__force u32)sum;
193
194         s += (__force u32)saddr;
195         s += (__force u32)daddr;
196 #ifdef __BIG_ENDIAN__
197         s += proto + len;
198 #else
199         s += (proto + len) << 8;
200 #endif
201         return (__force __u32)from64to32(s);
202 }
203
204 /*
205  * This function has been taken from
206  * Linux kernel include/asm-generic/checksum.h
207  */
208 static __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum)
209 {
210         return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
211 }
212
213 static u16 udp_csum(u32 saddr, u32 daddr, u32 len, u8 proto, u16 *udp_pkt)
214 {
215         u32 csum = 0;
216         u32 cnt = 0;
217
218         /* udp hdr and data */
219         for (; cnt < len; cnt += 2)
220                 csum += udp_pkt[cnt >> 1];
221
222         return csum_tcpudp_magic(saddr, daddr, len, proto, csum);
223 }
224
225 static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr)
226 {
227         memcpy(eth_hdr->h_dest, ifobject->dst_mac, ETH_ALEN);
228         memcpy(eth_hdr->h_source, ifobject->src_mac, ETH_ALEN);
229         eth_hdr->h_proto = htons(ETH_P_IP);
230 }
231
232 static void gen_ip_hdr(struct ifobject *ifobject, struct iphdr *ip_hdr)
233 {
234         ip_hdr->version = IP_PKT_VER;
235         ip_hdr->ihl = 0x5;
236         ip_hdr->tos = IP_PKT_TOS;
237         ip_hdr->tot_len = htons(IP_PKT_SIZE);
238         ip_hdr->id = 0;
239         ip_hdr->frag_off = 0;
240         ip_hdr->ttl = IPDEFTTL;
241         ip_hdr->protocol = IPPROTO_UDP;
242         ip_hdr->saddr = ifobject->src_ip;
243         ip_hdr->daddr = ifobject->dst_ip;
244         ip_hdr->check = 0;
245 }
246
247 static void gen_udp_hdr(u32 payload, void *pkt, struct ifobject *ifobject,
248                         struct udphdr *udp_hdr)
249 {
250         udp_hdr->source = htons(ifobject->src_port);
251         udp_hdr->dest = htons(ifobject->dst_port);
252         udp_hdr->len = htons(UDP_PKT_SIZE);
253         memset32_htonl(pkt + PKT_HDR_SIZE, payload, UDP_PKT_DATA_SIZE);
254 }
255
256 static bool is_umem_valid(struct ifobject *ifobj)
257 {
258         return !!ifobj->umem->umem;
259 }
260
261 static void gen_udp_csum(struct udphdr *udp_hdr, struct iphdr *ip_hdr)
262 {
263         udp_hdr->check = 0;
264         udp_hdr->check =
265             udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE, IPPROTO_UDP, (u16 *)udp_hdr);
266 }
267
268 static u32 mode_to_xdp_flags(enum test_mode mode)
269 {
270         return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE;
271 }
272
273 static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size)
274 {
275         struct xsk_umem_config cfg = {
276                 .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
277                 .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
278                 .frame_size = umem->frame_size,
279                 .frame_headroom = umem->frame_headroom,
280                 .flags = XSK_UMEM__DEFAULT_FLAGS
281         };
282         int ret;
283
284         if (umem->unaligned_mode)
285                 cfg.flags |= XDP_UMEM_UNALIGNED_CHUNK_FLAG;
286
287         ret = xsk_umem__create(&umem->umem, buffer, size,
288                                &umem->fq, &umem->cq, &cfg);
289         if (ret)
290                 return ret;
291
292         umem->buffer = buffer;
293         return 0;
294 }
295
296 static void enable_busy_poll(struct xsk_socket_info *xsk)
297 {
298         int sock_opt;
299
300         sock_opt = 1;
301         if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_PREFER_BUSY_POLL,
302                        (void *)&sock_opt, sizeof(sock_opt)) < 0)
303                 exit_with_error(errno);
304
305         sock_opt = 20;
306         if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_BUSY_POLL,
307                        (void *)&sock_opt, sizeof(sock_opt)) < 0)
308                 exit_with_error(errno);
309
310         sock_opt = BATCH_SIZE;
311         if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_BUSY_POLL_BUDGET,
312                        (void *)&sock_opt, sizeof(sock_opt)) < 0)
313                 exit_with_error(errno);
314 }
315
316 static int __xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,
317                                   struct ifobject *ifobject, bool shared)
318 {
319         struct xsk_socket_config cfg = {};
320         struct xsk_ring_cons *rxr;
321         struct xsk_ring_prod *txr;
322
323         xsk->umem = umem;
324         cfg.rx_size = xsk->rxqsize;
325         cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
326         cfg.bind_flags = ifobject->bind_flags;
327         if (shared)
328                 cfg.bind_flags |= XDP_SHARED_UMEM;
329
330         txr = ifobject->tx_on ? &xsk->tx : NULL;
331         rxr = ifobject->rx_on ? &xsk->rx : NULL;
332         return xsk_socket__create(&xsk->xsk, ifobject->ifindex, 0, umem->umem, rxr, txr, &cfg);
333 }
334
335 static bool ifobj_zc_avail(struct ifobject *ifobject)
336 {
337         size_t umem_sz = DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE;
338         int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
339         struct xsk_socket_info *xsk;
340         struct xsk_umem_info *umem;
341         bool zc_avail = false;
342         void *bufs;
343         int ret;
344
345         bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
346         if (bufs == MAP_FAILED)
347                 exit_with_error(errno);
348
349         umem = calloc(1, sizeof(struct xsk_umem_info));
350         if (!umem) {
351                 munmap(bufs, umem_sz);
352                 exit_with_error(ENOMEM);
353         }
354         umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
355         ret = xsk_configure_umem(umem, bufs, umem_sz);
356         if (ret)
357                 exit_with_error(-ret);
358
359         xsk = calloc(1, sizeof(struct xsk_socket_info));
360         if (!xsk)
361                 goto out;
362         ifobject->bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY;
363         ifobject->rx_on = true;
364         xsk->rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
365         ret = __xsk_configure_socket(xsk, umem, ifobject, false);
366         if (!ret)
367                 zc_avail = true;
368
369         xsk_socket__delete(xsk->xsk);
370         free(xsk);
371 out:
372         munmap(umem->buffer, umem_sz);
373         xsk_umem__delete(umem->umem);
374         free(umem);
375         return zc_avail;
376 }
377
378 static struct option long_options[] = {
379         {"interface", required_argument, 0, 'i'},
380         {"busy-poll", no_argument, 0, 'b'},
381         {"dump-pkts", no_argument, 0, 'D'},
382         {"verbose", no_argument, 0, 'v'},
383         {0, 0, 0, 0}
384 };
385
386 static void usage(const char *prog)
387 {
388         const char *str =
389                 "  Usage: %s [OPTIONS]\n"
390                 "  Options:\n"
391                 "  -i, --interface      Use interface\n"
392                 "  -D, --dump-pkts      Dump packets L2 - L5\n"
393                 "  -v, --verbose        Verbose output\n"
394                 "  -b, --busy-poll      Enable busy poll\n";
395
396         ksft_print_msg(str, prog);
397 }
398
399 static bool validate_interface(struct ifobject *ifobj)
400 {
401         if (!strcmp(ifobj->ifname, ""))
402                 return false;
403         return true;
404 }
405
406 static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx, int argc,
407                                char **argv)
408 {
409         struct ifobject *ifobj;
410         u32 interface_nb = 0;
411         int option_index, c;
412
413         opterr = 0;
414
415         for (;;) {
416                 c = getopt_long(argc, argv, "i:Dvb", long_options, &option_index);
417                 if (c == -1)
418                         break;
419
420                 switch (c) {
421                 case 'i':
422                         if (interface_nb == 0)
423                                 ifobj = ifobj_tx;
424                         else if (interface_nb == 1)
425                                 ifobj = ifobj_rx;
426                         else
427                                 break;
428
429                         memcpy(ifobj->ifname, optarg,
430                                min_t(size_t, MAX_INTERFACE_NAME_CHARS, strlen(optarg)));
431
432                         ifobj->ifindex = if_nametoindex(ifobj->ifname);
433                         if (!ifobj->ifindex)
434                                 exit_with_error(errno);
435
436                         interface_nb++;
437                         break;
438                 case 'D':
439                         opt_pkt_dump = true;
440                         break;
441                 case 'v':
442                         opt_verbose = true;
443                         break;
444                 case 'b':
445                         ifobj_tx->busy_poll = true;
446                         ifobj_rx->busy_poll = true;
447                         break;
448                 default:
449                         usage(basename(argv[0]));
450                         ksft_exit_xfail();
451                 }
452         }
453 }
454
455 static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
456                              struct ifobject *ifobj_rx)
457 {
458         u32 i, j;
459
460         for (i = 0; i < MAX_INTERFACES; i++) {
461                 struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
462
463                 ifobj->xsk = &ifobj->xsk_arr[0];
464                 ifobj->use_poll = false;
465                 ifobj->use_fill_ring = true;
466                 ifobj->release_rx = true;
467                 ifobj->validation_func = NULL;
468                 ifobj->use_metadata = false;
469
470                 if (i == 0) {
471                         ifobj->rx_on = false;
472                         ifobj->tx_on = true;
473                         ifobj->pkt_stream = test->tx_pkt_stream_default;
474                 } else {
475                         ifobj->rx_on = true;
476                         ifobj->tx_on = false;
477                         ifobj->pkt_stream = test->rx_pkt_stream_default;
478                 }
479
480                 memset(ifobj->umem, 0, sizeof(*ifobj->umem));
481                 ifobj->umem->num_frames = DEFAULT_UMEM_BUFFERS;
482                 ifobj->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
483                 if (ifobj->shared_umem && ifobj->rx_on)
484                         ifobj->umem->base_addr = DEFAULT_UMEM_BUFFERS *
485                                 XSK_UMEM__DEFAULT_FRAME_SIZE;
486
487                 for (j = 0; j < MAX_SOCKETS; j++) {
488                         memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j]));
489                         ifobj->xsk_arr[j].rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
490                 }
491         }
492
493         test->ifobj_tx = ifobj_tx;
494         test->ifobj_rx = ifobj_rx;
495         test->current_step = 0;
496         test->total_steps = 1;
497         test->nb_sockets = 1;
498         test->fail = false;
499         test->xdp_prog_rx = ifobj_rx->xdp_progs->progs.xsk_def_prog;
500         test->xskmap_rx = ifobj_rx->xdp_progs->maps.xsk;
501         test->xdp_prog_tx = ifobj_tx->xdp_progs->progs.xsk_def_prog;
502         test->xskmap_tx = ifobj_tx->xdp_progs->maps.xsk;
503 }
504
505 static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
506                            struct ifobject *ifobj_rx, enum test_mode mode)
507 {
508         struct pkt_stream *tx_pkt_stream;
509         struct pkt_stream *rx_pkt_stream;
510         u32 i;
511
512         tx_pkt_stream = test->tx_pkt_stream_default;
513         rx_pkt_stream = test->rx_pkt_stream_default;
514         memset(test, 0, sizeof(*test));
515         test->tx_pkt_stream_default = tx_pkt_stream;
516         test->rx_pkt_stream_default = rx_pkt_stream;
517
518         for (i = 0; i < MAX_INTERFACES; i++) {
519                 struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
520
521                 ifobj->bind_flags = XDP_USE_NEED_WAKEUP;
522                 if (mode == TEST_MODE_ZC)
523                         ifobj->bind_flags |= XDP_ZEROCOPY;
524                 else
525                         ifobj->bind_flags |= XDP_COPY;
526         }
527
528         test->mode = mode;
529         __test_spec_init(test, ifobj_tx, ifobj_rx);
530 }
531
532 static void test_spec_reset(struct test_spec *test)
533 {
534         __test_spec_init(test, test->ifobj_tx, test->ifobj_rx);
535 }
536
537 static void test_spec_set_name(struct test_spec *test, const char *name)
538 {
539         strncpy(test->name, name, MAX_TEST_NAME_SIZE);
540 }
541
542 static void test_spec_set_xdp_prog(struct test_spec *test, struct bpf_program *xdp_prog_rx,
543                                    struct bpf_program *xdp_prog_tx, struct bpf_map *xskmap_rx,
544                                    struct bpf_map *xskmap_tx)
545 {
546         test->xdp_prog_rx = xdp_prog_rx;
547         test->xdp_prog_tx = xdp_prog_tx;
548         test->xskmap_rx = xskmap_rx;
549         test->xskmap_tx = xskmap_tx;
550 }
551
552 static void pkt_stream_reset(struct pkt_stream *pkt_stream)
553 {
554         if (pkt_stream)
555                 pkt_stream->rx_pkt_nb = 0;
556 }
557
558 static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb)
559 {
560         if (pkt_nb >= pkt_stream->nb_pkts)
561                 return NULL;
562
563         return &pkt_stream->pkts[pkt_nb];
564 }
565
566 static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream, u32 *pkts_sent)
567 {
568         while (pkt_stream->rx_pkt_nb < pkt_stream->nb_pkts) {
569                 (*pkts_sent)++;
570                 if (pkt_stream->pkts[pkt_stream->rx_pkt_nb].valid)
571                         return &pkt_stream->pkts[pkt_stream->rx_pkt_nb++];
572                 pkt_stream->rx_pkt_nb++;
573         }
574         return NULL;
575 }
576
577 static void pkt_stream_delete(struct pkt_stream *pkt_stream)
578 {
579         free(pkt_stream->pkts);
580         free(pkt_stream);
581 }
582
583 static void pkt_stream_restore_default(struct test_spec *test)
584 {
585         struct pkt_stream *tx_pkt_stream = test->ifobj_tx->pkt_stream;
586         struct pkt_stream *rx_pkt_stream = test->ifobj_rx->pkt_stream;
587
588         if (tx_pkt_stream != test->tx_pkt_stream_default) {
589                 pkt_stream_delete(test->ifobj_tx->pkt_stream);
590                 test->ifobj_tx->pkt_stream = test->tx_pkt_stream_default;
591         }
592
593         if (rx_pkt_stream != test->rx_pkt_stream_default) {
594                 pkt_stream_delete(test->ifobj_rx->pkt_stream);
595                 test->ifobj_rx->pkt_stream = test->rx_pkt_stream_default;
596         }
597 }
598
599 static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts)
600 {
601         struct pkt_stream *pkt_stream;
602
603         pkt_stream = calloc(1, sizeof(*pkt_stream));
604         if (!pkt_stream)
605                 return NULL;
606
607         pkt_stream->pkts = calloc(nb_pkts, sizeof(*pkt_stream->pkts));
608         if (!pkt_stream->pkts) {
609                 free(pkt_stream);
610                 return NULL;
611         }
612
613         pkt_stream->nb_pkts = nb_pkts;
614         return pkt_stream;
615 }
616
617 static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr, u32 len)
618 {
619         pkt->addr = addr + umem->base_addr;
620         pkt->len = len;
621         if (len > umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 2 - umem->frame_headroom)
622                 pkt->valid = false;
623         else
624                 pkt->valid = true;
625 }
626
627 static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len)
628 {
629         struct pkt_stream *pkt_stream;
630         u32 i;
631
632         pkt_stream = __pkt_stream_alloc(nb_pkts);
633         if (!pkt_stream)
634                 exit_with_error(ENOMEM);
635
636         pkt_stream->nb_pkts = nb_pkts;
637         for (i = 0; i < nb_pkts; i++) {
638                 pkt_set(umem, &pkt_stream->pkts[i], (i % umem->num_frames) * umem->frame_size,
639                         pkt_len);
640                 pkt_stream->pkts[i].payload = i;
641         }
642
643         return pkt_stream;
644 }
645
646 static struct pkt_stream *pkt_stream_clone(struct xsk_umem_info *umem,
647                                            struct pkt_stream *pkt_stream)
648 {
649         return pkt_stream_generate(umem, pkt_stream->nb_pkts, pkt_stream->pkts[0].len);
650 }
651
652 static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len)
653 {
654         struct pkt_stream *pkt_stream;
655
656         pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, nb_pkts, pkt_len);
657         test->ifobj_tx->pkt_stream = pkt_stream;
658         pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, nb_pkts, pkt_len);
659         test->ifobj_rx->pkt_stream = pkt_stream;
660 }
661
662 static void __pkt_stream_replace_half(struct ifobject *ifobj, u32 pkt_len,
663                                       int offset)
664 {
665         struct xsk_umem_info *umem = ifobj->umem;
666         struct pkt_stream *pkt_stream;
667         u32 i;
668
669         pkt_stream = pkt_stream_clone(umem, ifobj->pkt_stream);
670         for (i = 1; i < ifobj->pkt_stream->nb_pkts; i += 2)
671                 pkt_set(umem, &pkt_stream->pkts[i],
672                         (i % umem->num_frames) * umem->frame_size + offset, pkt_len);
673
674         ifobj->pkt_stream = pkt_stream;
675 }
676
677 static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, int offset)
678 {
679         __pkt_stream_replace_half(test->ifobj_tx, pkt_len, offset);
680         __pkt_stream_replace_half(test->ifobj_rx, pkt_len, offset);
681 }
682
683 static void pkt_stream_receive_half(struct test_spec *test)
684 {
685         struct xsk_umem_info *umem = test->ifobj_rx->umem;
686         struct pkt_stream *pkt_stream = test->ifobj_tx->pkt_stream;
687         u32 i;
688
689         test->ifobj_rx->pkt_stream = pkt_stream_generate(umem, pkt_stream->nb_pkts,
690                                                          pkt_stream->pkts[0].len);
691         pkt_stream = test->ifobj_rx->pkt_stream;
692         for (i = 1; i < pkt_stream->nb_pkts; i += 2)
693                 pkt_stream->pkts[i].valid = false;
694 }
695
696 static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb)
697 {
698         struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb);
699         struct udphdr *udp_hdr;
700         struct ethhdr *eth_hdr;
701         struct iphdr *ip_hdr;
702         void *data;
703
704         if (!pkt)
705                 return NULL;
706         if (!pkt->valid || pkt->len < MIN_PKT_SIZE)
707                 return pkt;
708
709         data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr);
710         udp_hdr = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
711         ip_hdr = (struct iphdr *)(data + sizeof(struct ethhdr));
712         eth_hdr = (struct ethhdr *)data;
713
714         gen_udp_hdr(pkt_nb, data, ifobject, udp_hdr);
715         gen_ip_hdr(ifobject, ip_hdr);
716         gen_udp_csum(udp_hdr, ip_hdr);
717         gen_eth_hdr(ifobject, eth_hdr);
718
719         return pkt;
720 }
721
722 static void __pkt_stream_generate_custom(struct ifobject *ifobj,
723                                          struct pkt *pkts, u32 nb_pkts)
724 {
725         struct pkt_stream *pkt_stream;
726         u32 i;
727
728         pkt_stream = __pkt_stream_alloc(nb_pkts);
729         if (!pkt_stream)
730                 exit_with_error(ENOMEM);
731
732         for (i = 0; i < nb_pkts; i++) {
733                 pkt_stream->pkts[i].addr = pkts[i].addr + ifobj->umem->base_addr;
734                 pkt_stream->pkts[i].len = pkts[i].len;
735                 pkt_stream->pkts[i].payload = i;
736                 pkt_stream->pkts[i].valid = pkts[i].valid;
737         }
738
739         ifobj->pkt_stream = pkt_stream;
740 }
741
742 static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, u32 nb_pkts)
743 {
744         __pkt_stream_generate_custom(test->ifobj_tx, pkts, nb_pkts);
745         __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts);
746 }
747
748 static void pkt_dump(void *pkt, u32 len)
749 {
750         char s[INET_ADDRSTRLEN];
751         struct ethhdr *ethhdr;
752         struct udphdr *udphdr;
753         struct iphdr *iphdr;
754         u32 payload, i;
755
756         ethhdr = pkt;
757         iphdr = pkt + sizeof(*ethhdr);
758         udphdr = pkt + sizeof(*ethhdr) + sizeof(*iphdr);
759
760         /*extract L2 frame */
761         fprintf(stdout, "DEBUG>> L2: dst mac: ");
762         for (i = 0; i < ETH_ALEN; i++)
763                 fprintf(stdout, "%02X", ethhdr->h_dest[i]);
764
765         fprintf(stdout, "\nDEBUG>> L2: src mac: ");
766         for (i = 0; i < ETH_ALEN; i++)
767                 fprintf(stdout, "%02X", ethhdr->h_source[i]);
768
769         /*extract L3 frame */
770         fprintf(stdout, "\nDEBUG>> L3: ip_hdr->ihl: %02X\n", iphdr->ihl);
771         fprintf(stdout, "DEBUG>> L3: ip_hdr->saddr: %s\n",
772                 inet_ntop(AF_INET, &iphdr->saddr, s, sizeof(s)));
773         fprintf(stdout, "DEBUG>> L3: ip_hdr->daddr: %s\n",
774                 inet_ntop(AF_INET, &iphdr->daddr, s, sizeof(s)));
775         /*extract L4 frame */
776         fprintf(stdout, "DEBUG>> L4: udp_hdr->src: %d\n", ntohs(udphdr->source));
777         fprintf(stdout, "DEBUG>> L4: udp_hdr->dst: %d\n", ntohs(udphdr->dest));
778         /*extract L5 frame */
779         payload = ntohl(*((u32 *)(pkt + PKT_HDR_SIZE)));
780
781         fprintf(stdout, "DEBUG>> L5: payload: %d\n", payload);
782         fprintf(stdout, "---------------------------------------\n");
783 }
784
785 static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, u64 addr,
786                               u64 pkt_stream_addr)
787 {
788         u32 headroom = umem->unaligned_mode ? 0 : umem->frame_headroom;
789         u32 offset = addr % umem->frame_size, expected_offset = 0;
790
791         if (!pkt_stream->use_addr_for_fill)
792                 pkt_stream_addr = 0;
793
794         expected_offset += (pkt_stream_addr + headroom + XDP_PACKET_HEADROOM) % umem->frame_size;
795
796         if (offset == expected_offset)
797                 return true;
798
799         ksft_print_msg("[%s] expected [%u], got [%u]\n", __func__, expected_offset, offset);
800         return false;
801 }
802
803 static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr)
804 {
805         void *data = xsk_umem__get_data(buffer, addr);
806         struct xdp_info *meta = data - sizeof(struct xdp_info);
807
808         if (meta->count != pkt->payload) {
809                 ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%d]\n",
810                                __func__, pkt->payload, meta->count);
811                 return false;
812         }
813
814         return true;
815 }
816
817 static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len)
818 {
819         void *data = xsk_umem__get_data(buffer, addr);
820         struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr));
821
822         if (!pkt) {
823                 ksft_print_msg("[%s] too many packets received\n", __func__);
824                 return false;
825         }
826
827         if (len < MIN_PKT_SIZE || pkt->len < MIN_PKT_SIZE) {
828                 /* Do not try to verify packets that are smaller than minimum size. */
829                 return true;
830         }
831
832         if (pkt->len != len) {
833                 ksft_print_msg("[%s] expected length [%d], got length [%d]\n",
834                                __func__, pkt->len, len);
835                 return false;
836         }
837
838         if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) {
839                 u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE)));
840
841                 if (opt_pkt_dump)
842                         pkt_dump(data, PKT_SIZE);
843
844                 if (pkt->payload != seqnum) {
845                         ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n",
846                                        __func__, pkt->payload, seqnum);
847                         return false;
848                 }
849         } else {
850                 ksft_print_msg("Invalid frame received: ");
851                 ksft_print_msg("[IP_PKT_VER: %02X], [IP_PKT_TOS: %02X]\n", iphdr->version,
852                                iphdr->tos);
853                 return false;
854         }
855
856         return true;
857 }
858
859 static void kick_tx(struct xsk_socket_info *xsk)
860 {
861         int ret;
862
863         ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0);
864         if (ret >= 0)
865                 return;
866         if (errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN) {
867                 usleep(100);
868                 return;
869         }
870         exit_with_error(errno);
871 }
872
873 static void kick_rx(struct xsk_socket_info *xsk)
874 {
875         int ret;
876
877         ret = recvfrom(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, NULL);
878         if (ret < 0)
879                 exit_with_error(errno);
880 }
881
882 static int complete_pkts(struct xsk_socket_info *xsk, int batch_size)
883 {
884         unsigned int rcvd;
885         u32 idx;
886
887         if (xsk_ring_prod__needs_wakeup(&xsk->tx))
888                 kick_tx(xsk);
889
890         rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx);
891         if (rcvd) {
892                 if (rcvd > xsk->outstanding_tx) {
893                         u64 addr = *xsk_ring_cons__comp_addr(&xsk->umem->cq, idx + rcvd - 1);
894
895                         ksft_print_msg("[%s] Too many packets completed\n", __func__);
896                         ksft_print_msg("Last completion address: %llx\n", addr);
897                         return TEST_FAILURE;
898                 }
899
900                 xsk_ring_cons__release(&xsk->umem->cq, rcvd);
901                 xsk->outstanding_tx -= rcvd;
902         }
903
904         return TEST_PASS;
905 }
906
907 static int receive_pkts(struct test_spec *test, struct pollfd *fds)
908 {
909         struct timeval tv_end, tv_now, tv_timeout = {THREAD_TMOUT, 0};
910         struct pkt_stream *pkt_stream = test->ifobj_rx->pkt_stream;
911         u32 idx_rx = 0, idx_fq = 0, rcvd, i, pkts_sent = 0;
912         struct xsk_socket_info *xsk = test->ifobj_rx->xsk;
913         struct ifobject *ifobj = test->ifobj_rx;
914         struct xsk_umem_info *umem = xsk->umem;
915         struct pkt *pkt;
916         int ret;
917
918         ret = gettimeofday(&tv_now, NULL);
919         if (ret)
920                 exit_with_error(errno);
921         timeradd(&tv_now, &tv_timeout, &tv_end);
922
923         pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &pkts_sent);
924         while (pkt) {
925                 ret = gettimeofday(&tv_now, NULL);
926                 if (ret)
927                         exit_with_error(errno);
928                 if (timercmp(&tv_now, &tv_end, >)) {
929                         ksft_print_msg("ERROR: [%s] Receive loop timed out\n", __func__);
930                         return TEST_FAILURE;
931                 }
932
933                 kick_rx(xsk);
934                 if (ifobj->use_poll) {
935                         ret = poll(fds, 1, POLL_TMOUT);
936                         if (ret < 0)
937                                 exit_with_error(errno);
938
939                         if (!ret) {
940                                 if (!is_umem_valid(test->ifobj_tx))
941                                         return TEST_PASS;
942
943                                 ksft_print_msg("ERROR: [%s] Poll timed out\n", __func__);
944                                 return TEST_FAILURE;
945
946                         }
947
948                         if (!(fds->revents & POLLIN))
949                                 continue;
950                 }
951
952                 rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx);
953                 if (!rcvd)
954                         continue;
955
956                 if (ifobj->use_fill_ring) {
957                         ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
958                         while (ret != rcvd) {
959                                 if (ret < 0)
960                                         exit_with_error(-ret);
961                                 if (xsk_ring_prod__needs_wakeup(&umem->fq)) {
962                                         ret = poll(fds, 1, POLL_TMOUT);
963                                         if (ret < 0)
964                                                 exit_with_error(errno);
965                                 }
966                                 ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
967                         }
968                 }
969
970                 for (i = 0; i < rcvd; i++) {
971                         const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++);
972                         u64 addr = desc->addr, orig;
973
974                         orig = xsk_umem__extract_addr(addr);
975                         addr = xsk_umem__add_offset_to_addr(addr);
976
977                         if (!is_pkt_valid(pkt, umem->buffer, addr, desc->len) ||
978                             !is_offset_correct(umem, pkt_stream, addr, pkt->addr) ||
979                             (ifobj->use_metadata && !is_metadata_correct(pkt, umem->buffer, addr)))
980                                 return TEST_FAILURE;
981
982                         if (ifobj->use_fill_ring)
983                                 *xsk_ring_prod__fill_addr(&umem->fq, idx_fq++) = orig;
984                         pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &pkts_sent);
985                 }
986
987                 if (ifobj->use_fill_ring)
988                         xsk_ring_prod__submit(&umem->fq, rcvd);
989                 if (ifobj->release_rx)
990                         xsk_ring_cons__release(&xsk->rx, rcvd);
991
992                 pthread_mutex_lock(&pacing_mutex);
993                 pkts_in_flight -= pkts_sent;
994                 if (pkts_in_flight < umem->num_frames)
995                         pthread_cond_signal(&pacing_cond);
996                 pthread_mutex_unlock(&pacing_mutex);
997                 pkts_sent = 0;
998         }
999
1000         return TEST_PASS;
1001 }
1002
1003 static int __send_pkts(struct ifobject *ifobject, u32 *pkt_nb, struct pollfd *fds,
1004                        bool timeout)
1005 {
1006         struct xsk_socket_info *xsk = ifobject->xsk;
1007         bool use_poll = ifobject->use_poll;
1008         u32 i, idx = 0, valid_pkts = 0;
1009         int ret;
1010
1011         while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE) {
1012                 if (use_poll) {
1013                         ret = poll(fds, 1, POLL_TMOUT);
1014                         if (timeout) {
1015                                 if (ret < 0) {
1016                                         ksft_print_msg("ERROR: [%s] Poll error %d\n",
1017                                                        __func__, errno);
1018                                         return TEST_FAILURE;
1019                                 }
1020                                 if (ret == 0)
1021                                         return TEST_PASS;
1022                                 break;
1023                         }
1024                         if (ret <= 0) {
1025                                 ksft_print_msg("ERROR: [%s] Poll error %d\n",
1026                                                __func__, errno);
1027                                 return TEST_FAILURE;
1028                         }
1029                 }
1030
1031                 complete_pkts(xsk, BATCH_SIZE);
1032         }
1033
1034         for (i = 0; i < BATCH_SIZE; i++) {
1035                 struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i);
1036                 struct pkt *pkt = pkt_generate(ifobject, *pkt_nb);
1037
1038                 if (!pkt)
1039                         break;
1040
1041                 tx_desc->addr = pkt->addr;
1042                 tx_desc->len = pkt->len;
1043                 (*pkt_nb)++;
1044                 if (pkt->valid)
1045                         valid_pkts++;
1046         }
1047
1048         pthread_mutex_lock(&pacing_mutex);
1049         pkts_in_flight += valid_pkts;
1050         /* pkts_in_flight might be negative if many invalid packets are sent */
1051         if (pkts_in_flight >= (int)(ifobject->umem->num_frames - BATCH_SIZE)) {
1052                 kick_tx(xsk);
1053                 pthread_cond_wait(&pacing_cond, &pacing_mutex);
1054         }
1055         pthread_mutex_unlock(&pacing_mutex);
1056
1057         xsk_ring_prod__submit(&xsk->tx, i);
1058         xsk->outstanding_tx += valid_pkts;
1059
1060         if (use_poll) {
1061                 ret = poll(fds, 1, POLL_TMOUT);
1062                 if (ret <= 0) {
1063                         if (ret == 0 && timeout)
1064                                 return TEST_PASS;
1065
1066                         ksft_print_msg("ERROR: [%s] Poll error %d\n", __func__, ret);
1067                         return TEST_FAILURE;
1068                 }
1069         }
1070
1071         if (!timeout) {
1072                 if (complete_pkts(xsk, i))
1073                         return TEST_FAILURE;
1074
1075                 usleep(10);
1076                 return TEST_PASS;
1077         }
1078
1079         return TEST_CONTINUE;
1080 }
1081
1082 static void wait_for_tx_completion(struct xsk_socket_info *xsk)
1083 {
1084         while (xsk->outstanding_tx)
1085                 complete_pkts(xsk, BATCH_SIZE);
1086 }
1087
1088 static int send_pkts(struct test_spec *test, struct ifobject *ifobject)
1089 {
1090         bool timeout = !is_umem_valid(test->ifobj_rx);
1091         struct pollfd fds = { };
1092         u32 pkt_cnt = 0, ret;
1093
1094         fds.fd = xsk_socket__fd(ifobject->xsk->xsk);
1095         fds.events = POLLOUT;
1096
1097         while (pkt_cnt < ifobject->pkt_stream->nb_pkts) {
1098                 ret = __send_pkts(ifobject, &pkt_cnt, &fds, timeout);
1099                 if ((ret || test->fail) && !timeout)
1100                         return TEST_FAILURE;
1101                 else if (ret == TEST_PASS && timeout)
1102                         return ret;
1103         }
1104
1105         wait_for_tx_completion(ifobject->xsk);
1106         return TEST_PASS;
1107 }
1108
1109 static int get_xsk_stats(struct xsk_socket *xsk, struct xdp_statistics *stats)
1110 {
1111         int fd = xsk_socket__fd(xsk), err;
1112         socklen_t optlen, expected_len;
1113
1114         optlen = sizeof(*stats);
1115         err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, stats, &optlen);
1116         if (err) {
1117                 ksft_print_msg("[%s] getsockopt(XDP_STATISTICS) error %u %s\n",
1118                                __func__, -err, strerror(-err));
1119                 return TEST_FAILURE;
1120         }
1121
1122         expected_len = sizeof(struct xdp_statistics);
1123         if (optlen != expected_len) {
1124                 ksft_print_msg("[%s] getsockopt optlen error. Expected: %u got: %u\n",
1125                                __func__, expected_len, optlen);
1126                 return TEST_FAILURE;
1127         }
1128
1129         return TEST_PASS;
1130 }
1131
1132 static int validate_rx_dropped(struct ifobject *ifobject)
1133 {
1134         struct xsk_socket *xsk = ifobject->xsk->xsk;
1135         struct xdp_statistics stats;
1136         int err;
1137
1138         kick_rx(ifobject->xsk);
1139
1140         err = get_xsk_stats(xsk, &stats);
1141         if (err)
1142                 return TEST_FAILURE;
1143
1144         if (stats.rx_dropped == ifobject->pkt_stream->nb_pkts / 2)
1145                 return TEST_PASS;
1146
1147         return TEST_FAILURE;
1148 }
1149
1150 static int validate_rx_full(struct ifobject *ifobject)
1151 {
1152         struct xsk_socket *xsk = ifobject->xsk->xsk;
1153         struct xdp_statistics stats;
1154         int err;
1155
1156         usleep(1000);
1157         kick_rx(ifobject->xsk);
1158
1159         err = get_xsk_stats(xsk, &stats);
1160         if (err)
1161                 return TEST_FAILURE;
1162
1163         if (stats.rx_ring_full)
1164                 return TEST_PASS;
1165
1166         return TEST_FAILURE;
1167 }
1168
1169 static int validate_fill_empty(struct ifobject *ifobject)
1170 {
1171         struct xsk_socket *xsk = ifobject->xsk->xsk;
1172         struct xdp_statistics stats;
1173         int err;
1174
1175         usleep(1000);
1176         kick_rx(ifobject->xsk);
1177
1178         err = get_xsk_stats(xsk, &stats);
1179         if (err)
1180                 return TEST_FAILURE;
1181
1182         if (stats.rx_fill_ring_empty_descs)
1183                 return TEST_PASS;
1184
1185         return TEST_FAILURE;
1186 }
1187
1188 static int validate_tx_invalid_descs(struct ifobject *ifobject)
1189 {
1190         struct xsk_socket *xsk = ifobject->xsk->xsk;
1191         int fd = xsk_socket__fd(xsk);
1192         struct xdp_statistics stats;
1193         socklen_t optlen;
1194         int err;
1195
1196         optlen = sizeof(stats);
1197         err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
1198         if (err) {
1199                 ksft_print_msg("[%s] getsockopt(XDP_STATISTICS) error %u %s\n",
1200                                __func__, -err, strerror(-err));
1201                 return TEST_FAILURE;
1202         }
1203
1204         if (stats.tx_invalid_descs != ifobject->pkt_stream->nb_pkts / 2) {
1205                 ksft_print_msg("[%s] tx_invalid_descs incorrect. Got [%u] expected [%u]\n",
1206                                __func__, stats.tx_invalid_descs, ifobject->pkt_stream->nb_pkts);
1207                 return TEST_FAILURE;
1208         }
1209
1210         return TEST_PASS;
1211 }
1212
1213 static void xsk_configure_socket(struct test_spec *test, struct ifobject *ifobject,
1214                                  struct xsk_umem_info *umem, bool tx)
1215 {
1216         int i, ret;
1217
1218         for (i = 0; i < test->nb_sockets; i++) {
1219                 bool shared = (ifobject->shared_umem && tx) ? true : !!i;
1220                 u32 ctr = 0;
1221
1222                 while (ctr++ < SOCK_RECONF_CTR) {
1223                         ret = __xsk_configure_socket(&ifobject->xsk_arr[i], umem,
1224                                                      ifobject, shared);
1225                         if (!ret)
1226                                 break;
1227
1228                         /* Retry if it fails as xsk_socket__create() is asynchronous */
1229                         if (ctr >= SOCK_RECONF_CTR)
1230                                 exit_with_error(-ret);
1231                         usleep(USLEEP_MAX);
1232                 }
1233                 if (ifobject->busy_poll)
1234                         enable_busy_poll(&ifobject->xsk_arr[i]);
1235         }
1236 }
1237
1238 static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobject)
1239 {
1240         xsk_configure_socket(test, ifobject, test->ifobj_rx->umem, true);
1241         ifobject->xsk = &ifobject->xsk_arr[0];
1242         ifobject->xskmap = test->ifobj_rx->xskmap;
1243         memcpy(ifobject->umem, test->ifobj_rx->umem, sizeof(struct xsk_umem_info));
1244 }
1245
1246 static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream)
1247 {
1248         u32 idx = 0, i, buffers_to_fill;
1249         int ret;
1250
1251         if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS)
1252                 buffers_to_fill = umem->num_frames;
1253         else
1254                 buffers_to_fill = XSK_RING_PROD__DEFAULT_NUM_DESCS;
1255
1256         ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx);
1257         if (ret != buffers_to_fill)
1258                 exit_with_error(ENOSPC);
1259         for (i = 0; i < buffers_to_fill; i++) {
1260                 u64 addr;
1261
1262                 if (pkt_stream->use_addr_for_fill) {
1263                         struct pkt *pkt = pkt_stream_get_pkt(pkt_stream, i);
1264
1265                         if (!pkt)
1266                                 break;
1267                         addr = pkt->addr;
1268                 } else {
1269                         addr = i * umem->frame_size;
1270                 }
1271
1272                 *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr;
1273         }
1274         xsk_ring_prod__submit(&umem->fq, i);
1275 }
1276
1277 static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject)
1278 {
1279         u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
1280         int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
1281         LIBBPF_OPTS(bpf_xdp_query_opts, opts);
1282         void *bufs;
1283         int ret;
1284
1285         if (ifobject->umem->unaligned_mode)
1286                 mmap_flags |= MAP_HUGETLB;
1287
1288         if (ifobject->shared_umem)
1289                 umem_sz *= 2;
1290
1291         bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
1292         if (bufs == MAP_FAILED)
1293                 exit_with_error(errno);
1294
1295         ret = xsk_configure_umem(ifobject->umem, bufs, umem_sz);
1296         if (ret)
1297                 exit_with_error(-ret);
1298
1299         xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream);
1300
1301         xsk_configure_socket(test, ifobject, ifobject->umem, false);
1302
1303         ifobject->xsk = &ifobject->xsk_arr[0];
1304
1305         if (!ifobject->rx_on)
1306                 return;
1307
1308         ret = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk);
1309         if (ret)
1310                 exit_with_error(errno);
1311 }
1312
1313 static void *worker_testapp_validate_tx(void *arg)
1314 {
1315         struct test_spec *test = (struct test_spec *)arg;
1316         struct ifobject *ifobject = test->ifobj_tx;
1317         int err;
1318
1319         if (test->current_step == 1) {
1320                 if (!ifobject->shared_umem)
1321                         thread_common_ops(test, ifobject);
1322                 else
1323                         thread_common_ops_tx(test, ifobject);
1324         }
1325
1326         print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,
1327                       ifobject->ifname);
1328         err = send_pkts(test, ifobject);
1329
1330         if (!err && ifobject->validation_func)
1331                 err = ifobject->validation_func(ifobject);
1332         if (err)
1333                 report_failure(test);
1334
1335         pthread_exit(NULL);
1336 }
1337
1338 static void *worker_testapp_validate_rx(void *arg)
1339 {
1340         struct test_spec *test = (struct test_spec *)arg;
1341         struct ifobject *ifobject = test->ifobj_rx;
1342         struct pollfd fds = { };
1343         int err;
1344
1345         if (test->current_step == 1) {
1346                 thread_common_ops(test, ifobject);
1347         } else {
1348                 xsk_clear_xskmap(ifobject->xskmap);
1349                 err = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk);
1350                 if (err) {
1351                         printf("Error: Failed to update xskmap, error %s\n", strerror(-err));
1352                         exit_with_error(-err);
1353                 }
1354         }
1355
1356         fds.fd = xsk_socket__fd(ifobject->xsk->xsk);
1357         fds.events = POLLIN;
1358
1359         pthread_barrier_wait(&barr);
1360
1361         err = receive_pkts(test, &fds);
1362
1363         if (!err && ifobject->validation_func)
1364                 err = ifobject->validation_func(ifobject);
1365         if (err) {
1366                 report_failure(test);
1367                 pthread_mutex_lock(&pacing_mutex);
1368                 pthread_cond_signal(&pacing_cond);
1369                 pthread_mutex_unlock(&pacing_mutex);
1370         }
1371
1372         pthread_exit(NULL);
1373 }
1374
1375 static void testapp_clean_xsk_umem(struct ifobject *ifobj)
1376 {
1377         u64 umem_sz = ifobj->umem->num_frames * ifobj->umem->frame_size;
1378
1379         if (ifobj->shared_umem)
1380                 umem_sz *= 2;
1381
1382         xsk_umem__delete(ifobj->umem->umem);
1383         munmap(ifobj->umem->buffer, umem_sz);
1384 }
1385
1386 static void handler(int signum)
1387 {
1388         pthread_exit(NULL);
1389 }
1390
1391 static bool xdp_prog_changed(struct test_spec *test, struct ifobject *ifobj)
1392 {
1393         return ifobj->xdp_prog != test->xdp_prog_rx || ifobj->mode != test->mode;
1394 }
1395
1396 static void xsk_reattach_xdp(struct ifobject *ifobj, struct bpf_program *xdp_prog,
1397                              struct bpf_map *xskmap, enum test_mode mode)
1398 {
1399         int err;
1400
1401         xsk_detach_xdp_program(ifobj->ifindex, mode_to_xdp_flags(ifobj->mode));
1402         err = xsk_attach_xdp_program(xdp_prog, ifobj->ifindex, mode_to_xdp_flags(mode));
1403         if (err) {
1404                 printf("Error attaching XDP program\n");
1405                 exit_with_error(-err);
1406         }
1407
1408         if (ifobj->mode != mode && (mode == TEST_MODE_DRV || mode == TEST_MODE_ZC))
1409                 if (!xsk_is_in_mode(ifobj->ifindex, XDP_FLAGS_DRV_MODE)) {
1410                         ksft_print_msg("ERROR: XDP prog not in DRV mode\n");
1411                         exit_with_error(EINVAL);
1412                 }
1413
1414         ifobj->xdp_prog = xdp_prog;
1415         ifobj->xskmap = xskmap;
1416         ifobj->mode = mode;
1417 }
1418
1419 static void xsk_attach_xdp_progs(struct test_spec *test, struct ifobject *ifobj_rx,
1420                                  struct ifobject *ifobj_tx)
1421 {
1422         if (xdp_prog_changed(test, ifobj_rx))
1423                 xsk_reattach_xdp(ifobj_rx, test->xdp_prog_rx, test->xskmap_rx, test->mode);
1424
1425         if (!ifobj_tx || ifobj_tx->shared_umem)
1426                 return;
1427
1428         if (xdp_prog_changed(test, ifobj_tx))
1429                 xsk_reattach_xdp(ifobj_tx, test->xdp_prog_tx, test->xskmap_tx, test->mode);
1430 }
1431
1432 static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *ifobj1,
1433                                       struct ifobject *ifobj2)
1434 {
1435         pthread_t t0, t1;
1436
1437         if (ifobj2)
1438                 if (pthread_barrier_init(&barr, NULL, 2))
1439                         exit_with_error(errno);
1440
1441         test->current_step++;
1442         pkt_stream_reset(ifobj1->pkt_stream);
1443         pkts_in_flight = 0;
1444
1445         signal(SIGUSR1, handler);
1446         /*Spawn RX thread */
1447         pthread_create(&t0, NULL, ifobj1->func_ptr, test);
1448
1449         if (ifobj2) {
1450                 pthread_barrier_wait(&barr);
1451                 if (pthread_barrier_destroy(&barr))
1452                         exit_with_error(errno);
1453
1454                 /*Spawn TX thread */
1455                 pthread_create(&t1, NULL, ifobj2->func_ptr, test);
1456
1457                 pthread_join(t1, NULL);
1458         }
1459
1460         if (!ifobj2)
1461                 pthread_kill(t0, SIGUSR1);
1462         else
1463                 pthread_join(t0, NULL);
1464
1465         if (test->total_steps == test->current_step || test->fail) {
1466                 if (ifobj2)
1467                         xsk_socket__delete(ifobj2->xsk->xsk);
1468                 xsk_socket__delete(ifobj1->xsk->xsk);
1469                 testapp_clean_xsk_umem(ifobj1);
1470                 if (ifobj2 && !ifobj2->shared_umem)
1471                         testapp_clean_xsk_umem(ifobj2);
1472         }
1473
1474         return !!test->fail;
1475 }
1476
1477 static int testapp_validate_traffic(struct test_spec *test)
1478 {
1479         struct ifobject *ifobj_rx = test->ifobj_rx;
1480         struct ifobject *ifobj_tx = test->ifobj_tx;
1481
1482         xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx);
1483         return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx);
1484 }
1485
1486 static int testapp_validate_traffic_single_thread(struct test_spec *test, struct ifobject *ifobj)
1487 {
1488         return __testapp_validate_traffic(test, ifobj, NULL);
1489 }
1490
1491 static void testapp_teardown(struct test_spec *test)
1492 {
1493         int i;
1494
1495         test_spec_set_name(test, "TEARDOWN");
1496         for (i = 0; i < MAX_TEARDOWN_ITER; i++) {
1497                 if (testapp_validate_traffic(test))
1498                         return;
1499                 test_spec_reset(test);
1500         }
1501 }
1502
1503 static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2)
1504 {
1505         thread_func_t tmp_func_ptr = (*ifobj1)->func_ptr;
1506         struct ifobject *tmp_ifobj = (*ifobj1);
1507
1508         (*ifobj1)->func_ptr = (*ifobj2)->func_ptr;
1509         (*ifobj2)->func_ptr = tmp_func_ptr;
1510
1511         *ifobj1 = *ifobj2;
1512         *ifobj2 = tmp_ifobj;
1513 }
1514
1515 static void testapp_bidi(struct test_spec *test)
1516 {
1517         test_spec_set_name(test, "BIDIRECTIONAL");
1518         test->ifobj_tx->rx_on = true;
1519         test->ifobj_rx->tx_on = true;
1520         test->total_steps = 2;
1521         if (testapp_validate_traffic(test))
1522                 return;
1523
1524         print_verbose("Switching Tx/Rx vectors\n");
1525         swap_directions(&test->ifobj_rx, &test->ifobj_tx);
1526         __testapp_validate_traffic(test, test->ifobj_rx, test->ifobj_tx);
1527
1528         swap_directions(&test->ifobj_rx, &test->ifobj_tx);
1529 }
1530
1531 static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx)
1532 {
1533         int ret;
1534
1535         xsk_socket__delete(ifobj_tx->xsk->xsk);
1536         xsk_socket__delete(ifobj_rx->xsk->xsk);
1537         ifobj_tx->xsk = &ifobj_tx->xsk_arr[1];
1538         ifobj_rx->xsk = &ifobj_rx->xsk_arr[1];
1539
1540         ret = xsk_update_xskmap(ifobj_rx->xskmap, ifobj_rx->xsk->xsk);
1541         if (ret)
1542                 exit_with_error(errno);
1543 }
1544
1545 static void testapp_bpf_res(struct test_spec *test)
1546 {
1547         test_spec_set_name(test, "BPF_RES");
1548         test->total_steps = 2;
1549         test->nb_sockets = 2;
1550         if (testapp_validate_traffic(test))
1551                 return;
1552
1553         swap_xsk_resources(test->ifobj_tx, test->ifobj_rx);
1554         testapp_validate_traffic(test);
1555 }
1556
1557 static void testapp_headroom(struct test_spec *test)
1558 {
1559         test_spec_set_name(test, "UMEM_HEADROOM");
1560         test->ifobj_rx->umem->frame_headroom = UMEM_HEADROOM_TEST_SIZE;
1561         testapp_validate_traffic(test);
1562 }
1563
1564 static void testapp_stats_rx_dropped(struct test_spec *test)
1565 {
1566         test_spec_set_name(test, "STAT_RX_DROPPED");
1567         pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0);
1568         test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
1569                 XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3;
1570         pkt_stream_receive_half(test);
1571         test->ifobj_rx->validation_func = validate_rx_dropped;
1572         testapp_validate_traffic(test);
1573 }
1574
1575 static void testapp_stats_tx_invalid_descs(struct test_spec *test)
1576 {
1577         test_spec_set_name(test, "STAT_TX_INVALID");
1578         pkt_stream_replace_half(test, XSK_UMEM__INVALID_FRAME_SIZE, 0);
1579         test->ifobj_tx->validation_func = validate_tx_invalid_descs;
1580         testapp_validate_traffic(test);
1581 }
1582
1583 static void testapp_stats_rx_full(struct test_spec *test)
1584 {
1585         test_spec_set_name(test, "STAT_RX_FULL");
1586         pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE);
1587         test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem,
1588                                                          DEFAULT_UMEM_BUFFERS, PKT_SIZE);
1589         if (!test->ifobj_rx->pkt_stream)
1590                 exit_with_error(ENOMEM);
1591
1592         test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS;
1593         test->ifobj_rx->release_rx = false;
1594         test->ifobj_rx->validation_func = validate_rx_full;
1595         testapp_validate_traffic(test);
1596 }
1597
1598 static void testapp_stats_fill_empty(struct test_spec *test)
1599 {
1600         test_spec_set_name(test, "STAT_RX_FILL_EMPTY");
1601         pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE);
1602         test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem,
1603                                                          DEFAULT_UMEM_BUFFERS, PKT_SIZE);
1604         if (!test->ifobj_rx->pkt_stream)
1605                 exit_with_error(ENOMEM);
1606
1607         test->ifobj_rx->use_fill_ring = false;
1608         test->ifobj_rx->validation_func = validate_fill_empty;
1609         testapp_validate_traffic(test);
1610 }
1611
1612 /* Simple test */
1613 static bool hugepages_present(struct ifobject *ifobject)
1614 {
1615         const size_t mmap_sz = 2 * ifobject->umem->num_frames * ifobject->umem->frame_size;
1616         void *bufs;
1617
1618         bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
1619                     MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
1620         if (bufs == MAP_FAILED)
1621                 return false;
1622
1623         munmap(bufs, mmap_sz);
1624         return true;
1625 }
1626
1627 static bool testapp_unaligned(struct test_spec *test)
1628 {
1629         if (!hugepages_present(test->ifobj_tx)) {
1630                 ksft_test_result_skip("No 2M huge pages present.\n");
1631                 return false;
1632         }
1633
1634         test_spec_set_name(test, "UNALIGNED_MODE");
1635         test->ifobj_tx->umem->unaligned_mode = true;
1636         test->ifobj_rx->umem->unaligned_mode = true;
1637         /* Let half of the packets straddle a buffer boundrary */
1638         pkt_stream_replace_half(test, PKT_SIZE, -PKT_SIZE / 2);
1639         test->ifobj_rx->pkt_stream->use_addr_for_fill = true;
1640         testapp_validate_traffic(test);
1641
1642         return true;
1643 }
1644
1645 static void testapp_single_pkt(struct test_spec *test)
1646 {
1647         struct pkt pkts[] = {{0x1000, PKT_SIZE, 0, true}};
1648
1649         pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts));
1650         testapp_validate_traffic(test);
1651 }
1652
1653 static void testapp_invalid_desc(struct test_spec *test)
1654 {
1655         struct pkt pkts[] = {
1656                 /* Zero packet address allowed */
1657                 {0, PKT_SIZE, 0, true},
1658                 /* Allowed packet */
1659                 {0x1000, PKT_SIZE, 0, true},
1660                 /* Straddling the start of umem */
1661                 {-2, PKT_SIZE, 0, false},
1662                 /* Packet too large */
1663                 {0x2000, XSK_UMEM__INVALID_FRAME_SIZE, 0, false},
1664                 /* After umem ends */
1665                 {UMEM_SIZE, PKT_SIZE, 0, false},
1666                 /* Straddle the end of umem */
1667                 {UMEM_SIZE - PKT_SIZE / 2, PKT_SIZE, 0, false},
1668                 /* Straddle a page boundrary */
1669                 {0x3000 - PKT_SIZE / 2, PKT_SIZE, 0, false},
1670                 /* Straddle a 2K boundrary */
1671                 {0x3800 - PKT_SIZE / 2, PKT_SIZE, 0, true},
1672                 /* Valid packet for synch so that something is received */
1673                 {0x4000, PKT_SIZE, 0, true}};
1674
1675         if (test->ifobj_tx->umem->unaligned_mode) {
1676                 /* Crossing a page boundrary allowed */
1677                 pkts[6].valid = true;
1678         }
1679         if (test->ifobj_tx->umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) {
1680                 /* Crossing a 2K frame size boundrary not allowed */
1681                 pkts[7].valid = false;
1682         }
1683
1684         if (test->ifobj_tx->shared_umem) {
1685                 pkts[4].addr += UMEM_SIZE;
1686                 pkts[5].addr += UMEM_SIZE;
1687         }
1688
1689         pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts));
1690         testapp_validate_traffic(test);
1691 }
1692
1693 static void testapp_xdp_drop(struct test_spec *test)
1694 {
1695         struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs;
1696         struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs;
1697
1698         test_spec_set_name(test, "XDP_DROP_HALF");
1699         test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_drop, skel_tx->progs.xsk_xdp_drop,
1700                                skel_rx->maps.xsk, skel_tx->maps.xsk);
1701
1702         pkt_stream_receive_half(test);
1703         testapp_validate_traffic(test);
1704 }
1705
1706 static void testapp_xdp_metadata_count(struct test_spec *test)
1707 {
1708         struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs;
1709         struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs;
1710         struct bpf_map *data_map;
1711         int count = 0;
1712         int key = 0;
1713
1714         test_spec_set_name(test, "XDP_METADATA_COUNT");
1715         test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_populate_metadata,
1716                                skel_tx->progs.xsk_xdp_populate_metadata,
1717                                skel_rx->maps.xsk, skel_tx->maps.xsk);
1718         test->ifobj_rx->use_metadata = true;
1719
1720         data_map = bpf_object__find_map_by_name(skel_rx->obj, "xsk_xdp_.bss");
1721         if (!data_map || !bpf_map__is_internal(data_map))
1722                 exit_with_error(ENOMEM);
1723
1724         if (bpf_map_update_elem(bpf_map__fd(data_map), &key, &count, BPF_ANY))
1725                 exit_with_error(errno);
1726
1727         testapp_validate_traffic(test);
1728 }
1729
1730 static void testapp_poll_txq_tmout(struct test_spec *test)
1731 {
1732         test_spec_set_name(test, "POLL_TXQ_FULL");
1733
1734         test->ifobj_tx->use_poll = true;
1735         /* create invalid frame by set umem frame_size and pkt length equal to 2048 */
1736         test->ifobj_tx->umem->frame_size = 2048;
1737         pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048);
1738         testapp_validate_traffic_single_thread(test, test->ifobj_tx);
1739 }
1740
1741 static void testapp_poll_rxq_tmout(struct test_spec *test)
1742 {
1743         test_spec_set_name(test, "POLL_RXQ_EMPTY");
1744         test->ifobj_rx->use_poll = true;
1745         testapp_validate_traffic_single_thread(test, test->ifobj_rx);
1746 }
1747
1748 static int xsk_load_xdp_programs(struct ifobject *ifobj)
1749 {
1750         ifobj->xdp_progs = xsk_xdp_progs__open_and_load();
1751         if (libbpf_get_error(ifobj->xdp_progs))
1752                 return libbpf_get_error(ifobj->xdp_progs);
1753
1754         return 0;
1755 }
1756
1757 static void xsk_unload_xdp_programs(struct ifobject *ifobj)
1758 {
1759         xsk_xdp_progs__destroy(ifobj->xdp_progs);
1760 }
1761
1762 static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac,
1763                        const char *dst_ip, const char *src_ip, const u16 dst_port,
1764                        const u16 src_port, thread_func_t func_ptr)
1765 {
1766         struct in_addr ip;
1767         int err;
1768
1769         memcpy(ifobj->dst_mac, dst_mac, ETH_ALEN);
1770         memcpy(ifobj->src_mac, src_mac, ETH_ALEN);
1771
1772         inet_aton(dst_ip, &ip);
1773         ifobj->dst_ip = ip.s_addr;
1774
1775         inet_aton(src_ip, &ip);
1776         ifobj->src_ip = ip.s_addr;
1777
1778         ifobj->dst_port = dst_port;
1779         ifobj->src_port = src_port;
1780
1781         ifobj->func_ptr = func_ptr;
1782
1783         err = xsk_load_xdp_programs(ifobj);
1784         if (err) {
1785                 printf("Error loading XDP program\n");
1786                 exit_with_error(err);
1787         }
1788 }
1789
1790 static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_type type)
1791 {
1792         switch (type) {
1793         case TEST_TYPE_STATS_RX_DROPPED:
1794                 if (mode == TEST_MODE_ZC) {
1795                         ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n");
1796                         return;
1797                 }
1798                 testapp_stats_rx_dropped(test);
1799                 break;
1800         case TEST_TYPE_STATS_TX_INVALID_DESCS:
1801                 testapp_stats_tx_invalid_descs(test);
1802                 break;
1803         case TEST_TYPE_STATS_RX_FULL:
1804                 testapp_stats_rx_full(test);
1805                 break;
1806         case TEST_TYPE_STATS_FILL_EMPTY:
1807                 testapp_stats_fill_empty(test);
1808                 break;
1809         case TEST_TYPE_TEARDOWN:
1810                 testapp_teardown(test);
1811                 break;
1812         case TEST_TYPE_BIDI:
1813                 testapp_bidi(test);
1814                 break;
1815         case TEST_TYPE_BPF_RES:
1816                 testapp_bpf_res(test);
1817                 break;
1818         case TEST_TYPE_RUN_TO_COMPLETION:
1819                 test_spec_set_name(test, "RUN_TO_COMPLETION");
1820                 testapp_validate_traffic(test);
1821                 break;
1822         case TEST_TYPE_RUN_TO_COMPLETION_SINGLE_PKT:
1823                 test_spec_set_name(test, "RUN_TO_COMPLETION_SINGLE_PKT");
1824                 testapp_single_pkt(test);
1825                 break;
1826         case TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME:
1827                 test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE");
1828                 test->ifobj_tx->umem->frame_size = 2048;
1829                 test->ifobj_rx->umem->frame_size = 2048;
1830                 pkt_stream_replace(test, DEFAULT_PKT_CNT, PKT_SIZE);
1831                 testapp_validate_traffic(test);
1832                 break;
1833         case TEST_TYPE_RX_POLL:
1834                 test->ifobj_rx->use_poll = true;
1835                 test_spec_set_name(test, "POLL_RX");
1836                 testapp_validate_traffic(test);
1837                 break;
1838         case TEST_TYPE_TX_POLL:
1839                 test->ifobj_tx->use_poll = true;
1840                 test_spec_set_name(test, "POLL_TX");
1841                 testapp_validate_traffic(test);
1842                 break;
1843         case TEST_TYPE_POLL_TXQ_TMOUT:
1844                 testapp_poll_txq_tmout(test);
1845                 break;
1846         case TEST_TYPE_POLL_RXQ_TMOUT:
1847                 testapp_poll_rxq_tmout(test);
1848                 break;
1849         case TEST_TYPE_ALIGNED_INV_DESC:
1850                 test_spec_set_name(test, "ALIGNED_INV_DESC");
1851                 testapp_invalid_desc(test);
1852                 break;
1853         case TEST_TYPE_ALIGNED_INV_DESC_2K_FRAME:
1854                 test_spec_set_name(test, "ALIGNED_INV_DESC_2K_FRAME_SIZE");
1855                 test->ifobj_tx->umem->frame_size = 2048;
1856                 test->ifobj_rx->umem->frame_size = 2048;
1857                 testapp_invalid_desc(test);
1858                 break;
1859         case TEST_TYPE_UNALIGNED_INV_DESC:
1860                 if (!hugepages_present(test->ifobj_tx)) {
1861                         ksft_test_result_skip("No 2M huge pages present.\n");
1862                         return;
1863                 }
1864                 test_spec_set_name(test, "UNALIGNED_INV_DESC");
1865                 test->ifobj_tx->umem->unaligned_mode = true;
1866                 test->ifobj_rx->umem->unaligned_mode = true;
1867                 testapp_invalid_desc(test);
1868                 break;
1869         case TEST_TYPE_UNALIGNED:
1870                 if (!testapp_unaligned(test))
1871                         return;
1872                 break;
1873         case TEST_TYPE_HEADROOM:
1874                 testapp_headroom(test);
1875                 break;
1876         case TEST_TYPE_XDP_DROP_HALF:
1877                 testapp_xdp_drop(test);
1878                 break;
1879         case TEST_TYPE_XDP_METADATA_COUNT:
1880                 testapp_xdp_metadata_count(test);
1881                 break;
1882         default:
1883                 break;
1884         }
1885
1886         if (!test->fail)
1887                 ksft_test_result_pass("PASS: %s %s%s\n", mode_string(test), busy_poll_string(test),
1888                                       test->name);
1889         pkt_stream_restore_default(test);
1890 }
1891
1892 static struct ifobject *ifobject_create(void)
1893 {
1894         struct ifobject *ifobj;
1895
1896         ifobj = calloc(1, sizeof(struct ifobject));
1897         if (!ifobj)
1898                 return NULL;
1899
1900         ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr));
1901         if (!ifobj->xsk_arr)
1902                 goto out_xsk_arr;
1903
1904         ifobj->umem = calloc(1, sizeof(*ifobj->umem));
1905         if (!ifobj->umem)
1906                 goto out_umem;
1907
1908         return ifobj;
1909
1910 out_umem:
1911         free(ifobj->xsk_arr);
1912 out_xsk_arr:
1913         free(ifobj);
1914         return NULL;
1915 }
1916
1917 static void ifobject_delete(struct ifobject *ifobj)
1918 {
1919         free(ifobj->umem);
1920         free(ifobj->xsk_arr);
1921         free(ifobj);
1922 }
1923
1924 static bool is_xdp_supported(int ifindex)
1925 {
1926         int flags = XDP_FLAGS_DRV_MODE;
1927
1928         LIBBPF_OPTS(bpf_link_create_opts, opts, .flags = flags);
1929         struct bpf_insn insns[2] = {
1930                 BPF_MOV64_IMM(BPF_REG_0, XDP_PASS),
1931                 BPF_EXIT_INSN()
1932         };
1933         int prog_fd, insn_cnt = ARRAY_SIZE(insns);
1934         int err;
1935
1936         prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL);
1937         if (prog_fd < 0)
1938                 return false;
1939
1940         err = bpf_xdp_attach(ifindex, prog_fd, flags, NULL);
1941         if (err) {
1942                 close(prog_fd);
1943                 return false;
1944         }
1945
1946         bpf_xdp_detach(ifindex, flags, NULL);
1947         close(prog_fd);
1948
1949         return true;
1950 }
1951
1952 int main(int argc, char **argv)
1953 {
1954         struct pkt_stream *rx_pkt_stream_default;
1955         struct pkt_stream *tx_pkt_stream_default;
1956         struct ifobject *ifobj_tx, *ifobj_rx;
1957         int modes = TEST_MODE_SKB + 1;
1958         u32 i, j, failed_tests = 0;
1959         struct test_spec test;
1960         bool shared_netdev;
1961
1962         /* Use libbpf 1.0 API mode */
1963         libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
1964
1965         ifobj_tx = ifobject_create();
1966         if (!ifobj_tx)
1967                 exit_with_error(ENOMEM);
1968         ifobj_rx = ifobject_create();
1969         if (!ifobj_rx)
1970                 exit_with_error(ENOMEM);
1971
1972         setlocale(LC_ALL, "");
1973
1974         parse_command_line(ifobj_tx, ifobj_rx, argc, argv);
1975
1976         shared_netdev = (ifobj_tx->ifindex == ifobj_rx->ifindex);
1977         ifobj_tx->shared_umem = shared_netdev;
1978         ifobj_rx->shared_umem = shared_netdev;
1979
1980         if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx)) {
1981                 usage(basename(argv[0]));
1982                 ksft_exit_xfail();
1983         }
1984
1985         if (is_xdp_supported(ifobj_tx->ifindex)) {
1986                 modes++;
1987                 if (ifobj_zc_avail(ifobj_tx))
1988                         modes++;
1989         }
1990
1991         init_iface(ifobj_rx, MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2,
1992                    worker_testapp_validate_rx);
1993         init_iface(ifobj_tx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1,
1994                    worker_testapp_validate_tx);
1995
1996         test_spec_init(&test, ifobj_tx, ifobj_rx, 0);
1997         tx_pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
1998         rx_pkt_stream_default = pkt_stream_generate(ifobj_rx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
1999         if (!tx_pkt_stream_default || !rx_pkt_stream_default)
2000                 exit_with_error(ENOMEM);
2001         test.tx_pkt_stream_default = tx_pkt_stream_default;
2002         test.rx_pkt_stream_default = rx_pkt_stream_default;
2003
2004         ksft_set_plan(modes * TEST_TYPE_MAX);
2005
2006         for (i = 0; i < modes; i++) {
2007                 for (j = 0; j < TEST_TYPE_MAX; j++) {
2008                         test_spec_init(&test, ifobj_tx, ifobj_rx, i);
2009                         run_pkt_test(&test, i, j);
2010                         usleep(USLEEP_MAX);
2011
2012                         if (test.fail)
2013                                 failed_tests++;
2014                 }
2015         }
2016
2017         pkt_stream_delete(tx_pkt_stream_default);
2018         pkt_stream_delete(rx_pkt_stream_default);
2019         xsk_unload_xdp_programs(ifobj_tx);
2020         xsk_unload_xdp_programs(ifobj_rx);
2021         ifobject_delete(ifobj_tx);
2022         ifobject_delete(ifobj_rx);
2023
2024         if (failed_tests)
2025                 ksft_exit_fail();
2026         else
2027                 ksft_exit_pass();
2028 }