xref: /dpdk/examples/l3fwd/main.c (revision 089e5ed727a15da2729cfee9b63533dd120bd04c)
13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson  * Copyright(c) 2010-2016 Intel Corporation
3af75078fSIntel  */
4af75078fSIntel 
5af75078fSIntel #include <stdio.h>
6af75078fSIntel #include <stdlib.h>
7af75078fSIntel #include <stdint.h>
8af75078fSIntel #include <inttypes.h>
9af75078fSIntel #include <sys/types.h>
10af75078fSIntel #include <string.h>
11af75078fSIntel #include <sys/queue.h>
12af75078fSIntel #include <stdarg.h>
13af75078fSIntel #include <errno.h>
14af75078fSIntel #include <getopt.h>
15308df2bfSZhihong Wang #include <signal.h>
16308df2bfSZhihong Wang #include <stdbool.h>
17af75078fSIntel 
18af75078fSIntel #include <rte_common.h>
191e496d6fSKonstantin Ananyev #include <rte_vect.h>
20af75078fSIntel #include <rte_byteorder.h>
21af75078fSIntel #include <rte_log.h>
22af75078fSIntel #include <rte_memory.h>
23af75078fSIntel #include <rte_memcpy.h>
24af75078fSIntel #include <rte_eal.h>
25af75078fSIntel #include <rte_launch.h>
26af75078fSIntel #include <rte_atomic.h>
27af75078fSIntel #include <rte_cycles.h>
28af75078fSIntel #include <rte_prefetch.h>
29af75078fSIntel #include <rte_lcore.h>
30af75078fSIntel #include <rte_per_lcore.h>
31af75078fSIntel #include <rte_branch_prediction.h>
32af75078fSIntel #include <rte_interrupts.h>
33af75078fSIntel #include <rte_random.h>
34af75078fSIntel #include <rte_debug.h>
35af75078fSIntel #include <rte_ether.h>
36af75078fSIntel #include <rte_ethdev.h>
37af75078fSIntel #include <rte_mempool.h>
38af75078fSIntel #include <rte_mbuf.h>
39af75078fSIntel #include <rte_ip.h>
40af75078fSIntel #include <rte_tcp.h>
41af75078fSIntel #include <rte_udp.h>
42af75078fSIntel #include <rte_string_fns.h>
43268888b5SRavi Kerur #include <rte_cpuflags.h>
44af75078fSIntel 
45bd785f6fSAndrey Chilikin #include <cmdline_parse.h>
46bd785f6fSAndrey Chilikin #include <cmdline_parse_etheraddr.h>
47bd785f6fSAndrey Chilikin 
48268888b5SRavi Kerur #include "l3fwd.h"
4996ff4453SKonstantin Ananyev 
50af75078fSIntel /*
51af75078fSIntel  * Configurable number of RX/TX ring descriptors
52af75078fSIntel  */
53867a6c66SKevin Laatz #define RTE_TEST_RX_DESC_DEFAULT 1024
54867a6c66SKevin Laatz #define RTE_TEST_TX_DESC_DEFAULT 1024
55af75078fSIntel 
561c17baf4SIntel #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS
57af75078fSIntel #define MAX_RX_QUEUE_PER_PORT 128
58af75078fSIntel 
59af75078fSIntel #define MAX_LCORE_PARAMS 1024
60268888b5SRavi Kerur 
61268888b5SRavi Kerur /* Static global variables used within this file. */
62268888b5SRavi Kerur static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
63268888b5SRavi Kerur static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
64268888b5SRavi Kerur 
65268888b5SRavi Kerur /**< Ports set in promiscuous mode off by default. */
66268888b5SRavi Kerur static int promiscuous_on;
67268888b5SRavi Kerur 
68268888b5SRavi Kerur /* Select Longest-Prefix or Exact match. */
69268888b5SRavi Kerur static int l3fwd_lpm_on;
70268888b5SRavi Kerur static int l3fwd_em_on;
71268888b5SRavi Kerur 
72f0a26885SShreyansh Jain /* Global variables. */
73f0a26885SShreyansh Jain 
74268888b5SRavi Kerur static int numa_on = 1; /**< NUMA is enabled by default. */
7571a7e242SJianfeng Tan static int parse_ptype; /**< Parse packet type using rx callback, and */
7671a7e242SJianfeng Tan 			/**< disabled by default */
77f0a26885SShreyansh Jain static int per_port_pool; /**< Use separate buffer pools per port; disabled */
78f0a26885SShreyansh Jain 			  /**< by default */
79268888b5SRavi Kerur 
80268888b5SRavi Kerur volatile bool force_quit;
81268888b5SRavi Kerur 
82268888b5SRavi Kerur /* ethernet addresses of ports */
83268888b5SRavi Kerur uint64_t dest_eth_addr[RTE_MAX_ETHPORTS];
846d13ea8eSOlivier Matz struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
85268888b5SRavi Kerur 
8664d3955dSMaciej Czekaj xmm_t val_eth[RTE_MAX_ETHPORTS];
87268888b5SRavi Kerur 
88268888b5SRavi Kerur /* mask of enabled ports */
89268888b5SRavi Kerur uint32_t enabled_port_mask;
90268888b5SRavi Kerur 
91268888b5SRavi Kerur /* Used only in exact match mode. */
92268888b5SRavi Kerur int ipv6; /**< ipv6 is false by default. */
93268888b5SRavi Kerur uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
94268888b5SRavi Kerur 
95268888b5SRavi Kerur struct lcore_conf lcore_conf[RTE_MAX_LCORE];
96268888b5SRavi Kerur 
97af75078fSIntel struct lcore_params {
98f8244c63SZhiyong Yang 	uint16_t port_id;
99af75078fSIntel 	uint8_t queue_id;
100af75078fSIntel 	uint8_t lcore_id;
101af75078fSIntel } __rte_cache_aligned;
102af75078fSIntel 
103af75078fSIntel static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
104af75078fSIntel static struct lcore_params lcore_params_array_default[] = {
105af75078fSIntel 	{0, 0, 2},
106af75078fSIntel 	{0, 1, 2},
107af75078fSIntel 	{0, 2, 2},
108af75078fSIntel 	{1, 0, 2},
109af75078fSIntel 	{1, 1, 2},
110af75078fSIntel 	{1, 2, 2},
111af75078fSIntel 	{2, 0, 2},
112af75078fSIntel 	{3, 0, 3},
113af75078fSIntel 	{3, 1, 3},
114af75078fSIntel };
115af75078fSIntel 
116af75078fSIntel static struct lcore_params * lcore_params = lcore_params_array_default;
117af75078fSIntel static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
118af75078fSIntel 				sizeof(lcore_params_array_default[0]);
119af75078fSIntel 
120af75078fSIntel static struct rte_eth_conf port_conf = {
121af75078fSIntel 	.rxmode = {
12213c4ebd6SBruce Richardson 		.mq_mode = ETH_MQ_RX_RSS,
12335b2d13fSOlivier Matz 		.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
124af75078fSIntel 		.split_hdr_size = 0,
125323e7b66SFerruh Yigit 		.offloads = DEV_RX_OFFLOAD_CHECKSUM,
126af75078fSIntel 	},
127af75078fSIntel 	.rx_adv_conf = {
128af75078fSIntel 		.rss_conf = {
129af75078fSIntel 			.rss_key = NULL,
1308a387fa8SHelin Zhang 			.rss_hf = ETH_RSS_IP,
131af75078fSIntel 		},
132af75078fSIntel 	},
133af75078fSIntel 	.txmode = {
13432e7aa0bSIntel 		.mq_mode = ETH_MQ_TX_NONE,
135af75078fSIntel 	},
136af75078fSIntel };
137af75078fSIntel 
138f0a26885SShreyansh Jain static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS];
139f0a26885SShreyansh Jain static uint8_t lkp_per_socket[NB_SOCKETS];
140af75078fSIntel 
141268888b5SRavi Kerur struct l3fwd_lkp_mode {
142268888b5SRavi Kerur 	void  (*setup)(int);
14371a7e242SJianfeng Tan 	int   (*check_ptype)(int);
14471a7e242SJianfeng Tan 	rte_rx_callback_fn cb_parse_ptype;
145268888b5SRavi Kerur 	int   (*main_loop)(void *);
146268888b5SRavi Kerur 	void* (*get_ipv4_lookup_struct)(int);
147268888b5SRavi Kerur 	void* (*get_ipv6_lookup_struct)(int);
148997ee890SIntel };
149997ee890SIntel 
150268888b5SRavi Kerur static struct l3fwd_lkp_mode l3fwd_lkp;
151997ee890SIntel 
152268888b5SRavi Kerur static struct l3fwd_lkp_mode l3fwd_em_lkp = {
153268888b5SRavi Kerur 	.setup                  = setup_hash,
15471a7e242SJianfeng Tan 	.check_ptype		= em_check_ptype,
15571a7e242SJianfeng Tan 	.cb_parse_ptype		= em_cb_parse_ptype,
156268888b5SRavi Kerur 	.main_loop              = em_main_loop,
157268888b5SRavi Kerur 	.get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct,
158268888b5SRavi Kerur 	.get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct,
159997ee890SIntel };
160997ee890SIntel 
161268888b5SRavi Kerur static struct l3fwd_lkp_mode l3fwd_lpm_lkp = {
162268888b5SRavi Kerur 	.setup                  = setup_lpm,
16371a7e242SJianfeng Tan 	.check_ptype		= lpm_check_ptype,
16471a7e242SJianfeng Tan 	.cb_parse_ptype		= lpm_cb_parse_ptype,
165268888b5SRavi Kerur 	.main_loop              = lpm_main_loop,
166268888b5SRavi Kerur 	.get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct,
167268888b5SRavi Kerur 	.get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct,
168af75078fSIntel };
169af75078fSIntel 
17096ff4453SKonstantin Ananyev /*
171268888b5SRavi Kerur  * Setup lookup methods for forwarding.
172268888b5SRavi Kerur  * Currently exact-match and longest-prefix-match
173268888b5SRavi Kerur  * are supported ones.
17496ff4453SKonstantin Ananyev  */
175268888b5SRavi Kerur static void
176268888b5SRavi Kerur setup_l3fwd_lookup_tables(void)
177af75078fSIntel {
178268888b5SRavi Kerur 	/* Setup HASH lookup functions. */
179268888b5SRavi Kerur 	if (l3fwd_em_on)
180268888b5SRavi Kerur 		l3fwd_lkp = l3fwd_em_lkp;
181268888b5SRavi Kerur 	/* Setup LPM lookup functions. */
182268888b5SRavi Kerur 	else
183268888b5SRavi Kerur 		l3fwd_lkp = l3fwd_lpm_lkp;
184af75078fSIntel }
185af75078fSIntel 
186af75078fSIntel static int
187af75078fSIntel check_lcore_params(void)
188af75078fSIntel {
189af75078fSIntel 	uint8_t queue, lcore;
190af75078fSIntel 	uint16_t i;
191af75078fSIntel 	int socketid;
192af75078fSIntel 
193af75078fSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
194af75078fSIntel 		queue = lcore_params[i].queue_id;
195af75078fSIntel 		if (queue >= MAX_RX_QUEUE_PER_PORT) {
196af75078fSIntel 			printf("invalid queue number: %hhu\n", queue);
197af75078fSIntel 			return -1;
198af75078fSIntel 		}
199af75078fSIntel 		lcore = lcore_params[i].lcore_id;
200af75078fSIntel 		if (!rte_lcore_is_enabled(lcore)) {
201af75078fSIntel 			printf("error: lcore %hhu is not enabled in lcore mask\n", lcore);
202af75078fSIntel 			return -1;
203af75078fSIntel 		}
204af75078fSIntel 		if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
205af75078fSIntel 			(numa_on == 0)) {
206af75078fSIntel 			printf("warning: lcore %hhu is on socket %d with numa off \n",
207af75078fSIntel 				lcore, socketid);
208af75078fSIntel 		}
209af75078fSIntel 	}
210af75078fSIntel 	return 0;
211af75078fSIntel }
212af75078fSIntel 
213af75078fSIntel static int
214a9dbe180SThomas Monjalon check_port_config(void)
215af75078fSIntel {
216f8244c63SZhiyong Yang 	uint16_t portid;
217af75078fSIntel 	uint16_t i;
218af75078fSIntel 
219af75078fSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
220af75078fSIntel 		portid = lcore_params[i].port_id;
221af75078fSIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
222af75078fSIntel 			printf("port %u is not enabled in port mask\n", portid);
223af75078fSIntel 			return -1;
224af75078fSIntel 		}
225a9dbe180SThomas Monjalon 		if (!rte_eth_dev_is_valid_port(portid)) {
226af75078fSIntel 			printf("port %u is not present on the board\n", portid);
227af75078fSIntel 			return -1;
228af75078fSIntel 		}
229af75078fSIntel 	}
230af75078fSIntel 	return 0;
231af75078fSIntel }
232af75078fSIntel 
233af75078fSIntel static uint8_t
234f8244c63SZhiyong Yang get_port_n_rx_queues(const uint16_t port)
235af75078fSIntel {
236af75078fSIntel 	int queue = -1;
237af75078fSIntel 	uint16_t i;
238af75078fSIntel 
239af75078fSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
240a6b45080SReshma Pattan 		if (lcore_params[i].port_id == port) {
241a6b45080SReshma Pattan 			if (lcore_params[i].queue_id == queue+1)
242af75078fSIntel 				queue = lcore_params[i].queue_id;
243a6b45080SReshma Pattan 			else
244a6b45080SReshma Pattan 				rte_exit(EXIT_FAILURE, "queue ids of the port %d must be"
245a6b45080SReshma Pattan 						" in sequence and must start with 0\n",
246a6b45080SReshma Pattan 						lcore_params[i].port_id);
247a6b45080SReshma Pattan 		}
248af75078fSIntel 	}
249af75078fSIntel 	return (uint8_t)(++queue);
250af75078fSIntel }
251af75078fSIntel 
252af75078fSIntel static int
253af75078fSIntel init_lcore_rx_queues(void)
254af75078fSIntel {
255af75078fSIntel 	uint16_t i, nb_rx_queue;
256af75078fSIntel 	uint8_t lcore;
257af75078fSIntel 
258af75078fSIntel 	for (i = 0; i < nb_lcore_params; ++i) {
259af75078fSIntel 		lcore = lcore_params[i].lcore_id;
260af75078fSIntel 		nb_rx_queue = lcore_conf[lcore].n_rx_queue;
261af75078fSIntel 		if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
262af75078fSIntel 			printf("error: too many queues (%u) for lcore: %u\n",
263af75078fSIntel 				(unsigned)nb_rx_queue + 1, (unsigned)lcore);
264af75078fSIntel 			return -1;
265af75078fSIntel 		} else {
266af75078fSIntel 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
267af75078fSIntel 				lcore_params[i].port_id;
268af75078fSIntel 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
269af75078fSIntel 				lcore_params[i].queue_id;
270af75078fSIntel 			lcore_conf[lcore].n_rx_queue++;
271af75078fSIntel 		}
272af75078fSIntel 	}
273af75078fSIntel 	return 0;
274af75078fSIntel }
275af75078fSIntel 
276af75078fSIntel /* display usage */
277af75078fSIntel static void
278af75078fSIntel print_usage(const char *prgname)
279af75078fSIntel {
280c53a5fafSStephen Hemminger 	fprintf(stderr, "%s [EAL options] --"
28154659744SBeilei Xing 		" -p PORTMASK"
28254659744SBeilei Xing 		" [-P]"
28354659744SBeilei Xing 		" [-E]"
28454659744SBeilei Xing 		" [-L]"
28554659744SBeilei Xing 		" --config (port,queue,lcore)[,(port,queue,lcore)]"
28654659744SBeilei Xing 		" [--eth-dest=X,MM:MM:MM:MM:MM:MM]"
28754659744SBeilei Xing 		" [--enable-jumbo [--max-pkt-len PKTLEN]]"
28854659744SBeilei Xing 		" [--no-numa]"
28954659744SBeilei Xing 		" [--hash-entry-num]"
29054659744SBeilei Xing 		" [--ipv6]"
291f0a26885SShreyansh Jain 		" [--parse-ptype]"
292f0a26885SShreyansh Jain 		" [--per-port-pool]\n\n"
29354659744SBeilei Xing 
29454659744SBeilei Xing 		"  -p PORTMASK: Hexadecimal bitmask of ports to configure\n"
29554659744SBeilei Xing 		"  -P : Enable promiscuous mode\n"
29654659744SBeilei Xing 		"  -E : Enable exact match\n"
29754659744SBeilei Xing 		"  -L : Enable longest prefix match (default)\n"
29854659744SBeilei Xing 		"  --config (port,queue,lcore): Rx queue configuration\n"
29954659744SBeilei Xing 		"  --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n"
30054659744SBeilei Xing 		"  --enable-jumbo: Enable jumbo frames\n"
30154659744SBeilei Xing 		"  --max-pkt-len: Under the premise of enabling jumbo,\n"
30254659744SBeilei Xing 		"                 maximum packet length in decimal (64-9600)\n"
30354659744SBeilei Xing 		"  --no-numa: Disable numa awareness\n"
30454659744SBeilei Xing 		"  --hash-entry-num: Specify the hash entry number in hexadecimal to be setup\n"
30554659744SBeilei Xing 		"  --ipv6: Set if running ipv6 packets\n"
306f0a26885SShreyansh Jain 		"  --parse-ptype: Set to use software to analyze packet type\n"
307f0a26885SShreyansh Jain 		"  --per-port-pool: Use separate buffer pool per port\n\n",
308af75078fSIntel 		prgname);
309af75078fSIntel }
310af75078fSIntel 
311268888b5SRavi Kerur static int
312268888b5SRavi Kerur parse_max_pkt_len(const char *pktlen)
313f68aad79SIntel {
314f68aad79SIntel 	char *end = NULL;
315f68aad79SIntel 	unsigned long len;
316f68aad79SIntel 
317f68aad79SIntel 	/* parse decimal string */
318f68aad79SIntel 	len = strtoul(pktlen, &end, 10);
319f68aad79SIntel 	if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
320f68aad79SIntel 		return -1;
321f68aad79SIntel 
322f68aad79SIntel 	if (len == 0)
323f68aad79SIntel 		return -1;
324f68aad79SIntel 
325f68aad79SIntel 	return len;
326f68aad79SIntel }
327f68aad79SIntel 
328af75078fSIntel static int
329af75078fSIntel parse_portmask(const char *portmask)
330af75078fSIntel {
331af75078fSIntel 	char *end = NULL;
332af75078fSIntel 	unsigned long pm;
333af75078fSIntel 
334af75078fSIntel 	/* parse hexadecimal string */
335af75078fSIntel 	pm = strtoul(portmask, &end, 16);
336af75078fSIntel 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
337af75078fSIntel 		return -1;
338af75078fSIntel 
339af75078fSIntel 	if (pm == 0)
340af75078fSIntel 		return -1;
341af75078fSIntel 
342af75078fSIntel 	return pm;
343af75078fSIntel }
344af75078fSIntel 
345997ee890SIntel static int
346997ee890SIntel parse_hash_entry_number(const char *hash_entry_num)
347997ee890SIntel {
348997ee890SIntel 	char *end = NULL;
349997ee890SIntel 	unsigned long hash_en;
350997ee890SIntel 	/* parse hexadecimal string */
351997ee890SIntel 	hash_en = strtoul(hash_entry_num, &end, 16);
352997ee890SIntel 	if ((hash_entry_num[0] == '\0') || (end == NULL) || (*end != '\0'))
353997ee890SIntel 		return -1;
354997ee890SIntel 
355997ee890SIntel 	if (hash_en == 0)
356997ee890SIntel 		return -1;
357997ee890SIntel 
358997ee890SIntel 	return hash_en;
359997ee890SIntel }
360997ee890SIntel 
361af75078fSIntel static int
362af75078fSIntel parse_config(const char *q_arg)
363af75078fSIntel {
364af75078fSIntel 	char s[256];
365af75078fSIntel 	const char *p, *p0 = q_arg;
366af75078fSIntel 	char *end;
367af75078fSIntel 	enum fieldnames {
368af75078fSIntel 		FLD_PORT = 0,
369af75078fSIntel 		FLD_QUEUE,
370af75078fSIntel 		FLD_LCORE,
371af75078fSIntel 		_NUM_FLD
372af75078fSIntel 	};
373af75078fSIntel 	unsigned long int_fld[_NUM_FLD];
374af75078fSIntel 	char *str_fld[_NUM_FLD];
375af75078fSIntel 	int i;
376af75078fSIntel 	unsigned size;
377af75078fSIntel 
378af75078fSIntel 	nb_lcore_params = 0;
379af75078fSIntel 
380af75078fSIntel 	while ((p = strchr(p0,'(')) != NULL) {
381af75078fSIntel 		++p;
382af75078fSIntel 		if((p0 = strchr(p,')')) == NULL)
383af75078fSIntel 			return -1;
384af75078fSIntel 
385af75078fSIntel 		size = p0 - p;
386af75078fSIntel 		if(size >= sizeof(s))
387af75078fSIntel 			return -1;
388af75078fSIntel 
3896f41fe75SStephen Hemminger 		snprintf(s, sizeof(s), "%.*s", size, p);
390af75078fSIntel 		if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
391af75078fSIntel 			return -1;
392af75078fSIntel 		for (i = 0; i < _NUM_FLD; i++){
393af75078fSIntel 			errno = 0;
394af75078fSIntel 			int_fld[i] = strtoul(str_fld[i], &end, 0);
395af75078fSIntel 			if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
396af75078fSIntel 				return -1;
397af75078fSIntel 		}
398af75078fSIntel 		if (nb_lcore_params >= MAX_LCORE_PARAMS) {
399af75078fSIntel 			printf("exceeded max number of lcore params: %hu\n",
400af75078fSIntel 				nb_lcore_params);
401af75078fSIntel 			return -1;
402af75078fSIntel 		}
403268888b5SRavi Kerur 		lcore_params_array[nb_lcore_params].port_id =
404268888b5SRavi Kerur 			(uint8_t)int_fld[FLD_PORT];
405268888b5SRavi Kerur 		lcore_params_array[nb_lcore_params].queue_id =
406268888b5SRavi Kerur 			(uint8_t)int_fld[FLD_QUEUE];
407268888b5SRavi Kerur 		lcore_params_array[nb_lcore_params].lcore_id =
408268888b5SRavi Kerur 			(uint8_t)int_fld[FLD_LCORE];
409af75078fSIntel 		++nb_lcore_params;
410af75078fSIntel 	}
411af75078fSIntel 	lcore_params = lcore_params_array;
412af75078fSIntel 	return 0;
413af75078fSIntel }
414af75078fSIntel 
415bd785f6fSAndrey Chilikin static void
416bd785f6fSAndrey Chilikin parse_eth_dest(const char *optarg)
417bd785f6fSAndrey Chilikin {
418f8244c63SZhiyong Yang 	uint16_t portid;
419bd785f6fSAndrey Chilikin 	char *port_end;
420bd785f6fSAndrey Chilikin 	uint8_t c, *dest, peer_addr[6];
421bd785f6fSAndrey Chilikin 
422bd785f6fSAndrey Chilikin 	errno = 0;
423bd785f6fSAndrey Chilikin 	portid = strtoul(optarg, &port_end, 10);
424bd785f6fSAndrey Chilikin 	if (errno != 0 || port_end == optarg || *port_end++ != ',')
425bd785f6fSAndrey Chilikin 		rte_exit(EXIT_FAILURE,
426bd785f6fSAndrey Chilikin 		"Invalid eth-dest: %s", optarg);
427bd785f6fSAndrey Chilikin 	if (portid >= RTE_MAX_ETHPORTS)
428bd785f6fSAndrey Chilikin 		rte_exit(EXIT_FAILURE,
429bd785f6fSAndrey Chilikin 		"eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n",
430bd785f6fSAndrey Chilikin 		portid, RTE_MAX_ETHPORTS);
431bd785f6fSAndrey Chilikin 
432bd785f6fSAndrey Chilikin 	if (cmdline_parse_etheraddr(NULL, port_end,
433bd785f6fSAndrey Chilikin 		&peer_addr, sizeof(peer_addr)) < 0)
434bd785f6fSAndrey Chilikin 		rte_exit(EXIT_FAILURE,
435bd785f6fSAndrey Chilikin 		"Invalid ethernet address: %s\n",
436bd785f6fSAndrey Chilikin 		port_end);
437bd785f6fSAndrey Chilikin 	dest = (uint8_t *)&dest_eth_addr[portid];
438bd785f6fSAndrey Chilikin 	for (c = 0; c < 6; c++)
439bd785f6fSAndrey Chilikin 		dest[c] = peer_addr[c];
440bd785f6fSAndrey Chilikin 	*(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
441bd785f6fSAndrey Chilikin }
442bd785f6fSAndrey Chilikin 
443268888b5SRavi Kerur #define MAX_JUMBO_PKT_LEN  9600
444268888b5SRavi Kerur #define MEMPOOL_CACHE_SIZE 256
445268888b5SRavi Kerur 
44688617471SOlivier Matz static const char short_options[] =
44788617471SOlivier Matz 	"p:"  /* portmask */
44888617471SOlivier Matz 	"P"   /* promiscuous */
44988617471SOlivier Matz 	"L"   /* enable long prefix match */
45088617471SOlivier Matz 	"E"   /* enable exact match */
45188617471SOlivier Matz 	;
45288617471SOlivier Matz 
453997ee890SIntel #define CMD_LINE_OPT_CONFIG "config"
454bd785f6fSAndrey Chilikin #define CMD_LINE_OPT_ETH_DEST "eth-dest"
455997ee890SIntel #define CMD_LINE_OPT_NO_NUMA "no-numa"
456997ee890SIntel #define CMD_LINE_OPT_IPV6 "ipv6"
457997ee890SIntel #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
458997ee890SIntel #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
45971a7e242SJianfeng Tan #define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
460f0a26885SShreyansh Jain #define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool"
46188617471SOlivier Matz enum {
46288617471SOlivier Matz 	/* long options mapped to a short option */
46388617471SOlivier Matz 
46488617471SOlivier Matz 	/* first long only option value must be >= 256, so that we won't
46588617471SOlivier Matz 	 * conflict with short options */
46688617471SOlivier Matz 	CMD_LINE_OPT_MIN_NUM = 256,
46788617471SOlivier Matz 	CMD_LINE_OPT_CONFIG_NUM,
46888617471SOlivier Matz 	CMD_LINE_OPT_ETH_DEST_NUM,
46988617471SOlivier Matz 	CMD_LINE_OPT_NO_NUMA_NUM,
47088617471SOlivier Matz 	CMD_LINE_OPT_IPV6_NUM,
47188617471SOlivier Matz 	CMD_LINE_OPT_ENABLE_JUMBO_NUM,
47288617471SOlivier Matz 	CMD_LINE_OPT_HASH_ENTRY_NUM_NUM,
47388617471SOlivier Matz 	CMD_LINE_OPT_PARSE_PTYPE_NUM,
474f0a26885SShreyansh Jain 	CMD_LINE_OPT_PARSE_PER_PORT_POOL,
47588617471SOlivier Matz };
47688617471SOlivier Matz 
47788617471SOlivier Matz static const struct option lgopts[] = {
47888617471SOlivier Matz 	{CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM},
47988617471SOlivier Matz 	{CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM},
48088617471SOlivier Matz 	{CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM},
48188617471SOlivier Matz 	{CMD_LINE_OPT_IPV6, 0, 0, CMD_LINE_OPT_IPV6_NUM},
48288617471SOlivier Matz 	{CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, CMD_LINE_OPT_ENABLE_JUMBO_NUM},
48388617471SOlivier Matz 	{CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, CMD_LINE_OPT_HASH_ENTRY_NUM_NUM},
48488617471SOlivier Matz 	{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, CMD_LINE_OPT_PARSE_PTYPE_NUM},
485f0a26885SShreyansh Jain 	{CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL},
48688617471SOlivier Matz 	{NULL, 0, 0, 0}
48788617471SOlivier Matz };
488997ee890SIntel 
489268888b5SRavi Kerur /*
490268888b5SRavi Kerur  * This expression is used to calculate the number of mbufs needed
491268888b5SRavi Kerur  * depending on user input, taking  into account memory for rx and
492268888b5SRavi Kerur  * tx hardware rings, cache per lcore and mtable per port per lcore.
493268888b5SRavi Kerur  * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum
494268888b5SRavi Kerur  * value of 8192
495268888b5SRavi Kerur  */
496f0a26885SShreyansh Jain #define NB_MBUF(nports) RTE_MAX(	\
497f0a26885SShreyansh Jain 	(nports*nb_rx_queue*nb_rxd +		\
498f0a26885SShreyansh Jain 	nports*nb_lcores*MAX_PKT_BURST +	\
499f0a26885SShreyansh Jain 	nports*n_tx_queue*nb_txd +		\
500268888b5SRavi Kerur 	nb_lcores*MEMPOOL_CACHE_SIZE),		\
501268888b5SRavi Kerur 	(unsigned)8192)
502268888b5SRavi Kerur 
503af75078fSIntel /* Parse the argument given in the command line of the application */
504af75078fSIntel static int
505af75078fSIntel parse_args(int argc, char **argv)
506af75078fSIntel {
507af75078fSIntel 	int opt, ret;
508af75078fSIntel 	char **argvopt;
509af75078fSIntel 	int option_index;
510af75078fSIntel 	char *prgname = argv[0];
511af75078fSIntel 
512af75078fSIntel 	argvopt = argv;
513af75078fSIntel 
514268888b5SRavi Kerur 	/* Error or normal output strings. */
51588617471SOlivier Matz 	while ((opt = getopt_long(argc, argvopt, short_options,
516af75078fSIntel 				lgopts, &option_index)) != EOF) {
517af75078fSIntel 
518af75078fSIntel 		switch (opt) {
519af75078fSIntel 		/* portmask */
520af75078fSIntel 		case 'p':
521af75078fSIntel 			enabled_port_mask = parse_portmask(optarg);
522af75078fSIntel 			if (enabled_port_mask == 0) {
523c53a5fafSStephen Hemminger 				fprintf(stderr, "Invalid portmask\n");
524af75078fSIntel 				print_usage(prgname);
525af75078fSIntel 				return -1;
526af75078fSIntel 			}
527af75078fSIntel 			break;
52888617471SOlivier Matz 
529af75078fSIntel 		case 'P':
530af75078fSIntel 			promiscuous_on = 1;
531af75078fSIntel 			break;
532af75078fSIntel 
533268888b5SRavi Kerur 		case 'E':
534268888b5SRavi Kerur 			l3fwd_em_on = 1;
535268888b5SRavi Kerur 			break;
536268888b5SRavi Kerur 
537268888b5SRavi Kerur 		case 'L':
538268888b5SRavi Kerur 			l3fwd_lpm_on = 1;
539268888b5SRavi Kerur 			break;
540268888b5SRavi Kerur 
541af75078fSIntel 		/* long options */
54288617471SOlivier Matz 		case CMD_LINE_OPT_CONFIG_NUM:
543af75078fSIntel 			ret = parse_config(optarg);
544af75078fSIntel 			if (ret) {
545c53a5fafSStephen Hemminger 				fprintf(stderr, "Invalid config\n");
546af75078fSIntel 				print_usage(prgname);
547af75078fSIntel 				return -1;
548af75078fSIntel 			}
54988617471SOlivier Matz 			break;
550af75078fSIntel 
55188617471SOlivier Matz 		case CMD_LINE_OPT_ETH_DEST_NUM:
552bd785f6fSAndrey Chilikin 			parse_eth_dest(optarg);
55388617471SOlivier Matz 			break;
554bd785f6fSAndrey Chilikin 
55588617471SOlivier Matz 		case CMD_LINE_OPT_NO_NUMA_NUM:
556af75078fSIntel 			numa_on = 0;
55788617471SOlivier Matz 			break;
558f68aad79SIntel 
55988617471SOlivier Matz 		case CMD_LINE_OPT_IPV6_NUM:
560997ee890SIntel 			ipv6 = 1;
56188617471SOlivier Matz 			break;
562997ee890SIntel 
56388617471SOlivier Matz 		case CMD_LINE_OPT_ENABLE_JUMBO_NUM: {
564c53a5fafSStephen Hemminger 			const struct option lenopts = {
565268888b5SRavi Kerur 				"max-pkt-len", required_argument, 0, 0
566268888b5SRavi Kerur 			};
567f68aad79SIntel 
5681ef9600bSShahaf Shuler 			port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME;
5691ef9600bSShahaf Shuler 			port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS;
570f68aad79SIntel 
571268888b5SRavi Kerur 			/*
572268888b5SRavi Kerur 			 * if no max-pkt-len set, use the default
57335b2d13fSOlivier Matz 			 * value RTE_ETHER_MAX_LEN.
574268888b5SRavi Kerur 			 */
57588617471SOlivier Matz 			if (getopt_long(argc, argvopt, "",
57688617471SOlivier Matz 					&lenopts, &option_index) == 0) {
577f68aad79SIntel 				ret = parse_max_pkt_len(optarg);
578c53a5fafSStephen Hemminger 				if (ret < 64 || ret > MAX_JUMBO_PKT_LEN) {
579c53a5fafSStephen Hemminger 					fprintf(stderr,
580c53a5fafSStephen Hemminger 						"invalid maximum packet length\n");
581f68aad79SIntel 					print_usage(prgname);
582f68aad79SIntel 					return -1;
583f68aad79SIntel 				}
584f68aad79SIntel 				port_conf.rxmode.max_rx_pkt_len = ret;
585f68aad79SIntel 			}
58688617471SOlivier Matz 			break;
587f68aad79SIntel 		}
588268888b5SRavi Kerur 
58988617471SOlivier Matz 		case CMD_LINE_OPT_HASH_ENTRY_NUM_NUM:
590997ee890SIntel 			ret = parse_hash_entry_number(optarg);
591997ee890SIntel 			if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) {
592997ee890SIntel 				hash_entry_number = ret;
593997ee890SIntel 			} else {
594c53a5fafSStephen Hemminger 				fprintf(stderr, "invalid hash entry number\n");
595997ee890SIntel 				print_usage(prgname);
596997ee890SIntel 				return -1;
597997ee890SIntel 			}
59888617471SOlivier Matz 			break;
59971a7e242SJianfeng Tan 
60088617471SOlivier Matz 		case CMD_LINE_OPT_PARSE_PTYPE_NUM:
60171a7e242SJianfeng Tan 			printf("soft parse-ptype is enabled\n");
60271a7e242SJianfeng Tan 			parse_ptype = 1;
603af75078fSIntel 			break;
604af75078fSIntel 
605f0a26885SShreyansh Jain 		case CMD_LINE_OPT_PARSE_PER_PORT_POOL:
606f0a26885SShreyansh Jain 			printf("per port buffer pool is enabled\n");
607f0a26885SShreyansh Jain 			per_port_pool = 1;
608f0a26885SShreyansh Jain 			break;
609f0a26885SShreyansh Jain 
610af75078fSIntel 		default:
611af75078fSIntel 			print_usage(prgname);
612af75078fSIntel 			return -1;
613af75078fSIntel 		}
614af75078fSIntel 	}
615af75078fSIntel 
616268888b5SRavi Kerur 	/* If both LPM and EM are selected, return error. */
617268888b5SRavi Kerur 	if (l3fwd_lpm_on && l3fwd_em_on) {
618c53a5fafSStephen Hemminger 		fprintf(stderr, "LPM and EM are mutually exclusive, select only one\n");
619268888b5SRavi Kerur 		return -1;
620268888b5SRavi Kerur 	}
621268888b5SRavi Kerur 
622268888b5SRavi Kerur 	/*
623268888b5SRavi Kerur 	 * Nothing is selected, pick longest-prefix match
624268888b5SRavi Kerur 	 * as default match.
625268888b5SRavi Kerur 	 */
626268888b5SRavi Kerur 	if (!l3fwd_lpm_on && !l3fwd_em_on) {
627c53a5fafSStephen Hemminger 		fprintf(stderr, "LPM or EM none selected, default LPM on\n");
628268888b5SRavi Kerur 		l3fwd_lpm_on = 1;
629268888b5SRavi Kerur 	}
630268888b5SRavi Kerur 
631268888b5SRavi Kerur 	/*
632268888b5SRavi Kerur 	 * ipv6 and hash flags are valid only for
633268888b5SRavi Kerur 	 * exact macth, reset them to default for
634268888b5SRavi Kerur 	 * longest-prefix match.
635268888b5SRavi Kerur 	 */
636268888b5SRavi Kerur 	if (l3fwd_lpm_on) {
637268888b5SRavi Kerur 		ipv6 = 0;
638268888b5SRavi Kerur 		hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
639268888b5SRavi Kerur 	}
640268888b5SRavi Kerur 
641af75078fSIntel 	if (optind >= 0)
642af75078fSIntel 		argv[optind-1] = prgname;
643af75078fSIntel 
644af75078fSIntel 	ret = optind-1;
6459d5ca532SKeith Wiles 	optind = 1; /* reset getopt lib */
646af75078fSIntel 	return ret;
647af75078fSIntel }
648af75078fSIntel 
649af75078fSIntel static void
6506d13ea8eSOlivier Matz print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
651af75078fSIntel {
65235b2d13fSOlivier Matz 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
65335b2d13fSOlivier Matz 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
654ec3d82dbSCunming Liang 	printf("%s%s", name, buf);
655af75078fSIntel }
656af75078fSIntel 
657af75078fSIntel static int
658f0a26885SShreyansh Jain init_mem(uint16_t portid, unsigned int nb_mbuf)
659af75078fSIntel {
660af75078fSIntel 	struct lcore_conf *qconf;
661af75078fSIntel 	int socketid;
662af75078fSIntel 	unsigned lcore_id;
663af75078fSIntel 	char s[64];
664af75078fSIntel 
665af75078fSIntel 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
666af75078fSIntel 		if (rte_lcore_is_enabled(lcore_id) == 0)
667af75078fSIntel 			continue;
668af75078fSIntel 
669af75078fSIntel 		if (numa_on)
670af75078fSIntel 			socketid = rte_lcore_to_socket_id(lcore_id);
671af75078fSIntel 		else
672af75078fSIntel 			socketid = 0;
673af75078fSIntel 
674af75078fSIntel 		if (socketid >= NB_SOCKETS) {
675268888b5SRavi Kerur 			rte_exit(EXIT_FAILURE,
676268888b5SRavi Kerur 				"Socket %d of lcore %u is out of range %d\n",
677af75078fSIntel 				socketid, lcore_id, NB_SOCKETS);
678af75078fSIntel 		}
679268888b5SRavi Kerur 
680f0a26885SShreyansh Jain 		if (pktmbuf_pool[portid][socketid] == NULL) {
681f0a26885SShreyansh Jain 			snprintf(s, sizeof(s), "mbuf_pool_%d:%d",
682f0a26885SShreyansh Jain 				 portid, socketid);
683f0a26885SShreyansh Jain 			pktmbuf_pool[portid][socketid] =
684ea0c20eaSOlivier Matz 				rte_pktmbuf_pool_create(s, nb_mbuf,
685824cb29cSKonstantin Ananyev 					MEMPOOL_CACHE_SIZE, 0,
686824cb29cSKonstantin Ananyev 					RTE_MBUF_DEFAULT_BUF_SIZE, socketid);
687f0a26885SShreyansh Jain 			if (pktmbuf_pool[portid][socketid] == NULL)
688af75078fSIntel 				rte_exit(EXIT_FAILURE,
689268888b5SRavi Kerur 					"Cannot init mbuf pool on socket %d\n",
690268888b5SRavi Kerur 					socketid);
691af75078fSIntel 			else
692268888b5SRavi Kerur 				printf("Allocated mbuf pool on socket %d\n",
693268888b5SRavi Kerur 					socketid);
694af75078fSIntel 
695f0a26885SShreyansh Jain 			/* Setup either LPM or EM(f.e Hash). But, only once per
696f0a26885SShreyansh Jain 			 * available socket.
697f0a26885SShreyansh Jain 			 */
698f0a26885SShreyansh Jain 			if (!lkp_per_socket[socketid]) {
699268888b5SRavi Kerur 				l3fwd_lkp.setup(socketid);
700f0a26885SShreyansh Jain 				lkp_per_socket[socketid] = 1;
701f0a26885SShreyansh Jain 			}
702af75078fSIntel 		}
703af75078fSIntel 		qconf = &lcore_conf[lcore_id];
704268888b5SRavi Kerur 		qconf->ipv4_lookup_struct =
705268888b5SRavi Kerur 			l3fwd_lkp.get_ipv4_lookup_struct(socketid);
706268888b5SRavi Kerur 		qconf->ipv6_lookup_struct =
707268888b5SRavi Kerur 			l3fwd_lkp.get_ipv6_lookup_struct(socketid);
708af75078fSIntel 	}
709af75078fSIntel 	return 0;
710af75078fSIntel }
711af75078fSIntel 
712d3641ae8SIntel /* Check the link status of all ports in up to 9s, and print them finally */
713d3641ae8SIntel static void
7148728ccf3SThomas Monjalon check_all_ports_link_status(uint32_t port_mask)
715d3641ae8SIntel {
716d3641ae8SIntel #define CHECK_INTERVAL 100 /* 100ms */
717d3641ae8SIntel #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
718f8244c63SZhiyong Yang 	uint16_t portid;
719f8244c63SZhiyong Yang 	uint8_t count, all_ports_up, print_flag = 0;
720d3641ae8SIntel 	struct rte_eth_link link;
721d3641ae8SIntel 
722d3641ae8SIntel 	printf("\nChecking link status");
723d3641ae8SIntel 	fflush(stdout);
724d3641ae8SIntel 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
725308df2bfSZhihong Wang 		if (force_quit)
726308df2bfSZhihong Wang 			return;
727d3641ae8SIntel 		all_ports_up = 1;
7288728ccf3SThomas Monjalon 		RTE_ETH_FOREACH_DEV(portid) {
729308df2bfSZhihong Wang 			if (force_quit)
730308df2bfSZhihong Wang 				return;
731d3641ae8SIntel 			if ((port_mask & (1 << portid)) == 0)
732d3641ae8SIntel 				continue;
733d3641ae8SIntel 			memset(&link, 0, sizeof(link));
734d3641ae8SIntel 			rte_eth_link_get_nowait(portid, &link);
735d3641ae8SIntel 			/* print link status if flag set */
736d3641ae8SIntel 			if (print_flag == 1) {
737d3641ae8SIntel 				if (link.link_status)
738f8244c63SZhiyong Yang 					printf(
739f8244c63SZhiyong Yang 					"Port%d Link Up. Speed %u Mbps -%s\n",
740f8244c63SZhiyong Yang 						portid, link.link_speed,
741d3641ae8SIntel 				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
742d3641ae8SIntel 					("full-duplex") : ("half-duplex\n"));
743d3641ae8SIntel 				else
744f8244c63SZhiyong Yang 					printf("Port %d Link Down\n", portid);
745d3641ae8SIntel 				continue;
746d3641ae8SIntel 			}
747d3641ae8SIntel 			/* clear all_ports_up flag if any link down */
74809419f23SThomas Monjalon 			if (link.link_status == ETH_LINK_DOWN) {
749d3641ae8SIntel 				all_ports_up = 0;
750d3641ae8SIntel 				break;
751d3641ae8SIntel 			}
752d3641ae8SIntel 		}
753d3641ae8SIntel 		/* after finally printing all link status, get out */
754d3641ae8SIntel 		if (print_flag == 1)
755d3641ae8SIntel 			break;
756d3641ae8SIntel 
757d3641ae8SIntel 		if (all_ports_up == 0) {
758d3641ae8SIntel 			printf(".");
759d3641ae8SIntel 			fflush(stdout);
760d3641ae8SIntel 			rte_delay_ms(CHECK_INTERVAL);
761d3641ae8SIntel 		}
762d3641ae8SIntel 
763d3641ae8SIntel 		/* set the print_flag if all ports up or timeout */
764d3641ae8SIntel 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
765d3641ae8SIntel 			print_flag = 1;
766d3641ae8SIntel 			printf("done\n");
767d3641ae8SIntel 		}
768d3641ae8SIntel 	}
769d3641ae8SIntel }
770d3641ae8SIntel 
771308df2bfSZhihong Wang static void
772308df2bfSZhihong Wang signal_handler(int signum)
773308df2bfSZhihong Wang {
774308df2bfSZhihong Wang 	if (signum == SIGINT || signum == SIGTERM) {
775308df2bfSZhihong Wang 		printf("\n\nSignal %d received, preparing to exit...\n",
776308df2bfSZhihong Wang 				signum);
777308df2bfSZhihong Wang 		force_quit = true;
778308df2bfSZhihong Wang 	}
779308df2bfSZhihong Wang }
780308df2bfSZhihong Wang 
78171a7e242SJianfeng Tan static int
782f8244c63SZhiyong Yang prepare_ptype_parser(uint16_t portid, uint16_t queueid)
78371a7e242SJianfeng Tan {
78471a7e242SJianfeng Tan 	if (parse_ptype) {
78571a7e242SJianfeng Tan 		printf("Port %d: softly parse packet type info\n", portid);
78671a7e242SJianfeng Tan 		if (rte_eth_add_rx_callback(portid, queueid,
78771a7e242SJianfeng Tan 					    l3fwd_lkp.cb_parse_ptype,
78871a7e242SJianfeng Tan 					    NULL))
78971a7e242SJianfeng Tan 			return 1;
79071a7e242SJianfeng Tan 
79171a7e242SJianfeng Tan 		printf("Failed to add rx callback: port=%d\n", portid);
79271a7e242SJianfeng Tan 		return 0;
79371a7e242SJianfeng Tan 	}
79471a7e242SJianfeng Tan 
79571a7e242SJianfeng Tan 	if (l3fwd_lkp.check_ptype(portid))
79671a7e242SJianfeng Tan 		return 1;
79771a7e242SJianfeng Tan 
79871a7e242SJianfeng Tan 	printf("port %d cannot parse packet type, please add --%s\n",
79971a7e242SJianfeng Tan 	       portid, CMD_LINE_OPT_PARSE_PTYPE);
80071a7e242SJianfeng Tan 	return 0;
80171a7e242SJianfeng Tan }
80271a7e242SJianfeng Tan 
803af75078fSIntel int
80498a16481SDavid Marchand main(int argc, char **argv)
805af75078fSIntel {
806af75078fSIntel 	struct lcore_conf *qconf;
80781f7ecd9SPablo de Lara 	struct rte_eth_dev_info dev_info;
80881f7ecd9SPablo de Lara 	struct rte_eth_txconf *txconf;
809af75078fSIntel 	int ret;
810af75078fSIntel 	unsigned nb_ports;
811f8244c63SZhiyong Yang 	uint16_t queueid, portid;
812af75078fSIntel 	unsigned lcore_id;
813af75078fSIntel 	uint32_t n_tx_queue, nb_lcores;
814f8244c63SZhiyong Yang 	uint8_t nb_rx_queue, queue, socketid;
815af75078fSIntel 
816af75078fSIntel 	/* init EAL */
817af75078fSIntel 	ret = rte_eal_init(argc, argv);
818af75078fSIntel 	if (ret < 0)
819af75078fSIntel 		rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
820af75078fSIntel 	argc -= ret;
821af75078fSIntel 	argv += ret;
822af75078fSIntel 
823308df2bfSZhihong Wang 	force_quit = false;
824308df2bfSZhihong Wang 	signal(SIGINT, signal_handler);
825308df2bfSZhihong Wang 	signal(SIGTERM, signal_handler);
826308df2bfSZhihong Wang 
827bd785f6fSAndrey Chilikin 	/* pre-init dst MACs for all ports to 02:00:00:00:00:xx */
828bd785f6fSAndrey Chilikin 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
829268888b5SRavi Kerur 		dest_eth_addr[portid] =
83035b2d13fSOlivier Matz 			RTE_ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40);
831bd785f6fSAndrey Chilikin 		*(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
832bd785f6fSAndrey Chilikin 	}
833bd785f6fSAndrey Chilikin 
834af75078fSIntel 	/* parse application arguments (after the EAL ones) */
835af75078fSIntel 	ret = parse_args(argc, argv);
836af75078fSIntel 	if (ret < 0)
837af75078fSIntel 		rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
838af75078fSIntel 
839af75078fSIntel 	if (check_lcore_params() < 0)
840af75078fSIntel 		rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
841af75078fSIntel 
842af75078fSIntel 	ret = init_lcore_rx_queues();
843af75078fSIntel 	if (ret < 0)
844af75078fSIntel 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
845af75078fSIntel 
846d9a42a69SThomas Monjalon 	nb_ports = rte_eth_dev_count_avail();
847af75078fSIntel 
848a9dbe180SThomas Monjalon 	if (check_port_config() < 0)
849af75078fSIntel 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
850af75078fSIntel 
851af75078fSIntel 	nb_lcores = rte_lcore_count();
852af75078fSIntel 
853268888b5SRavi Kerur 	/* Setup function pointers for lookup method. */
854268888b5SRavi Kerur 	setup_l3fwd_lookup_tables();
855268888b5SRavi Kerur 
856af75078fSIntel 	/* initialize all ports */
8578728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
8581ef9600bSShahaf Shuler 		struct rte_eth_conf local_port_conf = port_conf;
8591ef9600bSShahaf Shuler 
860af75078fSIntel 		/* skip ports that are not enabled */
861af75078fSIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
862af75078fSIntel 			printf("\nSkipping disabled port %d\n", portid);
863af75078fSIntel 			continue;
864af75078fSIntel 		}
865af75078fSIntel 
866af75078fSIntel 		/* init port */
867af75078fSIntel 		printf("Initializing port %d ... ", portid );
868af75078fSIntel 		fflush(stdout);
869af75078fSIntel 
870af75078fSIntel 		nb_rx_queue = get_port_n_rx_queues(portid);
871af75078fSIntel 		n_tx_queue = nb_lcores;
872af75078fSIntel 		if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
873af75078fSIntel 			n_tx_queue = MAX_TX_QUEUE_PER_PORT;
874af75078fSIntel 		printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
875af75078fSIntel 			nb_rx_queue, (unsigned)n_tx_queue );
8761ef9600bSShahaf Shuler 
877*089e5ed7SIvan Ilchenko 		ret = rte_eth_dev_info_get(portid, &dev_info);
878*089e5ed7SIvan Ilchenko 		if (ret != 0)
879*089e5ed7SIvan Ilchenko 			rte_exit(EXIT_FAILURE,
880*089e5ed7SIvan Ilchenko 				"Error during getting device (port %u) info: %s\n",
881*089e5ed7SIvan Ilchenko 				portid, strerror(-ret));
882*089e5ed7SIvan Ilchenko 
8831ef9600bSShahaf Shuler 		if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
8841ef9600bSShahaf Shuler 			local_port_conf.txmode.offloads |=
8851ef9600bSShahaf Shuler 				DEV_TX_OFFLOAD_MBUF_FAST_FREE;
8864f5701f2SFerruh Yigit 
8874f5701f2SFerruh Yigit 		local_port_conf.rx_adv_conf.rss_conf.rss_hf &=
8884f5701f2SFerruh Yigit 			dev_info.flow_type_rss_offloads;
8894f5701f2SFerruh Yigit 		if (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=
8904f5701f2SFerruh Yigit 				port_conf.rx_adv_conf.rss_conf.rss_hf) {
8914f5701f2SFerruh Yigit 			printf("Port %u modified RSS hash function based on hardware support,"
8924f5701f2SFerruh Yigit 				"requested:%#"PRIx64" configured:%#"PRIx64"\n",
8934f5701f2SFerruh Yigit 				portid,
8944f5701f2SFerruh Yigit 				port_conf.rx_adv_conf.rss_conf.rss_hf,
8954f5701f2SFerruh Yigit 				local_port_conf.rx_adv_conf.rss_conf.rss_hf);
8964f5701f2SFerruh Yigit 		}
8974f5701f2SFerruh Yigit 
898af75078fSIntel 		ret = rte_eth_dev_configure(portid, nb_rx_queue,
8991ef9600bSShahaf Shuler 					(uint16_t)n_tx_queue, &local_port_conf);
900af75078fSIntel 		if (ret < 0)
901268888b5SRavi Kerur 			rte_exit(EXIT_FAILURE,
902268888b5SRavi Kerur 				"Cannot configure device: err=%d, port=%d\n",
903af75078fSIntel 				ret, portid);
904af75078fSIntel 
90560efb44fSRoman Zhukov 		ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
90660efb44fSRoman Zhukov 						       &nb_txd);
90760efb44fSRoman Zhukov 		if (ret < 0)
90860efb44fSRoman Zhukov 			rte_exit(EXIT_FAILURE,
90960efb44fSRoman Zhukov 				 "Cannot adjust number of descriptors: err=%d, "
91060efb44fSRoman Zhukov 				 "port=%d\n", ret, portid);
91160efb44fSRoman Zhukov 
912af75078fSIntel 		rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
913af75078fSIntel 		print_ethaddr(" Address:", &ports_eth_addr[portid]);
914af75078fSIntel 		printf(", ");
915bd785f6fSAndrey Chilikin 		print_ethaddr("Destination:",
9166d13ea8eSOlivier Matz 			(const struct rte_ether_addr *)&dest_eth_addr[portid]);
917bd785f6fSAndrey Chilikin 		printf(", ");
918af75078fSIntel 
91996ff4453SKonstantin Ananyev 		/*
920bd785f6fSAndrey Chilikin 		 * prepare src MACs for each port.
92196ff4453SKonstantin Ananyev 		 */
922538da7a1SOlivier Matz 		rte_ether_addr_copy(&ports_eth_addr[portid],
9236d13ea8eSOlivier Matz 			(struct rte_ether_addr *)(val_eth + portid) + 1);
92496ff4453SKonstantin Ananyev 
925f68aad79SIntel 		/* init memory */
926f0a26885SShreyansh Jain 		if (!per_port_pool) {
927f0a26885SShreyansh Jain 			/* portid = 0; this is *not* signifying the first port,
928f0a26885SShreyansh Jain 			 * rather, it signifies that portid is ignored.
929f0a26885SShreyansh Jain 			 */
930f0a26885SShreyansh Jain 			ret = init_mem(0, NB_MBUF(nb_ports));
931f0a26885SShreyansh Jain 		} else {
932f0a26885SShreyansh Jain 			ret = init_mem(portid, NB_MBUF(1));
933f0a26885SShreyansh Jain 		}
934f68aad79SIntel 		if (ret < 0)
935f68aad79SIntel 			rte_exit(EXIT_FAILURE, "init_mem failed\n");
936af75078fSIntel 
937af75078fSIntel 		/* init one TX queue per couple (lcore,port) */
938af75078fSIntel 		queueid = 0;
939af75078fSIntel 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
940af75078fSIntel 			if (rte_lcore_is_enabled(lcore_id) == 0)
941af75078fSIntel 				continue;
942af75078fSIntel 
943af75078fSIntel 			if (numa_on)
944268888b5SRavi Kerur 				socketid =
945268888b5SRavi Kerur 				(uint8_t)rte_lcore_to_socket_id(lcore_id);
946af75078fSIntel 			else
947af75078fSIntel 				socketid = 0;
948af75078fSIntel 
949af75078fSIntel 			printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
950af75078fSIntel 			fflush(stdout);
95181f7ecd9SPablo de Lara 
95281f7ecd9SPablo de Lara 			txconf = &dev_info.default_txconf;
9531ef9600bSShahaf Shuler 			txconf->offloads = local_port_conf.txmode.offloads;
954af75078fSIntel 			ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
95581f7ecd9SPablo de Lara 						     socketid, txconf);
956af75078fSIntel 			if (ret < 0)
957268888b5SRavi Kerur 				rte_exit(EXIT_FAILURE,
958268888b5SRavi Kerur 					"rte_eth_tx_queue_setup: err=%d, "
959af75078fSIntel 					"port=%d\n", ret, portid);
960af75078fSIntel 
961af75078fSIntel 			qconf = &lcore_conf[lcore_id];
962af75078fSIntel 			qconf->tx_queue_id[portid] = queueid;
963af75078fSIntel 			queueid++;
96452c97adcSTomasz Kulasek 
96552c97adcSTomasz Kulasek 			qconf->tx_port_id[qconf->n_tx_port] = portid;
9669d203b76STomasz Kulasek 			qconf->n_tx_port++;
967af75078fSIntel 		}
968af75078fSIntel 		printf("\n");
969af75078fSIntel 	}
970af75078fSIntel 
971af75078fSIntel 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
972af75078fSIntel 		if (rte_lcore_is_enabled(lcore_id) == 0)
973af75078fSIntel 			continue;
974af75078fSIntel 		qconf = &lcore_conf[lcore_id];
975af75078fSIntel 		printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
976af75078fSIntel 		fflush(stdout);
977af75078fSIntel 		/* init RX queues */
978af75078fSIntel 		for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
9791ef9600bSShahaf Shuler 			struct rte_eth_rxconf rxq_conf;
9801ef9600bSShahaf Shuler 
981af75078fSIntel 			portid = qconf->rx_queue_list[queue].port_id;
982af75078fSIntel 			queueid = qconf->rx_queue_list[queue].queue_id;
983af75078fSIntel 
984af75078fSIntel 			if (numa_on)
985268888b5SRavi Kerur 				socketid =
986268888b5SRavi Kerur 				(uint8_t)rte_lcore_to_socket_id(lcore_id);
987af75078fSIntel 			else
988af75078fSIntel 				socketid = 0;
989af75078fSIntel 
990af75078fSIntel 			printf("rxq=%d,%d,%d ", portid, queueid, socketid);
991af75078fSIntel 			fflush(stdout);
992af75078fSIntel 
993*089e5ed7SIvan Ilchenko 			ret = rte_eth_dev_info_get(portid, &dev_info);
994*089e5ed7SIvan Ilchenko 			if (ret != 0)
995*089e5ed7SIvan Ilchenko 				rte_exit(EXIT_FAILURE,
996*089e5ed7SIvan Ilchenko 					"Error during getting device (port %u) info: %s\n",
997*089e5ed7SIvan Ilchenko 					portid, strerror(-ret));
998*089e5ed7SIvan Ilchenko 
9991ef9600bSShahaf Shuler 			rxq_conf = dev_info.default_rxconf;
10005c5c1f99SMarcin Zapolski 			rxq_conf.offloads = port_conf.rxmode.offloads;
1001f0a26885SShreyansh Jain 			if (!per_port_pool)
1002f0a26885SShreyansh Jain 				ret = rte_eth_rx_queue_setup(portid, queueid,
1003f0a26885SShreyansh Jain 						nb_rxd, socketid,
10041ef9600bSShahaf Shuler 						&rxq_conf,
1005f0a26885SShreyansh Jain 						pktmbuf_pool[0][socketid]);
1006f0a26885SShreyansh Jain 			else
1007f0a26885SShreyansh Jain 				ret = rte_eth_rx_queue_setup(portid, queueid,
1008f0a26885SShreyansh Jain 						nb_rxd, socketid,
1009f0a26885SShreyansh Jain 						&rxq_conf,
1010f0a26885SShreyansh Jain 						pktmbuf_pool[portid][socketid]);
1011af75078fSIntel 			if (ret < 0)
1012268888b5SRavi Kerur 				rte_exit(EXIT_FAILURE,
1013268888b5SRavi Kerur 				"rte_eth_rx_queue_setup: err=%d, port=%d\n",
1014268888b5SRavi Kerur 				ret, portid);
1015af75078fSIntel 		}
1016af75078fSIntel 	}
1017af75078fSIntel 
1018af75078fSIntel 	printf("\n");
1019af75078fSIntel 
1020af75078fSIntel 	/* start ports */
10218728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
1022af75078fSIntel 		if ((enabled_port_mask & (1 << portid)) == 0) {
1023af75078fSIntel 			continue;
1024af75078fSIntel 		}
1025af75078fSIntel 		/* Start device */
1026af75078fSIntel 		ret = rte_eth_dev_start(portid);
1027af75078fSIntel 		if (ret < 0)
1028268888b5SRavi Kerur 			rte_exit(EXIT_FAILURE,
1029268888b5SRavi Kerur 				"rte_eth_dev_start: err=%d, port=%d\n",
1030af75078fSIntel 				ret, portid);
1031af75078fSIntel 
1032af75078fSIntel 		/*
1033af75078fSIntel 		 * If enabled, put device in promiscuous mode.
1034af75078fSIntel 		 * This allows IO forwarding mode to forward packets
1035af75078fSIntel 		 * to itself through 2 cross-connected  ports of the
1036af75078fSIntel 		 * target machine.
1037af75078fSIntel 		 */
1038af75078fSIntel 		if (promiscuous_on)
1039af75078fSIntel 			rte_eth_promiscuous_enable(portid);
1040af75078fSIntel 	}
1041af75078fSIntel 
104271a7e242SJianfeng Tan 	printf("\n");
104371a7e242SJianfeng Tan 
104471a7e242SJianfeng Tan 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
104571a7e242SJianfeng Tan 		if (rte_lcore_is_enabled(lcore_id) == 0)
104671a7e242SJianfeng Tan 			continue;
104771a7e242SJianfeng Tan 		qconf = &lcore_conf[lcore_id];
104871a7e242SJianfeng Tan 		for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
104971a7e242SJianfeng Tan 			portid = qconf->rx_queue_list[queue].port_id;
105071a7e242SJianfeng Tan 			queueid = qconf->rx_queue_list[queue].queue_id;
105171a7e242SJianfeng Tan 			if (prepare_ptype_parser(portid, queueid) == 0)
105271a7e242SJianfeng Tan 				rte_exit(EXIT_FAILURE, "ptype check fails\n");
105371a7e242SJianfeng Tan 		}
105471a7e242SJianfeng Tan 	}
105571a7e242SJianfeng Tan 
105671a7e242SJianfeng Tan 
10578728ccf3SThomas Monjalon 	check_all_ports_link_status(enabled_port_mask);
1058d3641ae8SIntel 
1059308df2bfSZhihong Wang 	ret = 0;
1060af75078fSIntel 	/* launch per-lcore init on every lcore */
1061268888b5SRavi Kerur 	rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MASTER);
1062af75078fSIntel 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1063308df2bfSZhihong Wang 		if (rte_eal_wait_lcore(lcore_id) < 0) {
1064308df2bfSZhihong Wang 			ret = -1;
1065308df2bfSZhihong Wang 			break;
1066308df2bfSZhihong Wang 		}
1067af75078fSIntel 	}
1068af75078fSIntel 
1069308df2bfSZhihong Wang 	/* stop ports */
10708728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
1071308df2bfSZhihong Wang 		if ((enabled_port_mask & (1 << portid)) == 0)
1072308df2bfSZhihong Wang 			continue;
1073308df2bfSZhihong Wang 		printf("Closing port %d...", portid);
1074308df2bfSZhihong Wang 		rte_eth_dev_stop(portid);
1075308df2bfSZhihong Wang 		rte_eth_dev_close(portid);
1076308df2bfSZhihong Wang 		printf(" Done\n");
1077308df2bfSZhihong Wang 	}
1078308df2bfSZhihong Wang 	printf("Bye...\n");
1079308df2bfSZhihong Wang 
1080308df2bfSZhihong Wang 	return ret;
1081af75078fSIntel }
1082