ethdev: add namespace
[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                "  --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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 * (RTE_TEST_RX_DESC_DEFAULT +
664                                        RTE_TEST_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                 rsrc->evt_vec_pool = rte_event_vector_pool_create(
682                         "vector_pool", nb_vec, 0, vec_size, rte_socket_id());
683                 if (rsrc->evt_vec_pool == NULL)
684                         rte_panic("Cannot init event vector pool\n");
685         }
686
687         nb_ports_available = l2fwd_event_init_ports(rsrc);
688         if (!nb_ports_available)
689                 rte_panic("All available ports are disabled. Please set portmask.\n");
690
691         /* Configure eventdev parameters if required */
692         if (rsrc->event_mode)
693                 l2fwd_event_resource_setup(rsrc);
694         else
695                 l2fwd_poll_resource_setup(rsrc);
696
697         /* initialize port stats */
698         memset(&rsrc->port_stats, 0,
699                                         sizeof(struct l2fwd_port_statistics));
700
701         /* All settings are done. Now enable eth devices */
702         RTE_ETH_FOREACH_DEV(port_id) {
703                 /* skip ports that are not enabled */
704                 if ((rsrc->enabled_port_mask &
705                                         (1 << port_id)) == 0)
706                         continue;
707
708                 ret = rte_eth_dev_start(port_id);
709                 if (ret < 0)
710                         rte_panic("rte_eth_dev_start:err=%d, port=%u\n", ret,
711                                   port_id);
712         }
713
714         if (rsrc->event_mode)
715                 l2fwd_event_service_setup(rsrc);
716
717         check_all_ports_link_status(rsrc, rsrc->enabled_port_mask);
718
719         /* launch per-lcore init on every lcore */
720         rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc,
721                                  SKIP_MAIN);
722         l2fwd_event_print_stats(rsrc);
723         if (rsrc->event_mode) {
724                 struct l2fwd_event_resources *evt_rsrc =
725                                                         rsrc->evt_rsrc;
726                 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++)
727                         rte_event_eth_rx_adapter_stop(
728                                 evt_rsrc->rx_adptr.rx_adptr[i]);
729                 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++)
730                         rte_event_eth_tx_adapter_stop(
731                                 evt_rsrc->tx_adptr.tx_adptr[i]);
732
733                 RTE_ETH_FOREACH_DEV(port_id) {
734                         if ((rsrc->enabled_port_mask &
735                                                         (1 << port_id)) == 0)
736                                 continue;
737                         ret = rte_eth_dev_stop(port_id);
738                         if (ret < 0)
739                                 printf("rte_eth_dev_stop:err=%d, port=%u\n",
740                                        ret, port_id);
741                 }
742
743                 rte_eal_mp_wait_lcore();
744                 RTE_ETH_FOREACH_DEV(port_id) {
745                         if ((rsrc->enabled_port_mask &
746                                                         (1 << port_id)) == 0)
747                                 continue;
748                         rte_eth_dev_close(port_id);
749                 }
750
751                 rte_event_dev_stop(evt_rsrc->event_d_id);
752                 rte_event_dev_close(evt_rsrc->event_d_id);
753
754         } else {
755                 rte_eal_mp_wait_lcore();
756
757                 RTE_ETH_FOREACH_DEV(port_id) {
758                         if ((rsrc->enabled_port_mask &
759                                                         (1 << port_id)) == 0)
760                                 continue;
761                         printf("Closing port %d...", port_id);
762                         ret = rte_eth_dev_stop(port_id);
763                         if (ret < 0)
764                                 printf("rte_eth_dev_stop:err=%d, port=%u\n",
765                                        ret, port_id);
766                         rte_eth_dev_close(port_id);
767                         printf(" Done\n");
768                 }
769         }
770
771         /* clean up the EAL */
772         rte_eal_cleanup();
773         printf("Bye...\n");
774
775         return 0;
776 }