4 * Copyright(c) 2010-2013 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,
136 * These default values are optimized for use with the Intel(R) 82599 10 GbE
137 * Controller and the DPDK ixgbe/igb PMD. Consider using other values for other
138 * network controllers and/or network drivers.
140 static const struct rte_eth_txconf tx_conf_default = {
142 .pthresh = TX_PTHRESH,
143 .hthresh = TX_HTHRESH,
144 .wthresh = TX_WTHRESH,
146 .tx_free_thresh = 0, /* Use PMD default values */
147 .tx_rs_thresh = 0, /* Use PMD default values */
150 /* empty vmdq configuration structure. Filled in programatically */
151 static const struct rte_eth_conf vmdq_conf_default = {
153 .mq_mode = ETH_MQ_RX_VMDQ_ONLY,
155 .header_split = 0, /**< Header Split disabled */
156 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
157 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
158 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
162 .mq_mode = ETH_MQ_TX_NONE,
166 * should be overridden separately in code with
170 .nb_queue_pools = ETH_8_POOLS,
171 .enable_default_pool = 0,
174 .pool_map = {{0, 0},},
179 static unsigned lcore_ids[RTE_MAX_LCORE];
180 static uint8_t ports[RTE_MAX_ETHPORTS];
181 static unsigned num_ports = 0; /**< The number of ports specified in command line */
183 /* array used for printing out statistics */
184 volatile unsigned long rxPackets[ MAX_QUEUES ] = {0};
186 const uint16_t vlan_tags[] = {
187 0, 1, 2, 3, 4, 5, 6, 7,
188 8, 9, 10, 11, 12, 13, 14, 15,
189 16, 17, 18, 19, 20, 21, 22, 23,
190 24, 25, 26, 27, 28, 29, 30, 31,
191 32, 33, 34, 35, 36, 37, 38, 39,
192 40, 41, 42, 43, 44, 45, 46, 47,
193 48, 49, 50, 51, 52, 53, 54, 55,
194 56, 57, 58, 59, 60, 61, 62, 63,
197 /* ethernet addresses of ports */
198 static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
200 #define MAX_QUEUE_NUM_10G 128
201 #define MAX_QUEUE_NUM_1G 8
202 #define MAX_POOL_MAP_NUM_10G 64
203 #define MAX_POOL_MAP_NUM_1G 32
204 #define MAX_POOL_NUM_10G 64
205 #define MAX_POOL_NUM_1G 8
206 /* Builds up the correct configuration for vmdq based on the vlan tags array
207 * given above, and determine the queue number and pool map number according to valid pool number */
209 get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools)
211 struct rte_eth_vmdq_rx_conf conf;
214 conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
215 conf.enable_default_pool = 0;
216 conf.default_pool = 0; /* set explicit value, even if not used */
218 /* For 10G NIC like 82599, 128 is valid for queue number */
219 case MAX_POOL_NUM_10G:
220 num_queues = MAX_QUEUE_NUM_10G;
221 conf.nb_pool_maps = MAX_POOL_MAP_NUM_10G;
223 /* For 1G NIC like i350, 82580 and 82576, 8 is valid for queue number */
224 case MAX_POOL_NUM_1G:
225 num_queues = MAX_QUEUE_NUM_1G;
226 conf.nb_pool_maps = MAX_POOL_MAP_NUM_1G;
232 for (i = 0; i < conf.nb_pool_maps; i++){
233 conf.pool_map[i].vlan_id = vlan_tags[ i ];
234 conf.pool_map[i].pools = (1UL << (i % num_pools));
237 (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
238 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf,
239 sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
244 * Validate the pool number accrording to the max pool number gotten form dev_info
245 * If the pool number is invalid, give the error message and return -1
248 validate_num_pools(uint32_t max_nb_pools)
250 if (num_pools > max_nb_pools) {
251 printf("invalid number of pools\n");
255 switch (max_nb_pools) {
256 /* For 10G NIC like 82599, 64 is valid for pool number */
257 case MAX_POOL_NUM_10G:
258 if (num_pools != MAX_POOL_NUM_10G) {
259 printf("invalid number of pools\n");
263 /* For 1G NIC like i350, 82580 and 82576, 8 is valid for pool number */
264 case MAX_POOL_NUM_1G:
265 if (num_pools != MAX_POOL_NUM_1G) {
266 printf("invalid number of pools\n");
278 * Initialises a given port using global settings and with the rx buffers
279 * coming from the mbuf_pool passed as parameter
282 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
284 struct rte_eth_dev_info dev_info;
285 struct rte_eth_conf port_conf;
286 uint16_t rxRings, txRings = (uint16_t)rte_lcore_count();
287 const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT, txRingSize = RTE_TEST_TX_DESC_DEFAULT;
290 uint32_t max_nb_pools;
292 /* The max pool number from dev_info will be used to validate the pool number specified in cmd line */
293 rte_eth_dev_info_get (port, &dev_info);
294 max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
295 retval = validate_num_pools(max_nb_pools);
299 retval = get_eth_conf(&port_conf, num_pools);
303 if (port >= rte_eth_dev_count()) return -1;
305 rxRings = (uint16_t)num_queues,
306 retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
310 for (q = 0; q < rxRings; q ++) {
311 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
312 rte_eth_dev_socket_id(port), &rx_conf_default,
318 for (q = 0; q < txRings; q ++) {
319 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
320 rte_eth_dev_socket_id(port), &tx_conf_default);
325 retval = rte_eth_dev_start(port);
329 rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
330 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
331 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
333 vmdq_ports_eth_addr[port].addr_bytes[0],
334 vmdq_ports_eth_addr[port].addr_bytes[1],
335 vmdq_ports_eth_addr[port].addr_bytes[2],
336 vmdq_ports_eth_addr[port].addr_bytes[3],
337 vmdq_ports_eth_addr[port].addr_bytes[4],
338 vmdq_ports_eth_addr[port].addr_bytes[5]);
343 /* Check num_pools parameter and set it if OK*/
345 vmdq_parse_num_pools(const char *q_arg)
350 /* parse number string */
351 n = strtol(q_arg, &end, 10);
352 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
362 parse_portmask(const char *portmask)
367 /* parse hexadecimal string */
368 pm = strtoul(portmask, &end, 16);
369 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
380 vmdq_usage(const char *prgname)
382 printf("%s [EAL options] -- -p PORTMASK]\n"
383 " --nb-pools NP: number of pools\n",
387 /* Parse the argument (num_pools) given in the command line of the application */
389 vmdq_parse_args(int argc, char **argv)
394 const char *prgname = argv[0];
395 static struct option long_option[] = {
396 {"nb-pools", required_argument, NULL, 0},
400 /* Parse command line */
401 while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
405 enabled_port_mask = parse_portmask(optarg);
406 if (enabled_port_mask == 0) {
407 printf("invalid portmask\n");
413 if (vmdq_parse_num_pools(optarg) == -1){
414 printf("invalid number of pools\n");
426 for(i = 0; i < RTE_MAX_ETHPORTS; i++) {
427 if (enabled_port_mask & (1 << i))
428 ports[num_ports++] = (uint8_t)i;
431 if (num_ports < 2 || num_ports % 2) {
432 printf("Current enabled port number is %u,"
433 "but it should be even and at least 2\n",num_ports);
441 update_mac_address(struct rte_mbuf *m, unsigned dst_port)
443 struct ether_hdr *eth;
446 eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
448 /* 02:00:00:00:00:xx */
449 tmp = ð->d_addr.addr_bytes[0];
450 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
453 ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr);
456 #ifndef RTE_EXEC_ENV_BAREMETAL
457 /* When we receive a HUP signal, print out our stats */
459 sighup_handler(int signum)
462 for (q = 0; q < num_queues; q ++) {
463 if (q % (num_queues/num_pools) == 0)
464 printf("\nPool %u: ", q/(num_queues/num_pools));
465 printf("%lu ", rxPackets[ q ]);
467 printf("\nFinished handling signal %d\n", signum);
472 * Main thread that does the work, reading from INPUT_PORT
473 * and writing to OUTPUT_PORT
475 static __attribute__((noreturn)) int
476 lcore_main(__attribute__((__unused__)) void* dummy)
478 const uint16_t lcore_id = (uint16_t)rte_lcore_id();
479 const uint16_t num_cores = (uint16_t)rte_lcore_count();
480 uint16_t core_id = 0;
481 uint16_t startQueue, endQueue;
483 const uint16_t remainder = (uint16_t)(num_queues % num_cores);
485 for (i = 0; i < num_cores; i ++)
486 if (lcore_ids[i] == lcore_id) {
491 if (remainder != 0) {
492 if (core_id < remainder) {
493 startQueue = (uint16_t)(core_id * (num_queues/num_cores + 1));
494 endQueue = (uint16_t)(startQueue + (num_queues/num_cores) + 1);
496 startQueue = (uint16_t)(core_id * (num_queues/num_cores) + remainder);
497 endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
500 startQueue = (uint16_t)(core_id * (num_queues/num_cores));
501 endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
504 printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id,
505 (unsigned)lcore_id, startQueue, endQueue - 1);
508 struct rte_mbuf *buf[MAX_PKT_BURST];
509 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
511 for (p = 0; p < num_ports; p++) {
512 const uint8_t sport = ports[p];
513 const uint8_t dport = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
515 if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID))
518 for (q = startQueue; q < endQueue; q++) {
519 const uint16_t rxCount = rte_eth_rx_burst(sport,
522 if (unlikely(rxCount == 0))
525 rxPackets[q] += rxCount;
527 for (i = 0; i < rxCount; i++)
528 update_mac_address(buf[i], dport);
530 const uint16_t txCount = rte_eth_tx_burst(dport,
531 lcore_id, buf, rxCount);
533 if (txCount != rxCount) {
534 for (i = txCount; i < rxCount; i++)
535 rte_pktmbuf_free(buf[i]);
543 * Update the global var NUM_PORTS and array PORTS according to system ports number
544 * and return valid ports number
546 static unsigned check_ports_num(unsigned nb_ports)
548 unsigned valid_num_ports = num_ports;
551 if (num_ports > nb_ports) {
552 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
553 num_ports, nb_ports);
554 num_ports = nb_ports;
557 for (portid = 0; portid < num_ports; portid ++) {
558 if (ports[portid] >= nb_ports) {
559 printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
560 ports[portid], (nb_ports - 1));
561 ports[portid] = INVALID_PORT_ID;
565 return valid_num_ports;
568 /* Main function, does initialisation and calls the per-lcore functions */
570 MAIN(int argc, char *argv[])
572 struct rte_mempool *mbuf_pool;
573 unsigned lcore_id, core_id = 0;
575 unsigned nb_ports, valid_num_ports;
578 #ifndef RTE_EXEC_ENV_BAREMETAL
579 signal(SIGHUP, sighup_handler);
583 ret = rte_eal_init(argc, argv);
585 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
589 /* parse app arguments */
590 ret = vmdq_parse_args(argc, argv);
592 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
594 if (rte_pmd_init_all() != 0 || rte_eal_pci_probe() != 0)
595 rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n");
597 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++)
598 if (rte_lcore_is_enabled(lcore_id))
599 lcore_ids[core_id ++] = lcore_id;
601 if (rte_lcore_count() > RTE_MAX_LCORE)
602 rte_exit(EXIT_FAILURE,"Not enough cores\n");
604 nb_ports = rte_eth_dev_count();
605 if (nb_ports > RTE_MAX_ETHPORTS)
606 nb_ports = RTE_MAX_ETHPORTS;
609 * Update the global var NUM_PORTS and global array PORTS
610 * and get value of var VALID_NUM_PORTS according to system ports number
612 valid_num_ports = check_ports_num(nb_ports);
614 if (valid_num_ports < 2 || valid_num_ports % 2) {
615 printf("Current valid ports number is %u\n", valid_num_ports);
616 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
619 mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS_PER_PORT * nb_ports,
620 MBUF_SIZE, MBUF_CACHE_SIZE,
621 sizeof(struct rte_pktmbuf_pool_private),
622 rte_pktmbuf_pool_init, NULL,
623 rte_pktmbuf_init, NULL,
625 if (mbuf_pool == NULL)
626 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
628 /* initialize all ports */
629 for (portid = 0; portid < nb_ports; portid++) {
630 /* skip ports that are not enabled */
631 if ((enabled_port_mask & (1 << portid)) == 0) {
632 printf("\nSkipping disabled port %d\n", portid);
635 if (port_init(portid, mbuf_pool) != 0)
636 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
639 /* call lcore_main() on every lcore */
640 rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER);
641 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
642 if (rte_eal_wait_lcore(lcore_id) < 0)