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