net/af_xdp: fix zero-copy Tx queue drain
[dpdk.git] / examples / l2fwd-event / main.c
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. 8< */
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         /* >8 End of reset l2fwd_dst_ports. */
293 }
294
295 /*
296  * Check port pair config with enabled port mask,
297  * and for valid port pair combinations.
298  */
299 static int
300 check_port_pair_config(struct l2fwd_resources *rsrc)
301 {
302         uint32_t port_pair_mask = 0;
303         uint32_t portid;
304         uint16_t index;
305
306         for (index = 0; index < rte_eth_dev_count_avail(); index++) {
307                 if ((rsrc->enabled_port_mask & (1 << index)) == 0 ||
308                     (port_pair_mask & (1 << index)))
309                         continue;
310
311                 portid = rsrc->dst_ports[index];
312                 if (portid == UINT32_MAX) {
313                         printf("port %u is enabled in but no valid port pair\n",
314                                index);
315                         return -1;
316                 }
317
318                 if (!rte_eth_dev_is_valid_port(index)) {
319                         printf("port %u is not valid\n", index);
320                         return -1;
321                 }
322
323                 if (!rte_eth_dev_is_valid_port(portid)) {
324                         printf("port %u is not valid\n", portid);
325                         return -1;
326                 }
327
328                 if (port_pair_mask & (1 << portid) &&
329                                 rsrc->dst_ports[portid] != index) {
330                         printf("port %u is used in other port pairs\n", portid);
331                         return -1;
332                 }
333
334                 port_pair_mask |= (1 << portid);
335                 port_pair_mask |= (1 << index);
336         }
337
338         return 0;
339 }
340
341 static int
342 l2fwd_launch_one_lcore(void *args)
343 {
344         struct l2fwd_resources *rsrc = args;
345         struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc;
346         struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
347
348         if (rsrc->event_mode)
349                 evt_rsrc->ops.l2fwd_event_loop(rsrc);
350         else
351                 poll_rsrc->poll_main_loop(rsrc);
352
353         return 0;
354 }
355
356 /* Check the link status of all ports in up to 9s, and print them finally */
357 static void
358 check_all_ports_link_status(struct l2fwd_resources *rsrc,
359                             uint32_t port_mask)
360 {
361 #define CHECK_INTERVAL 100 /* 100ms */
362 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
363         uint16_t port_id;
364         uint8_t count, all_ports_up, print_flag = 0;
365         struct rte_eth_link link;
366         int ret;
367         char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
368
369         printf("\nChecking link status...");
370         fflush(stdout);
371         for (count = 0; count <= MAX_CHECK_TIME; count++) {
372                 if (rsrc->force_quit)
373                         return;
374                 all_ports_up = 1;
375                 RTE_ETH_FOREACH_DEV(port_id) {
376                         if (rsrc->force_quit)
377                                 return;
378                         if ((port_mask & (1 << port_id)) == 0)
379                                 continue;
380                         memset(&link, 0, sizeof(link));
381                         ret = rte_eth_link_get_nowait(port_id, &link);
382                         if (ret < 0) {
383                                 all_ports_up = 0;
384                                 if (print_flag == 1)
385                                         printf("Port %u link get failed: %s\n",
386                                                 port_id, rte_strerror(-ret));
387                                 continue;
388                         }
389                         /* print link status if flag set */
390                         if (print_flag == 1) {
391                                 rte_eth_link_to_str(link_status_text,
392                                         sizeof(link_status_text), &link);
393                                 printf("Port %d %s\n", port_id,
394                                        link_status_text);
395                                 continue;
396                         }
397                         /* clear all_ports_up flag if any link down */
398                         if (link.link_status == ETH_LINK_DOWN) {
399                                 all_ports_up = 0;
400                                 break;
401                         }
402                 }
403                 /* after finally printing all link status, get out */
404                 if (print_flag == 1)
405                         break;
406
407                 if (all_ports_up == 0) {
408                         printf(".");
409                         fflush(stdout);
410                         rte_delay_ms(CHECK_INTERVAL);
411                 }
412
413                 /* set the print_flag if all ports up or timeout */
414                 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
415                         print_flag = 1;
416                         printf("done\n");
417                 }
418         }
419 }
420
421 /* Print out statistics on packets dropped */
422 static void
423 print_stats(struct l2fwd_resources *rsrc)
424 {
425         uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
426         uint32_t port_id;
427
428         total_packets_dropped = 0;
429         total_packets_tx = 0;
430         total_packets_rx = 0;
431
432         const char clr[] = {27, '[', '2', 'J', '\0' };
433         const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' };
434
435                 /* Clear screen and move to top left */
436         printf("%s%s", clr, topLeft);
437
438         printf("\nPort statistics ====================================");
439
440         for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
441                 /* skip disabled ports */
442                 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
443                         continue;
444                 printf("\nStatistics for port %u ------------------------------"
445                            "\nPackets sent: %29"PRIu64
446                            "\nPackets received: %25"PRIu64
447                            "\nPackets dropped: %26"PRIu64,
448                            port_id,
449                            rsrc->port_stats[port_id].tx,
450                            rsrc->port_stats[port_id].rx,
451                            rsrc->port_stats[port_id].dropped);
452
453                 total_packets_dropped +=
454                                         rsrc->port_stats[port_id].dropped;
455                 total_packets_tx += rsrc->port_stats[port_id].tx;
456                 total_packets_rx += rsrc->port_stats[port_id].rx;
457         }
458
459         if (rsrc->event_mode) {
460                 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
461                 struct rte_event_eth_rx_adapter_stats rx_adptr_stats;
462                 struct rte_event_eth_tx_adapter_stats tx_adptr_stats;
463                 int ret, i;
464
465                 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {
466                         ret = rte_event_eth_rx_adapter_stats_get(
467                                         evt_rsrc->rx_adptr.rx_adptr[i],
468                                         &rx_adptr_stats);
469                         if (ret < 0)
470                                 continue;
471                         printf("\nRx adapter[%d] statistics===================="
472                                    "\nReceive queue poll count: %17"PRIu64
473                                    "\nReceived packet count: %20"PRIu64
474                                    "\nEventdev enqueue count: %19"PRIu64
475                                    "\nEventdev enqueue retry count: %13"PRIu64
476                                    "\nReceived packet dropped count: %12"PRIu64
477                                    "\nRx enqueue start timestamp: %15"PRIu64
478                                    "\nRx enqueue block cycles: %18"PRIu64
479                                    "\nRx enqueue unblock timestamp: %13"PRIu64,
480                                    evt_rsrc->rx_adptr.rx_adptr[i],
481                                    rx_adptr_stats.rx_poll_count,
482                                    rx_adptr_stats.rx_packets,
483                                    rx_adptr_stats.rx_enq_count,
484                                    rx_adptr_stats.rx_enq_retry,
485                                    rx_adptr_stats.rx_dropped,
486                                    rx_adptr_stats.rx_enq_start_ts,
487                                    rx_adptr_stats.rx_enq_block_cycles,
488                                    rx_adptr_stats.rx_enq_end_ts);
489                 }
490                 for (i = 0; i <  evt_rsrc->tx_adptr.nb_tx_adptr; i++) {
491                         ret = rte_event_eth_tx_adapter_stats_get(
492                                         evt_rsrc->tx_adptr.tx_adptr[i],
493                                         &tx_adptr_stats);
494                         if (ret < 0)
495                                 continue;
496                         printf("\nTx adapter[%d] statistics===================="
497                                    "\nNumber of transmit retries: %15"PRIu64
498                                    "\nNumber of packets transmitted: %12"PRIu64
499                                    "\nNumber of packets dropped: %16"PRIu64,
500                                    evt_rsrc->tx_adptr.tx_adptr[i],
501                                    tx_adptr_stats.tx_retry,
502                                    tx_adptr_stats.tx_packets,
503                                    tx_adptr_stats.tx_dropped);
504                 }
505         }
506         printf("\nAggregate lcore statistics ========================="
507                    "\nTotal packets sent: %23"PRIu64
508                    "\nTotal packets received: %19"PRIu64
509                    "\nTotal packets dropped: %20"PRIu64,
510                    total_packets_tx,
511                    total_packets_rx,
512                    total_packets_dropped);
513         printf("\n====================================================\n");
514
515         fflush(stdout);
516 }
517
518 static void
519 l2fwd_event_print_stats(struct l2fwd_resources *rsrc)
520 {
521         uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
522         const uint64_t timer_period = rsrc->timer_period;
523
524         while (!rsrc->force_quit) {
525                 /* if timer is enabled */
526                 if (timer_period > 0) {
527                         cur_tsc = rte_rdtsc();
528                         diff_tsc = cur_tsc - prev_tsc;
529
530                         /* advance the timer */
531                         timer_tsc += diff_tsc;
532
533                         /* if timer has reached its timeout */
534                         if (unlikely(timer_tsc >= timer_period)) {
535                                 print_stats(rsrc);
536                                 /* reset the timer */
537                                 timer_tsc = 0;
538                         }
539                         prev_tsc = cur_tsc;
540                 }
541         }
542 }
543
544
545 static void
546 signal_handler(int signum)
547 {
548         struct l2fwd_resources *rsrc = l2fwd_get_rsrc();
549         if (signum == SIGINT || signum == SIGTERM) {
550                 printf("\n\nSignal %d received, preparing to exit...\n",
551                                 signum);
552                 rsrc->force_quit = true;
553         }
554 }
555
556 int
557 main(int argc, char **argv)
558 {
559         struct l2fwd_resources *rsrc;
560         uint16_t nb_ports_available = 0;
561         uint32_t nb_ports_in_mask = 0;
562         uint16_t port_id, last_port;
563         uint32_t nb_mbufs;
564         uint16_t nb_ports;
565         int i, ret;
566
567         /* Init EAL. 8< */
568         ret = rte_eal_init(argc, argv);
569         if (ret < 0)
570                 rte_panic("Invalid EAL arguments\n");
571         argc -= ret;
572         argv += ret;
573
574         rsrc = l2fwd_get_rsrc();
575
576         signal(SIGINT, signal_handler);
577         signal(SIGTERM, signal_handler);
578
579         /* parse application arguments (after the EAL ones) */
580         ret = l2fwd_event_parse_args(argc, argv, rsrc);
581         if (ret < 0)
582                 rte_panic("Invalid L2FWD arguments\n");
583         /* >8 End of init EAL. */
584
585         printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" :
586                         "disabled");
587
588         nb_ports = rte_eth_dev_count_avail();
589         if (nb_ports == 0)
590                 rte_panic("No Ethernet ports - bye\n");
591
592         /* check port mask to possible port mask */
593         if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1))
594                 rte_panic("Invalid portmask; possible (0x%x)\n",
595                         (1 << nb_ports) - 1);
596
597         if (!rsrc->port_pairs) {
598                 last_port = 0;
599                 /*
600                  * Each logical core is assigned a dedicated TX queue on each
601                  * port.
602                  */
603                 RTE_ETH_FOREACH_DEV(port_id) {
604                         /* skip ports that are not enabled */
605                         if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
606                                 continue;
607
608                         if (nb_ports_in_mask % 2) {
609                                 rsrc->dst_ports[port_id] = last_port;
610                                 rsrc->dst_ports[last_port] = port_id;
611                         } else {
612                                 last_port = port_id;
613                         }
614
615                         nb_ports_in_mask++;
616                 }
617                 if (nb_ports_in_mask % 2) {
618                         printf("Notice: odd number of ports in portmask.\n");
619                         rsrc->dst_ports[last_port] = last_port;
620                 }
621         } else {
622                 if (check_port_pair_config(rsrc) < 0)
623                         rte_panic("Invalid port pair config\n");
624         }
625
626         nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT +
627                                        RTE_TEST_TX_DESC_DEFAULT +
628                                        MAX_PKT_BURST + rte_lcore_count() *
629                                        MEMPOOL_CACHE_SIZE), 8192U);
630
631         /* Create the mbuf pool. 8< */
632         rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
633                         nb_mbufs, MEMPOOL_CACHE_SIZE, 0,
634                         RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
635         if (rsrc->pktmbuf_pool == NULL)
636                 rte_panic("Cannot init mbuf pool\n");
637         /* >8 End of creation of mbuf pool. */
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_MAIN);
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                         ret = rte_eth_dev_stop(port_id);
690                         if (ret < 0)
691                                 printf("rte_eth_dev_stop:err=%d, port=%u\n",
692                                        ret, port_id);
693                 }
694
695                 rte_eal_mp_wait_lcore();
696                 RTE_ETH_FOREACH_DEV(port_id) {
697                         if ((rsrc->enabled_port_mask &
698                                                         (1 << port_id)) == 0)
699                                 continue;
700                         rte_eth_dev_close(port_id);
701                 }
702
703                 rte_event_dev_stop(evt_rsrc->event_d_id);
704                 rte_event_dev_close(evt_rsrc->event_d_id);
705
706         } else {
707                 rte_eal_mp_wait_lcore();
708
709                 RTE_ETH_FOREACH_DEV(port_id) {
710                         if ((rsrc->enabled_port_mask &
711                                                         (1 << port_id)) == 0)
712                                 continue;
713                         printf("Closing port %d...", port_id);
714                         ret = rte_eth_dev_stop(port_id);
715                         if (ret < 0)
716                                 printf("rte_eth_dev_stop:err=%d, port=%u\n",
717                                        ret, port_id);
718                         rte_eth_dev_close(port_id);
719                         printf(" Done\n");
720                 }
721         }
722
723         /* clean up the EAL */
724         rte_eal_cleanup();
725         printf("Bye...\n");
726
727         return 0;
728 }