1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2016 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 <stdint.h> 37 #include <inttypes.h> 38 #include <sys/types.h> 39 #include <string.h> 40 #include <sys/queue.h> 41 #include <stdarg.h> 42 #include <errno.h> 43 #include <getopt.h> 44 #include <signal.h> 45 #include <stdbool.h> 46 47 #include <rte_common.h> 48 #include <rte_vect.h> 49 #include <rte_byteorder.h> 50 #include <rte_log.h> 51 #include <rte_memory.h> 52 #include <rte_memcpy.h> 53 #include <rte_memzone.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 #include <rte_ip.h> 73 #include <rte_tcp.h> 74 #include <rte_udp.h> 75 #include <rte_string_fns.h> 76 #include <rte_cpuflags.h> 77 78 #include <cmdline_parse.h> 79 #include <cmdline_parse_etheraddr.h> 80 81 #include "l3fwd.h" 82 83 /* 84 * Configurable number of RX/TX ring descriptors 85 */ 86 #define RTE_TEST_RX_DESC_DEFAULT 128 87 #define RTE_TEST_TX_DESC_DEFAULT 512 88 89 #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS 90 #define MAX_RX_QUEUE_PER_PORT 128 91 92 #define MAX_LCORE_PARAMS 1024 93 94 /* Static global variables used within this file. */ 95 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 96 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 97 98 /**< Ports set in promiscuous mode off by default. */ 99 static int promiscuous_on; 100 101 /* Select Longest-Prefix or Exact match. */ 102 static int l3fwd_lpm_on; 103 static int l3fwd_em_on; 104 105 static int numa_on = 1; /**< NUMA is enabled by default. */ 106 static int parse_ptype; /**< Parse packet type using rx callback, and */ 107 /**< disabled by default */ 108 109 /* Global variables. */ 110 111 volatile bool force_quit; 112 113 /* ethernet addresses of ports */ 114 uint64_t dest_eth_addr[RTE_MAX_ETHPORTS]; 115 struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; 116 117 xmm_t val_eth[RTE_MAX_ETHPORTS]; 118 119 /* mask of enabled ports */ 120 uint32_t enabled_port_mask; 121 122 /* Used only in exact match mode. */ 123 int ipv6; /**< ipv6 is false by default. */ 124 uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT; 125 126 struct lcore_conf lcore_conf[RTE_MAX_LCORE]; 127 128 struct lcore_params { 129 uint8_t port_id; 130 uint8_t queue_id; 131 uint8_t lcore_id; 132 } __rte_cache_aligned; 133 134 static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS]; 135 static struct lcore_params lcore_params_array_default[] = { 136 {0, 0, 2}, 137 {0, 1, 2}, 138 {0, 2, 2}, 139 {1, 0, 2}, 140 {1, 1, 2}, 141 {1, 2, 2}, 142 {2, 0, 2}, 143 {3, 0, 3}, 144 {3, 1, 3}, 145 }; 146 147 static struct lcore_params * lcore_params = lcore_params_array_default; 148 static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) / 149 sizeof(lcore_params_array_default[0]); 150 151 static struct rte_eth_conf port_conf = { 152 .rxmode = { 153 .mq_mode = ETH_MQ_RX_RSS, 154 .max_rx_pkt_len = ETHER_MAX_LEN, 155 .split_hdr_size = 0, 156 .header_split = 0, /**< Header Split disabled */ 157 .hw_ip_checksum = 1, /**< IP checksum offload enabled */ 158 .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 159 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 160 .hw_strip_crc = 0, /**< CRC stripped by hardware */ 161 }, 162 .rx_adv_conf = { 163 .rss_conf = { 164 .rss_key = NULL, 165 .rss_hf = ETH_RSS_IP, 166 }, 167 }, 168 .txmode = { 169 .mq_mode = ETH_MQ_TX_NONE, 170 }, 171 }; 172 173 static struct rte_mempool * pktmbuf_pool[NB_SOCKETS]; 174 175 struct l3fwd_lkp_mode { 176 void (*setup)(int); 177 int (*check_ptype)(int); 178 rte_rx_callback_fn cb_parse_ptype; 179 int (*main_loop)(void *); 180 void* (*get_ipv4_lookup_struct)(int); 181 void* (*get_ipv6_lookup_struct)(int); 182 }; 183 184 static struct l3fwd_lkp_mode l3fwd_lkp; 185 186 static struct l3fwd_lkp_mode l3fwd_em_lkp = { 187 .setup = setup_hash, 188 .check_ptype = em_check_ptype, 189 .cb_parse_ptype = em_cb_parse_ptype, 190 .main_loop = em_main_loop, 191 .get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct, 192 .get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct, 193 }; 194 195 static struct l3fwd_lkp_mode l3fwd_lpm_lkp = { 196 .setup = setup_lpm, 197 .check_ptype = lpm_check_ptype, 198 .cb_parse_ptype = lpm_cb_parse_ptype, 199 .main_loop = lpm_main_loop, 200 .get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct, 201 .get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct, 202 }; 203 204 /* 205 * Setup lookup methods for forwarding. 206 * Currently exact-match and longest-prefix-match 207 * are supported ones. 208 */ 209 static void 210 setup_l3fwd_lookup_tables(void) 211 { 212 /* Setup HASH lookup functions. */ 213 if (l3fwd_em_on) 214 l3fwd_lkp = l3fwd_em_lkp; 215 /* Setup LPM lookup functions. */ 216 else 217 l3fwd_lkp = l3fwd_lpm_lkp; 218 } 219 220 static int 221 check_lcore_params(void) 222 { 223 uint8_t queue, lcore; 224 uint16_t i; 225 int socketid; 226 227 for (i = 0; i < nb_lcore_params; ++i) { 228 queue = lcore_params[i].queue_id; 229 if (queue >= MAX_RX_QUEUE_PER_PORT) { 230 printf("invalid queue number: %hhu\n", queue); 231 return -1; 232 } 233 lcore = lcore_params[i].lcore_id; 234 if (!rte_lcore_is_enabled(lcore)) { 235 printf("error: lcore %hhu is not enabled in lcore mask\n", lcore); 236 return -1; 237 } 238 if ((socketid = rte_lcore_to_socket_id(lcore) != 0) && 239 (numa_on == 0)) { 240 printf("warning: lcore %hhu is on socket %d with numa off \n", 241 lcore, socketid); 242 } 243 } 244 return 0; 245 } 246 247 static int 248 check_port_config(const unsigned nb_ports) 249 { 250 unsigned portid; 251 uint16_t i; 252 253 for (i = 0; i < nb_lcore_params; ++i) { 254 portid = lcore_params[i].port_id; 255 if ((enabled_port_mask & (1 << portid)) == 0) { 256 printf("port %u is not enabled in port mask\n", portid); 257 return -1; 258 } 259 if (portid >= nb_ports) { 260 printf("port %u is not present on the board\n", portid); 261 return -1; 262 } 263 } 264 return 0; 265 } 266 267 static uint8_t 268 get_port_n_rx_queues(const uint8_t port) 269 { 270 int queue = -1; 271 uint16_t i; 272 273 for (i = 0; i < nb_lcore_params; ++i) { 274 if (lcore_params[i].port_id == port) { 275 if (lcore_params[i].queue_id == queue+1) 276 queue = lcore_params[i].queue_id; 277 else 278 rte_exit(EXIT_FAILURE, "queue ids of the port %d must be" 279 " in sequence and must start with 0\n", 280 lcore_params[i].port_id); 281 } 282 } 283 return (uint8_t)(++queue); 284 } 285 286 static int 287 init_lcore_rx_queues(void) 288 { 289 uint16_t i, nb_rx_queue; 290 uint8_t lcore; 291 292 for (i = 0; i < nb_lcore_params; ++i) { 293 lcore = lcore_params[i].lcore_id; 294 nb_rx_queue = lcore_conf[lcore].n_rx_queue; 295 if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) { 296 printf("error: too many queues (%u) for lcore: %u\n", 297 (unsigned)nb_rx_queue + 1, (unsigned)lcore); 298 return -1; 299 } else { 300 lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id = 301 lcore_params[i].port_id; 302 lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id = 303 lcore_params[i].queue_id; 304 lcore_conf[lcore].n_rx_queue++; 305 } 306 } 307 return 0; 308 } 309 310 /* display usage */ 311 static void 312 print_usage(const char *prgname) 313 { 314 printf ("%s [EAL options] -- -p PORTMASK -P" 315 " [--config (port,queue,lcore)[,(port,queue,lcore]]" 316 " [--enable-jumbo [--max-pkt-len PKTLEN]]\n" 317 " -p PORTMASK: hexadecimal bitmask of ports to configure\n" 318 " -P : enable promiscuous mode\n" 319 " -E : enable exact match\n" 320 " -L : enable longest prefix match\n" 321 " --config (port,queue,lcore): rx queues configuration\n" 322 " --eth-dest=X,MM:MM:MM:MM:MM:MM: optional, ethernet destination for port X\n" 323 " --no-numa: optional, disable numa awareness\n" 324 " --ipv6: optional, specify it if running ipv6 packets\n" 325 " --enable-jumbo: enable jumbo frame" 326 " which max packet len is PKTLEN in decimal (64-9600)\n" 327 " --hash-entry-num: specify the hash entry number in hexadecimal to be setup\n", 328 prgname); 329 } 330 331 static int 332 parse_max_pkt_len(const char *pktlen) 333 { 334 char *end = NULL; 335 unsigned long len; 336 337 /* parse decimal string */ 338 len = strtoul(pktlen, &end, 10); 339 if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0')) 340 return -1; 341 342 if (len == 0) 343 return -1; 344 345 return len; 346 } 347 348 static int 349 parse_portmask(const char *portmask) 350 { 351 char *end = NULL; 352 unsigned long pm; 353 354 /* parse hexadecimal string */ 355 pm = strtoul(portmask, &end, 16); 356 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 357 return -1; 358 359 if (pm == 0) 360 return -1; 361 362 return pm; 363 } 364 365 static int 366 parse_hash_entry_number(const char *hash_entry_num) 367 { 368 char *end = NULL; 369 unsigned long hash_en; 370 /* parse hexadecimal string */ 371 hash_en = strtoul(hash_entry_num, &end, 16); 372 if ((hash_entry_num[0] == '\0') || (end == NULL) || (*end != '\0')) 373 return -1; 374 375 if (hash_en == 0) 376 return -1; 377 378 return hash_en; 379 } 380 381 static int 382 parse_config(const char *q_arg) 383 { 384 char s[256]; 385 const char *p, *p0 = q_arg; 386 char *end; 387 enum fieldnames { 388 FLD_PORT = 0, 389 FLD_QUEUE, 390 FLD_LCORE, 391 _NUM_FLD 392 }; 393 unsigned long int_fld[_NUM_FLD]; 394 char *str_fld[_NUM_FLD]; 395 int i; 396 unsigned size; 397 398 nb_lcore_params = 0; 399 400 while ((p = strchr(p0,'(')) != NULL) { 401 ++p; 402 if((p0 = strchr(p,')')) == NULL) 403 return -1; 404 405 size = p0 - p; 406 if(size >= sizeof(s)) 407 return -1; 408 409 snprintf(s, sizeof(s), "%.*s", size, p); 410 if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD) 411 return -1; 412 for (i = 0; i < _NUM_FLD; i++){ 413 errno = 0; 414 int_fld[i] = strtoul(str_fld[i], &end, 0); 415 if (errno != 0 || end == str_fld[i] || int_fld[i] > 255) 416 return -1; 417 } 418 if (nb_lcore_params >= MAX_LCORE_PARAMS) { 419 printf("exceeded max number of lcore params: %hu\n", 420 nb_lcore_params); 421 return -1; 422 } 423 lcore_params_array[nb_lcore_params].port_id = 424 (uint8_t)int_fld[FLD_PORT]; 425 lcore_params_array[nb_lcore_params].queue_id = 426 (uint8_t)int_fld[FLD_QUEUE]; 427 lcore_params_array[nb_lcore_params].lcore_id = 428 (uint8_t)int_fld[FLD_LCORE]; 429 ++nb_lcore_params; 430 } 431 lcore_params = lcore_params_array; 432 return 0; 433 } 434 435 static void 436 parse_eth_dest(const char *optarg) 437 { 438 uint8_t portid; 439 char *port_end; 440 uint8_t c, *dest, peer_addr[6]; 441 442 errno = 0; 443 portid = strtoul(optarg, &port_end, 10); 444 if (errno != 0 || port_end == optarg || *port_end++ != ',') 445 rte_exit(EXIT_FAILURE, 446 "Invalid eth-dest: %s", optarg); 447 if (portid >= RTE_MAX_ETHPORTS) 448 rte_exit(EXIT_FAILURE, 449 "eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n", 450 portid, RTE_MAX_ETHPORTS); 451 452 if (cmdline_parse_etheraddr(NULL, port_end, 453 &peer_addr, sizeof(peer_addr)) < 0) 454 rte_exit(EXIT_FAILURE, 455 "Invalid ethernet address: %s\n", 456 port_end); 457 dest = (uint8_t *)&dest_eth_addr[portid]; 458 for (c = 0; c < 6; c++) 459 dest[c] = peer_addr[c]; 460 *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; 461 } 462 463 #define MAX_JUMBO_PKT_LEN 9600 464 #define MEMPOOL_CACHE_SIZE 256 465 466 #define CMD_LINE_OPT_CONFIG "config" 467 #define CMD_LINE_OPT_ETH_DEST "eth-dest" 468 #define CMD_LINE_OPT_NO_NUMA "no-numa" 469 #define CMD_LINE_OPT_IPV6 "ipv6" 470 #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo" 471 #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num" 472 #define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype" 473 474 /* 475 * This expression is used to calculate the number of mbufs needed 476 * depending on user input, taking into account memory for rx and 477 * tx hardware rings, cache per lcore and mtable per port per lcore. 478 * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum 479 * value of 8192 480 */ 481 #define NB_MBUF RTE_MAX( \ 482 (nb_ports*nb_rx_queue*RTE_TEST_RX_DESC_DEFAULT + \ 483 nb_ports*nb_lcores*MAX_PKT_BURST + \ 484 nb_ports*n_tx_queue*RTE_TEST_TX_DESC_DEFAULT + \ 485 nb_lcores*MEMPOOL_CACHE_SIZE), \ 486 (unsigned)8192) 487 488 /* Parse the argument given in the command line of the application */ 489 static int 490 parse_args(int argc, char **argv) 491 { 492 int opt, ret; 493 char **argvopt; 494 int option_index; 495 char *prgname = argv[0]; 496 static struct option lgopts[] = { 497 {CMD_LINE_OPT_CONFIG, 1, 0, 0}, 498 {CMD_LINE_OPT_ETH_DEST, 1, 0, 0}, 499 {CMD_LINE_OPT_NO_NUMA, 0, 0, 0}, 500 {CMD_LINE_OPT_IPV6, 0, 0, 0}, 501 {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0}, 502 {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0}, 503 {CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0}, 504 {NULL, 0, 0, 0} 505 }; 506 507 argvopt = argv; 508 509 /* Error or normal output strings. */ 510 const char *str1 = "L3FWD: Invalid portmask"; 511 const char *str2 = "L3FWD: Promiscuous mode selected"; 512 const char *str3 = "L3FWD: Exact match selected"; 513 const char *str4 = "L3FWD: Longest-prefix match selected"; 514 const char *str5 = "L3FWD: Invalid config"; 515 const char *str6 = "L3FWD: NUMA is disabled"; 516 const char *str7 = "L3FWD: IPV6 is specified"; 517 const char *str8 = 518 "L3FWD: Jumbo frame is enabled - disabling simple TX path"; 519 const char *str9 = "L3FWD: Invalid packet length"; 520 const char *str10 = "L3FWD: Set jumbo frame max packet len to "; 521 const char *str11 = "L3FWD: Invalid hash entry number"; 522 const char *str12 = 523 "L3FWD: LPM and EM are mutually exclusive, select only one"; 524 const char *str13 = "L3FWD: LPM or EM none selected, default LPM on"; 525 526 while ((opt = getopt_long(argc, argvopt, "p:PLE", 527 lgopts, &option_index)) != EOF) { 528 529 switch (opt) { 530 /* portmask */ 531 case 'p': 532 enabled_port_mask = parse_portmask(optarg); 533 if (enabled_port_mask == 0) { 534 printf("%s\n", str1); 535 print_usage(prgname); 536 return -1; 537 } 538 break; 539 case 'P': 540 printf("%s\n", str2); 541 promiscuous_on = 1; 542 break; 543 544 case 'E': 545 printf("%s\n", str3); 546 l3fwd_em_on = 1; 547 break; 548 549 case 'L': 550 printf("%s\n", str4); 551 l3fwd_lpm_on = 1; 552 break; 553 554 /* long options */ 555 case 0: 556 if (!strncmp(lgopts[option_index].name, 557 CMD_LINE_OPT_CONFIG, 558 sizeof(CMD_LINE_OPT_CONFIG))) { 559 560 ret = parse_config(optarg); 561 if (ret) { 562 printf("%s\n", str5); 563 print_usage(prgname); 564 return -1; 565 } 566 } 567 568 if (!strncmp(lgopts[option_index].name, 569 CMD_LINE_OPT_ETH_DEST, 570 sizeof(CMD_LINE_OPT_ETH_DEST))) { 571 parse_eth_dest(optarg); 572 } 573 574 if (!strncmp(lgopts[option_index].name, 575 CMD_LINE_OPT_NO_NUMA, 576 sizeof(CMD_LINE_OPT_NO_NUMA))) { 577 printf("%s\n", str6); 578 numa_on = 0; 579 } 580 581 if (!strncmp(lgopts[option_index].name, 582 CMD_LINE_OPT_IPV6, 583 sizeof(CMD_LINE_OPT_IPV6))) { 584 printf("%sn", str7); 585 ipv6 = 1; 586 } 587 588 if (!strncmp(lgopts[option_index].name, 589 CMD_LINE_OPT_ENABLE_JUMBO, 590 sizeof(CMD_LINE_OPT_ENABLE_JUMBO))) { 591 struct option lenopts = { 592 "max-pkt-len", required_argument, 0, 0 593 }; 594 595 printf("%s\n", str8); 596 port_conf.rxmode.jumbo_frame = 1; 597 598 /* 599 * if no max-pkt-len set, use the default 600 * value ETHER_MAX_LEN. 601 */ 602 if (0 == getopt_long(argc, argvopt, "", 603 &lenopts, &option_index)) { 604 ret = parse_max_pkt_len(optarg); 605 if ((ret < 64) || 606 (ret > MAX_JUMBO_PKT_LEN)) { 607 printf("%s\n", str9); 608 print_usage(prgname); 609 return -1; 610 } 611 port_conf.rxmode.max_rx_pkt_len = ret; 612 } 613 printf("%s %u\n", str10, 614 (unsigned int)port_conf.rxmode.max_rx_pkt_len); 615 } 616 617 if (!strncmp(lgopts[option_index].name, 618 CMD_LINE_OPT_HASH_ENTRY_NUM, 619 sizeof(CMD_LINE_OPT_HASH_ENTRY_NUM))) { 620 621 ret = parse_hash_entry_number(optarg); 622 if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) { 623 hash_entry_number = ret; 624 } else { 625 printf("%s\n", str11); 626 print_usage(prgname); 627 return -1; 628 } 629 } 630 631 if (!strncmp(lgopts[option_index].name, 632 CMD_LINE_OPT_PARSE_PTYPE, 633 sizeof(CMD_LINE_OPT_PARSE_PTYPE))) { 634 printf("soft parse-ptype is enabled\n"); 635 parse_ptype = 1; 636 } 637 638 break; 639 640 default: 641 print_usage(prgname); 642 return -1; 643 } 644 } 645 646 /* If both LPM and EM are selected, return error. */ 647 if (l3fwd_lpm_on && l3fwd_em_on) { 648 printf("%s\n", str12); 649 return -1; 650 } 651 652 /* 653 * Nothing is selected, pick longest-prefix match 654 * as default match. 655 */ 656 if (!l3fwd_lpm_on && !l3fwd_em_on) { 657 l3fwd_lpm_on = 1; 658 printf("%s\n", str13); 659 } 660 661 /* 662 * ipv6 and hash flags are valid only for 663 * exact macth, reset them to default for 664 * longest-prefix match. 665 */ 666 if (l3fwd_lpm_on) { 667 ipv6 = 0; 668 hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT; 669 } 670 671 if (optind >= 0) 672 argv[optind-1] = prgname; 673 674 ret = optind-1; 675 optind = 0; /* reset getopt lib */ 676 return ret; 677 } 678 679 static void 680 print_ethaddr(const char *name, const struct ether_addr *eth_addr) 681 { 682 char buf[ETHER_ADDR_FMT_SIZE]; 683 ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr); 684 printf("%s%s", name, buf); 685 } 686 687 static int 688 init_mem(unsigned nb_mbuf) 689 { 690 struct lcore_conf *qconf; 691 int socketid; 692 unsigned lcore_id; 693 char s[64]; 694 695 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 696 if (rte_lcore_is_enabled(lcore_id) == 0) 697 continue; 698 699 if (numa_on) 700 socketid = rte_lcore_to_socket_id(lcore_id); 701 else 702 socketid = 0; 703 704 if (socketid >= NB_SOCKETS) { 705 rte_exit(EXIT_FAILURE, 706 "Socket %d of lcore %u is out of range %d\n", 707 socketid, lcore_id, NB_SOCKETS); 708 } 709 710 if (pktmbuf_pool[socketid] == NULL) { 711 snprintf(s, sizeof(s), "mbuf_pool_%d", socketid); 712 pktmbuf_pool[socketid] = 713 rte_pktmbuf_pool_create(s, nb_mbuf, 714 MEMPOOL_CACHE_SIZE, 0, 715 RTE_MBUF_DEFAULT_BUF_SIZE, socketid); 716 if (pktmbuf_pool[socketid] == NULL) 717 rte_exit(EXIT_FAILURE, 718 "Cannot init mbuf pool on socket %d\n", 719 socketid); 720 else 721 printf("Allocated mbuf pool on socket %d\n", 722 socketid); 723 724 /* Setup either LPM or EM(f.e Hash). */ 725 l3fwd_lkp.setup(socketid); 726 } 727 qconf = &lcore_conf[lcore_id]; 728 qconf->ipv4_lookup_struct = 729 l3fwd_lkp.get_ipv4_lookup_struct(socketid); 730 qconf->ipv6_lookup_struct = 731 l3fwd_lkp.get_ipv6_lookup_struct(socketid); 732 } 733 return 0; 734 } 735 736 /* Check the link status of all ports in up to 9s, and print them finally */ 737 static void 738 check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) 739 { 740 #define CHECK_INTERVAL 100 /* 100ms */ 741 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 742 uint8_t portid, count, all_ports_up, print_flag = 0; 743 struct rte_eth_link link; 744 745 printf("\nChecking link status"); 746 fflush(stdout); 747 for (count = 0; count <= MAX_CHECK_TIME; count++) { 748 if (force_quit) 749 return; 750 all_ports_up = 1; 751 for (portid = 0; portid < port_num; portid++) { 752 if (force_quit) 753 return; 754 if ((port_mask & (1 << portid)) == 0) 755 continue; 756 memset(&link, 0, sizeof(link)); 757 rte_eth_link_get_nowait(portid, &link); 758 /* print link status if flag set */ 759 if (print_flag == 1) { 760 if (link.link_status) 761 printf("Port %d Link Up - speed %u " 762 "Mbps - %s\n", (uint8_t)portid, 763 (unsigned)link.link_speed, 764 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 765 ("full-duplex") : ("half-duplex\n")); 766 else 767 printf("Port %d Link Down\n", 768 (uint8_t)portid); 769 continue; 770 } 771 /* clear all_ports_up flag if any link down */ 772 if (link.link_status == 0) { 773 all_ports_up = 0; 774 break; 775 } 776 } 777 /* after finally printing all link status, get out */ 778 if (print_flag == 1) 779 break; 780 781 if (all_ports_up == 0) { 782 printf("."); 783 fflush(stdout); 784 rte_delay_ms(CHECK_INTERVAL); 785 } 786 787 /* set the print_flag if all ports up or timeout */ 788 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 789 print_flag = 1; 790 printf("done\n"); 791 } 792 } 793 } 794 795 static void 796 signal_handler(int signum) 797 { 798 if (signum == SIGINT || signum == SIGTERM) { 799 printf("\n\nSignal %d received, preparing to exit...\n", 800 signum); 801 force_quit = true; 802 } 803 } 804 805 static int 806 prepare_ptype_parser(uint8_t portid, uint16_t queueid) 807 { 808 if (parse_ptype) { 809 printf("Port %d: softly parse packet type info\n", portid); 810 if (rte_eth_add_rx_callback(portid, queueid, 811 l3fwd_lkp.cb_parse_ptype, 812 NULL)) 813 return 1; 814 815 printf("Failed to add rx callback: port=%d\n", portid); 816 return 0; 817 } 818 819 if (l3fwd_lkp.check_ptype(portid)) 820 return 1; 821 822 printf("port %d cannot parse packet type, please add --%s\n", 823 portid, CMD_LINE_OPT_PARSE_PTYPE); 824 return 0; 825 } 826 827 int 828 main(int argc, char **argv) 829 { 830 struct lcore_conf *qconf; 831 struct rte_eth_dev_info dev_info; 832 struct rte_eth_txconf *txconf; 833 int ret; 834 unsigned nb_ports; 835 uint16_t queueid; 836 unsigned lcore_id; 837 uint32_t n_tx_queue, nb_lcores; 838 uint8_t portid, nb_rx_queue, queue, socketid; 839 uint8_t nb_tx_port; 840 841 /* init EAL */ 842 ret = rte_eal_init(argc, argv); 843 if (ret < 0) 844 rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); 845 argc -= ret; 846 argv += ret; 847 848 force_quit = false; 849 signal(SIGINT, signal_handler); 850 signal(SIGTERM, signal_handler); 851 852 /* pre-init dst MACs for all ports to 02:00:00:00:00:xx */ 853 for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 854 dest_eth_addr[portid] = 855 ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40); 856 *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; 857 } 858 859 /* parse application arguments (after the EAL ones) */ 860 ret = parse_args(argc, argv); 861 if (ret < 0) 862 rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n"); 863 864 if (check_lcore_params() < 0) 865 rte_exit(EXIT_FAILURE, "check_lcore_params failed\n"); 866 867 ret = init_lcore_rx_queues(); 868 if (ret < 0) 869 rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n"); 870 871 nb_ports = rte_eth_dev_count(); 872 if (nb_ports > RTE_MAX_ETHPORTS) 873 nb_ports = RTE_MAX_ETHPORTS; 874 875 if (check_port_config(nb_ports) < 0) 876 rte_exit(EXIT_FAILURE, "check_port_config failed\n"); 877 878 nb_lcores = rte_lcore_count(); 879 nb_tx_port = 0; 880 881 /* Setup function pointers for lookup method. */ 882 setup_l3fwd_lookup_tables(); 883 884 /* initialize all ports */ 885 for (portid = 0; portid < nb_ports; portid++) { 886 /* skip ports that are not enabled */ 887 if ((enabled_port_mask & (1 << portid)) == 0) { 888 printf("\nSkipping disabled port %d\n", portid); 889 continue; 890 } 891 892 /* init port */ 893 printf("Initializing port %d ... ", portid ); 894 fflush(stdout); 895 896 nb_rx_queue = get_port_n_rx_queues(portid); 897 n_tx_queue = nb_lcores; 898 if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) 899 n_tx_queue = MAX_TX_QUEUE_PER_PORT; 900 printf("Creating queues: nb_rxq=%d nb_txq=%u... ", 901 nb_rx_queue, (unsigned)n_tx_queue ); 902 ret = rte_eth_dev_configure(portid, nb_rx_queue, 903 (uint16_t)n_tx_queue, &port_conf); 904 if (ret < 0) 905 rte_exit(EXIT_FAILURE, 906 "Cannot configure device: err=%d, port=%d\n", 907 ret, portid); 908 909 rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); 910 print_ethaddr(" Address:", &ports_eth_addr[portid]); 911 printf(", "); 912 print_ethaddr("Destination:", 913 (const struct ether_addr *)&dest_eth_addr[portid]); 914 printf(", "); 915 916 /* 917 * prepare src MACs for each port. 918 */ 919 ether_addr_copy(&ports_eth_addr[portid], 920 (struct ether_addr *)(val_eth + portid) + 1); 921 922 /* init memory */ 923 ret = init_mem(NB_MBUF); 924 if (ret < 0) 925 rte_exit(EXIT_FAILURE, "init_mem failed\n"); 926 927 /* init one TX queue per couple (lcore,port) */ 928 queueid = 0; 929 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 930 if (rte_lcore_is_enabled(lcore_id) == 0) 931 continue; 932 933 if (numa_on) 934 socketid = 935 (uint8_t)rte_lcore_to_socket_id(lcore_id); 936 else 937 socketid = 0; 938 939 printf("txq=%u,%d,%d ", lcore_id, queueid, socketid); 940 fflush(stdout); 941 942 rte_eth_dev_info_get(portid, &dev_info); 943 txconf = &dev_info.default_txconf; 944 if (port_conf.rxmode.jumbo_frame) 945 txconf->txq_flags = 0; 946 ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd, 947 socketid, txconf); 948 if (ret < 0) 949 rte_exit(EXIT_FAILURE, 950 "rte_eth_tx_queue_setup: err=%d, " 951 "port=%d\n", ret, portid); 952 953 qconf = &lcore_conf[lcore_id]; 954 qconf->tx_queue_id[portid] = queueid; 955 queueid++; 956 957 qconf->n_tx_port = nb_tx_port; 958 qconf->tx_port_id[qconf->n_tx_port] = portid; 959 } 960 printf("\n"); 961 962 nb_tx_port++; 963 } 964 965 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 966 if (rte_lcore_is_enabled(lcore_id) == 0) 967 continue; 968 qconf = &lcore_conf[lcore_id]; 969 printf("\nInitializing rx queues on lcore %u ... ", lcore_id ); 970 fflush(stdout); 971 /* init RX queues */ 972 for(queue = 0; queue < qconf->n_rx_queue; ++queue) { 973 portid = qconf->rx_queue_list[queue].port_id; 974 queueid = qconf->rx_queue_list[queue].queue_id; 975 976 if (numa_on) 977 socketid = 978 (uint8_t)rte_lcore_to_socket_id(lcore_id); 979 else 980 socketid = 0; 981 982 printf("rxq=%d,%d,%d ", portid, queueid, socketid); 983 fflush(stdout); 984 985 ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd, 986 socketid, 987 NULL, 988 pktmbuf_pool[socketid]); 989 if (ret < 0) 990 rte_exit(EXIT_FAILURE, 991 "rte_eth_rx_queue_setup: err=%d, port=%d\n", 992 ret, portid); 993 } 994 } 995 996 printf("\n"); 997 998 /* start ports */ 999 for (portid = 0; portid < nb_ports; portid++) { 1000 if ((enabled_port_mask & (1 << portid)) == 0) { 1001 continue; 1002 } 1003 /* Start device */ 1004 ret = rte_eth_dev_start(portid); 1005 if (ret < 0) 1006 rte_exit(EXIT_FAILURE, 1007 "rte_eth_dev_start: err=%d, port=%d\n", 1008 ret, portid); 1009 1010 /* 1011 * If enabled, put device in promiscuous mode. 1012 * This allows IO forwarding mode to forward packets 1013 * to itself through 2 cross-connected ports of the 1014 * target machine. 1015 */ 1016 if (promiscuous_on) 1017 rte_eth_promiscuous_enable(portid); 1018 } 1019 1020 printf("\n"); 1021 1022 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 1023 if (rte_lcore_is_enabled(lcore_id) == 0) 1024 continue; 1025 qconf = &lcore_conf[lcore_id]; 1026 for (queue = 0; queue < qconf->n_rx_queue; ++queue) { 1027 portid = qconf->rx_queue_list[queue].port_id; 1028 queueid = qconf->rx_queue_list[queue].queue_id; 1029 if (prepare_ptype_parser(portid, queueid) == 0) 1030 rte_exit(EXIT_FAILURE, "ptype check fails\n"); 1031 } 1032 } 1033 1034 1035 check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask); 1036 1037 ret = 0; 1038 /* launch per-lcore init on every lcore */ 1039 rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MASTER); 1040 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 1041 if (rte_eal_wait_lcore(lcore_id) < 0) { 1042 ret = -1; 1043 break; 1044 } 1045 } 1046 1047 /* stop ports */ 1048 for (portid = 0; portid < nb_ports; portid++) { 1049 if ((enabled_port_mask & (1 << portid)) == 0) 1050 continue; 1051 printf("Closing port %d...", portid); 1052 rte_eth_dev_stop(portid); 1053 rte_eth_dev_close(portid); 1054 printf(" Done\n"); 1055 } 1056 printf("Bye...\n"); 1057 1058 return ret; 1059 } 1060