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)
85 * RX and TX Prefetch, Host, and Write-back threshold values should be
86 * carefully set for optimal performance. Consult the network
87 * controller's datasheet and supporting DPDK documentation for guidance
88 * on how these parameters should be set.
90 #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
91 #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
92 #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
95 * These default values are optimized for use with the Intel(R) 82599 10 GbE
96 * Controller and the DPDK ixgbe PMD. Consider using other values for other
97 * network controllers and/or network drivers.
99 #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
100 #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */
101 #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */
103 #define MAX_PKT_BURST 32
106 * Configurable number of RX/TX ring descriptors
108 #define RTE_TEST_RX_DESC_DEFAULT 128
109 #define RTE_TEST_TX_DESC_DEFAULT 512
111 #define INVALID_PORT_ID 0xFF
113 /* mask of enabled ports */
114 static uint32_t enabled_port_mask = 0;
116 /* number of pools (if user does not specify any, 8 by default */
117 static uint32_t num_queues = 8;
118 static uint32_t num_pools = 8;
121 * RX and TX Prefetch, Host, and Write-back threshold values should be
122 * carefully set for optimal performance. Consult the network
123 * controller's datasheet and supporting DPDK documentation for guidance
124 * on how these parameters should be set.
126 /* Default configuration for rx and tx thresholds etc. */
127 static const struct rte_eth_rxconf rx_conf_default = {
129 .pthresh = RX_PTHRESH,
130 .hthresh = RX_HTHRESH,
131 .wthresh = RX_WTHRESH,
137 * These default values are optimized for use with the Intel(R) 82599 10 GbE
138 * Controller and the DPDK ixgbe/igb PMD. Consider using other values for other
139 * network controllers and/or network drivers.
141 static const struct rte_eth_txconf tx_conf_default = {
143 .pthresh = TX_PTHRESH,
144 .hthresh = TX_HTHRESH,
145 .wthresh = TX_WTHRESH,
147 .tx_free_thresh = 0, /* Use PMD default values */
148 .tx_rs_thresh = 0, /* Use PMD default values */
151 /* empty vmdq configuration structure. Filled in programatically */
152 static const struct rte_eth_conf vmdq_conf_default = {
154 .mq_mode = ETH_MQ_RX_VMDQ_ONLY,
156 .header_split = 0, /**< Header Split disabled */
157 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
158 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
159 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
163 .mq_mode = ETH_MQ_TX_NONE,
167 * should be overridden separately in code with
171 .nb_queue_pools = ETH_8_POOLS,
172 .enable_default_pool = 0,
175 .pool_map = {{0, 0},},
180 static unsigned lcore_ids[RTE_MAX_LCORE];
181 static uint8_t ports[RTE_MAX_ETHPORTS];
182 static unsigned num_ports = 0; /**< The number of ports specified in command line */
184 /* array used for printing out statistics */
185 volatile unsigned long rxPackets[ MAX_QUEUES ] = {0};
187 const uint16_t vlan_tags[] = {
188 0, 1, 2, 3, 4, 5, 6, 7,
189 8, 9, 10, 11, 12, 13, 14, 15,
190 16, 17, 18, 19, 20, 21, 22, 23,
191 24, 25, 26, 27, 28, 29, 30, 31,
192 32, 33, 34, 35, 36, 37, 38, 39,
193 40, 41, 42, 43, 44, 45, 46, 47,
194 48, 49, 50, 51, 52, 53, 54, 55,
195 56, 57, 58, 59, 60, 61, 62, 63,
198 /* ethernet addresses of ports */
199 static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
201 #define MAX_QUEUE_NUM_10G 128
202 #define MAX_QUEUE_NUM_1G 8
203 #define MAX_POOL_MAP_NUM_10G 64
204 #define MAX_POOL_MAP_NUM_1G 32
205 #define MAX_POOL_NUM_10G 64
206 #define MAX_POOL_NUM_1G 8
207 /* Builds up the correct configuration for vmdq based on the vlan tags array
208 * given above, and determine the queue number and pool map number according to valid pool number */
210 get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools)
212 struct rte_eth_vmdq_rx_conf conf;
215 conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
216 conf.enable_default_pool = 0;
217 conf.default_pool = 0; /* set explicit value, even if not used */
219 /* For 10G NIC like 82599, 128 is valid for queue number */
220 case MAX_POOL_NUM_10G:
221 num_queues = MAX_QUEUE_NUM_10G;
222 conf.nb_pool_maps = MAX_POOL_MAP_NUM_10G;
224 /* For 1G NIC like i350, 82580 and 82576, 8 is valid for queue number */
225 case MAX_POOL_NUM_1G:
226 num_queues = MAX_QUEUE_NUM_1G;
227 conf.nb_pool_maps = MAX_POOL_MAP_NUM_1G;
233 for (i = 0; i < conf.nb_pool_maps; i++){
234 conf.pool_map[i].vlan_id = vlan_tags[ i ];
235 conf.pool_map[i].pools = (1UL << (i % num_pools));
238 (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
239 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf,
240 sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
245 * Validate the pool number accrording to the max pool number gotten form dev_info
246 * If the pool number is invalid, give the error message and return -1
249 validate_num_pools(uint32_t max_nb_pools)
251 if (num_pools > max_nb_pools) {
252 printf("invalid number of pools\n");
256 switch (max_nb_pools) {
257 /* For 10G NIC like 82599, 64 is valid for pool number */
258 case MAX_POOL_NUM_10G:
259 if (num_pools != MAX_POOL_NUM_10G) {
260 printf("invalid number of pools\n");
264 /* For 1G NIC like i350, 82580 and 82576, 8 is valid for pool number */
265 case MAX_POOL_NUM_1G:
266 if (num_pools != MAX_POOL_NUM_1G) {
267 printf("invalid number of pools\n");
279 * Initialises a given port using global settings and with the rx buffers
280 * coming from the mbuf_pool passed as parameter
283 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
285 struct rte_eth_dev_info dev_info;
286 struct rte_eth_conf port_conf;
287 uint16_t rxRings, txRings = (uint16_t)rte_lcore_count();
288 const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT, txRingSize = RTE_TEST_TX_DESC_DEFAULT;
291 uint32_t max_nb_pools;
293 /* The max pool number from dev_info will be used to validate the pool number specified in cmd line */
294 rte_eth_dev_info_get (port, &dev_info);
295 max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
296 retval = validate_num_pools(max_nb_pools);
300 retval = get_eth_conf(&port_conf, num_pools);
304 if (port >= rte_eth_dev_count()) return -1;
306 rxRings = (uint16_t)num_queues,
307 retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
311 for (q = 0; q < rxRings; q ++) {
312 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
313 rte_eth_dev_socket_id(port), &rx_conf_default,
319 for (q = 0; q < txRings; q ++) {
320 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
321 rte_eth_dev_socket_id(port), &tx_conf_default);
326 retval = rte_eth_dev_start(port);
330 rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
331 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
332 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
334 vmdq_ports_eth_addr[port].addr_bytes[0],
335 vmdq_ports_eth_addr[port].addr_bytes[1],
336 vmdq_ports_eth_addr[port].addr_bytes[2],
337 vmdq_ports_eth_addr[port].addr_bytes[3],
338 vmdq_ports_eth_addr[port].addr_bytes[4],
339 vmdq_ports_eth_addr[port].addr_bytes[5]);
344 /* Check num_pools parameter and set it if OK*/
346 vmdq_parse_num_pools(const char *q_arg)
351 /* parse number string */
352 n = strtol(q_arg, &end, 10);
353 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
363 parse_portmask(const char *portmask)
368 /* parse hexadecimal string */
369 pm = strtoul(portmask, &end, 16);
370 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
381 vmdq_usage(const char *prgname)
383 printf("%s [EAL options] -- -p PORTMASK]\n"
384 " --nb-pools NP: number of pools\n",
388 /* Parse the argument (num_pools) given in the command line of the application */
390 vmdq_parse_args(int argc, char **argv)
395 const char *prgname = argv[0];
396 static struct option long_option[] = {
397 {"nb-pools", required_argument, NULL, 0},
401 /* Parse command line */
402 while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
406 enabled_port_mask = parse_portmask(optarg);
407 if (enabled_port_mask == 0) {
408 printf("invalid portmask\n");
414 if (vmdq_parse_num_pools(optarg) == -1){
415 printf("invalid number of pools\n");
427 for(i = 0; i < RTE_MAX_ETHPORTS; i++) {
428 if (enabled_port_mask & (1 << i))
429 ports[num_ports++] = (uint8_t)i;
432 if (num_ports < 2 || num_ports % 2) {
433 printf("Current enabled port number is %u,"
434 "but it should be even and at least 2\n",num_ports);
442 update_mac_address(struct rte_mbuf *m, unsigned dst_port)
444 struct ether_hdr *eth;
447 eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
449 /* 02:00:00:00:00:xx */
450 tmp = ð->d_addr.addr_bytes[0];
451 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
454 ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr);
457 #ifndef RTE_EXEC_ENV_BAREMETAL
458 /* When we receive a HUP signal, print out our stats */
460 sighup_handler(int signum)
463 for (q = 0; q < num_queues; q ++) {
464 if (q % (num_queues/num_pools) == 0)
465 printf("\nPool %u: ", q/(num_queues/num_pools));
466 printf("%lu ", rxPackets[ q ]);
468 printf("\nFinished handling signal %d\n", signum);
473 * Main thread that does the work, reading from INPUT_PORT
474 * and writing to OUTPUT_PORT
477 lcore_main(__attribute__((__unused__)) void* dummy)
479 const uint16_t lcore_id = (uint16_t)rte_lcore_id();
480 const uint16_t num_cores = (uint16_t)rte_lcore_count();
481 uint16_t core_id = 0;
482 uint16_t startQueue, endQueue;
484 const uint16_t remainder = (uint16_t)(num_queues % num_cores);
486 for (i = 0; i < num_cores; i ++)
487 if (lcore_ids[i] == lcore_id) {
492 if (remainder != 0) {
493 if (core_id < remainder) {
494 startQueue = (uint16_t)(core_id * (num_queues/num_cores + 1));
495 endQueue = (uint16_t)(startQueue + (num_queues/num_cores) + 1);
497 startQueue = (uint16_t)(core_id * (num_queues/num_cores) + remainder);
498 endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
501 startQueue = (uint16_t)(core_id * (num_queues/num_cores));
502 endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
505 printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id,
506 (unsigned)lcore_id, startQueue, endQueue - 1);
508 if (startQueue == endQueue) {
509 printf("lcore %u has nothing to do\n", lcore_id);
514 struct rte_mbuf *buf[MAX_PKT_BURST];
515 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
517 for (p = 0; p < num_ports; p++) {
518 const uint8_t sport = ports[p];
519 const uint8_t dport = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
521 if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID))
524 for (q = startQueue; q < endQueue; q++) {
525 const uint16_t rxCount = rte_eth_rx_burst(sport,
528 if (unlikely(rxCount == 0))
531 rxPackets[q] += rxCount;
533 for (i = 0; i < rxCount; i++)
534 update_mac_address(buf[i], dport);
536 const uint16_t txCount = rte_eth_tx_burst(dport,
537 core_id, buf, rxCount);
539 if (txCount != rxCount) {
540 for (i = txCount; i < rxCount; i++)
541 rte_pktmbuf_free(buf[i]);
549 * Update the global var NUM_PORTS and array PORTS according to system ports number
550 * and return valid ports number
552 static unsigned check_ports_num(unsigned nb_ports)
554 unsigned valid_num_ports = num_ports;
557 if (num_ports > nb_ports) {
558 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
559 num_ports, nb_ports);
560 num_ports = nb_ports;
563 for (portid = 0; portid < num_ports; portid ++) {
564 if (ports[portid] >= nb_ports) {
565 printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
566 ports[portid], (nb_ports - 1));
567 ports[portid] = INVALID_PORT_ID;
571 return valid_num_ports;
574 /* Main function, does initialisation and calls the per-lcore functions */
576 MAIN(int argc, char *argv[])
578 struct rte_mempool *mbuf_pool;
579 unsigned lcore_id, core_id = 0;
581 unsigned nb_ports, valid_num_ports;
584 #ifndef RTE_EXEC_ENV_BAREMETAL
585 signal(SIGHUP, sighup_handler);
589 ret = rte_eal_init(argc, argv);
591 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
595 /* parse app arguments */
596 ret = vmdq_parse_args(argc, argv);
598 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
600 if (rte_eal_pci_probe() != 0)
601 rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n");
603 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++)
604 if (rte_lcore_is_enabled(lcore_id))
605 lcore_ids[core_id ++] = lcore_id;
607 if (rte_lcore_count() > RTE_MAX_LCORE)
608 rte_exit(EXIT_FAILURE,"Not enough cores\n");
610 nb_ports = rte_eth_dev_count();
611 if (nb_ports > RTE_MAX_ETHPORTS)
612 nb_ports = RTE_MAX_ETHPORTS;
615 * Update the global var NUM_PORTS and global array PORTS
616 * and get value of var VALID_NUM_PORTS according to system ports number
618 valid_num_ports = check_ports_num(nb_ports);
620 if (valid_num_ports < 2 || valid_num_ports % 2) {
621 printf("Current valid ports number is %u\n", valid_num_ports);
622 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
625 mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS_PER_PORT * nb_ports,
626 MBUF_SIZE, MBUF_CACHE_SIZE,
627 sizeof(struct rte_pktmbuf_pool_private),
628 rte_pktmbuf_pool_init, NULL,
629 rte_pktmbuf_init, NULL,
631 if (mbuf_pool == NULL)
632 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
634 /* initialize all ports */
635 for (portid = 0; portid < nb_ports; portid++) {
636 /* skip ports that are not enabled */
637 if ((enabled_port_mask & (1 << portid)) == 0) {
638 printf("\nSkipping disabled port %d\n", portid);
641 if (port_init(portid, mbuf_pool) != 0)
642 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
645 /* call lcore_main() on every lcore */
646 rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER);
647 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
648 if (rte_eal_wait_lcore(lcore_id) < 0)