xref: /dpdk/examples/vmdq/main.c (revision 6bb97df521aa0770ae83e904627cfc6a7028da14)
1*6bb97df5SIntel /*-
2*6bb97df5SIntel  *   BSD LICENSE
3*6bb97df5SIntel  *
4*6bb97df5SIntel  *   Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
5*6bb97df5SIntel  *   All rights reserved.
6*6bb97df5SIntel  *
7*6bb97df5SIntel  *   Redistribution and use in source and binary forms, with or without
8*6bb97df5SIntel  *   modification, are permitted provided that the following conditions
9*6bb97df5SIntel  *   are met:
10*6bb97df5SIntel  *
11*6bb97df5SIntel  *     * Redistributions of source code must retain the above copyright
12*6bb97df5SIntel  *       notice, this list of conditions and the following disclaimer.
13*6bb97df5SIntel  *     * Redistributions in binary form must reproduce the above copyright
14*6bb97df5SIntel  *       notice, this list of conditions and the following disclaimer in
15*6bb97df5SIntel  *       the documentation and/or other materials provided with the
16*6bb97df5SIntel  *       distribution.
17*6bb97df5SIntel  *     * Neither the name of Intel Corporation nor the names of its
18*6bb97df5SIntel  *       contributors may be used to endorse or promote products derived
19*6bb97df5SIntel  *       from this software without specific prior written permission.
20*6bb97df5SIntel  *
21*6bb97df5SIntel  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*6bb97df5SIntel  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*6bb97df5SIntel  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24*6bb97df5SIntel  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25*6bb97df5SIntel  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26*6bb97df5SIntel  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27*6bb97df5SIntel  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*6bb97df5SIntel  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29*6bb97df5SIntel  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*6bb97df5SIntel  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*6bb97df5SIntel  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*6bb97df5SIntel  */
33*6bb97df5SIntel 
34*6bb97df5SIntel #include <stdint.h>
35*6bb97df5SIntel #include <sys/queue.h>
36*6bb97df5SIntel #include <stdlib.h>
37*6bb97df5SIntel #include <string.h>
38*6bb97df5SIntel #include <stdio.h>
39*6bb97df5SIntel #include <assert.h>
40*6bb97df5SIntel #include <errno.h>
41*6bb97df5SIntel #include <signal.h>
42*6bb97df5SIntel #include <stdarg.h>
43*6bb97df5SIntel #include <inttypes.h>
44*6bb97df5SIntel #include <getopt.h>
45*6bb97df5SIntel 
46*6bb97df5SIntel #include <rte_common.h>
47*6bb97df5SIntel #include <rte_log.h>
48*6bb97df5SIntel #include <rte_memory.h>
49*6bb97df5SIntel #include <rte_memcpy.h>
50*6bb97df5SIntel #include <rte_memzone.h>
51*6bb97df5SIntel #include <rte_tailq.h>
52*6bb97df5SIntel #include <rte_eal.h>
53*6bb97df5SIntel #include <rte_per_lcore.h>
54*6bb97df5SIntel #include <rte_launch.h>
55*6bb97df5SIntel #include <rte_atomic.h>
56*6bb97df5SIntel #include <rte_cycles.h>
57*6bb97df5SIntel #include <rte_prefetch.h>
58*6bb97df5SIntel #include <rte_lcore.h>
59*6bb97df5SIntel #include <rte_per_lcore.h>
60*6bb97df5SIntel #include <rte_branch_prediction.h>
61*6bb97df5SIntel #include <rte_interrupts.h>
62*6bb97df5SIntel #include <rte_pci.h>
63*6bb97df5SIntel #include <rte_random.h>
64*6bb97df5SIntel #include <rte_debug.h>
65*6bb97df5SIntel #include <rte_ether.h>
66*6bb97df5SIntel #include <rte_ethdev.h>
67*6bb97df5SIntel #include <rte_ring.h>
68*6bb97df5SIntel #include <rte_log.h>
69*6bb97df5SIntel #include <rte_mempool.h>
70*6bb97df5SIntel #include <rte_mbuf.h>
71*6bb97df5SIntel #include <rte_memcpy.h>
72*6bb97df5SIntel 
73*6bb97df5SIntel #include "main.h"
74*6bb97df5SIntel 
75*6bb97df5SIntel #define MAX_QUEUES 128
76*6bb97df5SIntel /*
77*6bb97df5SIntel  * For 10 GbE, 128 queues require roughly
78*6bb97df5SIntel  * 128*512 (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port.
79*6bb97df5SIntel  */
80*6bb97df5SIntel #define NUM_MBUFS_PER_PORT (128*512)
81*6bb97df5SIntel #define MBUF_CACHE_SIZE 64
82*6bb97df5SIntel #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
83*6bb97df5SIntel 
84*6bb97df5SIntel /*
85*6bb97df5SIntel  * RX and TX Prefetch, Host, and Write-back threshold values should be
86*6bb97df5SIntel  * carefully set for optimal performance. Consult the network
87*6bb97df5SIntel  * controller's datasheet and supporting DPDK documentation for guidance
88*6bb97df5SIntel  * on how these parameters should be set.
89*6bb97df5SIntel  */
90*6bb97df5SIntel #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
91*6bb97df5SIntel #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
92*6bb97df5SIntel #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
93*6bb97df5SIntel 
94*6bb97df5SIntel /*
95*6bb97df5SIntel  * These default values are optimized for use with the Intel(R) 82599 10 GbE
96*6bb97df5SIntel  * Controller and the DPDK ixgbe PMD. Consider using other values for other
97*6bb97df5SIntel  * network controllers and/or network drivers.
98*6bb97df5SIntel  */
99*6bb97df5SIntel #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
100*6bb97df5SIntel #define TX_HTHRESH 0  /**< Default values of TX host threshold reg. */
101*6bb97df5SIntel #define TX_WTHRESH 0  /**< Default values of TX write-back threshold reg. */
102*6bb97df5SIntel 
103*6bb97df5SIntel #define MAX_PKT_BURST 32
104*6bb97df5SIntel 
105*6bb97df5SIntel /*
106*6bb97df5SIntel  * Configurable number of RX/TX ring descriptors
107*6bb97df5SIntel  */
108*6bb97df5SIntel #define RTE_TEST_RX_DESC_DEFAULT 128
109*6bb97df5SIntel #define RTE_TEST_TX_DESC_DEFAULT 512
110*6bb97df5SIntel 
111*6bb97df5SIntel #define INVALID_PORT_ID 0xFF
112*6bb97df5SIntel 
113*6bb97df5SIntel /* mask of enabled ports */
114*6bb97df5SIntel static uint32_t enabled_port_mask = 0;
115*6bb97df5SIntel 
116*6bb97df5SIntel /* number of pools (if user does not specify any, 8 by default */
117*6bb97df5SIntel static uint32_t num_queues = 8;
118*6bb97df5SIntel static uint32_t num_pools = 8;
119*6bb97df5SIntel 
120*6bb97df5SIntel /*
121*6bb97df5SIntel  * RX and TX Prefetch, Host, and Write-back threshold values should be
122*6bb97df5SIntel  * carefully set for optimal performance. Consult the network
123*6bb97df5SIntel  * controller's datasheet and supporting DPDK documentation for guidance
124*6bb97df5SIntel  * on how these parameters should be set.
125*6bb97df5SIntel  */
126*6bb97df5SIntel /* Default configuration for rx and tx thresholds etc. */
127*6bb97df5SIntel static const struct rte_eth_rxconf rx_conf_default = {
128*6bb97df5SIntel 	.rx_thresh = {
129*6bb97df5SIntel 		.pthresh = RX_PTHRESH,
130*6bb97df5SIntel 		.hthresh = RX_HTHRESH,
131*6bb97df5SIntel 		.wthresh = RX_WTHRESH,
132*6bb97df5SIntel 	},
133*6bb97df5SIntel };
134*6bb97df5SIntel 
135*6bb97df5SIntel /*
136*6bb97df5SIntel  * These default values are optimized for use with the Intel(R) 82599 10 GbE
137*6bb97df5SIntel  * Controller and the DPDK ixgbe/igb PMD. Consider using other values for other
138*6bb97df5SIntel  * network controllers and/or network drivers.
139*6bb97df5SIntel  */
140*6bb97df5SIntel static const struct rte_eth_txconf tx_conf_default = {
141*6bb97df5SIntel 	.tx_thresh = {
142*6bb97df5SIntel 		.pthresh = TX_PTHRESH,
143*6bb97df5SIntel 		.hthresh = TX_HTHRESH,
144*6bb97df5SIntel 		.wthresh = TX_WTHRESH,
145*6bb97df5SIntel 	},
146*6bb97df5SIntel 	.tx_free_thresh = 0, /* Use PMD default values */
147*6bb97df5SIntel 	.tx_rs_thresh = 0, /* Use PMD default values */
148*6bb97df5SIntel };
149*6bb97df5SIntel 
150*6bb97df5SIntel /* empty vmdq configuration structure. Filled in programatically */
151*6bb97df5SIntel static const struct rte_eth_conf vmdq_conf_default = {
152*6bb97df5SIntel 	.rxmode = {
153*6bb97df5SIntel 		.mq_mode        = ETH_MQ_RX_VMDQ_ONLY,
154*6bb97df5SIntel 		.split_hdr_size = 0,
155*6bb97df5SIntel 		.header_split   = 0, /**< Header Split disabled */
156*6bb97df5SIntel 		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
157*6bb97df5SIntel 		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
158*6bb97df5SIntel 		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
159*6bb97df5SIntel 	},
160*6bb97df5SIntel 
161*6bb97df5SIntel 	.txmode = {
162*6bb97df5SIntel 		.mq_mode = ETH_MQ_TX_NONE,
163*6bb97df5SIntel 	},
164*6bb97df5SIntel 	.rx_adv_conf = {
165*6bb97df5SIntel 		/*
166*6bb97df5SIntel 		 * should be overridden separately in code with
167*6bb97df5SIntel 		 * appropriate values
168*6bb97df5SIntel 		 */
169*6bb97df5SIntel 		.vmdq_rx_conf = {
170*6bb97df5SIntel 			.nb_queue_pools = ETH_8_POOLS,
171*6bb97df5SIntel 			.enable_default_pool = 0,
172*6bb97df5SIntel 			.default_pool = 0,
173*6bb97df5SIntel 			.nb_pool_maps = 0,
174*6bb97df5SIntel 			.pool_map = {{0, 0},},
175*6bb97df5SIntel 		},
176*6bb97df5SIntel 	},
177*6bb97df5SIntel };
178*6bb97df5SIntel 
179*6bb97df5SIntel static unsigned lcore_ids[RTE_MAX_LCORE];
180*6bb97df5SIntel static uint8_t ports[RTE_MAX_ETHPORTS];
181*6bb97df5SIntel static unsigned num_ports = 0; /**< The number of ports specified in command line */
182*6bb97df5SIntel 
183*6bb97df5SIntel /* array used for printing out statistics */
184*6bb97df5SIntel volatile unsigned long rxPackets[ MAX_QUEUES ] = {0};
185*6bb97df5SIntel 
186*6bb97df5SIntel const uint16_t vlan_tags[] = {
187*6bb97df5SIntel 	0,  1,  2,  3,  4,  5,  6,  7,
188*6bb97df5SIntel 	8,  9, 10, 11,	12, 13, 14, 15,
189*6bb97df5SIntel 	16, 17, 18, 19, 20, 21, 22, 23,
190*6bb97df5SIntel 	24, 25, 26, 27, 28, 29, 30, 31,
191*6bb97df5SIntel 	32, 33, 34, 35, 36, 37, 38, 39,
192*6bb97df5SIntel 	40, 41, 42, 43, 44, 45, 46, 47,
193*6bb97df5SIntel 	48, 49, 50, 51, 52, 53, 54, 55,
194*6bb97df5SIntel 	56, 57, 58, 59, 60, 61, 62, 63,
195*6bb97df5SIntel };
196*6bb97df5SIntel 
197*6bb97df5SIntel /* ethernet addresses of ports */
198*6bb97df5SIntel static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
199*6bb97df5SIntel 
200*6bb97df5SIntel #define MAX_QUEUE_NUM_10G 128
201*6bb97df5SIntel #define MAX_QUEUE_NUM_1G 8
202*6bb97df5SIntel #define MAX_POOL_MAP_NUM_10G 64
203*6bb97df5SIntel #define MAX_POOL_MAP_NUM_1G 32
204*6bb97df5SIntel #define MAX_POOL_NUM_10G 64
205*6bb97df5SIntel #define MAX_POOL_NUM_1G 8
206*6bb97df5SIntel /* Builds up the correct configuration for vmdq based on the vlan tags array
207*6bb97df5SIntel  * given above, and determine the queue number and pool map number according to valid pool number */
208*6bb97df5SIntel static inline int
209*6bb97df5SIntel get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools)
210*6bb97df5SIntel {
211*6bb97df5SIntel 	struct rte_eth_vmdq_rx_conf conf;
212*6bb97df5SIntel 	unsigned i;
213*6bb97df5SIntel 
214*6bb97df5SIntel 	conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
215*6bb97df5SIntel 	conf.enable_default_pool = 0;
216*6bb97df5SIntel 	conf.default_pool = 0; /* set explicit value, even if not used */
217*6bb97df5SIntel 	switch (num_pools) {
218*6bb97df5SIntel 	/* For 10G NIC like 82599, 128 is valid for queue number */
219*6bb97df5SIntel 	case MAX_POOL_NUM_10G:
220*6bb97df5SIntel 		num_queues = MAX_QUEUE_NUM_10G;
221*6bb97df5SIntel 		conf.nb_pool_maps = MAX_POOL_MAP_NUM_10G;
222*6bb97df5SIntel 		break;
223*6bb97df5SIntel 	/* For 1G NIC like i350, 82580 and 82576, 8 is valid for queue number */
224*6bb97df5SIntel 	case MAX_POOL_NUM_1G:
225*6bb97df5SIntel 		num_queues = MAX_QUEUE_NUM_1G;
226*6bb97df5SIntel 		conf.nb_pool_maps = MAX_POOL_MAP_NUM_1G;
227*6bb97df5SIntel 		break;
228*6bb97df5SIntel 	default:
229*6bb97df5SIntel 		return -1;
230*6bb97df5SIntel 	}
231*6bb97df5SIntel 
232*6bb97df5SIntel 	for (i = 0; i < conf.nb_pool_maps; i++){
233*6bb97df5SIntel 		conf.pool_map[i].vlan_id = vlan_tags[ i ];
234*6bb97df5SIntel 		conf.pool_map[i].pools = (1UL << (i % num_pools));
235*6bb97df5SIntel 	}
236*6bb97df5SIntel 
237*6bb97df5SIntel 	(void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
238*6bb97df5SIntel 	(void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_rx_conf, &conf,
239*6bb97df5SIntel 		   sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
240*6bb97df5SIntel 	return 0;
241*6bb97df5SIntel }
242*6bb97df5SIntel 
243*6bb97df5SIntel /*
244*6bb97df5SIntel  * Validate the pool number accrording to the max pool number gotten form dev_info
245*6bb97df5SIntel  * If the pool number is invalid, give the error message and return -1
246*6bb97df5SIntel  */
247*6bb97df5SIntel static inline int
248*6bb97df5SIntel validate_num_pools(uint32_t max_nb_pools)
249*6bb97df5SIntel {
250*6bb97df5SIntel 	if (num_pools > max_nb_pools) {
251*6bb97df5SIntel 		printf("invalid number of pools\n");
252*6bb97df5SIntel 		return -1;
253*6bb97df5SIntel 	}
254*6bb97df5SIntel 
255*6bb97df5SIntel 	switch (max_nb_pools) {
256*6bb97df5SIntel 	/* For 10G NIC like 82599, 64 is valid for pool number */
257*6bb97df5SIntel 	case MAX_POOL_NUM_10G:
258*6bb97df5SIntel 		if (num_pools != MAX_POOL_NUM_10G) {
259*6bb97df5SIntel 			printf("invalid number of pools\n");
260*6bb97df5SIntel 			return -1;
261*6bb97df5SIntel 		}
262*6bb97df5SIntel 		break;
263*6bb97df5SIntel 	/* For 1G NIC like i350, 82580 and 82576, 8 is valid for pool number */
264*6bb97df5SIntel 	case MAX_POOL_NUM_1G:
265*6bb97df5SIntel 		if (num_pools != MAX_POOL_NUM_1G) {
266*6bb97df5SIntel 			printf("invalid number of pools\n");
267*6bb97df5SIntel 			return -1;
268*6bb97df5SIntel 		}
269*6bb97df5SIntel 		break;
270*6bb97df5SIntel 	default:
271*6bb97df5SIntel 		return -1;
272*6bb97df5SIntel 	}
273*6bb97df5SIntel 
274*6bb97df5SIntel 	return 0;
275*6bb97df5SIntel }
276*6bb97df5SIntel 
277*6bb97df5SIntel /*
278*6bb97df5SIntel  * Initialises a given port using global settings and with the rx buffers
279*6bb97df5SIntel  * coming from the mbuf_pool passed as parameter
280*6bb97df5SIntel  */
281*6bb97df5SIntel static inline int
282*6bb97df5SIntel port_init(uint8_t port, struct rte_mempool *mbuf_pool)
283*6bb97df5SIntel {
284*6bb97df5SIntel 	struct rte_eth_dev_info dev_info;
285*6bb97df5SIntel 	struct rte_eth_conf port_conf;
286*6bb97df5SIntel 	uint16_t rxRings, txRings = (uint16_t)rte_lcore_count();
287*6bb97df5SIntel 	const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT, txRingSize = RTE_TEST_TX_DESC_DEFAULT;
288*6bb97df5SIntel 	int retval;
289*6bb97df5SIntel 	uint16_t q;
290*6bb97df5SIntel 	uint32_t max_nb_pools;
291*6bb97df5SIntel 
292*6bb97df5SIntel 	/* The max pool number from dev_info will be used to validate the pool number specified in cmd line */
293*6bb97df5SIntel 	rte_eth_dev_info_get (port, &dev_info);
294*6bb97df5SIntel 	max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
295*6bb97df5SIntel 	retval = validate_num_pools(max_nb_pools);
296*6bb97df5SIntel 	if (retval < 0)
297*6bb97df5SIntel 		return retval;
298*6bb97df5SIntel 
299*6bb97df5SIntel 	retval = get_eth_conf(&port_conf, num_pools);
300*6bb97df5SIntel 	if (retval < 0)
301*6bb97df5SIntel 		return retval;
302*6bb97df5SIntel 
303*6bb97df5SIntel 	if (port >= rte_eth_dev_count()) return -1;
304*6bb97df5SIntel 
305*6bb97df5SIntel 	rxRings = (uint16_t)num_queues,
306*6bb97df5SIntel 	retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
307*6bb97df5SIntel 	if (retval != 0)
308*6bb97df5SIntel 		return retval;
309*6bb97df5SIntel 
310*6bb97df5SIntel 	for (q = 0; q < rxRings; q ++) {
311*6bb97df5SIntel 		retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
312*6bb97df5SIntel 						rte_eth_dev_socket_id(port), &rx_conf_default,
313*6bb97df5SIntel 						mbuf_pool);
314*6bb97df5SIntel 		if (retval < 0)
315*6bb97df5SIntel 			return retval;
316*6bb97df5SIntel 	}
317*6bb97df5SIntel 
318*6bb97df5SIntel 	for (q = 0; q < txRings; q ++) {
319*6bb97df5SIntel 		retval = rte_eth_tx_queue_setup(port, q, txRingSize,
320*6bb97df5SIntel 						rte_eth_dev_socket_id(port), &tx_conf_default);
321*6bb97df5SIntel 		if (retval < 0)
322*6bb97df5SIntel 			return retval;
323*6bb97df5SIntel 	}
324*6bb97df5SIntel 
325*6bb97df5SIntel 	retval  = rte_eth_dev_start(port);
326*6bb97df5SIntel 	if (retval < 0)
327*6bb97df5SIntel 		return retval;
328*6bb97df5SIntel 
329*6bb97df5SIntel 	rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
330*6bb97df5SIntel 	printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
331*6bb97df5SIntel 			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
332*6bb97df5SIntel 			(unsigned)port,
333*6bb97df5SIntel 			vmdq_ports_eth_addr[port].addr_bytes[0],
334*6bb97df5SIntel 			vmdq_ports_eth_addr[port].addr_bytes[1],
335*6bb97df5SIntel 			vmdq_ports_eth_addr[port].addr_bytes[2],
336*6bb97df5SIntel 			vmdq_ports_eth_addr[port].addr_bytes[3],
337*6bb97df5SIntel 			vmdq_ports_eth_addr[port].addr_bytes[4],
338*6bb97df5SIntel 			vmdq_ports_eth_addr[port].addr_bytes[5]);
339*6bb97df5SIntel 
340*6bb97df5SIntel 	return 0;
341*6bb97df5SIntel }
342*6bb97df5SIntel 
343*6bb97df5SIntel /* Check num_pools parameter and set it if OK*/
344*6bb97df5SIntel static int
345*6bb97df5SIntel vmdq_parse_num_pools(const char *q_arg)
346*6bb97df5SIntel {
347*6bb97df5SIntel 	char *end = NULL;
348*6bb97df5SIntel 	int n;
349*6bb97df5SIntel 
350*6bb97df5SIntel 	/* parse number string */
351*6bb97df5SIntel 	n = strtol(q_arg, &end, 10);
352*6bb97df5SIntel 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
353*6bb97df5SIntel 		return -1;
354*6bb97df5SIntel 
355*6bb97df5SIntel 	num_pools = n;
356*6bb97df5SIntel 
357*6bb97df5SIntel 	return 0;
358*6bb97df5SIntel }
359*6bb97df5SIntel 
360*6bb97df5SIntel 
361*6bb97df5SIntel static int
362*6bb97df5SIntel parse_portmask(const char *portmask)
363*6bb97df5SIntel {
364*6bb97df5SIntel 	char *end = NULL;
365*6bb97df5SIntel 	unsigned long pm;
366*6bb97df5SIntel 
367*6bb97df5SIntel 	/* parse hexadecimal string */
368*6bb97df5SIntel 	pm = strtoul(portmask, &end, 16);
369*6bb97df5SIntel 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
370*6bb97df5SIntel 		return -1;
371*6bb97df5SIntel 
372*6bb97df5SIntel 	if (pm == 0)
373*6bb97df5SIntel 		return -1;
374*6bb97df5SIntel 
375*6bb97df5SIntel 	return pm;
376*6bb97df5SIntel }
377*6bb97df5SIntel 
378*6bb97df5SIntel /* Display usage */
379*6bb97df5SIntel static void
380*6bb97df5SIntel vmdq_usage(const char *prgname)
381*6bb97df5SIntel {
382*6bb97df5SIntel 	printf("%s [EAL options] -- -p PORTMASK]\n"
383*6bb97df5SIntel 	"  --nb-pools NP: number of pools\n",
384*6bb97df5SIntel 	       prgname);
385*6bb97df5SIntel }
386*6bb97df5SIntel 
387*6bb97df5SIntel /*  Parse the argument (num_pools) given in the command line of the application */
388*6bb97df5SIntel static int
389*6bb97df5SIntel vmdq_parse_args(int argc, char **argv)
390*6bb97df5SIntel {
391*6bb97df5SIntel 	int opt;
392*6bb97df5SIntel 	int option_index;
393*6bb97df5SIntel 	unsigned i;
394*6bb97df5SIntel 	const char *prgname = argv[0];
395*6bb97df5SIntel 	static struct option long_option[] = {
396*6bb97df5SIntel 		{"nb-pools", required_argument, NULL, 0},
397*6bb97df5SIntel 		{NULL, 0, 0, 0}
398*6bb97df5SIntel 	};
399*6bb97df5SIntel 
400*6bb97df5SIntel 	/* Parse command line */
401*6bb97df5SIntel 	while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
402*6bb97df5SIntel 		switch (opt) {
403*6bb97df5SIntel 		/* portmask */
404*6bb97df5SIntel 		case 'p':
405*6bb97df5SIntel 			enabled_port_mask = parse_portmask(optarg);
406*6bb97df5SIntel 			if (enabled_port_mask == 0) {
407*6bb97df5SIntel 				printf("invalid portmask\n");
408*6bb97df5SIntel 				vmdq_usage(prgname);
409*6bb97df5SIntel 				return -1;
410*6bb97df5SIntel 			}
411*6bb97df5SIntel 			break;
412*6bb97df5SIntel 		case 0:
413*6bb97df5SIntel 			if (vmdq_parse_num_pools(optarg) == -1){
414*6bb97df5SIntel 				printf("invalid number of pools\n");
415*6bb97df5SIntel 				vmdq_usage(prgname);
416*6bb97df5SIntel 				return -1;
417*6bb97df5SIntel 			}
418*6bb97df5SIntel 			break;
419*6bb97df5SIntel 
420*6bb97df5SIntel 		default:
421*6bb97df5SIntel 			vmdq_usage(prgname);
422*6bb97df5SIntel 			return -1;
423*6bb97df5SIntel 		}
424*6bb97df5SIntel 	}
425*6bb97df5SIntel 
426*6bb97df5SIntel 	for(i = 0; i < RTE_MAX_ETHPORTS; i++) {
427*6bb97df5SIntel 		if (enabled_port_mask & (1 << i))
428*6bb97df5SIntel 			ports[num_ports++] = (uint8_t)i;
429*6bb97df5SIntel 	}
430*6bb97df5SIntel 
431*6bb97df5SIntel 	if (num_ports < 2 || num_ports % 2) {
432*6bb97df5SIntel 		printf("Current enabled port number is %u,"
433*6bb97df5SIntel 			"but it should be even and at least 2\n",num_ports);
434*6bb97df5SIntel 		return -1;
435*6bb97df5SIntel 	}
436*6bb97df5SIntel 
437*6bb97df5SIntel 	return 0;
438*6bb97df5SIntel }
439*6bb97df5SIntel 
440*6bb97df5SIntel static void
441*6bb97df5SIntel update_mac_address(struct rte_mbuf *m, unsigned dst_port)
442*6bb97df5SIntel {
443*6bb97df5SIntel 	struct ether_hdr *eth;
444*6bb97df5SIntel 	void *tmp;
445*6bb97df5SIntel 
446*6bb97df5SIntel 	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
447*6bb97df5SIntel 
448*6bb97df5SIntel 	/* 02:00:00:00:00:xx */
449*6bb97df5SIntel 	tmp = &eth->d_addr.addr_bytes[0];
450*6bb97df5SIntel 	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
451*6bb97df5SIntel 
452*6bb97df5SIntel 	/* src addr */
453*6bb97df5SIntel 	ether_addr_copy(&vmdq_ports_eth_addr[dst_port], &eth->s_addr);
454*6bb97df5SIntel }
455*6bb97df5SIntel 
456*6bb97df5SIntel #ifndef RTE_EXEC_ENV_BAREMETAL
457*6bb97df5SIntel /* When we receive a HUP signal, print out our stats */
458*6bb97df5SIntel static void
459*6bb97df5SIntel sighup_handler(int signum)
460*6bb97df5SIntel {
461*6bb97df5SIntel 	unsigned q;
462*6bb97df5SIntel 	for (q = 0; q < num_queues; q ++) {
463*6bb97df5SIntel 		if (q % (num_queues/num_pools) == 0)
464*6bb97df5SIntel 			printf("\nPool %u: ", q/(num_queues/num_pools));
465*6bb97df5SIntel 		printf("%lu ", rxPackets[ q ]);
466*6bb97df5SIntel 	}
467*6bb97df5SIntel 	printf("\nFinished handling signal %d\n", signum);
468*6bb97df5SIntel }
469*6bb97df5SIntel #endif
470*6bb97df5SIntel 
471*6bb97df5SIntel /*
472*6bb97df5SIntel  * Main thread that does the work, reading from INPUT_PORT
473*6bb97df5SIntel  * and writing to OUTPUT_PORT
474*6bb97df5SIntel  */
475*6bb97df5SIntel static  __attribute__((noreturn)) int
476*6bb97df5SIntel lcore_main(__attribute__((__unused__)) void* dummy)
477*6bb97df5SIntel {
478*6bb97df5SIntel 	const uint16_t lcore_id = (uint16_t)rte_lcore_id();
479*6bb97df5SIntel 	const uint16_t num_cores = (uint16_t)rte_lcore_count();
480*6bb97df5SIntel 	uint16_t core_id = 0;
481*6bb97df5SIntel 	uint16_t startQueue, endQueue;
482*6bb97df5SIntel 	uint16_t q, i, p;
483*6bb97df5SIntel 	const uint16_t remainder = (uint16_t)(num_queues % num_cores);
484*6bb97df5SIntel 
485*6bb97df5SIntel 	for (i = 0; i < num_cores; i ++)
486*6bb97df5SIntel 		if (lcore_ids[i] == lcore_id) {
487*6bb97df5SIntel 			core_id = i;
488*6bb97df5SIntel 			break;
489*6bb97df5SIntel 		}
490*6bb97df5SIntel 
491*6bb97df5SIntel 	if (remainder != 0) {
492*6bb97df5SIntel 		if (core_id < remainder) {
493*6bb97df5SIntel 			startQueue = (uint16_t)(core_id * (num_queues/num_cores + 1));
494*6bb97df5SIntel 			endQueue = (uint16_t)(startQueue + (num_queues/num_cores) + 1);
495*6bb97df5SIntel 		} else {
496*6bb97df5SIntel 			startQueue = (uint16_t)(core_id * (num_queues/num_cores) + remainder);
497*6bb97df5SIntel 			endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
498*6bb97df5SIntel 		}
499*6bb97df5SIntel 	} else {
500*6bb97df5SIntel 		startQueue = (uint16_t)(core_id * (num_queues/num_cores));
501*6bb97df5SIntel 		endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
502*6bb97df5SIntel 	}
503*6bb97df5SIntel 
504*6bb97df5SIntel 	printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id,
505*6bb97df5SIntel 		(unsigned)lcore_id, startQueue, endQueue - 1);
506*6bb97df5SIntel 
507*6bb97df5SIntel 	for (;;) {
508*6bb97df5SIntel 		struct rte_mbuf *buf[MAX_PKT_BURST];
509*6bb97df5SIntel 		const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
510*6bb97df5SIntel 
511*6bb97df5SIntel 		for (p = 0; p < num_ports; p++) {
512*6bb97df5SIntel 			const uint8_t sport = ports[p];
513*6bb97df5SIntel 			const uint8_t dport = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
514*6bb97df5SIntel 
515*6bb97df5SIntel 			if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID))
516*6bb97df5SIntel 				continue;
517*6bb97df5SIntel 
518*6bb97df5SIntel 			for (q = startQueue; q < endQueue; q++) {
519*6bb97df5SIntel 				const uint16_t rxCount = rte_eth_rx_burst(sport,
520*6bb97df5SIntel 					q, buf, buf_size);
521*6bb97df5SIntel 
522*6bb97df5SIntel 				if (unlikely(rxCount == 0))
523*6bb97df5SIntel 					continue;
524*6bb97df5SIntel 
525*6bb97df5SIntel 				rxPackets[q] += rxCount;
526*6bb97df5SIntel 
527*6bb97df5SIntel 				for (i = 0; i < rxCount; i++)
528*6bb97df5SIntel 					update_mac_address(buf[i], dport);
529*6bb97df5SIntel 
530*6bb97df5SIntel 				const uint16_t txCount = rte_eth_tx_burst(dport,
531*6bb97df5SIntel 					lcore_id, buf, rxCount);
532*6bb97df5SIntel 
533*6bb97df5SIntel 				if (txCount != rxCount) {
534*6bb97df5SIntel 					for (i = txCount; i < rxCount; i++)
535*6bb97df5SIntel 						rte_pktmbuf_free(buf[i]);
536*6bb97df5SIntel 				}
537*6bb97df5SIntel 			}
538*6bb97df5SIntel 		}
539*6bb97df5SIntel 	}
540*6bb97df5SIntel }
541*6bb97df5SIntel 
542*6bb97df5SIntel /*
543*6bb97df5SIntel  * Update the global var NUM_PORTS and array PORTS according to system ports number
544*6bb97df5SIntel  * and return valid ports number
545*6bb97df5SIntel  */
546*6bb97df5SIntel static unsigned check_ports_num(unsigned nb_ports)
547*6bb97df5SIntel {
548*6bb97df5SIntel 	unsigned valid_num_ports = num_ports;
549*6bb97df5SIntel 	unsigned portid;
550*6bb97df5SIntel 
551*6bb97df5SIntel 	if (num_ports > nb_ports) {
552*6bb97df5SIntel 		printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
553*6bb97df5SIntel 			num_ports, nb_ports);
554*6bb97df5SIntel 		num_ports = nb_ports;
555*6bb97df5SIntel 	}
556*6bb97df5SIntel 
557*6bb97df5SIntel 	for (portid = 0; portid < num_ports; portid ++) {
558*6bb97df5SIntel 		if (ports[portid] >= nb_ports) {
559*6bb97df5SIntel 			printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
560*6bb97df5SIntel 				ports[portid], (nb_ports - 1));
561*6bb97df5SIntel 			ports[portid] = INVALID_PORT_ID;
562*6bb97df5SIntel 			valid_num_ports --;
563*6bb97df5SIntel 		}
564*6bb97df5SIntel 	}
565*6bb97df5SIntel 	return valid_num_ports;
566*6bb97df5SIntel }
567*6bb97df5SIntel 
568*6bb97df5SIntel /* Main function, does initialisation and calls the per-lcore functions */
569*6bb97df5SIntel int
570*6bb97df5SIntel MAIN(int argc, char *argv[])
571*6bb97df5SIntel {
572*6bb97df5SIntel 	struct rte_mempool *mbuf_pool;
573*6bb97df5SIntel 	unsigned lcore_id, core_id = 0;
574*6bb97df5SIntel 	int ret;
575*6bb97df5SIntel 	unsigned nb_ports, valid_num_ports;
576*6bb97df5SIntel 	uint8_t portid;
577*6bb97df5SIntel 
578*6bb97df5SIntel #ifndef RTE_EXEC_ENV_BAREMETAL
579*6bb97df5SIntel 	signal(SIGHUP, sighup_handler);
580*6bb97df5SIntel #endif
581*6bb97df5SIntel 
582*6bb97df5SIntel 	/* init EAL */
583*6bb97df5SIntel 	ret = rte_eal_init(argc, argv);
584*6bb97df5SIntel 	if (ret < 0)
585*6bb97df5SIntel 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
586*6bb97df5SIntel 	argc -= ret;
587*6bb97df5SIntel 	argv += ret;
588*6bb97df5SIntel 
589*6bb97df5SIntel 	/* parse app arguments */
590*6bb97df5SIntel 	ret = vmdq_parse_args(argc, argv);
591*6bb97df5SIntel 	if (ret < 0)
592*6bb97df5SIntel 		rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
593*6bb97df5SIntel 
594*6bb97df5SIntel 	if (rte_pmd_init_all() != 0 || rte_eal_pci_probe() != 0)
595*6bb97df5SIntel 		rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n");
596*6bb97df5SIntel 
597*6bb97df5SIntel 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++)
598*6bb97df5SIntel 		if (rte_lcore_is_enabled(lcore_id))
599*6bb97df5SIntel 			lcore_ids[core_id ++] = lcore_id;
600*6bb97df5SIntel 
601*6bb97df5SIntel 	if (rte_lcore_count() > RTE_MAX_LCORE)
602*6bb97df5SIntel 		rte_exit(EXIT_FAILURE,"Not enough cores\n");
603*6bb97df5SIntel 
604*6bb97df5SIntel 	nb_ports = rte_eth_dev_count();
605*6bb97df5SIntel 	if (nb_ports > RTE_MAX_ETHPORTS)
606*6bb97df5SIntel 		nb_ports = RTE_MAX_ETHPORTS;
607*6bb97df5SIntel 
608*6bb97df5SIntel 	/*
609*6bb97df5SIntel    	 * Update the global var NUM_PORTS and global array PORTS
610*6bb97df5SIntel   	 * and get value of var VALID_NUM_PORTS according to system ports number
611*6bb97df5SIntel   	 */
612*6bb97df5SIntel 	valid_num_ports = check_ports_num(nb_ports);
613*6bb97df5SIntel 
614*6bb97df5SIntel 	if (valid_num_ports < 2 || valid_num_ports % 2) {
615*6bb97df5SIntel 		printf("Current valid ports number is %u\n", valid_num_ports);
616*6bb97df5SIntel 		rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
617*6bb97df5SIntel 	}
618*6bb97df5SIntel 
619*6bb97df5SIntel 	mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS_PER_PORT * nb_ports,
620*6bb97df5SIntel 				       MBUF_SIZE, MBUF_CACHE_SIZE,
621*6bb97df5SIntel 				       sizeof(struct rte_pktmbuf_pool_private),
622*6bb97df5SIntel 				       rte_pktmbuf_pool_init, NULL,
623*6bb97df5SIntel 				       rte_pktmbuf_init, NULL,
624*6bb97df5SIntel 				       rte_socket_id(), 0);
625*6bb97df5SIntel 	if (mbuf_pool == NULL)
626*6bb97df5SIntel 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
627*6bb97df5SIntel 
628*6bb97df5SIntel 	/* initialize all ports */
629*6bb97df5SIntel 	for (portid = 0; portid < nb_ports; portid++) {
630*6bb97df5SIntel 		/* skip ports that are not enabled */
631*6bb97df5SIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
632*6bb97df5SIntel 			printf("\nSkipping disabled port %d\n", portid);
633*6bb97df5SIntel 			continue;
634*6bb97df5SIntel 		}
635*6bb97df5SIntel 		if (port_init(portid, mbuf_pool) != 0)
636*6bb97df5SIntel 			rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
637*6bb97df5SIntel 	}
638*6bb97df5SIntel 
639*6bb97df5SIntel 	/* call lcore_main() on every lcore */
640*6bb97df5SIntel 	rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER);
641*6bb97df5SIntel 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
642*6bb97df5SIntel 		if (rte_eal_wait_lcore(lcore_id) < 0)
643*6bb97df5SIntel 			return -1;
644*6bb97df5SIntel 	}
645*6bb97df5SIntel 
646*6bb97df5SIntel 	return 0;
647*6bb97df5SIntel }
648