xref: /dpdk/examples/l3fwd/main.c (revision f8dbaebbf1c9efcbb2e2354b341ed62175466a57)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2021 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <inttypes.h>
9 #include <sys/types.h>
10 #include <string.h>
11 #include <sys/queue.h>
12 #include <stdarg.h>
13 #include <errno.h>
14 #include <getopt.h>
15 #include <signal.h>
16 #include <stdbool.h>
17 
18 #include <rte_common.h>
19 #include <rte_vect.h>
20 #include <rte_byteorder.h>
21 #include <rte_log.h>
22 #include <rte_malloc.h>
23 #include <rte_memory.h>
24 #include <rte_memcpy.h>
25 #include <rte_eal.h>
26 #include <rte_launch.h>
27 #include <rte_cycles.h>
28 #include <rte_prefetch.h>
29 #include <rte_lcore.h>
30 #include <rte_per_lcore.h>
31 #include <rte_branch_prediction.h>
32 #include <rte_interrupts.h>
33 #include <rte_random.h>
34 #include <rte_debug.h>
35 #include <rte_ether.h>
36 #include <rte_mempool.h>
37 #include <rte_mbuf.h>
38 #include <rte_ip.h>
39 #include <rte_tcp.h>
40 #include <rte_udp.h>
41 #include <rte_string_fns.h>
42 #include <rte_cpuflags.h>
43 
44 #include <cmdline_parse.h>
45 #include <cmdline_parse_etheraddr.h>
46 
47 #include "l3fwd.h"
48 #include "l3fwd_event.h"
49 #include "l3fwd_route.h"
50 
51 #define MAX_TX_QUEUE_PER_PORT RTE_MAX_LCORE
52 #define MAX_RX_QUEUE_PER_PORT 128
53 
54 #define MAX_LCORE_PARAMS 1024
55 
56 /* Static global variables used within this file. */
57 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
58 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
59 
60 /**< Ports set in promiscuous mode off by default. */
61 static int promiscuous_on;
62 
63 /* Select Longest-Prefix, Exact match or Forwarding Information Base. */
64 enum L3FWD_LOOKUP_MODE {
65 	L3FWD_LOOKUP_DEFAULT,
66 	L3FWD_LOOKUP_LPM,
67 	L3FWD_LOOKUP_EM,
68 	L3FWD_LOOKUP_FIB
69 };
70 static enum L3FWD_LOOKUP_MODE lookup_mode;
71 
72 /* Global variables. */
73 
74 static int numa_on = 1; /**< NUMA is enabled by default. */
75 static int parse_ptype; /**< Parse packet type using rx callback, and */
76 			/**< disabled by default */
77 static int per_port_pool; /**< Use separate buffer pools per port; disabled */
78 			  /**< by default */
79 
80 volatile bool force_quit;
81 
82 /* ethernet addresses of ports */
83 uint64_t dest_eth_addr[RTE_MAX_ETHPORTS];
84 struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
85 
86 xmm_t val_eth[RTE_MAX_ETHPORTS];
87 
88 /* mask of enabled ports */
89 uint32_t enabled_port_mask;
90 
91 /* Used only in exact match mode. */
92 int ipv6; /**< ipv6 is false by default. */
93 uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
94 
95 struct lcore_conf lcore_conf[RTE_MAX_LCORE];
96 
97 struct lcore_params {
98 	uint16_t port_id;
99 	uint8_t queue_id;
100 	uint8_t lcore_id;
101 } __rte_cache_aligned;
102 
103 static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
104 static struct lcore_params lcore_params_array_default[] = {
105 	{0, 0, 2},
106 	{0, 1, 2},
107 	{0, 2, 2},
108 	{1, 0, 2},
109 	{1, 1, 2},
110 	{1, 2, 2},
111 	{2, 0, 2},
112 	{3, 0, 3},
113 	{3, 1, 3},
114 };
115 
116 static struct lcore_params * lcore_params = lcore_params_array_default;
117 static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
118 				sizeof(lcore_params_array_default[0]);
119 
120 static struct rte_eth_conf port_conf = {
121 	.rxmode = {
122 		.mq_mode = RTE_ETH_MQ_RX_RSS,
123 		.split_hdr_size = 0,
124 		.offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM,
125 	},
126 	.rx_adv_conf = {
127 		.rss_conf = {
128 			.rss_key = NULL,
129 			.rss_hf = RTE_ETH_RSS_IP,
130 		},
131 	},
132 	.txmode = {
133 		.mq_mode = RTE_ETH_MQ_TX_NONE,
134 	},
135 };
136 
137 static uint32_t max_pkt_len;
138 
139 static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS];
140 static struct rte_mempool *vector_pool[RTE_MAX_ETHPORTS];
141 static uint8_t lkp_per_socket[NB_SOCKETS];
142 
143 struct l3fwd_lkp_mode {
144 	void  (*setup)(int);
145 	int   (*check_ptype)(int);
146 	rte_rx_callback_fn cb_parse_ptype;
147 	int   (*main_loop)(void *);
148 	void* (*get_ipv4_lookup_struct)(int);
149 	void* (*get_ipv6_lookup_struct)(int);
150 };
151 
152 static struct l3fwd_lkp_mode l3fwd_lkp;
153 
154 static struct l3fwd_lkp_mode l3fwd_em_lkp = {
155 	.setup                  = setup_hash,
156 	.check_ptype		= em_check_ptype,
157 	.cb_parse_ptype		= em_cb_parse_ptype,
158 	.main_loop              = em_main_loop,
159 	.get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct,
160 	.get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct,
161 };
162 
163 static struct l3fwd_lkp_mode l3fwd_lpm_lkp = {
164 	.setup                  = setup_lpm,
165 	.check_ptype		= lpm_check_ptype,
166 	.cb_parse_ptype		= lpm_cb_parse_ptype,
167 	.main_loop              = lpm_main_loop,
168 	.get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct,
169 	.get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct,
170 };
171 
172 static struct l3fwd_lkp_mode l3fwd_fib_lkp = {
173 	.setup                  = setup_fib,
174 	.check_ptype            = lpm_check_ptype,
175 	.cb_parse_ptype         = lpm_cb_parse_ptype,
176 	.main_loop              = fib_main_loop,
177 	.get_ipv4_lookup_struct = fib_get_ipv4_l3fwd_lookup_struct,
178 	.get_ipv6_lookup_struct = fib_get_ipv6_l3fwd_lookup_struct,
179 };
180 
181 /*
182  * 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735).
183  * 198.18.{0-15}.0/24 = Port {0-15}
184  */
185 const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
186 	{RTE_IPV4(198, 18, 0, 0), 24, 0},
187 	{RTE_IPV4(198, 18, 1, 0), 24, 1},
188 	{RTE_IPV4(198, 18, 2, 0), 24, 2},
189 	{RTE_IPV4(198, 18, 3, 0), 24, 3},
190 	{RTE_IPV4(198, 18, 4, 0), 24, 4},
191 	{RTE_IPV4(198, 18, 5, 0), 24, 5},
192 	{RTE_IPV4(198, 18, 6, 0), 24, 6},
193 	{RTE_IPV4(198, 18, 7, 0), 24, 7},
194 	{RTE_IPV4(198, 18, 8, 0), 24, 8},
195 	{RTE_IPV4(198, 18, 9, 0), 24, 9},
196 	{RTE_IPV4(198, 18, 10, 0), 24, 10},
197 	{RTE_IPV4(198, 18, 11, 0), 24, 11},
198 	{RTE_IPV4(198, 18, 12, 0), 24, 12},
199 	{RTE_IPV4(198, 18, 13, 0), 24, 13},
200 	{RTE_IPV4(198, 18, 14, 0), 24, 14},
201 	{RTE_IPV4(198, 18, 15, 0), 24, 15},
202 };
203 
204 /*
205  * 2001:200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180).
206  * 2001:200:0:{0-f}::/64 = Port {0-15}
207  */
208 const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
209 	{{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 0},
210 	{{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 1},
211 	{{32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 2},
212 	{{32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 3},
213 	{{32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 4},
214 	{{32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 5},
215 	{{32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 6},
216 	{{32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 7},
217 	{{32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 8},
218 	{{32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 9},
219 	{{32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 10},
220 	{{32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 11},
221 	{{32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 12},
222 	{{32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 13},
223 	{{32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 14},
224 	{{32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 15},
225 };
226 
227 /*
228  * Setup lookup methods for forwarding.
229  * Currently exact-match, longest-prefix-match and forwarding information
230  * base are the supported ones.
231  */
232 static void
233 setup_l3fwd_lookup_tables(void)
234 {
235 	/* Setup HASH lookup functions. */
236 	if (lookup_mode == L3FWD_LOOKUP_EM)
237 		l3fwd_lkp = l3fwd_em_lkp;
238 	/* Setup FIB lookup functions. */
239 	else if (lookup_mode == L3FWD_LOOKUP_FIB)
240 		l3fwd_lkp = l3fwd_fib_lkp;
241 	/* Setup LPM lookup functions. */
242 	else
243 		l3fwd_lkp = l3fwd_lpm_lkp;
244 }
245 
246 static int
247 check_lcore_params(void)
248 {
249 	uint8_t queue, lcore;
250 	uint16_t i;
251 	int socketid;
252 
253 	for (i = 0; i < nb_lcore_params; ++i) {
254 		queue = lcore_params[i].queue_id;
255 		if (queue >= MAX_RX_QUEUE_PER_PORT) {
256 			printf("invalid queue number: %hhu\n", queue);
257 			return -1;
258 		}
259 		lcore = lcore_params[i].lcore_id;
260 		if (!rte_lcore_is_enabled(lcore)) {
261 			printf("error: lcore %hhu is not enabled in lcore mask\n", lcore);
262 			return -1;
263 		}
264 		if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
265 			(numa_on == 0)) {
266 			printf("warning: lcore %hhu is on socket %d with numa off \n",
267 				lcore, socketid);
268 		}
269 	}
270 	return 0;
271 }
272 
273 static int
274 check_port_config(void)
275 {
276 	uint16_t portid;
277 	uint16_t i;
278 
279 	for (i = 0; i < nb_lcore_params; ++i) {
280 		portid = lcore_params[i].port_id;
281 		if ((enabled_port_mask & (1 << portid)) == 0) {
282 			printf("port %u is not enabled in port mask\n", portid);
283 			return -1;
284 		}
285 		if (!rte_eth_dev_is_valid_port(portid)) {
286 			printf("port %u is not present on the board\n", portid);
287 			return -1;
288 		}
289 	}
290 	return 0;
291 }
292 
293 static uint8_t
294 get_port_n_rx_queues(const uint16_t port)
295 {
296 	int queue = -1;
297 	uint16_t i;
298 
299 	for (i = 0; i < nb_lcore_params; ++i) {
300 		if (lcore_params[i].port_id == port) {
301 			if (lcore_params[i].queue_id == queue+1)
302 				queue = lcore_params[i].queue_id;
303 			else
304 				rte_exit(EXIT_FAILURE, "queue ids of the port %d must be"
305 						" in sequence and must start with 0\n",
306 						lcore_params[i].port_id);
307 		}
308 	}
309 	return (uint8_t)(++queue);
310 }
311 
312 static int
313 init_lcore_rx_queues(void)
314 {
315 	uint16_t i, nb_rx_queue;
316 	uint8_t lcore;
317 
318 	for (i = 0; i < nb_lcore_params; ++i) {
319 		lcore = lcore_params[i].lcore_id;
320 		nb_rx_queue = lcore_conf[lcore].n_rx_queue;
321 		if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
322 			printf("error: too many queues (%u) for lcore: %u\n",
323 				(unsigned)nb_rx_queue + 1, (unsigned)lcore);
324 			return -1;
325 		} else {
326 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
327 				lcore_params[i].port_id;
328 			lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
329 				lcore_params[i].queue_id;
330 			lcore_conf[lcore].n_rx_queue++;
331 		}
332 	}
333 	return 0;
334 }
335 
336 /* display usage */
337 static void
338 print_usage(const char *prgname)
339 {
340 	fprintf(stderr, "%s [EAL options] --"
341 		" -p PORTMASK"
342 		" [-P]"
343 		" [--lookup]"
344 		" --config (port,queue,lcore)[,(port,queue,lcore)]"
345 		" [--eth-dest=X,MM:MM:MM:MM:MM:MM]"
346 		" [--max-pkt-len PKTLEN]"
347 		" [--no-numa]"
348 		" [--hash-entry-num]"
349 		" [--ipv6]"
350 		" [--parse-ptype]"
351 		" [--per-port-pool]"
352 		" [--mode]"
353 		" [--eventq-sched]"
354 		" [--event-vector [--event-vector-size SIZE] [--event-vector-tmo NS]]"
355 		" [-E]"
356 		" [-L]\n\n"
357 
358 		"  -p PORTMASK: Hexadecimal bitmask of ports to configure\n"
359 		"  -P : Enable promiscuous mode\n"
360 		"  --lookup: Select the lookup method\n"
361 		"            Default: lpm\n"
362 		"            Accepted: em (Exact Match), lpm (Longest Prefix Match), fib (Forwarding Information Base)\n"
363 		"  --config (port,queue,lcore): Rx queue configuration\n"
364 		"  --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n"
365 		"  --max-pkt-len PKTLEN: maximum packet length in decimal (64-9600)\n"
366 		"  --no-numa: Disable numa awareness\n"
367 		"  --hash-entry-num: Specify the hash entry number in hexadecimal to be setup\n"
368 		"  --ipv6: Set if running ipv6 packets\n"
369 		"  --parse-ptype: Set to use software to analyze packet type\n"
370 		"  --per-port-pool: Use separate buffer pool per port\n"
371 		"  --mode: Packet transfer mode for I/O, poll or eventdev\n"
372 		"          Default mode = poll\n"
373 		"  --eventq-sched: Event queue synchronization method\n"
374 		"                  ordered, atomic or parallel.\n"
375 		"                  Default: atomic\n"
376 		"                  Valid only if --mode=eventdev\n"
377 		"  --event-eth-rxqs: Number of ethernet RX queues per device.\n"
378 		"                    Default: 1\n"
379 		"                    Valid only if --mode=eventdev\n"
380 		"  --event-vector:  Enable event vectorization.\n"
381 		"  --event-vector-size: Max vector size if event vectorization is enabled.\n"
382 		"  --event-vector-tmo: Max timeout to form vector in nanoseconds if event vectorization is enabled\n"
383 		"  -E : Enable exact match, legacy flag please use --lookup=em instead\n"
384 		"  -L : Enable longest prefix match, legacy flag please use --lookup=lpm instead\n\n",
385 		prgname);
386 }
387 
388 static int
389 parse_max_pkt_len(const char *pktlen)
390 {
391 	char *end = NULL;
392 	unsigned long len;
393 
394 	/* parse decimal string */
395 	len = strtoul(pktlen, &end, 10);
396 	if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
397 		return -1;
398 
399 	if (len == 0)
400 		return -1;
401 
402 	return len;
403 }
404 
405 static int
406 parse_portmask(const char *portmask)
407 {
408 	char *end = NULL;
409 	unsigned long pm;
410 
411 	/* parse hexadecimal string */
412 	pm = strtoul(portmask, &end, 16);
413 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
414 		return 0;
415 
416 	return pm;
417 }
418 
419 static int
420 parse_hash_entry_number(const char *hash_entry_num)
421 {
422 	char *end = NULL;
423 	unsigned long hash_en;
424 	/* parse hexadecimal string */
425 	hash_en = strtoul(hash_entry_num, &end, 16);
426 	if ((hash_entry_num[0] == '\0') || (end == NULL) || (*end != '\0'))
427 		return -1;
428 
429 	if (hash_en == 0)
430 		return -1;
431 
432 	return hash_en;
433 }
434 
435 static int
436 parse_config(const char *q_arg)
437 {
438 	char s[256];
439 	const char *p, *p0 = q_arg;
440 	char *end;
441 	enum fieldnames {
442 		FLD_PORT = 0,
443 		FLD_QUEUE,
444 		FLD_LCORE,
445 		_NUM_FLD
446 	};
447 	unsigned long int_fld[_NUM_FLD];
448 	char *str_fld[_NUM_FLD];
449 	int i;
450 	unsigned size;
451 
452 	nb_lcore_params = 0;
453 
454 	while ((p = strchr(p0,'(')) != NULL) {
455 		++p;
456 		if((p0 = strchr(p,')')) == NULL)
457 			return -1;
458 
459 		size = p0 - p;
460 		if(size >= sizeof(s))
461 			return -1;
462 
463 		snprintf(s, sizeof(s), "%.*s", size, p);
464 		if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
465 			return -1;
466 		for (i = 0; i < _NUM_FLD; i++){
467 			errno = 0;
468 			int_fld[i] = strtoul(str_fld[i], &end, 0);
469 			if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
470 				return -1;
471 		}
472 		if (nb_lcore_params >= MAX_LCORE_PARAMS) {
473 			printf("exceeded max number of lcore params: %hu\n",
474 				nb_lcore_params);
475 			return -1;
476 		}
477 		lcore_params_array[nb_lcore_params].port_id =
478 			(uint8_t)int_fld[FLD_PORT];
479 		lcore_params_array[nb_lcore_params].queue_id =
480 			(uint8_t)int_fld[FLD_QUEUE];
481 		lcore_params_array[nb_lcore_params].lcore_id =
482 			(uint8_t)int_fld[FLD_LCORE];
483 		++nb_lcore_params;
484 	}
485 	lcore_params = lcore_params_array;
486 	return 0;
487 }
488 
489 static void
490 parse_eth_dest(const char *optarg)
491 {
492 	uint16_t portid;
493 	char *port_end;
494 	uint8_t c, *dest, peer_addr[6];
495 
496 	errno = 0;
497 	portid = strtoul(optarg, &port_end, 10);
498 	if (errno != 0 || port_end == optarg || *port_end++ != ',')
499 		rte_exit(EXIT_FAILURE,
500 		"Invalid eth-dest: %s", optarg);
501 	if (portid >= RTE_MAX_ETHPORTS)
502 		rte_exit(EXIT_FAILURE,
503 		"eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n",
504 		portid, RTE_MAX_ETHPORTS);
505 
506 	if (cmdline_parse_etheraddr(NULL, port_end,
507 		&peer_addr, sizeof(peer_addr)) < 0)
508 		rte_exit(EXIT_FAILURE,
509 		"Invalid ethernet address: %s\n",
510 		port_end);
511 	dest = (uint8_t *)&dest_eth_addr[portid];
512 	for (c = 0; c < 6; c++)
513 		dest[c] = peer_addr[c];
514 	*(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
515 }
516 
517 static void
518 parse_mode(const char *optarg)
519 {
520 	struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
521 
522 	if (!strcmp(optarg, "poll"))
523 		evt_rsrc->enabled = false;
524 	else if (!strcmp(optarg, "eventdev"))
525 		evt_rsrc->enabled = true;
526 }
527 
528 static void
529 parse_eventq_sched(const char *optarg)
530 {
531 	struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
532 
533 	if (!strcmp(optarg, "ordered"))
534 		evt_rsrc->sched_type = RTE_SCHED_TYPE_ORDERED;
535 	if (!strcmp(optarg, "atomic"))
536 		evt_rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC;
537 	if (!strcmp(optarg, "parallel"))
538 		evt_rsrc->sched_type = RTE_SCHED_TYPE_PARALLEL;
539 }
540 
541 static void
542 parse_event_eth_rx_queues(const char *eth_rx_queues)
543 {
544 	struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
545 	char *end = NULL;
546 	uint8_t num_eth_rx_queues;
547 
548 	/* parse decimal string */
549 	num_eth_rx_queues = strtoul(eth_rx_queues, &end, 10);
550 	if ((eth_rx_queues[0] == '\0') || (end == NULL) || (*end != '\0'))
551 		return;
552 
553 	if (num_eth_rx_queues == 0)
554 		return;
555 
556 	evt_rsrc->eth_rx_queues = num_eth_rx_queues;
557 }
558 
559 static int
560 parse_lookup(const char *optarg)
561 {
562 	if (!strcmp(optarg, "em"))
563 		lookup_mode = L3FWD_LOOKUP_EM;
564 	else if (!strcmp(optarg, "lpm"))
565 		lookup_mode = L3FWD_LOOKUP_LPM;
566 	else if (!strcmp(optarg, "fib"))
567 		lookup_mode = L3FWD_LOOKUP_FIB;
568 	else {
569 		fprintf(stderr, "Invalid lookup option! Accepted options: em, lpm, fib\n");
570 		return -1;
571 	}
572 	return 0;
573 }
574 
575 #define MAX_JUMBO_PKT_LEN  9600
576 
577 static const char short_options[] =
578 	"p:"  /* portmask */
579 	"P"   /* promiscuous */
580 	"L"   /* legacy enable long prefix match */
581 	"E"   /* legacy enable exact match */
582 	;
583 
584 #define CMD_LINE_OPT_CONFIG "config"
585 #define CMD_LINE_OPT_ETH_DEST "eth-dest"
586 #define CMD_LINE_OPT_NO_NUMA "no-numa"
587 #define CMD_LINE_OPT_IPV6 "ipv6"
588 #define CMD_LINE_OPT_MAX_PKT_LEN "max-pkt-len"
589 #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
590 #define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
591 #define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool"
592 #define CMD_LINE_OPT_MODE "mode"
593 #define CMD_LINE_OPT_EVENTQ_SYNC "eventq-sched"
594 #define CMD_LINE_OPT_EVENT_ETH_RX_QUEUES "event-eth-rxqs"
595 #define CMD_LINE_OPT_LOOKUP "lookup"
596 #define CMD_LINE_OPT_ENABLE_VECTOR "event-vector"
597 #define CMD_LINE_OPT_VECTOR_SIZE "event-vector-size"
598 #define CMD_LINE_OPT_VECTOR_TMO_NS "event-vector-tmo"
599 
600 enum {
601 	/* long options mapped to a short option */
602 
603 	/* first long only option value must be >= 256, so that we won't
604 	 * conflict with short options */
605 	CMD_LINE_OPT_MIN_NUM = 256,
606 	CMD_LINE_OPT_CONFIG_NUM,
607 	CMD_LINE_OPT_ETH_DEST_NUM,
608 	CMD_LINE_OPT_NO_NUMA_NUM,
609 	CMD_LINE_OPT_IPV6_NUM,
610 	CMD_LINE_OPT_MAX_PKT_LEN_NUM,
611 	CMD_LINE_OPT_HASH_ENTRY_NUM_NUM,
612 	CMD_LINE_OPT_PARSE_PTYPE_NUM,
613 	CMD_LINE_OPT_PARSE_PER_PORT_POOL,
614 	CMD_LINE_OPT_MODE_NUM,
615 	CMD_LINE_OPT_EVENTQ_SYNC_NUM,
616 	CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM,
617 	CMD_LINE_OPT_LOOKUP_NUM,
618 	CMD_LINE_OPT_ENABLE_VECTOR_NUM,
619 	CMD_LINE_OPT_VECTOR_SIZE_NUM,
620 	CMD_LINE_OPT_VECTOR_TMO_NS_NUM
621 };
622 
623 static const struct option lgopts[] = {
624 	{CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM},
625 	{CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM},
626 	{CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM},
627 	{CMD_LINE_OPT_IPV6, 0, 0, CMD_LINE_OPT_IPV6_NUM},
628 	{CMD_LINE_OPT_MAX_PKT_LEN, 1, 0, CMD_LINE_OPT_MAX_PKT_LEN_NUM},
629 	{CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, CMD_LINE_OPT_HASH_ENTRY_NUM_NUM},
630 	{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, CMD_LINE_OPT_PARSE_PTYPE_NUM},
631 	{CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL},
632 	{CMD_LINE_OPT_MODE, 1, 0, CMD_LINE_OPT_MODE_NUM},
633 	{CMD_LINE_OPT_EVENTQ_SYNC, 1, 0, CMD_LINE_OPT_EVENTQ_SYNC_NUM},
634 	{CMD_LINE_OPT_EVENT_ETH_RX_QUEUES, 1, 0,
635 					CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM},
636 	{CMD_LINE_OPT_LOOKUP, 1, 0, CMD_LINE_OPT_LOOKUP_NUM},
637 	{CMD_LINE_OPT_ENABLE_VECTOR, 0, 0, CMD_LINE_OPT_ENABLE_VECTOR_NUM},
638 	{CMD_LINE_OPT_VECTOR_SIZE, 1, 0, CMD_LINE_OPT_VECTOR_SIZE_NUM},
639 	{CMD_LINE_OPT_VECTOR_TMO_NS, 1, 0, CMD_LINE_OPT_VECTOR_TMO_NS_NUM},
640 	{NULL, 0, 0, 0}
641 };
642 
643 /*
644  * This expression is used to calculate the number of mbufs needed
645  * depending on user input, taking  into account memory for rx and
646  * tx hardware rings, cache per lcore and mtable per port per lcore.
647  * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum
648  * value of 8192
649  */
650 #define NB_MBUF(nports) RTE_MAX(	\
651 	(nports*nb_rx_queue*nb_rxd +		\
652 	nports*nb_lcores*MAX_PKT_BURST +	\
653 	nports*n_tx_queue*nb_txd +		\
654 	nb_lcores*MEMPOOL_CACHE_SIZE),		\
655 	(unsigned)8192)
656 
657 /* Parse the argument given in the command line of the application */
658 static int
659 parse_args(int argc, char **argv)
660 {
661 	int opt, ret;
662 	char **argvopt;
663 	int option_index;
664 	char *prgname = argv[0];
665 	uint8_t lcore_params = 0;
666 	uint8_t eventq_sched = 0;
667 	uint8_t eth_rx_q = 0;
668 	struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
669 
670 	argvopt = argv;
671 
672 	/* Error or normal output strings. */
673 	while ((opt = getopt_long(argc, argvopt, short_options,
674 				lgopts, &option_index)) != EOF) {
675 
676 		switch (opt) {
677 		/* portmask */
678 		case 'p':
679 			enabled_port_mask = parse_portmask(optarg);
680 			if (enabled_port_mask == 0) {
681 				fprintf(stderr, "Invalid portmask\n");
682 				print_usage(prgname);
683 				return -1;
684 			}
685 			break;
686 
687 		case 'P':
688 			promiscuous_on = 1;
689 			break;
690 
691 		case 'E':
692 			if (lookup_mode != L3FWD_LOOKUP_DEFAULT) {
693 				fprintf(stderr, "Only one lookup mode is allowed at a time!\n");
694 				return -1;
695 			}
696 			lookup_mode = L3FWD_LOOKUP_EM;
697 			break;
698 
699 		case 'L':
700 			if (lookup_mode != L3FWD_LOOKUP_DEFAULT) {
701 				fprintf(stderr, "Only one lookup mode is allowed at a time!\n");
702 				return -1;
703 			}
704 			lookup_mode = L3FWD_LOOKUP_LPM;
705 			break;
706 
707 		/* long options */
708 		case CMD_LINE_OPT_CONFIG_NUM:
709 			ret = parse_config(optarg);
710 			if (ret) {
711 				fprintf(stderr, "Invalid config\n");
712 				print_usage(prgname);
713 				return -1;
714 			}
715 			lcore_params = 1;
716 			break;
717 
718 		case CMD_LINE_OPT_ETH_DEST_NUM:
719 			parse_eth_dest(optarg);
720 			break;
721 
722 		case CMD_LINE_OPT_NO_NUMA_NUM:
723 			numa_on = 0;
724 			break;
725 
726 		case CMD_LINE_OPT_IPV6_NUM:
727 			ipv6 = 1;
728 			break;
729 
730 		case CMD_LINE_OPT_MAX_PKT_LEN_NUM:
731 			max_pkt_len = parse_max_pkt_len(optarg);
732 			break;
733 
734 		case CMD_LINE_OPT_HASH_ENTRY_NUM_NUM:
735 			ret = parse_hash_entry_number(optarg);
736 			if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) {
737 				hash_entry_number = ret;
738 			} else {
739 				fprintf(stderr, "invalid hash entry number\n");
740 				print_usage(prgname);
741 				return -1;
742 			}
743 			break;
744 
745 		case CMD_LINE_OPT_PARSE_PTYPE_NUM:
746 			printf("soft parse-ptype is enabled\n");
747 			parse_ptype = 1;
748 			break;
749 
750 		case CMD_LINE_OPT_PARSE_PER_PORT_POOL:
751 			printf("per port buffer pool is enabled\n");
752 			per_port_pool = 1;
753 			break;
754 
755 		case CMD_LINE_OPT_MODE_NUM:
756 			parse_mode(optarg);
757 			break;
758 
759 		case CMD_LINE_OPT_EVENTQ_SYNC_NUM:
760 			parse_eventq_sched(optarg);
761 			eventq_sched = 1;
762 			break;
763 
764 		case CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM:
765 			parse_event_eth_rx_queues(optarg);
766 			eth_rx_q = 1;
767 			break;
768 
769 		case CMD_LINE_OPT_LOOKUP_NUM:
770 			if (lookup_mode != L3FWD_LOOKUP_DEFAULT) {
771 				fprintf(stderr, "Only one lookup mode is allowed at a time!\n");
772 				return -1;
773 			}
774 			ret = parse_lookup(optarg);
775 			/*
776 			 * If parse_lookup was passed an invalid lookup type
777 			 * then return -1. Error log included within
778 			 * parse_lookup for simplicity.
779 			 */
780 			if (ret)
781 				return -1;
782 			break;
783 
784 		case CMD_LINE_OPT_ENABLE_VECTOR_NUM:
785 			printf("event vectorization is enabled\n");
786 			evt_rsrc->vector_enabled = 1;
787 			break;
788 		case CMD_LINE_OPT_VECTOR_SIZE_NUM:
789 			evt_rsrc->vector_size = strtol(optarg, NULL, 10);
790 			break;
791 		case CMD_LINE_OPT_VECTOR_TMO_NS_NUM:
792 			evt_rsrc->vector_tmo_ns = strtoull(optarg, NULL, 10);
793 			break;
794 		default:
795 			print_usage(prgname);
796 			return -1;
797 		}
798 	}
799 
800 	if (evt_rsrc->enabled && lcore_params) {
801 		fprintf(stderr, "lcore config is not valid when event mode is selected\n");
802 		return -1;
803 	}
804 
805 	if (!evt_rsrc->enabled && eth_rx_q) {
806 		fprintf(stderr, "eth_rx_queues is valid only when event mode is selected\n");
807 		return -1;
808 	}
809 
810 	if (!evt_rsrc->enabled && eventq_sched) {
811 		fprintf(stderr, "eventq_sched is valid only when event mode is selected\n");
812 		return -1;
813 	}
814 
815 	if (evt_rsrc->vector_enabled && !evt_rsrc->vector_size) {
816 		evt_rsrc->vector_size = VECTOR_SIZE_DEFAULT;
817 		fprintf(stderr, "vector size set to default (%" PRIu16 ")\n",
818 			evt_rsrc->vector_size);
819 	}
820 
821 	if (evt_rsrc->vector_enabled && !evt_rsrc->vector_tmo_ns) {
822 		evt_rsrc->vector_tmo_ns = VECTOR_TMO_NS_DEFAULT;
823 		fprintf(stderr,
824 			"vector timeout set to default (%" PRIu64 " ns)\n",
825 			evt_rsrc->vector_tmo_ns);
826 	}
827 
828 	/*
829 	 * Nothing is selected, pick longest-prefix match
830 	 * as default match.
831 	 */
832 	if (lookup_mode == L3FWD_LOOKUP_DEFAULT) {
833 		fprintf(stderr, "Neither LPM, EM, or FIB selected, defaulting to LPM\n");
834 		lookup_mode = L3FWD_LOOKUP_LPM;
835 	}
836 
837 	/*
838 	 * ipv6 and hash flags are valid only for
839 	 * exact match, reset them to default for
840 	 * longest-prefix match.
841 	 */
842 	if (lookup_mode == L3FWD_LOOKUP_LPM) {
843 		ipv6 = 0;
844 		hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
845 	}
846 
847 	if (optind >= 0)
848 		argv[optind-1] = prgname;
849 
850 	ret = optind-1;
851 	optind = 1; /* reset getopt lib */
852 	return ret;
853 }
854 
855 static void
856 print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
857 {
858 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
859 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
860 	printf("%s%s", name, buf);
861 }
862 
863 int
864 init_mem(uint16_t portid, unsigned int nb_mbuf)
865 {
866 	struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
867 	struct lcore_conf *qconf;
868 	int socketid;
869 	unsigned lcore_id;
870 	char s[64];
871 
872 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
873 		if (rte_lcore_is_enabled(lcore_id) == 0)
874 			continue;
875 
876 		if (numa_on)
877 			socketid = rte_lcore_to_socket_id(lcore_id);
878 		else
879 			socketid = 0;
880 
881 		if (socketid >= NB_SOCKETS) {
882 			rte_exit(EXIT_FAILURE,
883 				"Socket %d of lcore %u is out of range %d\n",
884 				socketid, lcore_id, NB_SOCKETS);
885 		}
886 
887 		if (pktmbuf_pool[portid][socketid] == NULL) {
888 			snprintf(s, sizeof(s), "mbuf_pool_%d:%d",
889 				 portid, socketid);
890 			pktmbuf_pool[portid][socketid] =
891 				rte_pktmbuf_pool_create(s, nb_mbuf,
892 					MEMPOOL_CACHE_SIZE, 0,
893 					RTE_MBUF_DEFAULT_BUF_SIZE, socketid);
894 			if (pktmbuf_pool[portid][socketid] == NULL)
895 				rte_exit(EXIT_FAILURE,
896 					"Cannot init mbuf pool on socket %d\n",
897 					socketid);
898 			else
899 				printf("Allocated mbuf pool on socket %d\n",
900 					socketid);
901 
902 			/* Setup LPM, EM(f.e Hash) or FIB. But, only once per
903 			 * available socket.
904 			 */
905 			if (!lkp_per_socket[socketid]) {
906 				l3fwd_lkp.setup(socketid);
907 				lkp_per_socket[socketid] = 1;
908 			}
909 		}
910 
911 		if (evt_rsrc->vector_enabled && vector_pool[portid] == NULL) {
912 			unsigned int nb_vec;
913 
914 			nb_vec = (nb_mbuf + evt_rsrc->vector_size - 1) /
915 				 evt_rsrc->vector_size;
916 			snprintf(s, sizeof(s), "vector_pool_%d", portid);
917 			vector_pool[portid] = rte_event_vector_pool_create(
918 				s, nb_vec, 0, evt_rsrc->vector_size, socketid);
919 			if (vector_pool[portid] == NULL)
920 				rte_exit(EXIT_FAILURE,
921 					 "Failed to create vector pool for port %d\n",
922 					 portid);
923 			else
924 				printf("Allocated vector pool for port %d\n",
925 				       portid);
926 		}
927 
928 		qconf = &lcore_conf[lcore_id];
929 		qconf->ipv4_lookup_struct =
930 			l3fwd_lkp.get_ipv4_lookup_struct(socketid);
931 		qconf->ipv6_lookup_struct =
932 			l3fwd_lkp.get_ipv6_lookup_struct(socketid);
933 	}
934 	return 0;
935 }
936 
937 /* Check the link status of all ports in up to 9s, and print them finally */
938 static void
939 check_all_ports_link_status(uint32_t port_mask)
940 {
941 #define CHECK_INTERVAL 100 /* 100ms */
942 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
943 	uint16_t portid;
944 	uint8_t count, all_ports_up, print_flag = 0;
945 	struct rte_eth_link link;
946 	int ret;
947 	char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
948 
949 	printf("\nChecking link status");
950 	fflush(stdout);
951 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
952 		if (force_quit)
953 			return;
954 		all_ports_up = 1;
955 		RTE_ETH_FOREACH_DEV(portid) {
956 			if (force_quit)
957 				return;
958 			if ((port_mask & (1 << portid)) == 0)
959 				continue;
960 			memset(&link, 0, sizeof(link));
961 			ret = rte_eth_link_get_nowait(portid, &link);
962 			if (ret < 0) {
963 				all_ports_up = 0;
964 				if (print_flag == 1)
965 					printf("Port %u link get failed: %s\n",
966 						portid, rte_strerror(-ret));
967 				continue;
968 			}
969 			/* print link status if flag set */
970 			if (print_flag == 1) {
971 				rte_eth_link_to_str(link_status_text,
972 					sizeof(link_status_text), &link);
973 				printf("Port %d %s\n", portid,
974 				       link_status_text);
975 				continue;
976 			}
977 			/* clear all_ports_up flag if any link down */
978 			if (link.link_status == RTE_ETH_LINK_DOWN) {
979 				all_ports_up = 0;
980 				break;
981 			}
982 		}
983 		/* after finally printing all link status, get out */
984 		if (print_flag == 1)
985 			break;
986 
987 		if (all_ports_up == 0) {
988 			printf(".");
989 			fflush(stdout);
990 			rte_delay_ms(CHECK_INTERVAL);
991 		}
992 
993 		/* set the print_flag if all ports up or timeout */
994 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
995 			print_flag = 1;
996 			printf("done\n");
997 		}
998 	}
999 }
1000 
1001 static void
1002 signal_handler(int signum)
1003 {
1004 	if (signum == SIGINT || signum == SIGTERM) {
1005 		printf("\n\nSignal %d received, preparing to exit...\n",
1006 				signum);
1007 		force_quit = true;
1008 	}
1009 }
1010 
1011 static int
1012 prepare_ptype_parser(uint16_t portid, uint16_t queueid)
1013 {
1014 	if (parse_ptype) {
1015 		printf("Port %d: softly parse packet type info\n", portid);
1016 		if (rte_eth_add_rx_callback(portid, queueid,
1017 					    l3fwd_lkp.cb_parse_ptype,
1018 					    NULL))
1019 			return 1;
1020 
1021 		printf("Failed to add rx callback: port=%d\n", portid);
1022 		return 0;
1023 	}
1024 
1025 	if (l3fwd_lkp.check_ptype(portid))
1026 		return 1;
1027 
1028 	printf("port %d cannot parse packet type, please add --%s\n",
1029 	       portid, CMD_LINE_OPT_PARSE_PTYPE);
1030 	return 0;
1031 }
1032 
1033 static uint32_t
1034 eth_dev_get_overhead_len(uint32_t max_rx_pktlen, uint16_t max_mtu)
1035 {
1036 	uint32_t overhead_len;
1037 
1038 	if (max_mtu != UINT16_MAX && max_rx_pktlen > max_mtu)
1039 		overhead_len = max_rx_pktlen - max_mtu;
1040 	else
1041 		overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN;
1042 
1043 	return overhead_len;
1044 }
1045 
1046 static int
1047 config_port_max_pkt_len(struct rte_eth_conf *conf,
1048 		struct rte_eth_dev_info *dev_info)
1049 {
1050 	uint32_t overhead_len;
1051 
1052 	if (max_pkt_len == 0)
1053 		return 0;
1054 
1055 	if (max_pkt_len < RTE_ETHER_MIN_LEN || max_pkt_len > MAX_JUMBO_PKT_LEN)
1056 		return -1;
1057 
1058 	overhead_len = eth_dev_get_overhead_len(dev_info->max_rx_pktlen,
1059 			dev_info->max_mtu);
1060 	conf->rxmode.mtu = max_pkt_len - overhead_len;
1061 
1062 	if (conf->rxmode.mtu > RTE_ETHER_MTU)
1063 		conf->txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
1064 
1065 	return 0;
1066 }
1067 
1068 static void
1069 l3fwd_poll_resource_setup(void)
1070 {
1071 	uint8_t nb_rx_queue, queue, socketid;
1072 	struct rte_eth_dev_info dev_info;
1073 	uint32_t n_tx_queue, nb_lcores;
1074 	struct rte_eth_txconf *txconf;
1075 	struct lcore_conf *qconf;
1076 	uint16_t queueid, portid;
1077 	unsigned int nb_ports;
1078 	unsigned int lcore_id;
1079 	int ret;
1080 
1081 	if (check_lcore_params() < 0)
1082 		rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
1083 
1084 	ret = init_lcore_rx_queues();
1085 	if (ret < 0)
1086 		rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
1087 
1088 	nb_ports = rte_eth_dev_count_avail();
1089 
1090 	if (check_port_config() < 0)
1091 		rte_exit(EXIT_FAILURE, "check_port_config failed\n");
1092 
1093 	nb_lcores = rte_lcore_count();
1094 
1095 	/* initialize all ports */
1096 	RTE_ETH_FOREACH_DEV(portid) {
1097 		struct rte_eth_conf local_port_conf = port_conf;
1098 
1099 		/* skip ports that are not enabled */
1100 		if ((enabled_port_mask & (1 << portid)) == 0) {
1101 			printf("\nSkipping disabled port %d\n", portid);
1102 			continue;
1103 		}
1104 
1105 		/* init port */
1106 		printf("Initializing port %d ... ", portid );
1107 		fflush(stdout);
1108 
1109 		nb_rx_queue = get_port_n_rx_queues(portid);
1110 		n_tx_queue = nb_lcores;
1111 		if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
1112 			n_tx_queue = MAX_TX_QUEUE_PER_PORT;
1113 		printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
1114 			nb_rx_queue, (unsigned)n_tx_queue );
1115 
1116 		ret = rte_eth_dev_info_get(portid, &dev_info);
1117 		if (ret != 0)
1118 			rte_exit(EXIT_FAILURE,
1119 				"Error during getting device (port %u) info: %s\n",
1120 				portid, strerror(-ret));
1121 
1122 		ret = config_port_max_pkt_len(&local_port_conf, &dev_info);
1123 		if (ret != 0)
1124 			rte_exit(EXIT_FAILURE,
1125 				"Invalid max packet length: %u (port %u)\n",
1126 				max_pkt_len, portid);
1127 
1128 		if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
1129 			local_port_conf.txmode.offloads |=
1130 				RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
1131 
1132 		local_port_conf.rx_adv_conf.rss_conf.rss_hf &=
1133 			dev_info.flow_type_rss_offloads;
1134 
1135 		if (dev_info.max_rx_queues == 1)
1136 			local_port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_NONE;
1137 
1138 		if (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=
1139 				port_conf.rx_adv_conf.rss_conf.rss_hf) {
1140 			printf("Port %u modified RSS hash function based on hardware support,"
1141 				"requested:%#"PRIx64" configured:%#"PRIx64"\n",
1142 				portid,
1143 				port_conf.rx_adv_conf.rss_conf.rss_hf,
1144 				local_port_conf.rx_adv_conf.rss_conf.rss_hf);
1145 		}
1146 
1147 		ret = rte_eth_dev_configure(portid, nb_rx_queue,
1148 					(uint16_t)n_tx_queue, &local_port_conf);
1149 		if (ret < 0)
1150 			rte_exit(EXIT_FAILURE,
1151 				"Cannot configure device: err=%d, port=%d\n",
1152 				ret, portid);
1153 
1154 		ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
1155 						       &nb_txd);
1156 		if (ret < 0)
1157 			rte_exit(EXIT_FAILURE,
1158 				 "Cannot adjust number of descriptors: err=%d, "
1159 				 "port=%d\n", ret, portid);
1160 
1161 		ret = rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
1162 		if (ret < 0)
1163 			rte_exit(EXIT_FAILURE,
1164 				 "Cannot get MAC address: err=%d, port=%d\n",
1165 				 ret, portid);
1166 
1167 		print_ethaddr(" Address:", &ports_eth_addr[portid]);
1168 		printf(", ");
1169 		print_ethaddr("Destination:",
1170 			(const struct rte_ether_addr *)&dest_eth_addr[portid]);
1171 		printf(", ");
1172 
1173 		/*
1174 		 * prepare src MACs for each port.
1175 		 */
1176 		rte_ether_addr_copy(&ports_eth_addr[portid],
1177 			(struct rte_ether_addr *)(val_eth + portid) + 1);
1178 
1179 		/* init memory */
1180 		if (!per_port_pool) {
1181 			/* portid = 0; this is *not* signifying the first port,
1182 			 * rather, it signifies that portid is ignored.
1183 			 */
1184 			ret = init_mem(0, NB_MBUF(nb_ports));
1185 		} else {
1186 			ret = init_mem(portid, NB_MBUF(1));
1187 		}
1188 		if (ret < 0)
1189 			rte_exit(EXIT_FAILURE, "init_mem failed\n");
1190 
1191 		/* init one TX queue per couple (lcore,port) */
1192 		queueid = 0;
1193 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1194 			if (rte_lcore_is_enabled(lcore_id) == 0)
1195 				continue;
1196 
1197 			if (numa_on)
1198 				socketid =
1199 				(uint8_t)rte_lcore_to_socket_id(lcore_id);
1200 			else
1201 				socketid = 0;
1202 
1203 			printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
1204 			fflush(stdout);
1205 
1206 			txconf = &dev_info.default_txconf;
1207 			txconf->offloads = local_port_conf.txmode.offloads;
1208 			ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
1209 						     socketid, txconf);
1210 			if (ret < 0)
1211 				rte_exit(EXIT_FAILURE,
1212 					"rte_eth_tx_queue_setup: err=%d, "
1213 					"port=%d\n", ret, portid);
1214 
1215 			qconf = &lcore_conf[lcore_id];
1216 			qconf->tx_queue_id[portid] = queueid;
1217 			queueid++;
1218 
1219 			qconf->tx_port_id[qconf->n_tx_port] = portid;
1220 			qconf->n_tx_port++;
1221 		}
1222 		printf("\n");
1223 	}
1224 
1225 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1226 		if (rte_lcore_is_enabled(lcore_id) == 0)
1227 			continue;
1228 		qconf = &lcore_conf[lcore_id];
1229 		printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
1230 		fflush(stdout);
1231 		/* init RX queues */
1232 		for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
1233 			struct rte_eth_rxconf rxq_conf;
1234 
1235 			portid = qconf->rx_queue_list[queue].port_id;
1236 			queueid = qconf->rx_queue_list[queue].queue_id;
1237 
1238 			if (numa_on)
1239 				socketid =
1240 				(uint8_t)rte_lcore_to_socket_id(lcore_id);
1241 			else
1242 				socketid = 0;
1243 
1244 			printf("rxq=%d,%d,%d ", portid, queueid, socketid);
1245 			fflush(stdout);
1246 
1247 			ret = rte_eth_dev_info_get(portid, &dev_info);
1248 			if (ret != 0)
1249 				rte_exit(EXIT_FAILURE,
1250 					"Error during getting device (port %u) info: %s\n",
1251 					portid, strerror(-ret));
1252 
1253 			rxq_conf = dev_info.default_rxconf;
1254 			rxq_conf.offloads = port_conf.rxmode.offloads;
1255 			if (!per_port_pool)
1256 				ret = rte_eth_rx_queue_setup(portid, queueid,
1257 						nb_rxd, socketid,
1258 						&rxq_conf,
1259 						pktmbuf_pool[0][socketid]);
1260 			else
1261 				ret = rte_eth_rx_queue_setup(portid, queueid,
1262 						nb_rxd, socketid,
1263 						&rxq_conf,
1264 						pktmbuf_pool[portid][socketid]);
1265 			if (ret < 0)
1266 				rte_exit(EXIT_FAILURE,
1267 				"rte_eth_rx_queue_setup: err=%d, port=%d\n",
1268 				ret, portid);
1269 		}
1270 	}
1271 }
1272 
1273 static inline int
1274 l3fwd_service_enable(uint32_t service_id)
1275 {
1276 	uint8_t min_service_count = UINT8_MAX;
1277 	uint32_t slcore_array[RTE_MAX_LCORE];
1278 	unsigned int slcore = 0;
1279 	uint8_t service_count;
1280 	int32_t slcore_count;
1281 
1282 	if (!rte_service_lcore_count())
1283 		return -ENOENT;
1284 
1285 	slcore_count = rte_service_lcore_list(slcore_array, RTE_MAX_LCORE);
1286 	if (slcore_count < 0)
1287 		return -ENOENT;
1288 	/* Get the core which has least number of services running. */
1289 	while (slcore_count--) {
1290 		/* Reset default mapping */
1291 		if (rte_service_map_lcore_set(service_id,
1292 				slcore_array[slcore_count], 0) != 0)
1293 			return -ENOENT;
1294 		service_count = rte_service_lcore_count_services(
1295 				slcore_array[slcore_count]);
1296 		if (service_count < min_service_count) {
1297 			slcore = slcore_array[slcore_count];
1298 			min_service_count = service_count;
1299 		}
1300 	}
1301 	if (rte_service_map_lcore_set(service_id, slcore, 1))
1302 		return -ENOENT;
1303 	rte_service_lcore_start(slcore);
1304 
1305 	return 0;
1306 }
1307 
1308 static void
1309 l3fwd_event_service_setup(void)
1310 {
1311 	struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
1312 	struct rte_event_dev_info evdev_info;
1313 	uint32_t service_id, caps;
1314 	int ret, i;
1315 
1316 	rte_event_dev_info_get(evt_rsrc->event_d_id, &evdev_info);
1317 	if (!(evdev_info.event_dev_cap & RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED)) {
1318 		ret = rte_event_dev_service_id_get(evt_rsrc->event_d_id,
1319 				&service_id);
1320 		if (ret != -ESRCH && ret != 0)
1321 			rte_exit(EXIT_FAILURE,
1322 				 "Error in starting eventdev service\n");
1323 		l3fwd_service_enable(service_id);
1324 	}
1325 
1326 	for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {
1327 		ret = rte_event_eth_rx_adapter_caps_get(evt_rsrc->event_d_id,
1328 				evt_rsrc->rx_adptr.rx_adptr[i], &caps);
1329 		if (ret < 0)
1330 			rte_exit(EXIT_FAILURE,
1331 				 "Failed to get Rx adapter[%d] caps\n",
1332 				 evt_rsrc->rx_adptr.rx_adptr[i]);
1333 		ret = rte_event_eth_rx_adapter_service_id_get(
1334 				evt_rsrc->event_d_id,
1335 				&service_id);
1336 		if (ret != -ESRCH && ret != 0)
1337 			rte_exit(EXIT_FAILURE,
1338 				 "Error in starting Rx adapter[%d] service\n",
1339 				 evt_rsrc->rx_adptr.rx_adptr[i]);
1340 		l3fwd_service_enable(service_id);
1341 	}
1342 
1343 	for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) {
1344 		ret = rte_event_eth_tx_adapter_caps_get(evt_rsrc->event_d_id,
1345 				evt_rsrc->tx_adptr.tx_adptr[i], &caps);
1346 		if (ret < 0)
1347 			rte_exit(EXIT_FAILURE,
1348 				 "Failed to get Rx adapter[%d] caps\n",
1349 				 evt_rsrc->tx_adptr.tx_adptr[i]);
1350 		ret = rte_event_eth_tx_adapter_service_id_get(
1351 				evt_rsrc->event_d_id,
1352 				&service_id);
1353 		if (ret != -ESRCH && ret != 0)
1354 			rte_exit(EXIT_FAILURE,
1355 				 "Error in starting Rx adapter[%d] service\n",
1356 				 evt_rsrc->tx_adptr.tx_adptr[i]);
1357 		l3fwd_service_enable(service_id);
1358 	}
1359 }
1360 
1361 int
1362 main(int argc, char **argv)
1363 {
1364 	struct l3fwd_event_resources *evt_rsrc;
1365 	struct lcore_conf *qconf;
1366 	uint16_t queueid, portid;
1367 	unsigned int lcore_id;
1368 	uint8_t queue;
1369 	int i, ret;
1370 
1371 	/* init EAL */
1372 	ret = rte_eal_init(argc, argv);
1373 	if (ret < 0)
1374 		rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
1375 	argc -= ret;
1376 	argv += ret;
1377 
1378 	force_quit = false;
1379 	signal(SIGINT, signal_handler);
1380 	signal(SIGTERM, signal_handler);
1381 
1382 	/* pre-init dst MACs for all ports to 02:00:00:00:00:xx */
1383 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
1384 		dest_eth_addr[portid] =
1385 			RTE_ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40);
1386 		*(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
1387 	}
1388 
1389 	evt_rsrc = l3fwd_get_eventdev_rsrc();
1390 	/* parse application arguments (after the EAL ones) */
1391 	ret = parse_args(argc, argv);
1392 	if (ret < 0)
1393 		rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
1394 
1395 	/* Setup function pointers for lookup method. */
1396 	setup_l3fwd_lookup_tables();
1397 
1398 	evt_rsrc->per_port_pool = per_port_pool;
1399 	evt_rsrc->pkt_pool = pktmbuf_pool;
1400 	evt_rsrc->vec_pool = vector_pool;
1401 	evt_rsrc->port_mask = enabled_port_mask;
1402 	/* Configure eventdev parameters if user has requested */
1403 	if (evt_rsrc->enabled) {
1404 		l3fwd_event_resource_setup(&port_conf);
1405 		if (lookup_mode == L3FWD_LOOKUP_EM)
1406 			l3fwd_lkp.main_loop = evt_rsrc->ops.em_event_loop;
1407 		else if (lookup_mode == L3FWD_LOOKUP_FIB)
1408 			l3fwd_lkp.main_loop = evt_rsrc->ops.fib_event_loop;
1409 		else
1410 			l3fwd_lkp.main_loop = evt_rsrc->ops.lpm_event_loop;
1411 		l3fwd_event_service_setup();
1412 	} else
1413 		l3fwd_poll_resource_setup();
1414 
1415 	/* start ports */
1416 	RTE_ETH_FOREACH_DEV(portid) {
1417 		if ((enabled_port_mask & (1 << portid)) == 0) {
1418 			continue;
1419 		}
1420 		/* Start device */
1421 		ret = rte_eth_dev_start(portid);
1422 		if (ret < 0)
1423 			rte_exit(EXIT_FAILURE,
1424 				"rte_eth_dev_start: err=%d, port=%d\n",
1425 				ret, portid);
1426 
1427 		/*
1428 		 * If enabled, put device in promiscuous mode.
1429 		 * This allows IO forwarding mode to forward packets
1430 		 * to itself through 2 cross-connected  ports of the
1431 		 * target machine.
1432 		 */
1433 		if (promiscuous_on) {
1434 			ret = rte_eth_promiscuous_enable(portid);
1435 			if (ret != 0)
1436 				rte_exit(EXIT_FAILURE,
1437 					"rte_eth_promiscuous_enable: err=%s, port=%u\n",
1438 					rte_strerror(-ret), portid);
1439 		}
1440 	}
1441 
1442 	printf("\n");
1443 
1444 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1445 		if (rte_lcore_is_enabled(lcore_id) == 0)
1446 			continue;
1447 		qconf = &lcore_conf[lcore_id];
1448 		for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
1449 			portid = qconf->rx_queue_list[queue].port_id;
1450 			queueid = qconf->rx_queue_list[queue].queue_id;
1451 			if (prepare_ptype_parser(portid, queueid) == 0)
1452 				rte_exit(EXIT_FAILURE, "ptype check fails\n");
1453 		}
1454 	}
1455 
1456 	check_all_ports_link_status(enabled_port_mask);
1457 
1458 	ret = 0;
1459 	/* launch per-lcore init on every lcore */
1460 	rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MAIN);
1461 	if (evt_rsrc->enabled) {
1462 		for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++)
1463 			rte_event_eth_rx_adapter_stop(
1464 					evt_rsrc->rx_adptr.rx_adptr[i]);
1465 		for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++)
1466 			rte_event_eth_tx_adapter_stop(
1467 					evt_rsrc->tx_adptr.tx_adptr[i]);
1468 
1469 		RTE_ETH_FOREACH_DEV(portid) {
1470 			if ((enabled_port_mask & (1 << portid)) == 0)
1471 				continue;
1472 			ret = rte_eth_dev_stop(portid);
1473 			if (ret != 0)
1474 				printf("rte_eth_dev_stop: err=%d, port=%u\n",
1475 				       ret, portid);
1476 		}
1477 
1478 		rte_eal_mp_wait_lcore();
1479 		RTE_ETH_FOREACH_DEV(portid) {
1480 			if ((enabled_port_mask & (1 << portid)) == 0)
1481 				continue;
1482 			rte_eth_dev_close(portid);
1483 		}
1484 
1485 		rte_event_dev_stop(evt_rsrc->event_d_id);
1486 		rte_event_dev_close(evt_rsrc->event_d_id);
1487 
1488 	} else {
1489 		rte_eal_mp_wait_lcore();
1490 
1491 		RTE_ETH_FOREACH_DEV(portid) {
1492 			if ((enabled_port_mask & (1 << portid)) == 0)
1493 				continue;
1494 			printf("Closing port %d...", portid);
1495 			ret = rte_eth_dev_stop(portid);
1496 			if (ret != 0)
1497 				printf("rte_eth_dev_stop: err=%d, port=%u\n",
1498 				       ret, portid);
1499 			rte_eth_dev_close(portid);
1500 			printf(" Done\n");
1501 		}
1502 	}
1503 
1504 	/* clean up the EAL */
1505 	rte_eal_cleanup();
1506 
1507 	printf("Bye...\n");
1508 
1509 	return ret;
1510 }
1511