X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=examples%2Fl3fwd%2Fmain.c;h=a6291982238fd7e1da0df1cab9d7c8d296469f0d;hb=1230526d13dcaf55b80ee2e6b42db2d295ad151d;hp=97a1423d3de90a127b4d9bd5ba5ac1e83f671cb0;hpb=a6b450805ba18ae5768dd6f303843f8b6807e97d;p=dpdk.git diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c index 97a1423d3d..a629198223 100644 --- a/examples/l3fwd/main.c +++ b/examples/l3fwd/main.c @@ -1,34 +1,5 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2021 Intel Corporation */ #include @@ -48,25 +19,20 @@ #include #include #include +#include #include #include -#include #include -#include #include -#include #include #include #include #include #include #include -#include #include #include #include -#include -#include #include #include #include @@ -79,38 +45,42 @@ #include #include "l3fwd.h" +#include "l3fwd_event.h" +#include "l3fwd_route.h" -/* - * Configurable number of RX/TX ring descriptors - */ -#define RTE_TEST_RX_DESC_DEFAULT 128 -#define RTE_TEST_TX_DESC_DEFAULT 512 - -#define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS +#define MAX_TX_QUEUE_PER_PORT RTE_MAX_LCORE #define MAX_RX_QUEUE_PER_PORT 128 #define MAX_LCORE_PARAMS 1024 -/* Static global variables used within this file. */ -static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; -static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; +uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; +uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; /**< Ports set in promiscuous mode off by default. */ static int promiscuous_on; -/* Select Longest-Prefix or Exact match. */ -static int l3fwd_lpm_on; -static int l3fwd_em_on; - -static int numa_on = 1; /**< NUMA is enabled by default. */ +/* Select Longest-Prefix, Exact match or Forwarding Information Base. */ +enum L3FWD_LOOKUP_MODE { + L3FWD_LOOKUP_DEFAULT, + L3FWD_LOOKUP_LPM, + L3FWD_LOOKUP_EM, + L3FWD_LOOKUP_FIB +}; +static enum L3FWD_LOOKUP_MODE lookup_mode; /* Global variables. */ +static int numa_on = 1; /**< NUMA is enabled by default. */ +static int parse_ptype; /**< Parse packet type using rx callback, and */ + /**< disabled by default */ +static int per_port_pool; /**< Use separate buffer pools per port; disabled */ + /**< by default */ + volatile bool force_quit; /* ethernet addresses of ports */ uint64_t dest_eth_addr[RTE_MAX_ETHPORTS]; -struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; +struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; xmm_t val_eth[RTE_MAX_ETHPORTS]; @@ -123,8 +93,10 @@ uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT; struct lcore_conf lcore_conf[RTE_MAX_LCORE]; +struct parm_cfg parm_config; + struct lcore_params { - uint8_t port_id; + uint16_t port_id; uint8_t queue_id; uint8_t lcore_id; } __rte_cache_aligned; @@ -148,62 +120,148 @@ static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) / static struct rte_eth_conf port_conf = { .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .max_rx_pkt_len = ETHER_MAX_LEN, + .mq_mode = RTE_ETH_MQ_RX_RSS, .split_hdr_size = 0, - .header_split = 0, /**< Header Split disabled */ - .hw_ip_checksum = 1, /**< IP checksum offload enabled */ - .hw_vlan_filter = 0, /**< VLAN filtering disabled */ - .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ - .hw_strip_crc = 0, /**< CRC stripped by hardware */ + .offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM, }, .rx_adv_conf = { .rss_conf = { .rss_key = NULL, - .rss_hf = ETH_RSS_IP, + .rss_hf = RTE_ETH_RSS_IP, }, }, .txmode = { - .mq_mode = ETH_MQ_TX_NONE, + .mq_mode = RTE_ETH_MQ_TX_NONE, }, }; -static struct rte_mempool * pktmbuf_pool[NB_SOCKETS]; +static uint32_t max_pkt_len; + +static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS]; +static struct rte_mempool *vector_pool[RTE_MAX_ETHPORTS]; +static uint8_t lkp_per_socket[NB_SOCKETS]; struct l3fwd_lkp_mode { + void (*read_config_files)(void); void (*setup)(int); + int (*check_ptype)(int); + rte_rx_callback_fn cb_parse_ptype; int (*main_loop)(void *); void* (*get_ipv4_lookup_struct)(int); void* (*get_ipv6_lookup_struct)(int); + void (*free_routes)(void); }; static struct l3fwd_lkp_mode l3fwd_lkp; static struct l3fwd_lkp_mode l3fwd_em_lkp = { + .read_config_files = read_config_files_em, .setup = setup_hash, + .check_ptype = em_check_ptype, + .cb_parse_ptype = em_cb_parse_ptype, .main_loop = em_main_loop, .get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct, .get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct, + .free_routes = em_free_routes, }; static struct l3fwd_lkp_mode l3fwd_lpm_lkp = { + .read_config_files = read_config_files_lpm, .setup = setup_lpm, + .check_ptype = lpm_check_ptype, + .cb_parse_ptype = lpm_cb_parse_ptype, .main_loop = lpm_main_loop, .get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct, .get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct, + .free_routes = lpm_free_routes, +}; + +static struct l3fwd_lkp_mode l3fwd_fib_lkp = { + .read_config_files = read_config_files_lpm, + .setup = setup_fib, + .check_ptype = lpm_check_ptype, + .cb_parse_ptype = lpm_cb_parse_ptype, + .main_loop = fib_main_loop, + .get_ipv4_lookup_struct = fib_get_ipv4_l3fwd_lookup_struct, + .get_ipv6_lookup_struct = fib_get_ipv6_l3fwd_lookup_struct, + .free_routes = lpm_free_routes, +}; + +/* + * 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735). + * 198.18.{0-15}.0/24 = Port {0-15} + */ +const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = { + {RTE_IPV4(198, 18, 0, 0), 24, 0}, + {RTE_IPV4(198, 18, 1, 0), 24, 1}, + {RTE_IPV4(198, 18, 2, 0), 24, 2}, + {RTE_IPV4(198, 18, 3, 0), 24, 3}, + {RTE_IPV4(198, 18, 4, 0), 24, 4}, + {RTE_IPV4(198, 18, 5, 0), 24, 5}, + {RTE_IPV4(198, 18, 6, 0), 24, 6}, + {RTE_IPV4(198, 18, 7, 0), 24, 7}, + {RTE_IPV4(198, 18, 8, 0), 24, 8}, + {RTE_IPV4(198, 18, 9, 0), 24, 9}, + {RTE_IPV4(198, 18, 10, 0), 24, 10}, + {RTE_IPV4(198, 18, 11, 0), 24, 11}, + {RTE_IPV4(198, 18, 12, 0), 24, 12}, + {RTE_IPV4(198, 18, 13, 0), 24, 13}, + {RTE_IPV4(198, 18, 14, 0), 24, 14}, + {RTE_IPV4(198, 18, 15, 0), 24, 15}, +}; + +/* + * 2001:200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180). + * 2001:200:0:{0-f}::/64 = Port {0-15} + */ +const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = { + {{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 0}, + {{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 1}, + {{32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 2}, + {{32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 3}, + {{32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 4}, + {{32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 5}, + {{32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 6}, + {{32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 7}, + {{32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 8}, + {{32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 9}, + {{32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 10}, + {{32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 11}, + {{32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 12}, + {{32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 13}, + {{32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 14}, + {{32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 15}, }; +/* + * API's called during initialization to setup ACL/EM/LPM rules. + */ +static void +l3fwd_set_rule_ipv4_name(const char *optarg) +{ + parm_config.rule_ipv4_name = optarg; +} + +static void +l3fwd_set_rule_ipv6_name(const char *optarg) +{ + parm_config.rule_ipv6_name = optarg; +} + /* * Setup lookup methods for forwarding. - * Currently exact-match and longest-prefix-match - * are supported ones. + * Currently exact-match, longest-prefix-match and forwarding information + * base are the supported ones. */ static void setup_l3fwd_lookup_tables(void) { /* Setup HASH lookup functions. */ - if (l3fwd_em_on) + if (lookup_mode == L3FWD_LOOKUP_EM) l3fwd_lkp = l3fwd_em_lkp; + /* Setup FIB lookup functions. */ + else if (lookup_mode == L3FWD_LOOKUP_FIB) + l3fwd_lkp = l3fwd_fib_lkp; /* Setup LPM lookup functions. */ else l3fwd_lkp = l3fwd_lpm_lkp; @@ -237,9 +295,9 @@ check_lcore_params(void) } static int -check_port_config(const unsigned nb_ports) +check_port_config(void) { - unsigned portid; + uint16_t portid; uint16_t i; for (i = 0; i < nb_lcore_params; ++i) { @@ -248,7 +306,7 @@ check_port_config(const unsigned nb_ports) printf("port %u is not enabled in port mask\n", portid); return -1; } - if (portid >= nb_ports) { + if (!rte_eth_dev_is_valid_port(portid)) { printf("port %u is not present on the board\n", portid); return -1; } @@ -257,7 +315,7 @@ check_port_config(const unsigned nb_ports) } static uint8_t -get_port_n_rx_queues(const uint8_t port) +get_port_n_rx_queues(const uint16_t port) { int queue = -1; uint16_t i; @@ -303,21 +361,63 @@ init_lcore_rx_queues(void) static void print_usage(const char *prgname) { - printf ("%s [EAL options] -- -p PORTMASK -P" - " [--config (port,queue,lcore)[,(port,queue,lcore]]" - " [--enable-jumbo [--max-pkt-len PKTLEN]]\n" - " -p PORTMASK: hexadecimal bitmask of ports to configure\n" - " -P : enable promiscuous mode\n" - " -E : enable exact match\n" - " -L : enable longest prefix match\n" - " --config (port,queue,lcore): rx queues configuration\n" - " --eth-dest=X,MM:MM:MM:MM:MM:MM: optional, ethernet destination for port X\n" - " --no-numa: optional, disable numa awareness\n" - " --ipv6: optional, specify it if running ipv6 packets\n" - " --enable-jumbo: enable jumbo frame" - " which max packet len is PKTLEN in decimal (64-9600)\n" - " --hash-entry-num: specify the hash entry number in hexadecimal to be setup\n", - prgname); + fprintf(stderr, "%s [EAL options] --" + " -p PORTMASK" + " --rule_ipv4=FILE" + " --rule_ipv6=FILE" + " [-P]" + " [--lookup]" + " --config (port,queue,lcore)[,(port,queue,lcore)]" + " [--rx-queue-size NPKTS]" + " [--tx-queue-size NPKTS]" + " [--eth-dest=X,MM:MM:MM:MM:MM:MM]" + " [--max-pkt-len PKTLEN]" + " [--no-numa]" + " [--hash-entry-num]" + " [--ipv6]" + " [--parse-ptype]" + " [--per-port-pool]" + " [--mode]" + " [--eventq-sched]" + " [--event-vector [--event-vector-size SIZE] [--event-vector-tmo NS]]" + " [-E]" + " [-L]\n\n" + + " -p PORTMASK: Hexadecimal bitmask of ports to configure\n" + " -P : Enable promiscuous mode\n" + " --lookup: Select the lookup method\n" + " Default: lpm\n" + " Accepted: em (Exact Match), lpm (Longest Prefix Match), fib (Forwarding Information Base)\n" + " --config (port,queue,lcore): Rx queue configuration\n" + " --rx-queue-size NPKTS: Rx queue size in decimal\n" + " Default: %d\n" + " --tx-queue-size NPKTS: Tx queue size in decimal\n" + " Default: %d\n" + " --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n" + " --max-pkt-len PKTLEN: maximum packet length in decimal (64-9600)\n" + " --no-numa: Disable numa awareness\n" + " --hash-entry-num: Specify the hash entry number in hexadecimal to be setup\n" + " --ipv6: Set if running ipv6 packets\n" + " --parse-ptype: Set to use software to analyze packet type\n" + " --per-port-pool: Use separate buffer pool per port\n" + " --mode: Packet transfer mode for I/O, poll or eventdev\n" + " Default mode = poll\n" + " --eventq-sched: Event queue synchronization method\n" + " ordered, atomic or parallel.\n" + " Default: atomic\n" + " Valid only if --mode=eventdev\n" + " --event-eth-rxqs: Number of ethernet RX queues per device.\n" + " Default: 1\n" + " Valid only if --mode=eventdev\n" + " --event-vector: Enable event vectorization.\n" + " --event-vector-size: Max vector size if event vectorization is enabled.\n" + " --event-vector-tmo: Max timeout to form vector in nanoseconds if event vectorization is enabled\n" + " -E : Enable exact match, legacy flag please use --lookup=em instead\n" + " -L : Enable longest prefix match, legacy flag please use --lookup=lpm instead\n" + " --rule_ipv4=FILE: Specify the ipv4 rules entries file.\n" + " Each rule occupies one line.\n" + " --rule_ipv6=FILE: Specify the ipv6 rules entries file.\n\n", + prgname, RTE_TEST_RX_DESC_DEFAULT, RTE_TEST_TX_DESC_DEFAULT); } static int @@ -346,10 +446,7 @@ parse_portmask(const char *portmask) /* parse hexadecimal string */ pm = strtoul(portmask, &end, 16); if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - - if (pm == 0) - return -1; + return 0; return pm; } @@ -427,7 +524,7 @@ parse_config(const char *q_arg) static void parse_eth_dest(const char *optarg) { - uint8_t portid; + uint16_t portid; char *port_end; uint8_t c, *dest, peer_addr[6]; @@ -452,15 +549,175 @@ parse_eth_dest(const char *optarg) *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; } +static void +parse_mode(const char *optarg) +{ + struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); + + if (!strcmp(optarg, "poll")) + evt_rsrc->enabled = false; + else if (!strcmp(optarg, "eventdev")) + evt_rsrc->enabled = true; +} + +static void +parse_queue_size(const char *queue_size_arg, uint16_t *queue_size, int rx) +{ + char *end = NULL; + unsigned long value; + + /* parse decimal string */ + value = strtoul(queue_size_arg, &end, 10); + if ((queue_size_arg[0] == '\0') || (end == NULL) || + (*end != '\0') || (value == 0)) { + if (rx == 1) + rte_exit(EXIT_FAILURE, "Invalid rx-queue-size\n"); + else + rte_exit(EXIT_FAILURE, "Invalid tx-queue-size\n"); + + return; + } + + if (value > UINT16_MAX) { + if (rx == 1) + rte_exit(EXIT_FAILURE, "rx-queue-size %lu > %d\n", + value, UINT16_MAX); + else + rte_exit(EXIT_FAILURE, "tx-queue-size %lu > %d\n", + value, UINT16_MAX); + + return; + } + + *queue_size = value; +} + +static void +parse_eventq_sched(const char *optarg) +{ + struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); + + if (!strcmp(optarg, "ordered")) + evt_rsrc->sched_type = RTE_SCHED_TYPE_ORDERED; + if (!strcmp(optarg, "atomic")) + evt_rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC; + if (!strcmp(optarg, "parallel")) + evt_rsrc->sched_type = RTE_SCHED_TYPE_PARALLEL; +} + +static void +parse_event_eth_rx_queues(const char *eth_rx_queues) +{ + struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); + char *end = NULL; + uint8_t num_eth_rx_queues; + + /* parse decimal string */ + num_eth_rx_queues = strtoul(eth_rx_queues, &end, 10); + if ((eth_rx_queues[0] == '\0') || (end == NULL) || (*end != '\0')) + return; + + if (num_eth_rx_queues == 0) + return; + + evt_rsrc->eth_rx_queues = num_eth_rx_queues; +} + +static int +parse_lookup(const char *optarg) +{ + if (!strcmp(optarg, "em")) + lookup_mode = L3FWD_LOOKUP_EM; + else if (!strcmp(optarg, "lpm")) + lookup_mode = L3FWD_LOOKUP_LPM; + else if (!strcmp(optarg, "fib")) + lookup_mode = L3FWD_LOOKUP_FIB; + else { + fprintf(stderr, "Invalid lookup option! Accepted options: em, lpm, fib\n"); + return -1; + } + return 0; +} + #define MAX_JUMBO_PKT_LEN 9600 -#define MEMPOOL_CACHE_SIZE 256 + +static const char short_options[] = + "p:" /* portmask */ + "P" /* promiscuous */ + "L" /* legacy enable long prefix match */ + "E" /* legacy enable exact match */ + ; #define CMD_LINE_OPT_CONFIG "config" +#define CMD_LINE_OPT_RX_QUEUE_SIZE "rx-queue-size" +#define CMD_LINE_OPT_TX_QUEUE_SIZE "tx-queue-size" #define CMD_LINE_OPT_ETH_DEST "eth-dest" #define CMD_LINE_OPT_NO_NUMA "no-numa" #define CMD_LINE_OPT_IPV6 "ipv6" -#define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo" +#define CMD_LINE_OPT_MAX_PKT_LEN "max-pkt-len" #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num" +#define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype" +#define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool" +#define CMD_LINE_OPT_MODE "mode" +#define CMD_LINE_OPT_EVENTQ_SYNC "eventq-sched" +#define CMD_LINE_OPT_EVENT_ETH_RX_QUEUES "event-eth-rxqs" +#define CMD_LINE_OPT_LOOKUP "lookup" +#define CMD_LINE_OPT_ENABLE_VECTOR "event-vector" +#define CMD_LINE_OPT_VECTOR_SIZE "event-vector-size" +#define CMD_LINE_OPT_VECTOR_TMO_NS "event-vector-tmo" +#define CMD_LINE_OPT_RULE_IPV4 "rule_ipv4" +#define CMD_LINE_OPT_RULE_IPV6 "rule_ipv6" + +enum { + /* long options mapped to a short option */ + + /* first long only option value must be >= 256, so that we won't + * conflict with short options */ + CMD_LINE_OPT_MIN_NUM = 256, + CMD_LINE_OPT_CONFIG_NUM, + CMD_LINE_OPT_RX_QUEUE_SIZE_NUM, + CMD_LINE_OPT_TX_QUEUE_SIZE_NUM, + CMD_LINE_OPT_ETH_DEST_NUM, + CMD_LINE_OPT_NO_NUMA_NUM, + CMD_LINE_OPT_IPV6_NUM, + CMD_LINE_OPT_MAX_PKT_LEN_NUM, + CMD_LINE_OPT_HASH_ENTRY_NUM_NUM, + CMD_LINE_OPT_PARSE_PTYPE_NUM, + CMD_LINE_OPT_RULE_IPV4_NUM, + CMD_LINE_OPT_RULE_IPV6_NUM, + CMD_LINE_OPT_PARSE_PER_PORT_POOL, + CMD_LINE_OPT_MODE_NUM, + CMD_LINE_OPT_EVENTQ_SYNC_NUM, + CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM, + CMD_LINE_OPT_LOOKUP_NUM, + CMD_LINE_OPT_ENABLE_VECTOR_NUM, + CMD_LINE_OPT_VECTOR_SIZE_NUM, + CMD_LINE_OPT_VECTOR_TMO_NS_NUM +}; + +static const struct option lgopts[] = { + {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM}, + {CMD_LINE_OPT_RX_QUEUE_SIZE, 1, 0, CMD_LINE_OPT_RX_QUEUE_SIZE_NUM}, + {CMD_LINE_OPT_TX_QUEUE_SIZE, 1, 0, CMD_LINE_OPT_TX_QUEUE_SIZE_NUM}, + {CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM}, + {CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM}, + {CMD_LINE_OPT_IPV6, 0, 0, CMD_LINE_OPT_IPV6_NUM}, + {CMD_LINE_OPT_MAX_PKT_LEN, 1, 0, CMD_LINE_OPT_MAX_PKT_LEN_NUM}, + {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, CMD_LINE_OPT_HASH_ENTRY_NUM_NUM}, + {CMD_LINE_OPT_PARSE_PTYPE, 0, 0, CMD_LINE_OPT_PARSE_PTYPE_NUM}, + {CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL}, + {CMD_LINE_OPT_MODE, 1, 0, CMD_LINE_OPT_MODE_NUM}, + {CMD_LINE_OPT_EVENTQ_SYNC, 1, 0, CMD_LINE_OPT_EVENTQ_SYNC_NUM}, + {CMD_LINE_OPT_EVENT_ETH_RX_QUEUES, 1, 0, + CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM}, + {CMD_LINE_OPT_LOOKUP, 1, 0, CMD_LINE_OPT_LOOKUP_NUM}, + {CMD_LINE_OPT_ENABLE_VECTOR, 0, 0, CMD_LINE_OPT_ENABLE_VECTOR_NUM}, + {CMD_LINE_OPT_VECTOR_SIZE, 1, 0, CMD_LINE_OPT_VECTOR_SIZE_NUM}, + {CMD_LINE_OPT_VECTOR_TMO_NS, 1, 0, CMD_LINE_OPT_VECTOR_TMO_NS_NUM}, + {CMD_LINE_OPT_RULE_IPV4, 1, 0, CMD_LINE_OPT_RULE_IPV4_NUM}, + {CMD_LINE_OPT_RULE_IPV6, 1, 0, CMD_LINE_OPT_RULE_IPV6_NUM}, + {NULL, 0, 0, 0} +}; /* * This expression is used to calculate the number of mbufs needed @@ -469,11 +726,11 @@ parse_eth_dest(const char *optarg) * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum * value of 8192 */ -#define NB_MBUF RTE_MAX( \ - (nb_ports*nb_rx_queue*RTE_TEST_RX_DESC_DEFAULT + \ - nb_ports*nb_lcores*MAX_PKT_BURST + \ - nb_ports*n_tx_queue*RTE_TEST_TX_DESC_DEFAULT + \ - nb_lcores*MEMPOOL_CACHE_SIZE), \ +#define NB_MBUF(nports) RTE_MAX( \ + (nports*nb_rx_queue*nb_rxd + \ + nports*nb_lcores*MAX_PKT_BURST + \ + nports*n_tx_queue*nb_txd + \ + nb_lcores*MEMPOOL_CACHE_SIZE), \ (unsigned)8192) /* Parse the argument given in the command line of the application */ @@ -484,36 +741,15 @@ parse_args(int argc, char **argv) char **argvopt; int option_index; char *prgname = argv[0]; - static struct option lgopts[] = { - {CMD_LINE_OPT_CONFIG, 1, 0, 0}, - {CMD_LINE_OPT_ETH_DEST, 1, 0, 0}, - {CMD_LINE_OPT_NO_NUMA, 0, 0, 0}, - {CMD_LINE_OPT_IPV6, 0, 0, 0}, - {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0}, - {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0}, - {NULL, 0, 0, 0} - }; + uint8_t lcore_params = 0; + uint8_t eventq_sched = 0; + uint8_t eth_rx_q = 0; + struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); argvopt = argv; /* Error or normal output strings. */ - const char *str1 = "L3FWD: Invalid portmask"; - const char *str2 = "L3FWD: Promiscuous mode selected"; - const char *str3 = "L3FWD: Exact match selected"; - const char *str4 = "L3FWD: Longest-prefix match selected"; - const char *str5 = "L3FWD: Invalid config"; - const char *str6 = "L3FWD: NUMA is disabled"; - const char *str7 = "L3FWD: IPV6 is specified"; - const char *str8 = - "L3FWD: Jumbo frame is enabled - disabling simple TX path"; - const char *str9 = "L3FWD: Invalid packet length"; - const char *str10 = "L3FWD: Set jumbo frame max packet len to "; - const char *str11 = "L3FWD: Invalid hash entry number"; - const char *str12 = - "L3FWD: LPM and EM are mutually exclusive, select only one"; - const char *str13 = "L3FWD: LPM or EM none selected, default LPM on"; - - while ((opt = getopt_long(argc, argvopt, "p:PLE", + while ((opt = getopt_long(argc, argvopt, short_options, lgopts, &option_index)) != EOF) { switch (opt) { @@ -521,131 +757,182 @@ parse_args(int argc, char **argv) case 'p': enabled_port_mask = parse_portmask(optarg); if (enabled_port_mask == 0) { - printf("%s\n", str1); + fprintf(stderr, "Invalid portmask\n"); print_usage(prgname); return -1; } break; + case 'P': - printf("%s\n", str2); promiscuous_on = 1; break; case 'E': - printf("%s\n", str3); - l3fwd_em_on = 1; + if (lookup_mode != L3FWD_LOOKUP_DEFAULT) { + fprintf(stderr, "Only one lookup mode is allowed at a time!\n"); + return -1; + } + lookup_mode = L3FWD_LOOKUP_EM; break; case 'L': - printf("%s\n", str4); - l3fwd_lpm_on = 1; + if (lookup_mode != L3FWD_LOOKUP_DEFAULT) { + fprintf(stderr, "Only one lookup mode is allowed at a time!\n"); + return -1; + } + lookup_mode = L3FWD_LOOKUP_LPM; break; /* long options */ - case 0: - if (!strncmp(lgopts[option_index].name, - CMD_LINE_OPT_CONFIG, - sizeof(CMD_LINE_OPT_CONFIG))) { - - ret = parse_config(optarg); - if (ret) { - printf("%s\n", str5); - print_usage(prgname); - return -1; - } + case CMD_LINE_OPT_CONFIG_NUM: + ret = parse_config(optarg); + if (ret) { + fprintf(stderr, "Invalid config\n"); + print_usage(prgname); + return -1; } + lcore_params = 1; + break; - if (!strncmp(lgopts[option_index].name, - CMD_LINE_OPT_ETH_DEST, - sizeof(CMD_LINE_OPT_ETH_DEST))) { - parse_eth_dest(optarg); - } + case CMD_LINE_OPT_RX_QUEUE_SIZE_NUM: + parse_queue_size(optarg, &nb_rxd, 1); + break; - if (!strncmp(lgopts[option_index].name, - CMD_LINE_OPT_NO_NUMA, - sizeof(CMD_LINE_OPT_NO_NUMA))) { - printf("%s\n", str6); - numa_on = 0; - } + case CMD_LINE_OPT_TX_QUEUE_SIZE_NUM: + parse_queue_size(optarg, &nb_txd, 0); + break; - if (!strncmp(lgopts[option_index].name, - CMD_LINE_OPT_IPV6, - sizeof(CMD_LINE_OPT_IPV6))) { - printf("%sn", str7); - ipv6 = 1; - } + case CMD_LINE_OPT_ETH_DEST_NUM: + parse_eth_dest(optarg); + break; + + case CMD_LINE_OPT_NO_NUMA_NUM: + numa_on = 0; + break; + + case CMD_LINE_OPT_IPV6_NUM: + ipv6 = 1; + break; + + case CMD_LINE_OPT_MAX_PKT_LEN_NUM: + max_pkt_len = parse_max_pkt_len(optarg); + break; - if (!strncmp(lgopts[option_index].name, - CMD_LINE_OPT_ENABLE_JUMBO, - sizeof(CMD_LINE_OPT_ENABLE_JUMBO))) { - struct option lenopts = { - "max-pkt-len", required_argument, 0, 0 - }; - - printf("%s\n", str8); - port_conf.rxmode.jumbo_frame = 1; - - /* - * if no max-pkt-len set, use the default - * value ETHER_MAX_LEN. - */ - if (0 == getopt_long(argc, argvopt, "", - &lenopts, &option_index)) { - ret = parse_max_pkt_len(optarg); - if ((ret < 64) || - (ret > MAX_JUMBO_PKT_LEN)) { - printf("%s\n", str9); - print_usage(prgname); - return -1; - } - port_conf.rxmode.max_rx_pkt_len = ret; - } - printf("%s %u\n", str10, - (unsigned int)port_conf.rxmode.max_rx_pkt_len); + case CMD_LINE_OPT_HASH_ENTRY_NUM_NUM: + ret = parse_hash_entry_number(optarg); + if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) { + hash_entry_number = ret; + } else { + fprintf(stderr, "invalid hash entry number\n"); + print_usage(prgname); + return -1; } + break; + + case CMD_LINE_OPT_PARSE_PTYPE_NUM: + printf("soft parse-ptype is enabled\n"); + parse_ptype = 1; + break; - if (!strncmp(lgopts[option_index].name, - CMD_LINE_OPT_HASH_ENTRY_NUM, - sizeof(CMD_LINE_OPT_HASH_ENTRY_NUM))) { - - ret = parse_hash_entry_number(optarg); - if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) { - hash_entry_number = ret; - } else { - printf("%s\n", str11); - print_usage(prgname); - return -1; - } + case CMD_LINE_OPT_PARSE_PER_PORT_POOL: + printf("per port buffer pool is enabled\n"); + per_port_pool = 1; + break; + + case CMD_LINE_OPT_MODE_NUM: + parse_mode(optarg); + break; + + case CMD_LINE_OPT_EVENTQ_SYNC_NUM: + parse_eventq_sched(optarg); + eventq_sched = 1; + break; + + case CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM: + parse_event_eth_rx_queues(optarg); + eth_rx_q = 1; + break; + + case CMD_LINE_OPT_LOOKUP_NUM: + if (lookup_mode != L3FWD_LOOKUP_DEFAULT) { + fprintf(stderr, "Only one lookup mode is allowed at a time!\n"); + return -1; } + ret = parse_lookup(optarg); + /* + * If parse_lookup was passed an invalid lookup type + * then return -1. Error log included within + * parse_lookup for simplicity. + */ + if (ret) + return -1; break; + case CMD_LINE_OPT_ENABLE_VECTOR_NUM: + printf("event vectorization is enabled\n"); + evt_rsrc->vector_enabled = 1; + break; + case CMD_LINE_OPT_VECTOR_SIZE_NUM: + evt_rsrc->vector_size = strtol(optarg, NULL, 10); + break; + case CMD_LINE_OPT_VECTOR_TMO_NS_NUM: + evt_rsrc->vector_tmo_ns = strtoull(optarg, NULL, 10); + break; + case CMD_LINE_OPT_RULE_IPV4_NUM: + l3fwd_set_rule_ipv4_name(optarg); + break; + case CMD_LINE_OPT_RULE_IPV6_NUM: + l3fwd_set_rule_ipv6_name(optarg); + break; default: print_usage(prgname); return -1; } } - /* If both LPM and EM are selected, return error. */ - if (l3fwd_lpm_on && l3fwd_em_on) { - printf("%s\n", str12); + if (evt_rsrc->enabled && lcore_params) { + fprintf(stderr, "lcore config is not valid when event mode is selected\n"); return -1; } + if (!evt_rsrc->enabled && eth_rx_q) { + fprintf(stderr, "eth_rx_queues is valid only when event mode is selected\n"); + return -1; + } + + if (!evt_rsrc->enabled && eventq_sched) { + fprintf(stderr, "eventq_sched is valid only when event mode is selected\n"); + return -1; + } + + if (evt_rsrc->vector_enabled && !evt_rsrc->vector_size) { + evt_rsrc->vector_size = VECTOR_SIZE_DEFAULT; + fprintf(stderr, "vector size set to default (%" PRIu16 ")\n", + evt_rsrc->vector_size); + } + + if (evt_rsrc->vector_enabled && !evt_rsrc->vector_tmo_ns) { + evt_rsrc->vector_tmo_ns = VECTOR_TMO_NS_DEFAULT; + fprintf(stderr, + "vector timeout set to default (%" PRIu64 " ns)\n", + evt_rsrc->vector_tmo_ns); + } + /* * Nothing is selected, pick longest-prefix match * as default match. */ - if (!l3fwd_lpm_on && !l3fwd_em_on) { - l3fwd_lpm_on = 1; - printf("%s\n", str13); + if (lookup_mode == L3FWD_LOOKUP_DEFAULT) { + fprintf(stderr, "Neither LPM, EM, or FIB selected, defaulting to LPM\n"); + lookup_mode = L3FWD_LOOKUP_LPM; } /* * ipv6 and hash flags are valid only for - * exact macth, reset them to default for + * exact match, reset them to default for * longest-prefix match. */ - if (l3fwd_lpm_on) { + if (lookup_mode == L3FWD_LOOKUP_LPM) { ipv6 = 0; hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT; } @@ -654,21 +941,22 @@ parse_args(int argc, char **argv) argv[optind-1] = prgname; ret = optind-1; - optind = 0; /* reset getopt lib */ + optind = 1; /* reset getopt lib */ return ret; } static void -print_ethaddr(const char *name, const struct ether_addr *eth_addr) +print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr) { - char buf[ETHER_ADDR_FMT_SIZE]; - ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr); + char buf[RTE_ETHER_ADDR_FMT_SIZE]; + rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); printf("%s%s", name, buf); } -static int -init_mem(unsigned nb_mbuf) +int +init_mem(uint16_t portid, unsigned int nb_mbuf) { + struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); struct lcore_conf *qconf; int socketid; unsigned lcore_id; @@ -689,13 +977,14 @@ init_mem(unsigned nb_mbuf) socketid, lcore_id, NB_SOCKETS); } - if (pktmbuf_pool[socketid] == NULL) { - snprintf(s, sizeof(s), "mbuf_pool_%d", socketid); - pktmbuf_pool[socketid] = + if (pktmbuf_pool[portid][socketid] == NULL) { + snprintf(s, sizeof(s), "mbuf_pool_%d:%d", + portid, socketid); + pktmbuf_pool[portid][socketid] = rte_pktmbuf_pool_create(s, nb_mbuf, MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, socketid); - if (pktmbuf_pool[socketid] == NULL) + if (pktmbuf_pool[portid][socketid] == NULL) rte_exit(EXIT_FAILURE, "Cannot init mbuf pool on socket %d\n", socketid); @@ -703,9 +992,32 @@ init_mem(unsigned nb_mbuf) printf("Allocated mbuf pool on socket %d\n", socketid); - /* Setup either LPM or EM(f.e Hash). */ - l3fwd_lkp.setup(socketid); + /* Setup LPM, EM(f.e Hash) or FIB. But, only once per + * available socket. + */ + if (!lkp_per_socket[socketid]) { + l3fwd_lkp.setup(socketid); + lkp_per_socket[socketid] = 1; + } } + + if (evt_rsrc->vector_enabled && vector_pool[portid] == NULL) { + unsigned int nb_vec; + + nb_vec = (nb_mbuf + evt_rsrc->vector_size - 1) / + evt_rsrc->vector_size; + snprintf(s, sizeof(s), "vector_pool_%d", portid); + vector_pool[portid] = rte_event_vector_pool_create( + s, nb_vec, 0, evt_rsrc->vector_size, socketid); + if (vector_pool[portid] == NULL) + rte_exit(EXIT_FAILURE, + "Failed to create vector pool for port %d\n", + portid); + else + printf("Allocated vector pool for port %d\n", + portid); + } + qconf = &lcore_conf[lcore_id]; qconf->ipv4_lookup_struct = l3fwd_lkp.get_ipv4_lookup_struct(socketid); @@ -717,12 +1029,15 @@ init_mem(unsigned nb_mbuf) /* Check the link status of all ports in up to 9s, and print them finally */ static void -check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) +check_all_ports_link_status(uint32_t port_mask) { #define CHECK_INTERVAL 100 /* 100ms */ #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint8_t portid, count, all_ports_up, print_flag = 0; + uint16_t portid; + uint8_t count, all_ports_up, print_flag = 0; struct rte_eth_link link; + int ret; + char link_status_text[RTE_ETH_LINK_MAX_STR_LEN]; printf("\nChecking link status"); fflush(stdout); @@ -730,28 +1045,30 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) if (force_quit) return; all_ports_up = 1; - for (portid = 0; portid < port_num; portid++) { + RTE_ETH_FOREACH_DEV(portid) { if (force_quit) return; if ((port_mask & (1 << portid)) == 0) continue; memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); + ret = rte_eth_link_get_nowait(portid, &link); + if (ret < 0) { + all_ports_up = 0; + if (print_flag == 1) + printf("Port %u link get failed: %s\n", + portid, rte_strerror(-ret)); + continue; + } /* print link status if flag set */ if (print_flag == 1) { - if (link.link_status) - printf("Port %d Link Up - speed %u " - "Mbps - %s\n", (uint8_t)portid, - (unsigned)link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", - (uint8_t)portid); + rte_eth_link_to_str(link_status_text, + sizeof(link_status_text), &link); + printf("Port %d %s\n", portid, + link_status_text); continue; } /* clear all_ports_up flag if any link down */ - if (link.link_status == 0) { + if (link.link_status == RTE_ETH_LINK_DOWN) { all_ports_up = 0; break; } @@ -784,42 +1101,75 @@ signal_handler(int signum) } } -int -main(int argc, char **argv) +static int +prepare_ptype_parser(uint16_t portid, uint16_t queueid) { - struct lcore_conf *qconf; - struct rte_eth_dev_info dev_info; - struct rte_eth_txconf *txconf; - int ret; - unsigned nb_ports; - uint16_t queueid; - unsigned lcore_id; - uint32_t n_tx_queue, nb_lcores; - uint8_t portid, nb_rx_queue, queue, socketid; - uint8_t nb_tx_port; + if (parse_ptype) { + printf("Port %d: softly parse packet type info\n", portid); + if (rte_eth_add_rx_callback(portid, queueid, + l3fwd_lkp.cb_parse_ptype, + NULL)) + return 1; + + printf("Failed to add rx callback: port=%d\n", portid); + return 0; + } - /* init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); - argc -= ret; - argv += ret; + if (l3fwd_lkp.check_ptype(portid)) + return 1; - force_quit = false; - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); + printf("port %d cannot parse packet type, please add --%s\n", + portid, CMD_LINE_OPT_PARSE_PTYPE); + return 0; +} - /* pre-init dst MACs for all ports to 02:00:00:00:00:xx */ - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { - dest_eth_addr[portid] = - ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40); - *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; - } +static uint32_t +eth_dev_get_overhead_len(uint32_t max_rx_pktlen, uint16_t max_mtu) +{ + uint32_t overhead_len; - /* parse application arguments (after the EAL ones) */ - ret = parse_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n"); + if (max_mtu != UINT16_MAX && max_rx_pktlen > max_mtu) + overhead_len = max_rx_pktlen - max_mtu; + else + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + + return overhead_len; +} + +static int +config_port_max_pkt_len(struct rte_eth_conf *conf, + struct rte_eth_dev_info *dev_info) +{ + uint32_t overhead_len; + + if (max_pkt_len == 0) + return 0; + + if (max_pkt_len < RTE_ETHER_MIN_LEN || max_pkt_len > MAX_JUMBO_PKT_LEN) + return -1; + + overhead_len = eth_dev_get_overhead_len(dev_info->max_rx_pktlen, + dev_info->max_mtu); + conf->rxmode.mtu = max_pkt_len - overhead_len; + + if (conf->rxmode.mtu > RTE_ETHER_MTU) + conf->txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS; + + return 0; +} + +static void +l3fwd_poll_resource_setup(void) +{ + uint8_t nb_rx_queue, queue, socketid; + struct rte_eth_dev_info dev_info; + uint32_t n_tx_queue, nb_lcores; + struct rte_eth_txconf *txconf; + struct lcore_conf *qconf; + uint16_t queueid, portid; + unsigned int nb_ports; + unsigned int lcore_id; + int ret; if (check_lcore_params() < 0) rte_exit(EXIT_FAILURE, "check_lcore_params failed\n"); @@ -828,21 +1178,17 @@ main(int argc, char **argv) if (ret < 0) rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n"); - nb_ports = rte_eth_dev_count(); - if (nb_ports > RTE_MAX_ETHPORTS) - nb_ports = RTE_MAX_ETHPORTS; + nb_ports = rte_eth_dev_count_avail(); - if (check_port_config(nb_ports) < 0) + if (check_port_config() < 0) rte_exit(EXIT_FAILURE, "check_port_config failed\n"); nb_lcores = rte_lcore_count(); - nb_tx_port = 0; - - /* Setup function pointers for lookup method. */ - setup_l3fwd_lookup_tables(); /* initialize all ports */ - for (portid = 0; portid < nb_ports; portid++) { + RTE_ETH_FOREACH_DEV(portid) { + struct rte_eth_conf local_port_conf = port_conf; + /* skip ports that are not enabled */ if ((enabled_port_mask & (1 << portid)) == 0) { printf("\nSkipping disabled port %d\n", portid); @@ -859,28 +1205,79 @@ main(int argc, char **argv) n_tx_queue = MAX_TX_QUEUE_PER_PORT; printf("Creating queues: nb_rxq=%d nb_txq=%u... ", nb_rx_queue, (unsigned)n_tx_queue ); + + ret = rte_eth_dev_info_get(portid, &dev_info); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "Error during getting device (port %u) info: %s\n", + portid, strerror(-ret)); + + ret = config_port_max_pkt_len(&local_port_conf, &dev_info); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "Invalid max packet length: %u (port %u)\n", + max_pkt_len, portid); + + if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) + local_port_conf.txmode.offloads |= + RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; + + local_port_conf.rx_adv_conf.rss_conf.rss_hf &= + dev_info.flow_type_rss_offloads; + + if (dev_info.max_rx_queues == 1) + local_port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_NONE; + + if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != + port_conf.rx_adv_conf.rss_conf.rss_hf) { + printf("Port %u modified RSS hash function based on hardware support," + "requested:%#"PRIx64" configured:%#"PRIx64"\n", + portid, + port_conf.rx_adv_conf.rss_conf.rss_hf, + local_port_conf.rx_adv_conf.rss_conf.rss_hf); + } + ret = rte_eth_dev_configure(portid, nb_rx_queue, - (uint16_t)n_tx_queue, &port_conf); + (uint16_t)n_tx_queue, &local_port_conf); if (ret < 0) rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n", ret, portid); - rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); + ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, + &nb_txd); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Cannot adjust number of descriptors: err=%d, " + "port=%d\n", ret, portid); + + ret = rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Cannot get MAC address: err=%d, port=%d\n", + ret, portid); + print_ethaddr(" Address:", &ports_eth_addr[portid]); printf(", "); print_ethaddr("Destination:", - (const struct ether_addr *)&dest_eth_addr[portid]); + (const struct rte_ether_addr *)&dest_eth_addr[portid]); printf(", "); /* * prepare src MACs for each port. */ - ether_addr_copy(&ports_eth_addr[portid], - (struct ether_addr *)(val_eth + portid) + 1); + rte_ether_addr_copy(&ports_eth_addr[portid], + (struct rte_ether_addr *)(val_eth + portid) + 1); /* init memory */ - ret = init_mem(NB_MBUF); + if (!per_port_pool) { + /* portid = 0; this is *not* signifying the first port, + * rather, it signifies that portid is ignored. + */ + ret = init_mem(0, NB_MBUF(nb_ports)); + } else { + ret = init_mem(portid, NB_MBUF(1)); + } if (ret < 0) rte_exit(EXIT_FAILURE, "init_mem failed\n"); @@ -899,10 +1296,8 @@ main(int argc, char **argv) printf("txq=%u,%d,%d ", lcore_id, queueid, socketid); fflush(stdout); - rte_eth_dev_info_get(portid, &dev_info); txconf = &dev_info.default_txconf; - if (port_conf.rxmode.jumbo_frame) - txconf->txq_flags = 0; + txconf->offloads = local_port_conf.txmode.offloads; ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd, socketid, txconf); if (ret < 0) @@ -914,12 +1309,10 @@ main(int argc, char **argv) qconf->tx_queue_id[portid] = queueid; queueid++; - qconf->n_tx_port = nb_tx_port; qconf->tx_port_id[qconf->n_tx_port] = portid; + qconf->n_tx_port++; } printf("\n"); - - nb_tx_port++; } for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { @@ -930,6 +1323,8 @@ main(int argc, char **argv) fflush(stdout); /* init RX queues */ for(queue = 0; queue < qconf->n_rx_queue; ++queue) { + struct rte_eth_rxconf rxq_conf; + portid = qconf->rx_queue_list[queue].port_id; queueid = qconf->rx_queue_list[queue].queue_id; @@ -942,21 +1337,179 @@ main(int argc, char **argv) printf("rxq=%d,%d,%d ", portid, queueid, socketid); fflush(stdout); - ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd, - socketid, - NULL, - pktmbuf_pool[socketid]); + ret = rte_eth_dev_info_get(portid, &dev_info); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "Error during getting device (port %u) info: %s\n", + portid, strerror(-ret)); + + rxq_conf = dev_info.default_rxconf; + rxq_conf.offloads = port_conf.rxmode.offloads; + if (!per_port_pool) + ret = rte_eth_rx_queue_setup(portid, queueid, + nb_rxd, socketid, + &rxq_conf, + pktmbuf_pool[0][socketid]); + else + ret = rte_eth_rx_queue_setup(portid, queueid, + nb_rxd, socketid, + &rxq_conf, + pktmbuf_pool[portid][socketid]); if (ret < 0) rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d, port=%d\n", ret, portid); } } +} - printf("\n"); +static inline int +l3fwd_service_enable(uint32_t service_id) +{ + uint8_t min_service_count = UINT8_MAX; + uint32_t slcore_array[RTE_MAX_LCORE]; + unsigned int slcore = 0; + uint8_t service_count; + int32_t slcore_count; + + if (!rte_service_lcore_count()) + return -ENOENT; + + slcore_count = rte_service_lcore_list(slcore_array, RTE_MAX_LCORE); + if (slcore_count < 0) + return -ENOENT; + /* Get the core which has least number of services running. */ + while (slcore_count--) { + /* Reset default mapping */ + if (rte_service_map_lcore_set(service_id, + slcore_array[slcore_count], 0) != 0) + return -ENOENT; + service_count = rte_service_lcore_count_services( + slcore_array[slcore_count]); + if (service_count < min_service_count) { + slcore = slcore_array[slcore_count]; + min_service_count = service_count; + } + } + if (rte_service_map_lcore_set(service_id, slcore, 1)) + return -ENOENT; + rte_service_lcore_start(slcore); + + return 0; +} + +static void +l3fwd_event_service_setup(void) +{ + struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); + struct rte_event_dev_info evdev_info; + uint32_t service_id, caps; + int ret, i; + + rte_event_dev_info_get(evt_rsrc->event_d_id, &evdev_info); + if (!(evdev_info.event_dev_cap & RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED)) { + ret = rte_event_dev_service_id_get(evt_rsrc->event_d_id, + &service_id); + if (ret != -ESRCH && ret != 0) + rte_exit(EXIT_FAILURE, + "Error in starting eventdev service\n"); + l3fwd_service_enable(service_id); + } + + for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) { + ret = rte_event_eth_rx_adapter_caps_get(evt_rsrc->event_d_id, + evt_rsrc->rx_adptr.rx_adptr[i], &caps); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Failed to get Rx adapter[%d] caps\n", + evt_rsrc->rx_adptr.rx_adptr[i]); + ret = rte_event_eth_rx_adapter_service_id_get( + evt_rsrc->event_d_id, + &service_id); + if (ret != -ESRCH && ret != 0) + rte_exit(EXIT_FAILURE, + "Error in starting Rx adapter[%d] service\n", + evt_rsrc->rx_adptr.rx_adptr[i]); + l3fwd_service_enable(service_id); + } + + for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) { + ret = rte_event_eth_tx_adapter_caps_get(evt_rsrc->event_d_id, + evt_rsrc->tx_adptr.tx_adptr[i], &caps); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Failed to get Rx adapter[%d] caps\n", + evt_rsrc->tx_adptr.tx_adptr[i]); + ret = rte_event_eth_tx_adapter_service_id_get( + evt_rsrc->event_d_id, + &service_id); + if (ret != -ESRCH && ret != 0) + rte_exit(EXIT_FAILURE, + "Error in starting Rx adapter[%d] service\n", + evt_rsrc->tx_adptr.tx_adptr[i]); + l3fwd_service_enable(service_id); + } +} + +int +main(int argc, char **argv) +{ + struct l3fwd_event_resources *evt_rsrc; + struct lcore_conf *qconf; + uint16_t queueid, portid; + unsigned int lcore_id; + uint8_t queue; + int i, ret; + + /* init EAL */ + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); + argc -= ret; + argv += ret; + + force_quit = false; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + /* pre-init dst MACs for all ports to 02:00:00:00:00:xx */ + for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { + dest_eth_addr[portid] = + RTE_ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40); + *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; + } + + evt_rsrc = l3fwd_get_eventdev_rsrc(); + /* parse application arguments (after the EAL ones) */ + ret = parse_args(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n"); + + /* Setup function pointers for lookup method. */ + setup_l3fwd_lookup_tables(); + + /* Add the config file rules */ + l3fwd_lkp.read_config_files(); + + evt_rsrc->per_port_pool = per_port_pool; + evt_rsrc->pkt_pool = pktmbuf_pool; + evt_rsrc->vec_pool = vector_pool; + evt_rsrc->port_mask = enabled_port_mask; + /* Configure eventdev parameters if user has requested */ + if (evt_rsrc->enabled) { + l3fwd_event_resource_setup(&port_conf); + if (lookup_mode == L3FWD_LOOKUP_EM) + l3fwd_lkp.main_loop = evt_rsrc->ops.em_event_loop; + else if (lookup_mode == L3FWD_LOOKUP_FIB) + l3fwd_lkp.main_loop = evt_rsrc->ops.fib_event_loop; + else + l3fwd_lkp.main_loop = evt_rsrc->ops.lpm_event_loop; + l3fwd_event_service_setup(); + } else + l3fwd_poll_resource_setup(); /* start ports */ - for (portid = 0; portid < nb_ports; portid++) { + RTE_ETH_FOREACH_DEV(portid) { if ((enabled_port_mask & (1 << portid)) == 0) { continue; } @@ -973,31 +1526,83 @@ main(int argc, char **argv) * to itself through 2 cross-connected ports of the * target machine. */ - if (promiscuous_on) - rte_eth_promiscuous_enable(portid); + if (promiscuous_on) { + ret = rte_eth_promiscuous_enable(portid); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "rte_eth_promiscuous_enable: err=%s, port=%u\n", + rte_strerror(-ret), portid); + } } - check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask); + printf("\n"); + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + qconf = &lcore_conf[lcore_id]; + for (queue = 0; queue < qconf->n_rx_queue; ++queue) { + portid = qconf->rx_queue_list[queue].port_id; + queueid = qconf->rx_queue_list[queue].queue_id; + if (prepare_ptype_parser(portid, queueid) == 0) + rte_exit(EXIT_FAILURE, "ptype check fails\n"); + } + } + + check_all_ports_link_status(enabled_port_mask); ret = 0; /* launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore_id) { - if (rte_eal_wait_lcore(lcore_id) < 0) { - ret = -1; - break; + rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MAIN); + if (evt_rsrc->enabled) { + for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) + rte_event_eth_rx_adapter_stop( + evt_rsrc->rx_adptr.rx_adptr[i]); + for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) + rte_event_eth_tx_adapter_stop( + evt_rsrc->tx_adptr.tx_adptr[i]); + + RTE_ETH_FOREACH_DEV(portid) { + if ((enabled_port_mask & (1 << portid)) == 0) + continue; + ret = rte_eth_dev_stop(portid); + if (ret != 0) + printf("rte_eth_dev_stop: err=%d, port=%u\n", + ret, portid); } - } - /* stop ports */ - for (portid = 0; portid < nb_ports; portid++) { - if ((enabled_port_mask & (1 << portid)) == 0) - continue; - printf("Closing port %d...", portid); - rte_eth_dev_stop(portid); - rte_eth_dev_close(portid); - printf(" Done\n"); + rte_eal_mp_wait_lcore(); + RTE_ETH_FOREACH_DEV(portid) { + if ((enabled_port_mask & (1 << portid)) == 0) + continue; + rte_eth_dev_close(portid); + } + + rte_event_dev_stop(evt_rsrc->event_d_id); + rte_event_dev_close(evt_rsrc->event_d_id); + + } else { + rte_eal_mp_wait_lcore(); + + RTE_ETH_FOREACH_DEV(portid) { + if ((enabled_port_mask & (1 << portid)) == 0) + continue; + printf("Closing port %d...", portid); + ret = rte_eth_dev_stop(portid); + if (ret != 0) + printf("rte_eth_dev_stop: err=%d, port=%u\n", + ret, portid); + rte_eth_dev_close(portid); + printf(" Done\n"); + } } + + /* clean up config file routes */ + l3fwd_lkp.free_routes(); + + /* clean up the EAL */ + rte_eal_cleanup(); + printf("Bye...\n"); return ret;