1*6bb97df5SIntel /*- 2*6bb97df5SIntel * BSD LICENSE 3*6bb97df5SIntel * 4*6bb97df5SIntel * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. 5*6bb97df5SIntel * All rights reserved. 6*6bb97df5SIntel * 7*6bb97df5SIntel * Redistribution and use in source and binary forms, with or without 8*6bb97df5SIntel * modification, are permitted provided that the following conditions 9*6bb97df5SIntel * are met: 10*6bb97df5SIntel * 11*6bb97df5SIntel * * Redistributions of source code must retain the above copyright 12*6bb97df5SIntel * notice, this list of conditions and the following disclaimer. 13*6bb97df5SIntel * * Redistributions in binary form must reproduce the above copyright 14*6bb97df5SIntel * notice, this list of conditions and the following disclaimer in 15*6bb97df5SIntel * the documentation and/or other materials provided with the 16*6bb97df5SIntel * distribution. 17*6bb97df5SIntel * * Neither the name of Intel Corporation nor the names of its 18*6bb97df5SIntel * contributors may be used to endorse or promote products derived 19*6bb97df5SIntel * from this software without specific prior written permission. 20*6bb97df5SIntel * 21*6bb97df5SIntel * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*6bb97df5SIntel * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*6bb97df5SIntel * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24*6bb97df5SIntel * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25*6bb97df5SIntel * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26*6bb97df5SIntel * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27*6bb97df5SIntel * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*6bb97df5SIntel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29*6bb97df5SIntel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30*6bb97df5SIntel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31*6bb97df5SIntel * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*6bb97df5SIntel */ 33*6bb97df5SIntel 34*6bb97df5SIntel #include <stdint.h> 35*6bb97df5SIntel #include <sys/queue.h> 36*6bb97df5SIntel #include <stdlib.h> 37*6bb97df5SIntel #include <string.h> 38*6bb97df5SIntel #include <stdio.h> 39*6bb97df5SIntel #include <assert.h> 40*6bb97df5SIntel #include <errno.h> 41*6bb97df5SIntel #include <signal.h> 42*6bb97df5SIntel #include <stdarg.h> 43*6bb97df5SIntel #include <inttypes.h> 44*6bb97df5SIntel #include <getopt.h> 45*6bb97df5SIntel 46*6bb97df5SIntel #include <rte_common.h> 47*6bb97df5SIntel #include <rte_log.h> 48*6bb97df5SIntel #include <rte_memory.h> 49*6bb97df5SIntel #include <rte_memcpy.h> 50*6bb97df5SIntel #include <rte_memzone.h> 51*6bb97df5SIntel #include <rte_tailq.h> 52*6bb97df5SIntel #include <rte_eal.h> 53*6bb97df5SIntel #include <rte_per_lcore.h> 54*6bb97df5SIntel #include <rte_launch.h> 55*6bb97df5SIntel #include <rte_atomic.h> 56*6bb97df5SIntel #include <rte_cycles.h> 57*6bb97df5SIntel #include <rte_prefetch.h> 58*6bb97df5SIntel #include <rte_lcore.h> 59*6bb97df5SIntel #include <rte_per_lcore.h> 60*6bb97df5SIntel #include <rte_branch_prediction.h> 61*6bb97df5SIntel #include <rte_interrupts.h> 62*6bb97df5SIntel #include <rte_pci.h> 63*6bb97df5SIntel #include <rte_random.h> 64*6bb97df5SIntel #include <rte_debug.h> 65*6bb97df5SIntel #include <rte_ether.h> 66*6bb97df5SIntel #include <rte_ethdev.h> 67*6bb97df5SIntel #include <rte_ring.h> 68*6bb97df5SIntel #include <rte_log.h> 69*6bb97df5SIntel #include <rte_mempool.h> 70*6bb97df5SIntel #include <rte_mbuf.h> 71*6bb97df5SIntel #include <rte_memcpy.h> 72*6bb97df5SIntel 73*6bb97df5SIntel #include "main.h" 74*6bb97df5SIntel 75*6bb97df5SIntel #define MAX_QUEUES 128 76*6bb97df5SIntel /* 77*6bb97df5SIntel * For 10 GbE, 128 queues require roughly 78*6bb97df5SIntel * 128*512 (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port. 79*6bb97df5SIntel */ 80*6bb97df5SIntel #define NUM_MBUFS_PER_PORT (128*512) 81*6bb97df5SIntel #define MBUF_CACHE_SIZE 64 82*6bb97df5SIntel #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 83*6bb97df5SIntel 84*6bb97df5SIntel /* 85*6bb97df5SIntel * RX and TX Prefetch, Host, and Write-back threshold values should be 86*6bb97df5SIntel * carefully set for optimal performance. Consult the network 87*6bb97df5SIntel * controller's datasheet and supporting DPDK documentation for guidance 88*6bb97df5SIntel * on how these parameters should be set. 89*6bb97df5SIntel */ 90*6bb97df5SIntel #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ 91*6bb97df5SIntel #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */ 92*6bb97df5SIntel #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */ 93*6bb97df5SIntel 94*6bb97df5SIntel /* 95*6bb97df5SIntel * These default values are optimized for use with the Intel(R) 82599 10 GbE 96*6bb97df5SIntel * Controller and the DPDK ixgbe PMD. Consider using other values for other 97*6bb97df5SIntel * network controllers and/or network drivers. 98*6bb97df5SIntel */ 99*6bb97df5SIntel #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */ 100*6bb97df5SIntel #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ 101*6bb97df5SIntel #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ 102*6bb97df5SIntel 103*6bb97df5SIntel #define MAX_PKT_BURST 32 104*6bb97df5SIntel 105*6bb97df5SIntel /* 106*6bb97df5SIntel * Configurable number of RX/TX ring descriptors 107*6bb97df5SIntel */ 108*6bb97df5SIntel #define RTE_TEST_RX_DESC_DEFAULT 128 109*6bb97df5SIntel #define RTE_TEST_TX_DESC_DEFAULT 512 110*6bb97df5SIntel 111*6bb97df5SIntel #define INVALID_PORT_ID 0xFF 112*6bb97df5SIntel 113*6bb97df5SIntel /* mask of enabled ports */ 114*6bb97df5SIntel static uint32_t enabled_port_mask = 0; 115*6bb97df5SIntel 116*6bb97df5SIntel /* number of pools (if user does not specify any, 8 by default */ 117*6bb97df5SIntel static uint32_t num_queues = 8; 118*6bb97df5SIntel static uint32_t num_pools = 8; 119*6bb97df5SIntel 120*6bb97df5SIntel /* 121*6bb97df5SIntel * RX and TX Prefetch, Host, and Write-back threshold values should be 122*6bb97df5SIntel * carefully set for optimal performance. Consult the network 123*6bb97df5SIntel * controller's datasheet and supporting DPDK documentation for guidance 124*6bb97df5SIntel * on how these parameters should be set. 125*6bb97df5SIntel */ 126*6bb97df5SIntel /* Default configuration for rx and tx thresholds etc. */ 127*6bb97df5SIntel static const struct rte_eth_rxconf rx_conf_default = { 128*6bb97df5SIntel .rx_thresh = { 129*6bb97df5SIntel .pthresh = RX_PTHRESH, 130*6bb97df5SIntel .hthresh = RX_HTHRESH, 131*6bb97df5SIntel .wthresh = RX_WTHRESH, 132*6bb97df5SIntel }, 133*6bb97df5SIntel }; 134*6bb97df5SIntel 135*6bb97df5SIntel /* 136*6bb97df5SIntel * These default values are optimized for use with the Intel(R) 82599 10 GbE 137*6bb97df5SIntel * Controller and the DPDK ixgbe/igb PMD. Consider using other values for other 138*6bb97df5SIntel * network controllers and/or network drivers. 139*6bb97df5SIntel */ 140*6bb97df5SIntel static const struct rte_eth_txconf tx_conf_default = { 141*6bb97df5SIntel .tx_thresh = { 142*6bb97df5SIntel .pthresh = TX_PTHRESH, 143*6bb97df5SIntel .hthresh = TX_HTHRESH, 144*6bb97df5SIntel .wthresh = TX_WTHRESH, 145*6bb97df5SIntel }, 146*6bb97df5SIntel .tx_free_thresh = 0, /* Use PMD default values */ 147*6bb97df5SIntel .tx_rs_thresh = 0, /* Use PMD default values */ 148*6bb97df5SIntel }; 149*6bb97df5SIntel 150*6bb97df5SIntel /* empty vmdq configuration structure. Filled in programatically */ 151*6bb97df5SIntel static const struct rte_eth_conf vmdq_conf_default = { 152*6bb97df5SIntel .rxmode = { 153*6bb97df5SIntel .mq_mode = ETH_MQ_RX_VMDQ_ONLY, 154*6bb97df5SIntel .split_hdr_size = 0, 155*6bb97df5SIntel .header_split = 0, /**< Header Split disabled */ 156*6bb97df5SIntel .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 157*6bb97df5SIntel .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 158*6bb97df5SIntel .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 159*6bb97df5SIntel }, 160*6bb97df5SIntel 161*6bb97df5SIntel .txmode = { 162*6bb97df5SIntel .mq_mode = ETH_MQ_TX_NONE, 163*6bb97df5SIntel }, 164*6bb97df5SIntel .rx_adv_conf = { 165*6bb97df5SIntel /* 166*6bb97df5SIntel * should be overridden separately in code with 167*6bb97df5SIntel * appropriate values 168*6bb97df5SIntel */ 169*6bb97df5SIntel .vmdq_rx_conf = { 170*6bb97df5SIntel .nb_queue_pools = ETH_8_POOLS, 171*6bb97df5SIntel .enable_default_pool = 0, 172*6bb97df5SIntel .default_pool = 0, 173*6bb97df5SIntel .nb_pool_maps = 0, 174*6bb97df5SIntel .pool_map = {{0, 0},}, 175*6bb97df5SIntel }, 176*6bb97df5SIntel }, 177*6bb97df5SIntel }; 178*6bb97df5SIntel 179*6bb97df5SIntel static unsigned lcore_ids[RTE_MAX_LCORE]; 180*6bb97df5SIntel static uint8_t ports[RTE_MAX_ETHPORTS]; 181*6bb97df5SIntel static unsigned num_ports = 0; /**< The number of ports specified in command line */ 182*6bb97df5SIntel 183*6bb97df5SIntel /* array used for printing out statistics */ 184*6bb97df5SIntel volatile unsigned long rxPackets[ MAX_QUEUES ] = {0}; 185*6bb97df5SIntel 186*6bb97df5SIntel const uint16_t vlan_tags[] = { 187*6bb97df5SIntel 0, 1, 2, 3, 4, 5, 6, 7, 188*6bb97df5SIntel 8, 9, 10, 11, 12, 13, 14, 15, 189*6bb97df5SIntel 16, 17, 18, 19, 20, 21, 22, 23, 190*6bb97df5SIntel 24, 25, 26, 27, 28, 29, 30, 31, 191*6bb97df5SIntel 32, 33, 34, 35, 36, 37, 38, 39, 192*6bb97df5SIntel 40, 41, 42, 43, 44, 45, 46, 47, 193*6bb97df5SIntel 48, 49, 50, 51, 52, 53, 54, 55, 194*6bb97df5SIntel 56, 57, 58, 59, 60, 61, 62, 63, 195*6bb97df5SIntel }; 196*6bb97df5SIntel 197*6bb97df5SIntel /* ethernet addresses of ports */ 198*6bb97df5SIntel static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS]; 199*6bb97df5SIntel 200*6bb97df5SIntel #define MAX_QUEUE_NUM_10G 128 201*6bb97df5SIntel #define MAX_QUEUE_NUM_1G 8 202*6bb97df5SIntel #define MAX_POOL_MAP_NUM_10G 64 203*6bb97df5SIntel #define MAX_POOL_MAP_NUM_1G 32 204*6bb97df5SIntel #define MAX_POOL_NUM_10G 64 205*6bb97df5SIntel #define MAX_POOL_NUM_1G 8 206*6bb97df5SIntel /* Builds up the correct configuration for vmdq based on the vlan tags array 207*6bb97df5SIntel * given above, and determine the queue number and pool map number according to valid pool number */ 208*6bb97df5SIntel static inline int 209*6bb97df5SIntel get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools) 210*6bb97df5SIntel { 211*6bb97df5SIntel struct rte_eth_vmdq_rx_conf conf; 212*6bb97df5SIntel unsigned i; 213*6bb97df5SIntel 214*6bb97df5SIntel conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 215*6bb97df5SIntel conf.enable_default_pool = 0; 216*6bb97df5SIntel conf.default_pool = 0; /* set explicit value, even if not used */ 217*6bb97df5SIntel switch (num_pools) { 218*6bb97df5SIntel /* For 10G NIC like 82599, 128 is valid for queue number */ 219*6bb97df5SIntel case MAX_POOL_NUM_10G: 220*6bb97df5SIntel num_queues = MAX_QUEUE_NUM_10G; 221*6bb97df5SIntel conf.nb_pool_maps = MAX_POOL_MAP_NUM_10G; 222*6bb97df5SIntel break; 223*6bb97df5SIntel /* For 1G NIC like i350, 82580 and 82576, 8 is valid for queue number */ 224*6bb97df5SIntel case MAX_POOL_NUM_1G: 225*6bb97df5SIntel num_queues = MAX_QUEUE_NUM_1G; 226*6bb97df5SIntel conf.nb_pool_maps = MAX_POOL_MAP_NUM_1G; 227*6bb97df5SIntel break; 228*6bb97df5SIntel default: 229*6bb97df5SIntel return -1; 230*6bb97df5SIntel } 231*6bb97df5SIntel 232*6bb97df5SIntel for (i = 0; i < conf.nb_pool_maps; i++){ 233*6bb97df5SIntel conf.pool_map[i].vlan_id = vlan_tags[ i ]; 234*6bb97df5SIntel conf.pool_map[i].pools = (1UL << (i % num_pools)); 235*6bb97df5SIntel } 236*6bb97df5SIntel 237*6bb97df5SIntel (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf))); 238*6bb97df5SIntel (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf, 239*6bb97df5SIntel sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf))); 240*6bb97df5SIntel return 0; 241*6bb97df5SIntel } 242*6bb97df5SIntel 243*6bb97df5SIntel /* 244*6bb97df5SIntel * Validate the pool number accrording to the max pool number gotten form dev_info 245*6bb97df5SIntel * If the pool number is invalid, give the error message and return -1 246*6bb97df5SIntel */ 247*6bb97df5SIntel static inline int 248*6bb97df5SIntel validate_num_pools(uint32_t max_nb_pools) 249*6bb97df5SIntel { 250*6bb97df5SIntel if (num_pools > max_nb_pools) { 251*6bb97df5SIntel printf("invalid number of pools\n"); 252*6bb97df5SIntel return -1; 253*6bb97df5SIntel } 254*6bb97df5SIntel 255*6bb97df5SIntel switch (max_nb_pools) { 256*6bb97df5SIntel /* For 10G NIC like 82599, 64 is valid for pool number */ 257*6bb97df5SIntel case MAX_POOL_NUM_10G: 258*6bb97df5SIntel if (num_pools != MAX_POOL_NUM_10G) { 259*6bb97df5SIntel printf("invalid number of pools\n"); 260*6bb97df5SIntel return -1; 261*6bb97df5SIntel } 262*6bb97df5SIntel break; 263*6bb97df5SIntel /* For 1G NIC like i350, 82580 and 82576, 8 is valid for pool number */ 264*6bb97df5SIntel case MAX_POOL_NUM_1G: 265*6bb97df5SIntel if (num_pools != MAX_POOL_NUM_1G) { 266*6bb97df5SIntel printf("invalid number of pools\n"); 267*6bb97df5SIntel return -1; 268*6bb97df5SIntel } 269*6bb97df5SIntel break; 270*6bb97df5SIntel default: 271*6bb97df5SIntel return -1; 272*6bb97df5SIntel } 273*6bb97df5SIntel 274*6bb97df5SIntel return 0; 275*6bb97df5SIntel } 276*6bb97df5SIntel 277*6bb97df5SIntel /* 278*6bb97df5SIntel * Initialises a given port using global settings and with the rx buffers 279*6bb97df5SIntel * coming from the mbuf_pool passed as parameter 280*6bb97df5SIntel */ 281*6bb97df5SIntel static inline int 282*6bb97df5SIntel port_init(uint8_t port, struct rte_mempool *mbuf_pool) 283*6bb97df5SIntel { 284*6bb97df5SIntel struct rte_eth_dev_info dev_info; 285*6bb97df5SIntel struct rte_eth_conf port_conf; 286*6bb97df5SIntel uint16_t rxRings, txRings = (uint16_t)rte_lcore_count(); 287*6bb97df5SIntel const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT, txRingSize = RTE_TEST_TX_DESC_DEFAULT; 288*6bb97df5SIntel int retval; 289*6bb97df5SIntel uint16_t q; 290*6bb97df5SIntel uint32_t max_nb_pools; 291*6bb97df5SIntel 292*6bb97df5SIntel /* The max pool number from dev_info will be used to validate the pool number specified in cmd line */ 293*6bb97df5SIntel rte_eth_dev_info_get (port, &dev_info); 294*6bb97df5SIntel max_nb_pools = (uint32_t)dev_info.max_vmdq_pools; 295*6bb97df5SIntel retval = validate_num_pools(max_nb_pools); 296*6bb97df5SIntel if (retval < 0) 297*6bb97df5SIntel return retval; 298*6bb97df5SIntel 299*6bb97df5SIntel retval = get_eth_conf(&port_conf, num_pools); 300*6bb97df5SIntel if (retval < 0) 301*6bb97df5SIntel return retval; 302*6bb97df5SIntel 303*6bb97df5SIntel if (port >= rte_eth_dev_count()) return -1; 304*6bb97df5SIntel 305*6bb97df5SIntel rxRings = (uint16_t)num_queues, 306*6bb97df5SIntel retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf); 307*6bb97df5SIntel if (retval != 0) 308*6bb97df5SIntel return retval; 309*6bb97df5SIntel 310*6bb97df5SIntel for (q = 0; q < rxRings; q ++) { 311*6bb97df5SIntel retval = rte_eth_rx_queue_setup(port, q, rxRingSize, 312*6bb97df5SIntel rte_eth_dev_socket_id(port), &rx_conf_default, 313*6bb97df5SIntel mbuf_pool); 314*6bb97df5SIntel if (retval < 0) 315*6bb97df5SIntel return retval; 316*6bb97df5SIntel } 317*6bb97df5SIntel 318*6bb97df5SIntel for (q = 0; q < txRings; q ++) { 319*6bb97df5SIntel retval = rte_eth_tx_queue_setup(port, q, txRingSize, 320*6bb97df5SIntel rte_eth_dev_socket_id(port), &tx_conf_default); 321*6bb97df5SIntel if (retval < 0) 322*6bb97df5SIntel return retval; 323*6bb97df5SIntel } 324*6bb97df5SIntel 325*6bb97df5SIntel retval = rte_eth_dev_start(port); 326*6bb97df5SIntel if (retval < 0) 327*6bb97df5SIntel return retval; 328*6bb97df5SIntel 329*6bb97df5SIntel rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]); 330*6bb97df5SIntel printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 331*6bb97df5SIntel " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 332*6bb97df5SIntel (unsigned)port, 333*6bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[0], 334*6bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[1], 335*6bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[2], 336*6bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[3], 337*6bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[4], 338*6bb97df5SIntel vmdq_ports_eth_addr[port].addr_bytes[5]); 339*6bb97df5SIntel 340*6bb97df5SIntel return 0; 341*6bb97df5SIntel } 342*6bb97df5SIntel 343*6bb97df5SIntel /* Check num_pools parameter and set it if OK*/ 344*6bb97df5SIntel static int 345*6bb97df5SIntel vmdq_parse_num_pools(const char *q_arg) 346*6bb97df5SIntel { 347*6bb97df5SIntel char *end = NULL; 348*6bb97df5SIntel int n; 349*6bb97df5SIntel 350*6bb97df5SIntel /* parse number string */ 351*6bb97df5SIntel n = strtol(q_arg, &end, 10); 352*6bb97df5SIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 353*6bb97df5SIntel return -1; 354*6bb97df5SIntel 355*6bb97df5SIntel num_pools = n; 356*6bb97df5SIntel 357*6bb97df5SIntel return 0; 358*6bb97df5SIntel } 359*6bb97df5SIntel 360*6bb97df5SIntel 361*6bb97df5SIntel static int 362*6bb97df5SIntel parse_portmask(const char *portmask) 363*6bb97df5SIntel { 364*6bb97df5SIntel char *end = NULL; 365*6bb97df5SIntel unsigned long pm; 366*6bb97df5SIntel 367*6bb97df5SIntel /* parse hexadecimal string */ 368*6bb97df5SIntel pm = strtoul(portmask, &end, 16); 369*6bb97df5SIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 370*6bb97df5SIntel return -1; 371*6bb97df5SIntel 372*6bb97df5SIntel if (pm == 0) 373*6bb97df5SIntel return -1; 374*6bb97df5SIntel 375*6bb97df5SIntel return pm; 376*6bb97df5SIntel } 377*6bb97df5SIntel 378*6bb97df5SIntel /* Display usage */ 379*6bb97df5SIntel static void 380*6bb97df5SIntel vmdq_usage(const char *prgname) 381*6bb97df5SIntel { 382*6bb97df5SIntel printf("%s [EAL options] -- -p PORTMASK]\n" 383*6bb97df5SIntel " --nb-pools NP: number of pools\n", 384*6bb97df5SIntel prgname); 385*6bb97df5SIntel } 386*6bb97df5SIntel 387*6bb97df5SIntel /* Parse the argument (num_pools) given in the command line of the application */ 388*6bb97df5SIntel static int 389*6bb97df5SIntel vmdq_parse_args(int argc, char **argv) 390*6bb97df5SIntel { 391*6bb97df5SIntel int opt; 392*6bb97df5SIntel int option_index; 393*6bb97df5SIntel unsigned i; 394*6bb97df5SIntel const char *prgname = argv[0]; 395*6bb97df5SIntel static struct option long_option[] = { 396*6bb97df5SIntel {"nb-pools", required_argument, NULL, 0}, 397*6bb97df5SIntel {NULL, 0, 0, 0} 398*6bb97df5SIntel }; 399*6bb97df5SIntel 400*6bb97df5SIntel /* Parse command line */ 401*6bb97df5SIntel while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) { 402*6bb97df5SIntel switch (opt) { 403*6bb97df5SIntel /* portmask */ 404*6bb97df5SIntel case 'p': 405*6bb97df5SIntel enabled_port_mask = parse_portmask(optarg); 406*6bb97df5SIntel if (enabled_port_mask == 0) { 407*6bb97df5SIntel printf("invalid portmask\n"); 408*6bb97df5SIntel vmdq_usage(prgname); 409*6bb97df5SIntel return -1; 410*6bb97df5SIntel } 411*6bb97df5SIntel break; 412*6bb97df5SIntel case 0: 413*6bb97df5SIntel if (vmdq_parse_num_pools(optarg) == -1){ 414*6bb97df5SIntel printf("invalid number of pools\n"); 415*6bb97df5SIntel vmdq_usage(prgname); 416*6bb97df5SIntel return -1; 417*6bb97df5SIntel } 418*6bb97df5SIntel break; 419*6bb97df5SIntel 420*6bb97df5SIntel default: 421*6bb97df5SIntel vmdq_usage(prgname); 422*6bb97df5SIntel return -1; 423*6bb97df5SIntel } 424*6bb97df5SIntel } 425*6bb97df5SIntel 426*6bb97df5SIntel for(i = 0; i < RTE_MAX_ETHPORTS; i++) { 427*6bb97df5SIntel if (enabled_port_mask & (1 << i)) 428*6bb97df5SIntel ports[num_ports++] = (uint8_t)i; 429*6bb97df5SIntel } 430*6bb97df5SIntel 431*6bb97df5SIntel if (num_ports < 2 || num_ports % 2) { 432*6bb97df5SIntel printf("Current enabled port number is %u," 433*6bb97df5SIntel "but it should be even and at least 2\n",num_ports); 434*6bb97df5SIntel return -1; 435*6bb97df5SIntel } 436*6bb97df5SIntel 437*6bb97df5SIntel return 0; 438*6bb97df5SIntel } 439*6bb97df5SIntel 440*6bb97df5SIntel static void 441*6bb97df5SIntel update_mac_address(struct rte_mbuf *m, unsigned dst_port) 442*6bb97df5SIntel { 443*6bb97df5SIntel struct ether_hdr *eth; 444*6bb97df5SIntel void *tmp; 445*6bb97df5SIntel 446*6bb97df5SIntel eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 447*6bb97df5SIntel 448*6bb97df5SIntel /* 02:00:00:00:00:xx */ 449*6bb97df5SIntel tmp = ð->d_addr.addr_bytes[0]; 450*6bb97df5SIntel *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 451*6bb97df5SIntel 452*6bb97df5SIntel /* src addr */ 453*6bb97df5SIntel ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr); 454*6bb97df5SIntel } 455*6bb97df5SIntel 456*6bb97df5SIntel #ifndef RTE_EXEC_ENV_BAREMETAL 457*6bb97df5SIntel /* When we receive a HUP signal, print out our stats */ 458*6bb97df5SIntel static void 459*6bb97df5SIntel sighup_handler(int signum) 460*6bb97df5SIntel { 461*6bb97df5SIntel unsigned q; 462*6bb97df5SIntel for (q = 0; q < num_queues; q ++) { 463*6bb97df5SIntel if (q % (num_queues/num_pools) == 0) 464*6bb97df5SIntel printf("\nPool %u: ", q/(num_queues/num_pools)); 465*6bb97df5SIntel printf("%lu ", rxPackets[ q ]); 466*6bb97df5SIntel } 467*6bb97df5SIntel printf("\nFinished handling signal %d\n", signum); 468*6bb97df5SIntel } 469*6bb97df5SIntel #endif 470*6bb97df5SIntel 471*6bb97df5SIntel /* 472*6bb97df5SIntel * Main thread that does the work, reading from INPUT_PORT 473*6bb97df5SIntel * and writing to OUTPUT_PORT 474*6bb97df5SIntel */ 475*6bb97df5SIntel static __attribute__((noreturn)) int 476*6bb97df5SIntel lcore_main(__attribute__((__unused__)) void* dummy) 477*6bb97df5SIntel { 478*6bb97df5SIntel const uint16_t lcore_id = (uint16_t)rte_lcore_id(); 479*6bb97df5SIntel const uint16_t num_cores = (uint16_t)rte_lcore_count(); 480*6bb97df5SIntel uint16_t core_id = 0; 481*6bb97df5SIntel uint16_t startQueue, endQueue; 482*6bb97df5SIntel uint16_t q, i, p; 483*6bb97df5SIntel const uint16_t remainder = (uint16_t)(num_queues % num_cores); 484*6bb97df5SIntel 485*6bb97df5SIntel for (i = 0; i < num_cores; i ++) 486*6bb97df5SIntel if (lcore_ids[i] == lcore_id) { 487*6bb97df5SIntel core_id = i; 488*6bb97df5SIntel break; 489*6bb97df5SIntel } 490*6bb97df5SIntel 491*6bb97df5SIntel if (remainder != 0) { 492*6bb97df5SIntel if (core_id < remainder) { 493*6bb97df5SIntel startQueue = (uint16_t)(core_id * (num_queues/num_cores + 1)); 494*6bb97df5SIntel endQueue = (uint16_t)(startQueue + (num_queues/num_cores) + 1); 495*6bb97df5SIntel } else { 496*6bb97df5SIntel startQueue = (uint16_t)(core_id * (num_queues/num_cores) + remainder); 497*6bb97df5SIntel endQueue = (uint16_t)(startQueue + (num_queues/num_cores)); 498*6bb97df5SIntel } 499*6bb97df5SIntel } else { 500*6bb97df5SIntel startQueue = (uint16_t)(core_id * (num_queues/num_cores)); 501*6bb97df5SIntel endQueue = (uint16_t)(startQueue + (num_queues/num_cores)); 502*6bb97df5SIntel } 503*6bb97df5SIntel 504*6bb97df5SIntel printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id, 505*6bb97df5SIntel (unsigned)lcore_id, startQueue, endQueue - 1); 506*6bb97df5SIntel 507*6bb97df5SIntel for (;;) { 508*6bb97df5SIntel struct rte_mbuf *buf[MAX_PKT_BURST]; 509*6bb97df5SIntel const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]); 510*6bb97df5SIntel 511*6bb97df5SIntel for (p = 0; p < num_ports; p++) { 512*6bb97df5SIntel const uint8_t sport = ports[p]; 513*6bb97df5SIntel const uint8_t dport = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */ 514*6bb97df5SIntel 515*6bb97df5SIntel if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID)) 516*6bb97df5SIntel continue; 517*6bb97df5SIntel 518*6bb97df5SIntel for (q = startQueue; q < endQueue; q++) { 519*6bb97df5SIntel const uint16_t rxCount = rte_eth_rx_burst(sport, 520*6bb97df5SIntel q, buf, buf_size); 521*6bb97df5SIntel 522*6bb97df5SIntel if (unlikely(rxCount == 0)) 523*6bb97df5SIntel continue; 524*6bb97df5SIntel 525*6bb97df5SIntel rxPackets[q] += rxCount; 526*6bb97df5SIntel 527*6bb97df5SIntel for (i = 0; i < rxCount; i++) 528*6bb97df5SIntel update_mac_address(buf[i], dport); 529*6bb97df5SIntel 530*6bb97df5SIntel const uint16_t txCount = rte_eth_tx_burst(dport, 531*6bb97df5SIntel lcore_id, buf, rxCount); 532*6bb97df5SIntel 533*6bb97df5SIntel if (txCount != rxCount) { 534*6bb97df5SIntel for (i = txCount; i < rxCount; i++) 535*6bb97df5SIntel rte_pktmbuf_free(buf[i]); 536*6bb97df5SIntel } 537*6bb97df5SIntel } 538*6bb97df5SIntel } 539*6bb97df5SIntel } 540*6bb97df5SIntel } 541*6bb97df5SIntel 542*6bb97df5SIntel /* 543*6bb97df5SIntel * Update the global var NUM_PORTS and array PORTS according to system ports number 544*6bb97df5SIntel * and return valid ports number 545*6bb97df5SIntel */ 546*6bb97df5SIntel static unsigned check_ports_num(unsigned nb_ports) 547*6bb97df5SIntel { 548*6bb97df5SIntel unsigned valid_num_ports = num_ports; 549*6bb97df5SIntel unsigned portid; 550*6bb97df5SIntel 551*6bb97df5SIntel if (num_ports > nb_ports) { 552*6bb97df5SIntel printf("\nSpecified port number(%u) exceeds total system port number(%u)\n", 553*6bb97df5SIntel num_ports, nb_ports); 554*6bb97df5SIntel num_ports = nb_ports; 555*6bb97df5SIntel } 556*6bb97df5SIntel 557*6bb97df5SIntel for (portid = 0; portid < num_ports; portid ++) { 558*6bb97df5SIntel if (ports[portid] >= nb_ports) { 559*6bb97df5SIntel printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n", 560*6bb97df5SIntel ports[portid], (nb_ports - 1)); 561*6bb97df5SIntel ports[portid] = INVALID_PORT_ID; 562*6bb97df5SIntel valid_num_ports --; 563*6bb97df5SIntel } 564*6bb97df5SIntel } 565*6bb97df5SIntel return valid_num_ports; 566*6bb97df5SIntel } 567*6bb97df5SIntel 568*6bb97df5SIntel /* Main function, does initialisation and calls the per-lcore functions */ 569*6bb97df5SIntel int 570*6bb97df5SIntel MAIN(int argc, char *argv[]) 571*6bb97df5SIntel { 572*6bb97df5SIntel struct rte_mempool *mbuf_pool; 573*6bb97df5SIntel unsigned lcore_id, core_id = 0; 574*6bb97df5SIntel int ret; 575*6bb97df5SIntel unsigned nb_ports, valid_num_ports; 576*6bb97df5SIntel uint8_t portid; 577*6bb97df5SIntel 578*6bb97df5SIntel #ifndef RTE_EXEC_ENV_BAREMETAL 579*6bb97df5SIntel signal(SIGHUP, sighup_handler); 580*6bb97df5SIntel #endif 581*6bb97df5SIntel 582*6bb97df5SIntel /* init EAL */ 583*6bb97df5SIntel ret = rte_eal_init(argc, argv); 584*6bb97df5SIntel if (ret < 0) 585*6bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 586*6bb97df5SIntel argc -= ret; 587*6bb97df5SIntel argv += ret; 588*6bb97df5SIntel 589*6bb97df5SIntel /* parse app arguments */ 590*6bb97df5SIntel ret = vmdq_parse_args(argc, argv); 591*6bb97df5SIntel if (ret < 0) 592*6bb97df5SIntel rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n"); 593*6bb97df5SIntel 594*6bb97df5SIntel if (rte_pmd_init_all() != 0 || rte_eal_pci_probe() != 0) 595*6bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n"); 596*6bb97df5SIntel 597*6bb97df5SIntel for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++) 598*6bb97df5SIntel if (rte_lcore_is_enabled(lcore_id)) 599*6bb97df5SIntel lcore_ids[core_id ++] = lcore_id; 600*6bb97df5SIntel 601*6bb97df5SIntel if (rte_lcore_count() > RTE_MAX_LCORE) 602*6bb97df5SIntel rte_exit(EXIT_FAILURE,"Not enough cores\n"); 603*6bb97df5SIntel 604*6bb97df5SIntel nb_ports = rte_eth_dev_count(); 605*6bb97df5SIntel if (nb_ports > RTE_MAX_ETHPORTS) 606*6bb97df5SIntel nb_ports = RTE_MAX_ETHPORTS; 607*6bb97df5SIntel 608*6bb97df5SIntel /* 609*6bb97df5SIntel * Update the global var NUM_PORTS and global array PORTS 610*6bb97df5SIntel * and get value of var VALID_NUM_PORTS according to system ports number 611*6bb97df5SIntel */ 612*6bb97df5SIntel valid_num_ports = check_ports_num(nb_ports); 613*6bb97df5SIntel 614*6bb97df5SIntel if (valid_num_ports < 2 || valid_num_ports % 2) { 615*6bb97df5SIntel printf("Current valid ports number is %u\n", valid_num_ports); 616*6bb97df5SIntel rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n"); 617*6bb97df5SIntel } 618*6bb97df5SIntel 619*6bb97df5SIntel mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS_PER_PORT * nb_ports, 620*6bb97df5SIntel MBUF_SIZE, MBUF_CACHE_SIZE, 621*6bb97df5SIntel sizeof(struct rte_pktmbuf_pool_private), 622*6bb97df5SIntel rte_pktmbuf_pool_init, NULL, 623*6bb97df5SIntel rte_pktmbuf_init, NULL, 624*6bb97df5SIntel rte_socket_id(), 0); 625*6bb97df5SIntel if (mbuf_pool == NULL) 626*6bb97df5SIntel rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 627*6bb97df5SIntel 628*6bb97df5SIntel /* initialize all ports */ 629*6bb97df5SIntel for (portid = 0; portid < nb_ports; portid++) { 630*6bb97df5SIntel /* skip ports that are not enabled */ 631*6bb97df5SIntel if ((enabled_port_mask & (1 << portid)) == 0) { 632*6bb97df5SIntel printf("\nSkipping disabled port %d\n", portid); 633*6bb97df5SIntel continue; 634*6bb97df5SIntel } 635*6bb97df5SIntel if (port_init(portid, mbuf_pool) != 0) 636*6bb97df5SIntel rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n"); 637*6bb97df5SIntel } 638*6bb97df5SIntel 639*6bb97df5SIntel /* call lcore_main() on every lcore */ 640*6bb97df5SIntel rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER); 641*6bb97df5SIntel RTE_LCORE_FOREACH_SLAVE(lcore_id) { 642*6bb97df5SIntel if (rte_eal_wait_lcore(lcore_id) < 0) 643*6bb97df5SIntel return -1; 644*6bb97df5SIntel } 645*6bb97df5SIntel 646*6bb97df5SIntel return 0; 647*6bb97df5SIntel } 648