16bb97df5SIntel /*- 26bb97df5SIntel * BSD LICENSE 36bb97df5SIntel * 4*e9d48c00SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 56bb97df5SIntel * All rights reserved. 66bb97df5SIntel * 76bb97df5SIntel * Redistribution and use in source and binary forms, with or without 86bb97df5SIntel * modification, are permitted provided that the following conditions 96bb97df5SIntel * are met: 106bb97df5SIntel * 116bb97df5SIntel * * Redistributions of source code must retain the above copyright 126bb97df5SIntel * notice, this list of conditions and the following disclaimer. 136bb97df5SIntel * * Redistributions in binary form must reproduce the above copyright 146bb97df5SIntel * notice, this list of conditions and the following disclaimer in 156bb97df5SIntel * the documentation and/or other materials provided with the 166bb97df5SIntel * distribution. 176bb97df5SIntel * * Neither the name of Intel Corporation nor the names of its 186bb97df5SIntel * contributors may be used to endorse or promote products derived 196bb97df5SIntel * from this software without specific prior written permission. 206bb97df5SIntel * 216bb97df5SIntel * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 226bb97df5SIntel * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 236bb97df5SIntel * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 246bb97df5SIntel * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 256bb97df5SIntel * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 266bb97df5SIntel * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 276bb97df5SIntel * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 286bb97df5SIntel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 296bb97df5SIntel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 306bb97df5SIntel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 316bb97df5SIntel * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 326bb97df5SIntel */ 336bb97df5SIntel 346bb97df5SIntel #include <stdint.h> 356bb97df5SIntel #include <sys/queue.h> 366bb97df5SIntel #include <stdlib.h> 376bb97df5SIntel #include <string.h> 386bb97df5SIntel #include <stdio.h> 396bb97df5SIntel #include <assert.h> 406bb97df5SIntel #include <errno.h> 416bb97df5SIntel #include <signal.h> 426bb97df5SIntel #include <stdarg.h> 436bb97df5SIntel #include <inttypes.h> 446bb97df5SIntel #include <getopt.h> 456bb97df5SIntel 466bb97df5SIntel #include <rte_common.h> 476bb97df5SIntel #include <rte_log.h> 486bb97df5SIntel #include <rte_memory.h> 496bb97df5SIntel #include <rte_memcpy.h> 506bb97df5SIntel #include <rte_memzone.h> 516bb97df5SIntel #include <rte_tailq.h> 526bb97df5SIntel #include <rte_eal.h> 536bb97df5SIntel #include <rte_per_lcore.h> 546bb97df5SIntel #include <rte_launch.h> 556bb97df5SIntel #include <rte_atomic.h> 566bb97df5SIntel #include <rte_cycles.h> 576bb97df5SIntel #include <rte_prefetch.h> 586bb97df5SIntel #include <rte_lcore.h> 596bb97df5SIntel #include <rte_per_lcore.h> 606bb97df5SIntel #include <rte_branch_prediction.h> 616bb97df5SIntel #include <rte_interrupts.h> 626bb97df5SIntel #include <rte_pci.h> 636bb97df5SIntel #include <rte_random.h> 646bb97df5SIntel #include <rte_debug.h> 656bb97df5SIntel #include <rte_ether.h> 666bb97df5SIntel #include <rte_ethdev.h> 676bb97df5SIntel #include <rte_ring.h> 686bb97df5SIntel #include <rte_log.h> 696bb97df5SIntel #include <rte_mempool.h> 706bb97df5SIntel #include <rte_mbuf.h> 716bb97df5SIntel #include <rte_memcpy.h> 726bb97df5SIntel 736bb97df5SIntel #include "main.h" 746bb97df5SIntel 756bb97df5SIntel #define MAX_QUEUES 128 766bb97df5SIntel /* 776bb97df5SIntel * For 10 GbE, 128 queues require roughly 786bb97df5SIntel * 128*512 (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port. 796bb97df5SIntel */ 806bb97df5SIntel #define NUM_MBUFS_PER_PORT (128*512) 816bb97df5SIntel #define MBUF_CACHE_SIZE 64 826bb97df5SIntel #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 836bb97df5SIntel 846bb97df5SIntel /* 856bb97df5SIntel * RX and TX Prefetch, Host, and Write-back threshold values should be 866bb97df5SIntel * carefully set for optimal performance. Consult the network 876bb97df5SIntel * controller's datasheet and supporting DPDK documentation for guidance 886bb97df5SIntel * on how these parameters should be set. 896bb97df5SIntel */ 906bb97df5SIntel #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ 916bb97df5SIntel #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */ 926bb97df5SIntel #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */ 936bb97df5SIntel 946bb97df5SIntel /* 956bb97df5SIntel * These default values are optimized for use with the Intel(R) 82599 10 GbE 966bb97df5SIntel * Controller and the DPDK ixgbe PMD. Consider using other values for other 976bb97df5SIntel * network controllers and/or network drivers. 986bb97df5SIntel */ 996bb97df5SIntel #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */ 1006bb97df5SIntel #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ 1016bb97df5SIntel #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ 1026bb97df5SIntel 1036bb97df5SIntel #define MAX_PKT_BURST 32 1046bb97df5SIntel 1056bb97df5SIntel /* 1066bb97df5SIntel * Configurable number of RX/TX ring descriptors 1076bb97df5SIntel */ 1086bb97df5SIntel #define RTE_TEST_RX_DESC_DEFAULT 128 1096bb97df5SIntel #define RTE_TEST_TX_DESC_DEFAULT 512 1106bb97df5SIntel 1116bb97df5SIntel #define INVALID_PORT_ID 0xFF 1126bb97df5SIntel 1136bb97df5SIntel /* mask of enabled ports */ 1146bb97df5SIntel static uint32_t enabled_port_mask = 0; 1156bb97df5SIntel 1166bb97df5SIntel /* number of pools (if user does not specify any, 8 by default */ 1176bb97df5SIntel static uint32_t num_queues = 8; 1186bb97df5SIntel static uint32_t num_pools = 8; 1196bb97df5SIntel 1206bb97df5SIntel /* 1216bb97df5SIntel * RX and TX Prefetch, Host, and Write-back threshold values should be 1226bb97df5SIntel * carefully set for optimal performance. Consult the network 1236bb97df5SIntel * controller's datasheet and supporting DPDK documentation for guidance 1246bb97df5SIntel * on how these parameters should be set. 1256bb97df5SIntel */ 1266bb97df5SIntel /* Default configuration for rx and tx thresholds etc. */ 1276bb97df5SIntel static const struct rte_eth_rxconf rx_conf_default = { 1286bb97df5SIntel .rx_thresh = { 1296bb97df5SIntel .pthresh = RX_PTHRESH, 1306bb97df5SIntel .hthresh = RX_HTHRESH, 1316bb97df5SIntel .wthresh = RX_WTHRESH, 1326bb97df5SIntel }, 1336bb97df5SIntel }; 1346bb97df5SIntel 1356bb97df5SIntel /* 1366bb97df5SIntel * These default values are optimized for use with the Intel(R) 82599 10 GbE 1376bb97df5SIntel * Controller and the DPDK ixgbe/igb PMD. Consider using other values for other 1386bb97df5SIntel * network controllers and/or network drivers. 1396bb97df5SIntel */ 1406bb97df5SIntel static const struct rte_eth_txconf tx_conf_default = { 1416bb97df5SIntel .tx_thresh = { 1426bb97df5SIntel .pthresh = TX_PTHRESH, 1436bb97df5SIntel .hthresh = TX_HTHRESH, 1446bb97df5SIntel .wthresh = TX_WTHRESH, 1456bb97df5SIntel }, 1466bb97df5SIntel .tx_free_thresh = 0, /* Use PMD default values */ 1476bb97df5SIntel .tx_rs_thresh = 0, /* Use PMD default values */ 1486bb97df5SIntel }; 1496bb97df5SIntel 1506bb97df5SIntel /* empty vmdq configuration structure. Filled in programatically */ 1516bb97df5SIntel static const struct rte_eth_conf vmdq_conf_default = { 1526bb97df5SIntel .rxmode = { 1536bb97df5SIntel .mq_mode = ETH_MQ_RX_VMDQ_ONLY, 1546bb97df5SIntel .split_hdr_size = 0, 1556bb97df5SIntel .header_split = 0, /**< Header Split disabled */ 1566bb97df5SIntel .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 1576bb97df5SIntel .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 1586bb97df5SIntel .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 1596bb97df5SIntel }, 1606bb97df5SIntel 1616bb97df5SIntel .txmode = { 1626bb97df5SIntel .mq_mode = ETH_MQ_TX_NONE, 1636bb97df5SIntel }, 1646bb97df5SIntel .rx_adv_conf = { 1656bb97df5SIntel /* 1666bb97df5SIntel * should be overridden separately in code with 1676bb97df5SIntel * appropriate values 1686bb97df5SIntel */ 1696bb97df5SIntel .vmdq_rx_conf = { 1706bb97df5SIntel .nb_queue_pools = ETH_8_POOLS, 1716bb97df5SIntel .enable_default_pool = 0, 1726bb97df5SIntel .default_pool = 0, 1736bb97df5SIntel .nb_pool_maps = 0, 1746bb97df5SIntel .pool_map = {{0, 0},}, 1756bb97df5SIntel }, 1766bb97df5SIntel }, 1776bb97df5SIntel }; 1786bb97df5SIntel 1796bb97df5SIntel static unsigned lcore_ids[RTE_MAX_LCORE]; 1806bb97df5SIntel static uint8_t ports[RTE_MAX_ETHPORTS]; 1816bb97df5SIntel static unsigned num_ports = 0; /**< The number of ports specified in command line */ 1826bb97df5SIntel 1836bb97df5SIntel /* array used for printing out statistics */ 1846bb97df5SIntel volatile unsigned long rxPackets[ MAX_QUEUES ] = {0}; 1856bb97df5SIntel 1866bb97df5SIntel const uint16_t vlan_tags[] = { 1876bb97df5SIntel 0, 1, 2, 3, 4, 5, 6, 7, 1886bb97df5SIntel 8, 9, 10, 11, 12, 13, 14, 15, 1896bb97df5SIntel 16, 17, 18, 19, 20, 21, 22, 23, 1906bb97df5SIntel 24, 25, 26, 27, 28, 29, 30, 31, 1916bb97df5SIntel 32, 33, 34, 35, 36, 37, 38, 39, 1926bb97df5SIntel 40, 41, 42, 43, 44, 45, 46, 47, 1936bb97df5SIntel 48, 49, 50, 51, 52, 53, 54, 55, 1946bb97df5SIntel 56, 57, 58, 59, 60, 61, 62, 63, 1956bb97df5SIntel }; 1966bb97df5SIntel 1976bb97df5SIntel /* ethernet addresses of ports */ 1986bb97df5SIntel static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS]; 1996bb97df5SIntel 2006bb97df5SIntel #define MAX_QUEUE_NUM_10G 128 2016bb97df5SIntel #define MAX_QUEUE_NUM_1G 8 2026bb97df5SIntel #define MAX_POOL_MAP_NUM_10G 64 2036bb97df5SIntel #define MAX_POOL_MAP_NUM_1G 32 2046bb97df5SIntel #define MAX_POOL_NUM_10G 64 2056bb97df5SIntel #define MAX_POOL_NUM_1G 8 2066bb97df5SIntel /* Builds up the correct configuration for vmdq based on the vlan tags array 2076bb97df5SIntel * given above, and determine the queue number and pool map number according to valid pool number */ 2086bb97df5SIntel static inline int 2096bb97df5SIntel get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools) 2106bb97df5SIntel { 2116bb97df5SIntel struct rte_eth_vmdq_rx_conf conf; 2126bb97df5SIntel unsigned i; 2136bb97df5SIntel 2146bb97df5SIntel conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 2156bb97df5SIntel conf.enable_default_pool = 0; 2166bb97df5SIntel conf.default_pool = 0; /* set explicit value, even if not used */ 2176bb97df5SIntel switch (num_pools) { 2186bb97df5SIntel /* For 10G NIC like 82599, 128 is valid for queue number */ 2196bb97df5SIntel case MAX_POOL_NUM_10G: 2206bb97df5SIntel num_queues = MAX_QUEUE_NUM_10G; 2216bb97df5SIntel conf.nb_pool_maps = MAX_POOL_MAP_NUM_10G; 2226bb97df5SIntel break; 2236bb97df5SIntel /* For 1G NIC like i350, 82580 and 82576, 8 is valid for queue number */ 2246bb97df5SIntel case MAX_POOL_NUM_1G: 2256bb97df5SIntel num_queues = MAX_QUEUE_NUM_1G; 2266bb97df5SIntel conf.nb_pool_maps = MAX_POOL_MAP_NUM_1G; 2276bb97df5SIntel break; 2286bb97df5SIntel default: 2296bb97df5SIntel return -1; 2306bb97df5SIntel } 2316bb97df5SIntel 2326bb97df5SIntel for (i = 0; i < conf.nb_pool_maps; i++){ 2336bb97df5SIntel conf.pool_map[i].vlan_id = vlan_tags[ i ]; 2346bb97df5SIntel conf.pool_map[i].pools = (1UL << (i % num_pools)); 2356bb97df5SIntel } 2366bb97df5SIntel 2376bb97df5SIntel (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf))); 2386bb97df5SIntel (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf, 2396bb97df5SIntel sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf))); 2406bb97df5SIntel return 0; 2416bb97df5SIntel } 2426bb97df5SIntel 2436bb97df5SIntel /* 2446bb97df5SIntel * Validate the pool number accrording to the max pool number gotten form dev_info 2456bb97df5SIntel * If the pool number is invalid, give the error message and return -1 2466bb97df5SIntel */ 2476bb97df5SIntel static inline int 2486bb97df5SIntel validate_num_pools(uint32_t max_nb_pools) 2496bb97df5SIntel { 2506bb97df5SIntel if (num_pools > max_nb_pools) { 2516bb97df5SIntel printf("invalid number of pools\n"); 2526bb97df5SIntel return -1; 2536bb97df5SIntel } 2546bb97df5SIntel 2556bb97df5SIntel switch (max_nb_pools) { 2566bb97df5SIntel /* For 10G NIC like 82599, 64 is valid for pool number */ 2576bb97df5SIntel case MAX_POOL_NUM_10G: 2586bb97df5SIntel if (num_pools != MAX_POOL_NUM_10G) { 2596bb97df5SIntel printf("invalid number of pools\n"); 2606bb97df5SIntel return -1; 2616bb97df5SIntel } 2626bb97df5SIntel break; 2636bb97df5SIntel /* For 1G NIC like i350, 82580 and 82576, 8 is valid for pool number */ 2646bb97df5SIntel case MAX_POOL_NUM_1G: 2656bb97df5SIntel if (num_pools != MAX_POOL_NUM_1G) { 2666bb97df5SIntel printf("invalid number of pools\n"); 2676bb97df5SIntel return -1; 2686bb97df5SIntel } 2696bb97df5SIntel break; 2706bb97df5SIntel default: 2716bb97df5SIntel return -1; 2726bb97df5SIntel } 2736bb97df5SIntel 2746bb97df5SIntel return 0; 2756bb97df5SIntel } 2766bb97df5SIntel 2776bb97df5SIntel /* 2786bb97df5SIntel * Initialises a given port using global settings and with the rx buffers 2796bb97df5SIntel * coming from the mbuf_pool passed as parameter 2806bb97df5SIntel */ 2816bb97df5SIntel static inline int 2826bb97df5SIntel port_init(uint8_t port, struct rte_mempool *mbuf_pool) 2836bb97df5SIntel { 2846bb97df5SIntel struct rte_eth_dev_info dev_info; 2856bb97df5SIntel struct rte_eth_conf port_conf; 2866bb97df5SIntel uint16_t rxRings, txRings = (uint16_t)rte_lcore_count(); 2876bb97df5SIntel const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT, txRingSize = RTE_TEST_TX_DESC_DEFAULT; 2886bb97df5SIntel int retval; 2896bb97df5SIntel uint16_t q; 2906bb97df5SIntel uint32_t max_nb_pools; 2916bb97df5SIntel 2926bb97df5SIntel /* The max pool number from dev_info will be used to validate the pool number specified in cmd line */ 2936bb97df5SIntel rte_eth_dev_info_get (port, &dev_info); 2946bb97df5SIntel max_nb_pools = (uint32_t)dev_info.max_vmdq_pools; 2956bb97df5SIntel retval = validate_num_pools(max_nb_pools); 2966bb97df5SIntel if (retval < 0) 2976bb97df5SIntel return retval; 2986bb97df5SIntel 2996bb97df5SIntel retval = get_eth_conf(&port_conf, num_pools); 3006bb97df5SIntel if (retval < 0) 3016bb97df5SIntel return retval; 3026bb97df5SIntel 3036bb97df5SIntel if (port >= rte_eth_dev_count()) return -1; 3046bb97df5SIntel 3056bb97df5SIntel rxRings = (uint16_t)num_queues, 3066bb97df5SIntel retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf); 3076bb97df5SIntel if (retval != 0) 3086bb97df5SIntel return retval; 3096bb97df5SIntel 3106bb97df5SIntel for (q = 0; q < rxRings; q ++) { 3116bb97df5SIntel retval = rte_eth_rx_queue_setup(port, q, rxRingSize, 3126bb97df5SIntel rte_eth_dev_socket_id(port), &rx_conf_default, 3136bb97df5SIntel mbuf_pool); 3146bb97df5SIntel if (retval < 0) 3156bb97df5SIntel return retval; 3166bb97df5SIntel } 3176bb97df5SIntel 3186bb97df5SIntel for (q = 0; q < txRings; q ++) { 3196bb97df5SIntel retval = rte_eth_tx_queue_setup(port, q, txRingSize, 3206bb97df5SIntel rte_eth_dev_socket_id(port), &tx_conf_default); 3216bb97df5SIntel if (retval < 0) 3226bb97df5SIntel return retval; 3236bb97df5SIntel } 3246bb97df5SIntel 3256bb97df5SIntel retval = rte_eth_dev_start(port); 3266bb97df5SIntel if (retval < 0) 3276bb97df5SIntel return retval; 3286bb97df5SIntel 3296bb97df5SIntel rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]); 3306bb97df5SIntel printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 3316bb97df5SIntel " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 3326bb97df5SIntel (unsigned)port, 3336bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[0], 3346bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[1], 3356bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[2], 3366bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[3], 3376bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[4], 3386bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[5]); 3396bb97df5SIntel 3406bb97df5SIntel return 0; 3416bb97df5SIntel } 3426bb97df5SIntel 3436bb97df5SIntel /* Check num_pools parameter and set it if OK*/ 3446bb97df5SIntel static int 3456bb97df5SIntel vmdq_parse_num_pools(const char *q_arg) 3466bb97df5SIntel { 3476bb97df5SIntel char *end = NULL; 3486bb97df5SIntel int n; 3496bb97df5SIntel 3506bb97df5SIntel /* parse number string */ 3516bb97df5SIntel n = strtol(q_arg, &end, 10); 3526bb97df5SIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 3536bb97df5SIntel return -1; 3546bb97df5SIntel 3556bb97df5SIntel num_pools = n; 3566bb97df5SIntel 3576bb97df5SIntel return 0; 3586bb97df5SIntel } 3596bb97df5SIntel 3606bb97df5SIntel 3616bb97df5SIntel static int 3626bb97df5SIntel parse_portmask(const char *portmask) 3636bb97df5SIntel { 3646bb97df5SIntel char *end = NULL; 3656bb97df5SIntel unsigned long pm; 3666bb97df5SIntel 3676bb97df5SIntel /* parse hexadecimal string */ 3686bb97df5SIntel pm = strtoul(portmask, &end, 16); 3696bb97df5SIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 3706bb97df5SIntel return -1; 3716bb97df5SIntel 3726bb97df5SIntel if (pm == 0) 3736bb97df5SIntel return -1; 3746bb97df5SIntel 3756bb97df5SIntel return pm; 3766bb97df5SIntel } 3776bb97df5SIntel 3786bb97df5SIntel /* Display usage */ 3796bb97df5SIntel static void 3806bb97df5SIntel vmdq_usage(const char *prgname) 3816bb97df5SIntel { 3826bb97df5SIntel printf("%s [EAL options] -- -p PORTMASK]\n" 3836bb97df5SIntel " --nb-pools NP: number of pools\n", 3846bb97df5SIntel prgname); 3856bb97df5SIntel } 3866bb97df5SIntel 3876bb97df5SIntel /* Parse the argument (num_pools) given in the command line of the application */ 3886bb97df5SIntel static int 3896bb97df5SIntel vmdq_parse_args(int argc, char **argv) 3906bb97df5SIntel { 3916bb97df5SIntel int opt; 3926bb97df5SIntel int option_index; 3936bb97df5SIntel unsigned i; 3946bb97df5SIntel const char *prgname = argv[0]; 3956bb97df5SIntel static struct option long_option[] = { 3966bb97df5SIntel {"nb-pools", required_argument, NULL, 0}, 3976bb97df5SIntel {NULL, 0, 0, 0} 3986bb97df5SIntel }; 3996bb97df5SIntel 4006bb97df5SIntel /* Parse command line */ 4016bb97df5SIntel while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) { 4026bb97df5SIntel switch (opt) { 4036bb97df5SIntel /* portmask */ 4046bb97df5SIntel case 'p': 4056bb97df5SIntel enabled_port_mask = parse_portmask(optarg); 4066bb97df5SIntel if (enabled_port_mask == 0) { 4076bb97df5SIntel printf("invalid portmask\n"); 4086bb97df5SIntel vmdq_usage(prgname); 4096bb97df5SIntel return -1; 4106bb97df5SIntel } 4116bb97df5SIntel break; 4126bb97df5SIntel case 0: 4136bb97df5SIntel if (vmdq_parse_num_pools(optarg) == -1){ 4146bb97df5SIntel printf("invalid number of pools\n"); 4156bb97df5SIntel vmdq_usage(prgname); 4166bb97df5SIntel return -1; 4176bb97df5SIntel } 4186bb97df5SIntel break; 4196bb97df5SIntel 4206bb97df5SIntel default: 4216bb97df5SIntel vmdq_usage(prgname); 4226bb97df5SIntel return -1; 4236bb97df5SIntel } 4246bb97df5SIntel } 4256bb97df5SIntel 4266bb97df5SIntel for(i = 0; i < RTE_MAX_ETHPORTS; i++) { 4276bb97df5SIntel if (enabled_port_mask & (1 << i)) 4286bb97df5SIntel ports[num_ports++] = (uint8_t)i; 4296bb97df5SIntel } 4306bb97df5SIntel 4316bb97df5SIntel if (num_ports < 2 || num_ports % 2) { 4326bb97df5SIntel printf("Current enabled port number is %u," 4336bb97df5SIntel "but it should be even and at least 2\n",num_ports); 4346bb97df5SIntel return -1; 4356bb97df5SIntel } 4366bb97df5SIntel 4376bb97df5SIntel return 0; 4386bb97df5SIntel } 4396bb97df5SIntel 4406bb97df5SIntel static void 4416bb97df5SIntel update_mac_address(struct rte_mbuf *m, unsigned dst_port) 4426bb97df5SIntel { 4436bb97df5SIntel struct ether_hdr *eth; 4446bb97df5SIntel void *tmp; 4456bb97df5SIntel 4466bb97df5SIntel eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 4476bb97df5SIntel 4486bb97df5SIntel /* 02:00:00:00:00:xx */ 4496bb97df5SIntel tmp = ð->d_addr.addr_bytes[0]; 4506bb97df5SIntel *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 4516bb97df5SIntel 4526bb97df5SIntel /* src addr */ 4536bb97df5SIntel ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr); 4546bb97df5SIntel } 4556bb97df5SIntel 4566bb97df5SIntel #ifndef RTE_EXEC_ENV_BAREMETAL 4576bb97df5SIntel /* When we receive a HUP signal, print out our stats */ 4586bb97df5SIntel static void 4596bb97df5SIntel sighup_handler(int signum) 4606bb97df5SIntel { 4616bb97df5SIntel unsigned q; 4626bb97df5SIntel for (q = 0; q < num_queues; q ++) { 4636bb97df5SIntel if (q % (num_queues/num_pools) == 0) 4646bb97df5SIntel printf("\nPool %u: ", q/(num_queues/num_pools)); 4656bb97df5SIntel printf("%lu ", rxPackets[ q ]); 4666bb97df5SIntel } 4676bb97df5SIntel printf("\nFinished handling signal %d\n", signum); 4686bb97df5SIntel } 4696bb97df5SIntel #endif 4706bb97df5SIntel 4716bb97df5SIntel /* 4726bb97df5SIntel * Main thread that does the work, reading from INPUT_PORT 4736bb97df5SIntel * and writing to OUTPUT_PORT 4746bb97df5SIntel */ 4756bb97df5SIntel static __attribute__((noreturn)) int 4766bb97df5SIntel lcore_main(__attribute__((__unused__)) void* dummy) 4776bb97df5SIntel { 4786bb97df5SIntel const uint16_t lcore_id = (uint16_t)rte_lcore_id(); 4796bb97df5SIntel const uint16_t num_cores = (uint16_t)rte_lcore_count(); 4806bb97df5SIntel uint16_t core_id = 0; 4816bb97df5SIntel uint16_t startQueue, endQueue; 4826bb97df5SIntel uint16_t q, i, p; 4836bb97df5SIntel const uint16_t remainder = (uint16_t)(num_queues % num_cores); 4846bb97df5SIntel 4856bb97df5SIntel for (i = 0; i < num_cores; i ++) 4866bb97df5SIntel if (lcore_ids[i] == lcore_id) { 4876bb97df5SIntel core_id = i; 4886bb97df5SIntel break; 4896bb97df5SIntel } 4906bb97df5SIntel 4916bb97df5SIntel if (remainder != 0) { 4926bb97df5SIntel if (core_id < remainder) { 4936bb97df5SIntel startQueue = (uint16_t)(core_id * (num_queues/num_cores + 1)); 4946bb97df5SIntel endQueue = (uint16_t)(startQueue + (num_queues/num_cores) + 1); 4956bb97df5SIntel } else { 4966bb97df5SIntel startQueue = (uint16_t)(core_id * (num_queues/num_cores) + remainder); 4976bb97df5SIntel endQueue = (uint16_t)(startQueue + (num_queues/num_cores)); 4986bb97df5SIntel } 4996bb97df5SIntel } else { 5006bb97df5SIntel startQueue = (uint16_t)(core_id * (num_queues/num_cores)); 5016bb97df5SIntel endQueue = (uint16_t)(startQueue + (num_queues/num_cores)); 5026bb97df5SIntel } 5036bb97df5SIntel 5046bb97df5SIntel printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id, 5056bb97df5SIntel (unsigned)lcore_id, startQueue, endQueue - 1); 5066bb97df5SIntel 5076bb97df5SIntel for (;;) { 5086bb97df5SIntel struct rte_mbuf *buf[MAX_PKT_BURST]; 5096bb97df5SIntel const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]); 5106bb97df5SIntel 5116bb97df5SIntel for (p = 0; p < num_ports; p++) { 5126bb97df5SIntel const uint8_t sport = ports[p]; 5136bb97df5SIntel const uint8_t dport = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */ 5146bb97df5SIntel 5156bb97df5SIntel if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID)) 5166bb97df5SIntel continue; 5176bb97df5SIntel 5186bb97df5SIntel for (q = startQueue; q < endQueue; q++) { 5196bb97df5SIntel const uint16_t rxCount = rte_eth_rx_burst(sport, 5206bb97df5SIntel q, buf, buf_size); 5216bb97df5SIntel 5226bb97df5SIntel if (unlikely(rxCount == 0)) 5236bb97df5SIntel continue; 5246bb97df5SIntel 5256bb97df5SIntel rxPackets[q] += rxCount; 5266bb97df5SIntel 5276bb97df5SIntel for (i = 0; i < rxCount; i++) 5286bb97df5SIntel update_mac_address(buf[i], dport); 5296bb97df5SIntel 5306bb97df5SIntel const uint16_t txCount = rte_eth_tx_burst(dport, 5316bb97df5SIntel lcore_id, buf, rxCount); 5326bb97df5SIntel 5336bb97df5SIntel if (txCount != rxCount) { 5346bb97df5SIntel for (i = txCount; i < rxCount; i++) 5356bb97df5SIntel rte_pktmbuf_free(buf[i]); 5366bb97df5SIntel } 5376bb97df5SIntel } 5386bb97df5SIntel } 5396bb97df5SIntel } 5406bb97df5SIntel } 5416bb97df5SIntel 5426bb97df5SIntel /* 5436bb97df5SIntel * Update the global var NUM_PORTS and array PORTS according to system ports number 5446bb97df5SIntel * and return valid ports number 5456bb97df5SIntel */ 5466bb97df5SIntel static unsigned check_ports_num(unsigned nb_ports) 5476bb97df5SIntel { 5486bb97df5SIntel unsigned valid_num_ports = num_ports; 5496bb97df5SIntel unsigned portid; 5506bb97df5SIntel 5516bb97df5SIntel if (num_ports > nb_ports) { 5526bb97df5SIntel printf("\nSpecified port number(%u) exceeds total system port number(%u)\n", 5536bb97df5SIntel num_ports, nb_ports); 5546bb97df5SIntel num_ports = nb_ports; 5556bb97df5SIntel } 5566bb97df5SIntel 5576bb97df5SIntel for (portid = 0; portid < num_ports; portid ++) { 5586bb97df5SIntel if (ports[portid] >= nb_ports) { 5596bb97df5SIntel printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n", 5606bb97df5SIntel ports[portid], (nb_ports - 1)); 5616bb97df5SIntel ports[portid] = INVALID_PORT_ID; 5626bb97df5SIntel valid_num_ports --; 5636bb97df5SIntel } 5646bb97df5SIntel } 5656bb97df5SIntel return valid_num_ports; 5666bb97df5SIntel } 5676bb97df5SIntel 5686bb97df5SIntel /* Main function, does initialisation and calls the per-lcore functions */ 5696bb97df5SIntel int 5706bb97df5SIntel MAIN(int argc, char *argv[]) 5716bb97df5SIntel { 5726bb97df5SIntel struct rte_mempool *mbuf_pool; 5736bb97df5SIntel unsigned lcore_id, core_id = 0; 5746bb97df5SIntel int ret; 5756bb97df5SIntel unsigned nb_ports, valid_num_ports; 5766bb97df5SIntel uint8_t portid; 5776bb97df5SIntel 5786bb97df5SIntel #ifndef RTE_EXEC_ENV_BAREMETAL 5796bb97df5SIntel signal(SIGHUP, sighup_handler); 5806bb97df5SIntel #endif 5816bb97df5SIntel 5826bb97df5SIntel /* init EAL */ 5836bb97df5SIntel ret = rte_eal_init(argc, argv); 5846bb97df5SIntel if (ret < 0) 5856bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 5866bb97df5SIntel argc -= ret; 5876bb97df5SIntel argv += ret; 5886bb97df5SIntel 5896bb97df5SIntel /* parse app arguments */ 5906bb97df5SIntel ret = vmdq_parse_args(argc, argv); 5916bb97df5SIntel if (ret < 0) 5926bb97df5SIntel rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n"); 5936bb97df5SIntel 5946bb97df5SIntel if (rte_pmd_init_all() != 0 || rte_eal_pci_probe() != 0) 5956bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n"); 5966bb97df5SIntel 5976bb97df5SIntel for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++) 5986bb97df5SIntel if (rte_lcore_is_enabled(lcore_id)) 5996bb97df5SIntel lcore_ids[core_id ++] = lcore_id; 6006bb97df5SIntel 6016bb97df5SIntel if (rte_lcore_count() > RTE_MAX_LCORE) 6026bb97df5SIntel rte_exit(EXIT_FAILURE,"Not enough cores\n"); 6036bb97df5SIntel 6046bb97df5SIntel nb_ports = rte_eth_dev_count(); 6056bb97df5SIntel if (nb_ports > RTE_MAX_ETHPORTS) 6066bb97df5SIntel nb_ports = RTE_MAX_ETHPORTS; 6076bb97df5SIntel 6086bb97df5SIntel /* 6096bb97df5SIntel * Update the global var NUM_PORTS and global array PORTS 6106bb97df5SIntel * and get value of var VALID_NUM_PORTS according to system ports number 6116bb97df5SIntel */ 6126bb97df5SIntel valid_num_ports = check_ports_num(nb_ports); 6136bb97df5SIntel 6146bb97df5SIntel if (valid_num_ports < 2 || valid_num_ports % 2) { 6156bb97df5SIntel printf("Current valid ports number is %u\n", valid_num_ports); 6166bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n"); 6176bb97df5SIntel } 6186bb97df5SIntel 6196bb97df5SIntel mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS_PER_PORT * nb_ports, 6206bb97df5SIntel MBUF_SIZE, MBUF_CACHE_SIZE, 6216bb97df5SIntel sizeof(struct rte_pktmbuf_pool_private), 6226bb97df5SIntel rte_pktmbuf_pool_init, NULL, 6236bb97df5SIntel rte_pktmbuf_init, NULL, 6246bb97df5SIntel rte_socket_id(), 0); 6256bb97df5SIntel if (mbuf_pool == NULL) 6266bb97df5SIntel rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 6276bb97df5SIntel 6286bb97df5SIntel /* initialize all ports */ 6296bb97df5SIntel for (portid = 0; portid < nb_ports; portid++) { 6306bb97df5SIntel /* skip ports that are not enabled */ 6316bb97df5SIntel if ((enabled_port_mask & (1 << portid)) == 0) { 6326bb97df5SIntel printf("\nSkipping disabled port %d\n", portid); 6336bb97df5SIntel continue; 6346bb97df5SIntel } 6356bb97df5SIntel if (port_init(portid, mbuf_pool) != 0) 6366bb97df5SIntel rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n"); 6376bb97df5SIntel } 6386bb97df5SIntel 6396bb97df5SIntel /* call lcore_main() on every lcore */ 6406bb97df5SIntel rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER); 6416bb97df5SIntel RTE_LCORE_FOREACH_SLAVE(lcore_id) { 6426bb97df5SIntel if (rte_eal_wait_lcore(lcore_id) < 0) 6436bb97df5SIntel return -1; 6446bb97df5SIntel } 6456bb97df5SIntel 6466bb97df5SIntel return 0; 6476bb97df5SIntel } 648