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