1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2016 Intel Corporation
12 #include <rte_common.h>
14 #include <rte_malloc.h>
15 #include <rte_memory.h>
16 #include <rte_memcpy.h>
18 #include <rte_launch.h>
19 #include <rte_atomic.h>
20 #include <rte_cycles.h>
21 #include <rte_prefetch.h>
22 #include <rte_lcore.h>
23 #include <rte_per_lcore.h>
24 #include <rte_branch_prediction.h>
25 #include <rte_interrupts.h>
26 #include <rte_debug.h>
27 #include <rte_ether.h>
28 #include <rte_ethdev.h>
29 #include <rte_mempool.h>
31 #include <rte_spinlock.h>
33 #include <rte_errno.h>
34 #include <rte_jobstats.h>
35 #include <rte_timer.h>
36 #include <rte_alarm.h>
37 #include <rte_pause.h>
39 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
43 #define MAX_PKT_BURST 32
44 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
47 * Configurable number of RX/TX ring descriptors
49 #define RTE_TEST_RX_DESC_DEFAULT 1024
50 #define RTE_TEST_TX_DESC_DEFAULT 1024
51 static uint16_t nb_rxd
= RTE_TEST_RX_DESC_DEFAULT
;
52 static uint16_t nb_txd
= RTE_TEST_TX_DESC_DEFAULT
;
54 /* ethernet addresses of ports */
55 static struct rte_ether_addr l2fwd_ports_eth_addr
[RTE_MAX_ETHPORTS
];
57 /* mask of enabled ports */
58 static uint32_t l2fwd_enabled_port_mask
;
60 /* list of enabled ports */
61 static uint32_t l2fwd_dst_ports
[RTE_MAX_ETHPORTS
];
63 #define UPDATE_STEP_UP 1
64 #define UPDATE_STEP_DOWN 32
66 static unsigned int l2fwd_rx_queue_per_lcore
= 1;
68 #define MAX_RX_QUEUE_PER_LCORE 16
69 #define MAX_TX_QUEUE_PER_PORT 16
70 struct lcore_queue_conf
{
72 unsigned rx_port_list
[MAX_RX_QUEUE_PER_LCORE
];
73 uint64_t next_flush_time
[RTE_MAX_ETHPORTS
];
75 struct rte_timer rx_timers
[MAX_RX_QUEUE_PER_LCORE
];
76 struct rte_jobstats port_fwd_jobs
[MAX_RX_QUEUE_PER_LCORE
];
78 struct rte_timer flush_timer
;
79 struct rte_jobstats flush_job
;
80 struct rte_jobstats idle_job
;
81 struct rte_jobstats_context jobs_context
;
83 rte_atomic16_t stats_read_pending
;
85 } __rte_cache_aligned
;
86 struct lcore_queue_conf lcore_queue_conf
[RTE_MAX_LCORE
];
88 struct rte_eth_dev_tx_buffer
*tx_buffer
[RTE_MAX_ETHPORTS
];
90 static struct rte_eth_conf port_conf
= {
95 .mq_mode
= ETH_MQ_TX_NONE
,
99 struct rte_mempool
*l2fwd_pktmbuf_pool
= NULL
;
101 /* Per-port statistics struct */
102 struct l2fwd_port_statistics
{
106 } __rte_cache_aligned
;
107 struct l2fwd_port_statistics port_statistics
[RTE_MAX_ETHPORTS
];
110 #define MAX_TIMER_PERIOD 86400
111 /* default period is 10 seconds */
112 static int64_t timer_period
= 10;
113 /* default timer frequency */
115 /* BURST_TX_DRAIN_US converted to cycles */
117 /* Convert cycles to ns */
119 cycles_to_ns(uint64_t cycles
)
123 t
*= (double)NS_PER_S
;
129 show_lcore_stats(unsigned lcore_id
)
131 struct lcore_queue_conf
*qconf
= &lcore_queue_conf
[lcore_id
];
132 struct rte_jobstats_context
*ctx
= &qconf
->jobs_context
;
133 struct rte_jobstats
*job
;
136 /* LCore statistics. */
137 uint64_t stats_period
, loop_count
;
138 uint64_t exec
, exec_min
, exec_max
;
139 uint64_t management
, management_min
, management_max
;
140 uint64_t busy
, busy_min
, busy_max
;
142 /* Jobs statistics. */
143 const uint16_t port_cnt
= qconf
->n_rx_port
;
144 uint64_t jobs_exec_cnt
[port_cnt
], jobs_period
[port_cnt
];
145 uint64_t jobs_exec
[port_cnt
], jobs_exec_min
[port_cnt
],
146 jobs_exec_max
[port_cnt
];
148 uint64_t flush_exec_cnt
, flush_period
;
149 uint64_t flush_exec
, flush_exec_min
, flush_exec_max
;
151 uint64_t idle_exec_cnt
;
152 uint64_t idle_exec
, idle_exec_min
, idle_exec_max
;
153 uint64_t collection_time
= rte_get_timer_cycles();
155 /* Ask forwarding thread to give us stats. */
156 rte_atomic16_set(&qconf
->stats_read_pending
, 1);
157 rte_spinlock_lock(&qconf
->lock
);
158 rte_atomic16_set(&qconf
->stats_read_pending
, 0);
160 /* Collect context statistics. */
161 stats_period
= ctx
->state_time
- ctx
->start_time
;
162 loop_count
= ctx
->loop_cnt
;
164 exec
= ctx
->exec_time
;
165 exec_min
= ctx
->min_exec_time
;
166 exec_max
= ctx
->max_exec_time
;
168 management
= ctx
->management_time
;
169 management_min
= ctx
->min_management_time
;
170 management_max
= ctx
->max_management_time
;
172 rte_jobstats_context_reset(ctx
);
174 for (i
= 0; i
< port_cnt
; i
++) {
175 job
= &qconf
->port_fwd_jobs
[i
];
177 jobs_exec_cnt
[i
] = job
->exec_cnt
;
178 jobs_period
[i
] = job
->period
;
180 jobs_exec
[i
] = job
->exec_time
;
181 jobs_exec_min
[i
] = job
->min_exec_time
;
182 jobs_exec_max
[i
] = job
->max_exec_time
;
184 rte_jobstats_reset(job
);
187 flush_exec_cnt
= qconf
->flush_job
.exec_cnt
;
188 flush_period
= qconf
->flush_job
.period
;
189 flush_exec
= qconf
->flush_job
.exec_time
;
190 flush_exec_min
= qconf
->flush_job
.min_exec_time
;
191 flush_exec_max
= qconf
->flush_job
.max_exec_time
;
192 rte_jobstats_reset(&qconf
->flush_job
);
194 idle_exec_cnt
= qconf
->idle_job
.exec_cnt
;
195 idle_exec
= qconf
->idle_job
.exec_time
;
196 idle_exec_min
= qconf
->idle_job
.min_exec_time
;
197 idle_exec_max
= qconf
->idle_job
.max_exec_time
;
198 rte_jobstats_reset(&qconf
->idle_job
);
200 rte_spinlock_unlock(&qconf
->lock
);
203 busy
= exec
+ management
;
204 busy_min
= exec_min
+ management_min
;
205 busy_max
= exec_max
+ management_max
;
208 collection_time
= rte_get_timer_cycles() - collection_time
;
210 #define STAT_FMT "\n%-18s %'14.0f %6.1f%% %'10.0f %'10.0f %'10.0f"
212 printf("\n----------------"
213 "\nLCore %3u: statistics (time in ns, collected in %'9.0f)"
214 "\n%-18s %14s %7s %10s %10s %10s "
216 "\n%-18s %'14" PRIu64
218 STAT_FMT
/* Management */
221 lcore_id
, cycles_to_ns(collection_time
),
222 "Stat type", "total", "%total", "avg", "min", "max",
223 "Stats duration:", cycles_to_ns(stats_period
),
224 "Loop count:", loop_count
,
226 cycles_to_ns(exec
), exec
* 100.0 / stats_period
,
227 cycles_to_ns(loop_count
? exec
/ loop_count
: 0),
228 cycles_to_ns(exec_min
),
229 cycles_to_ns(exec_max
),
231 cycles_to_ns(management
), management
* 100.0 / stats_period
,
232 cycles_to_ns(loop_count
? management
/ loop_count
: 0),
233 cycles_to_ns(management_min
),
234 cycles_to_ns(management_max
),
236 cycles_to_ns(busy
), busy
* 100.0 / stats_period
,
237 cycles_to_ns(loop_count
? busy
/ loop_count
: 0),
238 cycles_to_ns(busy_min
),
239 cycles_to_ns(busy_max
),
241 cycles_to_ns(idle_exec
), idle_exec
* 100.0 / stats_period
,
242 cycles_to_ns(idle_exec_cnt
? idle_exec
/ idle_exec_cnt
: 0),
243 cycles_to_ns(idle_exec_min
),
244 cycles_to_ns(idle_exec_max
));
246 for (i
= 0; i
< qconf
->n_rx_port
; i
++) {
247 job
= &qconf
->port_fwd_jobs
[i
];
248 printf("\n\nJob %" PRIu32
": %-20s "
249 "\n%-18s %'14" PRIu64
253 "Exec count:", jobs_exec_cnt
[i
],
254 "Exec period: ", cycles_to_ns(jobs_period
[i
]),
256 cycles_to_ns(jobs_exec
[i
]), jobs_exec
[i
] * 100.0 / stats_period
,
257 cycles_to_ns(jobs_exec_cnt
[i
] ? jobs_exec
[i
] / jobs_exec_cnt
[i
]
259 cycles_to_ns(jobs_exec_min
[i
]),
260 cycles_to_ns(jobs_exec_max
[i
]));
263 if (qconf
->n_rx_port
> 0) {
264 job
= &qconf
->flush_job
;
265 printf("\n\nJob %" PRIu32
": %-20s "
266 "\n%-18s %'14" PRIu64
270 "Exec count:", flush_exec_cnt
,
271 "Exec period: ", cycles_to_ns(flush_period
),
273 cycles_to_ns(flush_exec
), flush_exec
* 100.0 / stats_period
,
274 cycles_to_ns(flush_exec_cnt
? flush_exec
/ flush_exec_cnt
: 0),
275 cycles_to_ns(flush_exec_min
),
276 cycles_to_ns(flush_exec_max
));
280 /* Print out statistics on packets dropped */
282 show_stats_cb(__rte_unused
void *param
)
284 uint64_t total_packets_dropped
, total_packets_tx
, total_packets_rx
;
285 unsigned portid
, lcore_id
;
287 total_packets_dropped
= 0;
288 total_packets_tx
= 0;
289 total_packets_rx
= 0;
291 const char clr
[] = { 27, '[', '2', 'J', '\0' };
292 const char topLeft
[] = { 27, '[', '1', ';', '1', 'H', '\0' };
294 /* Clear screen and move to top left */
296 "\nPort statistics ===================================",
299 for (portid
= 0; portid
< RTE_MAX_ETHPORTS
; portid
++) {
300 /* skip disabled ports */
301 if ((l2fwd_enabled_port_mask
& (1 << portid
)) == 0)
303 printf("\nStatistics for port %u ------------------------------"
304 "\nPackets sent: %24"PRIu64
305 "\nPackets received: %20"PRIu64
306 "\nPackets dropped: %21"PRIu64
,
308 port_statistics
[portid
].tx
,
309 port_statistics
[portid
].rx
,
310 port_statistics
[portid
].dropped
);
312 total_packets_dropped
+= port_statistics
[portid
].dropped
;
313 total_packets_tx
+= port_statistics
[portid
].tx
;
314 total_packets_rx
+= port_statistics
[portid
].rx
;
317 printf("\nAggregate statistics ==============================="
318 "\nTotal packets sent: %18"PRIu64
319 "\nTotal packets received: %14"PRIu64
320 "\nTotal packets dropped: %15"PRIu64
321 "\n====================================================",
324 total_packets_dropped
);
326 RTE_LCORE_FOREACH(lcore_id
) {
327 if (lcore_queue_conf
[lcore_id
].n_rx_port
> 0)
328 show_lcore_stats(lcore_id
);
331 printf("\n====================================================\n");
332 rte_eal_alarm_set(timer_period
* US_PER_S
, show_stats_cb
, NULL
);
336 l2fwd_simple_forward(struct rte_mbuf
*m
, unsigned portid
)
338 struct rte_ether_hdr
*eth
;
342 struct rte_eth_dev_tx_buffer
*buffer
;
344 dst_port
= l2fwd_dst_ports
[portid
];
345 eth
= rte_pktmbuf_mtod(m
, struct rte_ether_hdr
*);
347 /* 02:00:00:00:00:xx */
348 tmp
= ð
->d_addr
.addr_bytes
[0];
349 *((uint64_t *)tmp
) = 0x000000000002 + ((uint64_t)dst_port
<< 40);
352 rte_ether_addr_copy(&l2fwd_ports_eth_addr
[dst_port
], ð
->s_addr
);
354 buffer
= tx_buffer
[dst_port
];
355 sent
= rte_eth_tx_buffer(dst_port
, 0, buffer
, m
);
357 port_statistics
[dst_port
].tx
+= sent
;
361 l2fwd_job_update_cb(struct rte_jobstats
*job
, int64_t result
)
363 int64_t err
= job
->target
- result
;
364 int64_t histeresis
= job
->target
/ 8;
366 if (err
< -histeresis
) {
367 if (job
->min_period
+ UPDATE_STEP_DOWN
< job
->period
)
368 job
->period
-= UPDATE_STEP_DOWN
;
369 } else if (err
> histeresis
) {
370 if (job
->period
+ UPDATE_STEP_UP
< job
->max_period
)
371 job
->period
+= UPDATE_STEP_UP
;
376 l2fwd_fwd_job(__rte_unused
struct rte_timer
*timer
, void *arg
)
378 struct rte_mbuf
*pkts_burst
[MAX_PKT_BURST
];
381 const uint16_t port_idx
= (uintptr_t) arg
;
382 const unsigned lcore_id
= rte_lcore_id();
383 struct lcore_queue_conf
*qconf
= &lcore_queue_conf
[lcore_id
];
384 struct rte_jobstats
*job
= &qconf
->port_fwd_jobs
[port_idx
];
385 const uint16_t portid
= qconf
->rx_port_list
[port_idx
];
388 uint16_t total_nb_rx
;
390 rte_jobstats_start(&qconf
->jobs_context
, job
);
392 /* Call rx burst 2 times. This allow rte_jobstats logic to see if this
393 * function must be called more frequently. */
395 total_nb_rx
= rte_eth_rx_burst(portid
, 0, pkts_burst
,
398 for (j
= 0; j
< total_nb_rx
; j
++) {
400 rte_prefetch0(rte_pktmbuf_mtod(m
, void *));
401 l2fwd_simple_forward(m
, portid
);
404 if (total_nb_rx
== MAX_PKT_BURST
) {
405 const uint16_t nb_rx
= rte_eth_rx_burst(portid
, 0, pkts_burst
,
408 total_nb_rx
+= nb_rx
;
409 for (j
= 0; j
< nb_rx
; j
++) {
411 rte_prefetch0(rte_pktmbuf_mtod(m
, void *));
412 l2fwd_simple_forward(m
, portid
);
416 port_statistics
[portid
].rx
+= total_nb_rx
;
418 /* Adjust period time in which we are running here. */
419 if (rte_jobstats_finish(job
, total_nb_rx
) != 0) {
420 rte_timer_reset(&qconf
->rx_timers
[port_idx
], job
->period
, PERIODICAL
,
421 lcore_id
, l2fwd_fwd_job
, arg
);
426 l2fwd_flush_job(__rte_unused
struct rte_timer
*timer
, __rte_unused
void *arg
)
430 struct lcore_queue_conf
*qconf
;
434 struct rte_eth_dev_tx_buffer
*buffer
;
436 lcore_id
= rte_lcore_id();
437 qconf
= &lcore_queue_conf
[lcore_id
];
439 rte_jobstats_start(&qconf
->jobs_context
, &qconf
->flush_job
);
441 now
= rte_get_timer_cycles();
442 lcore_id
= rte_lcore_id();
443 qconf
= &lcore_queue_conf
[lcore_id
];
445 for (i
= 0; i
< qconf
->n_rx_port
; i
++) {
446 portid
= l2fwd_dst_ports
[qconf
->rx_port_list
[i
]];
448 if (qconf
->next_flush_time
[portid
] <= now
)
451 buffer
= tx_buffer
[portid
];
452 sent
= rte_eth_tx_buffer_flush(portid
, 0, buffer
);
454 port_statistics
[portid
].tx
+= sent
;
456 qconf
->next_flush_time
[portid
] = rte_get_timer_cycles() + drain_tsc
;
459 /* Pass target to indicate that this job is happy of time interwal
460 * in which it was called. */
461 rte_jobstats_finish(&qconf
->flush_job
, qconf
->flush_job
.target
);
464 /* main processing loop */
466 l2fwd_main_loop(void)
470 struct lcore_queue_conf
*qconf
;
471 uint8_t stats_read_pending
= 0;
474 lcore_id
= rte_lcore_id();
475 qconf
= &lcore_queue_conf
[lcore_id
];
477 if (qconf
->n_rx_port
== 0) {
478 RTE_LOG(INFO
, L2FWD
, "lcore %u has nothing to do\n", lcore_id
);
482 RTE_LOG(INFO
, L2FWD
, "entering main loop on lcore %u\n", lcore_id
);
484 for (i
= 0; i
< qconf
->n_rx_port
; i
++) {
486 portid
= qconf
->rx_port_list
[i
];
487 RTE_LOG(INFO
, L2FWD
, " -- lcoreid=%u portid=%u\n", lcore_id
,
491 rte_jobstats_init(&qconf
->idle_job
, "idle", 0, 0, 0, 0);
494 rte_spinlock_lock(&qconf
->lock
);
497 rte_jobstats_context_start(&qconf
->jobs_context
);
500 * - Read stats_read_pending flag
501 * - check if some real job need to be executed
503 rte_jobstats_start(&qconf
->jobs_context
, &qconf
->idle_job
);
505 uint64_t repeats
= 0;
509 uint64_t now
= rte_get_timer_cycles();
512 need_manage
= qconf
->flush_timer
.expire
< now
;
513 /* Check if we was esked to give a stats. */
515 rte_atomic16_read(&qconf
->stats_read_pending
);
516 need_manage
|= stats_read_pending
;
518 for (i
= 0; i
< qconf
->n_rx_port
&& !need_manage
; i
++)
519 need_manage
= qconf
->rx_timers
[i
].expire
< now
;
521 } while (!need_manage
);
523 if (likely(repeats
!= 1))
524 rte_jobstats_finish(&qconf
->idle_job
, qconf
->idle_job
.target
);
526 rte_jobstats_abort(&qconf
->idle_job
);
529 rte_jobstats_context_finish(&qconf
->jobs_context
);
530 } while (likely(stats_read_pending
== 0));
532 rte_spinlock_unlock(&qconf
->lock
);
538 l2fwd_launch_one_lcore(__rte_unused
void *dummy
)
546 l2fwd_usage(const char *prgname
)
548 printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
549 " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
550 " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
551 " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
552 " -l set system default locale instead of default (\"C\" locale) for thousands separator in stats.",
557 l2fwd_parse_portmask(const char *portmask
)
562 /* parse hexadecimal string */
563 pm
= strtoul(portmask
, &end
, 16);
564 if ((portmask
[0] == '\0') || (end
== NULL
) || (*end
!= '\0'))
574 l2fwd_parse_nqueue(const char *q_arg
)
579 /* parse hexadecimal string */
580 n
= strtoul(q_arg
, &end
, 10);
581 if ((q_arg
[0] == '\0') || (end
== NULL
) || (*end
!= '\0'))
585 if (n
>= MAX_RX_QUEUE_PER_LCORE
)
592 l2fwd_parse_timer_period(const char *q_arg
)
597 /* parse number string */
598 n
= strtol(q_arg
, &end
, 10);
599 if ((q_arg
[0] == '\0') || (end
== NULL
) || (*end
!= '\0'))
601 if (n
>= MAX_TIMER_PERIOD
)
607 /* Parse the argument given in the command line of the application */
609 l2fwd_parse_args(int argc
, char **argv
)
614 char *prgname
= argv
[0];
615 static struct option lgopts
[] = {
621 while ((opt
= getopt_long(argc
, argvopt
, "p:q:T:l",
622 lgopts
, &option_index
)) != EOF
) {
627 l2fwd_enabled_port_mask
= l2fwd_parse_portmask(optarg
);
628 if (l2fwd_enabled_port_mask
== 0) {
629 printf("invalid portmask\n");
630 l2fwd_usage(prgname
);
637 l2fwd_rx_queue_per_lcore
= l2fwd_parse_nqueue(optarg
);
638 if (l2fwd_rx_queue_per_lcore
== 0) {
639 printf("invalid queue number\n");
640 l2fwd_usage(prgname
);
647 timer_period
= l2fwd_parse_timer_period(optarg
);
648 if (timer_period
< 0) {
649 printf("invalid timer period\n");
650 l2fwd_usage(prgname
);
655 /* For thousands separator in printf. */
657 setlocale(LC_ALL
, "");
662 l2fwd_usage(prgname
);
666 l2fwd_usage(prgname
);
672 argv
[optind
-1] = prgname
;
675 optind
= 1; /* reset getopt lib */
679 /* Check the link status of all ports in up to 9s, and print them finally */
681 check_all_ports_link_status(uint32_t port_mask
)
683 #define CHECK_INTERVAL 100 /* 100ms */
684 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
686 uint8_t count
, all_ports_up
, print_flag
= 0;
687 struct rte_eth_link link
;
690 printf("\nChecking link status");
692 for (count
= 0; count
<= MAX_CHECK_TIME
; count
++) {
694 RTE_ETH_FOREACH_DEV(portid
) {
695 if ((port_mask
& (1 << portid
)) == 0)
697 memset(&link
, 0, sizeof(link
));
698 ret
= rte_eth_link_get_nowait(portid
, &link
);
702 printf("Port %u link get failed: %s\n",
703 portid
, rte_strerror(-ret
));
706 /* print link status if flag set */
707 if (print_flag
== 1) {
708 if (link
.link_status
)
710 "Port%d Link Up. Speed %u Mbps - %s\n",
711 portid
, link
.link_speed
,
712 (link
.link_duplex
== ETH_LINK_FULL_DUPLEX
) ?
713 ("full-duplex") : ("half-duplex"));
715 printf("Port %d Link Down\n", portid
);
718 /* clear all_ports_up flag if any link down */
719 if (link
.link_status
== ETH_LINK_DOWN
) {
724 /* after finally printing all link status, get out */
728 if (all_ports_up
== 0) {
731 rte_delay_ms(CHECK_INTERVAL
);
734 /* set the print_flag if all ports up or timeout */
735 if (all_ports_up
== 1 || count
== (MAX_CHECK_TIME
- 1)) {
743 main(int argc
, char **argv
)
745 struct lcore_queue_conf
*qconf
;
746 unsigned lcore_id
, rx_lcore_id
;
747 unsigned nb_ports_in_mask
= 0;
749 char name
[RTE_JOBSTATS_NAMESIZE
];
751 uint16_t nb_ports_available
= 0;
752 uint16_t portid
, last_port
;
756 ret
= rte_eal_init(argc
, argv
);
758 rte_exit(EXIT_FAILURE
, "Invalid EAL arguments\n");
762 /* parse application arguments (after the EAL ones) */
763 ret
= l2fwd_parse_args(argc
, argv
);
765 rte_exit(EXIT_FAILURE
, "Invalid L2FWD arguments\n");
767 rte_timer_subsystem_init();
769 /* fetch default timer frequency. */
770 hz
= rte_get_timer_hz();
772 /* create the mbuf pool */
774 rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF
, 32,
775 0, RTE_MBUF_DEFAULT_BUF_SIZE
, rte_socket_id());
776 if (l2fwd_pktmbuf_pool
== NULL
)
777 rte_exit(EXIT_FAILURE
, "Cannot init mbuf pool\n");
779 nb_ports
= rte_eth_dev_count_avail();
781 rte_exit(EXIT_FAILURE
, "No Ethernet ports - bye\n");
783 /* reset l2fwd_dst_ports */
784 for (portid
= 0; portid
< RTE_MAX_ETHPORTS
; portid
++)
785 l2fwd_dst_ports
[portid
] = 0;
789 * Each logical core is assigned a dedicated TX queue on each port.
791 RTE_ETH_FOREACH_DEV(portid
) {
792 /* skip ports that are not enabled */
793 if ((l2fwd_enabled_port_mask
& (1 << portid
)) == 0)
796 if (nb_ports_in_mask
% 2) {
797 l2fwd_dst_ports
[portid
] = last_port
;
798 l2fwd_dst_ports
[last_port
] = portid
;
804 if (nb_ports_in_mask
% 2) {
805 printf("Notice: odd number of ports in portmask.\n");
806 l2fwd_dst_ports
[last_port
] = last_port
;
812 /* Initialize the port/queue configuration of each logical core */
813 RTE_ETH_FOREACH_DEV(portid
) {
814 /* skip ports that are not enabled */
815 if ((l2fwd_enabled_port_mask
& (1 << portid
)) == 0)
818 /* get the lcore_id for this port */
819 while (rte_lcore_is_enabled(rx_lcore_id
) == 0 ||
820 lcore_queue_conf
[rx_lcore_id
].n_rx_port
==
821 l2fwd_rx_queue_per_lcore
) {
823 if (rx_lcore_id
>= RTE_MAX_LCORE
)
824 rte_exit(EXIT_FAILURE
, "Not enough cores\n");
827 if (qconf
!= &lcore_queue_conf
[rx_lcore_id
])
828 /* Assigned a new logical core in the loop above. */
829 qconf
= &lcore_queue_conf
[rx_lcore_id
];
831 qconf
->rx_port_list
[qconf
->n_rx_port
] = portid
;
833 printf("Lcore %u: RX port %u\n", rx_lcore_id
, portid
);
836 /* Initialise each port */
837 RTE_ETH_FOREACH_DEV(portid
) {
838 struct rte_eth_dev_info dev_info
;
839 struct rte_eth_rxconf rxq_conf
;
840 struct rte_eth_txconf txq_conf
;
841 struct rte_eth_conf local_port_conf
= port_conf
;
843 /* skip ports that are not enabled */
844 if ((l2fwd_enabled_port_mask
& (1 << portid
)) == 0) {
845 printf("Skipping disabled port %u\n", portid
);
848 nb_ports_available
++;
851 printf("Initializing port %u... ", portid
);
854 ret
= rte_eth_dev_info_get(portid
, &dev_info
);
856 rte_exit(EXIT_FAILURE
,
857 "Error during getting device (port %u) info: %s\n",
858 portid
, strerror(-ret
));
860 if (dev_info
.tx_offload_capa
& DEV_TX_OFFLOAD_MBUF_FAST_FREE
)
861 local_port_conf
.txmode
.offloads
|=
862 DEV_TX_OFFLOAD_MBUF_FAST_FREE
;
863 ret
= rte_eth_dev_configure(portid
, 1, 1, &local_port_conf
);
865 rte_exit(EXIT_FAILURE
, "Cannot configure device: err=%d, port=%u\n",
868 ret
= rte_eth_dev_adjust_nb_rx_tx_desc(portid
, &nb_rxd
,
871 rte_exit(EXIT_FAILURE
,
872 "Cannot adjust number of descriptors: err=%d, port=%u\n",
875 ret
= rte_eth_macaddr_get(portid
,
876 &l2fwd_ports_eth_addr
[portid
]);
878 rte_exit(EXIT_FAILURE
,
879 "Cannot get MAC address: err=%d, port=%u\n",
882 /* init one RX queue */
884 rxq_conf
= dev_info
.default_rxconf
;
885 rxq_conf
.offloads
= local_port_conf
.rxmode
.offloads
;
886 ret
= rte_eth_rx_queue_setup(portid
, 0, nb_rxd
,
887 rte_eth_dev_socket_id(portid
),
891 rte_exit(EXIT_FAILURE
, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
894 /* init one TX queue on each port */
895 txq_conf
= dev_info
.default_txconf
;
896 txq_conf
.offloads
= local_port_conf
.txmode
.offloads
;
898 ret
= rte_eth_tx_queue_setup(portid
, 0, nb_txd
,
899 rte_eth_dev_socket_id(portid
),
902 rte_exit(EXIT_FAILURE
,
903 "rte_eth_tx_queue_setup:err=%d, port=%u\n",
906 /* Initialize TX buffers */
907 tx_buffer
[portid
] = rte_zmalloc_socket("tx_buffer",
908 RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST
), 0,
909 rte_eth_dev_socket_id(portid
));
910 if (tx_buffer
[portid
] == NULL
)
911 rte_exit(EXIT_FAILURE
, "Cannot allocate buffer for tx on port %u\n",
914 rte_eth_tx_buffer_init(tx_buffer
[portid
], MAX_PKT_BURST
);
916 ret
= rte_eth_tx_buffer_set_err_callback(tx_buffer
[portid
],
917 rte_eth_tx_buffer_count_callback
,
918 &port_statistics
[portid
].dropped
);
920 rte_exit(EXIT_FAILURE
,
921 "Cannot set error callback for tx buffer on port %u\n",
925 ret
= rte_eth_dev_start(portid
);
927 rte_exit(EXIT_FAILURE
, "rte_eth_dev_start:err=%d, port=%u\n",
932 ret
= rte_eth_promiscuous_enable(portid
);
934 rte_exit(EXIT_FAILURE
,
935 "rte_eth_promiscuous_enable:err=%s, port=%u\n",
936 rte_strerror(-ret
), portid
);
941 printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
943 l2fwd_ports_eth_addr
[portid
].addr_bytes
[0],
944 l2fwd_ports_eth_addr
[portid
].addr_bytes
[1],
945 l2fwd_ports_eth_addr
[portid
].addr_bytes
[2],
946 l2fwd_ports_eth_addr
[portid
].addr_bytes
[3],
947 l2fwd_ports_eth_addr
[portid
].addr_bytes
[4],
948 l2fwd_ports_eth_addr
[portid
].addr_bytes
[5]);
950 /* initialize port stats */
951 memset(&port_statistics
, 0, sizeof(port_statistics
));
954 if (!nb_ports_available
) {
955 rte_exit(EXIT_FAILURE
,
956 "All available ports are disabled. Please set portmask.\n");
959 check_all_ports_link_status(l2fwd_enabled_port_mask
);
961 drain_tsc
= (hz
+ US_PER_S
- 1) / US_PER_S
* BURST_TX_DRAIN_US
;
963 RTE_LCORE_FOREACH(lcore_id
) {
964 qconf
= &lcore_queue_conf
[lcore_id
];
966 rte_spinlock_init(&qconf
->lock
);
968 if (rte_jobstats_context_init(&qconf
->jobs_context
) != 0)
969 rte_panic("Jobs stats context for core %u init failed\n", lcore_id
);
971 if (qconf
->n_rx_port
== 0) {
973 "lcore %u: no ports so no jobs stats context initialization\n",
978 * Set fixed period by setting min = max = initial period. Set target to
979 * zero as it is irrelevant for this job. */
980 rte_jobstats_init(&qconf
->flush_job
, "flush", drain_tsc
, drain_tsc
,
983 rte_timer_init(&qconf
->flush_timer
);
984 ret
= rte_timer_reset(&qconf
->flush_timer
, drain_tsc
, PERIODICAL
,
985 lcore_id
, &l2fwd_flush_job
, NULL
);
988 rte_exit(1, "Failed to reset flush job timer for lcore %u: %s",
989 lcore_id
, rte_strerror(-ret
));
992 for (i
= 0; i
< qconf
->n_rx_port
; i
++) {
993 struct rte_jobstats
*job
= &qconf
->port_fwd_jobs
[i
];
995 portid
= qconf
->rx_port_list
[i
];
996 printf("Setting forward job for port %u\n", portid
);
998 snprintf(name
, RTE_DIM(name
), "port %u fwd", portid
);
999 /* Setup forward job.
1000 * Set min, max and initial period. Set target to MAX_PKT_BURST as
1001 * this is desired optimal RX/TX burst size. */
1002 rte_jobstats_init(job
, name
, 0, drain_tsc
, 0, MAX_PKT_BURST
);
1003 rte_jobstats_set_update_period_function(job
, l2fwd_job_update_cb
);
1005 rte_timer_init(&qconf
->rx_timers
[i
]);
1006 ret
= rte_timer_reset(&qconf
->rx_timers
[i
], 0, PERIODICAL
, lcore_id
,
1007 &l2fwd_fwd_job
, (void *)(uintptr_t)i
);
1010 rte_exit(1, "Failed to reset lcore %u port %u job timer: %s",
1011 lcore_id
, qconf
->rx_port_list
[i
], rte_strerror(-ret
));
1017 rte_eal_alarm_set(timer_period
* MS_PER_S
, show_stats_cb
, NULL
);
1019 RTE_LOG(INFO
, L2FWD
, "Stats display disabled\n");
1021 /* launch per-lcore init on every lcore */
1022 rte_eal_mp_remote_launch(l2fwd_launch_one_lcore
, NULL
, CALL_MASTER
);
1023 RTE_LCORE_FOREACH_SLAVE(lcore_id
) {
1024 if (rte_eal_wait_lcore(lcore_id
) < 0)