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 */ 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 } 293 294 /* 295 * Check port pair config with enabled port mask, 296 * and for valid port pair combinations. 297 */ 298 static int 299 check_port_pair_config(struct l2fwd_resources *rsrc) 300 { 301 uint32_t port_pair_mask = 0; 302 uint32_t portid; 303 uint16_t index; 304 305 for (index = 0; index < rte_eth_dev_count_avail(); index++) { 306 if ((rsrc->enabled_port_mask & (1 << index)) == 0 || 307 (port_pair_mask & (1 << index))) 308 continue; 309 310 portid = rsrc->dst_ports[index]; 311 if (portid == UINT32_MAX) { 312 printf("port %u is enabled in but no valid port pair\n", 313 index); 314 return -1; 315 } 316 317 if (!rte_eth_dev_is_valid_port(index)) { 318 printf("port %u is not valid\n", index); 319 return -1; 320 } 321 322 if (!rte_eth_dev_is_valid_port(portid)) { 323 printf("port %u is not valid\n", portid); 324 return -1; 325 } 326 327 if (port_pair_mask & (1 << portid) && 328 rsrc->dst_ports[portid] != index) { 329 printf("port %u is used in other port pairs\n", portid); 330 return -1; 331 } 332 333 port_pair_mask |= (1 << portid); 334 port_pair_mask |= (1 << index); 335 } 336 337 return 0; 338 } 339 340 static int 341 l2fwd_launch_one_lcore(void *args) 342 { 343 struct l2fwd_resources *rsrc = args; 344 struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc; 345 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc; 346 347 if (rsrc->event_mode) 348 evt_rsrc->ops.l2fwd_event_loop(rsrc); 349 else 350 poll_rsrc->poll_main_loop(rsrc); 351 352 return 0; 353 } 354 355 /* Check the link status of all ports in up to 9s, and print them finally */ 356 static void 357 check_all_ports_link_status(struct l2fwd_resources *rsrc, 358 uint32_t port_mask) 359 { 360 #define CHECK_INTERVAL 100 /* 100ms */ 361 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 362 uint16_t port_id; 363 uint8_t count, all_ports_up, print_flag = 0; 364 struct rte_eth_link link; 365 int ret; 366 367 printf("\nChecking link status..."); 368 fflush(stdout); 369 for (count = 0; count <= MAX_CHECK_TIME; count++) { 370 if (rsrc->force_quit) 371 return; 372 all_ports_up = 1; 373 RTE_ETH_FOREACH_DEV(port_id) { 374 if (rsrc->force_quit) 375 return; 376 if ((port_mask & (1 << port_id)) == 0) 377 continue; 378 memset(&link, 0, sizeof(link)); 379 ret = rte_eth_link_get_nowait(port_id, &link); 380 if (ret < 0) { 381 all_ports_up = 0; 382 if (print_flag == 1) 383 printf("Port %u link get failed: %s\n", 384 port_id, rte_strerror(-ret)); 385 continue; 386 } 387 /* print link status if flag set */ 388 if (print_flag == 1) { 389 if (link.link_status) 390 printf( 391 "Port%d Link Up. Speed %u Mbps - %s\n", 392 port_id, link.link_speed, 393 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 394 ("full-duplex") : ("half-duplex")); 395 else 396 printf("Port %d Link Down\n", port_id); 397 continue; 398 } 399 /* clear all_ports_up flag if any link down */ 400 if (link.link_status == ETH_LINK_DOWN) { 401 all_ports_up = 0; 402 break; 403 } 404 } 405 /* after finally printing all link status, get out */ 406 if (print_flag == 1) 407 break; 408 409 if (all_ports_up == 0) { 410 printf("."); 411 fflush(stdout); 412 rte_delay_ms(CHECK_INTERVAL); 413 } 414 415 /* set the print_flag if all ports up or timeout */ 416 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 417 print_flag = 1; 418 printf("done\n"); 419 } 420 } 421 } 422 423 /* Print out statistics on packets dropped */ 424 static void 425 print_stats(struct l2fwd_resources *rsrc) 426 { 427 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 428 uint32_t port_id; 429 430 total_packets_dropped = 0; 431 total_packets_tx = 0; 432 total_packets_rx = 0; 433 434 const char clr[] = {27, '[', '2', 'J', '\0' }; 435 const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' }; 436 437 /* Clear screen and move to top left */ 438 printf("%s%s", clr, topLeft); 439 440 printf("\nPort statistics ===================================="); 441 442 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { 443 /* skip disabled ports */ 444 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) 445 continue; 446 printf("\nStatistics for port %u ------------------------------" 447 "\nPackets sent: %29"PRIu64 448 "\nPackets received: %25"PRIu64 449 "\nPackets dropped: %26"PRIu64, 450 port_id, 451 rsrc->port_stats[port_id].tx, 452 rsrc->port_stats[port_id].rx, 453 rsrc->port_stats[port_id].dropped); 454 455 total_packets_dropped += 456 rsrc->port_stats[port_id].dropped; 457 total_packets_tx += rsrc->port_stats[port_id].tx; 458 total_packets_rx += rsrc->port_stats[port_id].rx; 459 } 460 461 if (rsrc->event_mode) { 462 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc; 463 struct rte_event_eth_rx_adapter_stats rx_adptr_stats; 464 struct rte_event_eth_tx_adapter_stats tx_adptr_stats; 465 int ret, i; 466 467 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) { 468 ret = rte_event_eth_rx_adapter_stats_get( 469 evt_rsrc->rx_adptr.rx_adptr[i], 470 &rx_adptr_stats); 471 if (ret < 0) 472 continue; 473 printf("\nRx adapter[%d] statistics====================" 474 "\nReceive queue poll count: %17"PRIu64 475 "\nReceived packet count: %20"PRIu64 476 "\nEventdev enqueue count: %19"PRIu64 477 "\nEventdev enqueue retry count: %13"PRIu64 478 "\nReceived packet dropped count: %12"PRIu64 479 "\nRx enqueue start timestamp: %15"PRIu64 480 "\nRx enqueue block cycles: %18"PRIu64 481 "\nRx enqueue unblock timestamp: %13"PRIu64, 482 evt_rsrc->rx_adptr.rx_adptr[i], 483 rx_adptr_stats.rx_poll_count, 484 rx_adptr_stats.rx_packets, 485 rx_adptr_stats.rx_enq_count, 486 rx_adptr_stats.rx_enq_retry, 487 rx_adptr_stats.rx_dropped, 488 rx_adptr_stats.rx_enq_start_ts, 489 rx_adptr_stats.rx_enq_block_cycles, 490 rx_adptr_stats.rx_enq_end_ts); 491 } 492 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) { 493 ret = rte_event_eth_tx_adapter_stats_get( 494 evt_rsrc->tx_adptr.tx_adptr[i], 495 &tx_adptr_stats); 496 if (ret < 0) 497 continue; 498 printf("\nTx adapter[%d] statistics====================" 499 "\nNumber of transmit retries: %15"PRIu64 500 "\nNumber of packets transmitted: %12"PRIu64 501 "\nNumber of packets dropped: %16"PRIu64, 502 evt_rsrc->tx_adptr.tx_adptr[i], 503 tx_adptr_stats.tx_retry, 504 tx_adptr_stats.tx_packets, 505 tx_adptr_stats.tx_dropped); 506 } 507 } 508 printf("\nAggregate lcore statistics =========================" 509 "\nTotal packets sent: %23"PRIu64 510 "\nTotal packets received: %19"PRIu64 511 "\nTotal packets dropped: %20"PRIu64, 512 total_packets_tx, 513 total_packets_rx, 514 total_packets_dropped); 515 printf("\n====================================================\n"); 516 517 fflush(stdout); 518 } 519 520 static void 521 l2fwd_event_print_stats(struct l2fwd_resources *rsrc) 522 { 523 uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0; 524 const uint64_t timer_period = rsrc->timer_period; 525 526 while (!rsrc->force_quit) { 527 /* if timer is enabled */ 528 if (timer_period > 0) { 529 cur_tsc = rte_rdtsc(); 530 diff_tsc = cur_tsc - prev_tsc; 531 532 /* advance the timer */ 533 timer_tsc += diff_tsc; 534 535 /* if timer has reached its timeout */ 536 if (unlikely(timer_tsc >= timer_period)) { 537 print_stats(rsrc); 538 /* reset the timer */ 539 timer_tsc = 0; 540 } 541 prev_tsc = cur_tsc; 542 } 543 } 544 } 545 546 547 static void 548 signal_handler(int signum) 549 { 550 struct l2fwd_resources *rsrc = l2fwd_get_rsrc(); 551 if (signum == SIGINT || signum == SIGTERM) { 552 printf("\n\nSignal %d received, preparing to exit...\n", 553 signum); 554 rsrc->force_quit = true; 555 } 556 } 557 558 int 559 main(int argc, char **argv) 560 { 561 struct l2fwd_resources *rsrc; 562 uint16_t nb_ports_available = 0; 563 uint32_t nb_ports_in_mask = 0; 564 uint16_t port_id, last_port; 565 uint32_t nb_mbufs; 566 uint16_t nb_ports; 567 int i, ret; 568 569 /* init EAL */ 570 ret = rte_eal_init(argc, argv); 571 if (ret < 0) 572 rte_panic("Invalid EAL arguments\n"); 573 argc -= ret; 574 argv += ret; 575 576 rsrc = l2fwd_get_rsrc(); 577 578 signal(SIGINT, signal_handler); 579 signal(SIGTERM, signal_handler); 580 581 /* parse application arguments (after the EAL ones) */ 582 ret = l2fwd_event_parse_args(argc, argv, rsrc); 583 if (ret < 0) 584 rte_panic("Invalid L2FWD arguments\n"); 585 586 printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" : 587 "disabled"); 588 589 nb_ports = rte_eth_dev_count_avail(); 590 if (nb_ports == 0) 591 rte_panic("No Ethernet ports - bye\n"); 592 593 /* check port mask to possible port mask */ 594 if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1)) 595 rte_panic("Invalid portmask; possible (0x%x)\n", 596 (1 << nb_ports) - 1); 597 598 if (!rsrc->port_pairs) { 599 last_port = 0; 600 /* 601 * Each logical core is assigned a dedicated TX queue on each 602 * port. 603 */ 604 RTE_ETH_FOREACH_DEV(port_id) { 605 /* skip ports that are not enabled */ 606 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0) 607 continue; 608 609 if (nb_ports_in_mask % 2) { 610 rsrc->dst_ports[port_id] = last_port; 611 rsrc->dst_ports[last_port] = port_id; 612 } else { 613 last_port = port_id; 614 } 615 616 nb_ports_in_mask++; 617 } 618 if (nb_ports_in_mask % 2) { 619 printf("Notice: odd number of ports in portmask.\n"); 620 rsrc->dst_ports[last_port] = last_port; 621 } 622 } else { 623 if (check_port_pair_config(rsrc) < 0) 624 rte_panic("Invalid port pair config\n"); 625 } 626 627 nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT + 628 RTE_TEST_TX_DESC_DEFAULT + 629 MAX_PKT_BURST + rte_lcore_count() * 630 MEMPOOL_CACHE_SIZE), 8192U); 631 632 /* create the mbuf pool */ 633 rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 634 nb_mbufs, MEMPOOL_CACHE_SIZE, 0, 635 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 636 if (rsrc->pktmbuf_pool == NULL) 637 rte_panic("Cannot init mbuf pool\n"); 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_MASTER); 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 rte_eth_dev_stop(port_id); 690 } 691 692 rte_eal_mp_wait_lcore(); 693 RTE_ETH_FOREACH_DEV(port_id) { 694 if ((rsrc->enabled_port_mask & 695 (1 << port_id)) == 0) 696 continue; 697 rte_eth_dev_close(port_id); 698 } 699 700 rte_event_dev_stop(evt_rsrc->event_d_id); 701 rte_event_dev_close(evt_rsrc->event_d_id); 702 703 } else { 704 rte_eal_mp_wait_lcore(); 705 706 RTE_ETH_FOREACH_DEV(port_id) { 707 if ((rsrc->enabled_port_mask & 708 (1 << port_id)) == 0) 709 continue; 710 printf("Closing port %d...", port_id); 711 rte_eth_dev_stop(port_id); 712 rte_eth_dev_close(port_id); 713 printf(" Done\n"); 714 } 715 } 716 printf("Bye...\n"); 717 718 return 0; 719 } 720