1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2019 Marvell International Ltd. 3 */ 4 5 #include <rte_string_fns.h> 6 7 #include "l2fwd_event.h" 8 #include "l2fwd_poll.h" 9 10 /* display usage */ 11 static void 12 l2fwd_event_usage(const char *prgname) 13 { 14 printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 15 " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 16 " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 17 " -T PERIOD: statistics will be refreshed each PERIOD seconds " 18 " (0 to disable, 10 default, 86400 maximum)\n" 19 " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" 20 " When enabled:\n" 21 " - The source MAC address is replaced by the TX port MAC address\n" 22 " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n" 23 " --mode: Packet transfer mode for I/O, poll or eventdev\n" 24 " Default mode = eventdev\n" 25 " --eventq-sched: Event queue schedule type, ordered, atomic or parallel.\n" 26 " Default: atomic\n" 27 " Valid only if --mode=eventdev\n" 28 " --config: Configure forwarding port pair mapping\n" 29 " Default: alternate port pairs\n\n", 30 prgname); 31 } 32 33 static int 34 l2fwd_event_parse_portmask(const char *portmask) 35 { 36 char *end = NULL; 37 unsigned long pm; 38 39 /* parse hexadecimal string */ 40 pm = strtoul(portmask, &end, 16); 41 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 42 return 0; 43 44 return pm; 45 } 46 47 static unsigned int 48 l2fwd_event_parse_nqueue(const char *q_arg) 49 { 50 char *end = NULL; 51 unsigned long n; 52 53 /* parse hexadecimal string */ 54 n = strtoul(q_arg, &end, 10); 55 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 56 return 0; 57 if (n == 0) 58 return 0; 59 if (n >= MAX_RX_QUEUE_PER_LCORE) 60 return 0; 61 62 return n; 63 } 64 65 static int 66 l2fwd_event_parse_timer_period(const char *q_arg) 67 { 68 char *end = NULL; 69 int n; 70 71 /* parse number string */ 72 n = strtol(q_arg, &end, 10); 73 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 74 return -1; 75 if (n >= MAX_TIMER_PERIOD) 76 return -1; 77 78 return n; 79 } 80 81 static void 82 l2fwd_event_parse_mode(const char *optarg, 83 struct l2fwd_resources *rsrc) 84 { 85 if (!strncmp(optarg, "poll", 4)) 86 rsrc->event_mode = false; 87 else if (!strncmp(optarg, "eventdev", 8)) 88 rsrc->event_mode = true; 89 } 90 91 static void 92 l2fwd_event_parse_eventq_sched(const char *optarg, 93 struct l2fwd_resources *rsrc) 94 { 95 if (!strncmp(optarg, "ordered", 7)) 96 rsrc->sched_type = RTE_SCHED_TYPE_ORDERED; 97 else if (!strncmp(optarg, "atomic", 6)) 98 rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC; 99 else if (!strncmp(optarg, "parallel", 8)) 100 rsrc->sched_type = RTE_SCHED_TYPE_PARALLEL; 101 } 102 103 static int 104 l2fwd_parse_port_pair_config(const char *q_arg, struct l2fwd_resources *rsrc) 105 { 106 enum fieldnames { 107 FLD_PORT1 = 0, 108 FLD_PORT2, 109 _NUM_FLD 110 }; 111 const char *p, *p0 = q_arg; 112 uint16_t int_fld[_NUM_FLD]; 113 char *str_fld[_NUM_FLD]; 114 uint16_t port_pair = 0; 115 unsigned int size; 116 char s[256]; 117 char *end; 118 int i; 119 120 while ((p = strchr(p0, '(')) != NULL) { 121 ++p; 122 p0 = strchr(p, ')'); 123 if (p0 == NULL) 124 return -1; 125 126 size = p0 - p; 127 if (size >= sizeof(s)) 128 return -1; 129 130 memcpy(s, p, size); 131 if (rte_strsplit(s, sizeof(s), str_fld, 132 _NUM_FLD, ',') != _NUM_FLD) 133 return -1; 134 135 for (i = 0; i < _NUM_FLD; i++) { 136 errno = 0; 137 int_fld[i] = strtoul(str_fld[i], &end, 0); 138 if (errno != 0 || end == str_fld[i] || 139 int_fld[i] >= RTE_MAX_ETHPORTS) 140 return -1; 141 } 142 143 if (port_pair >= RTE_MAX_ETHPORTS / 2) { 144 printf("exceeded max number of port pair params: Current %d Max = %d\n", 145 port_pair, RTE_MAX_ETHPORTS / 2); 146 return -1; 147 } 148 149 if ((rsrc->dst_ports[int_fld[FLD_PORT1]] != UINT32_MAX) || 150 (rsrc->dst_ports[int_fld[FLD_PORT2]] != UINT32_MAX)) { 151 printf("Duplicate port pair (%d,%d) config\n", 152 int_fld[FLD_PORT1], int_fld[FLD_PORT2]); 153 return -1; 154 } 155 156 rsrc->dst_ports[int_fld[FLD_PORT1]] = int_fld[FLD_PORT2]; 157 rsrc->dst_ports[int_fld[FLD_PORT2]] = int_fld[FLD_PORT1]; 158 159 port_pair++; 160 } 161 162 rsrc->port_pairs = true; 163 164 return 0; 165 } 166 167 static const char short_options[] = 168 "p:" /* portmask */ 169 "q:" /* number of queues */ 170 "T:" /* timer period */ 171 ; 172 173 #define CMD_LINE_OPT_MAC_UPDATING "mac-updating" 174 #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" 175 #define CMD_LINE_OPT_MODE "mode" 176 #define CMD_LINE_OPT_EVENTQ_SCHED "eventq-sched" 177 #define CMD_LINE_OPT_PORT_PAIR_CONF "config" 178 179 enum { 180 /* long options mapped to a short option */ 181 182 /* first long only option value must be >= 256, so that we won't 183 * conflict with short options 184 */ 185 CMD_LINE_OPT_MIN_NUM = 256, 186 CMD_LINE_OPT_MODE_NUM, 187 CMD_LINE_OPT_EVENTQ_SCHED_NUM, 188 CMD_LINE_OPT_PORT_PAIR_CONF_NUM, 189 }; 190 191 /* Parse the argument given in the command line of the application */ 192 static int 193 l2fwd_event_parse_args(int argc, char **argv, struct l2fwd_resources *rsrc) 194 { 195 int mac_updating = 1; 196 struct option lgopts[] = { 197 { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, 198 { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, 199 { CMD_LINE_OPT_MODE, required_argument, NULL, 200 CMD_LINE_OPT_MODE_NUM}, 201 { CMD_LINE_OPT_EVENTQ_SCHED, required_argument, NULL, 202 CMD_LINE_OPT_EVENTQ_SCHED_NUM}, 203 { CMD_LINE_OPT_PORT_PAIR_CONF, required_argument, NULL, 204 CMD_LINE_OPT_PORT_PAIR_CONF_NUM}, 205 {NULL, 0, 0, 0} 206 }; 207 int opt, ret, timer_secs; 208 char *prgname = argv[0]; 209 uint16_t port_id; 210 int option_index; 211 char **argvopt; 212 213 /* Reset l2fwd_dst_ports. 8< */ 214 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) 215 rsrc->dst_ports[port_id] = UINT32_MAX; 216 217 argvopt = argv; 218 while ((opt = getopt_long(argc, argvopt, short_options, 219 lgopts, &option_index)) != EOF) { 220 221 switch (opt) { 222 /* portmask */ 223 case 'p': 224 rsrc->enabled_port_mask = 225 l2fwd_event_parse_portmask(optarg); 226 if (rsrc->enabled_port_mask == 0) { 227 printf("invalid portmask\n"); 228 l2fwd_event_usage(prgname); 229 return -1; 230 } 231 break; 232 233 /* nqueue */ 234 case 'q': 235 rsrc->rx_queue_per_lcore = 236 l2fwd_event_parse_nqueue(optarg); 237 if (rsrc->rx_queue_per_lcore == 0) { 238 printf("invalid queue number\n"); 239 l2fwd_event_usage(prgname); 240 return -1; 241 } 242 break; 243 244 /* timer period */ 245 case 'T': 246 timer_secs = l2fwd_event_parse_timer_period(optarg); 247 if (timer_secs < 0) { 248 printf("invalid timer period\n"); 249 l2fwd_event_usage(prgname); 250 return -1; 251 } 252 rsrc->timer_period = timer_secs; 253 /* convert to number of cycles */ 254 rsrc->timer_period *= rte_get_timer_hz(); 255 break; 256 257 case CMD_LINE_OPT_MODE_NUM: 258 l2fwd_event_parse_mode(optarg, rsrc); 259 break; 260 261 case CMD_LINE_OPT_EVENTQ_SCHED_NUM: 262 l2fwd_event_parse_eventq_sched(optarg, rsrc); 263 break; 264 265 case CMD_LINE_OPT_PORT_PAIR_CONF_NUM: 266 ret = l2fwd_parse_port_pair_config(optarg, rsrc); 267 if (ret) { 268 printf("Invalid port pair config\n"); 269 l2fwd_event_usage(prgname); 270 return -1; 271 } 272 break; 273 274 /* long options */ 275 case 0: 276 break; 277 278 default: 279 l2fwd_event_usage(prgname); 280 return -1; 281 } 282 } 283 284 rsrc->mac_updating = mac_updating; 285 286 if (optind >= 0) 287 argv[optind-1] = prgname; 288 289 ret = optind-1; 290 optind = 1; /* reset getopt lib */ 291 return ret; 292 /* >8 End of reset l2fwd_dst_ports. */ 293 } 294 295 /* 296 * Check port pair config with enabled port mask, 297 * and for valid port pair combinations. 298 */ 299 static int 300 check_port_pair_config(struct l2fwd_resources *rsrc) 301 { 302 uint32_t port_pair_mask = 0; 303 uint32_t portid; 304 uint16_t index; 305 306 for (index = 0; index < rte_eth_dev_count_avail(); index++) { 307 if ((rsrc->enabled_port_mask & (1 << index)) == 0 || 308 (port_pair_mask & (1 << index))) 309 continue; 310 311 portid = rsrc->dst_ports[index]; 312 if (portid == UINT32_MAX) { 313 printf("port %u is enabled in but no valid port pair\n", 314 index); 315 return -1; 316 } 317 318 if (!rte_eth_dev_is_valid_port(index)) { 319 printf("port %u is not valid\n", index); 320 return -1; 321 } 322 323 if (!rte_eth_dev_is_valid_port(portid)) { 324 printf("port %u is not valid\n", portid); 325 return -1; 326 } 327 328 if (port_pair_mask & (1 << portid) && 329 rsrc->dst_ports[portid] != index) { 330 printf("port %u is used in other port pairs\n", portid); 331 return -1; 332 } 333 334 port_pair_mask |= (1 << portid); 335 port_pair_mask |= (1 << index); 336 } 337 338 return 0; 339 } 340 341 static int 342 l2fwd_launch_one_lcore(void *args) 343 { 344 struct l2fwd_resources *rsrc = args; 345 struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc; 346 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc; 347 348 if (rsrc->event_mode) 349 evt_rsrc->ops.l2fwd_event_loop(rsrc); 350 else 351 poll_rsrc->poll_main_loop(rsrc); 352 353 return 0; 354 } 355 356 /* Check the link status of all ports in up to 9s, and print them finally */ 357 static void 358 check_all_ports_link_status(struct l2fwd_resources *rsrc, 359 uint32_t port_mask) 360 { 361 #define CHECK_INTERVAL 100 /* 100ms */ 362 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 363 uint16_t port_id; 364 uint8_t count, all_ports_up, print_flag = 0; 365 struct rte_eth_link link; 366 int ret; 367 char link_status_text[RTE_ETH_LINK_MAX_STR_LEN]; 368 369 printf("\nChecking link status..."); 370 fflush(stdout); 371 for (count = 0; count <= MAX_CHECK_TIME; count++) { 372 if (rsrc->force_quit) 373 return; 374 all_ports_up = 1; 375 RTE_ETH_FOREACH_DEV(port_id) { 376 if (rsrc->force_quit) 377 return; 378 if ((port_mask & (1 << port_id)) == 0) 379 continue; 380 memset(&link, 0, sizeof(link)); 381 ret = rte_eth_link_get_nowait(port_id, &link); 382 if (ret < 0) { 383 all_ports_up = 0; 384 if (print_flag == 1) 385 printf("Port %u link get failed: %s\n", 386 port_id, rte_strerror(-ret)); 387 continue; 388 } 389 /* print link status if flag set */ 390 if (print_flag == 1) { 391 rte_eth_link_to_str(link_status_text, 392 sizeof(link_status_text), &link); 393 printf("Port %d %s\n", port_id, 394 link_status_text); 395 continue; 396 } 397 /* clear all_ports_up flag if any link down */ 398 if (link.link_status == ETH_LINK_DOWN) { 399 all_ports_up = 0; 400 break; 401 } 402 } 403 /* after finally printing all link status, get out */ 404 if (print_flag == 1) 405 break; 406 407 if (all_ports_up == 0) { 408 printf("."); 409 fflush(stdout); 410 rte_delay_ms(CHECK_INTERVAL); 411 } 412 413 /* set the print_flag if all ports up or timeout */ 414 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 415 print_flag = 1; 416 printf("done\n"); 417 } 418 } 419 } 420 421 /* Print out statistics on packets dropped */ 422 static void 423 print_stats(struct l2fwd_resources *rsrc) 424 { 425 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 426 uint32_t port_id; 427 428 total_packets_dropped = 0; 429 total_packets_tx = 0; 430 total_packets_rx = 0; 431 432 const char clr[] = {27, '[', '2', 'J', '\0' }; 433 const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' }; 434 435 /* Clear screen and move to top left */ 436 printf("%s%s", clr, topLeft); 437 438 printf("\nPort statistics ===================================="); 439 440 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { 441 /* skip disabled ports */ 442 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) 443 continue; 444 printf("\nStatistics for port %u ------------------------------" 445 "\nPackets sent: %29"PRIu64 446 "\nPackets received: %25"PRIu64 447 "\nPackets dropped: %26"PRIu64, 448 port_id, 449 rsrc->port_stats[port_id].tx, 450 rsrc->port_stats[port_id].rx, 451 rsrc->port_stats[port_id].dropped); 452 453 total_packets_dropped += 454 rsrc->port_stats[port_id].dropped; 455 total_packets_tx += rsrc->port_stats[port_id].tx; 456 total_packets_rx += rsrc->port_stats[port_id].rx; 457 } 458 459 if (rsrc->event_mode) { 460 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc; 461 struct rte_event_eth_rx_adapter_stats rx_adptr_stats; 462 struct rte_event_eth_tx_adapter_stats tx_adptr_stats; 463 int ret, i; 464 465 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) { 466 ret = rte_event_eth_rx_adapter_stats_get( 467 evt_rsrc->rx_adptr.rx_adptr[i], 468 &rx_adptr_stats); 469 if (ret < 0) 470 continue; 471 printf("\nRx adapter[%d] statistics====================" 472 "\nReceive queue poll count: %17"PRIu64 473 "\nReceived packet count: %20"PRIu64 474 "\nEventdev enqueue count: %19"PRIu64 475 "\nEventdev enqueue retry count: %13"PRIu64 476 "\nReceived packet dropped count: %12"PRIu64 477 "\nRx enqueue start timestamp: %15"PRIu64 478 "\nRx enqueue block cycles: %18"PRIu64 479 "\nRx enqueue unblock timestamp: %13"PRIu64, 480 evt_rsrc->rx_adptr.rx_adptr[i], 481 rx_adptr_stats.rx_poll_count, 482 rx_adptr_stats.rx_packets, 483 rx_adptr_stats.rx_enq_count, 484 rx_adptr_stats.rx_enq_retry, 485 rx_adptr_stats.rx_dropped, 486 rx_adptr_stats.rx_enq_start_ts, 487 rx_adptr_stats.rx_enq_block_cycles, 488 rx_adptr_stats.rx_enq_end_ts); 489 } 490 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) { 491 ret = rte_event_eth_tx_adapter_stats_get( 492 evt_rsrc->tx_adptr.tx_adptr[i], 493 &tx_adptr_stats); 494 if (ret < 0) 495 continue; 496 printf("\nTx adapter[%d] statistics====================" 497 "\nNumber of transmit retries: %15"PRIu64 498 "\nNumber of packets transmitted: %12"PRIu64 499 "\nNumber of packets dropped: %16"PRIu64, 500 evt_rsrc->tx_adptr.tx_adptr[i], 501 tx_adptr_stats.tx_retry, 502 tx_adptr_stats.tx_packets, 503 tx_adptr_stats.tx_dropped); 504 } 505 } 506 printf("\nAggregate lcore statistics =========================" 507 "\nTotal packets sent: %23"PRIu64 508 "\nTotal packets received: %19"PRIu64 509 "\nTotal packets dropped: %20"PRIu64, 510 total_packets_tx, 511 total_packets_rx, 512 total_packets_dropped); 513 printf("\n====================================================\n"); 514 515 fflush(stdout); 516 } 517 518 static void 519 l2fwd_event_print_stats(struct l2fwd_resources *rsrc) 520 { 521 uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0; 522 const uint64_t timer_period = rsrc->timer_period; 523 524 while (!rsrc->force_quit) { 525 /* if timer is enabled */ 526 if (timer_period > 0) { 527 cur_tsc = rte_rdtsc(); 528 diff_tsc = cur_tsc - prev_tsc; 529 530 /* advance the timer */ 531 timer_tsc += diff_tsc; 532 533 /* if timer has reached its timeout */ 534 if (unlikely(timer_tsc >= timer_period)) { 535 print_stats(rsrc); 536 /* reset the timer */ 537 timer_tsc = 0; 538 } 539 prev_tsc = cur_tsc; 540 } 541 } 542 } 543 544 545 static void 546 signal_handler(int signum) 547 { 548 struct l2fwd_resources *rsrc = l2fwd_get_rsrc(); 549 if (signum == SIGINT || signum == SIGTERM) { 550 printf("\n\nSignal %d received, preparing to exit...\n", 551 signum); 552 rsrc->force_quit = true; 553 } 554 } 555 556 int 557 main(int argc, char **argv) 558 { 559 struct l2fwd_resources *rsrc; 560 uint16_t nb_ports_available = 0; 561 uint32_t nb_ports_in_mask = 0; 562 uint16_t port_id, last_port; 563 uint32_t nb_mbufs; 564 uint16_t nb_ports; 565 int i, ret; 566 567 /* Init EAL. 8< */ 568 ret = rte_eal_init(argc, argv); 569 if (ret < 0) 570 rte_panic("Invalid EAL arguments\n"); 571 argc -= ret; 572 argv += ret; 573 574 rsrc = l2fwd_get_rsrc(); 575 576 signal(SIGINT, signal_handler); 577 signal(SIGTERM, signal_handler); 578 579 /* parse application arguments (after the EAL ones) */ 580 ret = l2fwd_event_parse_args(argc, argv, rsrc); 581 if (ret < 0) 582 rte_panic("Invalid L2FWD arguments\n"); 583 /* >8 End of init EAL. */ 584 585 printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" : 586 "disabled"); 587 588 nb_ports = rte_eth_dev_count_avail(); 589 if (nb_ports == 0) 590 rte_panic("No Ethernet ports - bye\n"); 591 592 /* check port mask to possible port mask */ 593 if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1)) 594 rte_panic("Invalid portmask; possible (0x%x)\n", 595 (1 << nb_ports) - 1); 596 597 if (!rsrc->port_pairs) { 598 last_port = 0; 599 /* 600 * Each logical core is assigned a dedicated TX queue on each 601 * port. 602 */ 603 RTE_ETH_FOREACH_DEV(port_id) { 604 /* skip ports that are not enabled */ 605 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) 606 continue; 607 608 if (nb_ports_in_mask % 2) { 609 rsrc->dst_ports[port_id] = last_port; 610 rsrc->dst_ports[last_port] = port_id; 611 } else { 612 last_port = port_id; 613 } 614 615 nb_ports_in_mask++; 616 } 617 if (nb_ports_in_mask % 2) { 618 printf("Notice: odd number of ports in portmask.\n"); 619 rsrc->dst_ports[last_port] = last_port; 620 } 621 } else { 622 if (check_port_pair_config(rsrc) < 0) 623 rte_panic("Invalid port pair config\n"); 624 } 625 626 nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT + 627 RTE_TEST_TX_DESC_DEFAULT + 628 MAX_PKT_BURST + rte_lcore_count() * 629 MEMPOOL_CACHE_SIZE), 8192U); 630 631 /* Create the mbuf pool. 8< */ 632 rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 633 nb_mbufs, MEMPOOL_CACHE_SIZE, 0, 634 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 635 if (rsrc->pktmbuf_pool == NULL) 636 rte_panic("Cannot init mbuf pool\n"); 637 /* >8 End of creation of mbuf pool. */ 638 639 nb_ports_available = l2fwd_event_init_ports(rsrc); 640 if (!nb_ports_available) 641 rte_panic("All available ports are disabled. Please set portmask.\n"); 642 643 /* Configure eventdev parameters if required */ 644 if (rsrc->event_mode) 645 l2fwd_event_resource_setup(rsrc); 646 else 647 l2fwd_poll_resource_setup(rsrc); 648 649 /* initialize port stats */ 650 memset(&rsrc->port_stats, 0, 651 sizeof(struct l2fwd_port_statistics)); 652 653 /* All settings are done. Now enable eth devices */ 654 RTE_ETH_FOREACH_DEV(port_id) { 655 /* skip ports that are not enabled */ 656 if ((rsrc->enabled_port_mask & 657 (1 << port_id)) == 0) 658 continue; 659 660 ret = rte_eth_dev_start(port_id); 661 if (ret < 0) 662 rte_panic("rte_eth_dev_start:err=%d, port=%u\n", ret, 663 port_id); 664 } 665 666 if (rsrc->event_mode) 667 l2fwd_event_service_setup(rsrc); 668 669 check_all_ports_link_status(rsrc, rsrc->enabled_port_mask); 670 671 /* launch per-lcore init on every lcore */ 672 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc, 673 SKIP_MAIN); 674 l2fwd_event_print_stats(rsrc); 675 if (rsrc->event_mode) { 676 struct l2fwd_event_resources *evt_rsrc = 677 rsrc->evt_rsrc; 678 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) 679 rte_event_eth_rx_adapter_stop( 680 evt_rsrc->rx_adptr.rx_adptr[i]); 681 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) 682 rte_event_eth_tx_adapter_stop( 683 evt_rsrc->tx_adptr.tx_adptr[i]); 684 685 RTE_ETH_FOREACH_DEV(port_id) { 686 if ((rsrc->enabled_port_mask & 687 (1 << port_id)) == 0) 688 continue; 689 ret = rte_eth_dev_stop(port_id); 690 if (ret < 0) 691 printf("rte_eth_dev_stop:err=%d, port=%u\n", 692 ret, port_id); 693 } 694 695 rte_eal_mp_wait_lcore(); 696 RTE_ETH_FOREACH_DEV(port_id) { 697 if ((rsrc->enabled_port_mask & 698 (1 << port_id)) == 0) 699 continue; 700 rte_eth_dev_close(port_id); 701 } 702 703 rte_event_dev_stop(evt_rsrc->event_d_id); 704 rte_event_dev_close(evt_rsrc->event_d_id); 705 706 } else { 707 rte_eal_mp_wait_lcore(); 708 709 RTE_ETH_FOREACH_DEV(port_id) { 710 if ((rsrc->enabled_port_mask & 711 (1 << port_id)) == 0) 712 continue; 713 printf("Closing port %d...", port_id); 714 ret = rte_eth_dev_stop(port_id); 715 if (ret < 0) 716 printf("rte_eth_dev_stop:err=%d, port=%u\n", 717 ret, port_id); 718 rte_eth_dev_close(port_id); 719 printf(" Done\n"); 720 } 721 } 722 723 /* clean up the EAL */ 724 rte_eal_cleanup(); 725 printf("Bye...\n"); 726 727 return 0; 728 } 729