1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <stdint.h> 38 #include <inttypes.h> 39 #include <sys/types.h> 40 #include <sys/queue.h> 41 #include <netinet/in.h> 42 #include <setjmp.h> 43 #include <stdarg.h> 44 #include <ctype.h> 45 #include <errno.h> 46 #include <getopt.h> 47 48 #include <rte_common.h> 49 #include <rte_log.h> 50 #include <rte_memory.h> 51 #include <rte_memcpy.h> 52 #include <rte_memzone.h> 53 #include <rte_tailq.h> 54 #include <rte_eal.h> 55 #include <rte_per_lcore.h> 56 #include <rte_launch.h> 57 #include <rte_atomic.h> 58 #include <rte_cycles.h> 59 #include <rte_prefetch.h> 60 #include <rte_lcore.h> 61 #include <rte_per_lcore.h> 62 #include <rte_branch_prediction.h> 63 #include <rte_interrupts.h> 64 #include <rte_pci.h> 65 #include <rte_random.h> 66 #include <rte_debug.h> 67 #include <rte_ether.h> 68 #include <rte_ethdev.h> 69 #include <rte_ring.h> 70 #include <rte_mempool.h> 71 #include <rte_mbuf.h> 72 73 #include "main.h" 74 75 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 76 77 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 78 #define NB_MBUF 8192 79 80 /* 81 * RX and TX Prefetch, Host, and Write-back threshold values should be 82 * carefully set for optimal performance. Consult the network 83 * controller's datasheet and supporting DPDK documentation for guidance 84 * on how these parameters should be set. 85 */ 86 #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ 87 #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */ 88 #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */ 89 90 /* 91 * These default values are optimized for use with the Intel(R) 82599 10 GbE 92 * Controller and the DPDK ixgbe PMD. Consider using other values for other 93 * network controllers and/or network drivers. 94 */ 95 #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */ 96 #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ 97 #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ 98 99 #define MAX_PKT_BURST 32 100 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ 101 102 /* 103 * Configurable number of RX/TX ring descriptors 104 */ 105 #define RTE_TEST_RX_DESC_DEFAULT 128 106 #define RTE_TEST_TX_DESC_DEFAULT 512 107 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 108 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 109 110 /* ethernet addresses of ports */ 111 static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; 112 113 /* mask of enabled ports */ 114 static uint32_t l2fwd_enabled_port_mask = 0; 115 116 /* list of enabled ports */ 117 static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; 118 119 static unsigned int l2fwd_rx_queue_per_lcore = 1; 120 121 struct mbuf_table { 122 unsigned len; 123 struct rte_mbuf *m_table[MAX_PKT_BURST]; 124 }; 125 126 #define MAX_RX_QUEUE_PER_LCORE 16 127 #define MAX_TX_QUEUE_PER_PORT 16 128 struct lcore_queue_conf { 129 unsigned n_rx_port; 130 unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 131 struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS]; 132 133 } __rte_cache_aligned; 134 struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 135 136 static const struct rte_eth_conf port_conf = { 137 .rxmode = { 138 .split_hdr_size = 0, 139 .header_split = 0, /**< Header Split disabled */ 140 .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 141 .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 142 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 143 .hw_strip_crc = 0, /**< CRC stripped by hardware */ 144 }, 145 .txmode = { 146 .mq_mode = ETH_MQ_TX_NONE, 147 }, 148 }; 149 150 static const struct rte_eth_rxconf rx_conf = { 151 .rx_thresh = { 152 .pthresh = RX_PTHRESH, 153 .hthresh = RX_HTHRESH, 154 .wthresh = RX_WTHRESH, 155 }, 156 }; 157 158 static const struct rte_eth_txconf tx_conf = { 159 .tx_thresh = { 160 .pthresh = TX_PTHRESH, 161 .hthresh = TX_HTHRESH, 162 .wthresh = TX_WTHRESH, 163 }, 164 .tx_free_thresh = 0, /* Use PMD default values */ 165 .tx_rs_thresh = 0, /* Use PMD default values */ 166 }; 167 168 struct rte_mempool * l2fwd_pktmbuf_pool = NULL; 169 170 /* Per-port statistics struct */ 171 struct l2fwd_port_statistics { 172 uint64_t tx; 173 uint64_t rx; 174 uint64_t dropped; 175 } __rte_cache_aligned; 176 struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; 177 178 /* A tsc-based timer responsible for triggering statistics printout */ 179 #define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */ 180 #define MAX_TIMER_PERIOD 86400 /* 1 day max */ 181 static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */ 182 183 /* Print out statistics on packets dropped */ 184 static void 185 print_stats(void) 186 { 187 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; 188 unsigned portid; 189 190 total_packets_dropped = 0; 191 total_packets_tx = 0; 192 total_packets_rx = 0; 193 194 const char clr[] = { 27, '[', '2', 'J', '\0' }; 195 const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; 196 197 /* Clear screen and move to top left */ 198 printf("%s%s", clr, topLeft); 199 200 printf("\nPort statistics ===================================="); 201 202 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 203 /* skip disabled ports */ 204 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 205 continue; 206 printf("\nStatistics for port %u ------------------------------" 207 "\nPackets sent: %24"PRIu64 208 "\nPackets received: %20"PRIu64 209 "\nPackets dropped: %21"PRIu64, 210 portid, 211 port_statistics[portid].tx, 212 port_statistics[portid].rx, 213 port_statistics[portid].dropped); 214 215 total_packets_dropped += port_statistics[portid].dropped; 216 total_packets_tx += port_statistics[portid].tx; 217 total_packets_rx += port_statistics[portid].rx; 218 } 219 printf("\nAggregate statistics ===============================" 220 "\nTotal packets sent: %18"PRIu64 221 "\nTotal packets received: %14"PRIu64 222 "\nTotal packets dropped: %15"PRIu64, 223 total_packets_tx, 224 total_packets_rx, 225 total_packets_dropped); 226 printf("\n====================================================\n"); 227 } 228 229 /* Send the burst of packets on an output interface */ 230 static int 231 l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port) 232 { 233 struct rte_mbuf **m_table; 234 unsigned ret; 235 unsigned queueid =0; 236 237 m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table; 238 239 ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n); 240 port_statistics[port].tx += ret; 241 if (unlikely(ret < n)) { 242 port_statistics[port].dropped += (n - ret); 243 do { 244 rte_pktmbuf_free(m_table[ret]); 245 } while (++ret < n); 246 } 247 248 return 0; 249 } 250 251 /* Enqueue packets for TX and prepare them to be sent */ 252 static int 253 l2fwd_send_packet(struct rte_mbuf *m, uint8_t port) 254 { 255 unsigned lcore_id, len; 256 struct lcore_queue_conf *qconf; 257 258 lcore_id = rte_lcore_id(); 259 260 qconf = &lcore_queue_conf[lcore_id]; 261 len = qconf->tx_mbufs[port].len; 262 qconf->tx_mbufs[port].m_table[len] = m; 263 len++; 264 265 /* enough pkts to be sent */ 266 if (unlikely(len == MAX_PKT_BURST)) { 267 l2fwd_send_burst(qconf, MAX_PKT_BURST, port); 268 len = 0; 269 } 270 271 qconf->tx_mbufs[port].len = len; 272 return 0; 273 } 274 275 static void 276 l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) 277 { 278 struct ether_hdr *eth; 279 void *tmp; 280 unsigned dst_port; 281 282 dst_port = l2fwd_dst_ports[portid]; 283 eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 284 285 /* 02:00:00:00:00:xx */ 286 tmp = ð->d_addr.addr_bytes[0]; 287 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 288 289 /* src addr */ 290 ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr); 291 292 l2fwd_send_packet(m, (uint8_t) dst_port); 293 } 294 295 /* main processing loop */ 296 static void 297 l2fwd_main_loop(void) 298 { 299 struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 300 struct rte_mbuf *m; 301 unsigned lcore_id; 302 uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; 303 unsigned i, j, portid, nb_rx; 304 struct lcore_queue_conf *qconf; 305 const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; 306 307 prev_tsc = 0; 308 timer_tsc = 0; 309 310 lcore_id = rte_lcore_id(); 311 qconf = &lcore_queue_conf[lcore_id]; 312 313 if (qconf->n_rx_port == 0) { 314 RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); 315 return; 316 } 317 318 RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); 319 320 for (i = 0; i < qconf->n_rx_port; i++) { 321 322 portid = qconf->rx_port_list[i]; 323 RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, 324 portid); 325 } 326 327 while (1) { 328 329 cur_tsc = rte_rdtsc(); 330 331 /* 332 * TX burst queue drain 333 */ 334 diff_tsc = cur_tsc - prev_tsc; 335 if (unlikely(diff_tsc > drain_tsc)) { 336 337 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 338 if (qconf->tx_mbufs[portid].len == 0) 339 continue; 340 l2fwd_send_burst(&lcore_queue_conf[lcore_id], 341 qconf->tx_mbufs[portid].len, 342 (uint8_t) portid); 343 qconf->tx_mbufs[portid].len = 0; 344 } 345 346 /* if timer is enabled */ 347 if (timer_period > 0) { 348 349 /* advance the timer */ 350 timer_tsc += diff_tsc; 351 352 /* if timer has reached its timeout */ 353 if (unlikely(timer_tsc >= (uint64_t) timer_period)) { 354 355 /* do this only on master core */ 356 if (lcore_id == rte_get_master_lcore()) { 357 print_stats(); 358 /* reset the timer */ 359 timer_tsc = 0; 360 } 361 } 362 } 363 364 prev_tsc = cur_tsc; 365 } 366 367 /* 368 * Read packet from RX queues 369 */ 370 for (i = 0; i < qconf->n_rx_port; i++) { 371 372 portid = qconf->rx_port_list[i]; 373 nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, 374 pkts_burst, MAX_PKT_BURST); 375 376 port_statistics[portid].rx += nb_rx; 377 378 for (j = 0; j < nb_rx; j++) { 379 m = pkts_burst[j]; 380 rte_prefetch0(rte_pktmbuf_mtod(m, void *)); 381 l2fwd_simple_forward(m, portid); 382 } 383 } 384 } 385 } 386 387 static int 388 l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy) 389 { 390 l2fwd_main_loop(); 391 return 0; 392 } 393 394 /* display usage */ 395 static void 396 l2fwd_usage(const char *prgname) 397 { 398 printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" 399 " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 400 " -q NQ: number of queue (=ports) per lcore (default is 1)\n" 401 " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n", 402 prgname); 403 } 404 405 static int 406 l2fwd_parse_portmask(const char *portmask) 407 { 408 char *end = NULL; 409 unsigned long pm; 410 411 /* parse hexadecimal string */ 412 pm = strtoul(portmask, &end, 16); 413 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 414 return -1; 415 416 if (pm == 0) 417 return -1; 418 419 return pm; 420 } 421 422 static unsigned int 423 l2fwd_parse_nqueue(const char *q_arg) 424 { 425 char *end = NULL; 426 unsigned long n; 427 428 /* parse hexadecimal string */ 429 n = strtoul(q_arg, &end, 10); 430 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 431 return 0; 432 if (n == 0) 433 return 0; 434 if (n >= MAX_RX_QUEUE_PER_LCORE) 435 return 0; 436 437 return n; 438 } 439 440 static int 441 l2fwd_parse_timer_period(const char *q_arg) 442 { 443 char *end = NULL; 444 int n; 445 446 /* parse number string */ 447 n = strtol(q_arg, &end, 10); 448 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 449 return -1; 450 if (n >= MAX_TIMER_PERIOD) 451 return -1; 452 453 return n; 454 } 455 456 /* Parse the argument given in the command line of the application */ 457 static int 458 l2fwd_parse_args(int argc, char **argv) 459 { 460 int opt, ret; 461 char **argvopt; 462 int option_index; 463 char *prgname = argv[0]; 464 static struct option lgopts[] = { 465 {NULL, 0, 0, 0} 466 }; 467 468 argvopt = argv; 469 470 while ((opt = getopt_long(argc, argvopt, "p:q:T:", 471 lgopts, &option_index)) != EOF) { 472 473 switch (opt) { 474 /* portmask */ 475 case 'p': 476 l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); 477 if (l2fwd_enabled_port_mask == 0) { 478 printf("invalid portmask\n"); 479 l2fwd_usage(prgname); 480 return -1; 481 } 482 break; 483 484 /* nqueue */ 485 case 'q': 486 l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); 487 if (l2fwd_rx_queue_per_lcore == 0) { 488 printf("invalid queue number\n"); 489 l2fwd_usage(prgname); 490 return -1; 491 } 492 break; 493 494 /* timer period */ 495 case 'T': 496 timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND; 497 if (timer_period < 0) { 498 printf("invalid timer period\n"); 499 l2fwd_usage(prgname); 500 return -1; 501 } 502 break; 503 504 /* long options */ 505 case 0: 506 l2fwd_usage(prgname); 507 return -1; 508 509 default: 510 l2fwd_usage(prgname); 511 return -1; 512 } 513 } 514 515 if (optind >= 0) 516 argv[optind-1] = prgname; 517 518 ret = optind-1; 519 optind = 0; /* reset getopt lib */ 520 return ret; 521 } 522 523 /* Check the link status of all ports in up to 9s, and print them finally */ 524 static void 525 check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) 526 { 527 #define CHECK_INTERVAL 100 /* 100ms */ 528 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 529 uint8_t portid, count, all_ports_up, print_flag = 0; 530 struct rte_eth_link link; 531 532 printf("\nChecking link status"); 533 fflush(stdout); 534 for (count = 0; count <= MAX_CHECK_TIME; count++) { 535 all_ports_up = 1; 536 for (portid = 0; portid < port_num; portid++) { 537 if ((port_mask & (1 << portid)) == 0) 538 continue; 539 memset(&link, 0, sizeof(link)); 540 rte_eth_link_get_nowait(portid, &link); 541 /* print link status if flag set */ 542 if (print_flag == 1) { 543 if (link.link_status) 544 printf("Port %d Link Up - speed %u " 545 "Mbps - %s\n", (uint8_t)portid, 546 (unsigned)link.link_speed, 547 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 548 ("full-duplex") : ("half-duplex\n")); 549 else 550 printf("Port %d Link Down\n", 551 (uint8_t)portid); 552 continue; 553 } 554 /* clear all_ports_up flag if any link down */ 555 if (link.link_status == 0) { 556 all_ports_up = 0; 557 break; 558 } 559 } 560 /* after finally printing all link status, get out */ 561 if (print_flag == 1) 562 break; 563 564 if (all_ports_up == 0) { 565 printf("."); 566 fflush(stdout); 567 rte_delay_ms(CHECK_INTERVAL); 568 } 569 570 /* set the print_flag if all ports up or timeout */ 571 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 572 print_flag = 1; 573 printf("done\n"); 574 } 575 } 576 } 577 578 int 579 MAIN(int argc, char **argv) 580 { 581 struct lcore_queue_conf *qconf; 582 struct rte_eth_dev_info dev_info; 583 int ret; 584 uint8_t nb_ports; 585 uint8_t nb_ports_available; 586 uint8_t portid, last_port; 587 unsigned lcore_id, rx_lcore_id; 588 unsigned nb_ports_in_mask = 0; 589 590 /* init EAL */ 591 ret = rte_eal_init(argc, argv); 592 if (ret < 0) 593 rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 594 argc -= ret; 595 argv += ret; 596 597 /* parse application arguments (after the EAL ones) */ 598 ret = l2fwd_parse_args(argc, argv); 599 if (ret < 0) 600 rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 601 602 /* create the mbuf pool */ 603 l2fwd_pktmbuf_pool = 604 rte_mempool_create("mbuf_pool", NB_MBUF, 605 MBUF_SIZE, 32, 606 sizeof(struct rte_pktmbuf_pool_private), 607 rte_pktmbuf_pool_init, NULL, 608 rte_pktmbuf_init, NULL, 609 rte_socket_id(), 0); 610 if (l2fwd_pktmbuf_pool == NULL) 611 rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 612 613 /* init driver(s) */ 614 if (rte_pmd_init_all() < 0) 615 rte_exit(EXIT_FAILURE, "Cannot init pmd\n"); 616 617 if (rte_eal_pci_probe() < 0) 618 rte_exit(EXIT_FAILURE, "Cannot probe PCI\n"); 619 620 nb_ports = rte_eth_dev_count(); 621 if (nb_ports == 0) 622 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 623 624 if (nb_ports > RTE_MAX_ETHPORTS) 625 nb_ports = RTE_MAX_ETHPORTS; 626 627 /* reset l2fwd_dst_ports */ 628 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) 629 l2fwd_dst_ports[portid] = 0; 630 last_port = 0; 631 632 /* 633 * Each logical core is assigned a dedicated TX queue on each port. 634 */ 635 for (portid = 0; portid < nb_ports; portid++) { 636 /* skip ports that are not enabled */ 637 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 638 continue; 639 640 if (nb_ports_in_mask % 2) { 641 l2fwd_dst_ports[portid] = last_port; 642 l2fwd_dst_ports[last_port] = portid; 643 } 644 else 645 last_port = portid; 646 647 nb_ports_in_mask++; 648 649 rte_eth_dev_info_get(portid, &dev_info); 650 } 651 if (nb_ports_in_mask % 2) { 652 printf("Notice: odd number of ports in portmask.\n"); 653 l2fwd_dst_ports[last_port] = last_port; 654 } 655 656 rx_lcore_id = 0; 657 qconf = NULL; 658 659 /* Initialize the port/queue configuration of each logical core */ 660 for (portid = 0; portid < nb_ports; portid++) { 661 /* skip ports that are not enabled */ 662 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) 663 continue; 664 665 /* get the lcore_id for this port */ 666 while (rte_lcore_is_enabled(rx_lcore_id) == 0 || 667 lcore_queue_conf[rx_lcore_id].n_rx_port == 668 l2fwd_rx_queue_per_lcore) { 669 rx_lcore_id++; 670 if (rx_lcore_id >= RTE_MAX_LCORE) 671 rte_exit(EXIT_FAILURE, "Not enough cores\n"); 672 } 673 674 if (qconf != &lcore_queue_conf[rx_lcore_id]) 675 /* Assigned a new logical core in the loop above. */ 676 qconf = &lcore_queue_conf[rx_lcore_id]; 677 678 qconf->rx_port_list[qconf->n_rx_port] = portid; 679 qconf->n_rx_port++; 680 printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid); 681 } 682 683 nb_ports_available = nb_ports; 684 685 /* Initialise each port */ 686 for (portid = 0; portid < nb_ports; portid++) { 687 /* skip ports that are not enabled */ 688 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { 689 printf("Skipping disabled port %u\n", (unsigned) portid); 690 nb_ports_available--; 691 continue; 692 } 693 /* init port */ 694 printf("Initializing port %u... ", (unsigned) portid); 695 fflush(stdout); 696 ret = rte_eth_dev_configure(portid, 1, 1, &port_conf); 697 if (ret < 0) 698 rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 699 ret, (unsigned) portid); 700 701 rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); 702 703 /* init one RX queue */ 704 fflush(stdout); 705 ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 706 rte_eth_dev_socket_id(portid), &rx_conf, 707 l2fwd_pktmbuf_pool); 708 if (ret < 0) 709 rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", 710 ret, (unsigned) portid); 711 712 /* init one TX queue on each port */ 713 fflush(stdout); 714 ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 715 rte_eth_dev_socket_id(portid), &tx_conf); 716 if (ret < 0) 717 rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", 718 ret, (unsigned) portid); 719 720 /* Start device */ 721 ret = rte_eth_dev_start(portid); 722 if (ret < 0) 723 rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 724 ret, (unsigned) portid); 725 726 printf("done: \n"); 727 728 rte_eth_promiscuous_enable(portid); 729 730 printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 731 (unsigned) portid, 732 l2fwd_ports_eth_addr[portid].addr_bytes[0], 733 l2fwd_ports_eth_addr[portid].addr_bytes[1], 734 l2fwd_ports_eth_addr[portid].addr_bytes[2], 735 l2fwd_ports_eth_addr[portid].addr_bytes[3], 736 l2fwd_ports_eth_addr[portid].addr_bytes[4], 737 l2fwd_ports_eth_addr[portid].addr_bytes[5]); 738 739 /* initialize port stats */ 740 memset(&port_statistics, 0, sizeof(port_statistics)); 741 } 742 743 if (!nb_ports_available) { 744 rte_exit(EXIT_FAILURE, 745 "All available ports are disabled. Please set portmask.\n"); 746 } 747 748 check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask); 749 750 /* launch per-lcore init on every lcore */ 751 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER); 752 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 753 if (rte_eal_wait_lcore(lcore_id) < 0) 754 return -1; 755 } 756 757 return 0; 758 } 759 760