xref: /dpdk/examples/vmdq_dcb/main.c (revision e9d48c0072d36eb6423b45fba4ec49d0def6c36f)
1af75078fSIntel /*-
2af75078fSIntel  *   BSD LICENSE
3af75078fSIntel  *
4*e9d48c00SBruce 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 #include "main.h"
74af75078fSIntel 
75af75078fSIntel /* basic constants used in application */
76af75078fSIntel #define NUM_QUEUES 128
77af75078fSIntel 
78af75078fSIntel #define NUM_MBUFS 64*1024
79af75078fSIntel #define MBUF_CACHE_SIZE 64
80af75078fSIntel #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
81af75078fSIntel 
82d4f37b09SIntel #define INVALID_PORT_ID 0xFF
83d4f37b09SIntel 
84d4f37b09SIntel /* mask of enabled ports */
85d4f37b09SIntel static uint32_t enabled_port_mask = 0;
86af75078fSIntel 
871d8d954bSIntel /* number of pools (if user does not specify any, 16 by default */
881d8d954bSIntel static enum rte_eth_nb_pools num_pools = ETH_16_POOLS;
891d8d954bSIntel 
90af75078fSIntel /*
91af75078fSIntel  * RX and TX Prefetch, Host, and Write-back threshold values should be
92af75078fSIntel  * carefully set for optimal performance. Consult the network
93af75078fSIntel  * controller's datasheet and supporting DPDK documentation for guidance
94af75078fSIntel  * on how these parameters should be set.
95af75078fSIntel  */
96af75078fSIntel /* Default configuration for rx and tx thresholds etc. */
97af75078fSIntel static const struct rte_eth_rxconf rx_conf_default = {
98af75078fSIntel 	.rx_thresh = {
99af75078fSIntel 		.pthresh = 8,
100af75078fSIntel 		.hthresh = 8,
101af75078fSIntel 		.wthresh = 4,
102af75078fSIntel 	},
103af75078fSIntel };
104af75078fSIntel 
105af75078fSIntel /*
106af75078fSIntel  * These default values are optimized for use with the Intel(R) 82599 10 GbE
107af75078fSIntel  * Controller and the DPDK ixgbe PMD. Consider using other values for other
108af75078fSIntel  * network controllers and/or network drivers.
109af75078fSIntel  */
110af75078fSIntel static const struct rte_eth_txconf tx_conf_default = {
111af75078fSIntel 	.tx_thresh = {
112af75078fSIntel 		.pthresh = 36,
113af75078fSIntel 		.hthresh = 0,
114af75078fSIntel 		.wthresh = 0,
115af75078fSIntel 	},
116af75078fSIntel 	.tx_free_thresh = 0, /* Use PMD default values */
117af75078fSIntel 	.tx_rs_thresh = 0, /* Use PMD default values */
118af75078fSIntel };
119af75078fSIntel 
120af75078fSIntel /* empty vmdq+dcb configuration structure. Filled in programatically */
121af75078fSIntel static const struct rte_eth_conf vmdq_dcb_conf_default = {
122af75078fSIntel 	.rxmode = {
12332e7aa0bSIntel 		.mq_mode        = ETH_MQ_RX_VMDQ_DCB,
124af75078fSIntel 		.split_hdr_size = 0,
125af75078fSIntel 		.header_split   = 0, /**< Header Split disabled */
126af75078fSIntel 		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
127af75078fSIntel 		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
128af75078fSIntel 		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
129af75078fSIntel 	},
130af75078fSIntel 	.txmode = {
13132e7aa0bSIntel 		.mq_mode = ETH_MQ_TX_NONE,
132af75078fSIntel 	},
133af75078fSIntel 	.rx_adv_conf = {
134af75078fSIntel 		/*
135af75078fSIntel 		 * should be overridden separately in code with
136af75078fSIntel 		 * appropriate values
137af75078fSIntel 		 */
138af75078fSIntel 		.vmdq_dcb_conf = {
1391d8d954bSIntel 			.nb_queue_pools = ETH_16_POOLS,
140af75078fSIntel 			.enable_default_pool = 0,
141af75078fSIntel 			.default_pool = 0,
142af75078fSIntel 			.nb_pool_maps = 0,
143af75078fSIntel 			.pool_map = {{0, 0},},
144af75078fSIntel 			.dcb_queue = {0},
145af75078fSIntel 		},
146af75078fSIntel 	},
147af75078fSIntel };
148af75078fSIntel 
149d4f37b09SIntel static uint8_t ports[RTE_MAX_ETHPORTS];
150d4f37b09SIntel static unsigned num_ports = 0;
151d4f37b09SIntel 
152af75078fSIntel /* array used for printing out statistics */
153af75078fSIntel volatile unsigned long rxPackets[ NUM_QUEUES ] = {0};
154af75078fSIntel 
155af75078fSIntel const uint16_t vlan_tags[] = {
156af75078fSIntel 	0,  1,  2,  3,  4,  5,  6,  7,
157af75078fSIntel 	8,  9, 10, 11,	12, 13, 14, 15,
158af75078fSIntel 	16, 17, 18, 19, 20, 21, 22, 23,
159af75078fSIntel 	24, 25, 26, 27, 28, 29, 30, 31
160af75078fSIntel };
161af75078fSIntel 
162af75078fSIntel /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
163af75078fSIntel  * given above, and the number of traffic classes available for use. */
164af75078fSIntel static inline int
165af75078fSIntel get_eth_conf(struct rte_eth_conf *eth_conf, enum rte_eth_nb_pools num_pools)
166af75078fSIntel {
167af75078fSIntel 	struct rte_eth_vmdq_dcb_conf conf;
168af75078fSIntel 	unsigned i;
169af75078fSIntel 
170af75078fSIntel 	if (num_pools != ETH_16_POOLS && num_pools != ETH_32_POOLS ) return -1;
171af75078fSIntel 
172af75078fSIntel 	conf.nb_queue_pools = num_pools;
173af75078fSIntel 	conf.enable_default_pool = 0;
1741d8d954bSIntel 	conf.default_pool = 0; /* set explicit value, even if not used */
175af75078fSIntel 	conf.nb_pool_maps = sizeof( vlan_tags )/sizeof( vlan_tags[ 0 ]);
176af75078fSIntel 	for (i = 0; i < conf.nb_pool_maps; i++){
177af75078fSIntel 		conf.pool_map[i].vlan_id = vlan_tags[ i ];
178af75078fSIntel 		conf.pool_map[i].pools = 1 << (i % num_pools);
179af75078fSIntel 	}
180af75078fSIntel 	for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
181af75078fSIntel 		conf.dcb_queue[i] = (uint8_t)(i % (NUM_QUEUES/num_pools));
182af75078fSIntel 	}
1831d8d954bSIntel 	(void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
1841d8d954bSIntel 	(void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
1851d8d954bSIntel 		   sizeof(eth_conf->rx_adv_conf.vmdq_dcb_conf)));
186af75078fSIntel 	return 0;
187af75078fSIntel }
188af75078fSIntel 
189af75078fSIntel /*
190af75078fSIntel  * Initialises a given port using global settings and with the rx buffers
191af75078fSIntel  * coming from the mbuf_pool passed as parameter
192af75078fSIntel  */
193af75078fSIntel static inline int
194af75078fSIntel port_init(uint8_t port, struct rte_mempool *mbuf_pool)
195af75078fSIntel {
196af75078fSIntel 	struct rte_eth_conf port_conf;
197af75078fSIntel 	const uint16_t rxRings = ETH_VMDQ_DCB_NUM_QUEUES,
198af75078fSIntel 		txRings = (uint16_t)rte_lcore_count();
199af75078fSIntel 	const uint16_t rxRingSize = 128, txRingSize = 512;
200af75078fSIntel 	int retval;
201af75078fSIntel 	uint16_t q;
202af75078fSIntel 
2031d8d954bSIntel 	retval = get_eth_conf(&port_conf, num_pools);
2041d8d954bSIntel 	if (retval < 0)
2051d8d954bSIntel 		return retval;
206af75078fSIntel 
207af75078fSIntel 	if (port >= rte_eth_dev_count()) return -1;
208af75078fSIntel 
209af75078fSIntel 	retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
210af75078fSIntel 	if (retval != 0)
211af75078fSIntel 		return retval;
212af75078fSIntel 
213af75078fSIntel 	for (q = 0; q < rxRings; q ++) {
214af75078fSIntel 		retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
215e60f71ebSIntel 						rte_eth_dev_socket_id(port), &rx_conf_default,
216af75078fSIntel 						mbuf_pool);
217af75078fSIntel 		if (retval < 0)
218af75078fSIntel 			return retval;
219af75078fSIntel 	}
220af75078fSIntel 
221af75078fSIntel 	for (q = 0; q < txRings; q ++) {
222af75078fSIntel 		retval = rte_eth_tx_queue_setup(port, q, txRingSize,
223e60f71ebSIntel 						rte_eth_dev_socket_id(port), &tx_conf_default);
224af75078fSIntel 		if (retval < 0)
225af75078fSIntel 			return retval;
226af75078fSIntel 	}
227af75078fSIntel 
228af75078fSIntel 	retval  = rte_eth_dev_start(port);
229af75078fSIntel 	if (retval < 0)
230af75078fSIntel 		return retval;
231af75078fSIntel 
232967b6294SIntel 	struct ether_addr addr;
233967b6294SIntel 	rte_eth_macaddr_get(port, &addr);
234967b6294SIntel 	printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
235967b6294SIntel 			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
236967b6294SIntel 			(unsigned)port,
237967b6294SIntel 			addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
238967b6294SIntel 			addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
239967b6294SIntel 
240af75078fSIntel 	return 0;
241af75078fSIntel }
242af75078fSIntel 
2431d8d954bSIntel /* Check num_pools parameter and set it if OK*/
2441d8d954bSIntel static int
2451d8d954bSIntel vmdq_parse_num_pools(const char *q_arg)
2461d8d954bSIntel {
2471d8d954bSIntel 	char *end = NULL;
2481d8d954bSIntel 	int n;
2491d8d954bSIntel 
2501d8d954bSIntel 	/* parse number string */
2511d8d954bSIntel 	n = strtol(q_arg, &end, 10);
2521d8d954bSIntel 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
2531d8d954bSIntel 		return -1;
2541d8d954bSIntel 	if (n != 16 && n != 32)
2551d8d954bSIntel 		return -1;
2561d8d954bSIntel 	if (n == 16)
2571d8d954bSIntel 		num_pools = ETH_16_POOLS;
2581d8d954bSIntel 	else
2591d8d954bSIntel 		num_pools = ETH_32_POOLS;
2601d8d954bSIntel 
2611d8d954bSIntel 	return 0;
2621d8d954bSIntel }
2631d8d954bSIntel 
264d4f37b09SIntel static int
265d4f37b09SIntel parse_portmask(const char *portmask)
266d4f37b09SIntel {
267d4f37b09SIntel 	char *end = NULL;
268d4f37b09SIntel 	unsigned long pm;
269d4f37b09SIntel 
270d4f37b09SIntel 	/* parse hexadecimal string */
271d4f37b09SIntel 	pm = strtoul(portmask, &end, 16);
272d4f37b09SIntel 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
273d4f37b09SIntel 		return -1;
274d4f37b09SIntel 
275d4f37b09SIntel 	if (pm == 0)
276d4f37b09SIntel 		return -1;
277d4f37b09SIntel 
278d4f37b09SIntel 	return pm;
279d4f37b09SIntel }
280d4f37b09SIntel 
2811d8d954bSIntel /* Display usage */
2821d8d954bSIntel static void
2831d8d954bSIntel vmdq_usage(const char *prgname)
2841d8d954bSIntel {
285d4f37b09SIntel 	printf("%s [EAL options] -- -p PORTMASK]\n"
286d4f37b09SIntel 	       "  --nb-pools NP: number of pools (16 default, 32)\n",
2871d8d954bSIntel 	       prgname);
2881d8d954bSIntel }
2891d8d954bSIntel 
2901d8d954bSIntel /*  Parse the argument (num_pools) given in the command line of the application */
2911d8d954bSIntel static int
2921d8d954bSIntel vmdq_parse_args(int argc, char **argv)
2931d8d954bSIntel {
2941d8d954bSIntel 	int opt;
2951d8d954bSIntel 	int option_index;
296d4f37b09SIntel 	unsigned i;
2971d8d954bSIntel 	const char *prgname = argv[0];
2981d8d954bSIntel 	static struct option long_option[] = {
2991d8d954bSIntel 		{"nb-pools", required_argument, NULL, 0},
3001d8d954bSIntel 		{NULL, 0, 0, 0}
3011d8d954bSIntel 	};
3021d8d954bSIntel 
3031d8d954bSIntel 	/* Parse command line */
304d4f37b09SIntel 	while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
3051d8d954bSIntel 		switch (opt) {
306d4f37b09SIntel 		/* portmask */
307d4f37b09SIntel 		case 'p':
308d4f37b09SIntel 			enabled_port_mask = parse_portmask(optarg);
309d4f37b09SIntel 			if (enabled_port_mask == 0) {
310d4f37b09SIntel 				printf("invalid portmask\n");
311d4f37b09SIntel 				vmdq_usage(prgname);
312d4f37b09SIntel 				return -1;
313d4f37b09SIntel 			}
314d4f37b09SIntel 			break;
3151d8d954bSIntel 		case 0:
3161d8d954bSIntel 			if (vmdq_parse_num_pools(optarg) == -1){
3171d8d954bSIntel 				printf("invalid number of pools\n");
3181d8d954bSIntel 				vmdq_usage(prgname);
3191d8d954bSIntel 				return -1;
3201d8d954bSIntel 			}
3211d8d954bSIntel 			break;
3221d8d954bSIntel 		default:
3231d8d954bSIntel 			vmdq_usage(prgname);
3241d8d954bSIntel 			return -1;
3251d8d954bSIntel 		}
3261d8d954bSIntel 	}
327d4f37b09SIntel 
328d4f37b09SIntel 	for(i = 0; i < RTE_MAX_ETHPORTS; i++)
329d4f37b09SIntel 	{
330d4f37b09SIntel 		if (enabled_port_mask & (1 << i))
331d4f37b09SIntel 			ports[num_ports++] = (uint8_t)i;
332d4f37b09SIntel 	}
333d4f37b09SIntel 
334d4f37b09SIntel 	if (num_ports < 2 || num_ports % 2) {
335d4f37b09SIntel 		printf("Current enabled port number is %u,"
336d4f37b09SIntel 			"but it should be even and at least 2\n",num_ports);
337d4f37b09SIntel 		return -1;
338d4f37b09SIntel 	}
339d4f37b09SIntel 
3401d8d954bSIntel 	return 0;
3411d8d954bSIntel }
3421d8d954bSIntel 
3431d8d954bSIntel 
344af75078fSIntel #ifndef RTE_EXEC_ENV_BAREMETAL
345af75078fSIntel /* When we receive a HUP signal, print out our stats */
346af75078fSIntel static void
347af75078fSIntel sighup_handler(int signum)
348af75078fSIntel {
349af75078fSIntel 	unsigned q;
350af75078fSIntel 	for (q = 0; q < NUM_QUEUES; q ++) {
3511d8d954bSIntel 		if (q % (NUM_QUEUES/num_pools) == 0)
3521d8d954bSIntel 			printf("\nPool %u: ", q/(NUM_QUEUES/num_pools));
353af75078fSIntel 		printf("%lu ", rxPackets[ q ]);
354af75078fSIntel 	}
355af75078fSIntel 	printf("\nFinished handling signal %d\n", signum);
356af75078fSIntel }
357af75078fSIntel #endif
358af75078fSIntel 
359af75078fSIntel /*
360af75078fSIntel  * Main thread that does the work, reading from INPUT_PORT
361af75078fSIntel  * and writing to OUTPUT_PORT
362af75078fSIntel  */
363af75078fSIntel static  __attribute__((noreturn)) int
364af75078fSIntel lcore_main(void *arg)
365af75078fSIntel {
366af75078fSIntel 	const uintptr_t core_num = (uintptr_t)arg;
367af75078fSIntel 	const unsigned num_cores = rte_lcore_count();
368af75078fSIntel 	uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores));
369af75078fSIntel 	uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores));
370d4f37b09SIntel 	uint16_t q, i, p;
371af75078fSIntel 
372af75078fSIntel 	printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
373af75078fSIntel 	       rte_lcore_id(), startQueue, endQueue - 1);
374af75078fSIntel 
375af75078fSIntel 	for (;;) {
376af75078fSIntel 		struct rte_mbuf *buf[32];
377af75078fSIntel 		const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
378d4f37b09SIntel 		for (p = 0; p < num_ports; p++) {
379d4f37b09SIntel 			const uint8_t src = ports[p];
380d4f37b09SIntel 			const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
381d4f37b09SIntel 
382d4f37b09SIntel 			if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
383d4f37b09SIntel 				continue;
384af75078fSIntel 
385af75078fSIntel 			for (q = startQueue; q < endQueue; q++) {
386d4f37b09SIntel 				const uint16_t rxCount = rte_eth_rx_burst(src,
387af75078fSIntel 					q, buf, buf_size);
388af75078fSIntel 				if (rxCount == 0)
389af75078fSIntel 					continue;
390af75078fSIntel 				rxPackets[q] += rxCount;
391af75078fSIntel 
392d4f37b09SIntel 				const uint16_t txCount = rte_eth_tx_burst(dst,
393af75078fSIntel 					(uint16_t)core_num, buf, rxCount);
394af75078fSIntel 				if (txCount != rxCount) {
395af75078fSIntel 					for (i = txCount; i < rxCount; i++)
396af75078fSIntel 						rte_pktmbuf_free(buf[i]);
397af75078fSIntel 				}
398af75078fSIntel 			}
399af75078fSIntel 		}
400af75078fSIntel 	}
401d4f37b09SIntel }
402d4f37b09SIntel 
403d4f37b09SIntel /*
404d4f37b09SIntel  * Update the global var NUM_PORTS and array PORTS according to system ports number
405d4f37b09SIntel  * and return valid ports number
406d4f37b09SIntel  */
407d4f37b09SIntel static unsigned check_ports_num(unsigned nb_ports)
408d4f37b09SIntel {
409d4f37b09SIntel 	unsigned valid_num_ports = num_ports;
410d4f37b09SIntel 	unsigned portid;
411d4f37b09SIntel 
412d4f37b09SIntel 	if (num_ports > nb_ports) {
413d4f37b09SIntel 		printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
414d4f37b09SIntel 			num_ports, nb_ports);
415d4f37b09SIntel 		num_ports = nb_ports;
416d4f37b09SIntel 	}
417d4f37b09SIntel 
418d4f37b09SIntel 	for (portid = 0; portid < num_ports; portid ++) {
419d4f37b09SIntel 		if (ports[portid] >= nb_ports) {
420d4f37b09SIntel 			printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
421d4f37b09SIntel 				ports[portid], (nb_ports - 1));
422d4f37b09SIntel 			ports[portid] = INVALID_PORT_ID;
423d4f37b09SIntel 			valid_num_ports --;
424d4f37b09SIntel 		}
425d4f37b09SIntel 	}
426d4f37b09SIntel 	return valid_num_ports;
427d4f37b09SIntel }
428d4f37b09SIntel 
429af75078fSIntel 
430af75078fSIntel /* Main function, does initialisation and calls the per-lcore functions */
431af75078fSIntel int
432af75078fSIntel MAIN(int argc, char *argv[])
433af75078fSIntel {
434af75078fSIntel 	unsigned cores;
435af75078fSIntel 	struct rte_mempool *mbuf_pool;
436af75078fSIntel 	unsigned lcore_id;
437af75078fSIntel 	uintptr_t i;
4381d8d954bSIntel 	int ret;
439d4f37b09SIntel 	unsigned nb_ports, valid_num_ports;
440d4f37b09SIntel 	uint8_t portid;
441af75078fSIntel 
442af75078fSIntel #ifndef RTE_EXEC_ENV_BAREMETAL
443af75078fSIntel 	signal(SIGHUP, sighup_handler);
444af75078fSIntel #endif
445af75078fSIntel 
4461d8d954bSIntel 	/* init EAL */
4471d8d954bSIntel 	ret = rte_eal_init(argc, argv);
4481d8d954bSIntel 	if (ret < 0)
449af75078fSIntel 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
4501d8d954bSIntel 	argc -= ret;
4511d8d954bSIntel 	argv += ret;
4521d8d954bSIntel 
4531d8d954bSIntel 	/* parse app arguments */
4541d8d954bSIntel 	ret = vmdq_parse_args(argc, argv);
4551d8d954bSIntel 	if (ret < 0)
4561d8d954bSIntel 		rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
4571d8d954bSIntel 
4581d8d954bSIntel 	if (rte_ixgbe_pmd_init() != 0 ||
459af75078fSIntel 			rte_eal_pci_probe() != 0)
460af75078fSIntel 		rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n");
461af75078fSIntel 
462af75078fSIntel 	cores = rte_lcore_count();
463d4f37b09SIntel 	if ((cores & (cores - 1)) != 0 || cores > 128) {
464d4f37b09SIntel 		rte_exit(EXIT_FAILURE,"This program can only run on an even"
465d4f37b09SIntel 				"number of cores(1-128)\n\n");
466af75078fSIntel 	}
467af75078fSIntel 
468d4f37b09SIntel 	nb_ports = rte_eth_dev_count();
469d4f37b09SIntel 	if (nb_ports > RTE_MAX_ETHPORTS)
470d4f37b09SIntel 		nb_ports = RTE_MAX_ETHPORTS;
471d4f37b09SIntel 
472d4f37b09SIntel         /*
473d4f37b09SIntel 	 * Update the global var NUM_PORTS and global array PORTS
474d4f37b09SIntel 	 * and get value of var VALID_NUM_PORTS according to system ports number
475d4f37b09SIntel 	 */
476d4f37b09SIntel 	valid_num_ports = check_ports_num(nb_ports);
477d4f37b09SIntel 
478d4f37b09SIntel 	if (valid_num_ports < 2 || valid_num_ports % 2) {
479d4f37b09SIntel 		printf("Current valid ports number is %u\n", valid_num_ports);
480d4f37b09SIntel 		rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
481d4f37b09SIntel 	}
482d4f37b09SIntel 
483d4f37b09SIntel 	mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
484af75078fSIntel 				       MBUF_SIZE, MBUF_CACHE_SIZE,
485af75078fSIntel 				       sizeof(struct rte_pktmbuf_pool_private),
486af75078fSIntel 				       rte_pktmbuf_pool_init, NULL,
487af75078fSIntel 				       rte_pktmbuf_init, NULL,
488e60f71ebSIntel 				       rte_socket_id(), 0);
489af75078fSIntel 	if (mbuf_pool == NULL)
490af75078fSIntel 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
491af75078fSIntel 
492d4f37b09SIntel 	/* initialize all ports */
493d4f37b09SIntel 	for (portid = 0; portid < nb_ports; portid++) {
494d4f37b09SIntel 		/* skip ports that are not enabled */
495d4f37b09SIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
496d4f37b09SIntel 			printf("\nSkipping disabled port %d\n", portid);
497d4f37b09SIntel 			continue;
498d4f37b09SIntel 		}
499d4f37b09SIntel 		if (port_init(portid, mbuf_pool) != 0)
500af75078fSIntel 			rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
501d4f37b09SIntel 	}
502af75078fSIntel 
503af75078fSIntel 	/* call lcore_main() on every slave lcore */
504af75078fSIntel 	i = 0;
505af75078fSIntel 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
506af75078fSIntel 		rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
507af75078fSIntel 	}
508af75078fSIntel 	/* call on master too */
509af75078fSIntel 	(void) lcore_main((void*)i);
510af75078fSIntel 
511af75078fSIntel 	return 0;
512af75078fSIntel }
513