13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2016 Intel Corporation 3af75078fSIntel */ 4af75078fSIntel 5af75078fSIntel #include <stdio.h> 6af75078fSIntel #include <stdlib.h> 7af75078fSIntel #include <stdint.h> 8af75078fSIntel #include <inttypes.h> 9af75078fSIntel #include <sys/types.h> 10af75078fSIntel #include <string.h> 11af75078fSIntel #include <sys/queue.h> 12af75078fSIntel #include <stdarg.h> 13af75078fSIntel #include <errno.h> 14af75078fSIntel #include <getopt.h> 15308df2bfSZhihong Wang #include <signal.h> 16308df2bfSZhihong Wang #include <stdbool.h> 17af75078fSIntel 18af75078fSIntel #include <rte_common.h> 191e496d6fSKonstantin Ananyev #include <rte_vect.h> 20af75078fSIntel #include <rte_byteorder.h> 21af75078fSIntel #include <rte_log.h> 22af75078fSIntel #include <rte_memory.h> 23af75078fSIntel #include <rte_memcpy.h> 24af75078fSIntel #include <rte_eal.h> 25af75078fSIntel #include <rte_launch.h> 26af75078fSIntel #include <rte_atomic.h> 27af75078fSIntel #include <rte_cycles.h> 28af75078fSIntel #include <rte_prefetch.h> 29af75078fSIntel #include <rte_lcore.h> 30af75078fSIntel #include <rte_per_lcore.h> 31af75078fSIntel #include <rte_branch_prediction.h> 32af75078fSIntel #include <rte_interrupts.h> 33af75078fSIntel #include <rte_random.h> 34af75078fSIntel #include <rte_debug.h> 35af75078fSIntel #include <rte_ether.h> 36af75078fSIntel #include <rte_ethdev.h> 37af75078fSIntel #include <rte_mempool.h> 38af75078fSIntel #include <rte_mbuf.h> 39af75078fSIntel #include <rte_ip.h> 40af75078fSIntel #include <rte_tcp.h> 41af75078fSIntel #include <rte_udp.h> 42af75078fSIntel #include <rte_string_fns.h> 43268888b5SRavi Kerur #include <rte_cpuflags.h> 44af75078fSIntel 45bd785f6fSAndrey Chilikin #include <cmdline_parse.h> 46bd785f6fSAndrey Chilikin #include <cmdline_parse_etheraddr.h> 47bd785f6fSAndrey Chilikin 48268888b5SRavi Kerur #include "l3fwd.h" 4996ff4453SKonstantin Ananyev 50af75078fSIntel /* 51af75078fSIntel * Configurable number of RX/TX ring descriptors 52af75078fSIntel */ 53867a6c66SKevin Laatz #define RTE_TEST_RX_DESC_DEFAULT 1024 54867a6c66SKevin Laatz #define RTE_TEST_TX_DESC_DEFAULT 1024 55af75078fSIntel 561c17baf4SIntel #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS 57af75078fSIntel #define MAX_RX_QUEUE_PER_PORT 128 58af75078fSIntel 59af75078fSIntel #define MAX_LCORE_PARAMS 1024 60268888b5SRavi Kerur 61268888b5SRavi Kerur /* Static global variables used within this file. */ 62268888b5SRavi Kerur static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 63268888b5SRavi Kerur static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 64268888b5SRavi Kerur 65268888b5SRavi Kerur /**< Ports set in promiscuous mode off by default. */ 66268888b5SRavi Kerur static int promiscuous_on; 67268888b5SRavi Kerur 68268888b5SRavi Kerur /* Select Longest-Prefix or Exact match. */ 69268888b5SRavi Kerur static int l3fwd_lpm_on; 70268888b5SRavi Kerur static int l3fwd_em_on; 71268888b5SRavi Kerur 72f0a26885SShreyansh Jain /* Global variables. */ 73f0a26885SShreyansh Jain 74268888b5SRavi Kerur static int numa_on = 1; /**< NUMA is enabled by default. */ 7571a7e242SJianfeng Tan static int parse_ptype; /**< Parse packet type using rx callback, and */ 7671a7e242SJianfeng Tan /**< disabled by default */ 77f0a26885SShreyansh Jain static int per_port_pool; /**< Use separate buffer pools per port; disabled */ 78f0a26885SShreyansh Jain /**< by default */ 79268888b5SRavi Kerur 80268888b5SRavi Kerur volatile bool force_quit; 81268888b5SRavi Kerur 82268888b5SRavi Kerur /* ethernet addresses of ports */ 83268888b5SRavi Kerur uint64_t dest_eth_addr[RTE_MAX_ETHPORTS]; 846d13ea8eSOlivier Matz struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; 85268888b5SRavi Kerur 8664d3955dSMaciej Czekaj xmm_t val_eth[RTE_MAX_ETHPORTS]; 87268888b5SRavi Kerur 88268888b5SRavi Kerur /* mask of enabled ports */ 89268888b5SRavi Kerur uint32_t enabled_port_mask; 90268888b5SRavi Kerur 91268888b5SRavi Kerur /* Used only in exact match mode. */ 92268888b5SRavi Kerur int ipv6; /**< ipv6 is false by default. */ 93268888b5SRavi Kerur uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT; 94268888b5SRavi Kerur 95268888b5SRavi Kerur struct lcore_conf lcore_conf[RTE_MAX_LCORE]; 96268888b5SRavi Kerur 97af75078fSIntel struct lcore_params { 98f8244c63SZhiyong Yang uint16_t port_id; 99af75078fSIntel uint8_t queue_id; 100af75078fSIntel uint8_t lcore_id; 101af75078fSIntel } __rte_cache_aligned; 102af75078fSIntel 103af75078fSIntel static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS]; 104af75078fSIntel static struct lcore_params lcore_params_array_default[] = { 105af75078fSIntel {0, 0, 2}, 106af75078fSIntel {0, 1, 2}, 107af75078fSIntel {0, 2, 2}, 108af75078fSIntel {1, 0, 2}, 109af75078fSIntel {1, 1, 2}, 110af75078fSIntel {1, 2, 2}, 111af75078fSIntel {2, 0, 2}, 112af75078fSIntel {3, 0, 3}, 113af75078fSIntel {3, 1, 3}, 114af75078fSIntel }; 115af75078fSIntel 116af75078fSIntel static struct lcore_params * lcore_params = lcore_params_array_default; 117af75078fSIntel static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) / 118af75078fSIntel sizeof(lcore_params_array_default[0]); 119af75078fSIntel 120af75078fSIntel static struct rte_eth_conf port_conf = { 121af75078fSIntel .rxmode = { 12213c4ebd6SBruce Richardson .mq_mode = ETH_MQ_RX_RSS, 12335b2d13fSOlivier Matz .max_rx_pkt_len = RTE_ETHER_MAX_LEN, 124af75078fSIntel .split_hdr_size = 0, 125323e7b66SFerruh Yigit .offloads = DEV_RX_OFFLOAD_CHECKSUM, 126af75078fSIntel }, 127af75078fSIntel .rx_adv_conf = { 128af75078fSIntel .rss_conf = { 129af75078fSIntel .rss_key = NULL, 1308a387fa8SHelin Zhang .rss_hf = ETH_RSS_IP, 131af75078fSIntel }, 132af75078fSIntel }, 133af75078fSIntel .txmode = { 13432e7aa0bSIntel .mq_mode = ETH_MQ_TX_NONE, 135af75078fSIntel }, 136af75078fSIntel }; 137af75078fSIntel 138f0a26885SShreyansh Jain static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS]; 139f0a26885SShreyansh Jain static uint8_t lkp_per_socket[NB_SOCKETS]; 140af75078fSIntel 141268888b5SRavi Kerur struct l3fwd_lkp_mode { 142268888b5SRavi Kerur void (*setup)(int); 14371a7e242SJianfeng Tan int (*check_ptype)(int); 14471a7e242SJianfeng Tan rte_rx_callback_fn cb_parse_ptype; 145268888b5SRavi Kerur int (*main_loop)(void *); 146268888b5SRavi Kerur void* (*get_ipv4_lookup_struct)(int); 147268888b5SRavi Kerur void* (*get_ipv6_lookup_struct)(int); 148997ee890SIntel }; 149997ee890SIntel 150268888b5SRavi Kerur static struct l3fwd_lkp_mode l3fwd_lkp; 151997ee890SIntel 152268888b5SRavi Kerur static struct l3fwd_lkp_mode l3fwd_em_lkp = { 153268888b5SRavi Kerur .setup = setup_hash, 15471a7e242SJianfeng Tan .check_ptype = em_check_ptype, 15571a7e242SJianfeng Tan .cb_parse_ptype = em_cb_parse_ptype, 156268888b5SRavi Kerur .main_loop = em_main_loop, 157268888b5SRavi Kerur .get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct, 158268888b5SRavi Kerur .get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct, 159997ee890SIntel }; 160997ee890SIntel 161268888b5SRavi Kerur static struct l3fwd_lkp_mode l3fwd_lpm_lkp = { 162268888b5SRavi Kerur .setup = setup_lpm, 16371a7e242SJianfeng Tan .check_ptype = lpm_check_ptype, 16471a7e242SJianfeng Tan .cb_parse_ptype = lpm_cb_parse_ptype, 165268888b5SRavi Kerur .main_loop = lpm_main_loop, 166268888b5SRavi Kerur .get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct, 167268888b5SRavi Kerur .get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct, 168af75078fSIntel }; 169af75078fSIntel 17096ff4453SKonstantin Ananyev /* 171268888b5SRavi Kerur * Setup lookup methods for forwarding. 172268888b5SRavi Kerur * Currently exact-match and longest-prefix-match 173268888b5SRavi Kerur * are supported ones. 17496ff4453SKonstantin Ananyev */ 175268888b5SRavi Kerur static void 176268888b5SRavi Kerur setup_l3fwd_lookup_tables(void) 177af75078fSIntel { 178268888b5SRavi Kerur /* Setup HASH lookup functions. */ 179268888b5SRavi Kerur if (l3fwd_em_on) 180268888b5SRavi Kerur l3fwd_lkp = l3fwd_em_lkp; 181268888b5SRavi Kerur /* Setup LPM lookup functions. */ 182268888b5SRavi Kerur else 183268888b5SRavi Kerur l3fwd_lkp = l3fwd_lpm_lkp; 184af75078fSIntel } 185af75078fSIntel 186af75078fSIntel static int 187af75078fSIntel check_lcore_params(void) 188af75078fSIntel { 189af75078fSIntel uint8_t queue, lcore; 190af75078fSIntel uint16_t i; 191af75078fSIntel int socketid; 192af75078fSIntel 193af75078fSIntel for (i = 0; i < nb_lcore_params; ++i) { 194af75078fSIntel queue = lcore_params[i].queue_id; 195af75078fSIntel if (queue >= MAX_RX_QUEUE_PER_PORT) { 196af75078fSIntel printf("invalid queue number: %hhu\n", queue); 197af75078fSIntel return -1; 198af75078fSIntel } 199af75078fSIntel lcore = lcore_params[i].lcore_id; 200af75078fSIntel if (!rte_lcore_is_enabled(lcore)) { 201af75078fSIntel printf("error: lcore %hhu is not enabled in lcore mask\n", lcore); 202af75078fSIntel return -1; 203af75078fSIntel } 204af75078fSIntel if ((socketid = rte_lcore_to_socket_id(lcore) != 0) && 205af75078fSIntel (numa_on == 0)) { 206af75078fSIntel printf("warning: lcore %hhu is on socket %d with numa off \n", 207af75078fSIntel lcore, socketid); 208af75078fSIntel } 209af75078fSIntel } 210af75078fSIntel return 0; 211af75078fSIntel } 212af75078fSIntel 213af75078fSIntel static int 214a9dbe180SThomas Monjalon check_port_config(void) 215af75078fSIntel { 216f8244c63SZhiyong Yang uint16_t portid; 217af75078fSIntel uint16_t i; 218af75078fSIntel 219af75078fSIntel for (i = 0; i < nb_lcore_params; ++i) { 220af75078fSIntel portid = lcore_params[i].port_id; 221af75078fSIntel if ((enabled_port_mask & (1 << portid)) == 0) { 222af75078fSIntel printf("port %u is not enabled in port mask\n", portid); 223af75078fSIntel return -1; 224af75078fSIntel } 225a9dbe180SThomas Monjalon if (!rte_eth_dev_is_valid_port(portid)) { 226af75078fSIntel printf("port %u is not present on the board\n", portid); 227af75078fSIntel return -1; 228af75078fSIntel } 229af75078fSIntel } 230af75078fSIntel return 0; 231af75078fSIntel } 232af75078fSIntel 233af75078fSIntel static uint8_t 234f8244c63SZhiyong Yang get_port_n_rx_queues(const uint16_t port) 235af75078fSIntel { 236af75078fSIntel int queue = -1; 237af75078fSIntel uint16_t i; 238af75078fSIntel 239af75078fSIntel for (i = 0; i < nb_lcore_params; ++i) { 240a6b45080SReshma Pattan if (lcore_params[i].port_id == port) { 241a6b45080SReshma Pattan if (lcore_params[i].queue_id == queue+1) 242af75078fSIntel queue = lcore_params[i].queue_id; 243a6b45080SReshma Pattan else 244a6b45080SReshma Pattan rte_exit(EXIT_FAILURE, "queue ids of the port %d must be" 245a6b45080SReshma Pattan " in sequence and must start with 0\n", 246a6b45080SReshma Pattan lcore_params[i].port_id); 247a6b45080SReshma Pattan } 248af75078fSIntel } 249af75078fSIntel return (uint8_t)(++queue); 250af75078fSIntel } 251af75078fSIntel 252af75078fSIntel static int 253af75078fSIntel init_lcore_rx_queues(void) 254af75078fSIntel { 255af75078fSIntel uint16_t i, nb_rx_queue; 256af75078fSIntel uint8_t lcore; 257af75078fSIntel 258af75078fSIntel for (i = 0; i < nb_lcore_params; ++i) { 259af75078fSIntel lcore = lcore_params[i].lcore_id; 260af75078fSIntel nb_rx_queue = lcore_conf[lcore].n_rx_queue; 261af75078fSIntel if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) { 262af75078fSIntel printf("error: too many queues (%u) for lcore: %u\n", 263af75078fSIntel (unsigned)nb_rx_queue + 1, (unsigned)lcore); 264af75078fSIntel return -1; 265af75078fSIntel } else { 266af75078fSIntel lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id = 267af75078fSIntel lcore_params[i].port_id; 268af75078fSIntel lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id = 269af75078fSIntel lcore_params[i].queue_id; 270af75078fSIntel lcore_conf[lcore].n_rx_queue++; 271af75078fSIntel } 272af75078fSIntel } 273af75078fSIntel return 0; 274af75078fSIntel } 275af75078fSIntel 276af75078fSIntel /* display usage */ 277af75078fSIntel static void 278af75078fSIntel print_usage(const char *prgname) 279af75078fSIntel { 280c53a5fafSStephen Hemminger fprintf(stderr, "%s [EAL options] --" 28154659744SBeilei Xing " -p PORTMASK" 28254659744SBeilei Xing " [-P]" 28354659744SBeilei Xing " [-E]" 28454659744SBeilei Xing " [-L]" 28554659744SBeilei Xing " --config (port,queue,lcore)[,(port,queue,lcore)]" 28654659744SBeilei Xing " [--eth-dest=X,MM:MM:MM:MM:MM:MM]" 28754659744SBeilei Xing " [--enable-jumbo [--max-pkt-len PKTLEN]]" 28854659744SBeilei Xing " [--no-numa]" 28954659744SBeilei Xing " [--hash-entry-num]" 29054659744SBeilei Xing " [--ipv6]" 291f0a26885SShreyansh Jain " [--parse-ptype]" 292f0a26885SShreyansh Jain " [--per-port-pool]\n\n" 29354659744SBeilei Xing 29454659744SBeilei Xing " -p PORTMASK: Hexadecimal bitmask of ports to configure\n" 29554659744SBeilei Xing " -P : Enable promiscuous mode\n" 29654659744SBeilei Xing " -E : Enable exact match\n" 29754659744SBeilei Xing " -L : Enable longest prefix match (default)\n" 29854659744SBeilei Xing " --config (port,queue,lcore): Rx queue configuration\n" 29954659744SBeilei Xing " --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n" 30054659744SBeilei Xing " --enable-jumbo: Enable jumbo frames\n" 30154659744SBeilei Xing " --max-pkt-len: Under the premise of enabling jumbo,\n" 30254659744SBeilei Xing " maximum packet length in decimal (64-9600)\n" 30354659744SBeilei Xing " --no-numa: Disable numa awareness\n" 30454659744SBeilei Xing " --hash-entry-num: Specify the hash entry number in hexadecimal to be setup\n" 30554659744SBeilei Xing " --ipv6: Set if running ipv6 packets\n" 306f0a26885SShreyansh Jain " --parse-ptype: Set to use software to analyze packet type\n" 307f0a26885SShreyansh Jain " --per-port-pool: Use separate buffer pool per port\n\n", 308af75078fSIntel prgname); 309af75078fSIntel } 310af75078fSIntel 311268888b5SRavi Kerur static int 312268888b5SRavi Kerur parse_max_pkt_len(const char *pktlen) 313f68aad79SIntel { 314f68aad79SIntel char *end = NULL; 315f68aad79SIntel unsigned long len; 316f68aad79SIntel 317f68aad79SIntel /* parse decimal string */ 318f68aad79SIntel len = strtoul(pktlen, &end, 10); 319f68aad79SIntel if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0')) 320f68aad79SIntel return -1; 321f68aad79SIntel 322f68aad79SIntel if (len == 0) 323f68aad79SIntel return -1; 324f68aad79SIntel 325f68aad79SIntel return len; 326f68aad79SIntel } 327f68aad79SIntel 328af75078fSIntel static int 329af75078fSIntel parse_portmask(const char *portmask) 330af75078fSIntel { 331af75078fSIntel char *end = NULL; 332af75078fSIntel unsigned long pm; 333af75078fSIntel 334af75078fSIntel /* parse hexadecimal string */ 335af75078fSIntel pm = strtoul(portmask, &end, 16); 336af75078fSIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 337af75078fSIntel return -1; 338af75078fSIntel 339af75078fSIntel if (pm == 0) 340af75078fSIntel return -1; 341af75078fSIntel 342af75078fSIntel return pm; 343af75078fSIntel } 344af75078fSIntel 345997ee890SIntel static int 346997ee890SIntel parse_hash_entry_number(const char *hash_entry_num) 347997ee890SIntel { 348997ee890SIntel char *end = NULL; 349997ee890SIntel unsigned long hash_en; 350997ee890SIntel /* parse hexadecimal string */ 351997ee890SIntel hash_en = strtoul(hash_entry_num, &end, 16); 352997ee890SIntel if ((hash_entry_num[0] == '\0') || (end == NULL) || (*end != '\0')) 353997ee890SIntel return -1; 354997ee890SIntel 355997ee890SIntel if (hash_en == 0) 356997ee890SIntel return -1; 357997ee890SIntel 358997ee890SIntel return hash_en; 359997ee890SIntel } 360997ee890SIntel 361af75078fSIntel static int 362af75078fSIntel parse_config(const char *q_arg) 363af75078fSIntel { 364af75078fSIntel char s[256]; 365af75078fSIntel const char *p, *p0 = q_arg; 366af75078fSIntel char *end; 367af75078fSIntel enum fieldnames { 368af75078fSIntel FLD_PORT = 0, 369af75078fSIntel FLD_QUEUE, 370af75078fSIntel FLD_LCORE, 371af75078fSIntel _NUM_FLD 372af75078fSIntel }; 373af75078fSIntel unsigned long int_fld[_NUM_FLD]; 374af75078fSIntel char *str_fld[_NUM_FLD]; 375af75078fSIntel int i; 376af75078fSIntel unsigned size; 377af75078fSIntel 378af75078fSIntel nb_lcore_params = 0; 379af75078fSIntel 380af75078fSIntel while ((p = strchr(p0,'(')) != NULL) { 381af75078fSIntel ++p; 382af75078fSIntel if((p0 = strchr(p,')')) == NULL) 383af75078fSIntel return -1; 384af75078fSIntel 385af75078fSIntel size = p0 - p; 386af75078fSIntel if(size >= sizeof(s)) 387af75078fSIntel return -1; 388af75078fSIntel 3896f41fe75SStephen Hemminger snprintf(s, sizeof(s), "%.*s", size, p); 390af75078fSIntel if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD) 391af75078fSIntel return -1; 392af75078fSIntel for (i = 0; i < _NUM_FLD; i++){ 393af75078fSIntel errno = 0; 394af75078fSIntel int_fld[i] = strtoul(str_fld[i], &end, 0); 395af75078fSIntel if (errno != 0 || end == str_fld[i] || int_fld[i] > 255) 396af75078fSIntel return -1; 397af75078fSIntel } 398af75078fSIntel if (nb_lcore_params >= MAX_LCORE_PARAMS) { 399af75078fSIntel printf("exceeded max number of lcore params: %hu\n", 400af75078fSIntel nb_lcore_params); 401af75078fSIntel return -1; 402af75078fSIntel } 403268888b5SRavi Kerur lcore_params_array[nb_lcore_params].port_id = 404268888b5SRavi Kerur (uint8_t)int_fld[FLD_PORT]; 405268888b5SRavi Kerur lcore_params_array[nb_lcore_params].queue_id = 406268888b5SRavi Kerur (uint8_t)int_fld[FLD_QUEUE]; 407268888b5SRavi Kerur lcore_params_array[nb_lcore_params].lcore_id = 408268888b5SRavi Kerur (uint8_t)int_fld[FLD_LCORE]; 409af75078fSIntel ++nb_lcore_params; 410af75078fSIntel } 411af75078fSIntel lcore_params = lcore_params_array; 412af75078fSIntel return 0; 413af75078fSIntel } 414af75078fSIntel 415bd785f6fSAndrey Chilikin static void 416bd785f6fSAndrey Chilikin parse_eth_dest(const char *optarg) 417bd785f6fSAndrey Chilikin { 418f8244c63SZhiyong Yang uint16_t portid; 419bd785f6fSAndrey Chilikin char *port_end; 420bd785f6fSAndrey Chilikin uint8_t c, *dest, peer_addr[6]; 421bd785f6fSAndrey Chilikin 422bd785f6fSAndrey Chilikin errno = 0; 423bd785f6fSAndrey Chilikin portid = strtoul(optarg, &port_end, 10); 424bd785f6fSAndrey Chilikin if (errno != 0 || port_end == optarg || *port_end++ != ',') 425bd785f6fSAndrey Chilikin rte_exit(EXIT_FAILURE, 426bd785f6fSAndrey Chilikin "Invalid eth-dest: %s", optarg); 427bd785f6fSAndrey Chilikin if (portid >= RTE_MAX_ETHPORTS) 428bd785f6fSAndrey Chilikin rte_exit(EXIT_FAILURE, 429bd785f6fSAndrey Chilikin "eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n", 430bd785f6fSAndrey Chilikin portid, RTE_MAX_ETHPORTS); 431bd785f6fSAndrey Chilikin 432bd785f6fSAndrey Chilikin if (cmdline_parse_etheraddr(NULL, port_end, 433bd785f6fSAndrey Chilikin &peer_addr, sizeof(peer_addr)) < 0) 434bd785f6fSAndrey Chilikin rte_exit(EXIT_FAILURE, 435bd785f6fSAndrey Chilikin "Invalid ethernet address: %s\n", 436bd785f6fSAndrey Chilikin port_end); 437bd785f6fSAndrey Chilikin dest = (uint8_t *)&dest_eth_addr[portid]; 438bd785f6fSAndrey Chilikin for (c = 0; c < 6; c++) 439bd785f6fSAndrey Chilikin dest[c] = peer_addr[c]; 440bd785f6fSAndrey Chilikin *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; 441bd785f6fSAndrey Chilikin } 442bd785f6fSAndrey Chilikin 443268888b5SRavi Kerur #define MAX_JUMBO_PKT_LEN 9600 444268888b5SRavi Kerur #define MEMPOOL_CACHE_SIZE 256 445268888b5SRavi Kerur 44688617471SOlivier Matz static const char short_options[] = 44788617471SOlivier Matz "p:" /* portmask */ 44888617471SOlivier Matz "P" /* promiscuous */ 44988617471SOlivier Matz "L" /* enable long prefix match */ 45088617471SOlivier Matz "E" /* enable exact match */ 45188617471SOlivier Matz ; 45288617471SOlivier Matz 453997ee890SIntel #define CMD_LINE_OPT_CONFIG "config" 454bd785f6fSAndrey Chilikin #define CMD_LINE_OPT_ETH_DEST "eth-dest" 455997ee890SIntel #define CMD_LINE_OPT_NO_NUMA "no-numa" 456997ee890SIntel #define CMD_LINE_OPT_IPV6 "ipv6" 457997ee890SIntel #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo" 458997ee890SIntel #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num" 45971a7e242SJianfeng Tan #define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype" 460f0a26885SShreyansh Jain #define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool" 46188617471SOlivier Matz enum { 46288617471SOlivier Matz /* long options mapped to a short option */ 46388617471SOlivier Matz 46488617471SOlivier Matz /* first long only option value must be >= 256, so that we won't 46588617471SOlivier Matz * conflict with short options */ 46688617471SOlivier Matz CMD_LINE_OPT_MIN_NUM = 256, 46788617471SOlivier Matz CMD_LINE_OPT_CONFIG_NUM, 46888617471SOlivier Matz CMD_LINE_OPT_ETH_DEST_NUM, 46988617471SOlivier Matz CMD_LINE_OPT_NO_NUMA_NUM, 47088617471SOlivier Matz CMD_LINE_OPT_IPV6_NUM, 47188617471SOlivier Matz CMD_LINE_OPT_ENABLE_JUMBO_NUM, 47288617471SOlivier Matz CMD_LINE_OPT_HASH_ENTRY_NUM_NUM, 47388617471SOlivier Matz CMD_LINE_OPT_PARSE_PTYPE_NUM, 474f0a26885SShreyansh Jain CMD_LINE_OPT_PARSE_PER_PORT_POOL, 47588617471SOlivier Matz }; 47688617471SOlivier Matz 47788617471SOlivier Matz static const struct option lgopts[] = { 47888617471SOlivier Matz {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM}, 47988617471SOlivier Matz {CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM}, 48088617471SOlivier Matz {CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM}, 48188617471SOlivier Matz {CMD_LINE_OPT_IPV6, 0, 0, CMD_LINE_OPT_IPV6_NUM}, 48288617471SOlivier Matz {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, CMD_LINE_OPT_ENABLE_JUMBO_NUM}, 48388617471SOlivier Matz {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, CMD_LINE_OPT_HASH_ENTRY_NUM_NUM}, 48488617471SOlivier Matz {CMD_LINE_OPT_PARSE_PTYPE, 0, 0, CMD_LINE_OPT_PARSE_PTYPE_NUM}, 485f0a26885SShreyansh Jain {CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL}, 48688617471SOlivier Matz {NULL, 0, 0, 0} 48788617471SOlivier Matz }; 488997ee890SIntel 489268888b5SRavi Kerur /* 490268888b5SRavi Kerur * This expression is used to calculate the number of mbufs needed 491268888b5SRavi Kerur * depending on user input, taking into account memory for rx and 492268888b5SRavi Kerur * tx hardware rings, cache per lcore and mtable per port per lcore. 493268888b5SRavi Kerur * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum 494268888b5SRavi Kerur * value of 8192 495268888b5SRavi Kerur */ 496f0a26885SShreyansh Jain #define NB_MBUF(nports) RTE_MAX( \ 497f0a26885SShreyansh Jain (nports*nb_rx_queue*nb_rxd + \ 498f0a26885SShreyansh Jain nports*nb_lcores*MAX_PKT_BURST + \ 499f0a26885SShreyansh Jain nports*n_tx_queue*nb_txd + \ 500268888b5SRavi Kerur nb_lcores*MEMPOOL_CACHE_SIZE), \ 501268888b5SRavi Kerur (unsigned)8192) 502268888b5SRavi Kerur 503af75078fSIntel /* Parse the argument given in the command line of the application */ 504af75078fSIntel static int 505af75078fSIntel parse_args(int argc, char **argv) 506af75078fSIntel { 507af75078fSIntel int opt, ret; 508af75078fSIntel char **argvopt; 509af75078fSIntel int option_index; 510af75078fSIntel char *prgname = argv[0]; 511af75078fSIntel 512af75078fSIntel argvopt = argv; 513af75078fSIntel 514268888b5SRavi Kerur /* Error or normal output strings. */ 51588617471SOlivier Matz while ((opt = getopt_long(argc, argvopt, short_options, 516af75078fSIntel lgopts, &option_index)) != EOF) { 517af75078fSIntel 518af75078fSIntel switch (opt) { 519af75078fSIntel /* portmask */ 520af75078fSIntel case 'p': 521af75078fSIntel enabled_port_mask = parse_portmask(optarg); 522af75078fSIntel if (enabled_port_mask == 0) { 523c53a5fafSStephen Hemminger fprintf(stderr, "Invalid portmask\n"); 524af75078fSIntel print_usage(prgname); 525af75078fSIntel return -1; 526af75078fSIntel } 527af75078fSIntel break; 52888617471SOlivier Matz 529af75078fSIntel case 'P': 530af75078fSIntel promiscuous_on = 1; 531af75078fSIntel break; 532af75078fSIntel 533268888b5SRavi Kerur case 'E': 534268888b5SRavi Kerur l3fwd_em_on = 1; 535268888b5SRavi Kerur break; 536268888b5SRavi Kerur 537268888b5SRavi Kerur case 'L': 538268888b5SRavi Kerur l3fwd_lpm_on = 1; 539268888b5SRavi Kerur break; 540268888b5SRavi Kerur 541af75078fSIntel /* long options */ 54288617471SOlivier Matz case CMD_LINE_OPT_CONFIG_NUM: 543af75078fSIntel ret = parse_config(optarg); 544af75078fSIntel if (ret) { 545c53a5fafSStephen Hemminger fprintf(stderr, "Invalid config\n"); 546af75078fSIntel print_usage(prgname); 547af75078fSIntel return -1; 548af75078fSIntel } 54988617471SOlivier Matz break; 550af75078fSIntel 55188617471SOlivier Matz case CMD_LINE_OPT_ETH_DEST_NUM: 552bd785f6fSAndrey Chilikin parse_eth_dest(optarg); 55388617471SOlivier Matz break; 554bd785f6fSAndrey Chilikin 55588617471SOlivier Matz case CMD_LINE_OPT_NO_NUMA_NUM: 556af75078fSIntel numa_on = 0; 55788617471SOlivier Matz break; 558f68aad79SIntel 55988617471SOlivier Matz case CMD_LINE_OPT_IPV6_NUM: 560997ee890SIntel ipv6 = 1; 56188617471SOlivier Matz break; 562997ee890SIntel 56388617471SOlivier Matz case CMD_LINE_OPT_ENABLE_JUMBO_NUM: { 564c53a5fafSStephen Hemminger const struct option lenopts = { 565268888b5SRavi Kerur "max-pkt-len", required_argument, 0, 0 566268888b5SRavi Kerur }; 567f68aad79SIntel 5681ef9600bSShahaf Shuler port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME; 5691ef9600bSShahaf Shuler port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS; 570f68aad79SIntel 571268888b5SRavi Kerur /* 572268888b5SRavi Kerur * if no max-pkt-len set, use the default 57335b2d13fSOlivier Matz * value RTE_ETHER_MAX_LEN. 574268888b5SRavi Kerur */ 57588617471SOlivier Matz if (getopt_long(argc, argvopt, "", 57688617471SOlivier Matz &lenopts, &option_index) == 0) { 577f68aad79SIntel ret = parse_max_pkt_len(optarg); 578c53a5fafSStephen Hemminger if (ret < 64 || ret > MAX_JUMBO_PKT_LEN) { 579c53a5fafSStephen Hemminger fprintf(stderr, 580c53a5fafSStephen Hemminger "invalid maximum packet length\n"); 581f68aad79SIntel print_usage(prgname); 582f68aad79SIntel return -1; 583f68aad79SIntel } 584f68aad79SIntel port_conf.rxmode.max_rx_pkt_len = ret; 585f68aad79SIntel } 58688617471SOlivier Matz break; 587f68aad79SIntel } 588268888b5SRavi Kerur 58988617471SOlivier Matz case CMD_LINE_OPT_HASH_ENTRY_NUM_NUM: 590997ee890SIntel ret = parse_hash_entry_number(optarg); 591997ee890SIntel if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) { 592997ee890SIntel hash_entry_number = ret; 593997ee890SIntel } else { 594c53a5fafSStephen Hemminger fprintf(stderr, "invalid hash entry number\n"); 595997ee890SIntel print_usage(prgname); 596997ee890SIntel return -1; 597997ee890SIntel } 59888617471SOlivier Matz break; 59971a7e242SJianfeng Tan 60088617471SOlivier Matz case CMD_LINE_OPT_PARSE_PTYPE_NUM: 60171a7e242SJianfeng Tan printf("soft parse-ptype is enabled\n"); 60271a7e242SJianfeng Tan parse_ptype = 1; 603af75078fSIntel break; 604af75078fSIntel 605f0a26885SShreyansh Jain case CMD_LINE_OPT_PARSE_PER_PORT_POOL: 606f0a26885SShreyansh Jain printf("per port buffer pool is enabled\n"); 607f0a26885SShreyansh Jain per_port_pool = 1; 608f0a26885SShreyansh Jain break; 609f0a26885SShreyansh Jain 610af75078fSIntel default: 611af75078fSIntel print_usage(prgname); 612af75078fSIntel return -1; 613af75078fSIntel } 614af75078fSIntel } 615af75078fSIntel 616268888b5SRavi Kerur /* If both LPM and EM are selected, return error. */ 617268888b5SRavi Kerur if (l3fwd_lpm_on && l3fwd_em_on) { 618c53a5fafSStephen Hemminger fprintf(stderr, "LPM and EM are mutually exclusive, select only one\n"); 619268888b5SRavi Kerur return -1; 620268888b5SRavi Kerur } 621268888b5SRavi Kerur 622268888b5SRavi Kerur /* 623268888b5SRavi Kerur * Nothing is selected, pick longest-prefix match 624268888b5SRavi Kerur * as default match. 625268888b5SRavi Kerur */ 626268888b5SRavi Kerur if (!l3fwd_lpm_on && !l3fwd_em_on) { 627c53a5fafSStephen Hemminger fprintf(stderr, "LPM or EM none selected, default LPM on\n"); 628268888b5SRavi Kerur l3fwd_lpm_on = 1; 629268888b5SRavi Kerur } 630268888b5SRavi Kerur 631268888b5SRavi Kerur /* 632268888b5SRavi Kerur * ipv6 and hash flags are valid only for 633268888b5SRavi Kerur * exact macth, reset them to default for 634268888b5SRavi Kerur * longest-prefix match. 635268888b5SRavi Kerur */ 636268888b5SRavi Kerur if (l3fwd_lpm_on) { 637268888b5SRavi Kerur ipv6 = 0; 638268888b5SRavi Kerur hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT; 639268888b5SRavi Kerur } 640268888b5SRavi Kerur 641af75078fSIntel if (optind >= 0) 642af75078fSIntel argv[optind-1] = prgname; 643af75078fSIntel 644af75078fSIntel ret = optind-1; 6459d5ca532SKeith Wiles optind = 1; /* reset getopt lib */ 646af75078fSIntel return ret; 647af75078fSIntel } 648af75078fSIntel 649af75078fSIntel static void 6506d13ea8eSOlivier Matz print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr) 651af75078fSIntel { 65235b2d13fSOlivier Matz char buf[RTE_ETHER_ADDR_FMT_SIZE]; 65335b2d13fSOlivier Matz rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); 654ec3d82dbSCunming Liang printf("%s%s", name, buf); 655af75078fSIntel } 656af75078fSIntel 657af75078fSIntel static int 658f0a26885SShreyansh Jain init_mem(uint16_t portid, unsigned int nb_mbuf) 659af75078fSIntel { 660af75078fSIntel struct lcore_conf *qconf; 661af75078fSIntel int socketid; 662af75078fSIntel unsigned lcore_id; 663af75078fSIntel char s[64]; 664af75078fSIntel 665af75078fSIntel for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 666af75078fSIntel if (rte_lcore_is_enabled(lcore_id) == 0) 667af75078fSIntel continue; 668af75078fSIntel 669af75078fSIntel if (numa_on) 670af75078fSIntel socketid = rte_lcore_to_socket_id(lcore_id); 671af75078fSIntel else 672af75078fSIntel socketid = 0; 673af75078fSIntel 674af75078fSIntel if (socketid >= NB_SOCKETS) { 675268888b5SRavi Kerur rte_exit(EXIT_FAILURE, 676268888b5SRavi Kerur "Socket %d of lcore %u is out of range %d\n", 677af75078fSIntel socketid, lcore_id, NB_SOCKETS); 678af75078fSIntel } 679268888b5SRavi Kerur 680f0a26885SShreyansh Jain if (pktmbuf_pool[portid][socketid] == NULL) { 681f0a26885SShreyansh Jain snprintf(s, sizeof(s), "mbuf_pool_%d:%d", 682f0a26885SShreyansh Jain portid, socketid); 683f0a26885SShreyansh Jain pktmbuf_pool[portid][socketid] = 684ea0c20eaSOlivier Matz rte_pktmbuf_pool_create(s, nb_mbuf, 685824cb29cSKonstantin Ananyev MEMPOOL_CACHE_SIZE, 0, 686824cb29cSKonstantin Ananyev RTE_MBUF_DEFAULT_BUF_SIZE, socketid); 687f0a26885SShreyansh Jain if (pktmbuf_pool[portid][socketid] == NULL) 688af75078fSIntel rte_exit(EXIT_FAILURE, 689268888b5SRavi Kerur "Cannot init mbuf pool on socket %d\n", 690268888b5SRavi Kerur socketid); 691af75078fSIntel else 692268888b5SRavi Kerur printf("Allocated mbuf pool on socket %d\n", 693268888b5SRavi Kerur socketid); 694af75078fSIntel 695f0a26885SShreyansh Jain /* Setup either LPM or EM(f.e Hash). But, only once per 696f0a26885SShreyansh Jain * available socket. 697f0a26885SShreyansh Jain */ 698f0a26885SShreyansh Jain if (!lkp_per_socket[socketid]) { 699268888b5SRavi Kerur l3fwd_lkp.setup(socketid); 700f0a26885SShreyansh Jain lkp_per_socket[socketid] = 1; 701f0a26885SShreyansh Jain } 702af75078fSIntel } 703af75078fSIntel qconf = &lcore_conf[lcore_id]; 704268888b5SRavi Kerur qconf->ipv4_lookup_struct = 705268888b5SRavi Kerur l3fwd_lkp.get_ipv4_lookup_struct(socketid); 706268888b5SRavi Kerur qconf->ipv6_lookup_struct = 707268888b5SRavi Kerur l3fwd_lkp.get_ipv6_lookup_struct(socketid); 708af75078fSIntel } 709af75078fSIntel return 0; 710af75078fSIntel } 711af75078fSIntel 712d3641ae8SIntel /* Check the link status of all ports in up to 9s, and print them finally */ 713d3641ae8SIntel static void 7148728ccf3SThomas Monjalon check_all_ports_link_status(uint32_t port_mask) 715d3641ae8SIntel { 716d3641ae8SIntel #define CHECK_INTERVAL 100 /* 100ms */ 717d3641ae8SIntel #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 718f8244c63SZhiyong Yang uint16_t portid; 719f8244c63SZhiyong Yang uint8_t count, all_ports_up, print_flag = 0; 720d3641ae8SIntel struct rte_eth_link link; 721d3641ae8SIntel 722d3641ae8SIntel printf("\nChecking link status"); 723d3641ae8SIntel fflush(stdout); 724d3641ae8SIntel for (count = 0; count <= MAX_CHECK_TIME; count++) { 725308df2bfSZhihong Wang if (force_quit) 726308df2bfSZhihong Wang return; 727d3641ae8SIntel all_ports_up = 1; 7288728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 729308df2bfSZhihong Wang if (force_quit) 730308df2bfSZhihong Wang return; 731d3641ae8SIntel if ((port_mask & (1 << portid)) == 0) 732d3641ae8SIntel continue; 733d3641ae8SIntel memset(&link, 0, sizeof(link)); 734d3641ae8SIntel rte_eth_link_get_nowait(portid, &link); 735d3641ae8SIntel /* print link status if flag set */ 736d3641ae8SIntel if (print_flag == 1) { 737d3641ae8SIntel if (link.link_status) 738f8244c63SZhiyong Yang printf( 739f8244c63SZhiyong Yang "Port%d Link Up. Speed %u Mbps -%s\n", 740f8244c63SZhiyong Yang portid, link.link_speed, 741d3641ae8SIntel (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? 742d3641ae8SIntel ("full-duplex") : ("half-duplex\n")); 743d3641ae8SIntel else 744f8244c63SZhiyong Yang printf("Port %d Link Down\n", portid); 745d3641ae8SIntel continue; 746d3641ae8SIntel } 747d3641ae8SIntel /* clear all_ports_up flag if any link down */ 74809419f23SThomas Monjalon if (link.link_status == ETH_LINK_DOWN) { 749d3641ae8SIntel all_ports_up = 0; 750d3641ae8SIntel break; 751d3641ae8SIntel } 752d3641ae8SIntel } 753d3641ae8SIntel /* after finally printing all link status, get out */ 754d3641ae8SIntel if (print_flag == 1) 755d3641ae8SIntel break; 756d3641ae8SIntel 757d3641ae8SIntel if (all_ports_up == 0) { 758d3641ae8SIntel printf("."); 759d3641ae8SIntel fflush(stdout); 760d3641ae8SIntel rte_delay_ms(CHECK_INTERVAL); 761d3641ae8SIntel } 762d3641ae8SIntel 763d3641ae8SIntel /* set the print_flag if all ports up or timeout */ 764d3641ae8SIntel if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 765d3641ae8SIntel print_flag = 1; 766d3641ae8SIntel printf("done\n"); 767d3641ae8SIntel } 768d3641ae8SIntel } 769d3641ae8SIntel } 770d3641ae8SIntel 771308df2bfSZhihong Wang static void 772308df2bfSZhihong Wang signal_handler(int signum) 773308df2bfSZhihong Wang { 774308df2bfSZhihong Wang if (signum == SIGINT || signum == SIGTERM) { 775308df2bfSZhihong Wang printf("\n\nSignal %d received, preparing to exit...\n", 776308df2bfSZhihong Wang signum); 777308df2bfSZhihong Wang force_quit = true; 778308df2bfSZhihong Wang } 779308df2bfSZhihong Wang } 780308df2bfSZhihong Wang 78171a7e242SJianfeng Tan static int 782f8244c63SZhiyong Yang prepare_ptype_parser(uint16_t portid, uint16_t queueid) 78371a7e242SJianfeng Tan { 78471a7e242SJianfeng Tan if (parse_ptype) { 78571a7e242SJianfeng Tan printf("Port %d: softly parse packet type info\n", portid); 78671a7e242SJianfeng Tan if (rte_eth_add_rx_callback(portid, queueid, 78771a7e242SJianfeng Tan l3fwd_lkp.cb_parse_ptype, 78871a7e242SJianfeng Tan NULL)) 78971a7e242SJianfeng Tan return 1; 79071a7e242SJianfeng Tan 79171a7e242SJianfeng Tan printf("Failed to add rx callback: port=%d\n", portid); 79271a7e242SJianfeng Tan return 0; 79371a7e242SJianfeng Tan } 79471a7e242SJianfeng Tan 79571a7e242SJianfeng Tan if (l3fwd_lkp.check_ptype(portid)) 79671a7e242SJianfeng Tan return 1; 79771a7e242SJianfeng Tan 79871a7e242SJianfeng Tan printf("port %d cannot parse packet type, please add --%s\n", 79971a7e242SJianfeng Tan portid, CMD_LINE_OPT_PARSE_PTYPE); 80071a7e242SJianfeng Tan return 0; 80171a7e242SJianfeng Tan } 80271a7e242SJianfeng Tan 803af75078fSIntel int 80498a16481SDavid Marchand main(int argc, char **argv) 805af75078fSIntel { 806af75078fSIntel struct lcore_conf *qconf; 80781f7ecd9SPablo de Lara struct rte_eth_dev_info dev_info; 80881f7ecd9SPablo de Lara struct rte_eth_txconf *txconf; 809af75078fSIntel int ret; 810af75078fSIntel unsigned nb_ports; 811f8244c63SZhiyong Yang uint16_t queueid, portid; 812af75078fSIntel unsigned lcore_id; 813af75078fSIntel uint32_t n_tx_queue, nb_lcores; 814f8244c63SZhiyong Yang uint8_t nb_rx_queue, queue, socketid; 815af75078fSIntel 816af75078fSIntel /* init EAL */ 817af75078fSIntel ret = rte_eal_init(argc, argv); 818af75078fSIntel if (ret < 0) 819af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); 820af75078fSIntel argc -= ret; 821af75078fSIntel argv += ret; 822af75078fSIntel 823308df2bfSZhihong Wang force_quit = false; 824308df2bfSZhihong Wang signal(SIGINT, signal_handler); 825308df2bfSZhihong Wang signal(SIGTERM, signal_handler); 826308df2bfSZhihong Wang 827bd785f6fSAndrey Chilikin /* pre-init dst MACs for all ports to 02:00:00:00:00:xx */ 828bd785f6fSAndrey Chilikin for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { 829268888b5SRavi Kerur dest_eth_addr[portid] = 83035b2d13fSOlivier Matz RTE_ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40); 831bd785f6fSAndrey Chilikin *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; 832bd785f6fSAndrey Chilikin } 833bd785f6fSAndrey Chilikin 834af75078fSIntel /* parse application arguments (after the EAL ones) */ 835af75078fSIntel ret = parse_args(argc, argv); 836af75078fSIntel if (ret < 0) 837af75078fSIntel rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n"); 838af75078fSIntel 839af75078fSIntel if (check_lcore_params() < 0) 840af75078fSIntel rte_exit(EXIT_FAILURE, "check_lcore_params failed\n"); 841af75078fSIntel 842af75078fSIntel ret = init_lcore_rx_queues(); 843af75078fSIntel if (ret < 0) 844af75078fSIntel rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n"); 845af75078fSIntel 846d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail(); 847af75078fSIntel 848a9dbe180SThomas Monjalon if (check_port_config() < 0) 849af75078fSIntel rte_exit(EXIT_FAILURE, "check_port_config failed\n"); 850af75078fSIntel 851af75078fSIntel nb_lcores = rte_lcore_count(); 852af75078fSIntel 853268888b5SRavi Kerur /* Setup function pointers for lookup method. */ 854268888b5SRavi Kerur setup_l3fwd_lookup_tables(); 855268888b5SRavi Kerur 856af75078fSIntel /* initialize all ports */ 8578728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 8581ef9600bSShahaf Shuler struct rte_eth_conf local_port_conf = port_conf; 8591ef9600bSShahaf Shuler 860af75078fSIntel /* skip ports that are not enabled */ 861af75078fSIntel if ((enabled_port_mask & (1 << portid)) == 0) { 862af75078fSIntel printf("\nSkipping disabled port %d\n", portid); 863af75078fSIntel continue; 864af75078fSIntel } 865af75078fSIntel 866af75078fSIntel /* init port */ 867af75078fSIntel printf("Initializing port %d ... ", portid ); 868af75078fSIntel fflush(stdout); 869af75078fSIntel 870af75078fSIntel nb_rx_queue = get_port_n_rx_queues(portid); 871af75078fSIntel n_tx_queue = nb_lcores; 872af75078fSIntel if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) 873af75078fSIntel n_tx_queue = MAX_TX_QUEUE_PER_PORT; 874af75078fSIntel printf("Creating queues: nb_rxq=%d nb_txq=%u... ", 875af75078fSIntel nb_rx_queue, (unsigned)n_tx_queue ); 8761ef9600bSShahaf Shuler 877*089e5ed7SIvan Ilchenko ret = rte_eth_dev_info_get(portid, &dev_info); 878*089e5ed7SIvan Ilchenko if (ret != 0) 879*089e5ed7SIvan Ilchenko rte_exit(EXIT_FAILURE, 880*089e5ed7SIvan Ilchenko "Error during getting device (port %u) info: %s\n", 881*089e5ed7SIvan Ilchenko portid, strerror(-ret)); 882*089e5ed7SIvan Ilchenko 8831ef9600bSShahaf Shuler if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 8841ef9600bSShahaf Shuler local_port_conf.txmode.offloads |= 8851ef9600bSShahaf Shuler DEV_TX_OFFLOAD_MBUF_FAST_FREE; 8864f5701f2SFerruh Yigit 8874f5701f2SFerruh Yigit local_port_conf.rx_adv_conf.rss_conf.rss_hf &= 8884f5701f2SFerruh Yigit dev_info.flow_type_rss_offloads; 8894f5701f2SFerruh Yigit if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != 8904f5701f2SFerruh Yigit port_conf.rx_adv_conf.rss_conf.rss_hf) { 8914f5701f2SFerruh Yigit printf("Port %u modified RSS hash function based on hardware support," 8924f5701f2SFerruh Yigit "requested:%#"PRIx64" configured:%#"PRIx64"\n", 8934f5701f2SFerruh Yigit portid, 8944f5701f2SFerruh Yigit port_conf.rx_adv_conf.rss_conf.rss_hf, 8954f5701f2SFerruh Yigit local_port_conf.rx_adv_conf.rss_conf.rss_hf); 8964f5701f2SFerruh Yigit } 8974f5701f2SFerruh Yigit 898af75078fSIntel ret = rte_eth_dev_configure(portid, nb_rx_queue, 8991ef9600bSShahaf Shuler (uint16_t)n_tx_queue, &local_port_conf); 900af75078fSIntel if (ret < 0) 901268888b5SRavi Kerur rte_exit(EXIT_FAILURE, 902268888b5SRavi Kerur "Cannot configure device: err=%d, port=%d\n", 903af75078fSIntel ret, portid); 904af75078fSIntel 90560efb44fSRoman Zhukov ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, 90660efb44fSRoman Zhukov &nb_txd); 90760efb44fSRoman Zhukov if (ret < 0) 90860efb44fSRoman Zhukov rte_exit(EXIT_FAILURE, 90960efb44fSRoman Zhukov "Cannot adjust number of descriptors: err=%d, " 91060efb44fSRoman Zhukov "port=%d\n", ret, portid); 91160efb44fSRoman Zhukov 912af75078fSIntel rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); 913af75078fSIntel print_ethaddr(" Address:", &ports_eth_addr[portid]); 914af75078fSIntel printf(", "); 915bd785f6fSAndrey Chilikin print_ethaddr("Destination:", 9166d13ea8eSOlivier Matz (const struct rte_ether_addr *)&dest_eth_addr[portid]); 917bd785f6fSAndrey Chilikin printf(", "); 918af75078fSIntel 91996ff4453SKonstantin Ananyev /* 920bd785f6fSAndrey Chilikin * prepare src MACs for each port. 92196ff4453SKonstantin Ananyev */ 922538da7a1SOlivier Matz rte_ether_addr_copy(&ports_eth_addr[portid], 9236d13ea8eSOlivier Matz (struct rte_ether_addr *)(val_eth + portid) + 1); 92496ff4453SKonstantin Ananyev 925f68aad79SIntel /* init memory */ 926f0a26885SShreyansh Jain if (!per_port_pool) { 927f0a26885SShreyansh Jain /* portid = 0; this is *not* signifying the first port, 928f0a26885SShreyansh Jain * rather, it signifies that portid is ignored. 929f0a26885SShreyansh Jain */ 930f0a26885SShreyansh Jain ret = init_mem(0, NB_MBUF(nb_ports)); 931f0a26885SShreyansh Jain } else { 932f0a26885SShreyansh Jain ret = init_mem(portid, NB_MBUF(1)); 933f0a26885SShreyansh Jain } 934f68aad79SIntel if (ret < 0) 935f68aad79SIntel rte_exit(EXIT_FAILURE, "init_mem failed\n"); 936af75078fSIntel 937af75078fSIntel /* init one TX queue per couple (lcore,port) */ 938af75078fSIntel queueid = 0; 939af75078fSIntel for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 940af75078fSIntel if (rte_lcore_is_enabled(lcore_id) == 0) 941af75078fSIntel continue; 942af75078fSIntel 943af75078fSIntel if (numa_on) 944268888b5SRavi Kerur socketid = 945268888b5SRavi Kerur (uint8_t)rte_lcore_to_socket_id(lcore_id); 946af75078fSIntel else 947af75078fSIntel socketid = 0; 948af75078fSIntel 949af75078fSIntel printf("txq=%u,%d,%d ", lcore_id, queueid, socketid); 950af75078fSIntel fflush(stdout); 95181f7ecd9SPablo de Lara 95281f7ecd9SPablo de Lara txconf = &dev_info.default_txconf; 9531ef9600bSShahaf Shuler txconf->offloads = local_port_conf.txmode.offloads; 954af75078fSIntel ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd, 95581f7ecd9SPablo de Lara socketid, txconf); 956af75078fSIntel if (ret < 0) 957268888b5SRavi Kerur rte_exit(EXIT_FAILURE, 958268888b5SRavi Kerur "rte_eth_tx_queue_setup: err=%d, " 959af75078fSIntel "port=%d\n", ret, portid); 960af75078fSIntel 961af75078fSIntel qconf = &lcore_conf[lcore_id]; 962af75078fSIntel qconf->tx_queue_id[portid] = queueid; 963af75078fSIntel queueid++; 96452c97adcSTomasz Kulasek 96552c97adcSTomasz Kulasek qconf->tx_port_id[qconf->n_tx_port] = portid; 9669d203b76STomasz Kulasek qconf->n_tx_port++; 967af75078fSIntel } 968af75078fSIntel printf("\n"); 969af75078fSIntel } 970af75078fSIntel 971af75078fSIntel for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 972af75078fSIntel if (rte_lcore_is_enabled(lcore_id) == 0) 973af75078fSIntel continue; 974af75078fSIntel qconf = &lcore_conf[lcore_id]; 975af75078fSIntel printf("\nInitializing rx queues on lcore %u ... ", lcore_id ); 976af75078fSIntel fflush(stdout); 977af75078fSIntel /* init RX queues */ 978af75078fSIntel for(queue = 0; queue < qconf->n_rx_queue; ++queue) { 9791ef9600bSShahaf Shuler struct rte_eth_rxconf rxq_conf; 9801ef9600bSShahaf Shuler 981af75078fSIntel portid = qconf->rx_queue_list[queue].port_id; 982af75078fSIntel queueid = qconf->rx_queue_list[queue].queue_id; 983af75078fSIntel 984af75078fSIntel if (numa_on) 985268888b5SRavi Kerur socketid = 986268888b5SRavi Kerur (uint8_t)rte_lcore_to_socket_id(lcore_id); 987af75078fSIntel else 988af75078fSIntel socketid = 0; 989af75078fSIntel 990af75078fSIntel printf("rxq=%d,%d,%d ", portid, queueid, socketid); 991af75078fSIntel fflush(stdout); 992af75078fSIntel 993*089e5ed7SIvan Ilchenko ret = rte_eth_dev_info_get(portid, &dev_info); 994*089e5ed7SIvan Ilchenko if (ret != 0) 995*089e5ed7SIvan Ilchenko rte_exit(EXIT_FAILURE, 996*089e5ed7SIvan Ilchenko "Error during getting device (port %u) info: %s\n", 997*089e5ed7SIvan Ilchenko portid, strerror(-ret)); 998*089e5ed7SIvan Ilchenko 9991ef9600bSShahaf Shuler rxq_conf = dev_info.default_rxconf; 10005c5c1f99SMarcin Zapolski rxq_conf.offloads = port_conf.rxmode.offloads; 1001f0a26885SShreyansh Jain if (!per_port_pool) 1002f0a26885SShreyansh Jain ret = rte_eth_rx_queue_setup(portid, queueid, 1003f0a26885SShreyansh Jain nb_rxd, socketid, 10041ef9600bSShahaf Shuler &rxq_conf, 1005f0a26885SShreyansh Jain pktmbuf_pool[0][socketid]); 1006f0a26885SShreyansh Jain else 1007f0a26885SShreyansh Jain ret = rte_eth_rx_queue_setup(portid, queueid, 1008f0a26885SShreyansh Jain nb_rxd, socketid, 1009f0a26885SShreyansh Jain &rxq_conf, 1010f0a26885SShreyansh Jain pktmbuf_pool[portid][socketid]); 1011af75078fSIntel if (ret < 0) 1012268888b5SRavi Kerur rte_exit(EXIT_FAILURE, 1013268888b5SRavi Kerur "rte_eth_rx_queue_setup: err=%d, port=%d\n", 1014268888b5SRavi Kerur ret, portid); 1015af75078fSIntel } 1016af75078fSIntel } 1017af75078fSIntel 1018af75078fSIntel printf("\n"); 1019af75078fSIntel 1020af75078fSIntel /* start ports */ 10218728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 1022af75078fSIntel if ((enabled_port_mask & (1 << portid)) == 0) { 1023af75078fSIntel continue; 1024af75078fSIntel } 1025af75078fSIntel /* Start device */ 1026af75078fSIntel ret = rte_eth_dev_start(portid); 1027af75078fSIntel if (ret < 0) 1028268888b5SRavi Kerur rte_exit(EXIT_FAILURE, 1029268888b5SRavi Kerur "rte_eth_dev_start: err=%d, port=%d\n", 1030af75078fSIntel ret, portid); 1031af75078fSIntel 1032af75078fSIntel /* 1033af75078fSIntel * If enabled, put device in promiscuous mode. 1034af75078fSIntel * This allows IO forwarding mode to forward packets 1035af75078fSIntel * to itself through 2 cross-connected ports of the 1036af75078fSIntel * target machine. 1037af75078fSIntel */ 1038af75078fSIntel if (promiscuous_on) 1039af75078fSIntel rte_eth_promiscuous_enable(portid); 1040af75078fSIntel } 1041af75078fSIntel 104271a7e242SJianfeng Tan printf("\n"); 104371a7e242SJianfeng Tan 104471a7e242SJianfeng Tan for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 104571a7e242SJianfeng Tan if (rte_lcore_is_enabled(lcore_id) == 0) 104671a7e242SJianfeng Tan continue; 104771a7e242SJianfeng Tan qconf = &lcore_conf[lcore_id]; 104871a7e242SJianfeng Tan for (queue = 0; queue < qconf->n_rx_queue; ++queue) { 104971a7e242SJianfeng Tan portid = qconf->rx_queue_list[queue].port_id; 105071a7e242SJianfeng Tan queueid = qconf->rx_queue_list[queue].queue_id; 105171a7e242SJianfeng Tan if (prepare_ptype_parser(portid, queueid) == 0) 105271a7e242SJianfeng Tan rte_exit(EXIT_FAILURE, "ptype check fails\n"); 105371a7e242SJianfeng Tan } 105471a7e242SJianfeng Tan } 105571a7e242SJianfeng Tan 105671a7e242SJianfeng Tan 10578728ccf3SThomas Monjalon check_all_ports_link_status(enabled_port_mask); 1058d3641ae8SIntel 1059308df2bfSZhihong Wang ret = 0; 1060af75078fSIntel /* launch per-lcore init on every lcore */ 1061268888b5SRavi Kerur rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MASTER); 1062af75078fSIntel RTE_LCORE_FOREACH_SLAVE(lcore_id) { 1063308df2bfSZhihong Wang if (rte_eal_wait_lcore(lcore_id) < 0) { 1064308df2bfSZhihong Wang ret = -1; 1065308df2bfSZhihong Wang break; 1066308df2bfSZhihong Wang } 1067af75078fSIntel } 1068af75078fSIntel 1069308df2bfSZhihong Wang /* stop ports */ 10708728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 1071308df2bfSZhihong Wang if ((enabled_port_mask & (1 << portid)) == 0) 1072308df2bfSZhihong Wang continue; 1073308df2bfSZhihong Wang printf("Closing port %d...", portid); 1074308df2bfSZhihong Wang rte_eth_dev_stop(portid); 1075308df2bfSZhihong Wang rte_eth_dev_close(portid); 1076308df2bfSZhihong Wang printf(" Done\n"); 1077308df2bfSZhihong Wang } 1078308df2bfSZhihong Wang printf("Bye...\n"); 1079308df2bfSZhihong Wang 1080308df2bfSZhihong Wang return ret; 1081af75078fSIntel } 1082