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