1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2019 Marvell International Ltd.
5 #include "l2fwd_poll.h"
9 l2fwd_event_usage(const char *prgname)
11 printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
12 " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
13 " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
14 " -T PERIOD: statistics will be refreshed each PERIOD seconds "
15 " (0 to disable, 10 default, 86400 maximum)\n"
16 " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
18 " - The source MAC address is replaced by the TX port MAC address\n"
19 " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n",
24 l2fwd_event_parse_portmask(const char *portmask)
29 /* parse hexadecimal string */
30 pm = strtoul(portmask, &end, 16);
31 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
41 l2fwd_event_parse_nqueue(const char *q_arg)
46 /* parse hexadecimal string */
47 n = strtoul(q_arg, &end, 10);
48 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
52 if (n >= MAX_RX_QUEUE_PER_LCORE)
59 l2fwd_event_parse_timer_period(const char *q_arg)
64 /* parse number string */
65 n = strtol(q_arg, &end, 10);
66 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
68 if (n >= MAX_TIMER_PERIOD)
74 static const char short_options[] =
76 "q:" /* number of queues */
77 "T:" /* timer period */
80 #define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
81 #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
84 /* long options mapped to a short option */
86 /* first long only option value must be >= 256, so that we won't
87 * conflict with short options
89 CMD_LINE_OPT_MIN_NUM = 256,
92 /* Parse the argument given in the command line of the application */
94 l2fwd_event_parse_args(int argc, char **argv,
95 struct l2fwd_resources *rsrc)
98 struct option lgopts[] = {
99 { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
100 { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
103 int opt, ret, timer_secs;
104 char *prgname = argv[0];
109 while ((opt = getopt_long(argc, argvopt, short_options,
110 lgopts, &option_index)) != EOF) {
115 rsrc->enabled_port_mask =
116 l2fwd_event_parse_portmask(optarg);
117 if (rsrc->enabled_port_mask == 0) {
118 printf("invalid portmask\n");
119 l2fwd_event_usage(prgname);
126 rsrc->rx_queue_per_lcore =
127 l2fwd_event_parse_nqueue(optarg);
128 if (rsrc->rx_queue_per_lcore == 0) {
129 printf("invalid queue number\n");
130 l2fwd_event_usage(prgname);
137 timer_secs = l2fwd_event_parse_timer_period(optarg);
138 if (timer_secs < 0) {
139 printf("invalid timer period\n");
140 l2fwd_event_usage(prgname);
143 rsrc->timer_period = timer_secs;
144 /* convert to number of cycles */
145 rsrc->timer_period *= rte_get_timer_hz();
153 l2fwd_event_usage(prgname);
158 rsrc->mac_updating = mac_updating;
161 argv[optind-1] = prgname;
164 optind = 1; /* reset getopt lib */
169 l2fwd_launch_one_lcore(void *args)
171 struct l2fwd_resources *rsrc = args;
172 struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc;
174 poll_rsrc->poll_main_loop(rsrc);
179 /* Check the link status of all ports in up to 9s, and print them finally */
181 check_all_ports_link_status(struct l2fwd_resources *rsrc,
184 #define CHECK_INTERVAL 100 /* 100ms */
185 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
187 uint8_t count, all_ports_up, print_flag = 0;
188 struct rte_eth_link link;
190 printf("\nChecking link status...");
192 for (count = 0; count <= MAX_CHECK_TIME; count++) {
193 if (rsrc->force_quit)
196 RTE_ETH_FOREACH_DEV(port_id) {
197 if (rsrc->force_quit)
199 if ((port_mask & (1 << port_id)) == 0)
201 memset(&link, 0, sizeof(link));
202 rte_eth_link_get_nowait(port_id, &link);
203 /* print link status if flag set */
204 if (print_flag == 1) {
205 if (link.link_status)
207 "Port%d Link Up. Speed %u Mbps - %s\n",
208 port_id, link.link_speed,
209 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
210 ("full-duplex") : ("half-duplex\n"));
212 printf("Port %d Link Down\n", port_id);
215 /* clear all_ports_up flag if any link down */
216 if (link.link_status == ETH_LINK_DOWN) {
221 /* after finally printing all link status, get out */
225 if (all_ports_up == 0) {
228 rte_delay_ms(CHECK_INTERVAL);
231 /* set the print_flag if all ports up or timeout */
232 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
239 /* Print out statistics on packets dropped */
241 print_stats(struct l2fwd_resources *rsrc)
243 uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
246 total_packets_dropped = 0;
247 total_packets_tx = 0;
248 total_packets_rx = 0;
250 const char clr[] = {27, '[', '2', 'J', '\0' };
251 const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0' };
253 /* Clear screen and move to top left */
254 printf("%s%s", clr, topLeft);
256 printf("\nPort statistics ====================================");
258 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
259 /* skip disabled ports */
260 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
262 printf("\nStatistics for port %u ------------------------------"
263 "\nPackets sent: %24"PRIu64
264 "\nPackets received: %20"PRIu64
265 "\nPackets dropped: %21"PRIu64,
267 rsrc->port_stats[port_id].tx,
268 rsrc->port_stats[port_id].rx,
269 rsrc->port_stats[port_id].dropped);
271 total_packets_dropped +=
272 rsrc->port_stats[port_id].dropped;
273 total_packets_tx += rsrc->port_stats[port_id].tx;
274 total_packets_rx += rsrc->port_stats[port_id].rx;
276 printf("\nAggregate statistics ==============================="
277 "\nTotal packets sent: %18"PRIu64
278 "\nTotal packets received: %14"PRIu64
279 "\nTotal packets dropped: %15"PRIu64,
282 total_packets_dropped);
283 printf("\n====================================================\n");
287 l2fwd_event_print_stats(struct l2fwd_resources *rsrc)
289 uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
290 const uint64_t timer_period = rsrc->timer_period;
292 while (!rsrc->force_quit) {
293 /* if timer is enabled */
294 if (timer_period > 0) {
295 cur_tsc = rte_rdtsc();
296 diff_tsc = cur_tsc - prev_tsc;
298 /* advance the timer */
299 timer_tsc += diff_tsc;
301 /* if timer has reached its timeout */
302 if (unlikely(timer_tsc >= timer_period)) {
304 /* reset the timer */
314 signal_handler(int signum)
316 struct l2fwd_resources *rsrc = l2fwd_get_rsrc();
317 if (signum == SIGINT || signum == SIGTERM) {
318 printf("\n\nSignal %d received, preparing to exit...\n",
320 rsrc->force_quit = true;
325 main(int argc, char **argv)
327 struct l2fwd_resources *rsrc;
328 uint16_t nb_ports_available = 0;
329 uint32_t nb_ports_in_mask = 0;
330 uint16_t port_id, last_port;
336 ret = rte_eal_init(argc, argv);
338 rte_panic("Invalid EAL arguments\n");
342 rsrc = l2fwd_get_rsrc();
344 signal(SIGINT, signal_handler);
345 signal(SIGTERM, signal_handler);
347 /* parse application arguments (after the EAL ones) */
348 ret = l2fwd_event_parse_args(argc, argv, rsrc);
350 rte_panic("Invalid L2FWD arguments\n");
352 printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" :
355 nb_ports = rte_eth_dev_count_avail();
357 rte_panic("No Ethernet ports - bye\n");
359 /* check port mask to possible port mask */
360 if (rsrc->enabled_port_mask & ~((1 << nb_ports) - 1))
361 rte_panic("Invalid portmask; possible (0x%x)\n",
362 (1 << nb_ports) - 1);
364 /* reset l2fwd_dst_ports */
365 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++)
366 rsrc->dst_ports[port_id] = 0;
370 * Each logical core is assigned a dedicated TX queue on each port.
372 RTE_ETH_FOREACH_DEV(port_id) {
373 /* skip ports that are not enabled */
374 if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
377 if (nb_ports_in_mask % 2) {
378 rsrc->dst_ports[port_id] = last_port;
379 rsrc->dst_ports[last_port] = port_id;
386 if (nb_ports_in_mask % 2) {
387 printf("Notice: odd number of ports in portmask.\n");
388 rsrc->dst_ports[last_port] = last_port;
391 nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT +
392 RTE_TEST_TX_DESC_DEFAULT +
393 MAX_PKT_BURST + rte_lcore_count() *
394 MEMPOOL_CACHE_SIZE), 8192U);
396 /* create the mbuf pool */
397 rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
398 nb_mbufs, MEMPOOL_CACHE_SIZE, 0,
399 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
400 if (rsrc->pktmbuf_pool == NULL)
401 rte_panic("Cannot init mbuf pool\n");
403 nb_ports_available = l2fwd_event_init_ports(rsrc);
404 if (!nb_ports_available)
405 rte_panic("All available ports are disabled. Please set portmask.\n");
407 l2fwd_poll_resource_setup(rsrc);
409 /* initialize port stats */
410 memset(&rsrc->port_stats, 0,
411 sizeof(struct l2fwd_port_statistics));
413 /* All settings are done. Now enable eth devices */
414 RTE_ETH_FOREACH_DEV(port_id) {
415 /* skip ports that are not enabled */
416 if ((rsrc->enabled_port_mask &
417 (1 << port_id)) == 0)
420 ret = rte_eth_dev_start(port_id);
422 rte_panic("rte_eth_dev_start:err=%d, port=%u\n", ret,
426 check_all_ports_link_status(rsrc, rsrc->enabled_port_mask);
428 /* launch per-lcore init on every lcore */
429 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc,
431 l2fwd_event_print_stats(rsrc);
432 rte_eal_mp_wait_lcore();
434 RTE_ETH_FOREACH_DEV(port_id) {
435 if ((rsrc->enabled_port_mask &
436 (1 << port_id)) == 0)
438 printf("Closing port %d...", port_id);
439 rte_eth_dev_stop(port_id);
440 rte_eth_dev_close(port_id);