1af75078fSIntel /*- 2af75078fSIntel * BSD LICENSE 3af75078fSIntel * 4e9d48c00SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5af75078fSIntel * All rights reserved. 6af75078fSIntel * 7af75078fSIntel * Redistribution and use in source and binary forms, with or without 8af75078fSIntel * modification, are permitted provided that the following conditions 9af75078fSIntel * are met: 10af75078fSIntel * 11af75078fSIntel * * Redistributions of source code must retain the above copyright 12af75078fSIntel * notice, this list of conditions and the following disclaimer. 13af75078fSIntel * * Redistributions in binary form must reproduce the above copyright 14af75078fSIntel * notice, this list of conditions and the following disclaimer in 15af75078fSIntel * the documentation and/or other materials provided with the 16af75078fSIntel * distribution. 17af75078fSIntel * * Neither the name of Intel Corporation nor the names of its 18af75078fSIntel * contributors may be used to endorse or promote products derived 19af75078fSIntel * from this software without specific prior written permission. 20af75078fSIntel * 21af75078fSIntel * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22af75078fSIntel * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23af75078fSIntel * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24af75078fSIntel * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25af75078fSIntel * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26af75078fSIntel * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27af75078fSIntel * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28af75078fSIntel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29af75078fSIntel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30af75078fSIntel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31af75078fSIntel * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32af75078fSIntel */ 33af75078fSIntel 34af75078fSIntel #include <stdint.h> 35af75078fSIntel #include <sys/queue.h> 36af75078fSIntel #include <stdlib.h> 37af75078fSIntel #include <string.h> 38af75078fSIntel #include <stdio.h> 39af75078fSIntel #include <assert.h> 40af75078fSIntel #include <errno.h> 41af75078fSIntel #include <signal.h> 42af75078fSIntel #include <stdarg.h> 43af75078fSIntel #include <inttypes.h> 441d8d954bSIntel #include <getopt.h> 45af75078fSIntel 46af75078fSIntel #include <rte_common.h> 47af75078fSIntel #include <rte_log.h> 48af75078fSIntel #include <rte_memory.h> 49af75078fSIntel #include <rte_memcpy.h> 50af75078fSIntel #include <rte_memzone.h> 51af75078fSIntel #include <rte_eal.h> 52af75078fSIntel #include <rte_per_lcore.h> 53af75078fSIntel #include <rte_launch.h> 54af75078fSIntel #include <rte_atomic.h> 55af75078fSIntel #include <rte_cycles.h> 56af75078fSIntel #include <rte_prefetch.h> 57af75078fSIntel #include <rte_lcore.h> 58af75078fSIntel #include <rte_per_lcore.h> 59af75078fSIntel #include <rte_branch_prediction.h> 60af75078fSIntel #include <rte_interrupts.h> 61af75078fSIntel #include <rte_pci.h> 62af75078fSIntel #include <rte_random.h> 63af75078fSIntel #include <rte_debug.h> 64af75078fSIntel #include <rte_ether.h> 65af75078fSIntel #include <rte_ethdev.h> 66af75078fSIntel #include <rte_ring.h> 67af75078fSIntel #include <rte_log.h> 68af75078fSIntel #include <rte_mempool.h> 69af75078fSIntel #include <rte_mbuf.h> 70af75078fSIntel #include <rte_memcpy.h> 71af75078fSIntel 72af75078fSIntel /* basic constants used in application */ 73*8cc72f28SJingjing Wu #define MAX_QUEUES 1024 74*8cc72f28SJingjing Wu /* 75*8cc72f28SJingjing Wu * 1024 queues require to meet the needs of a large number of vmdq_pools. 76*8cc72f28SJingjing Wu * (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port. 77*8cc72f28SJingjing Wu */ 78*8cc72f28SJingjing Wu #define NUM_MBUFS_PER_PORT (MAX_QUEUES * RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, \ 79*8cc72f28SJingjing Wu RTE_TEST_TX_DESC_DEFAULT)) 80af75078fSIntel #define MBUF_CACHE_SIZE 64 81af75078fSIntel 82*8cc72f28SJingjing Wu #define MAX_PKT_BURST 32 83*8cc72f28SJingjing Wu 84*8cc72f28SJingjing Wu /* 85*8cc72f28SJingjing Wu * Configurable number of RX/TX ring descriptors 86*8cc72f28SJingjing Wu */ 87*8cc72f28SJingjing Wu #define RTE_TEST_RX_DESC_DEFAULT 128 88*8cc72f28SJingjing Wu #define RTE_TEST_TX_DESC_DEFAULT 512 89*8cc72f28SJingjing Wu 90d4f37b09SIntel #define INVALID_PORT_ID 0xFF 91d4f37b09SIntel 92d4f37b09SIntel /* mask of enabled ports */ 93*8cc72f28SJingjing Wu static uint32_t enabled_port_mask; 94*8cc72f28SJingjing Wu static uint8_t ports[RTE_MAX_ETHPORTS]; 95*8cc72f28SJingjing Wu static unsigned num_ports; 96af75078fSIntel 97*8cc72f28SJingjing Wu /* number of pools (if user does not specify any, 32 by default */ 98*8cc72f28SJingjing Wu static enum rte_eth_nb_pools num_pools = ETH_32_POOLS; 99*8cc72f28SJingjing Wu static enum rte_eth_nb_tcs num_tcs = ETH_4_TCS; 100*8cc72f28SJingjing Wu static uint16_t num_queues, num_vmdq_queues; 101*8cc72f28SJingjing Wu static uint16_t vmdq_pool_base, vmdq_queue_base; 102*8cc72f28SJingjing Wu static uint8_t rss_enable; 1031d8d954bSIntel 104af75078fSIntel /* empty vmdq+dcb configuration structure. Filled in programatically */ 105af75078fSIntel static const struct rte_eth_conf vmdq_dcb_conf_default = { 106af75078fSIntel .rxmode = { 10732e7aa0bSIntel .mq_mode = ETH_MQ_RX_VMDQ_DCB, 108af75078fSIntel .split_hdr_size = 0, 109af75078fSIntel .header_split = 0, /**< Header Split disabled */ 110af75078fSIntel .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 111af75078fSIntel .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 112af75078fSIntel .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 113af75078fSIntel }, 114af75078fSIntel .txmode = { 115*8cc72f28SJingjing Wu .mq_mode = ETH_MQ_TX_VMDQ_DCB, 116af75078fSIntel }, 117af75078fSIntel /* 118af75078fSIntel * should be overridden separately in code with 119af75078fSIntel * appropriate values 120af75078fSIntel */ 121*8cc72f28SJingjing Wu .rx_adv_conf = { 122af75078fSIntel .vmdq_dcb_conf = { 123*8cc72f28SJingjing Wu .nb_queue_pools = ETH_32_POOLS, 124af75078fSIntel .enable_default_pool = 0, 125af75078fSIntel .default_pool = 0, 126af75078fSIntel .nb_pool_maps = 0, 127af75078fSIntel .pool_map = {{0, 0},}, 128cb60ede6SJingjing Wu .dcb_tc = {0}, 129af75078fSIntel }, 130*8cc72f28SJingjing Wu .dcb_rx_conf = { 131*8cc72f28SJingjing Wu .nb_tcs = ETH_4_TCS, 132*8cc72f28SJingjing Wu /** Traffic class each UP mapped to. */ 133*8cc72f28SJingjing Wu .dcb_tc = {0}, 134*8cc72f28SJingjing Wu }, 135*8cc72f28SJingjing Wu .vmdq_rx_conf = { 136*8cc72f28SJingjing Wu .nb_queue_pools = ETH_32_POOLS, 137*8cc72f28SJingjing Wu .enable_default_pool = 0, 138*8cc72f28SJingjing Wu .default_pool = 0, 139*8cc72f28SJingjing Wu .nb_pool_maps = 0, 140*8cc72f28SJingjing Wu .pool_map = {{0, 0},}, 141*8cc72f28SJingjing Wu }, 142*8cc72f28SJingjing Wu }, 143*8cc72f28SJingjing Wu .tx_adv_conf = { 144*8cc72f28SJingjing Wu .vmdq_dcb_tx_conf = { 145*8cc72f28SJingjing Wu .nb_queue_pools = ETH_32_POOLS, 146*8cc72f28SJingjing Wu .dcb_tc = {0}, 147*8cc72f28SJingjing Wu }, 148af75078fSIntel }, 149af75078fSIntel }; 150af75078fSIntel 151af75078fSIntel /* array used for printing out statistics */ 152*8cc72f28SJingjing Wu volatile unsigned long rxPackets[MAX_QUEUES] = {0}; 153af75078fSIntel 154af75078fSIntel const uint16_t vlan_tags[] = { 155af75078fSIntel 0, 1, 2, 3, 4, 5, 6, 7, 156af75078fSIntel 8, 9, 10, 11, 12, 13, 14, 15, 157af75078fSIntel 16, 17, 18, 19, 20, 21, 22, 23, 158af75078fSIntel 24, 25, 26, 27, 28, 29, 30, 31 159af75078fSIntel }; 160af75078fSIntel 161*8cc72f28SJingjing Wu const uint16_t num_vlans = RTE_DIM(vlan_tags); 162*8cc72f28SJingjing Wu /* pool mac addr template, pool mac addr is like: 52 54 00 12 port# pool# */ 163*8cc72f28SJingjing Wu static struct ether_addr pool_addr_template = { 164*8cc72f28SJingjing Wu .addr_bytes = {0x52, 0x54, 0x00, 0x12, 0x00, 0x00} 165*8cc72f28SJingjing Wu }; 166*8cc72f28SJingjing Wu 167*8cc72f28SJingjing Wu /* ethernet addresses of ports */ 168*8cc72f28SJingjing Wu static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS]; 169*8cc72f28SJingjing Wu 170af75078fSIntel /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array 171af75078fSIntel * given above, and the number of traffic classes available for use. */ 172af75078fSIntel static inline int 173*8cc72f28SJingjing Wu get_eth_conf(struct rte_eth_conf *eth_conf) 174af75078fSIntel { 175af75078fSIntel struct rte_eth_vmdq_dcb_conf conf; 176*8cc72f28SJingjing Wu struct rte_eth_vmdq_rx_conf vmdq_conf; 177*8cc72f28SJingjing Wu struct rte_eth_dcb_rx_conf dcb_conf; 178*8cc72f28SJingjing Wu struct rte_eth_vmdq_dcb_tx_conf tx_conf; 179*8cc72f28SJingjing Wu uint8_t i; 180af75078fSIntel 181*8cc72f28SJingjing Wu conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 182*8cc72f28SJingjing Wu vmdq_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 183*8cc72f28SJingjing Wu tx_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools; 184*8cc72f28SJingjing Wu conf.nb_pool_maps = num_pools; 185*8cc72f28SJingjing Wu vmdq_conf.nb_pool_maps = num_pools; 186af75078fSIntel conf.enable_default_pool = 0; 187*8cc72f28SJingjing Wu vmdq_conf.enable_default_pool = 0; 1881d8d954bSIntel conf.default_pool = 0; /* set explicit value, even if not used */ 189*8cc72f28SJingjing Wu vmdq_conf.default_pool = 0; 190*8cc72f28SJingjing Wu 191af75078fSIntel for (i = 0; i < conf.nb_pool_maps; i++) { 192af75078fSIntel conf.pool_map[i].vlan_id = vlan_tags[i]; 193*8cc72f28SJingjing Wu vmdq_conf.pool_map[i].vlan_id = vlan_tags[i]; 194*8cc72f28SJingjing Wu conf.pool_map[i].pools = 1UL << i; 195*8cc72f28SJingjing Wu vmdq_conf.pool_map[i].pools = 1UL << i; 196af75078fSIntel } 197af75078fSIntel for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){ 198*8cc72f28SJingjing Wu conf.dcb_tc[i] = i % num_tcs; 199*8cc72f28SJingjing Wu dcb_conf.dcb_tc[i] = i % num_tcs; 200*8cc72f28SJingjing Wu tx_conf.dcb_tc[i] = i % num_tcs; 201af75078fSIntel } 202*8cc72f28SJingjing Wu dcb_conf.nb_tcs = (enum rte_eth_nb_tcs)num_tcs; 2031d8d954bSIntel (void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf))); 2041d8d954bSIntel (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_dcb_conf, &conf, 205*8cc72f28SJingjing Wu sizeof(conf))); 206*8cc72f28SJingjing Wu (void)(rte_memcpy(ð_conf->rx_adv_conf.dcb_rx_conf, &dcb_conf, 207*8cc72f28SJingjing Wu sizeof(dcb_conf))); 208*8cc72f28SJingjing Wu (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &vmdq_conf, 209*8cc72f28SJingjing Wu sizeof(vmdq_conf))); 210*8cc72f28SJingjing Wu (void)(rte_memcpy(ð_conf->tx_adv_conf.vmdq_dcb_tx_conf, &tx_conf, 211*8cc72f28SJingjing Wu sizeof(tx_conf))); 212*8cc72f28SJingjing Wu if (rss_enable) { 213*8cc72f28SJingjing Wu eth_conf->rxmode.mq_mode = ETH_MQ_RX_VMDQ_DCB_RSS; 214*8cc72f28SJingjing Wu eth_conf->rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP | 215*8cc72f28SJingjing Wu ETH_RSS_UDP | 216*8cc72f28SJingjing Wu ETH_RSS_TCP | 217*8cc72f28SJingjing Wu ETH_RSS_SCTP; 218*8cc72f28SJingjing Wu } 219af75078fSIntel return 0; 220af75078fSIntel } 221af75078fSIntel 222af75078fSIntel /* 223af75078fSIntel * Initialises a given port using global settings and with the rx buffers 224af75078fSIntel * coming from the mbuf_pool passed as parameter 225af75078fSIntel */ 226af75078fSIntel static inline int 227af75078fSIntel port_init(uint8_t port, struct rte_mempool *mbuf_pool) 228af75078fSIntel { 229*8cc72f28SJingjing Wu struct rte_eth_dev_info dev_info; 230*8cc72f28SJingjing Wu struct rte_eth_conf port_conf = {0}; 231*8cc72f28SJingjing Wu const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT; 232*8cc72f28SJingjing Wu const uint16_t txRingSize = RTE_TEST_TX_DESC_DEFAULT; 233af75078fSIntel int retval; 234af75078fSIntel uint16_t q; 235*8cc72f28SJingjing Wu uint16_t queues_per_pool; 236*8cc72f28SJingjing Wu uint32_t max_nb_pools; 237af75078fSIntel 238*8cc72f28SJingjing Wu /* 239*8cc72f28SJingjing Wu * The max pool number from dev_info will be used to validate the pool 240*8cc72f28SJingjing Wu * number specified in cmd line 241*8cc72f28SJingjing Wu */ 242*8cc72f28SJingjing Wu rte_eth_dev_info_get(port, &dev_info); 243*8cc72f28SJingjing Wu max_nb_pools = (uint32_t)dev_info.max_vmdq_pools; 244*8cc72f28SJingjing Wu /* 245*8cc72f28SJingjing Wu * We allow to process part of VMDQ pools specified by num_pools in 246*8cc72f28SJingjing Wu * command line. 247*8cc72f28SJingjing Wu */ 248*8cc72f28SJingjing Wu if (num_pools > max_nb_pools) { 249*8cc72f28SJingjing Wu printf("num_pools %d >max_nb_pools %d\n", 250*8cc72f28SJingjing Wu num_pools, max_nb_pools); 251*8cc72f28SJingjing Wu return -1; 252*8cc72f28SJingjing Wu } 253*8cc72f28SJingjing Wu 254*8cc72f28SJingjing Wu /* 255*8cc72f28SJingjing Wu * NIC queues are divided into pf queues and vmdq queues. 256*8cc72f28SJingjing Wu * There is assumption here all ports have the same configuration! 257*8cc72f28SJingjing Wu */ 258*8cc72f28SJingjing Wu vmdq_queue_base = dev_info.vmdq_queue_base; 259*8cc72f28SJingjing Wu vmdq_pool_base = dev_info.vmdq_pool_base; 260*8cc72f28SJingjing Wu printf("vmdq queue base: %d pool base %d\n", 261*8cc72f28SJingjing Wu vmdq_queue_base, vmdq_pool_base); 262*8cc72f28SJingjing Wu if (vmdq_pool_base == 0) { 263*8cc72f28SJingjing Wu num_vmdq_queues = dev_info.max_rx_queues; 264*8cc72f28SJingjing Wu num_queues = dev_info.max_rx_queues; 265*8cc72f28SJingjing Wu if (num_tcs != num_vmdq_queues / num_pools) { 266*8cc72f28SJingjing Wu printf("nb_tcs %d is invalid considering with" 267*8cc72f28SJingjing Wu " nb_pools %d, nb_tcs * nb_pools should = %d\n", 268*8cc72f28SJingjing Wu num_tcs, num_pools, num_vmdq_queues); 269*8cc72f28SJingjing Wu return -1; 270*8cc72f28SJingjing Wu } 271*8cc72f28SJingjing Wu } else { 272*8cc72f28SJingjing Wu queues_per_pool = dev_info.vmdq_queue_num / 273*8cc72f28SJingjing Wu dev_info.max_vmdq_pools; 274*8cc72f28SJingjing Wu if (num_tcs > queues_per_pool) { 275*8cc72f28SJingjing Wu printf("num_tcs %d > num of queues per pool %d\n", 276*8cc72f28SJingjing Wu num_tcs, queues_per_pool); 277*8cc72f28SJingjing Wu return -1; 278*8cc72f28SJingjing Wu } 279*8cc72f28SJingjing Wu num_vmdq_queues = num_pools * queues_per_pool; 280*8cc72f28SJingjing Wu num_queues = vmdq_queue_base + num_vmdq_queues; 281*8cc72f28SJingjing Wu printf("Configured vmdq pool num: %u," 282*8cc72f28SJingjing Wu " each vmdq pool has %u queues\n", 283*8cc72f28SJingjing Wu num_pools, queues_per_pool); 284*8cc72f28SJingjing Wu } 285*8cc72f28SJingjing Wu 286*8cc72f28SJingjing Wu if (port >= rte_eth_dev_count()) 287*8cc72f28SJingjing Wu return -1; 288*8cc72f28SJingjing Wu 289*8cc72f28SJingjing Wu retval = get_eth_conf(&port_conf); 2901d8d954bSIntel if (retval < 0) 2911d8d954bSIntel return retval; 292af75078fSIntel 293*8cc72f28SJingjing Wu /* 294*8cc72f28SJingjing Wu * Though in this example, all queues including pf queues are setup. 295*8cc72f28SJingjing Wu * This is because VMDQ queues doesn't always start from zero, and the 296*8cc72f28SJingjing Wu * PMD layer doesn't support selectively initialising part of rx/tx 297*8cc72f28SJingjing Wu * queues. 298*8cc72f28SJingjing Wu */ 299*8cc72f28SJingjing Wu retval = rte_eth_dev_configure(port, num_queues, num_queues, &port_conf); 300af75078fSIntel if (retval != 0) 301af75078fSIntel return retval; 302af75078fSIntel 303*8cc72f28SJingjing Wu for (q = 0; q < num_queues; q++) { 304af75078fSIntel retval = rte_eth_rx_queue_setup(port, q, rxRingSize, 30581f7ecd9SPablo de Lara rte_eth_dev_socket_id(port), 30681f7ecd9SPablo de Lara NULL, 307af75078fSIntel mbuf_pool); 308*8cc72f28SJingjing Wu if (retval < 0) { 309*8cc72f28SJingjing Wu printf("initialize rx queue %d failed\n", q); 310af75078fSIntel return retval; 311af75078fSIntel } 312*8cc72f28SJingjing Wu } 313af75078fSIntel 314*8cc72f28SJingjing Wu for (q = 0; q < num_queues; q++) { 315af75078fSIntel retval = rte_eth_tx_queue_setup(port, q, txRingSize, 31681f7ecd9SPablo de Lara rte_eth_dev_socket_id(port), 31781f7ecd9SPablo de Lara NULL); 318*8cc72f28SJingjing Wu if (retval < 0) { 319*8cc72f28SJingjing Wu printf("initialize tx queue %d failed\n", q); 320af75078fSIntel return retval; 321af75078fSIntel } 322*8cc72f28SJingjing Wu } 323af75078fSIntel 324af75078fSIntel retval = rte_eth_dev_start(port); 325*8cc72f28SJingjing Wu if (retval < 0) { 326*8cc72f28SJingjing Wu printf("port %d start failed\n", port); 327af75078fSIntel return retval; 328*8cc72f28SJingjing Wu } 329af75078fSIntel 330*8cc72f28SJingjing Wu rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]); 331967b6294SIntel printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 332967b6294SIntel " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 333967b6294SIntel (unsigned)port, 334*8cc72f28SJingjing Wu vmdq_ports_eth_addr[port].addr_bytes[0], 335*8cc72f28SJingjing Wu vmdq_ports_eth_addr[port].addr_bytes[1], 336*8cc72f28SJingjing Wu vmdq_ports_eth_addr[port].addr_bytes[2], 337*8cc72f28SJingjing Wu vmdq_ports_eth_addr[port].addr_bytes[3], 338*8cc72f28SJingjing Wu vmdq_ports_eth_addr[port].addr_bytes[4], 339*8cc72f28SJingjing Wu vmdq_ports_eth_addr[port].addr_bytes[5]); 340*8cc72f28SJingjing Wu 341*8cc72f28SJingjing Wu /* Set mac for each pool.*/ 342*8cc72f28SJingjing Wu for (q = 0; q < num_pools; q++) { 343*8cc72f28SJingjing Wu struct ether_addr mac; 344*8cc72f28SJingjing Wu 345*8cc72f28SJingjing Wu mac = pool_addr_template; 346*8cc72f28SJingjing Wu mac.addr_bytes[4] = port; 347*8cc72f28SJingjing Wu mac.addr_bytes[5] = q; 348*8cc72f28SJingjing Wu printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n", 349*8cc72f28SJingjing Wu port, q, 350*8cc72f28SJingjing Wu mac.addr_bytes[0], mac.addr_bytes[1], 351*8cc72f28SJingjing Wu mac.addr_bytes[2], mac.addr_bytes[3], 352*8cc72f28SJingjing Wu mac.addr_bytes[4], mac.addr_bytes[5]); 353*8cc72f28SJingjing Wu retval = rte_eth_dev_mac_addr_add(port, &mac, 354*8cc72f28SJingjing Wu q + vmdq_pool_base); 355*8cc72f28SJingjing Wu if (retval) { 356*8cc72f28SJingjing Wu printf("mac addr add failed at pool %d\n", q); 357*8cc72f28SJingjing Wu return retval; 358*8cc72f28SJingjing Wu } 359*8cc72f28SJingjing Wu } 360967b6294SIntel 361af75078fSIntel return 0; 362af75078fSIntel } 363af75078fSIntel 3641d8d954bSIntel /* Check num_pools parameter and set it if OK*/ 3651d8d954bSIntel static int 3661d8d954bSIntel vmdq_parse_num_pools(const char *q_arg) 3671d8d954bSIntel { 3681d8d954bSIntel char *end = NULL; 3691d8d954bSIntel int n; 3701d8d954bSIntel 3711d8d954bSIntel /* parse number string */ 3721d8d954bSIntel n = strtol(q_arg, &end, 10); 3731d8d954bSIntel if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 3741d8d954bSIntel return -1; 3751d8d954bSIntel if (n != 16 && n != 32) 3761d8d954bSIntel return -1; 3771d8d954bSIntel if (n == 16) 3781d8d954bSIntel num_pools = ETH_16_POOLS; 3791d8d954bSIntel else 3801d8d954bSIntel num_pools = ETH_32_POOLS; 3811d8d954bSIntel 3821d8d954bSIntel return 0; 3831d8d954bSIntel } 3841d8d954bSIntel 385*8cc72f28SJingjing Wu /* Check num_tcs parameter and set it if OK*/ 386*8cc72f28SJingjing Wu static int 387*8cc72f28SJingjing Wu vmdq_parse_num_tcs(const char *q_arg) 388*8cc72f28SJingjing Wu { 389*8cc72f28SJingjing Wu char *end = NULL; 390*8cc72f28SJingjing Wu int n; 391*8cc72f28SJingjing Wu 392*8cc72f28SJingjing Wu /* parse number string */ 393*8cc72f28SJingjing Wu n = strtol(q_arg, &end, 10); 394*8cc72f28SJingjing Wu if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 395*8cc72f28SJingjing Wu return -1; 396*8cc72f28SJingjing Wu 397*8cc72f28SJingjing Wu if (n != 4 && n != 8) 398*8cc72f28SJingjing Wu return -1; 399*8cc72f28SJingjing Wu if (n == 4) 400*8cc72f28SJingjing Wu num_tcs = ETH_4_TCS; 401*8cc72f28SJingjing Wu else 402*8cc72f28SJingjing Wu num_tcs = ETH_8_TCS; 403*8cc72f28SJingjing Wu 404*8cc72f28SJingjing Wu return 0; 405*8cc72f28SJingjing Wu } 406*8cc72f28SJingjing Wu 407d4f37b09SIntel static int 408d4f37b09SIntel parse_portmask(const char *portmask) 409d4f37b09SIntel { 410d4f37b09SIntel char *end = NULL; 411d4f37b09SIntel unsigned long pm; 412d4f37b09SIntel 413d4f37b09SIntel /* parse hexadecimal string */ 414d4f37b09SIntel pm = strtoul(portmask, &end, 16); 415d4f37b09SIntel if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 416d4f37b09SIntel return -1; 417d4f37b09SIntel 418d4f37b09SIntel if (pm == 0) 419d4f37b09SIntel return -1; 420d4f37b09SIntel 421d4f37b09SIntel return pm; 422d4f37b09SIntel } 423d4f37b09SIntel 4241d8d954bSIntel /* Display usage */ 4251d8d954bSIntel static void 4261d8d954bSIntel vmdq_usage(const char *prgname) 4271d8d954bSIntel { 428d4f37b09SIntel printf("%s [EAL options] -- -p PORTMASK]\n" 429*8cc72f28SJingjing Wu " --nb-pools NP: number of pools (32 default, 16)\n" 430*8cc72f28SJingjing Wu " --nb-tcs NP: number of TCs (4 default, 8)\n" 431*8cc72f28SJingjing Wu " --enable-rss: enable RSS (disabled by default)\n", 4321d8d954bSIntel prgname); 4331d8d954bSIntel } 4341d8d954bSIntel 4351d8d954bSIntel /* Parse the argument (num_pools) given in the command line of the application */ 4361d8d954bSIntel static int 4371d8d954bSIntel vmdq_parse_args(int argc, char **argv) 4381d8d954bSIntel { 4391d8d954bSIntel int opt; 4401d8d954bSIntel int option_index; 441d4f37b09SIntel unsigned i; 4421d8d954bSIntel const char *prgname = argv[0]; 4431d8d954bSIntel static struct option long_option[] = { 4441d8d954bSIntel {"nb-pools", required_argument, NULL, 0}, 445*8cc72f28SJingjing Wu {"nb-tcs", required_argument, NULL, 0}, 446*8cc72f28SJingjing Wu {"enable-rss", 0, NULL, 0}, 4471d8d954bSIntel {NULL, 0, 0, 0} 4481d8d954bSIntel }; 4491d8d954bSIntel 4501d8d954bSIntel /* Parse command line */ 451*8cc72f28SJingjing Wu while ((opt = getopt_long(argc, argv, "p:", long_option, 452*8cc72f28SJingjing Wu &option_index)) != EOF) { 4531d8d954bSIntel switch (opt) { 454d4f37b09SIntel /* portmask */ 455d4f37b09SIntel case 'p': 456d4f37b09SIntel enabled_port_mask = parse_portmask(optarg); 457d4f37b09SIntel if (enabled_port_mask == 0) { 458d4f37b09SIntel printf("invalid portmask\n"); 459d4f37b09SIntel vmdq_usage(prgname); 460d4f37b09SIntel return -1; 461d4f37b09SIntel } 462d4f37b09SIntel break; 4631d8d954bSIntel case 0: 464*8cc72f28SJingjing Wu if (!strcmp(long_option[option_index].name, "nb-pools")) { 4651d8d954bSIntel if (vmdq_parse_num_pools(optarg) == -1) { 4661d8d954bSIntel printf("invalid number of pools\n"); 4671d8d954bSIntel return -1; 4681d8d954bSIntel } 469*8cc72f28SJingjing Wu } 470*8cc72f28SJingjing Wu 471*8cc72f28SJingjing Wu if (!strcmp(long_option[option_index].name, "nb-tcs")) { 472*8cc72f28SJingjing Wu if (vmdq_parse_num_tcs(optarg) == -1) { 473*8cc72f28SJingjing Wu printf("invalid number of tcs\n"); 474*8cc72f28SJingjing Wu return -1; 475*8cc72f28SJingjing Wu } 476*8cc72f28SJingjing Wu } 477*8cc72f28SJingjing Wu 478*8cc72f28SJingjing Wu if (!strcmp(long_option[option_index].name, "enable-rss")) 479*8cc72f28SJingjing Wu rss_enable = 1; 4801d8d954bSIntel break; 481*8cc72f28SJingjing Wu 4821d8d954bSIntel default: 4831d8d954bSIntel vmdq_usage(prgname); 4841d8d954bSIntel return -1; 4851d8d954bSIntel } 4861d8d954bSIntel } 487d4f37b09SIntel 488*8cc72f28SJingjing Wu for (i = 0; i < RTE_MAX_ETHPORTS; i++) { 489d4f37b09SIntel if (enabled_port_mask & (1 << i)) 490d4f37b09SIntel ports[num_ports++] = (uint8_t)i; 491d4f37b09SIntel } 492d4f37b09SIntel 493d4f37b09SIntel if (num_ports < 2 || num_ports % 2) { 494d4f37b09SIntel printf("Current enabled port number is %u," 495d4f37b09SIntel " but it should be even and at least 2\n", num_ports); 496d4f37b09SIntel return -1; 497d4f37b09SIntel } 498d4f37b09SIntel 4991d8d954bSIntel return 0; 5001d8d954bSIntel } 5011d8d954bSIntel 502*8cc72f28SJingjing Wu static void 503*8cc72f28SJingjing Wu update_mac_address(struct rte_mbuf *m, unsigned dst_port) 504*8cc72f28SJingjing Wu { 505*8cc72f28SJingjing Wu struct ether_hdr *eth; 506*8cc72f28SJingjing Wu void *tmp; 507*8cc72f28SJingjing Wu 508*8cc72f28SJingjing Wu eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 509*8cc72f28SJingjing Wu 510*8cc72f28SJingjing Wu /* 02:00:00:00:00:xx */ 511*8cc72f28SJingjing Wu tmp = ð->d_addr.addr_bytes[0]; 512*8cc72f28SJingjing Wu *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); 513*8cc72f28SJingjing Wu 514*8cc72f28SJingjing Wu /* src addr */ 515*8cc72f28SJingjing Wu ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr); 516*8cc72f28SJingjing Wu } 5171d8d954bSIntel 518af75078fSIntel /* When we receive a HUP signal, print out our stats */ 519af75078fSIntel static void 520af75078fSIntel sighup_handler(int signum) 521af75078fSIntel { 522*8cc72f28SJingjing Wu unsigned q = vmdq_queue_base; 523*8cc72f28SJingjing Wu 524*8cc72f28SJingjing Wu for (; q < num_queues; q++) { 525*8cc72f28SJingjing Wu if (q % (num_vmdq_queues / num_pools) == 0) 526*8cc72f28SJingjing Wu printf("\nPool %u: ", (q - vmdq_queue_base) / 527*8cc72f28SJingjing Wu (num_vmdq_queues / num_pools)); 528af75078fSIntel printf("%lu ", rxPackets[q]); 529af75078fSIntel } 530af75078fSIntel printf("\nFinished handling signal %d\n", signum); 531af75078fSIntel } 532af75078fSIntel 533af75078fSIntel /* 534af75078fSIntel * Main thread that does the work, reading from INPUT_PORT 535af75078fSIntel * and writing to OUTPUT_PORT 536af75078fSIntel */ 537*8cc72f28SJingjing Wu static int 538af75078fSIntel lcore_main(void *arg) 539af75078fSIntel { 540af75078fSIntel const uintptr_t core_num = (uintptr_t)arg; 541af75078fSIntel const unsigned num_cores = rte_lcore_count(); 542*8cc72f28SJingjing Wu uint16_t startQueue, endQueue; 543d4f37b09SIntel uint16_t q, i, p; 544*8cc72f28SJingjing Wu const uint16_t quot = (uint16_t)(num_vmdq_queues / num_cores); 545*8cc72f28SJingjing Wu const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores); 546af75078fSIntel 547*8cc72f28SJingjing Wu 548*8cc72f28SJingjing Wu if (remainder) { 549*8cc72f28SJingjing Wu if (core_num < remainder) { 550*8cc72f28SJingjing Wu startQueue = (uint16_t)(core_num * (quot + 1)); 551*8cc72f28SJingjing Wu endQueue = (uint16_t)(startQueue + quot + 1); 552*8cc72f28SJingjing Wu } else { 553*8cc72f28SJingjing Wu startQueue = (uint16_t)(core_num * quot + remainder); 554*8cc72f28SJingjing Wu endQueue = (uint16_t)(startQueue + quot); 555*8cc72f28SJingjing Wu } 556*8cc72f28SJingjing Wu } else { 557*8cc72f28SJingjing Wu startQueue = (uint16_t)(core_num * quot); 558*8cc72f28SJingjing Wu endQueue = (uint16_t)(startQueue + quot); 559*8cc72f28SJingjing Wu } 560*8cc72f28SJingjing Wu 561*8cc72f28SJingjing Wu /* vmdq queue idx doesn't always start from zero.*/ 562*8cc72f28SJingjing Wu startQueue += vmdq_queue_base; 563*8cc72f28SJingjing Wu endQueue += vmdq_queue_base; 564af75078fSIntel printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num, 565af75078fSIntel rte_lcore_id(), startQueue, endQueue - 1); 566af75078fSIntel 567*8cc72f28SJingjing Wu if (startQueue == endQueue) { 568*8cc72f28SJingjing Wu printf("lcore %u has nothing to do\n", (unsigned)core_num); 569*8cc72f28SJingjing Wu return 0; 570*8cc72f28SJingjing Wu } 571*8cc72f28SJingjing Wu 572af75078fSIntel for (;;) { 573*8cc72f28SJingjing Wu struct rte_mbuf *buf[MAX_PKT_BURST]; 574af75078fSIntel const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]); 575d4f37b09SIntel for (p = 0; p < num_ports; p++) { 576d4f37b09SIntel const uint8_t src = ports[p]; 577d4f37b09SIntel const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */ 578d4f37b09SIntel 579d4f37b09SIntel if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID)) 580d4f37b09SIntel continue; 581af75078fSIntel 582af75078fSIntel for (q = startQueue; q < endQueue; q++) { 583d4f37b09SIntel const uint16_t rxCount = rte_eth_rx_burst(src, 584af75078fSIntel q, buf, buf_size); 585*8cc72f28SJingjing Wu 586*8cc72f28SJingjing Wu if (unlikely(rxCount == 0)) 587af75078fSIntel continue; 588*8cc72f28SJingjing Wu 589af75078fSIntel rxPackets[q] += rxCount; 590af75078fSIntel 591*8cc72f28SJingjing Wu for (i = 0; i < rxCount; i++) 592*8cc72f28SJingjing Wu update_mac_address(buf[i], dst); 593*8cc72f28SJingjing Wu 594d4f37b09SIntel const uint16_t txCount = rte_eth_tx_burst(dst, 595*8cc72f28SJingjing Wu q, buf, rxCount); 596af75078fSIntel if (txCount != rxCount) { 597af75078fSIntel for (i = txCount; i < rxCount; i++) 598af75078fSIntel rte_pktmbuf_free(buf[i]); 599af75078fSIntel } 600af75078fSIntel } 601af75078fSIntel } 602af75078fSIntel } 603d4f37b09SIntel } 604d4f37b09SIntel 605d4f37b09SIntel /* 606d4f37b09SIntel * Update the global var NUM_PORTS and array PORTS according to system ports number 607d4f37b09SIntel * and return valid ports number 608d4f37b09SIntel */ 609d4f37b09SIntel static unsigned check_ports_num(unsigned nb_ports) 610d4f37b09SIntel { 611d4f37b09SIntel unsigned valid_num_ports = num_ports; 612d4f37b09SIntel unsigned portid; 613d4f37b09SIntel 614d4f37b09SIntel if (num_ports > nb_ports) { 615d4f37b09SIntel printf("\nSpecified port number(%u) exceeds total system port number(%u)\n", 616d4f37b09SIntel num_ports, nb_ports); 617d4f37b09SIntel num_ports = nb_ports; 618d4f37b09SIntel } 619d4f37b09SIntel 620d4f37b09SIntel for (portid = 0; portid < num_ports; portid++) { 621d4f37b09SIntel if (ports[portid] >= nb_ports) { 622d4f37b09SIntel printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n", 623d4f37b09SIntel ports[portid], (nb_ports - 1)); 624d4f37b09SIntel ports[portid] = INVALID_PORT_ID; 625d4f37b09SIntel valid_num_ports--; 626d4f37b09SIntel } 627d4f37b09SIntel } 628d4f37b09SIntel return valid_num_ports; 629d4f37b09SIntel } 630d4f37b09SIntel 631af75078fSIntel 632af75078fSIntel /* Main function, does initialisation and calls the per-lcore functions */ 633af75078fSIntel int 63498a16481SDavid Marchand main(int argc, char *argv[]) 635af75078fSIntel { 636af75078fSIntel unsigned cores; 637af75078fSIntel struct rte_mempool *mbuf_pool; 638af75078fSIntel unsigned lcore_id; 639af75078fSIntel uintptr_t i; 6401d8d954bSIntel int ret; 641d4f37b09SIntel unsigned nb_ports, valid_num_ports; 642d4f37b09SIntel uint8_t portid; 643af75078fSIntel 644af75078fSIntel signal(SIGHUP, sighup_handler); 645af75078fSIntel 6461d8d954bSIntel /* init EAL */ 6471d8d954bSIntel ret = rte_eal_init(argc, argv); 6481d8d954bSIntel if (ret < 0) 649af75078fSIntel rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 6501d8d954bSIntel argc -= ret; 6511d8d954bSIntel argv += ret; 6521d8d954bSIntel 6531d8d954bSIntel /* parse app arguments */ 6541d8d954bSIntel ret = vmdq_parse_args(argc, argv); 6551d8d954bSIntel if (ret < 0) 6561d8d954bSIntel rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n"); 6571d8d954bSIntel 658af75078fSIntel cores = rte_lcore_count(); 659*8cc72f28SJingjing Wu if ((cores & (cores - 1)) != 0 || cores > RTE_MAX_LCORE) { 660d4f37b09SIntel rte_exit(EXIT_FAILURE,"This program can only run on an even" 661*8cc72f28SJingjing Wu " number of cores(1-%d)\n\n", RTE_MAX_LCORE); 662af75078fSIntel } 663af75078fSIntel 664d4f37b09SIntel nb_ports = rte_eth_dev_count(); 665d4f37b09SIntel if (nb_ports > RTE_MAX_ETHPORTS) 666d4f37b09SIntel nb_ports = RTE_MAX_ETHPORTS; 667d4f37b09SIntel 668d4f37b09SIntel /* 669d4f37b09SIntel * Update the global var NUM_PORTS and global array PORTS 670d4f37b09SIntel * and get value of var VALID_NUM_PORTS according to system ports number 671d4f37b09SIntel */ 672d4f37b09SIntel valid_num_ports = check_ports_num(nb_ports); 673d4f37b09SIntel 674d4f37b09SIntel if (valid_num_ports < 2 || valid_num_ports % 2) { 675d4f37b09SIntel printf("Current valid ports number is %u\n", valid_num_ports); 676d4f37b09SIntel rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n"); 677d4f37b09SIntel } 678d4f37b09SIntel 679*8cc72f28SJingjing Wu mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 680*8cc72f28SJingjing Wu NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE, 681*8cc72f28SJingjing Wu 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 682af75078fSIntel if (mbuf_pool == NULL) 683af75078fSIntel rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 684af75078fSIntel 685d4f37b09SIntel /* initialize all ports */ 686d4f37b09SIntel for (portid = 0; portid < nb_ports; portid++) { 687d4f37b09SIntel /* skip ports that are not enabled */ 688d4f37b09SIntel if ((enabled_port_mask & (1 << portid)) == 0) { 689d4f37b09SIntel printf("\nSkipping disabled port %d\n", portid); 690d4f37b09SIntel continue; 691d4f37b09SIntel } 692d4f37b09SIntel if (port_init(portid, mbuf_pool) != 0) 693af75078fSIntel rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n"); 694d4f37b09SIntel } 695af75078fSIntel 696af75078fSIntel /* call lcore_main() on every slave lcore */ 697af75078fSIntel i = 0; 698af75078fSIntel RTE_LCORE_FOREACH_SLAVE(lcore_id) { 699af75078fSIntel rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id); 700af75078fSIntel } 701af75078fSIntel /* call on master too */ 702af75078fSIntel (void) lcore_main((void*)i); 703af75078fSIntel 704af75078fSIntel return 0; 705af75078fSIntel } 706