1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdint.h> 7 #include <unistd.h> 8 #include <string.h> 9 #include <sys/wait.h> 10 #include <dirent.h> 11 12 #include "test.h" 13 14 #if !defined(RTE_EXEC_ENV_LINUX) || !defined(RTE_LIBRTE_KNI) 15 16 static int 17 test_kni(void) 18 { 19 printf("KNI not supported, skipping test\n"); 20 return TEST_SKIPPED; 21 } 22 23 #else 24 25 #include <rte_string_fns.h> 26 #include <rte_mempool.h> 27 #include <rte_ethdev.h> 28 #include <rte_bus_pci.h> 29 #include <rte_cycles.h> 30 #include <rte_kni.h> 31 32 #define NB_MBUF 8192 33 #define MAX_PACKET_SZ 2048 34 #define MBUF_DATA_SZ (MAX_PACKET_SZ + RTE_PKTMBUF_HEADROOM) 35 #define PKT_BURST_SZ 32 36 #define MEMPOOL_CACHE_SZ PKT_BURST_SZ 37 #define SOCKET 0 38 #define NB_RXD 1024 39 #define NB_TXD 1024 40 #define KNI_TIMEOUT_MS 5000 /* ms */ 41 42 #define IFCONFIG "/sbin/ifconfig " 43 #define TEST_KNI_PORT "test_kni_port" 44 #define KNI_MODULE_PATH "/sys/module/rte_kni" 45 #define KNI_MODULE_PARAM_LO KNI_MODULE_PATH"/parameters/lo_mode" 46 #define KNI_TEST_MAX_PORTS 4 47 /* The threshold number of mbufs to be transmitted or received. */ 48 #define KNI_NUM_MBUF_THRESHOLD 100 49 static int kni_pkt_mtu = 0; 50 51 struct test_kni_stats { 52 volatile uint64_t ingress; 53 volatile uint64_t egress; 54 }; 55 56 static const struct rte_eth_rxconf rx_conf = { 57 .rx_thresh = { 58 .pthresh = 8, 59 .hthresh = 8, 60 .wthresh = 4, 61 }, 62 .rx_free_thresh = 0, 63 }; 64 65 static const struct rte_eth_txconf tx_conf = { 66 .tx_thresh = { 67 .pthresh = 36, 68 .hthresh = 0, 69 .wthresh = 0, 70 }, 71 .tx_free_thresh = 0, 72 .tx_rs_thresh = 0, 73 }; 74 75 static const struct rte_eth_conf port_conf = { 76 .txmode = { 77 .mq_mode = ETH_DCB_NONE, 78 }, 79 }; 80 81 static struct rte_kni_ops kni_ops = { 82 .change_mtu = NULL, 83 .config_network_if = NULL, 84 .config_mac_address = NULL, 85 .config_promiscusity = NULL, 86 }; 87 88 static unsigned lcore_master, lcore_ingress, lcore_egress; 89 static struct rte_kni *test_kni_ctx; 90 static struct test_kni_stats stats; 91 92 static volatile uint32_t test_kni_processing_flag; 93 94 static struct rte_mempool * 95 test_kni_create_mempool(void) 96 { 97 struct rte_mempool * mp; 98 99 mp = rte_mempool_lookup("kni_mempool"); 100 if (!mp) 101 mp = rte_pktmbuf_pool_create("kni_mempool", 102 NB_MBUF, 103 MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, 104 SOCKET); 105 106 return mp; 107 } 108 109 static struct rte_mempool * 110 test_kni_lookup_mempool(void) 111 { 112 return rte_mempool_lookup("kni_mempool"); 113 } 114 /* Callback for request of changing MTU */ 115 static int 116 kni_change_mtu(uint16_t port_id, unsigned int new_mtu) 117 { 118 printf("Change MTU of port %d to %u\n", port_id, new_mtu); 119 kni_pkt_mtu = new_mtu; 120 printf("Change MTU of port %d to %i successfully.\n", 121 port_id, kni_pkt_mtu); 122 return 0; 123 } 124 125 static int 126 test_kni_link_change(void) 127 { 128 int ret; 129 int pid; 130 131 pid = fork(); 132 if (pid < 0) { 133 printf("Error: Failed to fork a process\n"); 134 return -1; 135 } 136 137 if (pid == 0) { 138 printf("Starting KNI Link status change tests.\n"); 139 if (system(IFCONFIG TEST_KNI_PORT" up") == -1) { 140 ret = -1; 141 goto error; 142 } 143 144 ret = rte_kni_update_link(test_kni_ctx, 1); 145 if (ret < 0) { 146 printf("Failed to change link state to Up ret=%d.\n", 147 ret); 148 goto error; 149 } 150 rte_delay_ms(1000); 151 printf("KNI: Set LINKUP, previous state=%d\n", ret); 152 153 ret = rte_kni_update_link(test_kni_ctx, 0); 154 if (ret != 1) { 155 printf( 156 "Failed! Previous link state should be 1, returned %d.\n", 157 ret); 158 goto error; 159 } 160 rte_delay_ms(1000); 161 printf("KNI: Set LINKDOWN, previous state=%d\n", ret); 162 163 ret = rte_kni_update_link(test_kni_ctx, 1); 164 if (ret != 0) { 165 printf( 166 "Failed! Previous link state should be 0, returned %d.\n", 167 ret); 168 goto error; 169 } 170 printf("KNI: Set LINKUP, previous state=%d\n", ret); 171 172 ret = 0; 173 rte_delay_ms(1000); 174 175 error: 176 if (system(IFCONFIG TEST_KNI_PORT" down") == -1) 177 ret = -1; 178 179 printf("KNI: Link status change tests: %s.\n", 180 (ret == 0) ? "Passed" : "Failed"); 181 exit(ret); 182 } else { 183 int p_ret, status; 184 185 while (1) { 186 p_ret = waitpid(pid, &status, WNOHANG); 187 if (p_ret != 0) { 188 if (WIFEXITED(status)) 189 return WEXITSTATUS(status); 190 return -1; 191 } 192 rte_delay_ms(10); 193 rte_kni_handle_request(test_kni_ctx); 194 } 195 } 196 } 197 /** 198 * This loop fully tests the basic functions of KNI. e.g. transmitting, 199 * receiving to, from kernel space, and kernel requests. 200 * 201 * This is the loop to transmit/receive mbufs to/from kernel interface with 202 * supported by KNI kernel module. The ingress lcore will allocate mbufs and 203 * transmit them to kernel space; while the egress lcore will receive the mbufs 204 * from kernel space and free them. 205 * On the master lcore, several commands will be run to check handling the 206 * kernel requests. And it will finally set the flag to exit the KNI 207 * transmitting/receiving to/from the kernel space. 208 * 209 * Note: To support this testing, the KNI kernel module needs to be insmodded 210 * in one of its loopback modes. 211 */ 212 static int 213 test_kni_loop(__rte_unused void *arg) 214 { 215 int ret = 0; 216 unsigned nb_rx, nb_tx, num, i; 217 const unsigned lcore_id = rte_lcore_id(); 218 struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; 219 220 if (lcore_id == lcore_master) { 221 rte_delay_ms(KNI_TIMEOUT_MS); 222 /* tests of handling kernel request */ 223 if (system(IFCONFIG TEST_KNI_PORT" up") == -1) 224 ret = -1; 225 if (system(IFCONFIG TEST_KNI_PORT" mtu 1400") == -1) 226 ret = -1; 227 if (system(IFCONFIG TEST_KNI_PORT" down") == -1) 228 ret = -1; 229 rte_delay_ms(KNI_TIMEOUT_MS); 230 test_kni_processing_flag = 1; 231 } else if (lcore_id == lcore_ingress) { 232 struct rte_mempool *mp = test_kni_lookup_mempool(); 233 234 if (mp == NULL) 235 return -1; 236 237 while (1) { 238 if (test_kni_processing_flag) 239 break; 240 241 for (nb_rx = 0; nb_rx < PKT_BURST_SZ; nb_rx++) { 242 pkts_burst[nb_rx] = rte_pktmbuf_alloc(mp); 243 if (!pkts_burst[nb_rx]) 244 break; 245 } 246 247 num = rte_kni_tx_burst(test_kni_ctx, pkts_burst, 248 nb_rx); 249 stats.ingress += num; 250 rte_kni_handle_request(test_kni_ctx); 251 if (num < nb_rx) { 252 for (i = num; i < nb_rx; i++) { 253 rte_pktmbuf_free(pkts_burst[i]); 254 } 255 } 256 rte_delay_ms(10); 257 } 258 } else if (lcore_id == lcore_egress) { 259 while (1) { 260 if (test_kni_processing_flag) 261 break; 262 num = rte_kni_rx_burst(test_kni_ctx, pkts_burst, 263 PKT_BURST_SZ); 264 stats.egress += num; 265 for (nb_tx = 0; nb_tx < num; nb_tx++) 266 rte_pktmbuf_free(pkts_burst[nb_tx]); 267 rte_delay_ms(10); 268 } 269 } 270 271 return ret; 272 } 273 274 static int 275 test_kni_allocate_lcores(void) 276 { 277 unsigned i, count = 0; 278 279 lcore_master = rte_get_master_lcore(); 280 printf("master lcore: %u\n", lcore_master); 281 for (i = 0; i < RTE_MAX_LCORE; i++) { 282 if (count >=2 ) 283 break; 284 if (rte_lcore_is_enabled(i) && i != lcore_master) { 285 count ++; 286 if (count == 1) 287 lcore_ingress = i; 288 else if (count == 2) 289 lcore_egress = i; 290 } 291 } 292 printf("count: %u\n", count); 293 294 return count == 2 ? 0 : -1; 295 } 296 297 static int 298 test_kni_register_handler_mp(void) 299 { 300 #define TEST_KNI_HANDLE_REQ_COUNT 10 /* 5s */ 301 #define TEST_KNI_HANDLE_REQ_INTERVAL 500 /* ms */ 302 #define TEST_KNI_MTU 1450 303 #define TEST_KNI_MTU_STR " 1450" 304 int pid; 305 306 pid = fork(); 307 if (pid < 0) { 308 printf("Failed to fork a process\n"); 309 return -1; 310 } else if (pid == 0) { 311 int i; 312 struct rte_kni *kni = rte_kni_get(TEST_KNI_PORT); 313 struct rte_kni_ops ops = { 314 .change_mtu = kni_change_mtu, 315 .config_network_if = NULL, 316 .config_mac_address = NULL, 317 .config_promiscusity = NULL, 318 }; 319 320 if (!kni) { 321 printf("Failed to get KNI named %s\n", TEST_KNI_PORT); 322 exit(-1); 323 } 324 325 kni_pkt_mtu = 0; 326 327 /* Check with the invalid parameters */ 328 if (rte_kni_register_handlers(kni, NULL) == 0) { 329 printf("Unexpectedly register successuflly " 330 "with NULL ops pointer\n"); 331 exit(-1); 332 } 333 if (rte_kni_register_handlers(NULL, &ops) == 0) { 334 printf("Unexpectedly register successfully " 335 "to NULL KNI device pointer\n"); 336 exit(-1); 337 } 338 339 if (rte_kni_register_handlers(kni, &ops)) { 340 printf("Fail to register ops\n"); 341 exit(-1); 342 } 343 344 /* Check registering again after it has been registered */ 345 if (rte_kni_register_handlers(kni, &ops) == 0) { 346 printf("Unexpectedly register successfully after " 347 "it has already been registered\n"); 348 exit(-1); 349 } 350 351 /** 352 * Handle the request of setting MTU, 353 * with registered handlers. 354 */ 355 for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) { 356 rte_kni_handle_request(kni); 357 if (kni_pkt_mtu == TEST_KNI_MTU) 358 break; 359 rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL); 360 } 361 if (i >= TEST_KNI_HANDLE_REQ_COUNT) { 362 printf("MTU has not been set\n"); 363 exit(-1); 364 } 365 366 kni_pkt_mtu = 0; 367 if (rte_kni_unregister_handlers(kni) < 0) { 368 printf("Fail to unregister ops\n"); 369 exit(-1); 370 } 371 372 /* Check with invalid parameter */ 373 if (rte_kni_unregister_handlers(NULL) == 0) { 374 exit(-1); 375 } 376 377 /** 378 * Handle the request of setting MTU, 379 * without registered handlers. 380 */ 381 for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) { 382 rte_kni_handle_request(kni); 383 if (kni_pkt_mtu != 0) 384 break; 385 rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL); 386 } 387 if (kni_pkt_mtu != 0) { 388 printf("MTU shouldn't be set\n"); 389 exit(-1); 390 } 391 392 exit(0); 393 } else { 394 int p_ret, status; 395 396 rte_delay_ms(1000); 397 if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR) 398 == -1) 399 return -1; 400 401 rte_delay_ms(1000); 402 if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR) 403 == -1) 404 return -1; 405 406 p_ret = wait(&status); 407 if (!WIFEXITED(status)) { 408 printf("Child process (%d) exit abnormally\n", p_ret); 409 return -1; 410 } 411 if (WEXITSTATUS(status) != 0) { 412 printf("Child process exit with failure\n"); 413 return -1; 414 } 415 } 416 417 return 0; 418 } 419 420 static int 421 test_kni_processing(uint16_t port_id, struct rte_mempool *mp) 422 { 423 int ret = 0; 424 unsigned i; 425 struct rte_kni *kni; 426 struct rte_kni_conf conf; 427 struct rte_eth_dev_info info; 428 struct rte_kni_ops ops; 429 const struct rte_pci_device *pci_dev; 430 const struct rte_bus *bus = NULL; 431 432 if (!mp) 433 return -1; 434 435 memset(&conf, 0, sizeof(conf)); 436 memset(&info, 0, sizeof(info)); 437 memset(&ops, 0, sizeof(ops)); 438 439 rte_eth_dev_info_get(port_id, &info); 440 if (info.device) 441 bus = rte_bus_find_by_device(info.device); 442 if (bus && !strcmp(bus->name, "pci")) { 443 pci_dev = RTE_DEV_TO_PCI(info.device); 444 conf.addr = pci_dev->addr; 445 conf.id = pci_dev->id; 446 } 447 snprintf(conf.name, sizeof(conf.name), TEST_KNI_PORT); 448 449 /* core id 1 configured for kernel thread */ 450 conf.core_id = 1; 451 conf.force_bind = 1; 452 conf.mbuf_size = MAX_PACKET_SZ; 453 conf.group_id = port_id; 454 455 ops = kni_ops; 456 ops.port_id = port_id; 457 458 /* basic test of kni processing */ 459 kni = rte_kni_alloc(mp, &conf, &ops); 460 if (!kni) { 461 printf("fail to create kni\n"); 462 return -1; 463 } 464 465 test_kni_ctx = kni; 466 test_kni_processing_flag = 0; 467 stats.ingress = 0; 468 stats.egress = 0; 469 470 /** 471 * Check multiple processes support on 472 * registerring/unregisterring handlers. 473 */ 474 if (test_kni_register_handler_mp() < 0) { 475 printf("fail to check multiple process support\n"); 476 ret = -1; 477 goto fail_kni; 478 } 479 480 ret = test_kni_link_change(); 481 if (ret != 0) 482 goto fail_kni; 483 484 rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER); 485 RTE_LCORE_FOREACH_SLAVE(i) { 486 if (rte_eal_wait_lcore(i) < 0) { 487 ret = -1; 488 goto fail_kni; 489 } 490 } 491 /** 492 * Check if the number of mbufs received from kernel space is equal 493 * to that of transmitted to kernel space 494 */ 495 if (stats.ingress < KNI_NUM_MBUF_THRESHOLD || 496 stats.egress < KNI_NUM_MBUF_THRESHOLD) { 497 printf("The ingress/egress number should not be " 498 "less than %u\n", (unsigned)KNI_NUM_MBUF_THRESHOLD); 499 ret = -1; 500 goto fail_kni; 501 } 502 503 if (rte_kni_release(kni) < 0) { 504 printf("fail to release kni\n"); 505 return -1; 506 } 507 test_kni_ctx = NULL; 508 509 /* test of reusing memzone */ 510 kni = rte_kni_alloc(mp, &conf, &ops); 511 if (!kni) { 512 printf("fail to create kni\n"); 513 return -1; 514 } 515 516 /* Release the kni for following testing */ 517 if (rte_kni_release(kni) < 0) { 518 printf("fail to release kni\n"); 519 return -1; 520 } 521 522 return ret; 523 fail_kni: 524 if (rte_kni_release(kni) < 0) { 525 printf("fail to release kni\n"); 526 ret = -1; 527 } 528 529 return ret; 530 } 531 532 static int 533 test_kni(void) 534 { 535 int ret = -1; 536 uint16_t port_id; 537 struct rte_kni *kni; 538 struct rte_mempool *mp; 539 struct rte_kni_conf conf; 540 struct rte_eth_dev_info info; 541 struct rte_kni_ops ops; 542 const struct rte_pci_device *pci_dev; 543 const struct rte_bus *bus; 544 FILE *fd; 545 DIR *dir; 546 char buf[16]; 547 548 dir = opendir(KNI_MODULE_PATH); 549 if (!dir) { 550 if (errno == ENOENT) { 551 printf("Cannot run UT due to missing rte_kni module\n"); 552 return TEST_SKIPPED; 553 } 554 printf("opendir: %s", strerror(errno)); 555 return -1; 556 } 557 closedir(dir); 558 559 /* Initialize KNI subsytem */ 560 rte_kni_init(KNI_TEST_MAX_PORTS); 561 562 if (test_kni_allocate_lcores() < 0) { 563 printf("No enough lcores for kni processing\n"); 564 return -1; 565 } 566 567 mp = test_kni_create_mempool(); 568 if (!mp) { 569 printf("fail to create mempool for kni\n"); 570 return -1; 571 } 572 573 /* configuring port 0 for the test is enough */ 574 port_id = 0; 575 ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf); 576 if (ret < 0) { 577 printf("fail to configure port %d\n", port_id); 578 return -1; 579 } 580 581 ret = rte_eth_rx_queue_setup(port_id, 0, NB_RXD, SOCKET, &rx_conf, mp); 582 if (ret < 0) { 583 printf("fail to setup rx queue for port %d\n", port_id); 584 return -1; 585 } 586 587 ret = rte_eth_tx_queue_setup(port_id, 0, NB_TXD, SOCKET, &tx_conf); 588 if (ret < 0) { 589 printf("fail to setup tx queue for port %d\n", port_id); 590 return -1; 591 } 592 593 ret = rte_eth_dev_start(port_id); 594 if (ret < 0) { 595 printf("fail to start port %d\n", port_id); 596 return -1; 597 } 598 rte_eth_promiscuous_enable(port_id); 599 600 /* basic test of kni processing */ 601 fd = fopen(KNI_MODULE_PARAM_LO, "r"); 602 if (fd == NULL) { 603 printf("fopen: %s", strerror(errno)); 604 return -1; 605 } 606 memset(&buf, 0, sizeof(buf)); 607 if (fgets(buf, sizeof(buf), fd)) { 608 if (!strncmp(buf, "lo_mode_fifo", strlen("lo_mode_fifo")) || 609 !strncmp(buf, "lo_mode_fifo_skb", 610 strlen("lo_mode_fifo_skb"))) { 611 ret = test_kni_processing(port_id, mp); 612 if (ret < 0) { 613 fclose(fd); 614 goto fail; 615 } 616 } else 617 printf("test_kni_processing skipped because of missing rte_kni module lo_mode argument\n"); 618 } 619 fclose(fd); 620 621 /* test of allocating KNI with NULL mempool pointer */ 622 memset(&info, 0, sizeof(info)); 623 memset(&conf, 0, sizeof(conf)); 624 memset(&ops, 0, sizeof(ops)); 625 rte_eth_dev_info_get(port_id, &info); 626 if (info.device) 627 bus = rte_bus_find_by_device(info.device); 628 else 629 bus = NULL; 630 if (bus && !strcmp(bus->name, "pci")) { 631 pci_dev = RTE_DEV_TO_PCI(info.device); 632 conf.addr = pci_dev->addr; 633 conf.id = pci_dev->id; 634 } 635 conf.group_id = port_id; 636 conf.mbuf_size = MAX_PACKET_SZ; 637 638 ops = kni_ops; 639 ops.port_id = port_id; 640 kni = rte_kni_alloc(NULL, &conf, &ops); 641 if (kni) { 642 ret = -1; 643 printf("unexpectedly creates kni successfully with NULL " 644 "mempool pointer\n"); 645 goto fail; 646 } 647 648 /* test of allocating KNI without configurations */ 649 kni = rte_kni_alloc(mp, NULL, NULL); 650 if (kni) { 651 ret = -1; 652 printf("Unexpectedly allocate KNI device successfully " 653 "without configurations\n"); 654 goto fail; 655 } 656 657 /* test of allocating KNI without a name */ 658 memset(&conf, 0, sizeof(conf)); 659 memset(&info, 0, sizeof(info)); 660 memset(&ops, 0, sizeof(ops)); 661 rte_eth_dev_info_get(port_id, &info); 662 if (info.device) 663 bus = rte_bus_find_by_device(info.device); 664 else 665 bus = NULL; 666 if (bus && !strcmp(bus->name, "pci")) { 667 pci_dev = RTE_DEV_TO_PCI(info.device); 668 conf.addr = pci_dev->addr; 669 conf.id = pci_dev->id; 670 } 671 conf.group_id = port_id; 672 conf.mbuf_size = MAX_PACKET_SZ; 673 674 ops = kni_ops; 675 ops.port_id = port_id; 676 kni = rte_kni_alloc(mp, &conf, &ops); 677 if (kni) { 678 ret = -1; 679 printf("Unexpectedly allocate a KNI device successfully " 680 "without a name\n"); 681 goto fail; 682 } 683 684 /* test of releasing NULL kni context */ 685 ret = rte_kni_release(NULL); 686 if (ret == 0) { 687 ret = -1; 688 printf("unexpectedly release kni successfully\n"); 689 goto fail; 690 } 691 692 /* test of handling request on NULL device pointer */ 693 ret = rte_kni_handle_request(NULL); 694 if (ret == 0) { 695 ret = -1; 696 printf("Unexpectedly handle request on NULL device pointer\n"); 697 goto fail; 698 } 699 700 /* test of getting KNI device with pointer to NULL */ 701 kni = rte_kni_get(NULL); 702 if (kni) { 703 ret = -1; 704 printf("Unexpectedly get a KNI device with " 705 "NULL name pointer\n"); 706 goto fail; 707 } 708 709 /* test of getting KNI device with an zero length name string */ 710 memset(&conf, 0, sizeof(conf)); 711 kni = rte_kni_get(conf.name); 712 if (kni) { 713 ret = -1; 714 printf("Unexpectedly get a KNI device with " 715 "zero length name string\n"); 716 goto fail; 717 } 718 719 /* test of getting KNI device with an invalid string name */ 720 memset(&conf, 0, sizeof(conf)); 721 snprintf(conf.name, sizeof(conf.name), "testing"); 722 kni = rte_kni_get(conf.name); 723 if (kni) { 724 ret = -1; 725 printf("Unexpectedly get a KNI device with " 726 "a never used name string\n"); 727 goto fail; 728 } 729 ret = 0; 730 731 fail: 732 rte_eth_dev_stop(port_id); 733 734 return ret; 735 } 736 737 #endif 738 739 REGISTER_TEST_COMMAND(kni_autotest, test_kni); 740