xref: /dpdk/examples/vmdq_dcb/main.c (revision 98a1648109b8dbaa4e6b821c17d1f6bd86d33a9a)
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_tailq.h>
52af75078fSIntel #include <rte_eal.h>
53af75078fSIntel #include <rte_per_lcore.h>
54af75078fSIntel #include <rte_launch.h>
55af75078fSIntel #include <rte_atomic.h>
56af75078fSIntel #include <rte_cycles.h>
57af75078fSIntel #include <rte_prefetch.h>
58af75078fSIntel #include <rte_lcore.h>
59af75078fSIntel #include <rte_per_lcore.h>
60af75078fSIntel #include <rte_branch_prediction.h>
61af75078fSIntel #include <rte_interrupts.h>
62af75078fSIntel #include <rte_pci.h>
63af75078fSIntel #include <rte_random.h>
64af75078fSIntel #include <rte_debug.h>
65af75078fSIntel #include <rte_ether.h>
66af75078fSIntel #include <rte_ethdev.h>
67af75078fSIntel #include <rte_ring.h>
68af75078fSIntel #include <rte_log.h>
69af75078fSIntel #include <rte_mempool.h>
70af75078fSIntel #include <rte_mbuf.h>
71af75078fSIntel #include <rte_memcpy.h>
72af75078fSIntel 
73af75078fSIntel /* basic constants used in application */
74af75078fSIntel #define NUM_QUEUES 128
75af75078fSIntel 
76af75078fSIntel #define NUM_MBUFS 64*1024
77af75078fSIntel #define MBUF_CACHE_SIZE 64
78af75078fSIntel #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
79af75078fSIntel 
80d4f37b09SIntel #define INVALID_PORT_ID 0xFF
81d4f37b09SIntel 
82d4f37b09SIntel /* mask of enabled ports */
83d4f37b09SIntel static uint32_t enabled_port_mask = 0;
84af75078fSIntel 
851d8d954bSIntel /* number of pools (if user does not specify any, 16 by default */
861d8d954bSIntel static enum rte_eth_nb_pools num_pools = ETH_16_POOLS;
871d8d954bSIntel 
88af75078fSIntel /* empty vmdq+dcb configuration structure. Filled in programatically */
89af75078fSIntel static const struct rte_eth_conf vmdq_dcb_conf_default = {
90af75078fSIntel 	.rxmode = {
9132e7aa0bSIntel 		.mq_mode        = ETH_MQ_RX_VMDQ_DCB,
92af75078fSIntel 		.split_hdr_size = 0,
93af75078fSIntel 		.header_split   = 0, /**< Header Split disabled */
94af75078fSIntel 		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
95af75078fSIntel 		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
96af75078fSIntel 		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
97af75078fSIntel 	},
98af75078fSIntel 	.txmode = {
9932e7aa0bSIntel 		.mq_mode = ETH_MQ_TX_NONE,
100af75078fSIntel 	},
101af75078fSIntel 	.rx_adv_conf = {
102af75078fSIntel 		/*
103af75078fSIntel 		 * should be overridden separately in code with
104af75078fSIntel 		 * appropriate values
105af75078fSIntel 		 */
106af75078fSIntel 		.vmdq_dcb_conf = {
1071d8d954bSIntel 			.nb_queue_pools = ETH_16_POOLS,
108af75078fSIntel 			.enable_default_pool = 0,
109af75078fSIntel 			.default_pool = 0,
110af75078fSIntel 			.nb_pool_maps = 0,
111af75078fSIntel 			.pool_map = {{0, 0},},
112af75078fSIntel 			.dcb_queue = {0},
113af75078fSIntel 		},
114af75078fSIntel 	},
115af75078fSIntel };
116af75078fSIntel 
117d4f37b09SIntel static uint8_t ports[RTE_MAX_ETHPORTS];
118d4f37b09SIntel static unsigned num_ports = 0;
119d4f37b09SIntel 
120af75078fSIntel /* array used for printing out statistics */
121af75078fSIntel volatile unsigned long rxPackets[ NUM_QUEUES ] = {0};
122af75078fSIntel 
123af75078fSIntel const uint16_t vlan_tags[] = {
124af75078fSIntel 	0,  1,  2,  3,  4,  5,  6,  7,
125af75078fSIntel 	8,  9, 10, 11,	12, 13, 14, 15,
126af75078fSIntel 	16, 17, 18, 19, 20, 21, 22, 23,
127af75078fSIntel 	24, 25, 26, 27, 28, 29, 30, 31
128af75078fSIntel };
129af75078fSIntel 
130af75078fSIntel /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
131af75078fSIntel  * given above, and the number of traffic classes available for use. */
132af75078fSIntel static inline int
133af75078fSIntel get_eth_conf(struct rte_eth_conf *eth_conf, enum rte_eth_nb_pools num_pools)
134af75078fSIntel {
135af75078fSIntel 	struct rte_eth_vmdq_dcb_conf conf;
136af75078fSIntel 	unsigned i;
137af75078fSIntel 
138af75078fSIntel 	if (num_pools != ETH_16_POOLS && num_pools != ETH_32_POOLS ) return -1;
139af75078fSIntel 
140af75078fSIntel 	conf.nb_queue_pools = num_pools;
141af75078fSIntel 	conf.enable_default_pool = 0;
1421d8d954bSIntel 	conf.default_pool = 0; /* set explicit value, even if not used */
143af75078fSIntel 	conf.nb_pool_maps = sizeof( vlan_tags )/sizeof( vlan_tags[ 0 ]);
144af75078fSIntel 	for (i = 0; i < conf.nb_pool_maps; i++){
145af75078fSIntel 		conf.pool_map[i].vlan_id = vlan_tags[ i ];
146af75078fSIntel 		conf.pool_map[i].pools = 1 << (i % num_pools);
147af75078fSIntel 	}
148af75078fSIntel 	for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
149af75078fSIntel 		conf.dcb_queue[i] = (uint8_t)(i % (NUM_QUEUES/num_pools));
150af75078fSIntel 	}
1511d8d954bSIntel 	(void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
1521d8d954bSIntel 	(void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
1531d8d954bSIntel 		   sizeof(eth_conf->rx_adv_conf.vmdq_dcb_conf)));
154af75078fSIntel 	return 0;
155af75078fSIntel }
156af75078fSIntel 
157af75078fSIntel /*
158af75078fSIntel  * Initialises a given port using global settings and with the rx buffers
159af75078fSIntel  * coming from the mbuf_pool passed as parameter
160af75078fSIntel  */
161af75078fSIntel static inline int
162af75078fSIntel port_init(uint8_t port, struct rte_mempool *mbuf_pool)
163af75078fSIntel {
164af75078fSIntel 	struct rte_eth_conf port_conf;
165af75078fSIntel 	const uint16_t rxRings = ETH_VMDQ_DCB_NUM_QUEUES,
166af75078fSIntel 		txRings = (uint16_t)rte_lcore_count();
167af75078fSIntel 	const uint16_t rxRingSize = 128, txRingSize = 512;
168af75078fSIntel 	int retval;
169af75078fSIntel 	uint16_t q;
170af75078fSIntel 
1711d8d954bSIntel 	retval = get_eth_conf(&port_conf, num_pools);
1721d8d954bSIntel 	if (retval < 0)
1731d8d954bSIntel 		return retval;
174af75078fSIntel 
175af75078fSIntel 	if (port >= rte_eth_dev_count()) return -1;
176af75078fSIntel 
177af75078fSIntel 	retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
178af75078fSIntel 	if (retval != 0)
179af75078fSIntel 		return retval;
180af75078fSIntel 
181af75078fSIntel 	for (q = 0; q < rxRings; q ++) {
182af75078fSIntel 		retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
18381f7ecd9SPablo de Lara 						rte_eth_dev_socket_id(port),
18481f7ecd9SPablo de Lara 						NULL,
185af75078fSIntel 						mbuf_pool);
186af75078fSIntel 		if (retval < 0)
187af75078fSIntel 			return retval;
188af75078fSIntel 	}
189af75078fSIntel 
190af75078fSIntel 	for (q = 0; q < txRings; q ++) {
191af75078fSIntel 		retval = rte_eth_tx_queue_setup(port, q, txRingSize,
19281f7ecd9SPablo de Lara 						rte_eth_dev_socket_id(port),
19381f7ecd9SPablo de Lara 						NULL);
194af75078fSIntel 		if (retval < 0)
195af75078fSIntel 			return retval;
196af75078fSIntel 	}
197af75078fSIntel 
198af75078fSIntel 	retval  = rte_eth_dev_start(port);
199af75078fSIntel 	if (retval < 0)
200af75078fSIntel 		return retval;
201af75078fSIntel 
202967b6294SIntel 	struct ether_addr addr;
203967b6294SIntel 	rte_eth_macaddr_get(port, &addr);
204967b6294SIntel 	printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
205967b6294SIntel 			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
206967b6294SIntel 			(unsigned)port,
207967b6294SIntel 			addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
208967b6294SIntel 			addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
209967b6294SIntel 
210af75078fSIntel 	return 0;
211af75078fSIntel }
212af75078fSIntel 
2131d8d954bSIntel /* Check num_pools parameter and set it if OK*/
2141d8d954bSIntel static int
2151d8d954bSIntel vmdq_parse_num_pools(const char *q_arg)
2161d8d954bSIntel {
2171d8d954bSIntel 	char *end = NULL;
2181d8d954bSIntel 	int n;
2191d8d954bSIntel 
2201d8d954bSIntel 	/* parse number string */
2211d8d954bSIntel 	n = strtol(q_arg, &end, 10);
2221d8d954bSIntel 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
2231d8d954bSIntel 		return -1;
2241d8d954bSIntel 	if (n != 16 && n != 32)
2251d8d954bSIntel 		return -1;
2261d8d954bSIntel 	if (n == 16)
2271d8d954bSIntel 		num_pools = ETH_16_POOLS;
2281d8d954bSIntel 	else
2291d8d954bSIntel 		num_pools = ETH_32_POOLS;
2301d8d954bSIntel 
2311d8d954bSIntel 	return 0;
2321d8d954bSIntel }
2331d8d954bSIntel 
234d4f37b09SIntel static int
235d4f37b09SIntel parse_portmask(const char *portmask)
236d4f37b09SIntel {
237d4f37b09SIntel 	char *end = NULL;
238d4f37b09SIntel 	unsigned long pm;
239d4f37b09SIntel 
240d4f37b09SIntel 	/* parse hexadecimal string */
241d4f37b09SIntel 	pm = strtoul(portmask, &end, 16);
242d4f37b09SIntel 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
243d4f37b09SIntel 		return -1;
244d4f37b09SIntel 
245d4f37b09SIntel 	if (pm == 0)
246d4f37b09SIntel 		return -1;
247d4f37b09SIntel 
248d4f37b09SIntel 	return pm;
249d4f37b09SIntel }
250d4f37b09SIntel 
2511d8d954bSIntel /* Display usage */
2521d8d954bSIntel static void
2531d8d954bSIntel vmdq_usage(const char *prgname)
2541d8d954bSIntel {
255d4f37b09SIntel 	printf("%s [EAL options] -- -p PORTMASK]\n"
256d4f37b09SIntel 	       "  --nb-pools NP: number of pools (16 default, 32)\n",
2571d8d954bSIntel 	       prgname);
2581d8d954bSIntel }
2591d8d954bSIntel 
2601d8d954bSIntel /*  Parse the argument (num_pools) given in the command line of the application */
2611d8d954bSIntel static int
2621d8d954bSIntel vmdq_parse_args(int argc, char **argv)
2631d8d954bSIntel {
2641d8d954bSIntel 	int opt;
2651d8d954bSIntel 	int option_index;
266d4f37b09SIntel 	unsigned i;
2671d8d954bSIntel 	const char *prgname = argv[0];
2681d8d954bSIntel 	static struct option long_option[] = {
2691d8d954bSIntel 		{"nb-pools", required_argument, NULL, 0},
2701d8d954bSIntel 		{NULL, 0, 0, 0}
2711d8d954bSIntel 	};
2721d8d954bSIntel 
2731d8d954bSIntel 	/* Parse command line */
274d4f37b09SIntel 	while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
2751d8d954bSIntel 		switch (opt) {
276d4f37b09SIntel 		/* portmask */
277d4f37b09SIntel 		case 'p':
278d4f37b09SIntel 			enabled_port_mask = parse_portmask(optarg);
279d4f37b09SIntel 			if (enabled_port_mask == 0) {
280d4f37b09SIntel 				printf("invalid portmask\n");
281d4f37b09SIntel 				vmdq_usage(prgname);
282d4f37b09SIntel 				return -1;
283d4f37b09SIntel 			}
284d4f37b09SIntel 			break;
2851d8d954bSIntel 		case 0:
2861d8d954bSIntel 			if (vmdq_parse_num_pools(optarg) == -1){
2871d8d954bSIntel 				printf("invalid number of pools\n");
2881d8d954bSIntel 				vmdq_usage(prgname);
2891d8d954bSIntel 				return -1;
2901d8d954bSIntel 			}
2911d8d954bSIntel 			break;
2921d8d954bSIntel 		default:
2931d8d954bSIntel 			vmdq_usage(prgname);
2941d8d954bSIntel 			return -1;
2951d8d954bSIntel 		}
2961d8d954bSIntel 	}
297d4f37b09SIntel 
298d4f37b09SIntel 	for(i = 0; i < RTE_MAX_ETHPORTS; i++)
299d4f37b09SIntel 	{
300d4f37b09SIntel 		if (enabled_port_mask & (1 << i))
301d4f37b09SIntel 			ports[num_ports++] = (uint8_t)i;
302d4f37b09SIntel 	}
303d4f37b09SIntel 
304d4f37b09SIntel 	if (num_ports < 2 || num_ports % 2) {
305d4f37b09SIntel 		printf("Current enabled port number is %u,"
306d4f37b09SIntel 			"but it should be even and at least 2\n",num_ports);
307d4f37b09SIntel 		return -1;
308d4f37b09SIntel 	}
309d4f37b09SIntel 
3101d8d954bSIntel 	return 0;
3111d8d954bSIntel }
3121d8d954bSIntel 
3131d8d954bSIntel 
314af75078fSIntel /* When we receive a HUP signal, print out our stats */
315af75078fSIntel static void
316af75078fSIntel sighup_handler(int signum)
317af75078fSIntel {
318af75078fSIntel 	unsigned q;
319af75078fSIntel 	for (q = 0; q < NUM_QUEUES; q ++) {
3201d8d954bSIntel 		if (q % (NUM_QUEUES/num_pools) == 0)
3211d8d954bSIntel 			printf("\nPool %u: ", q/(NUM_QUEUES/num_pools));
322af75078fSIntel 		printf("%lu ", rxPackets[ q ]);
323af75078fSIntel 	}
324af75078fSIntel 	printf("\nFinished handling signal %d\n", signum);
325af75078fSIntel }
326af75078fSIntel 
327af75078fSIntel /*
328af75078fSIntel  * Main thread that does the work, reading from INPUT_PORT
329af75078fSIntel  * and writing to OUTPUT_PORT
330af75078fSIntel  */
331af75078fSIntel static  __attribute__((noreturn)) int
332af75078fSIntel lcore_main(void *arg)
333af75078fSIntel {
334af75078fSIntel 	const uintptr_t core_num = (uintptr_t)arg;
335af75078fSIntel 	const unsigned num_cores = rte_lcore_count();
336af75078fSIntel 	uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores));
337af75078fSIntel 	uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores));
338d4f37b09SIntel 	uint16_t q, i, p;
339af75078fSIntel 
340af75078fSIntel 	printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
341af75078fSIntel 	       rte_lcore_id(), startQueue, endQueue - 1);
342af75078fSIntel 
343af75078fSIntel 	for (;;) {
344af75078fSIntel 		struct rte_mbuf *buf[32];
345af75078fSIntel 		const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
346d4f37b09SIntel 		for (p = 0; p < num_ports; p++) {
347d4f37b09SIntel 			const uint8_t src = ports[p];
348d4f37b09SIntel 			const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
349d4f37b09SIntel 
350d4f37b09SIntel 			if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
351d4f37b09SIntel 				continue;
352af75078fSIntel 
353af75078fSIntel 			for (q = startQueue; q < endQueue; q++) {
354d4f37b09SIntel 				const uint16_t rxCount = rte_eth_rx_burst(src,
355af75078fSIntel 					q, buf, buf_size);
356af75078fSIntel 				if (rxCount == 0)
357af75078fSIntel 					continue;
358af75078fSIntel 				rxPackets[q] += rxCount;
359af75078fSIntel 
360d4f37b09SIntel 				const uint16_t txCount = rte_eth_tx_burst(dst,
361af75078fSIntel 					(uint16_t)core_num, buf, rxCount);
362af75078fSIntel 				if (txCount != rxCount) {
363af75078fSIntel 					for (i = txCount; i < rxCount; i++)
364af75078fSIntel 						rte_pktmbuf_free(buf[i]);
365af75078fSIntel 				}
366af75078fSIntel 			}
367af75078fSIntel 		}
368af75078fSIntel 	}
369d4f37b09SIntel }
370d4f37b09SIntel 
371d4f37b09SIntel /*
372d4f37b09SIntel  * Update the global var NUM_PORTS and array PORTS according to system ports number
373d4f37b09SIntel  * and return valid ports number
374d4f37b09SIntel  */
375d4f37b09SIntel static unsigned check_ports_num(unsigned nb_ports)
376d4f37b09SIntel {
377d4f37b09SIntel 	unsigned valid_num_ports = num_ports;
378d4f37b09SIntel 	unsigned portid;
379d4f37b09SIntel 
380d4f37b09SIntel 	if (num_ports > nb_ports) {
381d4f37b09SIntel 		printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
382d4f37b09SIntel 			num_ports, nb_ports);
383d4f37b09SIntel 		num_ports = nb_ports;
384d4f37b09SIntel 	}
385d4f37b09SIntel 
386d4f37b09SIntel 	for (portid = 0; portid < num_ports; portid ++) {
387d4f37b09SIntel 		if (ports[portid] >= nb_ports) {
388d4f37b09SIntel 			printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
389d4f37b09SIntel 				ports[portid], (nb_ports - 1));
390d4f37b09SIntel 			ports[portid] = INVALID_PORT_ID;
391d4f37b09SIntel 			valid_num_ports --;
392d4f37b09SIntel 		}
393d4f37b09SIntel 	}
394d4f37b09SIntel 	return valid_num_ports;
395d4f37b09SIntel }
396d4f37b09SIntel 
397af75078fSIntel 
398af75078fSIntel /* Main function, does initialisation and calls the per-lcore functions */
399af75078fSIntel int
400*98a16481SDavid Marchand main(int argc, char *argv[])
401af75078fSIntel {
402af75078fSIntel 	unsigned cores;
403af75078fSIntel 	struct rte_mempool *mbuf_pool;
404af75078fSIntel 	unsigned lcore_id;
405af75078fSIntel 	uintptr_t i;
4061d8d954bSIntel 	int ret;
407d4f37b09SIntel 	unsigned nb_ports, valid_num_ports;
408d4f37b09SIntel 	uint8_t portid;
409af75078fSIntel 
410af75078fSIntel 	signal(SIGHUP, sighup_handler);
411af75078fSIntel 
4121d8d954bSIntel 	/* init EAL */
4131d8d954bSIntel 	ret = rte_eal_init(argc, argv);
4141d8d954bSIntel 	if (ret < 0)
415af75078fSIntel 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
4161d8d954bSIntel 	argc -= ret;
4171d8d954bSIntel 	argv += ret;
4181d8d954bSIntel 
4191d8d954bSIntel 	/* parse app arguments */
4201d8d954bSIntel 	ret = vmdq_parse_args(argc, argv);
4211d8d954bSIntel 	if (ret < 0)
4221d8d954bSIntel 		rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
4231d8d954bSIntel 
424af75078fSIntel 	cores = rte_lcore_count();
425d4f37b09SIntel 	if ((cores & (cores - 1)) != 0 || cores > 128) {
426d4f37b09SIntel 		rte_exit(EXIT_FAILURE,"This program can only run on an even"
427d4f37b09SIntel 				"number of cores(1-128)\n\n");
428af75078fSIntel 	}
429af75078fSIntel 
430d4f37b09SIntel 	nb_ports = rte_eth_dev_count();
431d4f37b09SIntel 	if (nb_ports > RTE_MAX_ETHPORTS)
432d4f37b09SIntel 		nb_ports = RTE_MAX_ETHPORTS;
433d4f37b09SIntel 
434d4f37b09SIntel         /*
435d4f37b09SIntel 	 * Update the global var NUM_PORTS and global array PORTS
436d4f37b09SIntel 	 * and get value of var VALID_NUM_PORTS according to system ports number
437d4f37b09SIntel 	 */
438d4f37b09SIntel 	valid_num_ports = check_ports_num(nb_ports);
439d4f37b09SIntel 
440d4f37b09SIntel 	if (valid_num_ports < 2 || valid_num_ports % 2) {
441d4f37b09SIntel 		printf("Current valid ports number is %u\n", valid_num_ports);
442d4f37b09SIntel 		rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
443d4f37b09SIntel 	}
444d4f37b09SIntel 
445d4f37b09SIntel 	mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
446af75078fSIntel 				       MBUF_SIZE, MBUF_CACHE_SIZE,
447af75078fSIntel 				       sizeof(struct rte_pktmbuf_pool_private),
448af75078fSIntel 				       rte_pktmbuf_pool_init, NULL,
449af75078fSIntel 				       rte_pktmbuf_init, NULL,
450e60f71ebSIntel 				       rte_socket_id(), 0);
451af75078fSIntel 	if (mbuf_pool == NULL)
452af75078fSIntel 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
453af75078fSIntel 
454d4f37b09SIntel 	/* initialize all ports */
455d4f37b09SIntel 	for (portid = 0; portid < nb_ports; portid++) {
456d4f37b09SIntel 		/* skip ports that are not enabled */
457d4f37b09SIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
458d4f37b09SIntel 			printf("\nSkipping disabled port %d\n", portid);
459d4f37b09SIntel 			continue;
460d4f37b09SIntel 		}
461d4f37b09SIntel 		if (port_init(portid, mbuf_pool) != 0)
462af75078fSIntel 			rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
463d4f37b09SIntel 	}
464af75078fSIntel 
465af75078fSIntel 	/* call lcore_main() on every slave lcore */
466af75078fSIntel 	i = 0;
467af75078fSIntel 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
468af75078fSIntel 		rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
469af75078fSIntel 	}
470af75078fSIntel 	/* call on master too */
471af75078fSIntel 	(void) lcore_main((void*)i);
472af75078fSIntel 
473af75078fSIntel 	return 0;
474af75078fSIntel }
475