1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2020 Intel Corporation. */
5 * Some functions in this program are taken from
6 * Linux kernel samples/bpf/xdpsock* and modified
9 * See test_xsk.sh for detailed information on test topology
10 * and prerequisite network setup.
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.
18 * These selftests test AF_XDP SKB and Native/DRV modes using veth
19 * Virtual Ethernet interfaces.
21 * For each mode, the following tests are run:
22 * a. nopoll - soft-irq processing
23 * b. poll - using poll() syscall
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
32 * Trigger some error conditions and ensure that the appropriate statistics
33 * are incremented. Within this test, the following statistics are tested:
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.
38 * Set the 'len' field of tx descriptors to an invalid value (umem frame
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
53 * - Single process spawns two threads: Tx and Rx
54 * - Each of these two threads attach to a veth interface within their assigned
56 * - Each thread Creates one AF_XDP socket connected to a unique umem for each
58 * - Tx thread Transmits 10k packets from veth<xxxx> to veth<yyyy>
59 * - Rx thread verifies if all 10k packets were received and delivered in-order,
60 * and have the right content
62 * Enable/disable packet dump mode:
63 * --------------------------
64 * To enable L2 - L4 headers and payload dump of each packet on STDOUT, add
65 * parameter -D to params array in test_xsk.sh, i.e. params=("-S" "-D")
72 #include <asm/barrier.h>
73 #include <linux/if_link.h>
74 #include <linux/if_ether.h>
76 #include <linux/udp.h>
77 #include <arpa/inet.h>
89 #include <sys/resource.h>
90 #include <sys/types.h>
91 #include <sys/queue.h>
94 #include <stdatomic.h>
96 #include "xdpxceiver.h"
97 #include "../kselftest.h"
99 static const char *MAC1 = "\x00\x0A\x56\x9E\xEE\x62";
100 static const char *MAC2 = "\x00\x0A\x56\x9E\xEE\x61";
101 static const char *IP1 = "192.168.100.162";
102 static const char *IP2 = "192.168.100.161";
103 static const u16 UDP_PORT1 = 2020;
104 static const u16 UDP_PORT2 = 2121;
106 static void __exit_with_error(int error, const char *file, const char *func, int line)
108 ksft_test_result_fail("[%s:%s:%i]: ERROR: %d/\"%s\"\n", file, func, line, error,
113 #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__)
115 #define print_ksft_result(test)\
116 (ksft_test_result_pass("PASS: %s %s\n", configured_mode ? "DRV" : "SKB", \
119 static void memset32_htonl(void *dest, u32 val, u32 size)
121 u32 *ptr = (u32 *)dest;
126 for (i = 0; i < (size & (~0x3)); i += 4)
131 * Fold a partial checksum
132 * This function code has been taken from
133 * Linux kernel include/asm-generic/checksum.h
135 static __u16 csum_fold(__u32 csum)
137 u32 sum = (__force u32)csum;
139 sum = (sum & 0xffff) + (sum >> 16);
140 sum = (sum & 0xffff) + (sum >> 16);
141 return (__force __u16)~sum;
145 * This function code has been taken from
146 * Linux kernel lib/checksum.c
148 static u32 from64to32(u64 x)
150 /* add up 32-bit and 32-bit for 32+c bit */
151 x = (x & 0xffffffff) + (x >> 32);
153 x = (x & 0xffffffff) + (x >> 32);
158 * This function code has been taken from
159 * Linux kernel lib/checksum.c
161 static __u32 csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum)
163 unsigned long long s = (__force u32)sum;
165 s += (__force u32)saddr;
166 s += (__force u32)daddr;
167 #ifdef __BIG_ENDIAN__
170 s += (proto + len) << 8;
172 return (__force __u32)from64to32(s);
176 * This function has been taken from
177 * Linux kernel include/asm-generic/checksum.h
179 static __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum)
181 return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
184 static u16 udp_csum(u32 saddr, u32 daddr, u32 len, u8 proto, u16 *udp_pkt)
189 /* udp hdr and data */
190 for (; cnt < len; cnt += 2)
191 csum += udp_pkt[cnt >> 1];
193 return csum_tcpudp_magic(saddr, daddr, len, proto, csum);
196 static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr)
198 memcpy(eth_hdr->h_dest, ifobject->dst_mac, ETH_ALEN);
199 memcpy(eth_hdr->h_source, ifobject->src_mac, ETH_ALEN);
200 eth_hdr->h_proto = htons(ETH_P_IP);
203 static void gen_ip_hdr(struct ifobject *ifobject, struct iphdr *ip_hdr)
205 ip_hdr->version = IP_PKT_VER;
207 ip_hdr->tos = IP_PKT_TOS;
208 ip_hdr->tot_len = htons(IP_PKT_SIZE);
210 ip_hdr->frag_off = 0;
211 ip_hdr->ttl = IPDEFTTL;
212 ip_hdr->protocol = IPPROTO_UDP;
213 ip_hdr->saddr = ifobject->src_ip;
214 ip_hdr->daddr = ifobject->dst_ip;
218 static void gen_udp_hdr(u32 payload, void *pkt, struct ifobject *ifobject,
219 struct udphdr *udp_hdr)
221 udp_hdr->source = htons(ifobject->src_port);
222 udp_hdr->dest = htons(ifobject->dst_port);
223 udp_hdr->len = htons(UDP_PKT_SIZE);
224 memset32_htonl(pkt + PKT_HDR_SIZE, payload, UDP_PKT_DATA_SIZE);
227 static void gen_udp_csum(struct udphdr *udp_hdr, struct iphdr *ip_hdr)
231 udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE, IPPROTO_UDP, (u16 *)udp_hdr);
234 static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size, int idx)
236 struct xsk_umem_config cfg = {
237 .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
238 .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
239 .frame_size = umem->frame_size,
240 .frame_headroom = umem->frame_headroom,
241 .flags = XSK_UMEM__DEFAULT_FLAGS
245 ret = xsk_umem__create(&umem->umem, buffer, size,
246 &umem->fq, &umem->cq, &cfg);
250 umem->buffer = buffer;
254 static void xsk_populate_fill_ring(struct xsk_umem_info *umem)
259 ret = xsk_ring_prod__reserve(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
260 if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
261 exit_with_error(-ret);
262 for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
263 *xsk_ring_prod__fill_addr(&umem->fq, idx++) = i * umem->frame_size;
264 xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
267 static int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,
268 struct ifobject *ifobject, u32 qid)
270 struct xsk_socket_config cfg;
271 struct xsk_ring_cons *rxr;
272 struct xsk_ring_prod *txr;
275 cfg.rx_size = xsk->rxqsize;
276 cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
277 cfg.libbpf_flags = 0;
278 cfg.xdp_flags = xdp_flags;
279 cfg.bind_flags = xdp_bind_flags;
281 txr = ifobject->tx_on ? &xsk->tx : NULL;
282 rxr = ifobject->rx_on ? &xsk->rx : NULL;
283 return xsk_socket__create(&xsk->xsk, ifobject->ifname, qid, umem->umem, rxr, txr, &cfg);
286 static struct option long_options[] = {
287 {"interface", required_argument, 0, 'i'},
288 {"queue", optional_argument, 0, 'q'},
289 {"dump-pkts", optional_argument, 0, 'D'},
290 {"verbose", no_argument, 0, 'v'},
294 static void usage(const char *prog)
297 " Usage: %s [OPTIONS]\n"
299 " -i, --interface Use interface\n"
300 " -q, --queue=n Use queue n (default 0)\n"
301 " -D, --dump-pkts Dump packets L2 - L5\n"
302 " -v, --verbose Verbose output\n";
304 ksft_print_msg(str, prog);
307 static int switch_namespace(const char *nsname)
309 char fqns[26] = "/var/run/netns/";
312 if (!nsname || strlen(nsname) == 0)
315 strncat(fqns, nsname, sizeof(fqns) - strlen(fqns) - 1);
316 nsfd = open(fqns, O_RDONLY);
319 exit_with_error(errno);
321 if (setns(nsfd, 0) == -1)
322 exit_with_error(errno);
324 print_verbose("NS switched: %s\n", nsname);
329 static bool validate_interface(struct ifobject *ifobj)
331 if (!strcmp(ifobj->ifname, ""))
336 static void parse_command_line(struct test_spec *test, int argc, char **argv)
338 struct ifobject *ifobj;
339 u32 interface_nb = 0;
347 c = getopt_long(argc, argv, "i:Dv", long_options, &option_index);
353 if (interface_nb == 0)
354 ifobj = test->ifobj_tx;
355 else if (interface_nb == 1)
356 ifobj = test->ifobj_rx;
360 sptr = strndupa(optarg, strlen(optarg));
361 memcpy(ifobj->ifname, strsep(&sptr, ","), MAX_INTERFACE_NAME_CHARS);
362 token = strsep(&sptr, ",");
364 memcpy(ifobj->nsname, token, MAX_INTERFACES_NAMESPACE_CHARS);
374 usage(basename(argv[0]));
380 static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
381 struct ifobject *ifobj_rx)
385 for (i = 0; i < MAX_INTERFACES; i++) {
386 struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
388 ifobj->umem = &ifobj->umem_arr[0];
389 ifobj->xsk = &ifobj->xsk_arr[0];
390 ifobj->use_poll = false;
393 ifobj->rx_on = false;
397 ifobj->tx_on = false;
400 for (j = 0; j < MAX_SOCKETS; j++) {
401 memset(&ifobj->umem_arr[j], 0, sizeof(ifobj->umem_arr[j]));
402 memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j]));
403 ifobj->umem_arr[j].num_frames = DEFAULT_PKT_CNT / 4;
404 ifobj->umem_arr[j].frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
405 ifobj->xsk_arr[j].rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
409 test->ifobj_tx = ifobj_tx;
410 test->ifobj_rx = ifobj_rx;
413 static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
414 struct ifobject *ifobj_rx)
416 memset(test, 0, sizeof(*test));
417 __test_spec_init(test, ifobj_tx, ifobj_rx);
420 static void test_spec_reset(struct test_spec *test)
422 __test_spec_init(test, test->ifobj_tx, test->ifobj_rx);
425 static void test_spec_set_name(struct test_spec *test, const char *name)
427 strncpy(test->name, name, MAX_TEST_NAME_SIZE);
430 static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb)
432 if (pkt_nb >= pkt_stream->nb_pkts)
435 return &pkt_stream->pkts[pkt_nb];
438 static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len)
440 struct pkt_stream *pkt_stream;
443 pkt_stream = malloc(sizeof(*pkt_stream));
445 exit_with_error(ENOMEM);
447 pkt_stream->pkts = calloc(nb_pkts, sizeof(*pkt_stream->pkts));
448 if (!pkt_stream->pkts)
449 exit_with_error(ENOMEM);
451 pkt_stream->nb_pkts = nb_pkts;
452 for (i = 0; i < nb_pkts; i++) {
453 pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size;
454 pkt_stream->pkts[i].len = pkt_len;
455 pkt_stream->pkts[i].payload = i;
461 static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb)
463 struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb);
464 struct udphdr *udp_hdr;
465 struct ethhdr *eth_hdr;
466 struct iphdr *ip_hdr;
472 data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr);
473 udp_hdr = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
474 ip_hdr = (struct iphdr *)(data + sizeof(struct ethhdr));
475 eth_hdr = (struct ethhdr *)data;
477 gen_udp_hdr(pkt_nb, data, ifobject, udp_hdr);
478 gen_ip_hdr(ifobject, ip_hdr);
479 gen_udp_csum(udp_hdr, ip_hdr);
480 gen_eth_hdr(ifobject, eth_hdr);
485 static void pkt_dump(void *pkt, u32 len)
487 char s[INET_ADDRSTRLEN];
488 struct ethhdr *ethhdr;
489 struct udphdr *udphdr;
494 iphdr = pkt + sizeof(*ethhdr);
495 udphdr = pkt + sizeof(*ethhdr) + sizeof(*iphdr);
497 /*extract L2 frame */
498 fprintf(stdout, "DEBUG>> L2: dst mac: ");
499 for (i = 0; i < ETH_ALEN; i++)
500 fprintf(stdout, "%02X", ethhdr->h_dest[i]);
502 fprintf(stdout, "\nDEBUG>> L2: src mac: ");
503 for (i = 0; i < ETH_ALEN; i++)
504 fprintf(stdout, "%02X", ethhdr->h_source[i]);
506 /*extract L3 frame */
507 fprintf(stdout, "\nDEBUG>> L3: ip_hdr->ihl: %02X\n", iphdr->ihl);
508 fprintf(stdout, "DEBUG>> L3: ip_hdr->saddr: %s\n",
509 inet_ntop(AF_INET, &iphdr->saddr, s, sizeof(s)));
510 fprintf(stdout, "DEBUG>> L3: ip_hdr->daddr: %s\n",
511 inet_ntop(AF_INET, &iphdr->daddr, s, sizeof(s)));
512 /*extract L4 frame */
513 fprintf(stdout, "DEBUG>> L4: udp_hdr->src: %d\n", ntohs(udphdr->source));
514 fprintf(stdout, "DEBUG>> L4: udp_hdr->dst: %d\n", ntohs(udphdr->dest));
515 /*extract L5 frame */
516 payload = *((uint32_t *)(pkt + PKT_HDR_SIZE));
518 fprintf(stdout, "DEBUG>> L5: payload: %d\n", payload);
519 fprintf(stdout, "---------------------------------------\n");
522 static bool is_pkt_valid(struct pkt *pkt, void *buffer, const struct xdp_desc *desc)
524 void *data = xsk_umem__get_data(buffer, desc->addr);
525 struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr));
528 ksft_test_result_fail("ERROR: [%s] too many packets received\n", __func__);
532 if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) {
533 u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE)));
535 if (opt_pkt_dump && test_type != TEST_TYPE_STATS)
536 pkt_dump(data, PKT_SIZE);
538 if (pkt->len != desc->len) {
539 ksft_test_result_fail
540 ("ERROR: [%s] expected length [%d], got length [%d]\n",
541 __func__, pkt->len, desc->len);
545 if (pkt->payload != seqnum) {
546 ksft_test_result_fail
547 ("ERROR: [%s] expected seqnum [%d], got seqnum [%d]\n",
548 __func__, pkt->payload, seqnum);
552 ksft_print_msg("Invalid frame received: ");
553 ksft_print_msg("[IP_PKT_VER: %02X], [IP_PKT_TOS: %02X]\n", iphdr->version,
561 static void kick_tx(struct xsk_socket_info *xsk)
565 ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0);
566 if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN)
568 exit_with_error(errno);
571 static void complete_pkts(struct xsk_socket_info *xsk, int batch_size)
576 if (!xsk->outstanding_tx)
579 if (xsk_ring_prod__needs_wakeup(&xsk->tx))
582 rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx);
584 xsk_ring_cons__release(&xsk->umem->cq, rcvd);
585 xsk->outstanding_tx -= rcvd;
589 static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *xsk,
592 u32 idx_rx = 0, idx_fq = 0, rcvd, i, pkt_count = 0;
596 pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
598 rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx);
600 if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
601 ret = poll(fds, 1, POLL_TMOUT);
603 exit_with_error(-ret);
608 ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
609 while (ret != rcvd) {
611 exit_with_error(-ret);
612 if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
613 ret = poll(fds, 1, POLL_TMOUT);
615 exit_with_error(-ret);
617 ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
620 for (i = 0; i < rcvd; i++) {
621 const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++);
622 u64 addr = desc->addr, orig;
624 orig = xsk_umem__extract_addr(addr);
625 addr = xsk_umem__add_offset_to_addr(addr);
626 if (!is_pkt_valid(pkt, xsk->umem->buffer, desc))
629 *xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = orig;
630 pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
633 xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
634 xsk_ring_cons__release(&xsk->rx, rcvd);
638 static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb)
640 struct xsk_socket_info *xsk = ifobject->xsk;
643 while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE)
644 complete_pkts(xsk, BATCH_SIZE);
646 for (i = 0; i < BATCH_SIZE; i++) {
647 struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i);
648 struct pkt *pkt = pkt_generate(ifobject, pkt_nb);
653 tx_desc->addr = pkt->addr;
654 tx_desc->len = pkt->len;
658 xsk_ring_prod__submit(&xsk->tx, i);
659 if (stat_test_type != STAT_TEST_TX_INVALID)
660 xsk->outstanding_tx += i;
661 else if (xsk_ring_prod__needs_wakeup(&xsk->tx))
663 complete_pkts(xsk, i);
668 static void wait_for_tx_completion(struct xsk_socket_info *xsk)
670 while (xsk->outstanding_tx)
671 complete_pkts(xsk, BATCH_SIZE);
674 static void send_pkts(struct ifobject *ifobject)
676 struct pollfd fds[MAX_SOCKS] = { };
679 fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
680 fds[0].events = POLLOUT;
682 while (pkt_cnt < ifobject->pkt_stream->nb_pkts) {
685 if (ifobject->use_poll) {
688 ret = poll(fds, 1, POLL_TMOUT);
692 if (!(fds[0].revents & POLLOUT))
696 sent = __send_pkts(ifobject, pkt_cnt);
701 wait_for_tx_completion(ifobject->xsk);
704 static bool rx_stats_are_valid(struct ifobject *ifobject)
706 u32 xsk_stat = 0, expected_stat = ifobject->pkt_stream->nb_pkts;
707 struct xsk_socket *xsk = ifobject->xsk->xsk;
708 int fd = xsk_socket__fd(xsk);
709 struct xdp_statistics stats;
713 optlen = sizeof(stats);
714 err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
716 ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
717 __func__, -err, strerror(-err));
721 if (optlen == sizeof(struct xdp_statistics)) {
722 switch (stat_test_type) {
723 case STAT_TEST_RX_DROPPED:
724 xsk_stat = stats.rx_dropped;
726 case STAT_TEST_TX_INVALID:
728 case STAT_TEST_RX_FULL:
729 xsk_stat = stats.rx_ring_full;
730 expected_stat -= RX_FULL_RXQSIZE;
732 case STAT_TEST_RX_FILL_EMPTY:
733 xsk_stat = stats.rx_fill_ring_empty_descs;
739 if (xsk_stat == expected_stat)
746 static void tx_stats_validate(struct ifobject *ifobject)
748 struct xsk_socket *xsk = ifobject->xsk->xsk;
749 int fd = xsk_socket__fd(xsk);
750 struct xdp_statistics stats;
754 optlen = sizeof(stats);
755 err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
757 ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
758 __func__, -err, strerror(-err));
762 if (stats.tx_invalid_descs == ifobject->pkt_stream->nb_pkts)
765 ksft_test_result_fail("ERROR: [%s] tx_invalid_descs incorrect. Got [%u] expected [%u]\n",
766 __func__, stats.tx_invalid_descs, ifobject->pkt_stream->nb_pkts);
769 static void thread_common_ops(struct ifobject *ifobject, void *bufs)
771 u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
772 int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
773 size_t mmap_sz = umem_sz;
776 ifobject->ns_fd = switch_namespace(ifobject->nsname);
778 if (test_type == TEST_TYPE_BPF_RES)
781 bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
782 if (bufs == MAP_FAILED)
783 exit_with_error(errno);
785 while (ctr++ < SOCK_RECONF_CTR) {
786 ret = xsk_configure_umem(&ifobject->umem_arr[0], bufs, umem_sz, 0);
788 exit_with_error(-ret);
790 ret = xsk_configure_socket(&ifobject->xsk_arr[0], &ifobject->umem_arr[0],
795 /* Retry Create Socket if it fails as xsk_socket__create() is asynchronous */
796 if (ctr >= SOCK_RECONF_CTR)
797 exit_with_error(-ret);
801 if (test_type == TEST_TYPE_BPF_RES) {
802 ret = xsk_configure_umem(&ifobject->umem_arr[1], (u8 *)bufs + umem_sz, umem_sz, 1);
804 exit_with_error(-ret);
806 ret = xsk_configure_socket(&ifobject->xsk_arr[1], &ifobject->umem_arr[1],
809 exit_with_error(-ret);
812 ifobject->umem = &ifobject->umem_arr[0];
813 ifobject->xsk = &ifobject->xsk_arr[0];
816 static bool testapp_is_test_two_stepped(void)
818 return (test_type != TEST_TYPE_BIDI && test_type != TEST_TYPE_BPF_RES) || second_step;
821 static void testapp_cleanup_xsk_res(struct ifobject *ifobj)
823 if (testapp_is_test_two_stepped()) {
824 xsk_socket__delete(ifobj->xsk->xsk);
825 (void)xsk_umem__delete(ifobj->umem->umem);
829 static void *worker_testapp_validate_tx(void *arg)
831 struct ifobject *ifobject = (struct ifobject *)arg;
835 thread_common_ops(ifobject, bufs);
837 print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,
841 if (stat_test_type == STAT_TEST_TX_INVALID)
842 tx_stats_validate(ifobject);
844 testapp_cleanup_xsk_res(ifobject);
848 static void *worker_testapp_validate_rx(void *arg)
850 struct ifobject *ifobject = (struct ifobject *)arg;
851 struct pollfd fds[MAX_SOCKS] = { };
855 thread_common_ops(ifobject, bufs);
857 if (stat_test_type != STAT_TEST_RX_FILL_EMPTY)
858 xsk_populate_fill_ring(ifobject->umem);
860 fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
861 fds[0].events = POLLIN;
863 pthread_barrier_wait(&barr);
865 if (test_type == TEST_TYPE_STATS)
866 while (!rx_stats_are_valid(ifobject))
869 receive_pkts(ifobject->pkt_stream, ifobject->xsk, fds);
871 if (test_type == TEST_TYPE_TEARDOWN)
872 print_verbose("Destroying socket\n");
874 testapp_cleanup_xsk_res(ifobject);
878 static void testapp_validate_traffic(struct test_spec *test)
880 struct ifobject *ifobj_tx = test->ifobj_tx;
881 struct ifobject *ifobj_rx = test->ifobj_rx;
882 struct pkt_stream *pkt_stream;
884 if (pthread_barrier_init(&barr, NULL, 2))
885 exit_with_error(errno);
887 if (stat_test_type == STAT_TEST_TX_INVALID)
888 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, DEFAULT_PKT_CNT,
889 XSK_UMEM__INVALID_FRAME_SIZE);
891 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
892 ifobj_tx->pkt_stream = pkt_stream;
893 ifobj_rx->pkt_stream = pkt_stream;
896 pthread_create(&t0, NULL, ifobj_rx->func_ptr, ifobj_rx);
898 pthread_barrier_wait(&barr);
899 if (pthread_barrier_destroy(&barr))
900 exit_with_error(errno);
903 pthread_create(&t1, NULL, ifobj_tx->func_ptr, ifobj_tx);
905 pthread_join(t1, NULL);
906 pthread_join(t0, NULL);
909 static void testapp_teardown(struct test_spec *test)
913 test_spec_set_name(test, "TEARDOWN");
914 for (i = 0; i < MAX_TEARDOWN_ITER; i++) {
915 testapp_validate_traffic(test);
916 test_spec_reset(test);
920 static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2)
922 thread_func_t tmp_func_ptr = (*ifobj1)->func_ptr;
923 struct ifobject *tmp_ifobj = (*ifobj1);
925 (*ifobj1)->func_ptr = (*ifobj2)->func_ptr;
926 (*ifobj2)->func_ptr = tmp_func_ptr;
932 static void testapp_bidi(struct test_spec *test)
934 test_spec_set_name(test, "BIDIRECTIONAL");
935 test->ifobj_tx->rx_on = true;
936 test->ifobj_rx->tx_on = true;
937 for (int i = 0; i < MAX_BIDI_ITER; i++) {
938 print_verbose("Creating socket\n");
939 testapp_validate_traffic(test);
941 print_verbose("Switching Tx/Rx vectors\n");
942 swap_directions(&test->ifobj_rx, &test->ifobj_tx);
947 swap_directions(&test->ifobj_rx, &test->ifobj_tx);
950 static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx)
952 xsk_socket__delete(ifobj_tx->xsk->xsk);
953 xsk_umem__delete(ifobj_tx->umem->umem);
954 xsk_socket__delete(ifobj_rx->xsk->xsk);
955 xsk_umem__delete(ifobj_rx->umem->umem);
956 ifobj_tx->umem = &ifobj_tx->umem_arr[1];
957 ifobj_tx->xsk = &ifobj_tx->xsk_arr[1];
958 ifobj_rx->umem = &ifobj_rx->umem_arr[1];
959 ifobj_rx->xsk = &ifobj_rx->xsk_arr[1];
962 static void testapp_bpf_res(struct test_spec *test)
966 test_spec_set_name(test, "BPF_RES");
967 for (i = 0; i < MAX_BPF_ITER; i++) {
968 print_verbose("Creating socket\n");
969 testapp_validate_traffic(test);
971 swap_xsk_resources(test->ifobj_tx, test->ifobj_rx);
976 static void testapp_stats(struct test_spec *test)
978 for (int i = 0; i < STAT_TEST_TYPE_MAX; i++) {
979 test_spec_reset(test);
982 switch (stat_test_type) {
983 case STAT_TEST_RX_DROPPED:
984 test_spec_set_name(test, "STAT_RX_DROPPED");
985 test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
986 XDP_PACKET_HEADROOM - 1;
988 case STAT_TEST_RX_FULL:
989 test_spec_set_name(test, "STAT_RX_FULL");
990 test->ifobj_rx->xsk->rxqsize = RX_FULL_RXQSIZE;
992 case STAT_TEST_TX_INVALID:
993 test_spec_set_name(test, "STAT_TX_INVALID");
995 case STAT_TEST_RX_FILL_EMPTY:
996 test_spec_set_name(test, "STAT_RX_FILL_EMPTY");
1001 testapp_validate_traffic(test);
1004 /* To only see the whole stat set being completed unless an individual test fails. */
1005 test_spec_set_name(test, "STATS");
1008 static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac,
1009 const char *dst_ip, const char *src_ip, const u16 dst_port,
1010 const u16 src_port, thread_func_t func_ptr)
1014 memcpy(ifobj->dst_mac, dst_mac, ETH_ALEN);
1015 memcpy(ifobj->src_mac, src_mac, ETH_ALEN);
1017 inet_aton(dst_ip, &ip);
1018 ifobj->dst_ip = ip.s_addr;
1020 inet_aton(src_ip, &ip);
1021 ifobj->src_ip = ip.s_addr;
1023 ifobj->dst_port = dst_port;
1024 ifobj->src_port = src_port;
1026 ifobj->func_ptr = func_ptr;
1029 static void run_pkt_test(struct test_spec *test, int mode, int type)
1033 /* reset defaults after potential previous test */
1034 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
1036 stat_test_type = -1;
1038 configured_mode = mode;
1041 case (TEST_MODE_SKB):
1042 xdp_flags |= XDP_FLAGS_SKB_MODE;
1044 case (TEST_MODE_DRV):
1045 xdp_flags |= XDP_FLAGS_DRV_MODE;
1051 switch (test_type) {
1052 case TEST_TYPE_STATS:
1053 testapp_stats(test);
1055 case TEST_TYPE_TEARDOWN:
1056 testapp_teardown(test);
1058 case TEST_TYPE_BIDI:
1061 case TEST_TYPE_BPF_RES:
1062 testapp_bpf_res(test);
1064 case TEST_TYPE_NOPOLL:
1065 test_spec_set_name(test, "RUN_TO_COMPLETION");
1066 testapp_validate_traffic(test);
1068 case TEST_TYPE_POLL:
1069 test->ifobj_tx->use_poll = true;
1070 test->ifobj_rx->use_poll = true;
1071 test_spec_set_name(test, "POLL");
1072 testapp_validate_traffic(test);
1078 print_ksft_result(test);
1081 static struct ifobject *ifobject_create(void)
1083 struct ifobject *ifobj;
1085 ifobj = calloc(1, sizeof(struct ifobject));
1089 ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr));
1090 if (!ifobj->xsk_arr)
1093 ifobj->umem_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->umem_arr));
1094 if (!ifobj->umem_arr)
1100 free(ifobj->xsk_arr);
1106 static void ifobject_delete(struct ifobject *ifobj)
1108 free(ifobj->umem_arr);
1109 free(ifobj->xsk_arr);
1113 int main(int argc, char **argv)
1115 struct rlimit _rlim = { RLIM_INFINITY, RLIM_INFINITY };
1116 struct ifobject *ifobj_tx, *ifobj_rx;
1117 struct test_spec test;
1120 if (setrlimit(RLIMIT_MEMLOCK, &_rlim))
1121 exit_with_error(errno);
1123 ifobj_tx = ifobject_create();
1125 exit_with_error(ENOMEM);
1126 ifobj_rx = ifobject_create();
1128 exit_with_error(ENOMEM);
1130 test_spec_init(&test, ifobj_tx, ifobj_rx);
1132 setlocale(LC_ALL, "");
1134 parse_command_line(&test, argc, argv);
1136 if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx)) {
1137 usage(basename(argv[0]));
1141 init_iface(ifobj_tx, MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2,
1142 worker_testapp_validate_tx);
1143 init_iface(ifobj_rx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1,
1144 worker_testapp_validate_rx);
1146 ksft_set_plan(TEST_MODE_MAX * TEST_TYPE_MAX);
1148 for (i = 0; i < TEST_MODE_MAX; i++)
1149 for (j = 0; j < TEST_TYPE_MAX; j++) {
1150 test_spec_init(&test, ifobj_tx, ifobj_rx);
1151 run_pkt_test(&test, i, j);
1155 ifobject_delete(ifobj_tx);
1156 ifobject_delete(ifobj_rx);