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 " --config: Configure forwarding port pair mapping\n"
29 " Default: alternate port pairs\n\n",
30 prgname);
31 }
32
33 static int
l2fwd_event_parse_portmask(const char * portmask)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
l2fwd_event_parse_nqueue(const char * q_arg)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
l2fwd_event_parse_timer_period(const char * q_arg)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
l2fwd_event_parse_mode(const char * optarg,struct l2fwd_resources * rsrc)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
l2fwd_event_parse_eventq_sched(const char * optarg,struct l2fwd_resources * rsrc)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
l2fwd_parse_port_pair_config(const char * q_arg,struct l2fwd_resources * rsrc)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
l2fwd_event_parse_args(int argc,char ** argv,struct l2fwd_resources * rsrc)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
check_port_pair_config(struct l2fwd_resources * rsrc)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
l2fwd_launch_one_lcore(void * args)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
check_all_ports_link_status(struct l2fwd_resources * rsrc,uint32_t port_mask)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 char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
367
368 printf("\nChecking link status...");
369 fflush(stdout);
370 for (count = 0; count <= MAX_CHECK_TIME; count++) {
371 if (rsrc->force_quit)
372 return;
373 all_ports_up = 1;
374 RTE_ETH_FOREACH_DEV(port_id) {
375 if (rsrc->force_quit)
376 return;
377 if ((port_mask & (1 << port_id)) == 0)
378 continue;
379 memset(&link, 0, sizeof(link));
380 ret = rte_eth_link_get_nowait(port_id, &link);
381 if (ret < 0) {
382 all_ports_up = 0;
383 if (print_flag == 1)
384 printf("Port %u link get failed: %s\n",
385 port_id, rte_strerror(-ret));
386 continue;
387 }
388 /* print link status if flag set */
389 if (print_flag == 1) {
390 rte_eth_link_to_str(link_status_text,
391 sizeof(link_status_text), &link);
392 printf("Port %d %s\n", port_id,
393 link_status_text);
394 continue;
395 }
396 /* clear all_ports_up flag if any link down */
397 if (link.link_status == ETH_LINK_DOWN) {
398 all_ports_up = 0;
399 break;
400 }
401 }
402 /* after finally printing all link status, get out */
403 if (print_flag == 1)
404 break;
405
406 if (all_ports_up == 0) {
407 printf(".");
408 fflush(stdout);
409 rte_delay_ms(CHECK_INTERVAL);
410 }
411
412 /* set the print_flag if all ports up or timeout */
413 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
414 print_flag = 1;
415 printf("done\n");
416 }
417 }
418 }
419
420 /* Print out statistics on packets dropped */
421 static void
print_stats(struct l2fwd_resources * rsrc)422 print_stats(struct l2fwd_resources *rsrc)
423 {
424 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
425 uint32_t port_id;
426
427 total_packets_dropped = 0;
428 total_packets_tx = 0;
429 total_packets_rx = 0;
430
431 const char clr[] = {27, '[', '2', 'J', '\0' };
432 const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' };
433
434 /* Clear screen and move to top left */
435 printf("%s%s", clr, topLeft);
436
437 printf("\nPort statistics ====================================");
438
439 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
440 /* skip disabled ports */
441 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
442 continue;
443 printf("\nStatistics for port %u ------------------------------"
444 "\nPackets sent: %29"PRIu64
445 "\nPackets received: %25"PRIu64
446 "\nPackets dropped: %26"PRIu64,
447 port_id,
448 rsrc->port_stats[port_id].tx,
449 rsrc->port_stats[port_id].rx,
450 rsrc->port_stats[port_id].dropped);
451
452 total_packets_dropped +=
453 rsrc->port_stats[port_id].dropped;
454 total_packets_tx += rsrc->port_stats[port_id].tx;
455 total_packets_rx += rsrc->port_stats[port_id].rx;
456 }
457
458 if (rsrc->event_mode) {
459 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
460 struct rte_event_eth_rx_adapter_stats rx_adptr_stats;
461 struct rte_event_eth_tx_adapter_stats tx_adptr_stats;
462 int ret, i;
463
464 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {
465 ret = rte_event_eth_rx_adapter_stats_get(
466 evt_rsrc->rx_adptr.rx_adptr[i],
467 &rx_adptr_stats);
468 if (ret < 0)
469 continue;
470 printf("\nRx adapter[%d] statistics===================="
471 "\nReceive queue poll count: %17"PRIu64
472 "\nReceived packet count: %20"PRIu64
473 "\nEventdev enqueue count: %19"PRIu64
474 "\nEventdev enqueue retry count: %13"PRIu64
475 "\nReceived packet dropped count: %12"PRIu64
476 "\nRx enqueue start timestamp: %15"PRIu64
477 "\nRx enqueue block cycles: %18"PRIu64
478 "\nRx enqueue unblock timestamp: %13"PRIu64,
479 evt_rsrc->rx_adptr.rx_adptr[i],
480 rx_adptr_stats.rx_poll_count,
481 rx_adptr_stats.rx_packets,
482 rx_adptr_stats.rx_enq_count,
483 rx_adptr_stats.rx_enq_retry,
484 rx_adptr_stats.rx_dropped,
485 rx_adptr_stats.rx_enq_start_ts,
486 rx_adptr_stats.rx_enq_block_cycles,
487 rx_adptr_stats.rx_enq_end_ts);
488 }
489 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) {
490 ret = rte_event_eth_tx_adapter_stats_get(
491 evt_rsrc->tx_adptr.tx_adptr[i],
492 &tx_adptr_stats);
493 if (ret < 0)
494 continue;
495 printf("\nTx adapter[%d] statistics===================="
496 "\nNumber of transmit retries: %15"PRIu64
497 "\nNumber of packets transmitted: %12"PRIu64
498 "\nNumber of packets dropped: %16"PRIu64,
499 evt_rsrc->tx_adptr.tx_adptr[i],
500 tx_adptr_stats.tx_retry,
501 tx_adptr_stats.tx_packets,
502 tx_adptr_stats.tx_dropped);
503 }
504 }
505 printf("\nAggregate lcore statistics ========================="
506 "\nTotal packets sent: %23"PRIu64
507 "\nTotal packets received: %19"PRIu64
508 "\nTotal packets dropped: %20"PRIu64,
509 total_packets_tx,
510 total_packets_rx,
511 total_packets_dropped);
512 printf("\n====================================================\n");
513
514 fflush(stdout);
515 }
516
517 static void
l2fwd_event_print_stats(struct l2fwd_resources * rsrc)518 l2fwd_event_print_stats(struct l2fwd_resources *rsrc)
519 {
520 uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
521 const uint64_t timer_period = rsrc->timer_period;
522
523 while (!rsrc->force_quit) {
524 /* if timer is enabled */
525 if (timer_period > 0) {
526 cur_tsc = rte_rdtsc();
527 diff_tsc = cur_tsc - prev_tsc;
528
529 /* advance the timer */
530 timer_tsc += diff_tsc;
531
532 /* if timer has reached its timeout */
533 if (unlikely(timer_tsc >= timer_period)) {
534 print_stats(rsrc);
535 /* reset the timer */
536 timer_tsc = 0;
537 }
538 prev_tsc = cur_tsc;
539 }
540 }
541 }
542
543
544 static void
signal_handler(int signum)545 signal_handler(int signum)
546 {
547 struct l2fwd_resources *rsrc = l2fwd_get_rsrc();
548 if (signum == SIGINT || signum == SIGTERM) {
549 printf("\n\nSignal %d received, preparing to exit...\n",
550 signum);
551 rsrc->force_quit = true;
552 }
553 }
554
555 int
main(int argc,char ** argv)556 main(int argc, char **argv)
557 {
558 struct l2fwd_resources *rsrc;
559 uint16_t nb_ports_available = 0;
560 uint32_t nb_ports_in_mask = 0;
561 uint16_t port_id, last_port;
562 uint32_t nb_mbufs;
563 uint16_t nb_ports;
564 int i, ret;
565
566 /* init EAL */
567 ret = rte_eal_init(argc, argv);
568 if (ret < 0)
569 rte_panic("Invalid EAL arguments\n");
570 argc -= ret;
571 argv += ret;
572
573 rsrc = l2fwd_get_rsrc();
574
575 signal(SIGINT, signal_handler);
576 signal(SIGTERM, signal_handler);
577
578 /* parse application arguments (after the EAL ones) */
579 ret = l2fwd_event_parse_args(argc, argv, rsrc);
580 if (ret < 0)
581 rte_panic("Invalid L2FWD arguments\n");
582
583 printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" :
584 "disabled");
585
586 nb_ports = rte_eth_dev_count_avail();
587 if (nb_ports == 0)
588 rte_panic("No Ethernet ports - bye\n");
589
590 /* check port mask to possible port mask */
591 if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1))
592 rte_panic("Invalid portmask; possible (0x%x)\n",
593 (1 << nb_ports) - 1);
594
595 if (!rsrc->port_pairs) {
596 last_port = 0;
597 /*
598 * Each logical core is assigned a dedicated TX queue on each
599 * port.
600 */
601 RTE_ETH_FOREACH_DEV(port_id) {
602 /* skip ports that are not enabled */
603 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
604 continue;
605
606 if (nb_ports_in_mask % 2) {
607 rsrc->dst_ports[port_id] = last_port;
608 rsrc->dst_ports[last_port] = port_id;
609 } else {
610 last_port = port_id;
611 }
612
613 nb_ports_in_mask++;
614 }
615 if (nb_ports_in_mask % 2) {
616 printf("Notice: odd number of ports in portmask.\n");
617 rsrc->dst_ports[last_port] = last_port;
618 }
619 } else {
620 if (check_port_pair_config(rsrc) < 0)
621 rte_panic("Invalid port pair config\n");
622 }
623
624 nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT +
625 RTE_TEST_TX_DESC_DEFAULT +
626 MAX_PKT_BURST + rte_lcore_count() *
627 MEMPOOL_CACHE_SIZE), 8192U);
628
629 /* create the mbuf pool */
630 rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
631 nb_mbufs, MEMPOOL_CACHE_SIZE, 0,
632 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
633 if (rsrc->pktmbuf_pool == NULL)
634 rte_panic("Cannot init mbuf pool\n");
635
636 nb_ports_available = l2fwd_event_init_ports(rsrc);
637 if (!nb_ports_available)
638 rte_panic("All available ports are disabled. Please set portmask.\n");
639
640 /* Configure eventdev parameters if required */
641 if (rsrc->event_mode)
642 l2fwd_event_resource_setup(rsrc);
643 else
644 l2fwd_poll_resource_setup(rsrc);
645
646 /* initialize port stats */
647 memset(&rsrc->port_stats, 0,
648 sizeof(struct l2fwd_port_statistics));
649
650 /* All settings are done. Now enable eth devices */
651 RTE_ETH_FOREACH_DEV(port_id) {
652 /* skip ports that are not enabled */
653 if ((rsrc->enabled_port_mask &
654 (1 << port_id)) == 0)
655 continue;
656
657 ret = rte_eth_dev_start(port_id);
658 if (ret < 0)
659 rte_panic("rte_eth_dev_start:err=%d, port=%u\n", ret,
660 port_id);
661 }
662
663 if (rsrc->event_mode)
664 l2fwd_event_service_setup(rsrc);
665
666 check_all_ports_link_status(rsrc, rsrc->enabled_port_mask);
667
668 /* launch per-lcore init on every lcore */
669 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc,
670 SKIP_MAIN);
671 l2fwd_event_print_stats(rsrc);
672 if (rsrc->event_mode) {
673 struct l2fwd_event_resources *evt_rsrc =
674 rsrc->evt_rsrc;
675 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++)
676 rte_event_eth_rx_adapter_stop(
677 evt_rsrc->rx_adptr.rx_adptr[i]);
678 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++)
679 rte_event_eth_tx_adapter_stop(
680 evt_rsrc->tx_adptr.tx_adptr[i]);
681
682 RTE_ETH_FOREACH_DEV(port_id) {
683 if ((rsrc->enabled_port_mask &
684 (1 << port_id)) == 0)
685 continue;
686 ret = rte_eth_dev_stop(port_id);
687 if (ret < 0)
688 printf("rte_eth_dev_stop:err=%d, port=%u\n",
689 ret, 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 ret = rte_eth_dev_stop(port_id);
712 if (ret < 0)
713 printf("rte_eth_dev_stop:err=%d, port=%u\n",
714 ret, port_id);
715 rte_eth_dev_close(port_id);
716 printf(" Done\n");
717 }
718 }
719 printf("Bye...\n");
720
721 return 0;
722 }
723