1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2012 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 #include <stdint.h> 36 #include <sys/queue.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <stdio.h> 40 #include <unistd.h> 41 #include <assert.h> 42 #include <errno.h> 43 #include <signal.h> 44 #include <stdarg.h> 45 #include <inttypes.h> 46 47 #include <rte_common.h> 48 #include <rte_log.h> 49 #include <rte_memory.h> 50 #include <rte_memcpy.h> 51 #include <rte_memzone.h> 52 #include <rte_tailq.h> 53 #include <rte_eal.h> 54 #include <rte_per_lcore.h> 55 #include <rte_launch.h> 56 #include <rte_atomic.h> 57 #include <rte_cycles.h> 58 #include <rte_prefetch.h> 59 #include <rte_lcore.h> 60 #include <rte_per_lcore.h> 61 #include <rte_branch_prediction.h> 62 #include <rte_interrupts.h> 63 #include <rte_pci.h> 64 #include <rte_random.h> 65 #include <rte_debug.h> 66 #include <rte_ether.h> 67 #include <rte_ethdev.h> 68 #include <rte_ring.h> 69 #include <rte_log.h> 70 #include <rte_mempool.h> 71 #include <rte_mbuf.h> 72 #include <rte_memcpy.h> 73 74 #include "main.h" 75 76 /* basic constants used in application */ 77 #define SOCKET0 0 78 #define SOCKET1 1 79 80 #define NUM_QUEUES 128 81 82 #define NUM_MBUFS 64*1024 83 #define MBUF_CACHE_SIZE 64 84 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 85 86 /* Basic application settings */ 87 #define NUM_POOLS ETH_16_POOLS /* can be ETH_16_POOLS or ETH_32_POOLS */ 88 89 #define RX_PORT 0 90 #define TX_PORT 1 91 92 /* 93 * RX and TX Prefetch, Host, and Write-back threshold values should be 94 * carefully set for optimal performance. Consult the network 95 * controller's datasheet and supporting DPDK documentation for guidance 96 * on how these parameters should be set. 97 */ 98 /* Default configuration for rx and tx thresholds etc. */ 99 static const struct rte_eth_rxconf rx_conf_default = { 100 .rx_thresh = { 101 .pthresh = 8, 102 .hthresh = 8, 103 .wthresh = 4, 104 }, 105 }; 106 107 /* 108 * These default values are optimized for use with the Intel(R) 82599 10 GbE 109 * Controller and the DPDK ixgbe PMD. Consider using other values for other 110 * network controllers and/or network drivers. 111 */ 112 static const struct rte_eth_txconf tx_conf_default = { 113 .tx_thresh = { 114 .pthresh = 36, 115 .hthresh = 0, 116 .wthresh = 0, 117 }, 118 .tx_free_thresh = 0, /* Use PMD default values */ 119 .tx_rs_thresh = 0, /* Use PMD default values */ 120 }; 121 122 /* empty vmdq+dcb configuration structure. Filled in programatically */ 123 static const struct rte_eth_conf vmdq_dcb_conf_default = { 124 .rxmode = { 125 .mq_mode = ETH_VMDQ_DCB, 126 .split_hdr_size = 0, 127 .header_split = 0, /**< Header Split disabled */ 128 .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 129 .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 130 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 131 }, 132 .txmode = { 133 }, 134 .rx_adv_conf = { 135 /* 136 * should be overridden separately in code with 137 * appropriate values 138 */ 139 .vmdq_dcb_conf = { 140 .nb_queue_pools = NUM_POOLS, 141 .enable_default_pool = 0, 142 .default_pool = 0, 143 .nb_pool_maps = 0, 144 .pool_map = {{0, 0},}, 145 .dcb_queue = {0}, 146 }, 147 }, 148 }; 149 150 /* array used for printing out statistics */ 151 volatile unsigned long rxPackets[ NUM_QUEUES ] = {0}; 152 153 const uint16_t vlan_tags[] = { 154 0, 1, 2, 3, 4, 5, 6, 7, 155 8, 9, 10, 11, 12, 13, 14, 15, 156 16, 17, 18, 19, 20, 21, 22, 23, 157 24, 25, 26, 27, 28, 29, 30, 31 158 }; 159 160 /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array 161 * given above, and the number of traffic classes available for use. */ 162 static inline int 163 get_eth_conf(struct rte_eth_conf *eth_conf, enum rte_eth_nb_pools num_pools) 164 { 165 struct rte_eth_vmdq_dcb_conf conf; 166 unsigned i; 167 168 if (num_pools != ETH_16_POOLS && num_pools != ETH_32_POOLS ) return -1; 169 170 conf.nb_queue_pools = num_pools; 171 conf.enable_default_pool = 0; 172 conf.nb_pool_maps = sizeof( vlan_tags )/sizeof( vlan_tags[ 0 ]); 173 for (i = 0; i < conf.nb_pool_maps; i++){ 174 conf.pool_map[i].vlan_id = vlan_tags[ i ]; 175 conf.pool_map[i].pools = 1 << (i % num_pools); 176 } 177 for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){ 178 conf.dcb_queue[i] = (uint8_t)(i % (NUM_QUEUES/num_pools)); 179 } 180 rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)); 181 rte_memcpy(ð_conf->rx_adv_conf.vmdq_dcb_conf, &conf, 182 sizeof(eth_conf->rx_adv_conf.vmdq_dcb_conf)); 183 return 0; 184 } 185 186 /* 187 * Initialises a given port using global settings and with the rx buffers 188 * coming from the mbuf_pool passed as parameter 189 */ 190 static inline int 191 port_init(uint8_t port, struct rte_mempool *mbuf_pool) 192 { 193 struct rte_eth_conf port_conf; 194 const uint16_t rxRings = ETH_VMDQ_DCB_NUM_QUEUES, 195 txRings = (uint16_t)rte_lcore_count(); 196 const uint16_t rxRingSize = 128, txRingSize = 512; 197 int retval; 198 uint16_t q; 199 200 get_eth_conf(&port_conf, NUM_POOLS); 201 202 if (port >= rte_eth_dev_count()) return -1; 203 204 retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf); 205 if (retval != 0) 206 return retval; 207 208 for (q = 0; q < rxRings; q ++) { 209 retval = rte_eth_rx_queue_setup(port, q, rxRingSize, 210 SOCKET0, &rx_conf_default, 211 mbuf_pool); 212 if (retval < 0) 213 return retval; 214 } 215 216 for (q = 0; q < txRings; q ++) { 217 retval = rte_eth_tx_queue_setup(port, q, txRingSize, 218 SOCKET0, &tx_conf_default); 219 if (retval < 0) 220 return retval; 221 } 222 223 retval = rte_eth_dev_start(port); 224 if (retval < 0) 225 return retval; 226 227 return 0; 228 } 229 230 #ifndef RTE_EXEC_ENV_BAREMETAL 231 /* When we receive a HUP signal, print out our stats */ 232 static void 233 sighup_handler(int signum) 234 { 235 unsigned q; 236 for (q = 0; q < NUM_QUEUES; q ++) { 237 if (q % (NUM_QUEUES/NUM_POOLS) == 0) 238 printf("\nPool %u: ", q/(NUM_QUEUES/NUM_POOLS)); 239 printf("%lu ", rxPackets[ q ]); 240 } 241 printf("\nFinished handling signal %d\n", signum); 242 } 243 #endif 244 245 /* 246 * Main thread that does the work, reading from INPUT_PORT 247 * and writing to OUTPUT_PORT 248 */ 249 static __attribute__((noreturn)) int 250 lcore_main(void *arg) 251 { 252 const uintptr_t core_num = (uintptr_t)arg; 253 const unsigned num_cores = rte_lcore_count(); 254 uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores)); 255 uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores)); 256 uint16_t q, i; 257 258 printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num, 259 rte_lcore_id(), startQueue, endQueue - 1); 260 261 for (;;) { 262 struct rte_mbuf *buf[32]; 263 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]); 264 265 for (q = startQueue; q < endQueue; q++) { 266 const uint16_t rxCount = rte_eth_rx_burst(RX_PORT, 267 q, buf, buf_size); 268 if (rxCount == 0) 269 continue; 270 rxPackets[q] += rxCount; 271 272 const uint16_t txCount = rte_eth_tx_burst(TX_PORT, 273 (uint16_t)core_num, buf, rxCount); 274 if (txCount != rxCount) { 275 for (i = txCount; i < rxCount; i++) 276 rte_pktmbuf_free(buf[i]); 277 } 278 } 279 } 280 } 281 282 /* Main function, does initialisation and calls the per-lcore functions */ 283 int 284 MAIN(int argc, char *argv[]) 285 { 286 unsigned cores; 287 struct rte_mempool *mbuf_pool; 288 unsigned lcore_id; 289 uintptr_t i; 290 291 #ifndef RTE_EXEC_ENV_BAREMETAL 292 signal(SIGHUP, sighup_handler); 293 #endif 294 295 if (rte_eal_init(argc, argv) < 0) 296 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 297 if (rte_igb_pmd_init() != 0 || 298 rte_ixgbe_pmd_init() != 0 || 299 rte_eal_pci_probe() != 0) 300 rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n"); 301 302 cores = rte_lcore_count(); 303 if ((cores & (cores - 1)) != 0 || cores > 16) { 304 rte_exit(EXIT_FAILURE, 305 "This program can only run on 2,4,8 or 16 cores\n\n"); 306 } 307 308 mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS, 309 MBUF_SIZE, MBUF_CACHE_SIZE, 310 sizeof(struct rte_pktmbuf_pool_private), 311 rte_pktmbuf_pool_init, NULL, 312 rte_pktmbuf_init, NULL, 313 SOCKET0, 0); 314 if (mbuf_pool == NULL) 315 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 316 317 if (port_init(RX_PORT, mbuf_pool) != 0 || 318 port_init(TX_PORT, mbuf_pool) != 0) 319 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n"); 320 321 /* call lcore_main() on every slave lcore */ 322 i = 0; 323 RTE_LCORE_FOREACH_SLAVE(lcore_id) { 324 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id); 325 } 326 /* call on master too */ 327 (void) lcore_main((void*)i); 328 329 return 0; 330 } 331