13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 36bb97df5SIntel */ 46bb97df5SIntel 56bb97df5SIntel #include <stdint.h> 66bb97df5SIntel #include <sys/queue.h> 76bb97df5SIntel #include <stdlib.h> 86bb97df5SIntel #include <string.h> 96bb97df5SIntel #include <stdio.h> 106bb97df5SIntel #include <assert.h> 116bb97df5SIntel #include <errno.h> 126bb97df5SIntel #include <signal.h> 136bb97df5SIntel #include <stdarg.h> 146bb97df5SIntel #include <inttypes.h> 156bb97df5SIntel #include <getopt.h> 166bb97df5SIntel 176bb97df5SIntel #include <rte_common.h> 186bb97df5SIntel #include <rte_log.h> 196bb97df5SIntel #include <rte_memory.h> 206bb97df5SIntel #include <rte_memcpy.h> 216bb97df5SIntel #include <rte_eal.h> 226bb97df5SIntel #include <rte_launch.h> 236bb97df5SIntel #include <rte_atomic.h> 246bb97df5SIntel #include <rte_cycles.h> 256bb97df5SIntel #include <rte_prefetch.h> 266bb97df5SIntel #include <rte_lcore.h> 276bb97df5SIntel #include <rte_per_lcore.h> 286bb97df5SIntel #include <rte_branch_prediction.h> 296bb97df5SIntel #include <rte_interrupts.h> 306bb97df5SIntel #include <rte_random.h> 316bb97df5SIntel #include <rte_debug.h> 326bb97df5SIntel #include <rte_ether.h> 336bb97df5SIntel #include <rte_ethdev.h> 346bb97df5SIntel #include <rte_mempool.h> 356bb97df5SIntel #include <rte_mbuf.h> 366bb97df5SIntel 37e4363e81SXutao Sun #define MAX_QUEUES 1024 386bb97df5SIntel /* 39e4363e81SXutao Sun * 1024 queues require to meet the needs of a large number of vmdq_pools. 40e4363e81SXutao Sun * (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port. 416bb97df5SIntel */ 42e4363e81SXutao Sun #define NUM_MBUFS_PER_PORT (MAX_QUEUES * RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, \ 43e4363e81SXutao Sun RTE_TEST_TX_DESC_DEFAULT)) 446bb97df5SIntel #define MBUF_CACHE_SIZE 64 456bb97df5SIntel 466bb97df5SIntel #define MAX_PKT_BURST 32 476bb97df5SIntel 486bb97df5SIntel /* 496bb97df5SIntel * Configurable number of RX/TX ring descriptors 506bb97df5SIntel */ 51867a6c66SKevin Laatz #define RTE_TEST_RX_DESC_DEFAULT 1024 52867a6c66SKevin Laatz #define RTE_TEST_TX_DESC_DEFAULT 1024 536bb97df5SIntel 546bb97df5SIntel #define INVALID_PORT_ID 0xFF 556bb97df5SIntel 566bb97df5SIntel /* mask of enabled ports */ 57b30eb1d2SHuawei Xie static uint32_t enabled_port_mask; 586bb97df5SIntel 596bb97df5SIntel /* number of pools (if user does not specify any, 8 by default */ 606bb97df5SIntel static uint32_t num_queues = 8; 616bb97df5SIntel static uint32_t num_pools = 8; 626bb97df5SIntel 636bb97df5SIntel /* empty vmdq configuration structure. Filled in programatically */ 646bb97df5SIntel static const struct rte_eth_conf vmdq_conf_default = { 656bb97df5SIntel .rxmode = { 666bb97df5SIntel .mq_mode = ETH_MQ_RX_VMDQ_ONLY, 676bb97df5SIntel .split_hdr_size = 0, 686bb97df5SIntel }, 696bb97df5SIntel 706bb97df5SIntel .txmode = { 716bb97df5SIntel .mq_mode = ETH_MQ_TX_NONE, 726bb97df5SIntel }, 736bb97df5SIntel .rx_adv_conf = { 746bb97df5SIntel /* 756bb97df5SIntel * should be overridden separately in code with 766bb97df5SIntel * appropriate values 776bb97df5SIntel */ 786bb97df5SIntel .vmdq_rx_conf = { 796bb97df5SIntel .nb_queue_pools = ETH_8_POOLS, 806bb97df5SIntel .enable_default_pool = 0, 816bb97df5SIntel .default_pool = 0, 826bb97df5SIntel .nb_pool_maps = 0, 836bb97df5SIntel .pool_map = {{0, 0},}, 846bb97df5SIntel }, 856bb97df5SIntel }, 866bb97df5SIntel }; 876bb97df5SIntel 886bb97df5SIntel static unsigned lcore_ids[RTE_MAX_LCORE]; 8947523597SZhiyong Yang static uint16_t ports[RTE_MAX_ETHPORTS]; 90b30eb1d2SHuawei Xie static unsigned num_ports; /**< The number of ports specified in command line */ 916bb97df5SIntel 926bb97df5SIntel /* array used for printing out statistics */ 936bb97df5SIntel volatile unsigned long rxPackets[MAX_QUEUES] = {0}; 946bb97df5SIntel 956bb97df5SIntel const uint16_t vlan_tags[] = { 966bb97df5SIntel 0, 1, 2, 3, 4, 5, 6, 7, 976bb97df5SIntel 8, 9, 10, 11, 12, 13, 14, 15, 986bb97df5SIntel 16, 17, 18, 19, 20, 21, 22, 23, 996bb97df5SIntel 24, 25, 26, 27, 28, 29, 30, 31, 1006bb97df5SIntel 32, 33, 34, 35, 36, 37, 38, 39, 1016bb97df5SIntel 40, 41, 42, 43, 44, 45, 46, 47, 1026bb97df5SIntel 48, 49, 50, 51, 52, 53, 54, 55, 1036bb97df5SIntel 56, 57, 58, 59, 60, 61, 62, 63, 1046bb97df5SIntel }; 1052a13a5a0SHuawei Xie const uint16_t num_vlans = RTE_DIM(vlan_tags); 1062a13a5a0SHuawei Xie static uint16_t num_pf_queues, num_vmdq_queues; 1072a13a5a0SHuawei Xie static uint16_t vmdq_pool_base, vmdq_queue_base; 1082a13a5a0SHuawei Xie /* pool mac addr template, pool mac addr is like: 52 54 00 12 port# pool# */ 1096d13ea8eSOlivier Matz static struct rte_ether_addr pool_addr_template = { 1102a13a5a0SHuawei Xie .addr_bytes = {0x52, 0x54, 0x00, 0x12, 0x00, 0x00} 1112a13a5a0SHuawei Xie }; 1126bb97df5SIntel 1136bb97df5SIntel /* ethernet addresses of ports */ 1146d13ea8eSOlivier Matz static struct rte_ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS]; 1156bb97df5SIntel 1166bb97df5SIntel #define MAX_QUEUE_NUM_10G 128 1176bb97df5SIntel #define MAX_QUEUE_NUM_1G 8 1186bb97df5SIntel #define MAX_POOL_MAP_NUM_10G 64 1196bb97df5SIntel #define MAX_POOL_MAP_NUM_1G 32 1206bb97df5SIntel #define MAX_POOL_NUM_10G 64 1216bb97df5SIntel #define MAX_POOL_NUM_1G 8 122b30eb1d2SHuawei Xie /* 123b30eb1d2SHuawei Xie * Builds up the correct configuration for vmdq based on the vlan tags array 124b30eb1d2SHuawei Xie * given above, and determine the queue number and pool map number according to 125b30eb1d2SHuawei Xie * valid pool number 126b30eb1d2SHuawei Xie */ 1276bb97df5SIntel static inline int 1286bb97df5SIntel get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools) 1296bb97df5SIntel { 1306bb97df5SIntel struct rte_eth_vmdq_rx_conf conf; 1316bb97df5SIntel unsigned i; 1326bb97df5SIntel 1336bb97df5SIntel conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 1342a13a5a0SHuawei Xie conf.nb_pool_maps = num_pools; 1356bb97df5SIntel conf.enable_default_pool = 0; 1366bb97df5SIntel conf.default_pool = 0; /* set explicit value, even if not used */ 1376bb97df5SIntel 1386bb97df5SIntel for (i = 0; i < conf.nb_pool_maps; i++) { 1396bb97df5SIntel conf.pool_map[i].vlan_id = vlan_tags[i]; 1406bb97df5SIntel conf.pool_map[i].pools = (1UL << (i % num_pools)); 1416bb97df5SIntel } 1426bb97df5SIntel 1436bb97df5SIntel (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf))); 1446bb97df5SIntel (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf, 1456bb97df5SIntel sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf))); 1466bb97df5SIntel return 0; 1476bb97df5SIntel } 1486bb97df5SIntel 1496bb97df5SIntel /* 1506bb97df5SIntel * Initialises a given port using global settings and with the rx buffers 1516bb97df5SIntel * coming from the mbuf_pool passed as parameter 1526bb97df5SIntel */ 1536bb97df5SIntel static inline int 15447523597SZhiyong Yang port_init(uint16_t port, struct rte_mempool *mbuf_pool) 1556bb97df5SIntel { 1566bb97df5SIntel struct rte_eth_dev_info dev_info; 15781f7ecd9SPablo de Lara struct rte_eth_rxconf *rxconf; 1588dd0befeSShahaf Shuler struct rte_eth_txconf *txconf; 1596bb97df5SIntel struct rte_eth_conf port_conf; 1602a13a5a0SHuawei Xie uint16_t rxRings, txRings; 16160efb44fSRoman Zhukov uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT; 16260efb44fSRoman Zhukov uint16_t txRingSize = RTE_TEST_TX_DESC_DEFAULT; 1636bb97df5SIntel int retval; 1646bb97df5SIntel uint16_t q; 1652a13a5a0SHuawei Xie uint16_t queues_per_pool; 1666bb97df5SIntel uint32_t max_nb_pools; 1676bb97df5SIntel 168b30eb1d2SHuawei Xie /* 169b30eb1d2SHuawei Xie * The max pool number from dev_info will be used to validate the pool 170b30eb1d2SHuawei Xie * number specified in cmd line 171b30eb1d2SHuawei Xie */ 172*089e5ed7SIvan Ilchenko retval = rte_eth_dev_info_get(port, &dev_info); 173*089e5ed7SIvan Ilchenko if (retval != 0) { 174*089e5ed7SIvan Ilchenko printf("Error during getting device (port %u) info: %s\n", 175*089e5ed7SIvan Ilchenko port, strerror(-retval)); 176*089e5ed7SIvan Ilchenko return retval; 177*089e5ed7SIvan Ilchenko } 178*089e5ed7SIvan Ilchenko 1796bb97df5SIntel max_nb_pools = (uint32_t)dev_info.max_vmdq_pools; 1802a13a5a0SHuawei Xie /* 1812a13a5a0SHuawei Xie * We allow to process part of VMDQ pools specified by num_pools in 1822a13a5a0SHuawei Xie * command line. 1832a13a5a0SHuawei Xie */ 1842a13a5a0SHuawei Xie if (num_pools > max_nb_pools) { 1852a13a5a0SHuawei Xie printf("num_pools %d >max_nb_pools %d\n", 1862a13a5a0SHuawei Xie num_pools, max_nb_pools); 1872a13a5a0SHuawei Xie return -1; 1882a13a5a0SHuawei Xie } 1892a13a5a0SHuawei Xie retval = get_eth_conf(&port_conf, max_nb_pools); 1906bb97df5SIntel if (retval < 0) 1916bb97df5SIntel return retval; 1926bb97df5SIntel 1932a13a5a0SHuawei Xie /* 1942a13a5a0SHuawei Xie * NIC queues are divided into pf queues and vmdq queues. 1952a13a5a0SHuawei Xie */ 1962a13a5a0SHuawei Xie /* There is assumption here all ports have the same configuration! */ 1972a13a5a0SHuawei Xie num_pf_queues = dev_info.max_rx_queues - dev_info.vmdq_queue_num; 1982a13a5a0SHuawei Xie queues_per_pool = dev_info.vmdq_queue_num / dev_info.max_vmdq_pools; 1992a13a5a0SHuawei Xie num_vmdq_queues = num_pools * queues_per_pool; 2002a13a5a0SHuawei Xie num_queues = num_pf_queues + num_vmdq_queues; 2012a13a5a0SHuawei Xie vmdq_queue_base = dev_info.vmdq_queue_base; 2022a13a5a0SHuawei Xie vmdq_pool_base = dev_info.vmdq_pool_base; 2036bb97df5SIntel 2042a13a5a0SHuawei Xie printf("pf queue num: %u, configured vmdq pool num: %u," 2052a13a5a0SHuawei Xie " each vmdq pool has %u queues\n", 2062a13a5a0SHuawei Xie num_pf_queues, num_pools, queues_per_pool); 2072a13a5a0SHuawei Xie printf("vmdq queue base: %d pool base %d\n", 2082a13a5a0SHuawei Xie vmdq_queue_base, vmdq_pool_base); 209a9dbe180SThomas Monjalon if (!rte_eth_dev_is_valid_port(port)) 210b30eb1d2SHuawei Xie return -1; 2116bb97df5SIntel 2122a13a5a0SHuawei Xie /* 2132a13a5a0SHuawei Xie * Though in this example, we only receive packets from the first queue 2142a13a5a0SHuawei Xie * of each pool and send packets through first rte_lcore_count() tx 2152a13a5a0SHuawei Xie * queues of vmdq queues, all queues including pf queues are setup. 2162a13a5a0SHuawei Xie * This is because VMDQ queues doesn't always start from zero, and the 2172a13a5a0SHuawei Xie * PMD layer doesn't support selectively initialising part of rx/tx 2182a13a5a0SHuawei Xie * queues. 2192a13a5a0SHuawei Xie */ 2202a13a5a0SHuawei Xie rxRings = (uint16_t)dev_info.max_rx_queues; 2212a13a5a0SHuawei Xie txRings = (uint16_t)dev_info.max_tx_queues; 2228dd0befeSShahaf Shuler 223*089e5ed7SIvan Ilchenko retval = rte_eth_dev_info_get(port, &dev_info); 224*089e5ed7SIvan Ilchenko if (retval != 0) { 225*089e5ed7SIvan Ilchenko printf("Error during getting device (port %u) info: %s\n", 226*089e5ed7SIvan Ilchenko port, strerror(-retval)); 227*089e5ed7SIvan Ilchenko return retval; 228*089e5ed7SIvan Ilchenko } 229*089e5ed7SIvan Ilchenko 2308dd0befeSShahaf Shuler if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 2318dd0befeSShahaf Shuler port_conf.txmode.offloads |= 2328dd0befeSShahaf Shuler DEV_TX_OFFLOAD_MBUF_FAST_FREE; 2336bb97df5SIntel retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf); 2346bb97df5SIntel if (retval != 0) 2356bb97df5SIntel return retval; 2366bb97df5SIntel 23760efb44fSRoman Zhukov retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &rxRingSize, 23860efb44fSRoman Zhukov &txRingSize); 23960efb44fSRoman Zhukov if (retval != 0) 24060efb44fSRoman Zhukov return retval; 24160efb44fSRoman Zhukov if (RTE_MAX(rxRingSize, txRingSize) > RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, 24260efb44fSRoman Zhukov RTE_TEST_TX_DESC_DEFAULT)) { 24360efb44fSRoman Zhukov printf("Mbuf pool has an insufficient size for port %u.\n", 24460efb44fSRoman Zhukov port); 24560efb44fSRoman Zhukov return -1; 24660efb44fSRoman Zhukov } 24760efb44fSRoman Zhukov 24881f7ecd9SPablo de Lara rxconf = &dev_info.default_rxconf; 24981f7ecd9SPablo de Lara rxconf->rx_drop_en = 1; 2508dd0befeSShahaf Shuler txconf = &dev_info.default_txconf; 2518dd0befeSShahaf Shuler txconf->offloads = port_conf.txmode.offloads; 2526bb97df5SIntel for (q = 0; q < rxRings; q++) { 2536bb97df5SIntel retval = rte_eth_rx_queue_setup(port, q, rxRingSize, 25481f7ecd9SPablo de Lara rte_eth_dev_socket_id(port), 25581f7ecd9SPablo de Lara rxconf, 2566bb97df5SIntel mbuf_pool); 2572a13a5a0SHuawei Xie if (retval < 0) { 2582a13a5a0SHuawei Xie printf("initialise rx queue %d failed\n", q); 2596bb97df5SIntel return retval; 2606bb97df5SIntel } 2612a13a5a0SHuawei Xie } 2626bb97df5SIntel 2636bb97df5SIntel for (q = 0; q < txRings; q++) { 2646bb97df5SIntel retval = rte_eth_tx_queue_setup(port, q, txRingSize, 26581f7ecd9SPablo de Lara rte_eth_dev_socket_id(port), 2668dd0befeSShahaf Shuler txconf); 2672a13a5a0SHuawei Xie if (retval < 0) { 2682a13a5a0SHuawei Xie printf("initialise tx queue %d failed\n", q); 2696bb97df5SIntel return retval; 2706bb97df5SIntel } 2712a13a5a0SHuawei Xie } 2726bb97df5SIntel 2736bb97df5SIntel retval = rte_eth_dev_start(port); 2742a13a5a0SHuawei Xie if (retval < 0) { 2752a13a5a0SHuawei Xie printf("port %d start failed\n", port); 2766bb97df5SIntel return retval; 2772a13a5a0SHuawei Xie } 2786bb97df5SIntel 2796bb97df5SIntel rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]); 2806bb97df5SIntel printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 2816bb97df5SIntel " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 2826bb97df5SIntel (unsigned)port, 2836bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[0], 2846bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[1], 2856bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[2], 2866bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[3], 2876bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[4], 2886bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[5]); 2896bb97df5SIntel 2902a13a5a0SHuawei Xie /* 2912a13a5a0SHuawei Xie * Set mac for each pool. 2922a13a5a0SHuawei Xie * There is no default mac for the pools in i40. 2932a13a5a0SHuawei Xie * Removes this after i40e fixes this issue. 2942a13a5a0SHuawei Xie */ 2952a13a5a0SHuawei Xie for (q = 0; q < num_pools; q++) { 2966d13ea8eSOlivier Matz struct rte_ether_addr mac; 2972a13a5a0SHuawei Xie mac = pool_addr_template; 2982a13a5a0SHuawei Xie mac.addr_bytes[4] = port; 2992a13a5a0SHuawei Xie mac.addr_bytes[5] = q; 3002a13a5a0SHuawei Xie printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n", 3012a13a5a0SHuawei Xie port, q, 3022a13a5a0SHuawei Xie mac.addr_bytes[0], mac.addr_bytes[1], 3032a13a5a0SHuawei Xie mac.addr_bytes[2], mac.addr_bytes[3], 3042a13a5a0SHuawei Xie mac.addr_bytes[4], mac.addr_bytes[5]); 3052a13a5a0SHuawei Xie retval = rte_eth_dev_mac_addr_add(port, &mac, 3062a13a5a0SHuawei Xie q + vmdq_pool_base); 3072a13a5a0SHuawei Xie if (retval) { 3082a13a5a0SHuawei Xie printf("mac addr add failed at pool %d\n", q); 3092a13a5a0SHuawei Xie return retval; 3102a13a5a0SHuawei Xie } 3112a13a5a0SHuawei Xie } 3122a13a5a0SHuawei Xie 3136bb97df5SIntel return 0; 3146bb97df5SIntel } 3156bb97df5SIntel 3166bb97df5SIntel /* Check num_pools parameter and set it if OK*/ 3176bb97df5SIntel static int 3186bb97df5SIntel vmdq_parse_num_pools(const char *q_arg) 3196bb97df5SIntel { 3206bb97df5SIntel char *end = NULL; 3216bb97df5SIntel int n; 3226bb97df5SIntel 3236bb97df5SIntel /* parse number string */ 3246bb97df5SIntel n = strtol(q_arg, &end, 10); 3256bb97df5SIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 3266bb97df5SIntel return -1; 3276bb97df5SIntel 3282a13a5a0SHuawei Xie if (num_pools > num_vlans) { 3292a13a5a0SHuawei Xie printf("num_pools %d > num_vlans %d\n", num_pools, num_vlans); 3302a13a5a0SHuawei Xie return -1; 3312a13a5a0SHuawei Xie } 3322a13a5a0SHuawei Xie 3336bb97df5SIntel num_pools = n; 3346bb97df5SIntel 3356bb97df5SIntel return 0; 3366bb97df5SIntel } 3376bb97df5SIntel 3386bb97df5SIntel 3396bb97df5SIntel static int 3406bb97df5SIntel parse_portmask(const char *portmask) 3416bb97df5SIntel { 3426bb97df5SIntel char *end = NULL; 3436bb97df5SIntel unsigned long pm; 3446bb97df5SIntel 3456bb97df5SIntel /* parse hexadecimal string */ 3466bb97df5SIntel pm = strtoul(portmask, &end, 16); 3476bb97df5SIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 3486bb97df5SIntel return -1; 3496bb97df5SIntel 3506bb97df5SIntel if (pm == 0) 3516bb97df5SIntel return -1; 3526bb97df5SIntel 3536bb97df5SIntel return pm; 3546bb97df5SIntel } 3556bb97df5SIntel 3566bb97df5SIntel /* Display usage */ 3576bb97df5SIntel static void 3586bb97df5SIntel vmdq_usage(const char *prgname) 3596bb97df5SIntel { 3606bb97df5SIntel printf("%s [EAL options] -- -p PORTMASK]\n" 3616bb97df5SIntel " --nb-pools NP: number of pools\n", 3626bb97df5SIntel prgname); 3636bb97df5SIntel } 3646bb97df5SIntel 3656bb97df5SIntel /* Parse the argument (num_pools) given in the command line of the application */ 3666bb97df5SIntel static int 3676bb97df5SIntel vmdq_parse_args(int argc, char **argv) 3686bb97df5SIntel { 3696bb97df5SIntel int opt; 3706bb97df5SIntel int option_index; 3716bb97df5SIntel unsigned i; 3726bb97df5SIntel const char *prgname = argv[0]; 3736bb97df5SIntel static struct option long_option[] = { 3746bb97df5SIntel {"nb-pools", required_argument, NULL, 0}, 3756bb97df5SIntel {NULL, 0, 0, 0} 3766bb97df5SIntel }; 3776bb97df5SIntel 3786bb97df5SIntel /* Parse command line */ 379b30eb1d2SHuawei Xie while ((opt = getopt_long(argc, argv, "p:", long_option, 380b30eb1d2SHuawei Xie &option_index)) != EOF) { 3816bb97df5SIntel switch (opt) { 3826bb97df5SIntel /* portmask */ 3836bb97df5SIntel case 'p': 3846bb97df5SIntel enabled_port_mask = parse_portmask(optarg); 3856bb97df5SIntel if (enabled_port_mask == 0) { 3866bb97df5SIntel printf("invalid portmask\n"); 3876bb97df5SIntel vmdq_usage(prgname); 3886bb97df5SIntel return -1; 3896bb97df5SIntel } 3906bb97df5SIntel break; 3916bb97df5SIntel case 0: 3926bb97df5SIntel if (vmdq_parse_num_pools(optarg) == -1) { 3936bb97df5SIntel printf("invalid number of pools\n"); 3946bb97df5SIntel vmdq_usage(prgname); 3956bb97df5SIntel return -1; 3966bb97df5SIntel } 3976bb97df5SIntel break; 3986bb97df5SIntel 3996bb97df5SIntel default: 4006bb97df5SIntel vmdq_usage(prgname); 4016bb97df5SIntel return -1; 4026bb97df5SIntel } 4036bb97df5SIntel } 4046bb97df5SIntel 4056bb97df5SIntel for (i = 0; i < RTE_MAX_ETHPORTS; i++) { 4066bb97df5SIntel if (enabled_port_mask & (1 << i)) 4076bb97df5SIntel ports[num_ports++] = (uint8_t)i; 4086bb97df5SIntel } 4096bb97df5SIntel 4106bb97df5SIntel if (num_ports < 2 || num_ports % 2) { 4116bb97df5SIntel printf("Current enabled port number is %u," 4126bb97df5SIntel "but it should be even and at least 2\n", num_ports); 4136bb97df5SIntel return -1; 4146bb97df5SIntel } 4156bb97df5SIntel 4166bb97df5SIntel return 0; 4176bb97df5SIntel } 4186bb97df5SIntel 4196bb97df5SIntel static void 4206bb97df5SIntel update_mac_address(struct rte_mbuf *m, unsigned dst_port) 4216bb97df5SIntel { 4226d13ea8eSOlivier Matz struct rte_ether_hdr *eth; 4236bb97df5SIntel void *tmp; 4246bb97df5SIntel 4256d13ea8eSOlivier Matz eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); 4266bb97df5SIntel 4276bb97df5SIntel /* 02:00:00:00:00:xx */ 4286bb97df5SIntel tmp = ð->d_addr.addr_bytes[0]; 4296bb97df5SIntel *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 4306bb97df5SIntel 4316bb97df5SIntel /* src addr */ 432538da7a1SOlivier Matz rte_ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr); 4336bb97df5SIntel } 4346bb97df5SIntel 4356bb97df5SIntel /* When we receive a HUP signal, print out our stats */ 4366bb97df5SIntel static void 4376bb97df5SIntel sighup_handler(int signum) 4386bb97df5SIntel { 4396bb97df5SIntel unsigned q; 4406bb97df5SIntel for (q = 0; q < num_queues; q++) { 4416bb97df5SIntel if (q % (num_queues/num_pools) == 0) 4426bb97df5SIntel printf("\nPool %u: ", q/(num_queues/num_pools)); 4436bb97df5SIntel printf("%lu ", rxPackets[q]); 4446bb97df5SIntel } 4456bb97df5SIntel printf("\nFinished handling signal %d\n", signum); 4466bb97df5SIntel } 4476bb97df5SIntel 4486bb97df5SIntel /* 4496bb97df5SIntel * Main thread that does the work, reading from INPUT_PORT 4506bb97df5SIntel * and writing to OUTPUT_PORT 4516bb97df5SIntel */ 45213c4ebd6SBruce Richardson static int 4536bb97df5SIntel lcore_main(__attribute__((__unused__)) void *dummy) 4546bb97df5SIntel { 4556bb97df5SIntel const uint16_t lcore_id = (uint16_t)rte_lcore_id(); 4566bb97df5SIntel const uint16_t num_cores = (uint16_t)rte_lcore_count(); 4576bb97df5SIntel uint16_t core_id = 0; 4586bb97df5SIntel uint16_t startQueue, endQueue; 4596bb97df5SIntel uint16_t q, i, p; 4602a13a5a0SHuawei Xie const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores); 4616bb97df5SIntel 4626bb97df5SIntel for (i = 0; i < num_cores; i++) 4636bb97df5SIntel if (lcore_ids[i] == lcore_id) { 4646bb97df5SIntel core_id = i; 4656bb97df5SIntel break; 4666bb97df5SIntel } 4676bb97df5SIntel 4686bb97df5SIntel if (remainder != 0) { 4696bb97df5SIntel if (core_id < remainder) { 4702a13a5a0SHuawei Xie startQueue = (uint16_t)(core_id * 4712a13a5a0SHuawei Xie (num_vmdq_queues / num_cores + 1)); 4722a13a5a0SHuawei Xie endQueue = (uint16_t)(startQueue + 4732a13a5a0SHuawei Xie (num_vmdq_queues / num_cores) + 1); 4746bb97df5SIntel } else { 4752a13a5a0SHuawei Xie startQueue = (uint16_t)(core_id * 4762a13a5a0SHuawei Xie (num_vmdq_queues / num_cores) + 4772a13a5a0SHuawei Xie remainder); 4782a13a5a0SHuawei Xie endQueue = (uint16_t)(startQueue + 4792a13a5a0SHuawei Xie (num_vmdq_queues / num_cores)); 4806bb97df5SIntel } 4816bb97df5SIntel } else { 4822a13a5a0SHuawei Xie startQueue = (uint16_t)(core_id * 4832a13a5a0SHuawei Xie (num_vmdq_queues / num_cores)); 4842a13a5a0SHuawei Xie endQueue = (uint16_t)(startQueue + 4852a13a5a0SHuawei Xie (num_vmdq_queues / num_cores)); 4866bb97df5SIntel } 4876bb97df5SIntel 4882a13a5a0SHuawei Xie /* vmdq queue idx doesn't always start from zero.*/ 4892a13a5a0SHuawei Xie startQueue += vmdq_queue_base; 4902a13a5a0SHuawei Xie endQueue += vmdq_queue_base; 4916bb97df5SIntel printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id, 4926bb97df5SIntel (unsigned)lcore_id, startQueue, endQueue - 1); 4936bb97df5SIntel 49413c4ebd6SBruce Richardson if (startQueue == endQueue) { 49513c4ebd6SBruce Richardson printf("lcore %u has nothing to do\n", lcore_id); 496b30eb1d2SHuawei Xie return 0; 49713c4ebd6SBruce Richardson } 49813c4ebd6SBruce Richardson 4996bb97df5SIntel for (;;) { 5006bb97df5SIntel struct rte_mbuf *buf[MAX_PKT_BURST]; 5016bb97df5SIntel const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]); 5026bb97df5SIntel 5036bb97df5SIntel for (p = 0; p < num_ports; p++) { 5046bb97df5SIntel const uint8_t sport = ports[p]; 505b30eb1d2SHuawei Xie /* 0 <-> 1, 2 <-> 3 etc */ 506b30eb1d2SHuawei Xie const uint8_t dport = ports[p ^ 1]; 5076bb97df5SIntel if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID)) 5086bb97df5SIntel continue; 5096bb97df5SIntel 5106bb97df5SIntel for (q = startQueue; q < endQueue; q++) { 5116bb97df5SIntel const uint16_t rxCount = rte_eth_rx_burst(sport, 5126bb97df5SIntel q, buf, buf_size); 5136bb97df5SIntel 5146bb97df5SIntel if (unlikely(rxCount == 0)) 5156bb97df5SIntel continue; 5166bb97df5SIntel 5176bb97df5SIntel rxPackets[q] += rxCount; 5186bb97df5SIntel 5196bb97df5SIntel for (i = 0; i < rxCount; i++) 5206bb97df5SIntel update_mac_address(buf[i], dport); 5216bb97df5SIntel 5226bb97df5SIntel const uint16_t txCount = rte_eth_tx_burst(dport, 5232a13a5a0SHuawei Xie vmdq_queue_base + core_id, 5242a13a5a0SHuawei Xie buf, 5252a13a5a0SHuawei Xie rxCount); 5266bb97df5SIntel 5276bb97df5SIntel if (txCount != rxCount) { 5286bb97df5SIntel for (i = txCount; i < rxCount; i++) 5296bb97df5SIntel rte_pktmbuf_free(buf[i]); 5306bb97df5SIntel } 5316bb97df5SIntel } 5326bb97df5SIntel } 5336bb97df5SIntel } 5346bb97df5SIntel } 5356bb97df5SIntel 5366bb97df5SIntel /* 5376bb97df5SIntel * Update the global var NUM_PORTS and array PORTS according to system ports number 5386bb97df5SIntel * and return valid ports number 5396bb97df5SIntel */ 5406bb97df5SIntel static unsigned check_ports_num(unsigned nb_ports) 5416bb97df5SIntel { 5426bb97df5SIntel unsigned valid_num_ports = num_ports; 5436bb97df5SIntel unsigned portid; 5446bb97df5SIntel 5456bb97df5SIntel if (num_ports > nb_ports) { 5466bb97df5SIntel printf("\nSpecified port number(%u) exceeds total system port number(%u)\n", 5476bb97df5SIntel num_ports, nb_ports); 5486bb97df5SIntel num_ports = nb_ports; 5496bb97df5SIntel } 5506bb97df5SIntel 5516bb97df5SIntel for (portid = 0; portid < num_ports; portid++) { 552a9dbe180SThomas Monjalon if (!rte_eth_dev_is_valid_port(ports[portid])) { 553a9dbe180SThomas Monjalon printf("\nSpecified port ID(%u) is not valid\n", 554a9dbe180SThomas Monjalon ports[portid]); 5556bb97df5SIntel ports[portid] = INVALID_PORT_ID; 5566bb97df5SIntel valid_num_ports--; 5576bb97df5SIntel } 5586bb97df5SIntel } 5596bb97df5SIntel return valid_num_ports; 5606bb97df5SIntel } 5616bb97df5SIntel 5626bb97df5SIntel /* Main function, does initialisation and calls the per-lcore functions */ 5636bb97df5SIntel int 56498a16481SDavid Marchand main(int argc, char *argv[]) 5656bb97df5SIntel { 5666bb97df5SIntel struct rte_mempool *mbuf_pool; 5676bb97df5SIntel unsigned lcore_id, core_id = 0; 5686bb97df5SIntel int ret; 5696bb97df5SIntel unsigned nb_ports, valid_num_ports; 57047523597SZhiyong Yang uint16_t portid; 5716bb97df5SIntel 5726bb97df5SIntel signal(SIGHUP, sighup_handler); 5736bb97df5SIntel 5746bb97df5SIntel /* init EAL */ 5756bb97df5SIntel ret = rte_eal_init(argc, argv); 5766bb97df5SIntel if (ret < 0) 5776bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 5786bb97df5SIntel argc -= ret; 5796bb97df5SIntel argv += ret; 5806bb97df5SIntel 5816bb97df5SIntel /* parse app arguments */ 5826bb97df5SIntel ret = vmdq_parse_args(argc, argv); 5836bb97df5SIntel if (ret < 0) 5846bb97df5SIntel rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n"); 5856bb97df5SIntel 5866bb97df5SIntel for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) 5876bb97df5SIntel if (rte_lcore_is_enabled(lcore_id)) 5886bb97df5SIntel lcore_ids[core_id++] = lcore_id; 5896bb97df5SIntel 5906bb97df5SIntel if (rte_lcore_count() > RTE_MAX_LCORE) 5916bb97df5SIntel rte_exit(EXIT_FAILURE, "Not enough cores\n"); 5926bb97df5SIntel 593d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail(); 5946bb97df5SIntel 5956bb97df5SIntel /* 5966bb97df5SIntel * Update the global var NUM_PORTS and global array PORTS 5976bb97df5SIntel * and get value of var VALID_NUM_PORTS according to system ports number 5986bb97df5SIntel */ 5996bb97df5SIntel valid_num_ports = check_ports_num(nb_ports); 6006bb97df5SIntel 6016bb97df5SIntel if (valid_num_ports < 2 || valid_num_ports % 2) { 6026bb97df5SIntel printf("Current valid ports number is %u\n", valid_num_ports); 6036bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n"); 6046bb97df5SIntel } 6056bb97df5SIntel 606ea0c20eaSOlivier Matz mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 607ea0c20eaSOlivier Matz NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE, 608824cb29cSKonstantin Ananyev 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 6096bb97df5SIntel if (mbuf_pool == NULL) 6106bb97df5SIntel rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 6116bb97df5SIntel 6126bb97df5SIntel /* initialize all ports */ 6138728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid) { 6146bb97df5SIntel /* skip ports that are not enabled */ 6156bb97df5SIntel if ((enabled_port_mask & (1 << portid)) == 0) { 6166bb97df5SIntel printf("\nSkipping disabled port %d\n", portid); 6176bb97df5SIntel continue; 6186bb97df5SIntel } 6196bb97df5SIntel if (port_init(portid, mbuf_pool) != 0) 6206bb97df5SIntel rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n"); 6216bb97df5SIntel } 6226bb97df5SIntel 6236bb97df5SIntel /* call lcore_main() on every lcore */ 6246bb97df5SIntel rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER); 6256bb97df5SIntel RTE_LCORE_FOREACH_SLAVE(lcore_id) { 6266bb97df5SIntel if (rte_eal_wait_lcore(lcore_id) < 0) 6276bb97df5SIntel return -1; 6286bb97df5SIntel } 6296bb97df5SIntel 6306bb97df5SIntel return 0; 6316bb97df5SIntel } 632