4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
35 #include <sys/queue.h>
46 #include <rte_common.h>
48 #include <rte_memory.h>
49 #include <rte_memcpy.h>
50 #include <rte_memzone.h>
51 #include <rte_tailq.h>
53 #include <rte_per_lcore.h>
54 #include <rte_launch.h>
55 #include <rte_atomic.h>
56 #include <rte_cycles.h>
57 #include <rte_prefetch.h>
58 #include <rte_lcore.h>
59 #include <rte_per_lcore.h>
60 #include <rte_branch_prediction.h>
61 #include <rte_interrupts.h>
63 #include <rte_random.h>
64 #include <rte_debug.h>
65 #include <rte_ether.h>
66 #include <rte_ethdev.h>
69 #include <rte_mempool.h>
71 #include <rte_memcpy.h>
73 /* basic constants used in application */
74 #define NUM_QUEUES 128
76 #define NUM_MBUFS 64*1024
77 #define MBUF_CACHE_SIZE 64
78 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
80 #define INVALID_PORT_ID 0xFF
82 /* mask of enabled ports */
83 static uint32_t enabled_port_mask = 0;
85 /* number of pools (if user does not specify any, 16 by default */
86 static enum rte_eth_nb_pools num_pools = ETH_16_POOLS;
88 /* empty vmdq+dcb configuration structure. Filled in programatically */
89 static const struct rte_eth_conf vmdq_dcb_conf_default = {
91 .mq_mode = ETH_MQ_RX_VMDQ_DCB,
93 .header_split = 0, /**< Header Split disabled */
94 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
95 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
96 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
99 .mq_mode = ETH_MQ_TX_NONE,
103 * should be overridden separately in code with
107 .nb_queue_pools = ETH_16_POOLS,
108 .enable_default_pool = 0,
111 .pool_map = {{0, 0},},
117 static uint8_t ports[RTE_MAX_ETHPORTS];
118 static unsigned num_ports = 0;
120 /* array used for printing out statistics */
121 volatile unsigned long rxPackets[ NUM_QUEUES ] = {0};
123 const uint16_t vlan_tags[] = {
124 0, 1, 2, 3, 4, 5, 6, 7,
125 8, 9, 10, 11, 12, 13, 14, 15,
126 16, 17, 18, 19, 20, 21, 22, 23,
127 24, 25, 26, 27, 28, 29, 30, 31
130 /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
131 * given above, and the number of traffic classes available for use. */
133 get_eth_conf(struct rte_eth_conf *eth_conf, enum rte_eth_nb_pools num_pools)
135 struct rte_eth_vmdq_dcb_conf conf;
138 if (num_pools != ETH_16_POOLS && num_pools != ETH_32_POOLS ) return -1;
140 conf.nb_queue_pools = num_pools;
141 conf.enable_default_pool = 0;
142 conf.default_pool = 0; /* set explicit value, even if not used */
143 conf.nb_pool_maps = sizeof( vlan_tags )/sizeof( vlan_tags[ 0 ]);
144 for (i = 0; i < conf.nb_pool_maps; i++){
145 conf.pool_map[i].vlan_id = vlan_tags[ i ];
146 conf.pool_map[i].pools = 1 << (i % num_pools);
148 for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
149 conf.dcb_queue[i] = (uint8_t)(i % (NUM_QUEUES/num_pools));
151 (void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
152 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
153 sizeof(eth_conf->rx_adv_conf.vmdq_dcb_conf)));
158 * Initialises a given port using global settings and with the rx buffers
159 * coming from the mbuf_pool passed as parameter
162 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
164 struct rte_eth_conf port_conf;
165 const uint16_t rxRings = ETH_VMDQ_DCB_NUM_QUEUES,
166 txRings = (uint16_t)rte_lcore_count();
167 const uint16_t rxRingSize = 128, txRingSize = 512;
171 retval = get_eth_conf(&port_conf, num_pools);
175 if (port >= rte_eth_dev_count()) return -1;
177 retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
181 for (q = 0; q < rxRings; q ++) {
182 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
183 rte_eth_dev_socket_id(port),
190 for (q = 0; q < txRings; q ++) {
191 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
192 rte_eth_dev_socket_id(port),
198 retval = rte_eth_dev_start(port);
202 struct ether_addr addr;
203 rte_eth_macaddr_get(port, &addr);
204 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
205 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
207 addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
208 addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
213 /* Check num_pools parameter and set it if OK*/
215 vmdq_parse_num_pools(const char *q_arg)
220 /* parse number string */
221 n = strtol(q_arg, &end, 10);
222 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
224 if (n != 16 && n != 32)
227 num_pools = ETH_16_POOLS;
229 num_pools = ETH_32_POOLS;
235 parse_portmask(const char *portmask)
240 /* parse hexadecimal string */
241 pm = strtoul(portmask, &end, 16);
242 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
253 vmdq_usage(const char *prgname)
255 printf("%s [EAL options] -- -p PORTMASK]\n"
256 " --nb-pools NP: number of pools (16 default, 32)\n",
260 /* Parse the argument (num_pools) given in the command line of the application */
262 vmdq_parse_args(int argc, char **argv)
267 const char *prgname = argv[0];
268 static struct option long_option[] = {
269 {"nb-pools", required_argument, NULL, 0},
273 /* Parse command line */
274 while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
278 enabled_port_mask = parse_portmask(optarg);
279 if (enabled_port_mask == 0) {
280 printf("invalid portmask\n");
286 if (vmdq_parse_num_pools(optarg) == -1){
287 printf("invalid number of pools\n");
298 for(i = 0; i < RTE_MAX_ETHPORTS; i++)
300 if (enabled_port_mask & (1 << i))
301 ports[num_ports++] = (uint8_t)i;
304 if (num_ports < 2 || num_ports % 2) {
305 printf("Current enabled port number is %u,"
306 "but it should be even and at least 2\n",num_ports);
314 /* When we receive a HUP signal, print out our stats */
316 sighup_handler(int signum)
319 for (q = 0; q < NUM_QUEUES; q ++) {
320 if (q % (NUM_QUEUES/num_pools) == 0)
321 printf("\nPool %u: ", q/(NUM_QUEUES/num_pools));
322 printf("%lu ", rxPackets[ q ]);
324 printf("\nFinished handling signal %d\n", signum);
328 * Main thread that does the work, reading from INPUT_PORT
329 * and writing to OUTPUT_PORT
331 static __attribute__((noreturn)) int
332 lcore_main(void *arg)
334 const uintptr_t core_num = (uintptr_t)arg;
335 const unsigned num_cores = rte_lcore_count();
336 uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores));
337 uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores));
340 printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
341 rte_lcore_id(), startQueue, endQueue - 1);
344 struct rte_mbuf *buf[32];
345 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
346 for (p = 0; p < num_ports; p++) {
347 const uint8_t src = ports[p];
348 const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
350 if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
353 for (q = startQueue; q < endQueue; q++) {
354 const uint16_t rxCount = rte_eth_rx_burst(src,
358 rxPackets[q] += rxCount;
360 const uint16_t txCount = rte_eth_tx_burst(dst,
361 (uint16_t)core_num, buf, rxCount);
362 if (txCount != rxCount) {
363 for (i = txCount; i < rxCount; i++)
364 rte_pktmbuf_free(buf[i]);
372 * Update the global var NUM_PORTS and array PORTS according to system ports number
373 * and return valid ports number
375 static unsigned check_ports_num(unsigned nb_ports)
377 unsigned valid_num_ports = num_ports;
380 if (num_ports > nb_ports) {
381 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
382 num_ports, nb_ports);
383 num_ports = nb_ports;
386 for (portid = 0; portid < num_ports; portid ++) {
387 if (ports[portid] >= nb_ports) {
388 printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
389 ports[portid], (nb_ports - 1));
390 ports[portid] = INVALID_PORT_ID;
394 return valid_num_ports;
398 /* Main function, does initialisation and calls the per-lcore functions */
400 main(int argc, char *argv[])
403 struct rte_mempool *mbuf_pool;
407 unsigned nb_ports, valid_num_ports;
410 signal(SIGHUP, sighup_handler);
413 ret = rte_eal_init(argc, argv);
415 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
419 /* parse app arguments */
420 ret = vmdq_parse_args(argc, argv);
422 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
424 cores = rte_lcore_count();
425 if ((cores & (cores - 1)) != 0 || cores > 128) {
426 rte_exit(EXIT_FAILURE,"This program can only run on an even"
427 "number of cores(1-128)\n\n");
430 nb_ports = rte_eth_dev_count();
431 if (nb_ports > RTE_MAX_ETHPORTS)
432 nb_ports = RTE_MAX_ETHPORTS;
435 * Update the global var NUM_PORTS and global array PORTS
436 * and get value of var VALID_NUM_PORTS according to system ports number
438 valid_num_ports = check_ports_num(nb_ports);
440 if (valid_num_ports < 2 || valid_num_ports % 2) {
441 printf("Current valid ports number is %u\n", valid_num_ports);
442 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
445 mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
446 MBUF_SIZE, MBUF_CACHE_SIZE,
447 sizeof(struct rte_pktmbuf_pool_private),
448 rte_pktmbuf_pool_init, NULL,
449 rte_pktmbuf_init, NULL,
451 if (mbuf_pool == NULL)
452 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
454 /* initialize all ports */
455 for (portid = 0; portid < nb_ports; portid++) {
456 /* skip ports that are not enabled */
457 if ((enabled_port_mask & (1 << portid)) == 0) {
458 printf("\nSkipping disabled port %d\n", portid);
461 if (port_init(portid, mbuf_pool) != 0)
462 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
465 /* call lcore_main() on every slave lcore */
467 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
468 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
470 /* call on master too */
471 (void) lcore_main((void*)i);