1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
17 #include <rte_common.h>
19 #include <rte_memory.h>
20 #include <rte_memcpy.h>
22 #include <rte_launch.h>
23 #include <rte_atomic.h>
24 #include <rte_cycles.h>
25 #include <rte_prefetch.h>
26 #include <rte_lcore.h>
27 #include <rte_per_lcore.h>
28 #include <rte_branch_prediction.h>
29 #include <rte_interrupts.h>
30 #include <rte_random.h>
31 #include <rte_debug.h>
32 #include <rte_ether.h>
33 #include <rte_ethdev.h>
34 #include <rte_mempool.h>
37 #define MAX_QUEUES 1024
39 * 1024 queues require to meet the needs of a large number of vmdq_pools.
40 * (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port.
42 #define NUM_MBUFS_PER_PORT (MAX_QUEUES * RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, \
43 RTE_TEST_TX_DESC_DEFAULT))
44 #define MBUF_CACHE_SIZE 64
46 #define MAX_PKT_BURST 32
49 * Configurable number of RX/TX ring descriptors
51 #define RTE_TEST_RX_DESC_DEFAULT 1024
52 #define RTE_TEST_TX_DESC_DEFAULT 1024
54 #define INVALID_PORT_ID 0xFF
56 /* mask of enabled ports */
57 static uint32_t enabled_port_mask;
59 /* number of pools (if user does not specify any, 8 by default */
60 static uint32_t num_queues = 8;
61 static uint32_t num_pools = 8;
63 /* empty vmdq configuration structure. Filled in programatically */
64 static const struct rte_eth_conf vmdq_conf_default = {
66 .mq_mode = ETH_MQ_RX_VMDQ_ONLY,
68 .ignore_offload_bitfield = 1,
72 .mq_mode = ETH_MQ_TX_NONE,
76 * should be overridden separately in code with
80 .nb_queue_pools = ETH_8_POOLS,
81 .enable_default_pool = 0,
84 .pool_map = {{0, 0},},
89 static unsigned lcore_ids[RTE_MAX_LCORE];
90 static uint16_t ports[RTE_MAX_ETHPORTS];
91 static unsigned num_ports; /**< The number of ports specified in command line */
93 /* array used for printing out statistics */
94 volatile unsigned long rxPackets[MAX_QUEUES] = {0};
96 const uint16_t vlan_tags[] = {
97 0, 1, 2, 3, 4, 5, 6, 7,
98 8, 9, 10, 11, 12, 13, 14, 15,
99 16, 17, 18, 19, 20, 21, 22, 23,
100 24, 25, 26, 27, 28, 29, 30, 31,
101 32, 33, 34, 35, 36, 37, 38, 39,
102 40, 41, 42, 43, 44, 45, 46, 47,
103 48, 49, 50, 51, 52, 53, 54, 55,
104 56, 57, 58, 59, 60, 61, 62, 63,
106 const uint16_t num_vlans = RTE_DIM(vlan_tags);
107 static uint16_t num_pf_queues, num_vmdq_queues;
108 static uint16_t vmdq_pool_base, vmdq_queue_base;
109 /* pool mac addr template, pool mac addr is like: 52 54 00 12 port# pool# */
110 static struct ether_addr pool_addr_template = {
111 .addr_bytes = {0x52, 0x54, 0x00, 0x12, 0x00, 0x00}
114 /* ethernet addresses of ports */
115 static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
117 #define MAX_QUEUE_NUM_10G 128
118 #define MAX_QUEUE_NUM_1G 8
119 #define MAX_POOL_MAP_NUM_10G 64
120 #define MAX_POOL_MAP_NUM_1G 32
121 #define MAX_POOL_NUM_10G 64
122 #define MAX_POOL_NUM_1G 8
124 * Builds up the correct configuration for vmdq based on the vlan tags array
125 * given above, and determine the queue number and pool map number according to
129 get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools)
131 struct rte_eth_vmdq_rx_conf conf;
134 conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
135 conf.nb_pool_maps = num_pools;
136 conf.enable_default_pool = 0;
137 conf.default_pool = 0; /* set explicit value, even if not used */
139 for (i = 0; i < conf.nb_pool_maps; i++) {
140 conf.pool_map[i].vlan_id = vlan_tags[i];
141 conf.pool_map[i].pools = (1UL << (i % num_pools));
144 (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
145 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf,
146 sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
151 * Initialises a given port using global settings and with the rx buffers
152 * coming from the mbuf_pool passed as parameter
155 port_init(uint16_t port, struct rte_mempool *mbuf_pool)
157 struct rte_eth_dev_info dev_info;
158 struct rte_eth_rxconf *rxconf;
159 struct rte_eth_txconf *txconf;
160 struct rte_eth_conf port_conf;
161 uint16_t rxRings, txRings;
162 uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT;
163 uint16_t txRingSize = RTE_TEST_TX_DESC_DEFAULT;
166 uint16_t queues_per_pool;
167 uint32_t max_nb_pools;
170 * The max pool number from dev_info will be used to validate the pool
171 * number specified in cmd line
173 rte_eth_dev_info_get(port, &dev_info);
174 max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
176 * We allow to process part of VMDQ pools specified by num_pools in
179 if (num_pools > max_nb_pools) {
180 printf("num_pools %d >max_nb_pools %d\n",
181 num_pools, max_nb_pools);
184 retval = get_eth_conf(&port_conf, max_nb_pools);
189 * NIC queues are divided into pf queues and vmdq queues.
191 /* There is assumption here all ports have the same configuration! */
192 num_pf_queues = dev_info.max_rx_queues - dev_info.vmdq_queue_num;
193 queues_per_pool = dev_info.vmdq_queue_num / dev_info.max_vmdq_pools;
194 num_vmdq_queues = num_pools * queues_per_pool;
195 num_queues = num_pf_queues + num_vmdq_queues;
196 vmdq_queue_base = dev_info.vmdq_queue_base;
197 vmdq_pool_base = dev_info.vmdq_pool_base;
199 printf("pf queue num: %u, configured vmdq pool num: %u,"
200 " each vmdq pool has %u queues\n",
201 num_pf_queues, num_pools, queues_per_pool);
202 printf("vmdq queue base: %d pool base %d\n",
203 vmdq_queue_base, vmdq_pool_base);
204 if (!rte_eth_dev_is_valid_port(port))
208 * Though in this example, we only receive packets from the first queue
209 * of each pool and send packets through first rte_lcore_count() tx
210 * queues of vmdq queues, all queues including pf queues are setup.
211 * This is because VMDQ queues doesn't always start from zero, and the
212 * PMD layer doesn't support selectively initialising part of rx/tx
215 rxRings = (uint16_t)dev_info.max_rx_queues;
216 txRings = (uint16_t)dev_info.max_tx_queues;
218 rte_eth_dev_info_get(port, &dev_info);
219 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
220 port_conf.txmode.offloads |=
221 DEV_TX_OFFLOAD_MBUF_FAST_FREE;
222 retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
226 retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &rxRingSize,
230 if (RTE_MAX(rxRingSize, txRingSize) > RTE_MAX(RTE_TEST_RX_DESC_DEFAULT,
231 RTE_TEST_TX_DESC_DEFAULT)) {
232 printf("Mbuf pool has an insufficient size for port %u.\n",
237 rxconf = &dev_info.default_rxconf;
238 rxconf->rx_drop_en = 1;
239 txconf = &dev_info.default_txconf;
240 txconf->txq_flags = ETH_TXQ_FLAGS_IGNORE;
241 txconf->offloads = port_conf.txmode.offloads;
242 for (q = 0; q < rxRings; q++) {
243 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
244 rte_eth_dev_socket_id(port),
248 printf("initialise rx queue %d failed\n", q);
253 for (q = 0; q < txRings; q++) {
254 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
255 rte_eth_dev_socket_id(port),
258 printf("initialise tx queue %d failed\n", q);
263 retval = rte_eth_dev_start(port);
265 printf("port %d start failed\n", port);
269 rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
270 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
271 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
273 vmdq_ports_eth_addr[port].addr_bytes[0],
274 vmdq_ports_eth_addr[port].addr_bytes[1],
275 vmdq_ports_eth_addr[port].addr_bytes[2],
276 vmdq_ports_eth_addr[port].addr_bytes[3],
277 vmdq_ports_eth_addr[port].addr_bytes[4],
278 vmdq_ports_eth_addr[port].addr_bytes[5]);
281 * Set mac for each pool.
282 * There is no default mac for the pools in i40.
283 * Removes this after i40e fixes this issue.
285 for (q = 0; q < num_pools; q++) {
286 struct ether_addr mac;
287 mac = pool_addr_template;
288 mac.addr_bytes[4] = port;
289 mac.addr_bytes[5] = q;
290 printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n",
292 mac.addr_bytes[0], mac.addr_bytes[1],
293 mac.addr_bytes[2], mac.addr_bytes[3],
294 mac.addr_bytes[4], mac.addr_bytes[5]);
295 retval = rte_eth_dev_mac_addr_add(port, &mac,
298 printf("mac addr add failed at pool %d\n", q);
306 /* Check num_pools parameter and set it if OK*/
308 vmdq_parse_num_pools(const char *q_arg)
313 /* parse number string */
314 n = strtol(q_arg, &end, 10);
315 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
318 if (num_pools > num_vlans) {
319 printf("num_pools %d > num_vlans %d\n", num_pools, num_vlans);
330 parse_portmask(const char *portmask)
335 /* parse hexadecimal string */
336 pm = strtoul(portmask, &end, 16);
337 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
348 vmdq_usage(const char *prgname)
350 printf("%s [EAL options] -- -p PORTMASK]\n"
351 " --nb-pools NP: number of pools\n",
355 /* Parse the argument (num_pools) given in the command line of the application */
357 vmdq_parse_args(int argc, char **argv)
362 const char *prgname = argv[0];
363 static struct option long_option[] = {
364 {"nb-pools", required_argument, NULL, 0},
368 /* Parse command line */
369 while ((opt = getopt_long(argc, argv, "p:", long_option,
370 &option_index)) != EOF) {
374 enabled_port_mask = parse_portmask(optarg);
375 if (enabled_port_mask == 0) {
376 printf("invalid portmask\n");
382 if (vmdq_parse_num_pools(optarg) == -1) {
383 printf("invalid number of pools\n");
395 for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
396 if (enabled_port_mask & (1 << i))
397 ports[num_ports++] = (uint8_t)i;
400 if (num_ports < 2 || num_ports % 2) {
401 printf("Current enabled port number is %u,"
402 "but it should be even and at least 2\n", num_ports);
410 update_mac_address(struct rte_mbuf *m, unsigned dst_port)
412 struct ether_hdr *eth;
415 eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
417 /* 02:00:00:00:00:xx */
418 tmp = ð->d_addr.addr_bytes[0];
419 *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
422 ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr);
425 /* When we receive a HUP signal, print out our stats */
427 sighup_handler(int signum)
430 for (q = 0; q < num_queues; q++) {
431 if (q % (num_queues/num_pools) == 0)
432 printf("\nPool %u: ", q/(num_queues/num_pools));
433 printf("%lu ", rxPackets[q]);
435 printf("\nFinished handling signal %d\n", signum);
439 * Main thread that does the work, reading from INPUT_PORT
440 * and writing to OUTPUT_PORT
443 lcore_main(__attribute__((__unused__)) void *dummy)
445 const uint16_t lcore_id = (uint16_t)rte_lcore_id();
446 const uint16_t num_cores = (uint16_t)rte_lcore_count();
447 uint16_t core_id = 0;
448 uint16_t startQueue, endQueue;
450 const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores);
452 for (i = 0; i < num_cores; i++)
453 if (lcore_ids[i] == lcore_id) {
458 if (remainder != 0) {
459 if (core_id < remainder) {
460 startQueue = (uint16_t)(core_id *
461 (num_vmdq_queues / num_cores + 1));
462 endQueue = (uint16_t)(startQueue +
463 (num_vmdq_queues / num_cores) + 1);
465 startQueue = (uint16_t)(core_id *
466 (num_vmdq_queues / num_cores) +
468 endQueue = (uint16_t)(startQueue +
469 (num_vmdq_queues / num_cores));
472 startQueue = (uint16_t)(core_id *
473 (num_vmdq_queues / num_cores));
474 endQueue = (uint16_t)(startQueue +
475 (num_vmdq_queues / num_cores));
478 /* vmdq queue idx doesn't always start from zero.*/
479 startQueue += vmdq_queue_base;
480 endQueue += vmdq_queue_base;
481 printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id,
482 (unsigned)lcore_id, startQueue, endQueue - 1);
484 if (startQueue == endQueue) {
485 printf("lcore %u has nothing to do\n", lcore_id);
490 struct rte_mbuf *buf[MAX_PKT_BURST];
491 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
493 for (p = 0; p < num_ports; p++) {
494 const uint8_t sport = ports[p];
495 /* 0 <-> 1, 2 <-> 3 etc */
496 const uint8_t dport = ports[p ^ 1];
497 if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID))
500 for (q = startQueue; q < endQueue; q++) {
501 const uint16_t rxCount = rte_eth_rx_burst(sport,
504 if (unlikely(rxCount == 0))
507 rxPackets[q] += rxCount;
509 for (i = 0; i < rxCount; i++)
510 update_mac_address(buf[i], dport);
512 const uint16_t txCount = rte_eth_tx_burst(dport,
513 vmdq_queue_base + core_id,
517 if (txCount != rxCount) {
518 for (i = txCount; i < rxCount; i++)
519 rte_pktmbuf_free(buf[i]);
527 * Update the global var NUM_PORTS and array PORTS according to system ports number
528 * and return valid ports number
530 static unsigned check_ports_num(unsigned nb_ports)
532 unsigned valid_num_ports = num_ports;
535 if (num_ports > nb_ports) {
536 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
537 num_ports, nb_ports);
538 num_ports = nb_ports;
541 for (portid = 0; portid < num_ports; portid++) {
542 if (!rte_eth_dev_is_valid_port(ports[portid])) {
543 printf("\nSpecified port ID(%u) is not valid\n",
545 ports[portid] = INVALID_PORT_ID;
549 return valid_num_ports;
552 /* Main function, does initialisation and calls the per-lcore functions */
554 main(int argc, char *argv[])
556 struct rte_mempool *mbuf_pool;
557 unsigned lcore_id, core_id = 0;
559 unsigned nb_ports, valid_num_ports;
562 signal(SIGHUP, sighup_handler);
565 ret = rte_eal_init(argc, argv);
567 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
571 /* parse app arguments */
572 ret = vmdq_parse_args(argc, argv);
574 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
576 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
577 if (rte_lcore_is_enabled(lcore_id))
578 lcore_ids[core_id++] = lcore_id;
580 if (rte_lcore_count() > RTE_MAX_LCORE)
581 rte_exit(EXIT_FAILURE, "Not enough cores\n");
583 nb_ports = rte_eth_dev_count_avail();
586 * Update the global var NUM_PORTS and global array PORTS
587 * and get value of var VALID_NUM_PORTS according to system ports number
589 valid_num_ports = check_ports_num(nb_ports);
591 if (valid_num_ports < 2 || valid_num_ports % 2) {
592 printf("Current valid ports number is %u\n", valid_num_ports);
593 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
596 mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
597 NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE,
598 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
599 if (mbuf_pool == NULL)
600 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
602 /* initialize all ports */
603 RTE_ETH_FOREACH_DEV(portid) {
604 /* skip ports that are not enabled */
605 if ((enabled_port_mask & (1 << portid)) == 0) {
606 printf("\nSkipping disabled port %d\n", portid);
609 if (port_init(portid, mbuf_pool) != 0)
610 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
613 /* call lcore_main() on every lcore */
614 rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER);
615 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
616 if (rte_eal_wait_lcore(lcore_id) < 0)