xref: /dpdk/examples/l2fwd-event/main.c (revision 4ed890495594a71e618d62fd975c5868915eb4a1)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2019 Marvell International Ltd.
3  */
4 
5 #include <rte_string_fns.h>
6 
7 #include "l2fwd_event.h"
8 #include "l2fwd_poll.h"
9 
10 /* display usage */
11 static void
l2fwd_event_usage(const char * prgname)12 l2fwd_event_usage(const char *prgname)
13 {
14 	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
15 	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
16 	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
17 	       "  -T PERIOD: statistics will be refreshed each PERIOD seconds "
18 	       "		(0 to disable, 10 default, 86400 maximum)\n"
19 	       "  --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
20 	       "      When enabled:\n"
21 	       "       - The source MAC address is replaced by the TX port MAC address\n"
22 	       "       - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n"
23 	       "  --mode: Packet transfer mode for I/O, poll or eventdev\n"
24 	       "          Default mode = eventdev\n"
25 	       "  --eventq-sched: Event queue schedule type, ordered, atomic or parallel.\n"
26 	       "                  Default: atomic\n"
27 	       "                  Valid only if --mode=eventdev\n"
28 	       "  --event-vector:  Enable event vectorization.\n"
29 	       "  --event-vector-size: Max vector size if event vectorization is enabled.\n"
30 	       "  --event-vector-tmo: Max timeout to form vector in nanoseconds if event vectorization is enabled\n"
31 	       "  --config: Configure forwarding port pair mapping\n"
32 	       "	    Default: alternate port pairs\n\n",
33 	       prgname);
34 }
35 
36 static int
l2fwd_event_parse_portmask(const char * portmask)37 l2fwd_event_parse_portmask(const char *portmask)
38 {
39 	char *end = NULL;
40 	unsigned long pm;
41 
42 	/* parse hexadecimal string */
43 	pm = strtoul(portmask, &end, 16);
44 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
45 		return 0;
46 
47 	return pm;
48 }
49 
50 static unsigned int
l2fwd_event_parse_nqueue(const char * q_arg)51 l2fwd_event_parse_nqueue(const char *q_arg)
52 {
53 	char *end = NULL;
54 	unsigned long n;
55 
56 	/* parse hexadecimal string */
57 	n = strtoul(q_arg, &end, 10);
58 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
59 		return 0;
60 	if (n == 0)
61 		return 0;
62 	if (n >= MAX_RX_QUEUE_PER_LCORE)
63 		return 0;
64 
65 	return n;
66 }
67 
68 static int
l2fwd_event_parse_timer_period(const char * q_arg)69 l2fwd_event_parse_timer_period(const char *q_arg)
70 {
71 	char *end = NULL;
72 	int n;
73 
74 	/* parse number string */
75 	n = strtol(q_arg, &end, 10);
76 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
77 		return -1;
78 	if (n >= MAX_TIMER_PERIOD)
79 		return -1;
80 
81 	return n;
82 }
83 
84 static void
l2fwd_event_parse_mode(const char * optarg,struct l2fwd_resources * rsrc)85 l2fwd_event_parse_mode(const char *optarg,
86 		       struct l2fwd_resources *rsrc)
87 {
88 	if (!strncmp(optarg, "poll", 4))
89 		rsrc->event_mode = false;
90 	else if (!strncmp(optarg, "eventdev", 8))
91 		rsrc->event_mode = true;
92 }
93 
94 static void
l2fwd_event_parse_eventq_sched(const char * optarg,struct l2fwd_resources * rsrc)95 l2fwd_event_parse_eventq_sched(const char *optarg,
96 			       struct l2fwd_resources *rsrc)
97 {
98 	if (!strncmp(optarg, "ordered", 7))
99 		rsrc->sched_type = RTE_SCHED_TYPE_ORDERED;
100 	else if (!strncmp(optarg, "atomic", 6))
101 		rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC;
102 	else if (!strncmp(optarg, "parallel", 8))
103 		rsrc->sched_type = RTE_SCHED_TYPE_PARALLEL;
104 }
105 
106 static int
l2fwd_parse_port_pair_config(const char * q_arg,struct l2fwd_resources * rsrc)107 l2fwd_parse_port_pair_config(const char *q_arg, struct l2fwd_resources *rsrc)
108 {
109 	enum fieldnames {
110 		FLD_PORT1 = 0,
111 		FLD_PORT2,
112 		_NUM_FLD
113 	};
114 	const char *p, *p0 = q_arg;
115 	uint16_t int_fld[_NUM_FLD];
116 	char *str_fld[_NUM_FLD];
117 	uint16_t port_pair = 0;
118 	unsigned int size;
119 	char s[256];
120 	char *end;
121 	int i;
122 
123 	while ((p = strchr(p0, '(')) != NULL) {
124 		++p;
125 		p0 = strchr(p, ')');
126 		if (p0 == NULL)
127 			return -1;
128 
129 		size = p0 - p;
130 		if (size >= sizeof(s))
131 			return -1;
132 
133 		memcpy(s, p, size);
134 		if (rte_strsplit(s, sizeof(s), str_fld,
135 					_NUM_FLD, ',') != _NUM_FLD)
136 			return -1;
137 
138 		for (i = 0; i < _NUM_FLD; i++) {
139 			errno = 0;
140 			int_fld[i] = strtoul(str_fld[i], &end, 0);
141 			if (errno != 0 || end == str_fld[i] ||
142 			    int_fld[i] >= RTE_MAX_ETHPORTS)
143 				return -1;
144 		}
145 
146 		if (port_pair >= RTE_MAX_ETHPORTS / 2) {
147 			printf("exceeded max number of port pair params: Current %d Max = %d\n",
148 			       port_pair, RTE_MAX_ETHPORTS / 2);
149 			return -1;
150 		}
151 
152 		if ((rsrc->dst_ports[int_fld[FLD_PORT1]] != UINT32_MAX) ||
153 			(rsrc->dst_ports[int_fld[FLD_PORT2]] != UINT32_MAX)) {
154 			printf("Duplicate port pair (%d,%d) config\n",
155 					int_fld[FLD_PORT1], int_fld[FLD_PORT2]);
156 			return -1;
157 		}
158 
159 		rsrc->dst_ports[int_fld[FLD_PORT1]] = int_fld[FLD_PORT2];
160 		rsrc->dst_ports[int_fld[FLD_PORT2]] = int_fld[FLD_PORT1];
161 
162 		port_pair++;
163 	}
164 
165 	rsrc->port_pairs = true;
166 
167 	return 0;
168 }
169 
170 static const char short_options[] =
171 	"p:"  /* portmask */
172 	"q:"  /* number of queues */
173 	"T:"  /* timer period */
174 	;
175 
176 #define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
177 #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
178 #define CMD_LINE_OPT_MODE "mode"
179 #define CMD_LINE_OPT_EVENTQ_SCHED "eventq-sched"
180 #define CMD_LINE_OPT_PORT_PAIR_CONF "config"
181 #define CMD_LINE_OPT_ENABLE_VECTOR "event-vector"
182 #define CMD_LINE_OPT_VECTOR_SIZE "event-vector-size"
183 #define CMD_LINE_OPT_VECTOR_TMO_NS "event-vector-tmo"
184 
185 enum {
186 	/* long options mapped to a short option */
187 
188 	/* first long only option value must be >= 256, so that we won't
189 	 * conflict with short options
190 	 */
191 	CMD_LINE_OPT_MIN_NUM = 256,
192 	CMD_LINE_OPT_MODE_NUM,
193 	CMD_LINE_OPT_EVENTQ_SCHED_NUM,
194 	CMD_LINE_OPT_PORT_PAIR_CONF_NUM,
195 	CMD_LINE_OPT_ENABLE_VECTOR_NUM,
196 	CMD_LINE_OPT_VECTOR_SIZE_NUM,
197 	CMD_LINE_OPT_VECTOR_TMO_NS_NUM
198 };
199 
200 /* Parse the argument given in the command line of the application */
201 static int
l2fwd_event_parse_args(int argc,char ** argv,struct l2fwd_resources * rsrc)202 l2fwd_event_parse_args(int argc, char **argv, struct l2fwd_resources *rsrc)
203 {
204 	int mac_updating = 1;
205 	struct option lgopts[] = {
206 		{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
207 		{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
208 		{ CMD_LINE_OPT_MODE, required_argument, NULL,
209 							CMD_LINE_OPT_MODE_NUM},
210 		{ CMD_LINE_OPT_EVENTQ_SCHED, required_argument, NULL,
211 						CMD_LINE_OPT_EVENTQ_SCHED_NUM},
212 		{ CMD_LINE_OPT_PORT_PAIR_CONF, required_argument, NULL,
213 					CMD_LINE_OPT_PORT_PAIR_CONF_NUM},
214 		{CMD_LINE_OPT_ENABLE_VECTOR, no_argument, NULL,
215 					CMD_LINE_OPT_ENABLE_VECTOR_NUM},
216 		{CMD_LINE_OPT_VECTOR_SIZE, required_argument, NULL,
217 					CMD_LINE_OPT_VECTOR_SIZE_NUM},
218 		{CMD_LINE_OPT_VECTOR_TMO_NS, required_argument, NULL,
219 					CMD_LINE_OPT_VECTOR_TMO_NS_NUM},
220 		{NULL, 0, 0, 0}
221 	};
222 	int opt, ret, timer_secs;
223 	char *prgname = argv[0];
224 	uint16_t port_id;
225 	int option_index;
226 	char **argvopt;
227 
228 	/* Reset l2fwd_dst_ports. 8< */
229 	for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++)
230 		rsrc->dst_ports[port_id] = UINT32_MAX;
231 
232 	argvopt = argv;
233 	while ((opt = getopt_long(argc, argvopt, short_options,
234 				  lgopts, &option_index)) != EOF) {
235 
236 		switch (opt) {
237 		/* portmask */
238 		case 'p':
239 			rsrc->enabled_port_mask =
240 					l2fwd_event_parse_portmask(optarg);
241 			if (rsrc->enabled_port_mask == 0) {
242 				printf("invalid portmask\n");
243 				l2fwd_event_usage(prgname);
244 				return -1;
245 			}
246 			break;
247 
248 		/* nqueue */
249 		case 'q':
250 			rsrc->rx_queue_per_lcore =
251 					l2fwd_event_parse_nqueue(optarg);
252 			if (rsrc->rx_queue_per_lcore == 0) {
253 				printf("invalid queue number\n");
254 				l2fwd_event_usage(prgname);
255 				return -1;
256 			}
257 			break;
258 
259 		/* timer period */
260 		case 'T':
261 			timer_secs = l2fwd_event_parse_timer_period(optarg);
262 			if (timer_secs < 0) {
263 				printf("invalid timer period\n");
264 				l2fwd_event_usage(prgname);
265 				return -1;
266 			}
267 			rsrc->timer_period = timer_secs;
268 			/* convert to number of cycles */
269 			rsrc->timer_period *= rte_get_timer_hz();
270 			break;
271 
272 		case CMD_LINE_OPT_MODE_NUM:
273 			l2fwd_event_parse_mode(optarg, rsrc);
274 			break;
275 
276 		case CMD_LINE_OPT_EVENTQ_SCHED_NUM:
277 			l2fwd_event_parse_eventq_sched(optarg, rsrc);
278 			break;
279 
280 		case CMD_LINE_OPT_PORT_PAIR_CONF_NUM:
281 			ret = l2fwd_parse_port_pair_config(optarg, rsrc);
282 			if (ret) {
283 				printf("Invalid port pair config\n");
284 				l2fwd_event_usage(prgname);
285 				return -1;
286 			}
287 			break;
288 		case CMD_LINE_OPT_ENABLE_VECTOR_NUM:
289 			printf("event vectorization is enabled\n");
290 			rsrc->evt_vec.enabled = 1;
291 			break;
292 		case CMD_LINE_OPT_VECTOR_SIZE_NUM:
293 			rsrc->evt_vec.size = strtol(optarg, NULL, 10);
294 			break;
295 		case CMD_LINE_OPT_VECTOR_TMO_NS_NUM:
296 			rsrc->evt_vec.timeout_ns = strtoull(optarg, NULL, 10);
297 			break;
298 
299 		/* long options */
300 		case 0:
301 			break;
302 
303 		default:
304 			l2fwd_event_usage(prgname);
305 			return -1;
306 		}
307 	}
308 
309 	rsrc->mac_updating = mac_updating;
310 
311 	if (rsrc->evt_vec.enabled && !rsrc->evt_vec.size) {
312 		rsrc->evt_vec.size = VECTOR_SIZE_DEFAULT;
313 		printf("vector size set to default (%" PRIu16 ")\n",
314 		       rsrc->evt_vec.size);
315 	}
316 
317 	if (rsrc->evt_vec.enabled && !rsrc->evt_vec.timeout_ns) {
318 		rsrc->evt_vec.timeout_ns = VECTOR_TMO_NS_DEFAULT;
319 		printf("vector timeout set to default (%" PRIu64 " ns)\n",
320 		       rsrc->evt_vec.timeout_ns);
321 	}
322 
323 	if (optind >= 0)
324 		argv[optind-1] = prgname;
325 
326 	ret = optind-1;
327 	optind = 1; /* reset getopt lib */
328 	return ret;
329 	/* >8 End of reset l2fwd_dst_ports. */
330 }
331 
332 /*
333  * Check port pair config with enabled port mask,
334  * and for valid port pair combinations.
335  */
336 static int
check_port_pair_config(struct l2fwd_resources * rsrc)337 check_port_pair_config(struct l2fwd_resources *rsrc)
338 {
339 	uint32_t port_pair_mask = 0;
340 	uint32_t portid;
341 	uint16_t index;
342 
343 	for (index = 0; index < rte_eth_dev_count_avail(); index++) {
344 		if ((rsrc->enabled_port_mask & (1 << index)) == 0 ||
345 		    (port_pair_mask & (1 << index)))
346 			continue;
347 
348 		portid = rsrc->dst_ports[index];
349 		if (portid == UINT32_MAX) {
350 			printf("port %u is enabled in but no valid port pair\n",
351 			       index);
352 			return -1;
353 		}
354 
355 		if (!rte_eth_dev_is_valid_port(index)) {
356 			printf("port %u is not valid\n", index);
357 			return -1;
358 		}
359 
360 		if (!rte_eth_dev_is_valid_port(portid)) {
361 			printf("port %u is not valid\n", portid);
362 			return -1;
363 		}
364 
365 		if (port_pair_mask & (1 << portid) &&
366 				rsrc->dst_ports[portid] != index) {
367 			printf("port %u is used in other port pairs\n", portid);
368 			return -1;
369 		}
370 
371 		port_pair_mask |= (1 << portid);
372 		port_pair_mask |= (1 << index);
373 	}
374 
375 	return 0;
376 }
377 
378 static int
l2fwd_launch_one_lcore(void * args)379 l2fwd_launch_one_lcore(void *args)
380 {
381 	struct l2fwd_resources *rsrc = args;
382 	struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc;
383 	struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
384 
385 	if (rsrc->event_mode)
386 		evt_rsrc->ops.l2fwd_event_loop(rsrc);
387 	else
388 		poll_rsrc->poll_main_loop(rsrc);
389 
390 	return 0;
391 }
392 
393 /* Check the link status of all ports in up to 9s, and print them finally */
394 static void
check_all_ports_link_status(struct l2fwd_resources * rsrc,uint32_t port_mask)395 check_all_ports_link_status(struct l2fwd_resources *rsrc,
396 			    uint32_t port_mask)
397 {
398 #define CHECK_INTERVAL 100 /* 100ms */
399 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
400 	uint16_t port_id;
401 	uint8_t count, all_ports_up, print_flag = 0;
402 	struct rte_eth_link link;
403 	int ret;
404 	char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
405 
406 	printf("\nChecking link status...");
407 	fflush(stdout);
408 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
409 		if (rsrc->force_quit)
410 			return;
411 		all_ports_up = 1;
412 		RTE_ETH_FOREACH_DEV(port_id) {
413 			if (rsrc->force_quit)
414 				return;
415 			if ((port_mask & (1 << port_id)) == 0)
416 				continue;
417 			memset(&link, 0, sizeof(link));
418 			ret = rte_eth_link_get_nowait(port_id, &link);
419 			if (ret < 0) {
420 				all_ports_up = 0;
421 				if (print_flag == 1)
422 					printf("Port %u link get failed: %s\n",
423 						port_id, rte_strerror(-ret));
424 				continue;
425 			}
426 			/* print link status if flag set */
427 			if (print_flag == 1) {
428 				rte_eth_link_to_str(link_status_text,
429 					sizeof(link_status_text), &link);
430 				printf("Port %d %s\n", port_id,
431 				       link_status_text);
432 				continue;
433 			}
434 			/* clear all_ports_up flag if any link down */
435 			if (link.link_status == RTE_ETH_LINK_DOWN) {
436 				all_ports_up = 0;
437 				break;
438 			}
439 		}
440 		/* after finally printing all link status, get out */
441 		if (print_flag == 1)
442 			break;
443 
444 		if (all_ports_up == 0) {
445 			printf(".");
446 			fflush(stdout);
447 			rte_delay_ms(CHECK_INTERVAL);
448 		}
449 
450 		/* set the print_flag if all ports up or timeout */
451 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
452 			print_flag = 1;
453 			printf("done\n");
454 		}
455 	}
456 }
457 
458 /* Print out statistics on packets dropped */
459 static void
print_stats(struct l2fwd_resources * rsrc)460 print_stats(struct l2fwd_resources *rsrc)
461 {
462 	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
463 	uint32_t port_id;
464 
465 	total_packets_dropped = 0;
466 	total_packets_tx = 0;
467 	total_packets_rx = 0;
468 
469 	const char clr[] = {27, '[', '2', 'J', '\0' };
470 	const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' };
471 
472 		/* Clear screen and move to top left */
473 	printf("%s%s", clr, topLeft);
474 
475 	printf("\nPort statistics ====================================");
476 
477 	for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
478 		/* skip disabled ports */
479 		if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
480 			continue;
481 		printf("\nStatistics for port %u ------------------------------"
482 			   "\nPackets sent: %29"PRIu64
483 			   "\nPackets received: %25"PRIu64
484 			   "\nPackets dropped: %26"PRIu64,
485 			   port_id,
486 			   rsrc->port_stats[port_id].tx,
487 			   rsrc->port_stats[port_id].rx,
488 			   rsrc->port_stats[port_id].dropped);
489 
490 		total_packets_dropped +=
491 					rsrc->port_stats[port_id].dropped;
492 		total_packets_tx += rsrc->port_stats[port_id].tx;
493 		total_packets_rx += rsrc->port_stats[port_id].rx;
494 	}
495 
496 	if (rsrc->event_mode) {
497 		struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
498 		struct rte_event_eth_rx_adapter_stats rx_adptr_stats;
499 		struct rte_event_eth_tx_adapter_stats tx_adptr_stats;
500 		int ret, i;
501 
502 		for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {
503 			ret = rte_event_eth_rx_adapter_stats_get(
504 					evt_rsrc->rx_adptr.rx_adptr[i],
505 					&rx_adptr_stats);
506 			if (ret < 0)
507 				continue;
508 			printf("\nRx adapter[%d] statistics===================="
509 				   "\nReceive queue poll count: %17"PRIu64
510 				   "\nReceived packet count: %20"PRIu64
511 				   "\nEventdev enqueue count: %19"PRIu64
512 				   "\nEventdev enqueue retry count: %13"PRIu64
513 				   "\nReceived packet dropped count: %12"PRIu64
514 				   "\nRx enqueue start timestamp: %15"PRIu64
515 				   "\nRx enqueue block cycles: %18"PRIu64
516 				   "\nRx enqueue unblock timestamp: %13"PRIu64,
517 				   evt_rsrc->rx_adptr.rx_adptr[i],
518 				   rx_adptr_stats.rx_poll_count,
519 				   rx_adptr_stats.rx_packets,
520 				   rx_adptr_stats.rx_enq_count,
521 				   rx_adptr_stats.rx_enq_retry,
522 				   rx_adptr_stats.rx_dropped,
523 				   rx_adptr_stats.rx_enq_start_ts,
524 				   rx_adptr_stats.rx_enq_block_cycles,
525 				   rx_adptr_stats.rx_enq_end_ts);
526 		}
527 		for (i = 0; i <  evt_rsrc->tx_adptr.nb_tx_adptr; i++) {
528 			ret = rte_event_eth_tx_adapter_stats_get(
529 					evt_rsrc->tx_adptr.tx_adptr[i],
530 					&tx_adptr_stats);
531 			if (ret < 0)
532 				continue;
533 			printf("\nTx adapter[%d] statistics===================="
534 				   "\nNumber of transmit retries: %15"PRIu64
535 				   "\nNumber of packets transmitted: %12"PRIu64
536 				   "\nNumber of packets dropped: %16"PRIu64,
537 				   evt_rsrc->tx_adptr.tx_adptr[i],
538 				   tx_adptr_stats.tx_retry,
539 				   tx_adptr_stats.tx_packets,
540 				   tx_adptr_stats.tx_dropped);
541 		}
542 	}
543 	printf("\nAggregate lcore statistics ========================="
544 		   "\nTotal packets sent: %23"PRIu64
545 		   "\nTotal packets received: %19"PRIu64
546 		   "\nTotal packets dropped: %20"PRIu64,
547 		   total_packets_tx,
548 		   total_packets_rx,
549 		   total_packets_dropped);
550 	printf("\n====================================================\n");
551 
552 	fflush(stdout);
553 }
554 
555 static void
l2fwd_event_print_stats(struct l2fwd_resources * rsrc)556 l2fwd_event_print_stats(struct l2fwd_resources *rsrc)
557 {
558 	uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
559 	const uint64_t timer_period = rsrc->timer_period;
560 
561 	while (!rsrc->force_quit) {
562 		/* if timer is enabled */
563 		if (timer_period > 0) {
564 			cur_tsc = rte_rdtsc();
565 			diff_tsc = cur_tsc - prev_tsc;
566 
567 			/* advance the timer */
568 			timer_tsc += diff_tsc;
569 
570 			/* if timer has reached its timeout */
571 			if (unlikely(timer_tsc >= timer_period)) {
572 				print_stats(rsrc);
573 				/* reset the timer */
574 				timer_tsc = 0;
575 			}
576 			prev_tsc = cur_tsc;
577 		}
578 	}
579 }
580 
581 
582 static void
signal_handler(int signum)583 signal_handler(int signum)
584 {
585 	struct l2fwd_resources *rsrc = l2fwd_get_rsrc();
586 	if (signum == SIGINT || signum == SIGTERM) {
587 		printf("\n\nSignal %d received, preparing to exit...\n",
588 				signum);
589 		rsrc->force_quit = true;
590 	}
591 }
592 
593 int
main(int argc,char ** argv)594 main(int argc, char **argv)
595 {
596 	struct l2fwd_resources *rsrc;
597 	uint16_t nb_ports_available = 0;
598 	uint32_t nb_ports_in_mask = 0;
599 	uint16_t port_id, last_port;
600 	uint32_t nb_mbufs;
601 	uint16_t nb_ports;
602 	int i, ret;
603 
604 	/* Init EAL. 8< */
605 	ret = rte_eal_init(argc, argv);
606 	if (ret < 0)
607 		rte_panic("Invalid EAL arguments\n");
608 	argc -= ret;
609 	argv += ret;
610 
611 	rsrc = l2fwd_get_rsrc();
612 
613 	signal(SIGINT, signal_handler);
614 	signal(SIGTERM, signal_handler);
615 
616 	/* parse application arguments (after the EAL ones) */
617 	ret = l2fwd_event_parse_args(argc, argv, rsrc);
618 	if (ret < 0)
619 		rte_panic("Invalid L2FWD arguments\n");
620 	/* >8 End of init EAL. */
621 
622 	printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" :
623 			"disabled");
624 
625 	nb_ports = rte_eth_dev_count_avail();
626 	if (nb_ports == 0)
627 		rte_panic("No Ethernet ports - bye\n");
628 
629 	/* check port mask to possible port mask */
630 	if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1))
631 		rte_panic("Invalid portmask; possible (0x%x)\n",
632 			(1 << nb_ports) - 1);
633 
634 	if (!rsrc->port_pairs) {
635 		last_port = 0;
636 		/*
637 		 * Each logical core is assigned a dedicated TX queue on each
638 		 * port.
639 		 */
640 		RTE_ETH_FOREACH_DEV(port_id) {
641 			/* skip ports that are not enabled */
642 			if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
643 				continue;
644 
645 			if (nb_ports_in_mask % 2) {
646 				rsrc->dst_ports[port_id] = last_port;
647 				rsrc->dst_ports[last_port] = port_id;
648 			} else {
649 				last_port = port_id;
650 			}
651 
652 			nb_ports_in_mask++;
653 		}
654 		if (nb_ports_in_mask % 2) {
655 			printf("Notice: odd number of ports in portmask.\n");
656 			rsrc->dst_ports[last_port] = last_port;
657 		}
658 	} else {
659 		if (check_port_pair_config(rsrc) < 0)
660 			rte_panic("Invalid port pair config\n");
661 	}
662 
663 	nb_mbufs = RTE_MAX(nb_ports * (RX_DESC_DEFAULT +
664 				       TX_DESC_DEFAULT +
665 				       MAX_PKT_BURST + rte_lcore_count() *
666 				       MEMPOOL_CACHE_SIZE), 8192U);
667 
668 	/* Create the mbuf pool. 8< */
669 	rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
670 			nb_mbufs, MEMPOOL_CACHE_SIZE, 0,
671 			RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
672 	if (rsrc->pktmbuf_pool == NULL)
673 		rte_panic("Cannot init mbuf pool\n");
674 	/* >8 End of creation of mbuf pool. */
675 
676 	if (rsrc->evt_vec.enabled) {
677 		unsigned int nb_vec, vec_size;
678 
679 		vec_size = rsrc->evt_vec.size;
680 		nb_vec = (nb_mbufs + vec_size - 1) / vec_size;
681 		nb_vec = RTE_MAX(512U, nb_vec);
682 		nb_vec += rte_lcore_count() * 32;
683 		rsrc->evt_vec_pool = rte_event_vector_pool_create(
684 			"vector_pool", nb_vec, 32, vec_size, rte_socket_id());
685 		if (rsrc->evt_vec_pool == NULL)
686 			rte_panic("Cannot init event vector pool\n");
687 	}
688 
689 	nb_ports_available = l2fwd_event_init_ports(rsrc);
690 	if (!nb_ports_available)
691 		rte_panic("All available ports are disabled. Please set portmask.\n");
692 
693 	/* Configure eventdev parameters if required */
694 	if (rsrc->event_mode)
695 		l2fwd_event_resource_setup(rsrc);
696 	else
697 		l2fwd_poll_resource_setup(rsrc);
698 
699 	/* initialize port stats */
700 	memset(&rsrc->port_stats, 0,
701 					sizeof(struct l2fwd_port_statistics));
702 
703 	/* All settings are done. Now enable eth devices */
704 	RTE_ETH_FOREACH_DEV(port_id) {
705 		/* skip ports that are not enabled */
706 		if ((rsrc->enabled_port_mask &
707 					(1 << port_id)) == 0)
708 			continue;
709 
710 		ret = rte_eth_dev_start(port_id);
711 		if (ret < 0)
712 			rte_panic("rte_eth_dev_start:err=%d, port=%u\n", ret,
713 				  port_id);
714 	}
715 
716 	if (rsrc->event_mode)
717 		l2fwd_event_service_setup(rsrc);
718 
719 	check_all_ports_link_status(rsrc, rsrc->enabled_port_mask);
720 
721 	/* launch per-lcore init on every lcore */
722 	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc,
723 				 SKIP_MAIN);
724 	l2fwd_event_print_stats(rsrc);
725 	if (rsrc->event_mode) {
726 		struct l2fwd_event_resources *evt_rsrc =
727 							rsrc->evt_rsrc;
728 		for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++)
729 			rte_event_eth_rx_adapter_stop(
730 				evt_rsrc->rx_adptr.rx_adptr[i]);
731 		for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++)
732 			rte_event_eth_tx_adapter_stop(
733 				evt_rsrc->tx_adptr.tx_adptr[i]);
734 
735 		RTE_ETH_FOREACH_DEV(port_id) {
736 			if ((rsrc->enabled_port_mask &
737 							(1 << port_id)) == 0)
738 				continue;
739 			ret = rte_eth_dev_stop(port_id);
740 			if (ret < 0)
741 				printf("rte_eth_dev_stop:err=%d, port=%u\n",
742 				       ret, port_id);
743 		}
744 
745 		rte_eal_mp_wait_lcore();
746 		RTE_ETH_FOREACH_DEV(port_id) {
747 			if ((rsrc->enabled_port_mask &
748 							(1 << port_id)) == 0)
749 				continue;
750 			rte_eth_dev_close(port_id);
751 		}
752 
753 		rte_event_dev_stop(evt_rsrc->event_d_id);
754 		rte_event_dev_close(evt_rsrc->event_d_id);
755 
756 	} else {
757 		rte_eal_mp_wait_lcore();
758 
759 		RTE_ETH_FOREACH_DEV(port_id) {
760 			if ((rsrc->enabled_port_mask &
761 							(1 << port_id)) == 0)
762 				continue;
763 			printf("Closing port %d...", port_id);
764 			ret = rte_eth_dev_stop(port_id);
765 			if (ret < 0)
766 				printf("rte_eth_dev_stop:err=%d, port=%u\n",
767 				       ret, port_id);
768 			rte_eth_dev_close(port_id);
769 			printf(" Done\n");
770 		}
771 	}
772 
773 	/* clean up the EAL */
774 	rte_eal_cleanup();
775 	printf("Bye...\n");
776 
777 	return 0;
778 }
779