1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <stdint.h> 9 #include <inttypes.h> 10 #include <sys/types.h> 11 #include <sys/queue.h> 12 #include <netinet/in.h> 13 #include <setjmp.h> 14 #include <stdarg.h> 15 #include <ctype.h> 16 #include <errno.h> 17 #include <getopt.h> 18 #include <signal.h> 19 #include <stdbool.h> 20 21 #include <rte_common.h> 22 #include <rte_log.h> 23 #include <rte_malloc.h> 24 #include <rte_memory.h> 25 #include <rte_memcpy.h> 26 #include <rte_eal.h> 27 #include <rte_launch.h> 28 #include <rte_atomic.h> 29 #include <rte_cycles.h> 30 #include <rte_prefetch.h> 31 #include <rte_lcore.h> 32 #include <rte_per_lcore.h> 33 #include <rte_branch_prediction.h> 34 #include <rte_interrupts.h> 35 #include <rte_random.h> 36 #include <rte_debug.h> 37 #include <rte_ether.h> 38 #include <rte_ethdev.h> 39 #include <rte_mempool.h> 40 #include <rte_mbuf.h> 41 42 static volatile bool force_quit; 43 44 /* MAC updating enabled by default */ 45 static int mac_updating = 1; 46 47 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 48 49 #define MAX_PKT_BURST 32 50 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ 51 #define MEMPOOL_CACHE_SIZE 256 52 53 /* 54 * Configurable number of RX/TX ring descriptors 55 */ 56 #define RTE_TEST_RX_DESC_DEFAULT 1024 57 #define RTE_TEST_TX_DESC_DEFAULT 1024 58 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 59 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 60 61 /* ethernet addresses of ports */ 62 static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; 63 64 /* mask of enabled ports */ 65 static uint32_t l2fwd_enabled_port_mask = 0; 66 67 /* list of enabled ports */ 68 static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; 69 70 static unsigned int l2fwd_rx_queue_per_lcore = 1; 71 72 #define MAX_RX_QUEUE_PER_LCORE 16 73 #define MAX_TX_QUEUE_PER_PORT 16 74 struct lcore_queue_conf { 75 unsigned n_rx_port; 76 unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 77 } __rte_cache_aligned; 78 struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 79 80 static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; 81 82 static struct rte_eth_conf port_conf = { 83 .rxmode = { 84 .split_hdr_size = 0, 85 .offloads = DEV_RX_OFFLOAD_CRC_STRIP, 86 }, 87 .txmode = { 88 .mq_mode = ETH_MQ_TX_NONE, 89 }, 90 }; 91 92 struct rte_mempool * l2fwd_pktmbuf_pool = NULL; 93 94 /* Per-port statistics struct */ 95 struct l2fwd_port_statistics { 96 uint64_t tx; 97 uint64_t rx; 98 uint64_t dropped; 99 } __rte_cache_aligned; 100 struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; 101 102 #define MAX_TIMER_PERIOD 86400 /* 1 day max */ 103 /* A tsc-based timer responsible for triggering statistics printout */ 104 static uint64_t timer_period = 10; /* default period is 10 seconds */ 105 106 /* Print out statistics on packets dropped */ 107 static void 108 print_stats(void) 109 { 110 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 111 unsigned portid; 112 113 total_packets_dropped = 0; 114 total_packets_tx = 0; 115 total_packets_rx = 0; 116 117 const char clr[] = { 27, '[', '2', 'J', '\0' }; 118 const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; 119 120 /* Clear screen and move to top left */ 121 printf("%s%s", clr, topLeft); 122 123 printf("\nPort statistics ===================================="); 124 125 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 126 /* skip disabled ports */ 127 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 128 continue; 129 printf("\nStatistics for port %u ------------------------------" 130 "\nPackets sent: %24"PRIu64 131 "\nPackets received: %20"PRIu64 132 "\nPackets dropped: %21"PRIu64, 133 portid, 134 port_statistics[portid].tx, 135 port_statistics[portid].rx, 136 port_statistics[portid].dropped); 137 138 total_packets_dropped += port_statistics[portid].dropped; 139 total_packets_tx += port_statistics[portid].tx; 140 total_packets_rx += port_statistics[portid].rx; 141 } 142 printf("\nAggregate statistics ===============================" 143 "\nTotal packets sent: %18"PRIu64 144 "\nTotal packets received: %14"PRIu64 145 "\nTotal packets dropped: %15"PRIu64, 146 total_packets_tx, 147 total_packets_rx, 148 total_packets_dropped); 149 printf("\n====================================================\n"); 150 } 151 152 static void 153 l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid) 154 { 155 struct ether_hdr *eth; 156 void *tmp; 157 158 eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 159 160 /* 02:00:00:00:00:xx */ 161 tmp = ð->d_addr.addr_bytes[0]; 162 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40); 163 164 /* src addr */ 165 ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], ð->s_addr); 166 } 167 168 static void 169 l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) 170 { 171 unsigned dst_port; 172 int sent; 173 struct rte_eth_dev_tx_buffer *buffer; 174 175 dst_port = l2fwd_dst_ports[portid]; 176 177 if (mac_updating) 178 l2fwd_mac_updating(m, dst_port); 179 180 buffer = tx_buffer[dst_port]; 181 sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); 182 if (sent) 183 port_statistics[dst_port].tx += sent; 184 } 185 186 /* main processing loop */ 187 static void 188 l2fwd_main_loop(void) 189 { 190 struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 191 struct rte_mbuf *m; 192 int sent; 193 unsigned lcore_id; 194 uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; 195 unsigned i, j, portid, nb_rx; 196 struct lcore_queue_conf *qconf; 197 const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * 198 BURST_TX_DRAIN_US; 199 struct rte_eth_dev_tx_buffer *buffer; 200 201 prev_tsc = 0; 202 timer_tsc = 0; 203 204 lcore_id = rte_lcore_id(); 205 qconf = &lcore_queue_conf[lcore_id]; 206 207 if (qconf->n_rx_port == 0) { 208 RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); 209 return; 210 } 211 212 RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); 213 214 for (i = 0; i < qconf->n_rx_port; i++) { 215 216 portid = qconf->rx_port_list[i]; 217 RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, 218 portid); 219 220 } 221 222 while (!force_quit) { 223 224 cur_tsc = rte_rdtsc(); 225 226 /* 227 * TX burst queue drain 228 */ 229 diff_tsc = cur_tsc - prev_tsc; 230 if (unlikely(diff_tsc > drain_tsc)) { 231 232 for (i = 0; i < qconf->n_rx_port; i++) { 233 234 portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; 235 buffer = tx_buffer[portid]; 236 237 sent = rte_eth_tx_buffer_flush(portid, 0, buffer); 238 if (sent) 239 port_statistics[portid].tx += sent; 240 241 } 242 243 /* if timer is enabled */ 244 if (timer_period > 0) { 245 246 /* advance the timer */ 247 timer_tsc += diff_tsc; 248 249 /* if timer has reached its timeout */ 250 if (unlikely(timer_tsc >= timer_period)) { 251 252 /* do this only on master core */ 253 if (lcore_id == rte_get_master_lcore()) { 254 print_stats(); 255 /* reset the timer */ 256 timer_tsc = 0; 257 } 258 } 259 } 260 261 prev_tsc = cur_tsc; 262 } 263 264 /* 265 * Read packet from RX queues 266 */ 267 for (i = 0; i < qconf->n_rx_port; i++) { 268 269 portid = qconf->rx_port_list[i]; 270 nb_rx = rte_eth_rx_burst(portid, 0, 271 pkts_burst, MAX_PKT_BURST); 272 273 port_statistics[portid].rx += nb_rx; 274 275 for (j = 0; j < nb_rx; j++) { 276 m = pkts_burst[j]; 277 rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 278 l2fwd_simple_forward(m, portid); 279 } 280 } 281 } 282 } 283 284 static int 285 l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy) 286 { 287 l2fwd_main_loop(); 288 return 0; 289 } 290 291 /* display usage */ 292 static void 293 l2fwd_usage(const char *prgname) 294 { 295 printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 296 " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 297 " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 298 " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" 299 " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" 300 " When enabled:\n" 301 " - The source MAC address is replaced by the TX port MAC address\n" 302 " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n", 303 prgname); 304 } 305 306 static int 307 l2fwd_parse_portmask(const char *portmask) 308 { 309 char *end = NULL; 310 unsigned long pm; 311 312 /* parse hexadecimal string */ 313 pm = strtoul(portmask, &end, 16); 314 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 315 return -1; 316 317 if (pm == 0) 318 return -1; 319 320 return pm; 321 } 322 323 static unsigned int 324 l2fwd_parse_nqueue(const char *q_arg) 325 { 326 char *end = NULL; 327 unsigned long n; 328 329 /* parse hexadecimal string */ 330 n = strtoul(q_arg, &end, 10); 331 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 332 return 0; 333 if (n == 0) 334 return 0; 335 if (n >= MAX_RX_QUEUE_PER_LCORE) 336 return 0; 337 338 return n; 339 } 340 341 static int 342 l2fwd_parse_timer_period(const char *q_arg) 343 { 344 char *end = NULL; 345 int n; 346 347 /* parse number string */ 348 n = strtol(q_arg, &end, 10); 349 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 350 return -1; 351 if (n >= MAX_TIMER_PERIOD) 352 return -1; 353 354 return n; 355 } 356 357 static const char short_options[] = 358 "p:" /* portmask */ 359 "q:" /* number of queues */ 360 "T:" /* timer period */ 361 ; 362 363 #define CMD_LINE_OPT_MAC_UPDATING "mac-updating" 364 #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" 365 366 enum { 367 /* long options mapped to a short option */ 368 369 /* first long only option value must be >= 256, so that we won't 370 * conflict with short options */ 371 CMD_LINE_OPT_MIN_NUM = 256, 372 }; 373 374 static const struct option lgopts[] = { 375 { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, 376 { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, 377 {NULL, 0, 0, 0} 378 }; 379 380 /* Parse the argument given in the command line of the application */ 381 static int 382 l2fwd_parse_args(int argc, char **argv) 383 { 384 int opt, ret, timer_secs; 385 char **argvopt; 386 int option_index; 387 char *prgname = argv[0]; 388 389 argvopt = argv; 390 391 while ((opt = getopt_long(argc, argvopt, short_options, 392 lgopts, &option_index)) != EOF) { 393 394 switch (opt) { 395 /* portmask */ 396 case 'p': 397 l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 398 if (l2fwd_enabled_port_mask == 0) { 399 printf("invalid portmask\n"); 400 l2fwd_usage(prgname); 401 return -1; 402 } 403 break; 404 405 /* nqueue */ 406 case 'q': 407 l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 408 if (l2fwd_rx_queue_per_lcore == 0) { 409 printf("invalid queue number\n"); 410 l2fwd_usage(prgname); 411 return -1; 412 } 413 break; 414 415 /* timer period */ 416 case 'T': 417 timer_secs = l2fwd_parse_timer_period(optarg); 418 if (timer_secs < 0) { 419 printf("invalid timer period\n"); 420 l2fwd_usage(prgname); 421 return -1; 422 } 423 timer_period = timer_secs; 424 break; 425 426 /* long options */ 427 case 0: 428 break; 429 430 default: 431 l2fwd_usage(prgname); 432 return -1; 433 } 434 } 435 436 if (optind >= 0) 437 argv[optind-1] = prgname; 438 439 ret = optind-1; 440 optind = 1; /* reset getopt lib */ 441 return ret; 442 } 443 444 /* Check the link status of all ports in up to 9s, and print them finally */ 445 static void 446 check_all_ports_link_status(uint32_t port_mask) 447 { 448 #define CHECK_INTERVAL 100 /* 100ms */ 449 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 450 uint16_t portid; 451 uint8_t count, all_ports_up, print_flag = 0; 452 struct rte_eth_link link; 453 454 printf("\nChecking link status"); 455 fflush(stdout); 456 for (count = 0; count <= MAX_CHECK_TIME; count++) { 457 if (force_quit) 458 return; 459 all_ports_up = 1; 460 RTE_ETH_FOREACH_DEV(portid) { 461 if (force_quit) 462 return; 463 if ((port_mask & (1 << portid)) == 0) 464 continue; 465 memset(&link, 0, sizeof(link)); 466 rte_eth_link_get_nowait(portid, &link); 467 /* print link status if flag set */ 468 if (print_flag == 1) { 469 if (link.link_status) 470 printf( 471 "Port%d Link Up. Speed %u Mbps - %s\n", 472 portid, link.link_speed, 473 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 474 ("full-duplex") : ("half-duplex\n")); 475 else 476 printf("Port %d Link Down\n", portid); 477 continue; 478 } 479 /* clear all_ports_up flag if any link down */ 480 if (link.link_status == ETH_LINK_DOWN) { 481 all_ports_up = 0; 482 break; 483 } 484 } 485 /* after finally printing all link status, get out */ 486 if (print_flag == 1) 487 break; 488 489 if (all_ports_up == 0) { 490 printf("."); 491 fflush(stdout); 492 rte_delay_ms(CHECK_INTERVAL); 493 } 494 495 /* set the print_flag if all ports up or timeout */ 496 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 497 print_flag = 1; 498 printf("done\n"); 499 } 500 } 501 } 502 503 static void 504 signal_handler(int signum) 505 { 506 if (signum == SIGINT || signum == SIGTERM) { 507 printf("\n\nSignal %d received, preparing to exit...\n", 508 signum); 509 force_quit = true; 510 } 511 } 512 513 int 514 main(int argc, char **argv) 515 { 516 struct lcore_queue_conf *qconf; 517 int ret; 518 uint16_t nb_ports; 519 uint16_t nb_ports_available = 0; 520 uint16_t portid, last_port; 521 unsigned lcore_id, rx_lcore_id; 522 unsigned nb_ports_in_mask = 0; 523 unsigned int nb_lcores = 0; 524 unsigned int nb_mbufs; 525 526 /* init EAL */ 527 ret = rte_eal_init(argc, argv); 528 if (ret < 0) 529 rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 530 argc -= ret; 531 argv += ret; 532 533 force_quit = false; 534 signal(SIGINT, signal_handler); 535 signal(SIGTERM, signal_handler); 536 537 /* parse application arguments (after the EAL ones) */ 538 ret = l2fwd_parse_args(argc, argv); 539 if (ret < 0) 540 rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 541 542 printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); 543 544 /* convert to number of cycles */ 545 timer_period *= rte_get_timer_hz(); 546 547 nb_ports = rte_eth_dev_count_avail(); 548 if (nb_ports == 0) 549 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 550 551 /* check port mask to possible port mask */ 552 if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1)) 553 rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", 554 (1 << nb_ports) - 1); 555 556 /* reset l2fwd_dst_ports */ 557 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 558 l2fwd_dst_ports[portid] = 0; 559 last_port = 0; 560 561 /* 562 * Each logical core is assigned a dedicated TX queue on each port. 563 */ 564 RTE_ETH_FOREACH_DEV(portid) { 565 /* skip ports that are not enabled */ 566 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 567 continue; 568 569 if (nb_ports_in_mask % 2) { 570 l2fwd_dst_ports[portid] = last_port; 571 l2fwd_dst_ports[last_port] = portid; 572 } 573 else 574 last_port = portid; 575 576 nb_ports_in_mask++; 577 } 578 if (nb_ports_in_mask % 2) { 579 printf("Notice: odd number of ports in portmask.\n"); 580 l2fwd_dst_ports[last_port] = last_port; 581 } 582 583 rx_lcore_id = 0; 584 qconf = NULL; 585 586 /* Initialize the port/queue configuration of each logical core */ 587 RTE_ETH_FOREACH_DEV(portid) { 588 /* skip ports that are not enabled */ 589 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 590 continue; 591 592 /* get the lcore_id for this port */ 593 while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 594 lcore_queue_conf[rx_lcore_id].n_rx_port == 595 l2fwd_rx_queue_per_lcore) { 596 rx_lcore_id++; 597 if (rx_lcore_id >= RTE_MAX_LCORE) 598 rte_exit(EXIT_FAILURE, "Not enough cores\n"); 599 } 600 601 if (qconf != &lcore_queue_conf[rx_lcore_id]) { 602 /* Assigned a new logical core in the loop above. */ 603 qconf = &lcore_queue_conf[rx_lcore_id]; 604 nb_lcores++; 605 } 606 607 qconf->rx_port_list[qconf->n_rx_port] = portid; 608 qconf->n_rx_port++; 609 printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); 610 } 611 612 nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + 613 nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); 614 615 /* create the mbuf pool */ 616 l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, 617 MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, 618 rte_socket_id()); 619 if (l2fwd_pktmbuf_pool == NULL) 620 rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 621 622 /* Initialise each port */ 623 RTE_ETH_FOREACH_DEV(portid) { 624 struct rte_eth_rxconf rxq_conf; 625 struct rte_eth_txconf txq_conf; 626 struct rte_eth_conf local_port_conf = port_conf; 627 struct rte_eth_dev_info dev_info; 628 629 /* skip ports that are not enabled */ 630 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 631 printf("Skipping disabled port %u\n", portid); 632 continue; 633 } 634 nb_ports_available++; 635 636 /* init port */ 637 printf("Initializing port %u... ", portid); 638 fflush(stdout); 639 rte_eth_dev_info_get(portid, &dev_info); 640 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 641 local_port_conf.txmode.offloads |= 642 DEV_TX_OFFLOAD_MBUF_FAST_FREE; 643 ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); 644 if (ret < 0) 645 rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 646 ret, portid); 647 648 ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, 649 &nb_txd); 650 if (ret < 0) 651 rte_exit(EXIT_FAILURE, 652 "Cannot adjust number of descriptors: err=%d, port=%u\n", 653 ret, portid); 654 655 rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); 656 657 /* init one RX queue */ 658 fflush(stdout); 659 rxq_conf = dev_info.default_rxconf; 660 rxq_conf.offloads = local_port_conf.rxmode.offloads; 661 ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 662 rte_eth_dev_socket_id(portid), 663 &rxq_conf, 664 l2fwd_pktmbuf_pool); 665 if (ret < 0) 666 rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", 667 ret, portid); 668 669 /* init one TX queue on each port */ 670 fflush(stdout); 671 txq_conf = dev_info.default_txconf; 672 txq_conf.offloads = local_port_conf.txmode.offloads; 673 ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 674 rte_eth_dev_socket_id(portid), 675 &txq_conf); 676 if (ret < 0) 677 rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", 678 ret, portid); 679 680 /* Initialize TX buffers */ 681 tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", 682 RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, 683 rte_eth_dev_socket_id(portid)); 684 if (tx_buffer[portid] == NULL) 685 rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", 686 portid); 687 688 rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); 689 690 ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], 691 rte_eth_tx_buffer_count_callback, 692 &port_statistics[portid].dropped); 693 if (ret < 0) 694 rte_exit(EXIT_FAILURE, 695 "Cannot set error callback for tx buffer on port %u\n", 696 portid); 697 698 /* Start device */ 699 ret = rte_eth_dev_start(portid); 700 if (ret < 0) 701 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 702 ret, portid); 703 704 printf("done: \n"); 705 706 rte_eth_promiscuous_enable(portid); 707 708 printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 709 portid, 710 l2fwd_ports_eth_addr[portid].addr_bytes[0], 711 l2fwd_ports_eth_addr[portid].addr_bytes[1], 712 l2fwd_ports_eth_addr[portid].addr_bytes[2], 713 l2fwd_ports_eth_addr[portid].addr_bytes[3], 714 l2fwd_ports_eth_addr[portid].addr_bytes[4], 715 l2fwd_ports_eth_addr[portid].addr_bytes[5]); 716 717 /* initialize port stats */ 718 memset(&port_statistics, 0, sizeof(port_statistics)); 719 } 720 721 if (!nb_ports_available) { 722 rte_exit(EXIT_FAILURE, 723 "All available ports are disabled. Please set portmask.\n"); 724 } 725 726 check_all_ports_link_status(l2fwd_enabled_port_mask); 727 728 ret = 0; 729 /* launch per-lcore init on every lcore */ 730 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER); 731 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 732 if (rte_eal_wait_lcore(lcore_id) < 0) { 733 ret = -1; 734 break; 735 } 736 } 737 738 RTE_ETH_FOREACH_DEV(portid) { 739 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 740 continue; 741 printf("Closing port %d...", portid); 742 rte_eth_dev_stop(portid); 743 rte_eth_dev_close(portid); 744 printf(" Done\n"); 745 } 746 printf("Bye...\n"); 747 748 return ret; 749 } 750