1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2019 Marvell International Ltd.
5 #include "l2fwd_event.h"
6 #include "l2fwd_poll.h"
10 l2fwd_event_usage(const char *prgname)
12 printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
13 " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
14 " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
15 " -T PERIOD: statistics will be refreshed each PERIOD seconds "
16 " (0 to disable, 10 default, 86400 maximum)\n"
17 " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
19 " - The source MAC address is replaced by the TX port MAC address\n"
20 " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n"
21 " --mode: Packet transfer mode for I/O, poll or eventdev\n"
22 " Default mode = eventdev\n"
23 " --eventq-sched: Event queue schedule type, ordered, atomic or parallel.\n"
25 " Valid only if --mode=eventdev\n\n",
30 l2fwd_event_parse_portmask(const char *portmask)
35 /* parse hexadecimal string */
36 pm = strtoul(portmask, &end, 16);
37 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
47 l2fwd_event_parse_nqueue(const char *q_arg)
52 /* parse hexadecimal string */
53 n = strtoul(q_arg, &end, 10);
54 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
58 if (n >= MAX_RX_QUEUE_PER_LCORE)
65 l2fwd_event_parse_timer_period(const char *q_arg)
70 /* parse number string */
71 n = strtol(q_arg, &end, 10);
72 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
74 if (n >= MAX_TIMER_PERIOD)
81 l2fwd_event_parse_mode(const char *optarg,
82 struct l2fwd_resources *rsrc)
84 if (!strncmp(optarg, "poll", 4))
85 rsrc->event_mode = false;
86 else if (!strncmp(optarg, "eventdev", 8))
87 rsrc->event_mode = true;
91 l2fwd_event_parse_eventq_sched(const char *optarg,
92 struct l2fwd_resources *rsrc)
94 if (!strncmp(optarg, "ordered", 7))
95 rsrc->sched_type = RTE_SCHED_TYPE_ORDERED;
96 else if (!strncmp(optarg, "atomic", 6))
97 rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC;
98 else if (!strncmp(optarg, "parallel", 8))
99 rsrc->sched_type = RTE_SCHED_TYPE_PARALLEL;
102 static const char short_options[] =
104 "q:" /* number of queues */
105 "T:" /* timer period */
108 #define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
109 #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
110 #define CMD_LINE_OPT_MODE "mode"
111 #define CMD_LINE_OPT_EVENTQ_SCHED "eventq-sched"
114 /* long options mapped to a short option */
116 /* first long only option value must be >= 256, so that we won't
117 * conflict with short options
119 CMD_LINE_OPT_MIN_NUM = 256,
120 CMD_LINE_OPT_MODE_NUM,
121 CMD_LINE_OPT_EVENTQ_SCHED_NUM,
124 /* Parse the argument given in the command line of the application */
126 l2fwd_event_parse_args(int argc, char **argv,
127 struct l2fwd_resources *rsrc)
129 int mac_updating = 1;
130 struct option lgopts[] = {
131 { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
132 { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
133 { CMD_LINE_OPT_MODE, required_argument, NULL,
134 CMD_LINE_OPT_MODE_NUM},
135 { CMD_LINE_OPT_EVENTQ_SCHED, required_argument, NULL,
136 CMD_LINE_OPT_EVENTQ_SCHED_NUM},
139 int opt, ret, timer_secs;
140 char *prgname = argv[0];
145 while ((opt = getopt_long(argc, argvopt, short_options,
146 lgopts, &option_index)) != EOF) {
151 rsrc->enabled_port_mask =
152 l2fwd_event_parse_portmask(optarg);
153 if (rsrc->enabled_port_mask == 0) {
154 printf("invalid portmask\n");
155 l2fwd_event_usage(prgname);
162 rsrc->rx_queue_per_lcore =
163 l2fwd_event_parse_nqueue(optarg);
164 if (rsrc->rx_queue_per_lcore == 0) {
165 printf("invalid queue number\n");
166 l2fwd_event_usage(prgname);
173 timer_secs = l2fwd_event_parse_timer_period(optarg);
174 if (timer_secs < 0) {
175 printf("invalid timer period\n");
176 l2fwd_event_usage(prgname);
179 rsrc->timer_period = timer_secs;
180 /* convert to number of cycles */
181 rsrc->timer_period *= rte_get_timer_hz();
184 case CMD_LINE_OPT_MODE_NUM:
185 l2fwd_event_parse_mode(optarg, rsrc);
188 case CMD_LINE_OPT_EVENTQ_SCHED_NUM:
189 l2fwd_event_parse_eventq_sched(optarg, rsrc);
197 l2fwd_event_usage(prgname);
202 rsrc->mac_updating = mac_updating;
205 argv[optind-1] = prgname;
208 optind = 1; /* reset getopt lib */
213 l2fwd_launch_one_lcore(void *args)
215 struct l2fwd_resources *rsrc = args;
216 struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc;
217 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
219 if (rsrc->event_mode)
220 evt_rsrc->ops.l2fwd_event_loop(rsrc);
222 poll_rsrc->poll_main_loop(rsrc);
227 /* Check the link status of all ports in up to 9s, and print them finally */
229 check_all_ports_link_status(struct l2fwd_resources *rsrc,
232 #define CHECK_INTERVAL 100 /* 100ms */
233 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
235 uint8_t count, all_ports_up, print_flag = 0;
236 struct rte_eth_link link;
239 printf("\nChecking link status...");
241 for (count = 0; count <= MAX_CHECK_TIME; count++) {
242 if (rsrc->force_quit)
245 RTE_ETH_FOREACH_DEV(port_id) {
246 if (rsrc->force_quit)
248 if ((port_mask & (1 << port_id)) == 0)
250 memset(&link, 0, sizeof(link));
251 ret = rte_eth_link_get_nowait(port_id, &link);
255 printf("Port %u link get failed: %s\n",
256 port_id, rte_strerror(-ret));
259 /* print link status if flag set */
260 if (print_flag == 1) {
261 if (link.link_status)
263 "Port%d Link Up. Speed %u Mbps - %s\n",
264 port_id, link.link_speed,
265 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
266 ("full-duplex") : ("half-duplex\n"));
268 printf("Port %d Link Down\n", port_id);
271 /* clear all_ports_up flag if any link down */
272 if (link.link_status == ETH_LINK_DOWN) {
277 /* after finally printing all link status, get out */
281 if (all_ports_up == 0) {
284 rte_delay_ms(CHECK_INTERVAL);
287 /* set the print_flag if all ports up or timeout */
288 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
295 /* Print out statistics on packets dropped */
297 print_stats(struct l2fwd_resources *rsrc)
299 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
302 total_packets_dropped = 0;
303 total_packets_tx = 0;
304 total_packets_rx = 0;
306 const char clr[] = {27, '[', '2', 'J', '\0' };
307 const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' };
309 /* Clear screen and move to top left */
310 printf("%s%s", clr, topLeft);
312 printf("\nPort statistics ====================================");
314 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
315 /* skip disabled ports */
316 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
318 printf("\nStatistics for port %u ------------------------------"
319 "\nPackets sent: %29"PRIu64
320 "\nPackets received: %25"PRIu64
321 "\nPackets dropped: %26"PRIu64,
323 rsrc->port_stats[port_id].tx,
324 rsrc->port_stats[port_id].rx,
325 rsrc->port_stats[port_id].dropped);
327 total_packets_dropped +=
328 rsrc->port_stats[port_id].dropped;
329 total_packets_tx += rsrc->port_stats[port_id].tx;
330 total_packets_rx += rsrc->port_stats[port_id].rx;
333 if (rsrc->event_mode) {
334 struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
335 struct rte_event_eth_rx_adapter_stats rx_adptr_stats;
336 struct rte_event_eth_tx_adapter_stats tx_adptr_stats;
339 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {
340 ret = rte_event_eth_rx_adapter_stats_get(
341 evt_rsrc->rx_adptr.rx_adptr[i],
345 printf("\nRx adapter[%d] statistics===================="
346 "\nReceive queue poll count: %17"PRIu64
347 "\nReceived packet count: %20"PRIu64
348 "\nEventdev enqueue count: %19"PRIu64
349 "\nEventdev enqueue retry count: %13"PRIu64
350 "\nReceived packet dropped count: %12"PRIu64
351 "\nRx enqueue start timestamp: %15"PRIu64
352 "\nRx enqueue block cycles: %18"PRIu64
353 "\nRx enqueue unblock timestamp: %13"PRIu64,
354 evt_rsrc->rx_adptr.rx_adptr[i],
355 rx_adptr_stats.rx_poll_count,
356 rx_adptr_stats.rx_packets,
357 rx_adptr_stats.rx_enq_count,
358 rx_adptr_stats.rx_enq_retry,
359 rx_adptr_stats.rx_dropped,
360 rx_adptr_stats.rx_enq_start_ts,
361 rx_adptr_stats.rx_enq_block_cycles,
362 rx_adptr_stats.rx_enq_end_ts);
364 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) {
365 ret = rte_event_eth_tx_adapter_stats_get(
366 evt_rsrc->tx_adptr.tx_adptr[i],
370 printf("\nTx adapter[%d] statistics===================="
371 "\nNumber of transmit retries: %15"PRIu64
372 "\nNumber of packets transmitted: %12"PRIu64
373 "\nNumber of packets dropped: %16"PRIu64,
374 evt_rsrc->tx_adptr.tx_adptr[i],
375 tx_adptr_stats.tx_retry,
376 tx_adptr_stats.tx_packets,
377 tx_adptr_stats.tx_dropped);
380 printf("\nAggregate lcore statistics ========================="
381 "\nTotal packets sent: %23"PRIu64
382 "\nTotal packets received: %19"PRIu64
383 "\nTotal packets dropped: %20"PRIu64,
386 total_packets_dropped);
387 printf("\n====================================================\n");
391 l2fwd_event_print_stats(struct l2fwd_resources *rsrc)
393 uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
394 const uint64_t timer_period = rsrc->timer_period;
396 while (!rsrc->force_quit) {
397 /* if timer is enabled */
398 if (timer_period > 0) {
399 cur_tsc = rte_rdtsc();
400 diff_tsc = cur_tsc - prev_tsc;
402 /* advance the timer */
403 timer_tsc += diff_tsc;
405 /* if timer has reached its timeout */
406 if (unlikely(timer_tsc >= timer_period)) {
408 /* reset the timer */
418 signal_handler(int signum)
420 struct l2fwd_resources *rsrc = l2fwd_get_rsrc();
421 if (signum == SIGINT || signum == SIGTERM) {
422 printf("\n\nSignal %d received, preparing to exit...\n",
424 rsrc->force_quit = true;
429 main(int argc, char **argv)
431 struct l2fwd_resources *rsrc;
432 uint16_t nb_ports_available = 0;
433 uint32_t nb_ports_in_mask = 0;
434 uint16_t port_id, last_port;
440 ret = rte_eal_init(argc, argv);
442 rte_panic("Invalid EAL arguments\n");
446 rsrc = l2fwd_get_rsrc();
448 signal(SIGINT, signal_handler);
449 signal(SIGTERM, signal_handler);
451 /* parse application arguments (after the EAL ones) */
452 ret = l2fwd_event_parse_args(argc, argv, rsrc);
454 rte_panic("Invalid L2FWD arguments\n");
456 printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" :
459 nb_ports = rte_eth_dev_count_avail();
461 rte_panic("No Ethernet ports - bye\n");
463 /* check port mask to possible port mask */
464 if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1))
465 rte_panic("Invalid portmask; possible (0x%x)\n",
466 (1 << nb_ports) - 1);
468 /* reset l2fwd_dst_ports */
469 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++)
470 rsrc->dst_ports[port_id] = 0;
474 * Each logical core is assigned a dedicated TX queue on each port.
476 RTE_ETH_FOREACH_DEV(port_id) {
477 /* skip ports that are not enabled */
478 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
481 if (nb_ports_in_mask % 2) {
482 rsrc->dst_ports[port_id] = last_port;
483 rsrc->dst_ports[last_port] = port_id;
490 if (nb_ports_in_mask % 2) {
491 printf("Notice: odd number of ports in portmask.\n");
492 rsrc->dst_ports[last_port] = last_port;
495 nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT +
496 RTE_TEST_TX_DESC_DEFAULT +
497 MAX_PKT_BURST + rte_lcore_count() *
498 MEMPOOL_CACHE_SIZE), 8192U);
500 /* create the mbuf pool */
501 rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
502 nb_mbufs, MEMPOOL_CACHE_SIZE, 0,
503 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
504 if (rsrc->pktmbuf_pool == NULL)
505 rte_panic("Cannot init mbuf pool\n");
507 nb_ports_available = l2fwd_event_init_ports(rsrc);
508 if (!nb_ports_available)
509 rte_panic("All available ports are disabled. Please set portmask.\n");
511 /* Configure eventdev parameters if required */
512 if (rsrc->event_mode)
513 l2fwd_event_resource_setup(rsrc);
515 l2fwd_poll_resource_setup(rsrc);
517 /* initialize port stats */
518 memset(&rsrc->port_stats, 0,
519 sizeof(struct l2fwd_port_statistics));
521 /* All settings are done. Now enable eth devices */
522 RTE_ETH_FOREACH_DEV(port_id) {
523 /* skip ports that are not enabled */
524 if ((rsrc->enabled_port_mask &
525 (1 << port_id)) == 0)
528 ret = rte_eth_dev_start(port_id);
530 rte_panic("rte_eth_dev_start:err=%d, port=%u\n", ret,
534 if (rsrc->event_mode)
535 l2fwd_event_service_setup(rsrc);
537 check_all_ports_link_status(rsrc, rsrc->enabled_port_mask);
539 /* launch per-lcore init on every lcore */
540 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc,
542 l2fwd_event_print_stats(rsrc);
543 if (rsrc->event_mode) {
544 struct l2fwd_event_resources *evt_rsrc =
546 for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++)
547 rte_event_eth_rx_adapter_stop(
548 evt_rsrc->rx_adptr.rx_adptr[i]);
549 for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++)
550 rte_event_eth_tx_adapter_stop(
551 evt_rsrc->tx_adptr.tx_adptr[i]);
553 RTE_ETH_FOREACH_DEV(port_id) {
554 if ((rsrc->enabled_port_mask &
555 (1 << port_id)) == 0)
557 rte_eth_dev_stop(port_id);
560 rte_eal_mp_wait_lcore();
561 RTE_ETH_FOREACH_DEV(port_id) {
562 if ((rsrc->enabled_port_mask &
563 (1 << port_id)) == 0)
565 rte_eth_dev_close(port_id);
568 rte_event_dev_stop(evt_rsrc->event_d_id);
569 rte_event_dev_close(evt_rsrc->event_d_id);
572 rte_eal_mp_wait_lcore();
574 RTE_ETH_FOREACH_DEV(port_id) {
575 if ((rsrc->enabled_port_mask &
576 (1 << port_id)) == 0)
578 printf("Closing port %d...", port_id);
579 rte_eth_dev_stop(port_id);
580 rte_eth_dev_close(port_id);