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 <stdint.h> 35 #include <sys/queue.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <stdio.h> 39 #include <assert.h> 40 #include <errno.h> 41 #include <signal.h> 42 #include <stdarg.h> 43 #include <inttypes.h> 44 #include <getopt.h> 45 46 #include <rte_common.h> 47 #include <rte_log.h> 48 #include <rte_memory.h> 49 #include <rte_memcpy.h> 50 #include <rte_memzone.h> 51 #include <rte_eal.h> 52 #include <rte_per_lcore.h> 53 #include <rte_launch.h> 54 #include <rte_atomic.h> 55 #include <rte_cycles.h> 56 #include <rte_prefetch.h> 57 #include <rte_lcore.h> 58 #include <rte_per_lcore.h> 59 #include <rte_branch_prediction.h> 60 #include <rte_interrupts.h> 61 #include <rte_pci.h> 62 #include <rte_random.h> 63 #include <rte_debug.h> 64 #include <rte_ether.h> 65 #include <rte_ethdev.h> 66 #include <rte_ring.h> 67 #include <rte_log.h> 68 #include <rte_mempool.h> 69 #include <rte_mbuf.h> 70 #include <rte_memcpy.h> 71 72 /* basic constants used in application */ 73 #define MAX_QUEUES 1024 74 /* 75 * 1024 queues require to meet the needs of a large number of vmdq_pools. 76 * (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port. 77 */ 78 #define NUM_MBUFS_PER_PORT (MAX_QUEUES * RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, \ 79 RTE_TEST_TX_DESC_DEFAULT)) 80 #define MBUF_CACHE_SIZE 64 81 82 #define MAX_PKT_BURST 32 83 84 /* 85 * Configurable number of RX/TX ring descriptors 86 */ 87 #define RTE_TEST_RX_DESC_DEFAULT 128 88 #define RTE_TEST_TX_DESC_DEFAULT 512 89 90 #define INVALID_PORT_ID 0xFF 91 92 /* mask of enabled ports */ 93 static uint32_t enabled_port_mask; 94 static uint8_t ports[RTE_MAX_ETHPORTS]; 95 static unsigned num_ports; 96 97 /* number of pools (if user does not specify any, 32 by default */ 98 static enum rte_eth_nb_pools num_pools = ETH_32_POOLS; 99 static enum rte_eth_nb_tcs num_tcs = ETH_4_TCS; 100 static uint16_t num_queues, num_vmdq_queues; 101 static uint16_t vmdq_pool_base, vmdq_queue_base; 102 static uint8_t rss_enable; 103 104 /* empty vmdq+dcb configuration structure. Filled in programatically */ 105 static const struct rte_eth_conf vmdq_dcb_conf_default = { 106 .rxmode = { 107 .mq_mode = ETH_MQ_RX_VMDQ_DCB, 108 .split_hdr_size = 0, 109 .header_split = 0, /**< Header Split disabled */ 110 .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 111 .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 112 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 113 }, 114 .txmode = { 115 .mq_mode = ETH_MQ_TX_VMDQ_DCB, 116 }, 117 /* 118 * should be overridden separately in code with 119 * appropriate values 120 */ 121 .rx_adv_conf = { 122 .vmdq_dcb_conf = { 123 .nb_queue_pools = ETH_32_POOLS, 124 .enable_default_pool = 0, 125 .default_pool = 0, 126 .nb_pool_maps = 0, 127 .pool_map = {{0, 0},}, 128 .dcb_tc = {0}, 129 }, 130 .dcb_rx_conf = { 131 .nb_tcs = ETH_4_TCS, 132 /** Traffic class each UP mapped to. */ 133 .dcb_tc = {0}, 134 }, 135 .vmdq_rx_conf = { 136 .nb_queue_pools = ETH_32_POOLS, 137 .enable_default_pool = 0, 138 .default_pool = 0, 139 .nb_pool_maps = 0, 140 .pool_map = {{0, 0},}, 141 }, 142 }, 143 .tx_adv_conf = { 144 .vmdq_dcb_tx_conf = { 145 .nb_queue_pools = ETH_32_POOLS, 146 .dcb_tc = {0}, 147 }, 148 }, 149 }; 150 151 /* array used for printing out statistics */ 152 volatile unsigned long rxPackets[MAX_QUEUES] = {0}; 153 154 const uint16_t vlan_tags[] = { 155 0, 1, 2, 3, 4, 5, 6, 7, 156 8, 9, 10, 11, 12, 13, 14, 15, 157 16, 17, 18, 19, 20, 21, 22, 23, 158 24, 25, 26, 27, 28, 29, 30, 31 159 }; 160 161 const uint16_t num_vlans = RTE_DIM(vlan_tags); 162 /* pool mac addr template, pool mac addr is like: 52 54 00 12 port# pool# */ 163 static struct ether_addr pool_addr_template = { 164 .addr_bytes = {0x52, 0x54, 0x00, 0x12, 0x00, 0x00} 165 }; 166 167 /* ethernet addresses of ports */ 168 static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS]; 169 170 /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array 171 * given above, and the number of traffic classes available for use. */ 172 static inline int 173 get_eth_conf(struct rte_eth_conf *eth_conf) 174 { 175 struct rte_eth_vmdq_dcb_conf conf; 176 struct rte_eth_vmdq_rx_conf vmdq_conf; 177 struct rte_eth_dcb_rx_conf dcb_conf; 178 struct rte_eth_vmdq_dcb_tx_conf tx_conf; 179 uint8_t i; 180 181 conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 182 vmdq_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 183 tx_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 184 conf.nb_pool_maps = num_pools; 185 vmdq_conf.nb_pool_maps = num_pools; 186 conf.enable_default_pool = 0; 187 vmdq_conf.enable_default_pool = 0; 188 conf.default_pool = 0; /* set explicit value, even if not used */ 189 vmdq_conf.default_pool = 0; 190 191 for (i = 0; i < conf.nb_pool_maps; i++) { 192 conf.pool_map[i].vlan_id = vlan_tags[i]; 193 vmdq_conf.pool_map[i].vlan_id = vlan_tags[i]; 194 conf.pool_map[i].pools = 1UL << i; 195 vmdq_conf.pool_map[i].pools = 1UL << i; 196 } 197 for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){ 198 conf.dcb_tc[i] = i % num_tcs; 199 dcb_conf.dcb_tc[i] = i % num_tcs; 200 tx_conf.dcb_tc[i] = i % num_tcs; 201 } 202 dcb_conf.nb_tcs = (enum rte_eth_nb_tcs)num_tcs; 203 (void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf))); 204 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_dcb_conf, &conf, 205 sizeof(conf))); 206 (void)(rte_memcpy(ð_conf->rx_adv_conf.dcb_rx_conf, &dcb_conf, 207 sizeof(dcb_conf))); 208 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &vmdq_conf, 209 sizeof(vmdq_conf))); 210 (void)(rte_memcpy(ð_conf->tx_adv_conf.vmdq_dcb_tx_conf, &tx_conf, 211 sizeof(tx_conf))); 212 if (rss_enable) { 213 eth_conf->rxmode.mq_mode = ETH_MQ_RX_VMDQ_DCB_RSS; 214 eth_conf->rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP | 215 ETH_RSS_UDP | 216 ETH_RSS_TCP | 217 ETH_RSS_SCTP; 218 } 219 return 0; 220 } 221 222 /* 223 * Initialises a given port using global settings and with the rx buffers 224 * coming from the mbuf_pool passed as parameter 225 */ 226 static inline int 227 port_init(uint8_t port, struct rte_mempool *mbuf_pool) 228 { 229 struct rte_eth_dev_info dev_info; 230 struct rte_eth_conf port_conf = {0}; 231 const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT; 232 const uint16_t txRingSize = RTE_TEST_TX_DESC_DEFAULT; 233 int retval; 234 uint16_t q; 235 uint16_t queues_per_pool; 236 uint32_t max_nb_pools; 237 238 /* 239 * The max pool number from dev_info will be used to validate the pool 240 * number specified in cmd line 241 */ 242 rte_eth_dev_info_get(port, &dev_info); 243 max_nb_pools = (uint32_t)dev_info.max_vmdq_pools; 244 /* 245 * We allow to process part of VMDQ pools specified by num_pools in 246 * command line. 247 */ 248 if (num_pools > max_nb_pools) { 249 printf("num_pools %d >max_nb_pools %d\n", 250 num_pools, max_nb_pools); 251 return -1; 252 } 253 254 /* 255 * NIC queues are divided into pf queues and vmdq queues. 256 * There is assumption here all ports have the same configuration! 257 */ 258 vmdq_queue_base = dev_info.vmdq_queue_base; 259 vmdq_pool_base = dev_info.vmdq_pool_base; 260 printf("vmdq queue base: %d pool base %d\n", 261 vmdq_queue_base, vmdq_pool_base); 262 if (vmdq_pool_base == 0) { 263 num_vmdq_queues = dev_info.max_rx_queues; 264 num_queues = dev_info.max_rx_queues; 265 if (num_tcs != num_vmdq_queues / num_pools) { 266 printf("nb_tcs %d is invalid considering with" 267 " nb_pools %d, nb_tcs * nb_pools should = %d\n", 268 num_tcs, num_pools, num_vmdq_queues); 269 return -1; 270 } 271 } else { 272 queues_per_pool = dev_info.vmdq_queue_num / 273 dev_info.max_vmdq_pools; 274 if (num_tcs > queues_per_pool) { 275 printf("num_tcs %d > num of queues per pool %d\n", 276 num_tcs, queues_per_pool); 277 return -1; 278 } 279 num_vmdq_queues = num_pools * queues_per_pool; 280 num_queues = vmdq_queue_base + num_vmdq_queues; 281 printf("Configured vmdq pool num: %u," 282 " each vmdq pool has %u queues\n", 283 num_pools, queues_per_pool); 284 } 285 286 if (port >= rte_eth_dev_count()) 287 return -1; 288 289 retval = get_eth_conf(&port_conf); 290 if (retval < 0) 291 return retval; 292 293 /* 294 * Though in this example, all queues including pf queues are setup. 295 * This is because VMDQ queues doesn't always start from zero, and the 296 * PMD layer doesn't support selectively initialising part of rx/tx 297 * queues. 298 */ 299 retval = rte_eth_dev_configure(port, num_queues, num_queues, &port_conf); 300 if (retval != 0) 301 return retval; 302 303 for (q = 0; q < num_queues; q++) { 304 retval = rte_eth_rx_queue_setup(port, q, rxRingSize, 305 rte_eth_dev_socket_id(port), 306 NULL, 307 mbuf_pool); 308 if (retval < 0) { 309 printf("initialize rx queue %d failed\n", q); 310 return retval; 311 } 312 } 313 314 for (q = 0; q < num_queues; q++) { 315 retval = rte_eth_tx_queue_setup(port, q, txRingSize, 316 rte_eth_dev_socket_id(port), 317 NULL); 318 if (retval < 0) { 319 printf("initialize tx queue %d failed\n", q); 320 return retval; 321 } 322 } 323 324 retval = rte_eth_dev_start(port); 325 if (retval < 0) { 326 printf("port %d start failed\n", port); 327 return retval; 328 } 329 330 rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]); 331 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 332 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 333 (unsigned)port, 334 vmdq_ports_eth_addr[port].addr_bytes[0], 335 vmdq_ports_eth_addr[port].addr_bytes[1], 336 vmdq_ports_eth_addr[port].addr_bytes[2], 337 vmdq_ports_eth_addr[port].addr_bytes[3], 338 vmdq_ports_eth_addr[port].addr_bytes[4], 339 vmdq_ports_eth_addr[port].addr_bytes[5]); 340 341 /* Set mac for each pool.*/ 342 for (q = 0; q < num_pools; q++) { 343 struct ether_addr mac; 344 345 mac = pool_addr_template; 346 mac.addr_bytes[4] = port; 347 mac.addr_bytes[5] = q; 348 printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n", 349 port, q, 350 mac.addr_bytes[0], mac.addr_bytes[1], 351 mac.addr_bytes[2], mac.addr_bytes[3], 352 mac.addr_bytes[4], mac.addr_bytes[5]); 353 retval = rte_eth_dev_mac_addr_add(port, &mac, 354 q + vmdq_pool_base); 355 if (retval) { 356 printf("mac addr add failed at pool %d\n", q); 357 return retval; 358 } 359 } 360 361 return 0; 362 } 363 364 /* Check num_pools parameter and set it if OK*/ 365 static int 366 vmdq_parse_num_pools(const char *q_arg) 367 { 368 char *end = NULL; 369 int n; 370 371 /* parse number string */ 372 n = strtol(q_arg, &end, 10); 373 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 374 return -1; 375 if (n != 16 && n != 32) 376 return -1; 377 if (n == 16) 378 num_pools = ETH_16_POOLS; 379 else 380 num_pools = ETH_32_POOLS; 381 382 return 0; 383 } 384 385 /* Check num_tcs parameter and set it if OK*/ 386 static int 387 vmdq_parse_num_tcs(const char *q_arg) 388 { 389 char *end = NULL; 390 int n; 391 392 /* parse number string */ 393 n = strtol(q_arg, &end, 10); 394 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 395 return -1; 396 397 if (n != 4 && n != 8) 398 return -1; 399 if (n == 4) 400 num_tcs = ETH_4_TCS; 401 else 402 num_tcs = ETH_8_TCS; 403 404 return 0; 405 } 406 407 static int 408 parse_portmask(const char *portmask) 409 { 410 char *end = NULL; 411 unsigned long pm; 412 413 /* parse hexadecimal string */ 414 pm = strtoul(portmask, &end, 16); 415 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 416 return -1; 417 418 if (pm == 0) 419 return -1; 420 421 return pm; 422 } 423 424 /* Display usage */ 425 static void 426 vmdq_usage(const char *prgname) 427 { 428 printf("%s [EAL options] -- -p PORTMASK]\n" 429 " --nb-pools NP: number of pools (32 default, 16)\n" 430 " --nb-tcs NP: number of TCs (4 default, 8)\n" 431 " --enable-rss: enable RSS (disabled by default)\n", 432 prgname); 433 } 434 435 /* Parse the argument (num_pools) given in the command line of the application */ 436 static int 437 vmdq_parse_args(int argc, char **argv) 438 { 439 int opt; 440 int option_index; 441 unsigned i; 442 const char *prgname = argv[0]; 443 static struct option long_option[] = { 444 {"nb-pools", required_argument, NULL, 0}, 445 {"nb-tcs", required_argument, NULL, 0}, 446 {"enable-rss", 0, NULL, 0}, 447 {NULL, 0, 0, 0} 448 }; 449 450 /* Parse command line */ 451 while ((opt = getopt_long(argc, argv, "p:", long_option, 452 &option_index)) != EOF) { 453 switch (opt) { 454 /* portmask */ 455 case 'p': 456 enabled_port_mask = parse_portmask(optarg); 457 if (enabled_port_mask == 0) { 458 printf("invalid portmask\n"); 459 vmdq_usage(prgname); 460 return -1; 461 } 462 break; 463 case 0: 464 if (!strcmp(long_option[option_index].name, "nb-pools")) { 465 if (vmdq_parse_num_pools(optarg) == -1) { 466 printf("invalid number of pools\n"); 467 return -1; 468 } 469 } 470 471 if (!strcmp(long_option[option_index].name, "nb-tcs")) { 472 if (vmdq_parse_num_tcs(optarg) == -1) { 473 printf("invalid number of tcs\n"); 474 return -1; 475 } 476 } 477 478 if (!strcmp(long_option[option_index].name, "enable-rss")) 479 rss_enable = 1; 480 break; 481 482 default: 483 vmdq_usage(prgname); 484 return -1; 485 } 486 } 487 488 for (i = 0; i < RTE_MAX_ETHPORTS; i++) { 489 if (enabled_port_mask & (1 << i)) 490 ports[num_ports++] = (uint8_t)i; 491 } 492 493 if (num_ports < 2 || num_ports % 2) { 494 printf("Current enabled port number is %u," 495 " but it should be even and at least 2\n", num_ports); 496 return -1; 497 } 498 499 return 0; 500 } 501 502 static void 503 update_mac_address(struct rte_mbuf *m, unsigned dst_port) 504 { 505 struct ether_hdr *eth; 506 void *tmp; 507 508 eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 509 510 /* 02:00:00:00:00:xx */ 511 tmp = ð->d_addr.addr_bytes[0]; 512 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 513 514 /* src addr */ 515 ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr); 516 } 517 518 /* When we receive a HUP signal, print out our stats */ 519 static void 520 sighup_handler(int signum) 521 { 522 unsigned q = vmdq_queue_base; 523 524 for (; q < num_queues; q++) { 525 if (q % (num_vmdq_queues / num_pools) == 0) 526 printf("\nPool %u: ", (q - vmdq_queue_base) / 527 (num_vmdq_queues / num_pools)); 528 printf("%lu ", rxPackets[q]); 529 } 530 printf("\nFinished handling signal %d\n", signum); 531 } 532 533 /* 534 * Main thread that does the work, reading from INPUT_PORT 535 * and writing to OUTPUT_PORT 536 */ 537 static int 538 lcore_main(void *arg) 539 { 540 const uintptr_t core_num = (uintptr_t)arg; 541 const unsigned num_cores = rte_lcore_count(); 542 uint16_t startQueue, endQueue; 543 uint16_t q, i, p; 544 const uint16_t quot = (uint16_t)(num_vmdq_queues / num_cores); 545 const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores); 546 547 548 if (remainder) { 549 if (core_num < remainder) { 550 startQueue = (uint16_t)(core_num * (quot + 1)); 551 endQueue = (uint16_t)(startQueue + quot + 1); 552 } else { 553 startQueue = (uint16_t)(core_num * quot + remainder); 554 endQueue = (uint16_t)(startQueue + quot); 555 } 556 } else { 557 startQueue = (uint16_t)(core_num * quot); 558 endQueue = (uint16_t)(startQueue + quot); 559 } 560 561 /* vmdq queue idx doesn't always start from zero.*/ 562 startQueue += vmdq_queue_base; 563 endQueue += vmdq_queue_base; 564 printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num, 565 rte_lcore_id(), startQueue, endQueue - 1); 566 567 if (startQueue == endQueue) { 568 printf("lcore %u has nothing to do\n", (unsigned)core_num); 569 return 0; 570 } 571 572 for (;;) { 573 struct rte_mbuf *buf[MAX_PKT_BURST]; 574 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]); 575 for (p = 0; p < num_ports; p++) { 576 const uint8_t src = ports[p]; 577 const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */ 578 579 if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID)) 580 continue; 581 582 for (q = startQueue; q < endQueue; q++) { 583 const uint16_t rxCount = rte_eth_rx_burst(src, 584 q, buf, buf_size); 585 586 if (unlikely(rxCount == 0)) 587 continue; 588 589 rxPackets[q] += rxCount; 590 591 for (i = 0; i < rxCount; i++) 592 update_mac_address(buf[i], dst); 593 594 const uint16_t txCount = rte_eth_tx_burst(dst, 595 q, buf, rxCount); 596 if (txCount != rxCount) { 597 for (i = txCount; i < rxCount; i++) 598 rte_pktmbuf_free(buf[i]); 599 } 600 } 601 } 602 } 603 } 604 605 /* 606 * Update the global var NUM_PORTS and array PORTS according to system ports number 607 * and return valid ports number 608 */ 609 static unsigned check_ports_num(unsigned nb_ports) 610 { 611 unsigned valid_num_ports = num_ports; 612 unsigned portid; 613 614 if (num_ports > nb_ports) { 615 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n", 616 num_ports, nb_ports); 617 num_ports = nb_ports; 618 } 619 620 for (portid = 0; portid < num_ports; portid++) { 621 if (ports[portid] >= nb_ports) { 622 printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n", 623 ports[portid], (nb_ports - 1)); 624 ports[portid] = INVALID_PORT_ID; 625 valid_num_ports--; 626 } 627 } 628 return valid_num_ports; 629 } 630 631 632 /* Main function, does initialisation and calls the per-lcore functions */ 633 int 634 main(int argc, char *argv[]) 635 { 636 unsigned cores; 637 struct rte_mempool *mbuf_pool; 638 unsigned lcore_id; 639 uintptr_t i; 640 int ret; 641 unsigned nb_ports, valid_num_ports; 642 uint8_t portid; 643 644 signal(SIGHUP, sighup_handler); 645 646 /* init EAL */ 647 ret = rte_eal_init(argc, argv); 648 if (ret < 0) 649 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 650 argc -= ret; 651 argv += ret; 652 653 /* parse app arguments */ 654 ret = vmdq_parse_args(argc, argv); 655 if (ret < 0) 656 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n"); 657 658 cores = rte_lcore_count(); 659 if ((cores & (cores - 1)) != 0 || cores > RTE_MAX_LCORE) { 660 rte_exit(EXIT_FAILURE,"This program can only run on an even" 661 " number of cores(1-%d)\n\n", RTE_MAX_LCORE); 662 } 663 664 nb_ports = rte_eth_dev_count(); 665 if (nb_ports > RTE_MAX_ETHPORTS) 666 nb_ports = RTE_MAX_ETHPORTS; 667 668 /* 669 * Update the global var NUM_PORTS and global array PORTS 670 * and get value of var VALID_NUM_PORTS according to system ports number 671 */ 672 valid_num_ports = check_ports_num(nb_ports); 673 674 if (valid_num_ports < 2 || valid_num_ports % 2) { 675 printf("Current valid ports number is %u\n", valid_num_ports); 676 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n"); 677 } 678 679 mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 680 NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE, 681 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 682 if (mbuf_pool == NULL) 683 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 684 685 /* initialize all ports */ 686 for (portid = 0; portid < nb_ports; portid++) { 687 /* skip ports that are not enabled */ 688 if ((enabled_port_mask & (1 << portid)) == 0) { 689 printf("\nSkipping disabled port %d\n", portid); 690 continue; 691 } 692 if (port_init(portid, mbuf_pool) != 0) 693 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n"); 694 } 695 696 /* call lcore_main() on every slave lcore */ 697 i = 0; 698 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 699 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id); 700 } 701 /* call on master too */ 702 (void) lcore_main((void*)i); 703 704 return 0; 705 } 706