1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606 * Copyright(c) 2010-2014 Intel Corporation
3a9643ea8Slogwang */
4a9643ea8Slogwang
5a9643ea8Slogwang #include <stdint.h>
6a9643ea8Slogwang #include <sys/queue.h>
7a9643ea8Slogwang #include <stdlib.h>
8a9643ea8Slogwang #include <string.h>
9a9643ea8Slogwang #include <stdio.h>
10a9643ea8Slogwang #include <assert.h>
11a9643ea8Slogwang #include <errno.h>
12a9643ea8Slogwang #include <signal.h>
13a9643ea8Slogwang #include <stdarg.h>
14a9643ea8Slogwang #include <inttypes.h>
15a9643ea8Slogwang #include <getopt.h>
16a9643ea8Slogwang
17a9643ea8Slogwang #include <rte_common.h>
18a9643ea8Slogwang #include <rte_log.h>
19a9643ea8Slogwang #include <rte_memory.h>
20a9643ea8Slogwang #include <rte_memcpy.h>
21a9643ea8Slogwang #include <rte_eal.h>
22a9643ea8Slogwang #include <rte_launch.h>
23a9643ea8Slogwang #include <rte_atomic.h>
24a9643ea8Slogwang #include <rte_cycles.h>
25a9643ea8Slogwang #include <rte_prefetch.h>
26a9643ea8Slogwang #include <rte_lcore.h>
27a9643ea8Slogwang #include <rte_per_lcore.h>
28a9643ea8Slogwang #include <rte_branch_prediction.h>
29a9643ea8Slogwang #include <rte_interrupts.h>
30a9643ea8Slogwang #include <rte_random.h>
31a9643ea8Slogwang #include <rte_debug.h>
32a9643ea8Slogwang #include <rte_ether.h>
33a9643ea8Slogwang #include <rte_ethdev.h>
34a9643ea8Slogwang #include <rte_mempool.h>
35a9643ea8Slogwang #include <rte_mbuf.h>
36a9643ea8Slogwang
37a9643ea8Slogwang #define MAX_QUEUES 1024
38a9643ea8Slogwang /*
39a9643ea8Slogwang * 1024 queues require to meet the needs of a large number of vmdq_pools.
40a9643ea8Slogwang * (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port.
41a9643ea8Slogwang */
42a9643ea8Slogwang #define NUM_MBUFS_PER_PORT (MAX_QUEUES * RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, \
43a9643ea8Slogwang RTE_TEST_TX_DESC_DEFAULT))
44a9643ea8Slogwang #define MBUF_CACHE_SIZE 64
45a9643ea8Slogwang
46a9643ea8Slogwang #define MAX_PKT_BURST 32
47a9643ea8Slogwang
48a9643ea8Slogwang /*
49a9643ea8Slogwang * Configurable number of RX/TX ring descriptors
50a9643ea8Slogwang */
51d30ea906Sjfb8856606 #define RTE_TEST_RX_DESC_DEFAULT 1024
52d30ea906Sjfb8856606 #define RTE_TEST_TX_DESC_DEFAULT 1024
53a9643ea8Slogwang
54a9643ea8Slogwang #define INVALID_PORT_ID 0xFF
55a9643ea8Slogwang
56a9643ea8Slogwang /* mask of enabled ports */
57a9643ea8Slogwang static uint32_t enabled_port_mask;
58a9643ea8Slogwang
59a9643ea8Slogwang /* number of pools (if user does not specify any, 8 by default */
60a9643ea8Slogwang static uint32_t num_queues = 8;
61a9643ea8Slogwang static uint32_t num_pools = 8;
620c6bd470Sfengbojiang static uint8_t rss_enable;
63a9643ea8Slogwang
64a9643ea8Slogwang /* empty vmdq configuration structure. Filled in programatically */
65a9643ea8Slogwang static const struct rte_eth_conf vmdq_conf_default = {
66a9643ea8Slogwang .rxmode = {
67a9643ea8Slogwang .mq_mode = ETH_MQ_RX_VMDQ_ONLY,
68a9643ea8Slogwang .split_hdr_size = 0,
69a9643ea8Slogwang },
70a9643ea8Slogwang
71a9643ea8Slogwang .txmode = {
72a9643ea8Slogwang .mq_mode = ETH_MQ_TX_NONE,
73a9643ea8Slogwang },
74a9643ea8Slogwang .rx_adv_conf = {
75a9643ea8Slogwang /*
76a9643ea8Slogwang * should be overridden separately in code with
77a9643ea8Slogwang * appropriate values
78a9643ea8Slogwang */
79a9643ea8Slogwang .vmdq_rx_conf = {
80a9643ea8Slogwang .nb_queue_pools = ETH_8_POOLS,
81a9643ea8Slogwang .enable_default_pool = 0,
82a9643ea8Slogwang .default_pool = 0,
83a9643ea8Slogwang .nb_pool_maps = 0,
84a9643ea8Slogwang .pool_map = {{0, 0},},
85a9643ea8Slogwang },
86a9643ea8Slogwang },
87a9643ea8Slogwang };
88a9643ea8Slogwang
89a9643ea8Slogwang static unsigned lcore_ids[RTE_MAX_LCORE];
902bfe3f2eSlogwang static uint16_t ports[RTE_MAX_ETHPORTS];
91a9643ea8Slogwang static unsigned num_ports; /**< The number of ports specified in command line */
92a9643ea8Slogwang
93a9643ea8Slogwang /* array used for printing out statistics */
94a9643ea8Slogwang volatile unsigned long rxPackets[MAX_QUEUES] = {0};
95a9643ea8Slogwang
96a9643ea8Slogwang const uint16_t vlan_tags[] = {
97a9643ea8Slogwang 0, 1, 2, 3, 4, 5, 6, 7,
98a9643ea8Slogwang 8, 9, 10, 11, 12, 13, 14, 15,
99a9643ea8Slogwang 16, 17, 18, 19, 20, 21, 22, 23,
100a9643ea8Slogwang 24, 25, 26, 27, 28, 29, 30, 31,
101a9643ea8Slogwang 32, 33, 34, 35, 36, 37, 38, 39,
102a9643ea8Slogwang 40, 41, 42, 43, 44, 45, 46, 47,
103a9643ea8Slogwang 48, 49, 50, 51, 52, 53, 54, 55,
104a9643ea8Slogwang 56, 57, 58, 59, 60, 61, 62, 63,
105a9643ea8Slogwang };
106a9643ea8Slogwang const uint16_t num_vlans = RTE_DIM(vlan_tags);
107a9643ea8Slogwang static uint16_t num_pf_queues, num_vmdq_queues;
108a9643ea8Slogwang static uint16_t vmdq_pool_base, vmdq_queue_base;
109a9643ea8Slogwang /* pool mac addr template, pool mac addr is like: 52 54 00 12 port# pool# */
1104418919fSjohnjiang static struct rte_ether_addr pool_addr_template = {
111a9643ea8Slogwang .addr_bytes = {0x52, 0x54, 0x00, 0x12, 0x00, 0x00}
112a9643ea8Slogwang };
113a9643ea8Slogwang
114a9643ea8Slogwang /* ethernet addresses of ports */
1154418919fSjohnjiang static struct rte_ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
116a9643ea8Slogwang
117a9643ea8Slogwang #define MAX_QUEUE_NUM_10G 128
118a9643ea8Slogwang #define MAX_QUEUE_NUM_1G 8
119a9643ea8Slogwang #define MAX_POOL_MAP_NUM_10G 64
120a9643ea8Slogwang #define MAX_POOL_MAP_NUM_1G 32
121a9643ea8Slogwang #define MAX_POOL_NUM_10G 64
122a9643ea8Slogwang #define MAX_POOL_NUM_1G 8
123a9643ea8Slogwang /*
124a9643ea8Slogwang * Builds up the correct configuration for vmdq based on the vlan tags array
125a9643ea8Slogwang * given above, and determine the queue number and pool map number according to
126a9643ea8Slogwang * valid pool number
127a9643ea8Slogwang */
128a9643ea8Slogwang static inline int
get_eth_conf(struct rte_eth_conf * eth_conf,uint32_t num_pools)129a9643ea8Slogwang get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools)
130a9643ea8Slogwang {
131a9643ea8Slogwang struct rte_eth_vmdq_rx_conf conf;
132a9643ea8Slogwang unsigned i;
133a9643ea8Slogwang
134a9643ea8Slogwang conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
135a9643ea8Slogwang conf.nb_pool_maps = num_pools;
136a9643ea8Slogwang conf.enable_default_pool = 0;
137a9643ea8Slogwang conf.default_pool = 0; /* set explicit value, even if not used */
138a9643ea8Slogwang
139a9643ea8Slogwang for (i = 0; i < conf.nb_pool_maps; i++) {
140a9643ea8Slogwang conf.pool_map[i].vlan_id = vlan_tags[i];
141a9643ea8Slogwang conf.pool_map[i].pools = (1UL << (i % num_pools));
142a9643ea8Slogwang }
143a9643ea8Slogwang
144a9643ea8Slogwang (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
145a9643ea8Slogwang (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_rx_conf, &conf,
146a9643ea8Slogwang sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
1470c6bd470Sfengbojiang if (rss_enable) {
1480c6bd470Sfengbojiang eth_conf->rxmode.mq_mode = ETH_MQ_RX_VMDQ_RSS;
1490c6bd470Sfengbojiang eth_conf->rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP |
1500c6bd470Sfengbojiang ETH_RSS_UDP |
1510c6bd470Sfengbojiang ETH_RSS_TCP |
1520c6bd470Sfengbojiang ETH_RSS_SCTP;
1530c6bd470Sfengbojiang }
154a9643ea8Slogwang return 0;
155a9643ea8Slogwang }
156a9643ea8Slogwang
157a9643ea8Slogwang /*
158a9643ea8Slogwang * Initialises a given port using global settings and with the rx buffers
159a9643ea8Slogwang * coming from the mbuf_pool passed as parameter
160a9643ea8Slogwang */
161a9643ea8Slogwang static inline int
port_init(uint16_t port,struct rte_mempool * mbuf_pool)1622bfe3f2eSlogwang port_init(uint16_t port, struct rte_mempool *mbuf_pool)
163a9643ea8Slogwang {
164a9643ea8Slogwang struct rte_eth_dev_info dev_info;
165a9643ea8Slogwang struct rte_eth_rxconf *rxconf;
166d30ea906Sjfb8856606 struct rte_eth_txconf *txconf;
167a9643ea8Slogwang struct rte_eth_conf port_conf;
168a9643ea8Slogwang uint16_t rxRings, txRings;
1692bfe3f2eSlogwang uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT;
1702bfe3f2eSlogwang uint16_t txRingSize = RTE_TEST_TX_DESC_DEFAULT;
171a9643ea8Slogwang int retval;
172a9643ea8Slogwang uint16_t q;
173a9643ea8Slogwang uint16_t queues_per_pool;
174a9643ea8Slogwang uint32_t max_nb_pools;
1750c6bd470Sfengbojiang uint64_t rss_hf_tmp;
176a9643ea8Slogwang
177a9643ea8Slogwang /*
178a9643ea8Slogwang * The max pool number from dev_info will be used to validate the pool
179a9643ea8Slogwang * number specified in cmd line
180a9643ea8Slogwang */
1814418919fSjohnjiang retval = rte_eth_dev_info_get(port, &dev_info);
1824418919fSjohnjiang if (retval != 0) {
1834418919fSjohnjiang printf("Error during getting device (port %u) info: %s\n",
1844418919fSjohnjiang port, strerror(-retval));
1854418919fSjohnjiang return retval;
1864418919fSjohnjiang }
1874418919fSjohnjiang
188a9643ea8Slogwang max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
189a9643ea8Slogwang /*
190a9643ea8Slogwang * We allow to process part of VMDQ pools specified by num_pools in
191a9643ea8Slogwang * command line.
192a9643ea8Slogwang */
193a9643ea8Slogwang if (num_pools > max_nb_pools) {
194a9643ea8Slogwang printf("num_pools %d >max_nb_pools %d\n",
195a9643ea8Slogwang num_pools, max_nb_pools);
196a9643ea8Slogwang return -1;
197a9643ea8Slogwang }
198a9643ea8Slogwang retval = get_eth_conf(&port_conf, max_nb_pools);
199a9643ea8Slogwang if (retval < 0)
200a9643ea8Slogwang return retval;
201a9643ea8Slogwang
202a9643ea8Slogwang /*
203a9643ea8Slogwang * NIC queues are divided into pf queues and vmdq queues.
204a9643ea8Slogwang */
205a9643ea8Slogwang /* There is assumption here all ports have the same configuration! */
206a9643ea8Slogwang num_pf_queues = dev_info.max_rx_queues - dev_info.vmdq_queue_num;
207a9643ea8Slogwang queues_per_pool = dev_info.vmdq_queue_num / dev_info.max_vmdq_pools;
208a9643ea8Slogwang num_vmdq_queues = num_pools * queues_per_pool;
209a9643ea8Slogwang num_queues = num_pf_queues + num_vmdq_queues;
210a9643ea8Slogwang vmdq_queue_base = dev_info.vmdq_queue_base;
211a9643ea8Slogwang vmdq_pool_base = dev_info.vmdq_pool_base;
212a9643ea8Slogwang
213a9643ea8Slogwang printf("pf queue num: %u, configured vmdq pool num: %u,"
214a9643ea8Slogwang " each vmdq pool has %u queues\n",
215a9643ea8Slogwang num_pf_queues, num_pools, queues_per_pool);
216a9643ea8Slogwang printf("vmdq queue base: %d pool base %d\n",
217a9643ea8Slogwang vmdq_queue_base, vmdq_pool_base);
218d30ea906Sjfb8856606 if (!rte_eth_dev_is_valid_port(port))
219a9643ea8Slogwang return -1;
220a9643ea8Slogwang
2210c6bd470Sfengbojiang rss_hf_tmp = port_conf.rx_adv_conf.rss_conf.rss_hf;
2220c6bd470Sfengbojiang port_conf.rx_adv_conf.rss_conf.rss_hf &=
2230c6bd470Sfengbojiang dev_info.flow_type_rss_offloads;
2240c6bd470Sfengbojiang if (port_conf.rx_adv_conf.rss_conf.rss_hf != rss_hf_tmp) {
2250c6bd470Sfengbojiang printf("Port %u modified RSS hash function based on hardware support,"
2260c6bd470Sfengbojiang "requested:%#"PRIx64" configured:%#"PRIx64"\n",
2270c6bd470Sfengbojiang port,
2280c6bd470Sfengbojiang rss_hf_tmp,
2290c6bd470Sfengbojiang port_conf.rx_adv_conf.rss_conf.rss_hf);
2300c6bd470Sfengbojiang }
2310c6bd470Sfengbojiang
232a9643ea8Slogwang /*
233a9643ea8Slogwang * Though in this example, we only receive packets from the first queue
234a9643ea8Slogwang * of each pool and send packets through first rte_lcore_count() tx
235a9643ea8Slogwang * queues of vmdq queues, all queues including pf queues are setup.
236a9643ea8Slogwang * This is because VMDQ queues doesn't always start from zero, and the
237a9643ea8Slogwang * PMD layer doesn't support selectively initialising part of rx/tx
238a9643ea8Slogwang * queues.
239a9643ea8Slogwang */
240a9643ea8Slogwang rxRings = (uint16_t)dev_info.max_rx_queues;
241a9643ea8Slogwang txRings = (uint16_t)dev_info.max_tx_queues;
242d30ea906Sjfb8856606
2434418919fSjohnjiang retval = rte_eth_dev_info_get(port, &dev_info);
2444418919fSjohnjiang if (retval != 0) {
2454418919fSjohnjiang printf("Error during getting device (port %u) info: %s\n",
2464418919fSjohnjiang port, strerror(-retval));
2474418919fSjohnjiang return retval;
2484418919fSjohnjiang }
2494418919fSjohnjiang
250d30ea906Sjfb8856606 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
251d30ea906Sjfb8856606 port_conf.txmode.offloads |=
252d30ea906Sjfb8856606 DEV_TX_OFFLOAD_MBUF_FAST_FREE;
253a9643ea8Slogwang retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
254a9643ea8Slogwang if (retval != 0)
255a9643ea8Slogwang return retval;
256a9643ea8Slogwang
2572bfe3f2eSlogwang retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &rxRingSize,
2582bfe3f2eSlogwang &txRingSize);
2592bfe3f2eSlogwang if (retval != 0)
2602bfe3f2eSlogwang return retval;
2612bfe3f2eSlogwang if (RTE_MAX(rxRingSize, txRingSize) > RTE_MAX(RTE_TEST_RX_DESC_DEFAULT,
2622bfe3f2eSlogwang RTE_TEST_TX_DESC_DEFAULT)) {
2632bfe3f2eSlogwang printf("Mbuf pool has an insufficient size for port %u.\n",
2642bfe3f2eSlogwang port);
2652bfe3f2eSlogwang return -1;
2662bfe3f2eSlogwang }
2672bfe3f2eSlogwang
268a9643ea8Slogwang rxconf = &dev_info.default_rxconf;
269a9643ea8Slogwang rxconf->rx_drop_en = 1;
270d30ea906Sjfb8856606 txconf = &dev_info.default_txconf;
271d30ea906Sjfb8856606 txconf->offloads = port_conf.txmode.offloads;
272a9643ea8Slogwang for (q = 0; q < rxRings; q++) {
273a9643ea8Slogwang retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
274a9643ea8Slogwang rte_eth_dev_socket_id(port),
275a9643ea8Slogwang rxconf,
276a9643ea8Slogwang mbuf_pool);
277a9643ea8Slogwang if (retval < 0) {
278a9643ea8Slogwang printf("initialise rx queue %d failed\n", q);
279a9643ea8Slogwang return retval;
280a9643ea8Slogwang }
281a9643ea8Slogwang }
282a9643ea8Slogwang
283a9643ea8Slogwang for (q = 0; q < txRings; q++) {
284a9643ea8Slogwang retval = rte_eth_tx_queue_setup(port, q, txRingSize,
285a9643ea8Slogwang rte_eth_dev_socket_id(port),
286d30ea906Sjfb8856606 txconf);
287a9643ea8Slogwang if (retval < 0) {
288a9643ea8Slogwang printf("initialise tx queue %d failed\n", q);
289a9643ea8Slogwang return retval;
290a9643ea8Slogwang }
291a9643ea8Slogwang }
292a9643ea8Slogwang
293a9643ea8Slogwang retval = rte_eth_dev_start(port);
294a9643ea8Slogwang if (retval < 0) {
295a9643ea8Slogwang printf("port %d start failed\n", port);
296a9643ea8Slogwang return retval;
297a9643ea8Slogwang }
298a9643ea8Slogwang
2994418919fSjohnjiang retval = rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
3004418919fSjohnjiang if (retval < 0) {
3014418919fSjohnjiang printf("port %d MAC address get failed: %s\n", port,
3024418919fSjohnjiang rte_strerror(-retval));
3034418919fSjohnjiang return retval;
3044418919fSjohnjiang }
305a9643ea8Slogwang printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
306a9643ea8Slogwang " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
307a9643ea8Slogwang (unsigned)port,
308a9643ea8Slogwang vmdq_ports_eth_addr[port].addr_bytes[0],
309a9643ea8Slogwang vmdq_ports_eth_addr[port].addr_bytes[1],
310a9643ea8Slogwang vmdq_ports_eth_addr[port].addr_bytes[2],
311a9643ea8Slogwang vmdq_ports_eth_addr[port].addr_bytes[3],
312a9643ea8Slogwang vmdq_ports_eth_addr[port].addr_bytes[4],
313a9643ea8Slogwang vmdq_ports_eth_addr[port].addr_bytes[5]);
314a9643ea8Slogwang
315a9643ea8Slogwang /*
316a9643ea8Slogwang * Set mac for each pool.
317a9643ea8Slogwang * There is no default mac for the pools in i40.
318a9643ea8Slogwang * Removes this after i40e fixes this issue.
319a9643ea8Slogwang */
320a9643ea8Slogwang for (q = 0; q < num_pools; q++) {
3214418919fSjohnjiang struct rte_ether_addr mac;
322a9643ea8Slogwang mac = pool_addr_template;
323a9643ea8Slogwang mac.addr_bytes[4] = port;
324a9643ea8Slogwang mac.addr_bytes[5] = q;
325a9643ea8Slogwang printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n",
326a9643ea8Slogwang port, q,
327a9643ea8Slogwang mac.addr_bytes[0], mac.addr_bytes[1],
328a9643ea8Slogwang mac.addr_bytes[2], mac.addr_bytes[3],
329a9643ea8Slogwang mac.addr_bytes[4], mac.addr_bytes[5]);
330a9643ea8Slogwang retval = rte_eth_dev_mac_addr_add(port, &mac,
331a9643ea8Slogwang q + vmdq_pool_base);
332a9643ea8Slogwang if (retval) {
333a9643ea8Slogwang printf("mac addr add failed at pool %d\n", q);
334a9643ea8Slogwang return retval;
335a9643ea8Slogwang }
336a9643ea8Slogwang }
337a9643ea8Slogwang
338a9643ea8Slogwang return 0;
339a9643ea8Slogwang }
340a9643ea8Slogwang
341a9643ea8Slogwang /* Check num_pools parameter and set it if OK*/
342a9643ea8Slogwang static int
vmdq_parse_num_pools(const char * q_arg)343a9643ea8Slogwang vmdq_parse_num_pools(const char *q_arg)
344a9643ea8Slogwang {
345a9643ea8Slogwang char *end = NULL;
346a9643ea8Slogwang int n;
347a9643ea8Slogwang
348a9643ea8Slogwang /* parse number string */
349a9643ea8Slogwang n = strtol(q_arg, &end, 10);
350a9643ea8Slogwang if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
351a9643ea8Slogwang return -1;
352a9643ea8Slogwang
353a9643ea8Slogwang if (num_pools > num_vlans) {
354a9643ea8Slogwang printf("num_pools %d > num_vlans %d\n", num_pools, num_vlans);
355a9643ea8Slogwang return -1;
356a9643ea8Slogwang }
357a9643ea8Slogwang
358a9643ea8Slogwang num_pools = n;
359a9643ea8Slogwang
360a9643ea8Slogwang return 0;
361a9643ea8Slogwang }
362a9643ea8Slogwang
363a9643ea8Slogwang
364a9643ea8Slogwang static int
parse_portmask(const char * portmask)365a9643ea8Slogwang parse_portmask(const char *portmask)
366a9643ea8Slogwang {
367a9643ea8Slogwang char *end = NULL;
368a9643ea8Slogwang unsigned long pm;
369a9643ea8Slogwang
370a9643ea8Slogwang /* parse hexadecimal string */
371a9643ea8Slogwang pm = strtoul(portmask, &end, 16);
372a9643ea8Slogwang if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
373*2d9fd380Sjfb8856606 return 0;
374a9643ea8Slogwang
375a9643ea8Slogwang return pm;
376a9643ea8Slogwang }
377a9643ea8Slogwang
378a9643ea8Slogwang /* Display usage */
379a9643ea8Slogwang static void
vmdq_usage(const char * prgname)380a9643ea8Slogwang vmdq_usage(const char *prgname)
381a9643ea8Slogwang {
382a9643ea8Slogwang printf("%s [EAL options] -- -p PORTMASK]\n"
3830c6bd470Sfengbojiang " --nb-pools NP: number of pools\n"
3840c6bd470Sfengbojiang " --enable-rss: enable RSS (disabled by default)\n",
385a9643ea8Slogwang prgname);
386a9643ea8Slogwang }
387a9643ea8Slogwang
388a9643ea8Slogwang /* Parse the argument (num_pools) given in the command line of the application */
389a9643ea8Slogwang static int
vmdq_parse_args(int argc,char ** argv)390a9643ea8Slogwang vmdq_parse_args(int argc, char **argv)
391a9643ea8Slogwang {
392a9643ea8Slogwang int opt;
393a9643ea8Slogwang int option_index;
394a9643ea8Slogwang unsigned i;
395a9643ea8Slogwang const char *prgname = argv[0];
396a9643ea8Slogwang static struct option long_option[] = {
397a9643ea8Slogwang {"nb-pools", required_argument, NULL, 0},
3980c6bd470Sfengbojiang {"enable-rss", 0, NULL, 0},
399a9643ea8Slogwang {NULL, 0, 0, 0}
400a9643ea8Slogwang };
401a9643ea8Slogwang
402a9643ea8Slogwang /* Parse command line */
403a9643ea8Slogwang while ((opt = getopt_long(argc, argv, "p:", long_option,
404a9643ea8Slogwang &option_index)) != EOF) {
405a9643ea8Slogwang switch (opt) {
406a9643ea8Slogwang /* portmask */
407a9643ea8Slogwang case 'p':
408a9643ea8Slogwang enabled_port_mask = parse_portmask(optarg);
409a9643ea8Slogwang if (enabled_port_mask == 0) {
410a9643ea8Slogwang printf("invalid portmask\n");
411a9643ea8Slogwang vmdq_usage(prgname);
412a9643ea8Slogwang return -1;
413a9643ea8Slogwang }
414a9643ea8Slogwang break;
415a9643ea8Slogwang case 0:
4160c6bd470Sfengbojiang if (!strcmp(long_option[option_index].name,
4170c6bd470Sfengbojiang "nb-pools")) {
418a9643ea8Slogwang if (vmdq_parse_num_pools(optarg) == -1) {
419a9643ea8Slogwang printf("invalid number of pools\n");
420a9643ea8Slogwang vmdq_usage(prgname);
421a9643ea8Slogwang return -1;
422a9643ea8Slogwang }
4230c6bd470Sfengbojiang }
4240c6bd470Sfengbojiang
4250c6bd470Sfengbojiang if (!strcmp(long_option[option_index].name,
4260c6bd470Sfengbojiang "enable-rss"))
4270c6bd470Sfengbojiang rss_enable = 1;
428a9643ea8Slogwang break;
429a9643ea8Slogwang
430a9643ea8Slogwang default:
431a9643ea8Slogwang vmdq_usage(prgname);
432a9643ea8Slogwang return -1;
433a9643ea8Slogwang }
434a9643ea8Slogwang }
435a9643ea8Slogwang
436a9643ea8Slogwang for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
437a9643ea8Slogwang if (enabled_port_mask & (1 << i))
438a9643ea8Slogwang ports[num_ports++] = (uint8_t)i;
439a9643ea8Slogwang }
440a9643ea8Slogwang
441a9643ea8Slogwang if (num_ports < 2 || num_ports % 2) {
442a9643ea8Slogwang printf("Current enabled port number is %u,"
443a9643ea8Slogwang "but it should be even and at least 2\n", num_ports);
444a9643ea8Slogwang return -1;
445a9643ea8Slogwang }
446a9643ea8Slogwang
447a9643ea8Slogwang return 0;
448a9643ea8Slogwang }
449a9643ea8Slogwang
450a9643ea8Slogwang static void
update_mac_address(struct rte_mbuf * m,unsigned dst_port)451a9643ea8Slogwang update_mac_address(struct rte_mbuf *m, unsigned dst_port)
452a9643ea8Slogwang {
4534418919fSjohnjiang struct rte_ether_hdr *eth;
454a9643ea8Slogwang void *tmp;
455a9643ea8Slogwang
4564418919fSjohnjiang eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
457a9643ea8Slogwang
458a9643ea8Slogwang /* 02:00:00:00:00:xx */
459a9643ea8Slogwang tmp = ð->d_addr.addr_bytes[0];
460a9643ea8Slogwang *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
461a9643ea8Slogwang
462a9643ea8Slogwang /* src addr */
4634418919fSjohnjiang rte_ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->s_addr);
464a9643ea8Slogwang }
465a9643ea8Slogwang
466a9643ea8Slogwang /* When we receive a HUP signal, print out our stats */
467a9643ea8Slogwang static void
sighup_handler(int signum)468a9643ea8Slogwang sighup_handler(int signum)
469a9643ea8Slogwang {
4700c6bd470Sfengbojiang unsigned int q = vmdq_queue_base;
4710c6bd470Sfengbojiang for (; q < num_queues; q++) {
4720c6bd470Sfengbojiang if ((q - vmdq_queue_base) % (num_vmdq_queues / num_pools) == 0)
4730c6bd470Sfengbojiang printf("\nPool %u: ", (q - vmdq_queue_base) /
4740c6bd470Sfengbojiang (num_vmdq_queues / num_pools));
475a9643ea8Slogwang printf("%lu ", rxPackets[q]);
476a9643ea8Slogwang }
477a9643ea8Slogwang printf("\nFinished handling signal %d\n", signum);
478a9643ea8Slogwang }
479a9643ea8Slogwang
480a9643ea8Slogwang /*
481a9643ea8Slogwang * Main thread that does the work, reading from INPUT_PORT
482a9643ea8Slogwang * and writing to OUTPUT_PORT
483a9643ea8Slogwang */
484a9643ea8Slogwang static int
lcore_main(__rte_unused void * dummy)485*2d9fd380Sjfb8856606 lcore_main(__rte_unused void *dummy)
486a9643ea8Slogwang {
487a9643ea8Slogwang const uint16_t lcore_id = (uint16_t)rte_lcore_id();
488a9643ea8Slogwang const uint16_t num_cores = (uint16_t)rte_lcore_count();
489a9643ea8Slogwang uint16_t core_id = 0;
490a9643ea8Slogwang uint16_t startQueue, endQueue;
491a9643ea8Slogwang uint16_t q, i, p;
492a9643ea8Slogwang const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores);
493a9643ea8Slogwang
494a9643ea8Slogwang for (i = 0; i < num_cores; i++)
495a9643ea8Slogwang if (lcore_ids[i] == lcore_id) {
496a9643ea8Slogwang core_id = i;
497a9643ea8Slogwang break;
498a9643ea8Slogwang }
499a9643ea8Slogwang
500a9643ea8Slogwang if (remainder != 0) {
501a9643ea8Slogwang if (core_id < remainder) {
502a9643ea8Slogwang startQueue = (uint16_t)(core_id *
503a9643ea8Slogwang (num_vmdq_queues / num_cores + 1));
504a9643ea8Slogwang endQueue = (uint16_t)(startQueue +
505a9643ea8Slogwang (num_vmdq_queues / num_cores) + 1);
506a9643ea8Slogwang } else {
507a9643ea8Slogwang startQueue = (uint16_t)(core_id *
508a9643ea8Slogwang (num_vmdq_queues / num_cores) +
509a9643ea8Slogwang remainder);
510a9643ea8Slogwang endQueue = (uint16_t)(startQueue +
511a9643ea8Slogwang (num_vmdq_queues / num_cores));
512a9643ea8Slogwang }
513a9643ea8Slogwang } else {
514a9643ea8Slogwang startQueue = (uint16_t)(core_id *
515a9643ea8Slogwang (num_vmdq_queues / num_cores));
516a9643ea8Slogwang endQueue = (uint16_t)(startQueue +
517a9643ea8Slogwang (num_vmdq_queues / num_cores));
518a9643ea8Slogwang }
519a9643ea8Slogwang
520a9643ea8Slogwang /* vmdq queue idx doesn't always start from zero.*/
521a9643ea8Slogwang startQueue += vmdq_queue_base;
522a9643ea8Slogwang endQueue += vmdq_queue_base;
523a9643ea8Slogwang printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id,
524a9643ea8Slogwang (unsigned)lcore_id, startQueue, endQueue - 1);
525a9643ea8Slogwang
526a9643ea8Slogwang if (startQueue == endQueue) {
527a9643ea8Slogwang printf("lcore %u has nothing to do\n", lcore_id);
528a9643ea8Slogwang return 0;
529a9643ea8Slogwang }
530a9643ea8Slogwang
531a9643ea8Slogwang for (;;) {
532a9643ea8Slogwang struct rte_mbuf *buf[MAX_PKT_BURST];
533*2d9fd380Sjfb8856606 const uint16_t buf_size = RTE_DIM(buf);
534a9643ea8Slogwang
535a9643ea8Slogwang for (p = 0; p < num_ports; p++) {
536a9643ea8Slogwang const uint8_t sport = ports[p];
537a9643ea8Slogwang /* 0 <-> 1, 2 <-> 3 etc */
538a9643ea8Slogwang const uint8_t dport = ports[p ^ 1];
539a9643ea8Slogwang if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID))
540a9643ea8Slogwang continue;
541a9643ea8Slogwang
542a9643ea8Slogwang for (q = startQueue; q < endQueue; q++) {
543a9643ea8Slogwang const uint16_t rxCount = rte_eth_rx_burst(sport,
544a9643ea8Slogwang q, buf, buf_size);
545a9643ea8Slogwang
546a9643ea8Slogwang if (unlikely(rxCount == 0))
547a9643ea8Slogwang continue;
548a9643ea8Slogwang
549a9643ea8Slogwang rxPackets[q] += rxCount;
550a9643ea8Slogwang
551a9643ea8Slogwang for (i = 0; i < rxCount; i++)
552a9643ea8Slogwang update_mac_address(buf[i], dport);
553a9643ea8Slogwang
554a9643ea8Slogwang const uint16_t txCount = rte_eth_tx_burst(dport,
555a9643ea8Slogwang vmdq_queue_base + core_id,
556a9643ea8Slogwang buf,
557a9643ea8Slogwang rxCount);
558a9643ea8Slogwang
559a9643ea8Slogwang if (txCount != rxCount) {
560a9643ea8Slogwang for (i = txCount; i < rxCount; i++)
561a9643ea8Slogwang rte_pktmbuf_free(buf[i]);
562a9643ea8Slogwang }
563a9643ea8Slogwang }
564a9643ea8Slogwang }
565a9643ea8Slogwang }
566a9643ea8Slogwang }
567a9643ea8Slogwang
568a9643ea8Slogwang /*
569a9643ea8Slogwang * Update the global var NUM_PORTS and array PORTS according to system ports number
570a9643ea8Slogwang * and return valid ports number
571a9643ea8Slogwang */
check_ports_num(unsigned nb_ports)572a9643ea8Slogwang static unsigned check_ports_num(unsigned nb_ports)
573a9643ea8Slogwang {
574a9643ea8Slogwang unsigned valid_num_ports = num_ports;
575a9643ea8Slogwang unsigned portid;
576a9643ea8Slogwang
577a9643ea8Slogwang if (num_ports > nb_ports) {
578a9643ea8Slogwang printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
579a9643ea8Slogwang num_ports, nb_ports);
580a9643ea8Slogwang num_ports = nb_ports;
581a9643ea8Slogwang }
582a9643ea8Slogwang
583a9643ea8Slogwang for (portid = 0; portid < num_ports; portid++) {
584d30ea906Sjfb8856606 if (!rte_eth_dev_is_valid_port(ports[portid])) {
585d30ea906Sjfb8856606 printf("\nSpecified port ID(%u) is not valid\n",
586d30ea906Sjfb8856606 ports[portid]);
587a9643ea8Slogwang ports[portid] = INVALID_PORT_ID;
588a9643ea8Slogwang valid_num_ports--;
589a9643ea8Slogwang }
590a9643ea8Slogwang }
591a9643ea8Slogwang return valid_num_ports;
592a9643ea8Slogwang }
593a9643ea8Slogwang
594a9643ea8Slogwang /* Main function, does initialisation and calls the per-lcore functions */
595a9643ea8Slogwang int
main(int argc,char * argv[])596a9643ea8Slogwang main(int argc, char *argv[])
597a9643ea8Slogwang {
598a9643ea8Slogwang struct rte_mempool *mbuf_pool;
599a9643ea8Slogwang unsigned lcore_id, core_id = 0;
600a9643ea8Slogwang int ret;
601a9643ea8Slogwang unsigned nb_ports, valid_num_ports;
6022bfe3f2eSlogwang uint16_t portid;
603a9643ea8Slogwang
604a9643ea8Slogwang signal(SIGHUP, sighup_handler);
605a9643ea8Slogwang
606a9643ea8Slogwang /* init EAL */
607a9643ea8Slogwang ret = rte_eal_init(argc, argv);
608a9643ea8Slogwang if (ret < 0)
609a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
610a9643ea8Slogwang argc -= ret;
611a9643ea8Slogwang argv += ret;
612a9643ea8Slogwang
613a9643ea8Slogwang /* parse app arguments */
614a9643ea8Slogwang ret = vmdq_parse_args(argc, argv);
615a9643ea8Slogwang if (ret < 0)
616a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
617a9643ea8Slogwang
618a9643ea8Slogwang for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
619a9643ea8Slogwang if (rte_lcore_is_enabled(lcore_id))
620a9643ea8Slogwang lcore_ids[core_id++] = lcore_id;
621a9643ea8Slogwang
622a9643ea8Slogwang if (rte_lcore_count() > RTE_MAX_LCORE)
623a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Not enough cores\n");
624a9643ea8Slogwang
625d30ea906Sjfb8856606 nb_ports = rte_eth_dev_count_avail();
626a9643ea8Slogwang
627a9643ea8Slogwang /*
628a9643ea8Slogwang * Update the global var NUM_PORTS and global array PORTS
629a9643ea8Slogwang * and get value of var VALID_NUM_PORTS according to system ports number
630a9643ea8Slogwang */
631a9643ea8Slogwang valid_num_ports = check_ports_num(nb_ports);
632a9643ea8Slogwang
633a9643ea8Slogwang if (valid_num_ports < 2 || valid_num_ports % 2) {
634a9643ea8Slogwang printf("Current valid ports number is %u\n", valid_num_ports);
635a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
636a9643ea8Slogwang }
637a9643ea8Slogwang
638a9643ea8Slogwang mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
639a9643ea8Slogwang NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE,
640a9643ea8Slogwang 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
641a9643ea8Slogwang if (mbuf_pool == NULL)
642a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
643a9643ea8Slogwang
644a9643ea8Slogwang /* initialize all ports */
645d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(portid) {
646a9643ea8Slogwang /* skip ports that are not enabled */
647a9643ea8Slogwang if ((enabled_port_mask & (1 << portid)) == 0) {
648a9643ea8Slogwang printf("\nSkipping disabled port %d\n", portid);
649a9643ea8Slogwang continue;
650a9643ea8Slogwang }
651a9643ea8Slogwang if (port_init(portid, mbuf_pool) != 0)
652a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
653a9643ea8Slogwang }
654a9643ea8Slogwang
655a9643ea8Slogwang /* call lcore_main() on every lcore */
656*2d9fd380Sjfb8856606 rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MAIN);
657*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(lcore_id) {
658a9643ea8Slogwang if (rte_eal_wait_lcore(lcore_id) < 0)
659a9643ea8Slogwang return -1;
660a9643ea8Slogwang }
661a9643ea8Slogwang
662a9643ea8Slogwang return 0;
663a9643ea8Slogwang }
664