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>
75 #define MAX_QUEUES 128
77 * For 10 GbE, 128 queues require roughly
78 * 128*512 (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port.
80 #define NUM_MBUFS_PER_PORT (128*512)
81 #define MBUF_CACHE_SIZE 64
82 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
84 #define MAX_PKT_BURST 32
87 * Configurable number of RX/TX ring descriptors
89 #define RTE_TEST_RX_DESC_DEFAULT 128
90 #define RTE_TEST_TX_DESC_DEFAULT 512
92 #define INVALID_PORT_ID 0xFF
94 /* mask of enabled ports */
95 static uint32_t enabled_port_mask = 0;
97 /* number of pools (if user does not specify any, 8 by default */
98 static uint32_t num_queues = 8;
99 static uint32_t num_pools = 8;
101 /* empty vmdq configuration structure. Filled in programatically */
102 static const struct rte_eth_conf vmdq_conf_default = {
104 .mq_mode = ETH_MQ_RX_VMDQ_ONLY,
106 .header_split = 0, /**< Header Split disabled */
107 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
108 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
109 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
113 .mq_mode = ETH_MQ_TX_NONE,
117 * should be overridden separately in code with
121 .nb_queue_pools = ETH_8_POOLS,
122 .enable_default_pool = 0,
125 .pool_map = {{0, 0},},
130 static unsigned lcore_ids[RTE_MAX_LCORE];
131 static uint8_t ports[RTE_MAX_ETHPORTS];
132 static unsigned num_ports = 0; /**< The number of ports specified in command line */
134 /* array used for printing out statistics */
135 volatile unsigned long rxPackets[ MAX_QUEUES ] = {0};
137 const uint16_t vlan_tags[] = {
138 0, 1, 2, 3, 4, 5, 6, 7,
139 8, 9, 10, 11, 12, 13, 14, 15,
140 16, 17, 18, 19, 20, 21, 22, 23,
141 24, 25, 26, 27, 28, 29, 30, 31,
142 32, 33, 34, 35, 36, 37, 38, 39,
143 40, 41, 42, 43, 44, 45, 46, 47,
144 48, 49, 50, 51, 52, 53, 54, 55,
145 56, 57, 58, 59, 60, 61, 62, 63,
148 /* ethernet addresses of ports */
149 static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
151 #define MAX_QUEUE_NUM_10G 128
152 #define MAX_QUEUE_NUM_1G 8
153 #define MAX_POOL_MAP_NUM_10G 64
154 #define MAX_POOL_MAP_NUM_1G 32
155 #define MAX_POOL_NUM_10G 64
156 #define MAX_POOL_NUM_1G 8
157 /* Builds up the correct configuration for vmdq based on the vlan tags array
158 * given above, and determine the queue number and pool map number according to valid pool number */
160 get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools)
162 struct rte_eth_vmdq_rx_conf conf;
165 conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
166 conf.enable_default_pool = 0;
167 conf.default_pool = 0; /* set explicit value, even if not used */
169 /* For 10G NIC like 82599, 128 is valid for queue number */
170 case MAX_POOL_NUM_10G:
171 num_queues = MAX_QUEUE_NUM_10G;
172 conf.nb_pool_maps = MAX_POOL_MAP_NUM_10G;
174 /* For 1G NIC like i350, 82580 and 82576, 8 is valid for queue number */
175 case MAX_POOL_NUM_1G:
176 num_queues = MAX_QUEUE_NUM_1G;
177 conf.nb_pool_maps = MAX_POOL_MAP_NUM_1G;
183 for (i = 0; i < conf.nb_pool_maps; i++){
184 conf.pool_map[i].vlan_id = vlan_tags[ i ];
185 conf.pool_map[i].pools = (1UL << (i % num_pools));
188 (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
189 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf,
190 sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
195 * Validate the pool number accrording to the max pool number gotten form dev_info
196 * If the pool number is invalid, give the error message and return -1
199 validate_num_pools(uint32_t max_nb_pools)
201 if (num_pools > max_nb_pools) {
202 printf("invalid number of pools\n");
206 switch (max_nb_pools) {
207 /* For 10G NIC like 82599, 64 is valid for pool number */
208 case MAX_POOL_NUM_10G:
209 if (num_pools != MAX_POOL_NUM_10G) {
210 printf("invalid number of pools\n");
214 /* For 1G NIC like i350, 82580 and 82576, 8 is valid for pool number */
215 case MAX_POOL_NUM_1G:
216 if (num_pools != MAX_POOL_NUM_1G) {
217 printf("invalid number of pools\n");
229 * Initialises a given port using global settings and with the rx buffers
230 * coming from the mbuf_pool passed as parameter
233 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
235 struct rte_eth_dev_info dev_info;
236 struct rte_eth_rxconf *rxconf;
237 struct rte_eth_conf port_conf;
238 uint16_t rxRings, txRings = (uint16_t)rte_lcore_count();
239 const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT, txRingSize = RTE_TEST_TX_DESC_DEFAULT;
242 uint32_t max_nb_pools;
244 /* The max pool number from dev_info will be used to validate the pool number specified in cmd line */
245 rte_eth_dev_info_get (port, &dev_info);
246 max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
247 retval = validate_num_pools(max_nb_pools);
251 retval = get_eth_conf(&port_conf, num_pools);
255 if (port >= rte_eth_dev_count()) return -1;
257 rxRings = (uint16_t)num_queues,
258 retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
262 rte_eth_dev_info_get(port, &dev_info);
263 rxconf = &dev_info.default_rxconf;
264 rxconf->rx_drop_en = 1;
265 for (q = 0; q < rxRings; q ++) {
266 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
267 rte_eth_dev_socket_id(port),
274 for (q = 0; q < txRings; q ++) {
275 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
276 rte_eth_dev_socket_id(port),
282 retval = rte_eth_dev_start(port);
286 rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
287 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
288 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
290 vmdq_ports_eth_addr[port].addr_bytes[0],
291 vmdq_ports_eth_addr[port].addr_bytes[1],
292 vmdq_ports_eth_addr[port].addr_bytes[2],
293 vmdq_ports_eth_addr[port].addr_bytes[3],
294 vmdq_ports_eth_addr[port].addr_bytes[4],
295 vmdq_ports_eth_addr[port].addr_bytes[5]);
300 /* Check num_pools parameter and set it if OK*/
302 vmdq_parse_num_pools(const char *q_arg)
307 /* parse number string */
308 n = strtol(q_arg, &end, 10);
309 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
319 parse_portmask(const char *portmask)
324 /* parse hexadecimal string */
325 pm = strtoul(portmask, &end, 16);
326 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
337 vmdq_usage(const char *prgname)
339 printf("%s [EAL options] -- -p PORTMASK]\n"
340 " --nb-pools NP: number of pools\n",
344 /* Parse the argument (num_pools) given in the command line of the application */
346 vmdq_parse_args(int argc, char **argv)
351 const char *prgname = argv[0];
352 static struct option long_option[] = {
353 {"nb-pools", required_argument, NULL, 0},
357 /* Parse command line */
358 while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
362 enabled_port_mask = parse_portmask(optarg);
363 if (enabled_port_mask == 0) {
364 printf("invalid portmask\n");
370 if (vmdq_parse_num_pools(optarg) == -1){
371 printf("invalid number of pools\n");
383 for(i = 0; i < RTE_MAX_ETHPORTS; i++) {
384 if (enabled_port_mask & (1 << i))
385 ports[num_ports++] = (uint8_t)i;
388 if (num_ports < 2 || num_ports % 2) {
389 printf("Current enabled port number is %u,"
390 "but it should be even and at least 2\n",num_ports);
398 update_mac_address(struct rte_mbuf *m, unsigned dst_port)
400 struct ether_hdr *eth;
403 eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
405 /* 02:00:00:00:00:xx */
406 tmp = ð->d_addr.addr_bytes[0];
407 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
410 ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr);
413 #ifndef RTE_EXEC_ENV_BAREMETAL
414 /* When we receive a HUP signal, print out our stats */
416 sighup_handler(int signum)
419 for (q = 0; q < num_queues; q ++) {
420 if (q % (num_queues/num_pools) == 0)
421 printf("\nPool %u: ", q/(num_queues/num_pools));
422 printf("%lu ", rxPackets[ q ]);
424 printf("\nFinished handling signal %d\n", signum);
429 * Main thread that does the work, reading from INPUT_PORT
430 * and writing to OUTPUT_PORT
433 lcore_main(__attribute__((__unused__)) void* dummy)
435 const uint16_t lcore_id = (uint16_t)rte_lcore_id();
436 const uint16_t num_cores = (uint16_t)rte_lcore_count();
437 uint16_t core_id = 0;
438 uint16_t startQueue, endQueue;
440 const uint16_t remainder = (uint16_t)(num_queues % num_cores);
442 for (i = 0; i < num_cores; i ++)
443 if (lcore_ids[i] == lcore_id) {
448 if (remainder != 0) {
449 if (core_id < remainder) {
450 startQueue = (uint16_t)(core_id * (num_queues/num_cores + 1));
451 endQueue = (uint16_t)(startQueue + (num_queues/num_cores) + 1);
453 startQueue = (uint16_t)(core_id * (num_queues/num_cores) + remainder);
454 endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
457 startQueue = (uint16_t)(core_id * (num_queues/num_cores));
458 endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
461 printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id,
462 (unsigned)lcore_id, startQueue, endQueue - 1);
464 if (startQueue == endQueue) {
465 printf("lcore %u has nothing to do\n", lcore_id);
470 struct rte_mbuf *buf[MAX_PKT_BURST];
471 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
473 for (p = 0; p < num_ports; p++) {
474 const uint8_t sport = ports[p];
475 const uint8_t dport = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
477 if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID))
480 for (q = startQueue; q < endQueue; q++) {
481 const uint16_t rxCount = rte_eth_rx_burst(sport,
484 if (unlikely(rxCount == 0))
487 rxPackets[q] += rxCount;
489 for (i = 0; i < rxCount; i++)
490 update_mac_address(buf[i], dport);
492 const uint16_t txCount = rte_eth_tx_burst(dport,
493 core_id, buf, rxCount);
495 if (txCount != rxCount) {
496 for (i = txCount; i < rxCount; i++)
497 rte_pktmbuf_free(buf[i]);
505 * Update the global var NUM_PORTS and array PORTS according to system ports number
506 * and return valid ports number
508 static unsigned check_ports_num(unsigned nb_ports)
510 unsigned valid_num_ports = num_ports;
513 if (num_ports > nb_ports) {
514 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
515 num_ports, nb_ports);
516 num_ports = nb_ports;
519 for (portid = 0; portid < num_ports; portid ++) {
520 if (ports[portid] >= nb_ports) {
521 printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
522 ports[portid], (nb_ports - 1));
523 ports[portid] = INVALID_PORT_ID;
527 return valid_num_ports;
530 /* Main function, does initialisation and calls the per-lcore functions */
532 MAIN(int argc, char *argv[])
534 struct rte_mempool *mbuf_pool;
535 unsigned lcore_id, core_id = 0;
537 unsigned nb_ports, valid_num_ports;
540 #ifndef RTE_EXEC_ENV_BAREMETAL
541 signal(SIGHUP, sighup_handler);
545 ret = rte_eal_init(argc, argv);
547 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
551 /* parse app arguments */
552 ret = vmdq_parse_args(argc, argv);
554 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
556 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++)
557 if (rte_lcore_is_enabled(lcore_id))
558 lcore_ids[core_id ++] = lcore_id;
560 if (rte_lcore_count() > RTE_MAX_LCORE)
561 rte_exit(EXIT_FAILURE,"Not enough cores\n");
563 nb_ports = rte_eth_dev_count();
564 if (nb_ports > RTE_MAX_ETHPORTS)
565 nb_ports = RTE_MAX_ETHPORTS;
568 * Update the global var NUM_PORTS and global array PORTS
569 * and get value of var VALID_NUM_PORTS according to system ports number
571 valid_num_ports = check_ports_num(nb_ports);
573 if (valid_num_ports < 2 || valid_num_ports % 2) {
574 printf("Current valid ports number is %u\n", valid_num_ports);
575 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
578 mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS_PER_PORT * nb_ports,
579 MBUF_SIZE, MBUF_CACHE_SIZE,
580 sizeof(struct rte_pktmbuf_pool_private),
581 rte_pktmbuf_pool_init, NULL,
582 rte_pktmbuf_init, NULL,
584 if (mbuf_pool == NULL)
585 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
587 /* initialize all ports */
588 for (portid = 0; portid < nb_ports; portid++) {
589 /* skip ports that are not enabled */
590 if ((enabled_port_mask & (1 << portid)) == 0) {
591 printf("\nSkipping disabled port %d\n", portid);
594 if (port_init(portid, mbuf_pool) != 0)
595 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
598 /* call lcore_main() on every lcore */
599 rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER);
600 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
601 if (rte_eal_wait_lcore(lcore_id) < 0)