xref: /dpdk/examples/vmdq_dcb/main.c (revision 8cc72f2814dd7f0b805e5a170e93f464c0ffcd51)
1af75078fSIntel /*-
2af75078fSIntel  *   BSD LICENSE
3af75078fSIntel  *
4e9d48c00SBruce Richardson  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5af75078fSIntel  *   All rights reserved.
6af75078fSIntel  *
7af75078fSIntel  *   Redistribution and use in source and binary forms, with or without
8af75078fSIntel  *   modification, are permitted provided that the following conditions
9af75078fSIntel  *   are met:
10af75078fSIntel  *
11af75078fSIntel  *     * Redistributions of source code must retain the above copyright
12af75078fSIntel  *       notice, this list of conditions and the following disclaimer.
13af75078fSIntel  *     * Redistributions in binary form must reproduce the above copyright
14af75078fSIntel  *       notice, this list of conditions and the following disclaimer in
15af75078fSIntel  *       the documentation and/or other materials provided with the
16af75078fSIntel  *       distribution.
17af75078fSIntel  *     * Neither the name of Intel Corporation nor the names of its
18af75078fSIntel  *       contributors may be used to endorse or promote products derived
19af75078fSIntel  *       from this software without specific prior written permission.
20af75078fSIntel  *
21af75078fSIntel  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22af75078fSIntel  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23af75078fSIntel  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24af75078fSIntel  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25af75078fSIntel  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26af75078fSIntel  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27af75078fSIntel  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28af75078fSIntel  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29af75078fSIntel  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30af75078fSIntel  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31af75078fSIntel  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32af75078fSIntel  */
33af75078fSIntel 
34af75078fSIntel #include <stdint.h>
35af75078fSIntel #include <sys/queue.h>
36af75078fSIntel #include <stdlib.h>
37af75078fSIntel #include <string.h>
38af75078fSIntel #include <stdio.h>
39af75078fSIntel #include <assert.h>
40af75078fSIntel #include <errno.h>
41af75078fSIntel #include <signal.h>
42af75078fSIntel #include <stdarg.h>
43af75078fSIntel #include <inttypes.h>
441d8d954bSIntel #include <getopt.h>
45af75078fSIntel 
46af75078fSIntel #include <rte_common.h>
47af75078fSIntel #include <rte_log.h>
48af75078fSIntel #include <rte_memory.h>
49af75078fSIntel #include <rte_memcpy.h>
50af75078fSIntel #include <rte_memzone.h>
51af75078fSIntel #include <rte_eal.h>
52af75078fSIntel #include <rte_per_lcore.h>
53af75078fSIntel #include <rte_launch.h>
54af75078fSIntel #include <rte_atomic.h>
55af75078fSIntel #include <rte_cycles.h>
56af75078fSIntel #include <rte_prefetch.h>
57af75078fSIntel #include <rte_lcore.h>
58af75078fSIntel #include <rte_per_lcore.h>
59af75078fSIntel #include <rte_branch_prediction.h>
60af75078fSIntel #include <rte_interrupts.h>
61af75078fSIntel #include <rte_pci.h>
62af75078fSIntel #include <rte_random.h>
63af75078fSIntel #include <rte_debug.h>
64af75078fSIntel #include <rte_ether.h>
65af75078fSIntel #include <rte_ethdev.h>
66af75078fSIntel #include <rte_ring.h>
67af75078fSIntel #include <rte_log.h>
68af75078fSIntel #include <rte_mempool.h>
69af75078fSIntel #include <rte_mbuf.h>
70af75078fSIntel #include <rte_memcpy.h>
71af75078fSIntel 
72af75078fSIntel /* basic constants used in application */
73*8cc72f28SJingjing Wu #define MAX_QUEUES 1024
74*8cc72f28SJingjing Wu /*
75*8cc72f28SJingjing Wu  * 1024 queues require to meet the needs of a large number of vmdq_pools.
76*8cc72f28SJingjing Wu  * (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port.
77*8cc72f28SJingjing Wu  */
78*8cc72f28SJingjing Wu #define NUM_MBUFS_PER_PORT (MAX_QUEUES * RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, \
79*8cc72f28SJingjing Wu 						RTE_TEST_TX_DESC_DEFAULT))
80af75078fSIntel #define MBUF_CACHE_SIZE 64
81af75078fSIntel 
82*8cc72f28SJingjing Wu #define MAX_PKT_BURST 32
83*8cc72f28SJingjing Wu 
84*8cc72f28SJingjing Wu /*
85*8cc72f28SJingjing Wu  * Configurable number of RX/TX ring descriptors
86*8cc72f28SJingjing Wu  */
87*8cc72f28SJingjing Wu #define RTE_TEST_RX_DESC_DEFAULT 128
88*8cc72f28SJingjing Wu #define RTE_TEST_TX_DESC_DEFAULT 512
89*8cc72f28SJingjing Wu 
90d4f37b09SIntel #define INVALID_PORT_ID 0xFF
91d4f37b09SIntel 
92d4f37b09SIntel /* mask of enabled ports */
93*8cc72f28SJingjing Wu static uint32_t enabled_port_mask;
94*8cc72f28SJingjing Wu static uint8_t ports[RTE_MAX_ETHPORTS];
95*8cc72f28SJingjing Wu static unsigned num_ports;
96af75078fSIntel 
97*8cc72f28SJingjing Wu /* number of pools (if user does not specify any, 32 by default */
98*8cc72f28SJingjing Wu static enum rte_eth_nb_pools num_pools = ETH_32_POOLS;
99*8cc72f28SJingjing Wu static enum rte_eth_nb_tcs   num_tcs   = ETH_4_TCS;
100*8cc72f28SJingjing Wu static uint16_t num_queues, num_vmdq_queues;
101*8cc72f28SJingjing Wu static uint16_t vmdq_pool_base, vmdq_queue_base;
102*8cc72f28SJingjing Wu static uint8_t rss_enable;
1031d8d954bSIntel 
104af75078fSIntel /* empty vmdq+dcb configuration structure. Filled in programatically */
105af75078fSIntel static const struct rte_eth_conf vmdq_dcb_conf_default = {
106af75078fSIntel 	.rxmode = {
10732e7aa0bSIntel 		.mq_mode        = ETH_MQ_RX_VMDQ_DCB,
108af75078fSIntel 		.split_hdr_size = 0,
109af75078fSIntel 		.header_split   = 0, /**< Header Split disabled */
110af75078fSIntel 		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
111af75078fSIntel 		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
112af75078fSIntel 		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
113af75078fSIntel 	},
114af75078fSIntel 	.txmode = {
115*8cc72f28SJingjing Wu 		.mq_mode = ETH_MQ_TX_VMDQ_DCB,
116af75078fSIntel 	},
117af75078fSIntel 	/*
118af75078fSIntel 	 * should be overridden separately in code with
119af75078fSIntel 	 * appropriate values
120af75078fSIntel 	 */
121*8cc72f28SJingjing Wu 	.rx_adv_conf = {
122af75078fSIntel 		.vmdq_dcb_conf = {
123*8cc72f28SJingjing Wu 			.nb_queue_pools = ETH_32_POOLS,
124af75078fSIntel 			.enable_default_pool = 0,
125af75078fSIntel 			.default_pool = 0,
126af75078fSIntel 			.nb_pool_maps = 0,
127af75078fSIntel 			.pool_map = {{0, 0},},
128cb60ede6SJingjing Wu 			.dcb_tc = {0},
129af75078fSIntel 		},
130*8cc72f28SJingjing Wu 		.dcb_rx_conf = {
131*8cc72f28SJingjing Wu 				.nb_tcs = ETH_4_TCS,
132*8cc72f28SJingjing Wu 				/** Traffic class each UP mapped to. */
133*8cc72f28SJingjing Wu 				.dcb_tc = {0},
134*8cc72f28SJingjing Wu 		},
135*8cc72f28SJingjing Wu 		.vmdq_rx_conf = {
136*8cc72f28SJingjing Wu 			.nb_queue_pools = ETH_32_POOLS,
137*8cc72f28SJingjing Wu 			.enable_default_pool = 0,
138*8cc72f28SJingjing Wu 			.default_pool = 0,
139*8cc72f28SJingjing Wu 			.nb_pool_maps = 0,
140*8cc72f28SJingjing Wu 			.pool_map = {{0, 0},},
141*8cc72f28SJingjing Wu 		},
142*8cc72f28SJingjing Wu 	},
143*8cc72f28SJingjing Wu 	.tx_adv_conf = {
144*8cc72f28SJingjing Wu 		.vmdq_dcb_tx_conf = {
145*8cc72f28SJingjing Wu 			.nb_queue_pools = ETH_32_POOLS,
146*8cc72f28SJingjing Wu 			.dcb_tc = {0},
147*8cc72f28SJingjing Wu 		},
148af75078fSIntel 	},
149af75078fSIntel };
150af75078fSIntel 
151af75078fSIntel /* array used for printing out statistics */
152*8cc72f28SJingjing Wu volatile unsigned long rxPackets[MAX_QUEUES] = {0};
153af75078fSIntel 
154af75078fSIntel const uint16_t vlan_tags[] = {
155af75078fSIntel 	0,  1,  2,  3,  4,  5,  6,  7,
156af75078fSIntel 	8,  9, 10, 11,	12, 13, 14, 15,
157af75078fSIntel 	16, 17, 18, 19, 20, 21, 22, 23,
158af75078fSIntel 	24, 25, 26, 27, 28, 29, 30, 31
159af75078fSIntel };
160af75078fSIntel 
161*8cc72f28SJingjing Wu const uint16_t num_vlans = RTE_DIM(vlan_tags);
162*8cc72f28SJingjing Wu /* pool mac addr template, pool mac addr is like: 52 54 00 12 port# pool# */
163*8cc72f28SJingjing Wu static struct ether_addr pool_addr_template = {
164*8cc72f28SJingjing Wu 	.addr_bytes = {0x52, 0x54, 0x00, 0x12, 0x00, 0x00}
165*8cc72f28SJingjing Wu };
166*8cc72f28SJingjing Wu 
167*8cc72f28SJingjing Wu /* ethernet addresses of ports */
168*8cc72f28SJingjing Wu static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
169*8cc72f28SJingjing Wu 
170af75078fSIntel /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
171af75078fSIntel  * given above, and the number of traffic classes available for use. */
172af75078fSIntel static inline int
173*8cc72f28SJingjing Wu get_eth_conf(struct rte_eth_conf *eth_conf)
174af75078fSIntel {
175af75078fSIntel 	struct rte_eth_vmdq_dcb_conf conf;
176*8cc72f28SJingjing Wu 	struct rte_eth_vmdq_rx_conf  vmdq_conf;
177*8cc72f28SJingjing Wu 	struct rte_eth_dcb_rx_conf   dcb_conf;
178*8cc72f28SJingjing Wu 	struct rte_eth_vmdq_dcb_tx_conf tx_conf;
179*8cc72f28SJingjing Wu 	uint8_t i;
180af75078fSIntel 
181*8cc72f28SJingjing Wu 	conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
182*8cc72f28SJingjing Wu 	vmdq_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
183*8cc72f28SJingjing Wu 	tx_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
184*8cc72f28SJingjing Wu 	conf.nb_pool_maps = num_pools;
185*8cc72f28SJingjing Wu 	vmdq_conf.nb_pool_maps = num_pools;
186af75078fSIntel 	conf.enable_default_pool = 0;
187*8cc72f28SJingjing Wu 	vmdq_conf.enable_default_pool = 0;
1881d8d954bSIntel 	conf.default_pool = 0; /* set explicit value, even if not used */
189*8cc72f28SJingjing Wu 	vmdq_conf.default_pool = 0;
190*8cc72f28SJingjing Wu 
191af75078fSIntel 	for (i = 0; i < conf.nb_pool_maps; i++) {
192af75078fSIntel 		conf.pool_map[i].vlan_id = vlan_tags[i];
193*8cc72f28SJingjing Wu 		vmdq_conf.pool_map[i].vlan_id = vlan_tags[i];
194*8cc72f28SJingjing Wu 		conf.pool_map[i].pools = 1UL << i;
195*8cc72f28SJingjing Wu 		vmdq_conf.pool_map[i].pools = 1UL << i;
196af75078fSIntel 	}
197af75078fSIntel 	for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
198*8cc72f28SJingjing Wu 		conf.dcb_tc[i] = i % num_tcs;
199*8cc72f28SJingjing Wu 		dcb_conf.dcb_tc[i] = i % num_tcs;
200*8cc72f28SJingjing Wu 		tx_conf.dcb_tc[i] = i % num_tcs;
201af75078fSIntel 	}
202*8cc72f28SJingjing Wu 	dcb_conf.nb_tcs = (enum rte_eth_nb_tcs)num_tcs;
2031d8d954bSIntel 	(void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
2041d8d954bSIntel 	(void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
205*8cc72f28SJingjing Wu 			  sizeof(conf)));
206*8cc72f28SJingjing Wu 	(void)(rte_memcpy(&eth_conf->rx_adv_conf.dcb_rx_conf, &dcb_conf,
207*8cc72f28SJingjing Wu 			  sizeof(dcb_conf)));
208*8cc72f28SJingjing Wu 	(void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_rx_conf, &vmdq_conf,
209*8cc72f28SJingjing Wu 			  sizeof(vmdq_conf)));
210*8cc72f28SJingjing Wu 	(void)(rte_memcpy(&eth_conf->tx_adv_conf.vmdq_dcb_tx_conf, &tx_conf,
211*8cc72f28SJingjing Wu 			  sizeof(tx_conf)));
212*8cc72f28SJingjing Wu 	if (rss_enable) {
213*8cc72f28SJingjing Wu 		eth_conf->rxmode.mq_mode = ETH_MQ_RX_VMDQ_DCB_RSS;
214*8cc72f28SJingjing Wu 		eth_conf->rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP |
215*8cc72f28SJingjing Wu 							ETH_RSS_UDP |
216*8cc72f28SJingjing Wu 							ETH_RSS_TCP |
217*8cc72f28SJingjing Wu 							ETH_RSS_SCTP;
218*8cc72f28SJingjing Wu 	}
219af75078fSIntel 	return 0;
220af75078fSIntel }
221af75078fSIntel 
222af75078fSIntel /*
223af75078fSIntel  * Initialises a given port using global settings and with the rx buffers
224af75078fSIntel  * coming from the mbuf_pool passed as parameter
225af75078fSIntel  */
226af75078fSIntel static inline int
227af75078fSIntel port_init(uint8_t port, struct rte_mempool *mbuf_pool)
228af75078fSIntel {
229*8cc72f28SJingjing Wu 	struct rte_eth_dev_info dev_info;
230*8cc72f28SJingjing Wu 	struct rte_eth_conf port_conf = {0};
231*8cc72f28SJingjing Wu 	const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT;
232*8cc72f28SJingjing Wu 	const uint16_t txRingSize = RTE_TEST_TX_DESC_DEFAULT;
233af75078fSIntel 	int retval;
234af75078fSIntel 	uint16_t q;
235*8cc72f28SJingjing Wu 	uint16_t queues_per_pool;
236*8cc72f28SJingjing Wu 	uint32_t max_nb_pools;
237af75078fSIntel 
238*8cc72f28SJingjing Wu 	/*
239*8cc72f28SJingjing Wu 	 * The max pool number from dev_info will be used to validate the pool
240*8cc72f28SJingjing Wu 	 * number specified in cmd line
241*8cc72f28SJingjing Wu 	 */
242*8cc72f28SJingjing Wu 	rte_eth_dev_info_get(port, &dev_info);
243*8cc72f28SJingjing Wu 	max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
244*8cc72f28SJingjing Wu 	/*
245*8cc72f28SJingjing Wu 	 * We allow to process part of VMDQ pools specified by num_pools in
246*8cc72f28SJingjing Wu 	 * command line.
247*8cc72f28SJingjing Wu 	 */
248*8cc72f28SJingjing Wu 	if (num_pools > max_nb_pools) {
249*8cc72f28SJingjing Wu 		printf("num_pools %d >max_nb_pools %d\n",
250*8cc72f28SJingjing Wu 			num_pools, max_nb_pools);
251*8cc72f28SJingjing Wu 		return -1;
252*8cc72f28SJingjing Wu 	}
253*8cc72f28SJingjing Wu 
254*8cc72f28SJingjing Wu 	/*
255*8cc72f28SJingjing Wu 	 * NIC queues are divided into pf queues and vmdq queues.
256*8cc72f28SJingjing Wu 	 * There is assumption here all ports have the same configuration!
257*8cc72f28SJingjing Wu 	*/
258*8cc72f28SJingjing Wu 	vmdq_queue_base = dev_info.vmdq_queue_base;
259*8cc72f28SJingjing Wu 	vmdq_pool_base  = dev_info.vmdq_pool_base;
260*8cc72f28SJingjing Wu 	printf("vmdq queue base: %d pool base %d\n",
261*8cc72f28SJingjing Wu 		vmdq_queue_base, vmdq_pool_base);
262*8cc72f28SJingjing Wu 	if (vmdq_pool_base == 0) {
263*8cc72f28SJingjing Wu 		num_vmdq_queues = dev_info.max_rx_queues;
264*8cc72f28SJingjing Wu 		num_queues = dev_info.max_rx_queues;
265*8cc72f28SJingjing Wu 		if (num_tcs != num_vmdq_queues / num_pools) {
266*8cc72f28SJingjing Wu 			printf("nb_tcs %d is invalid considering with"
267*8cc72f28SJingjing Wu 				" nb_pools %d, nb_tcs * nb_pools should = %d\n",
268*8cc72f28SJingjing Wu 				num_tcs, num_pools, num_vmdq_queues);
269*8cc72f28SJingjing Wu 			return -1;
270*8cc72f28SJingjing Wu 		}
271*8cc72f28SJingjing Wu 	} else {
272*8cc72f28SJingjing Wu 		queues_per_pool = dev_info.vmdq_queue_num /
273*8cc72f28SJingjing Wu 				  dev_info.max_vmdq_pools;
274*8cc72f28SJingjing Wu 		if (num_tcs > queues_per_pool) {
275*8cc72f28SJingjing Wu 			printf("num_tcs %d > num of queues per pool %d\n",
276*8cc72f28SJingjing Wu 				num_tcs, queues_per_pool);
277*8cc72f28SJingjing Wu 			return -1;
278*8cc72f28SJingjing Wu 		}
279*8cc72f28SJingjing Wu 		num_vmdq_queues = num_pools * queues_per_pool;
280*8cc72f28SJingjing Wu 		num_queues = vmdq_queue_base + num_vmdq_queues;
281*8cc72f28SJingjing Wu 		printf("Configured vmdq pool num: %u,"
282*8cc72f28SJingjing Wu 			" each vmdq pool has %u queues\n",
283*8cc72f28SJingjing Wu 			num_pools, queues_per_pool);
284*8cc72f28SJingjing Wu 	}
285*8cc72f28SJingjing Wu 
286*8cc72f28SJingjing Wu 	if (port >= rte_eth_dev_count())
287*8cc72f28SJingjing Wu 		return -1;
288*8cc72f28SJingjing Wu 
289*8cc72f28SJingjing Wu 	retval = get_eth_conf(&port_conf);
2901d8d954bSIntel 	if (retval < 0)
2911d8d954bSIntel 		return retval;
292af75078fSIntel 
293*8cc72f28SJingjing Wu 	/*
294*8cc72f28SJingjing Wu 	 * Though in this example, all queues including pf queues are setup.
295*8cc72f28SJingjing Wu 	 * This is because VMDQ queues doesn't always start from zero, and the
296*8cc72f28SJingjing Wu 	 * PMD layer doesn't support selectively initialising part of rx/tx
297*8cc72f28SJingjing Wu 	 * queues.
298*8cc72f28SJingjing Wu 	 */
299*8cc72f28SJingjing Wu 	retval = rte_eth_dev_configure(port, num_queues, num_queues, &port_conf);
300af75078fSIntel 	if (retval != 0)
301af75078fSIntel 		return retval;
302af75078fSIntel 
303*8cc72f28SJingjing Wu 	for (q = 0; q < num_queues; q++) {
304af75078fSIntel 		retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
30581f7ecd9SPablo de Lara 					rte_eth_dev_socket_id(port),
30681f7ecd9SPablo de Lara 					NULL,
307af75078fSIntel 					mbuf_pool);
308*8cc72f28SJingjing Wu 		if (retval < 0) {
309*8cc72f28SJingjing Wu 			printf("initialize rx queue %d failed\n", q);
310af75078fSIntel 			return retval;
311af75078fSIntel 		}
312*8cc72f28SJingjing Wu 	}
313af75078fSIntel 
314*8cc72f28SJingjing Wu 	for (q = 0; q < num_queues; q++) {
315af75078fSIntel 		retval = rte_eth_tx_queue_setup(port, q, txRingSize,
31681f7ecd9SPablo de Lara 					rte_eth_dev_socket_id(port),
31781f7ecd9SPablo de Lara 					NULL);
318*8cc72f28SJingjing Wu 		if (retval < 0) {
319*8cc72f28SJingjing Wu 			printf("initialize tx queue %d failed\n", q);
320af75078fSIntel 			return retval;
321af75078fSIntel 		}
322*8cc72f28SJingjing Wu 	}
323af75078fSIntel 
324af75078fSIntel 	retval  = rte_eth_dev_start(port);
325*8cc72f28SJingjing Wu 	if (retval < 0) {
326*8cc72f28SJingjing Wu 		printf("port %d start failed\n", port);
327af75078fSIntel 		return retval;
328*8cc72f28SJingjing Wu 	}
329af75078fSIntel 
330*8cc72f28SJingjing Wu 	rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
331967b6294SIntel 	printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
332967b6294SIntel 			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
333967b6294SIntel 			(unsigned)port,
334*8cc72f28SJingjing Wu 			vmdq_ports_eth_addr[port].addr_bytes[0],
335*8cc72f28SJingjing Wu 			vmdq_ports_eth_addr[port].addr_bytes[1],
336*8cc72f28SJingjing Wu 			vmdq_ports_eth_addr[port].addr_bytes[2],
337*8cc72f28SJingjing Wu 			vmdq_ports_eth_addr[port].addr_bytes[3],
338*8cc72f28SJingjing Wu 			vmdq_ports_eth_addr[port].addr_bytes[4],
339*8cc72f28SJingjing Wu 			vmdq_ports_eth_addr[port].addr_bytes[5]);
340*8cc72f28SJingjing Wu 
341*8cc72f28SJingjing Wu 	/* Set mac for each pool.*/
342*8cc72f28SJingjing Wu 	for (q = 0; q < num_pools; q++) {
343*8cc72f28SJingjing Wu 		struct ether_addr mac;
344*8cc72f28SJingjing Wu 
345*8cc72f28SJingjing Wu 		mac = pool_addr_template;
346*8cc72f28SJingjing Wu 		mac.addr_bytes[4] = port;
347*8cc72f28SJingjing Wu 		mac.addr_bytes[5] = q;
348*8cc72f28SJingjing Wu 		printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n",
349*8cc72f28SJingjing Wu 			port, q,
350*8cc72f28SJingjing Wu 			mac.addr_bytes[0], mac.addr_bytes[1],
351*8cc72f28SJingjing Wu 			mac.addr_bytes[2], mac.addr_bytes[3],
352*8cc72f28SJingjing Wu 			mac.addr_bytes[4], mac.addr_bytes[5]);
353*8cc72f28SJingjing Wu 		retval = rte_eth_dev_mac_addr_add(port, &mac,
354*8cc72f28SJingjing Wu 				q + vmdq_pool_base);
355*8cc72f28SJingjing Wu 		if (retval) {
356*8cc72f28SJingjing Wu 			printf("mac addr add failed at pool %d\n", q);
357*8cc72f28SJingjing Wu 			return retval;
358*8cc72f28SJingjing Wu 		}
359*8cc72f28SJingjing Wu 	}
360967b6294SIntel 
361af75078fSIntel 	return 0;
362af75078fSIntel }
363af75078fSIntel 
3641d8d954bSIntel /* Check num_pools parameter and set it if OK*/
3651d8d954bSIntel static int
3661d8d954bSIntel vmdq_parse_num_pools(const char *q_arg)
3671d8d954bSIntel {
3681d8d954bSIntel 	char *end = NULL;
3691d8d954bSIntel 	int n;
3701d8d954bSIntel 
3711d8d954bSIntel 	/* parse number string */
3721d8d954bSIntel 	n = strtol(q_arg, &end, 10);
3731d8d954bSIntel 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
3741d8d954bSIntel 		return -1;
3751d8d954bSIntel 	if (n != 16 && n != 32)
3761d8d954bSIntel 		return -1;
3771d8d954bSIntel 	if (n == 16)
3781d8d954bSIntel 		num_pools = ETH_16_POOLS;
3791d8d954bSIntel 	else
3801d8d954bSIntel 		num_pools = ETH_32_POOLS;
3811d8d954bSIntel 
3821d8d954bSIntel 	return 0;
3831d8d954bSIntel }
3841d8d954bSIntel 
385*8cc72f28SJingjing Wu /* Check num_tcs parameter and set it if OK*/
386*8cc72f28SJingjing Wu static int
387*8cc72f28SJingjing Wu vmdq_parse_num_tcs(const char *q_arg)
388*8cc72f28SJingjing Wu {
389*8cc72f28SJingjing Wu 	char *end = NULL;
390*8cc72f28SJingjing Wu 	int n;
391*8cc72f28SJingjing Wu 
392*8cc72f28SJingjing Wu 	/* parse number string */
393*8cc72f28SJingjing Wu 	n = strtol(q_arg, &end, 10);
394*8cc72f28SJingjing Wu 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
395*8cc72f28SJingjing Wu 		return -1;
396*8cc72f28SJingjing Wu 
397*8cc72f28SJingjing Wu 	if (n != 4 && n != 8)
398*8cc72f28SJingjing Wu 		return -1;
399*8cc72f28SJingjing Wu 	if (n == 4)
400*8cc72f28SJingjing Wu 		num_tcs = ETH_4_TCS;
401*8cc72f28SJingjing Wu 	else
402*8cc72f28SJingjing Wu 		num_tcs = ETH_8_TCS;
403*8cc72f28SJingjing Wu 
404*8cc72f28SJingjing Wu 	return 0;
405*8cc72f28SJingjing Wu }
406*8cc72f28SJingjing Wu 
407d4f37b09SIntel static int
408d4f37b09SIntel parse_portmask(const char *portmask)
409d4f37b09SIntel {
410d4f37b09SIntel 	char *end = NULL;
411d4f37b09SIntel 	unsigned long pm;
412d4f37b09SIntel 
413d4f37b09SIntel 	/* parse hexadecimal string */
414d4f37b09SIntel 	pm = strtoul(portmask, &end, 16);
415d4f37b09SIntel 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
416d4f37b09SIntel 		return -1;
417d4f37b09SIntel 
418d4f37b09SIntel 	if (pm == 0)
419d4f37b09SIntel 		return -1;
420d4f37b09SIntel 
421d4f37b09SIntel 	return pm;
422d4f37b09SIntel }
423d4f37b09SIntel 
4241d8d954bSIntel /* Display usage */
4251d8d954bSIntel static void
4261d8d954bSIntel vmdq_usage(const char *prgname)
4271d8d954bSIntel {
428d4f37b09SIntel 	printf("%s [EAL options] -- -p PORTMASK]\n"
429*8cc72f28SJingjing Wu 	"  --nb-pools NP: number of pools (32 default, 16)\n"
430*8cc72f28SJingjing Wu 	"  --nb-tcs NP: number of TCs (4 default, 8)\n"
431*8cc72f28SJingjing Wu 	"  --enable-rss: enable RSS (disabled by default)\n",
4321d8d954bSIntel 	       prgname);
4331d8d954bSIntel }
4341d8d954bSIntel 
4351d8d954bSIntel /*  Parse the argument (num_pools) given in the command line of the application */
4361d8d954bSIntel static int
4371d8d954bSIntel vmdq_parse_args(int argc, char **argv)
4381d8d954bSIntel {
4391d8d954bSIntel 	int opt;
4401d8d954bSIntel 	int option_index;
441d4f37b09SIntel 	unsigned i;
4421d8d954bSIntel 	const char *prgname = argv[0];
4431d8d954bSIntel 	static struct option long_option[] = {
4441d8d954bSIntel 		{"nb-pools", required_argument, NULL, 0},
445*8cc72f28SJingjing Wu 		{"nb-tcs", required_argument, NULL, 0},
446*8cc72f28SJingjing Wu 		{"enable-rss", 0, NULL, 0},
4471d8d954bSIntel 		{NULL, 0, 0, 0}
4481d8d954bSIntel 	};
4491d8d954bSIntel 
4501d8d954bSIntel 	/* Parse command line */
451*8cc72f28SJingjing Wu 	while ((opt = getopt_long(argc, argv, "p:", long_option,
452*8cc72f28SJingjing Wu 		&option_index)) != EOF) {
4531d8d954bSIntel 		switch (opt) {
454d4f37b09SIntel 		/* portmask */
455d4f37b09SIntel 		case 'p':
456d4f37b09SIntel 			enabled_port_mask = parse_portmask(optarg);
457d4f37b09SIntel 			if (enabled_port_mask == 0) {
458d4f37b09SIntel 				printf("invalid portmask\n");
459d4f37b09SIntel 				vmdq_usage(prgname);
460d4f37b09SIntel 				return -1;
461d4f37b09SIntel 			}
462d4f37b09SIntel 			break;
4631d8d954bSIntel 		case 0:
464*8cc72f28SJingjing Wu 			if (!strcmp(long_option[option_index].name, "nb-pools")) {
4651d8d954bSIntel 				if (vmdq_parse_num_pools(optarg) == -1) {
4661d8d954bSIntel 					printf("invalid number of pools\n");
4671d8d954bSIntel 					return -1;
4681d8d954bSIntel 				}
469*8cc72f28SJingjing Wu 			}
470*8cc72f28SJingjing Wu 
471*8cc72f28SJingjing Wu 			if (!strcmp(long_option[option_index].name, "nb-tcs")) {
472*8cc72f28SJingjing Wu 				if (vmdq_parse_num_tcs(optarg) == -1) {
473*8cc72f28SJingjing Wu 					printf("invalid number of tcs\n");
474*8cc72f28SJingjing Wu 					return -1;
475*8cc72f28SJingjing Wu 				}
476*8cc72f28SJingjing Wu 			}
477*8cc72f28SJingjing Wu 
478*8cc72f28SJingjing Wu 			if (!strcmp(long_option[option_index].name, "enable-rss"))
479*8cc72f28SJingjing Wu 				rss_enable = 1;
4801d8d954bSIntel 			break;
481*8cc72f28SJingjing Wu 
4821d8d954bSIntel 		default:
4831d8d954bSIntel 			vmdq_usage(prgname);
4841d8d954bSIntel 			return -1;
4851d8d954bSIntel 		}
4861d8d954bSIntel 	}
487d4f37b09SIntel 
488*8cc72f28SJingjing Wu 	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
489d4f37b09SIntel 		if (enabled_port_mask & (1 << i))
490d4f37b09SIntel 			ports[num_ports++] = (uint8_t)i;
491d4f37b09SIntel 	}
492d4f37b09SIntel 
493d4f37b09SIntel 	if (num_ports < 2 || num_ports % 2) {
494d4f37b09SIntel 		printf("Current enabled port number is %u,"
495d4f37b09SIntel 			" but it should be even and at least 2\n", num_ports);
496d4f37b09SIntel 		return -1;
497d4f37b09SIntel 	}
498d4f37b09SIntel 
4991d8d954bSIntel 	return 0;
5001d8d954bSIntel }
5011d8d954bSIntel 
502*8cc72f28SJingjing Wu static void
503*8cc72f28SJingjing Wu update_mac_address(struct rte_mbuf *m, unsigned dst_port)
504*8cc72f28SJingjing Wu {
505*8cc72f28SJingjing Wu 	struct ether_hdr *eth;
506*8cc72f28SJingjing Wu 	void *tmp;
507*8cc72f28SJingjing Wu 
508*8cc72f28SJingjing Wu 	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
509*8cc72f28SJingjing Wu 
510*8cc72f28SJingjing Wu 	/* 02:00:00:00:00:xx */
511*8cc72f28SJingjing Wu 	tmp = &eth->d_addr.addr_bytes[0];
512*8cc72f28SJingjing Wu 	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
513*8cc72f28SJingjing Wu 
514*8cc72f28SJingjing Wu 	/* src addr */
515*8cc72f28SJingjing Wu 	ether_addr_copy(&vmdq_ports_eth_addr[dst_port], &eth->s_addr);
516*8cc72f28SJingjing Wu }
5171d8d954bSIntel 
518af75078fSIntel /* When we receive a HUP signal, print out our stats */
519af75078fSIntel static void
520af75078fSIntel sighup_handler(int signum)
521af75078fSIntel {
522*8cc72f28SJingjing Wu 	unsigned q = vmdq_queue_base;
523*8cc72f28SJingjing Wu 
524*8cc72f28SJingjing Wu 	for (; q < num_queues; q++) {
525*8cc72f28SJingjing Wu 		if (q % (num_vmdq_queues / num_pools) == 0)
526*8cc72f28SJingjing Wu 			printf("\nPool %u: ", (q - vmdq_queue_base) /
527*8cc72f28SJingjing Wu 					      (num_vmdq_queues / num_pools));
528af75078fSIntel 		printf("%lu ", rxPackets[q]);
529af75078fSIntel 	}
530af75078fSIntel 	printf("\nFinished handling signal %d\n", signum);
531af75078fSIntel }
532af75078fSIntel 
533af75078fSIntel /*
534af75078fSIntel  * Main thread that does the work, reading from INPUT_PORT
535af75078fSIntel  * and writing to OUTPUT_PORT
536af75078fSIntel  */
537*8cc72f28SJingjing Wu static int
538af75078fSIntel lcore_main(void *arg)
539af75078fSIntel {
540af75078fSIntel 	const uintptr_t core_num = (uintptr_t)arg;
541af75078fSIntel 	const unsigned num_cores = rte_lcore_count();
542*8cc72f28SJingjing Wu 	uint16_t startQueue, endQueue;
543d4f37b09SIntel 	uint16_t q, i, p;
544*8cc72f28SJingjing Wu 	const uint16_t quot = (uint16_t)(num_vmdq_queues / num_cores);
545*8cc72f28SJingjing Wu 	const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores);
546af75078fSIntel 
547*8cc72f28SJingjing Wu 
548*8cc72f28SJingjing Wu 	if (remainder) {
549*8cc72f28SJingjing Wu 		if (core_num < remainder) {
550*8cc72f28SJingjing Wu 			startQueue = (uint16_t)(core_num * (quot + 1));
551*8cc72f28SJingjing Wu 			endQueue = (uint16_t)(startQueue + quot + 1);
552*8cc72f28SJingjing Wu 		} else {
553*8cc72f28SJingjing Wu 			startQueue = (uint16_t)(core_num * quot + remainder);
554*8cc72f28SJingjing Wu 			endQueue = (uint16_t)(startQueue + quot);
555*8cc72f28SJingjing Wu 		}
556*8cc72f28SJingjing Wu 	} else {
557*8cc72f28SJingjing Wu 		startQueue = (uint16_t)(core_num * quot);
558*8cc72f28SJingjing Wu 		endQueue = (uint16_t)(startQueue + quot);
559*8cc72f28SJingjing Wu 	}
560*8cc72f28SJingjing Wu 
561*8cc72f28SJingjing Wu 	/* vmdq queue idx doesn't always start from zero.*/
562*8cc72f28SJingjing Wu 	startQueue += vmdq_queue_base;
563*8cc72f28SJingjing Wu 	endQueue   += vmdq_queue_base;
564af75078fSIntel 	printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
565af75078fSIntel 	       rte_lcore_id(), startQueue, endQueue - 1);
566af75078fSIntel 
567*8cc72f28SJingjing Wu 	if (startQueue == endQueue) {
568*8cc72f28SJingjing Wu 		printf("lcore %u has nothing to do\n", (unsigned)core_num);
569*8cc72f28SJingjing Wu 		return 0;
570*8cc72f28SJingjing Wu 	}
571*8cc72f28SJingjing Wu 
572af75078fSIntel 	for (;;) {
573*8cc72f28SJingjing Wu 		struct rte_mbuf *buf[MAX_PKT_BURST];
574af75078fSIntel 		const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
575d4f37b09SIntel 		for (p = 0; p < num_ports; p++) {
576d4f37b09SIntel 			const uint8_t src = ports[p];
577d4f37b09SIntel 			const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
578d4f37b09SIntel 
579d4f37b09SIntel 			if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
580d4f37b09SIntel 				continue;
581af75078fSIntel 
582af75078fSIntel 			for (q = startQueue; q < endQueue; q++) {
583d4f37b09SIntel 				const uint16_t rxCount = rte_eth_rx_burst(src,
584af75078fSIntel 					q, buf, buf_size);
585*8cc72f28SJingjing Wu 
586*8cc72f28SJingjing Wu 				if (unlikely(rxCount == 0))
587af75078fSIntel 					continue;
588*8cc72f28SJingjing Wu 
589af75078fSIntel 				rxPackets[q] += rxCount;
590af75078fSIntel 
591*8cc72f28SJingjing Wu 				for (i = 0; i < rxCount; i++)
592*8cc72f28SJingjing Wu 					update_mac_address(buf[i], dst);
593*8cc72f28SJingjing Wu 
594d4f37b09SIntel 				const uint16_t txCount = rte_eth_tx_burst(dst,
595*8cc72f28SJingjing Wu 					q, buf, rxCount);
596af75078fSIntel 				if (txCount != rxCount) {
597af75078fSIntel 					for (i = txCount; i < rxCount; i++)
598af75078fSIntel 						rte_pktmbuf_free(buf[i]);
599af75078fSIntel 				}
600af75078fSIntel 			}
601af75078fSIntel 		}
602af75078fSIntel 	}
603d4f37b09SIntel }
604d4f37b09SIntel 
605d4f37b09SIntel /*
606d4f37b09SIntel  * Update the global var NUM_PORTS and array PORTS according to system ports number
607d4f37b09SIntel  * and return valid ports number
608d4f37b09SIntel  */
609d4f37b09SIntel static unsigned check_ports_num(unsigned nb_ports)
610d4f37b09SIntel {
611d4f37b09SIntel 	unsigned valid_num_ports = num_ports;
612d4f37b09SIntel 	unsigned portid;
613d4f37b09SIntel 
614d4f37b09SIntel 	if (num_ports > nb_ports) {
615d4f37b09SIntel 		printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
616d4f37b09SIntel 			num_ports, nb_ports);
617d4f37b09SIntel 		num_ports = nb_ports;
618d4f37b09SIntel 	}
619d4f37b09SIntel 
620d4f37b09SIntel 	for (portid = 0; portid < num_ports; portid++) {
621d4f37b09SIntel 		if (ports[portid] >= nb_ports) {
622d4f37b09SIntel 			printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
623d4f37b09SIntel 				ports[portid], (nb_ports - 1));
624d4f37b09SIntel 			ports[portid] = INVALID_PORT_ID;
625d4f37b09SIntel 			valid_num_ports--;
626d4f37b09SIntel 		}
627d4f37b09SIntel 	}
628d4f37b09SIntel 	return valid_num_ports;
629d4f37b09SIntel }
630d4f37b09SIntel 
631af75078fSIntel 
632af75078fSIntel /* Main function, does initialisation and calls the per-lcore functions */
633af75078fSIntel int
63498a16481SDavid Marchand main(int argc, char *argv[])
635af75078fSIntel {
636af75078fSIntel 	unsigned cores;
637af75078fSIntel 	struct rte_mempool *mbuf_pool;
638af75078fSIntel 	unsigned lcore_id;
639af75078fSIntel 	uintptr_t i;
6401d8d954bSIntel 	int ret;
641d4f37b09SIntel 	unsigned nb_ports, valid_num_ports;
642d4f37b09SIntel 	uint8_t portid;
643af75078fSIntel 
644af75078fSIntel 	signal(SIGHUP, sighup_handler);
645af75078fSIntel 
6461d8d954bSIntel 	/* init EAL */
6471d8d954bSIntel 	ret = rte_eal_init(argc, argv);
6481d8d954bSIntel 	if (ret < 0)
649af75078fSIntel 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
6501d8d954bSIntel 	argc -= ret;
6511d8d954bSIntel 	argv += ret;
6521d8d954bSIntel 
6531d8d954bSIntel 	/* parse app arguments */
6541d8d954bSIntel 	ret = vmdq_parse_args(argc, argv);
6551d8d954bSIntel 	if (ret < 0)
6561d8d954bSIntel 		rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
6571d8d954bSIntel 
658af75078fSIntel 	cores = rte_lcore_count();
659*8cc72f28SJingjing Wu 	if ((cores & (cores - 1)) != 0 || cores > RTE_MAX_LCORE) {
660d4f37b09SIntel 		rte_exit(EXIT_FAILURE,"This program can only run on an even"
661*8cc72f28SJingjing Wu 				" number of cores(1-%d)\n\n", RTE_MAX_LCORE);
662af75078fSIntel 	}
663af75078fSIntel 
664d4f37b09SIntel 	nb_ports = rte_eth_dev_count();
665d4f37b09SIntel 	if (nb_ports > RTE_MAX_ETHPORTS)
666d4f37b09SIntel 		nb_ports = RTE_MAX_ETHPORTS;
667d4f37b09SIntel 
668d4f37b09SIntel 	/*
669d4f37b09SIntel 	 * Update the global var NUM_PORTS and global array PORTS
670d4f37b09SIntel 	 * and get value of var VALID_NUM_PORTS according to system ports number
671d4f37b09SIntel 	 */
672d4f37b09SIntel 	valid_num_ports = check_ports_num(nb_ports);
673d4f37b09SIntel 
674d4f37b09SIntel 	if (valid_num_ports < 2 || valid_num_ports % 2) {
675d4f37b09SIntel 		printf("Current valid ports number is %u\n", valid_num_ports);
676d4f37b09SIntel 		rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
677d4f37b09SIntel 	}
678d4f37b09SIntel 
679*8cc72f28SJingjing Wu 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
680*8cc72f28SJingjing Wu 		NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE,
681*8cc72f28SJingjing Wu 		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
682af75078fSIntel 	if (mbuf_pool == NULL)
683af75078fSIntel 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
684af75078fSIntel 
685d4f37b09SIntel 	/* initialize all ports */
686d4f37b09SIntel 	for (portid = 0; portid < nb_ports; portid++) {
687d4f37b09SIntel 		/* skip ports that are not enabled */
688d4f37b09SIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
689d4f37b09SIntel 			printf("\nSkipping disabled port %d\n", portid);
690d4f37b09SIntel 			continue;
691d4f37b09SIntel 		}
692d4f37b09SIntel 		if (port_init(portid, mbuf_pool) != 0)
693af75078fSIntel 			rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
694d4f37b09SIntel 	}
695af75078fSIntel 
696af75078fSIntel 	/* call lcore_main() on every slave lcore */
697af75078fSIntel 	i = 0;
698af75078fSIntel 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
699af75078fSIntel 		rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
700af75078fSIntel 	}
701af75078fSIntel 	/* call on master too */
702af75078fSIntel 	(void) lcore_main((void*)i);
703af75078fSIntel 
704af75078fSIntel 	return 0;
705af75078fSIntel }
706