1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606 * Copyright(c) 2010-2016 Intel Corporation
3a9643ea8Slogwang */
4a9643ea8Slogwang
5a9643ea8Slogwang #include <stdio.h>
6a9643ea8Slogwang #include <stdlib.h>
7a9643ea8Slogwang #include <string.h>
8a9643ea8Slogwang #include <stdint.h>
9a9643ea8Slogwang #include <inttypes.h>
10a9643ea8Slogwang #include <sys/types.h>
11a9643ea8Slogwang #include <sys/queue.h>
12a9643ea8Slogwang #include <netinet/in.h>
13a9643ea8Slogwang #include <setjmp.h>
14a9643ea8Slogwang #include <stdarg.h>
15a9643ea8Slogwang #include <ctype.h>
16a9643ea8Slogwang #include <errno.h>
17a9643ea8Slogwang #include <getopt.h>
18a9643ea8Slogwang
19a9643ea8Slogwang #include <rte_common.h>
20a9643ea8Slogwang #include <rte_log.h>
21a9643ea8Slogwang #include <rte_malloc.h>
22a9643ea8Slogwang #include <rte_memory.h>
23a9643ea8Slogwang #include <rte_memcpy.h>
24a9643ea8Slogwang #include <rte_eal.h>
25a9643ea8Slogwang #include <rte_launch.h>
26a9643ea8Slogwang #include <rte_atomic.h>
27a9643ea8Slogwang #include <rte_cycles.h>
28a9643ea8Slogwang #include <rte_prefetch.h>
29a9643ea8Slogwang #include <rte_lcore.h>
30a9643ea8Slogwang #include <rte_per_lcore.h>
31a9643ea8Slogwang #include <rte_branch_prediction.h>
32a9643ea8Slogwang #include <rte_interrupts.h>
33a9643ea8Slogwang #include <rte_random.h>
34a9643ea8Slogwang #include <rte_debug.h>
35a9643ea8Slogwang #include <rte_ether.h>
36a9643ea8Slogwang #include <rte_ethdev.h>
37a9643ea8Slogwang #include <rte_mempool.h>
38a9643ea8Slogwang #include <rte_mbuf.h>
39a9643ea8Slogwang
40a9643ea8Slogwang #define RTE_LOGTYPE_LSI RTE_LOGTYPE_USER1
41a9643ea8Slogwang
42a9643ea8Slogwang #define NB_MBUF 8192
43a9643ea8Slogwang
44a9643ea8Slogwang #define MAX_PKT_BURST 32
45a9643ea8Slogwang #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
46a9643ea8Slogwang
47a9643ea8Slogwang /*
48a9643ea8Slogwang * Configurable number of RX/TX ring descriptors
49a9643ea8Slogwang */
50d30ea906Sjfb8856606 #define RTE_TEST_RX_DESC_DEFAULT 1024
51d30ea906Sjfb8856606 #define RTE_TEST_TX_DESC_DEFAULT 1024
52a9643ea8Slogwang static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
53a9643ea8Slogwang static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
54a9643ea8Slogwang
55a9643ea8Slogwang /* ethernet addresses of ports */
564418919fSjohnjiang static struct rte_ether_addr lsi_ports_eth_addr[RTE_MAX_ETHPORTS];
57a9643ea8Slogwang
58a9643ea8Slogwang /* mask of enabled ports */
59a9643ea8Slogwang static uint32_t lsi_enabled_port_mask = 0;
60a9643ea8Slogwang
61a9643ea8Slogwang static unsigned int lsi_rx_queue_per_lcore = 1;
62a9643ea8Slogwang
63a9643ea8Slogwang /* destination port for L2 forwarding */
64a9643ea8Slogwang static unsigned lsi_dst_ports[RTE_MAX_ETHPORTS] = {0};
65a9643ea8Slogwang
66a9643ea8Slogwang #define MAX_PKT_BURST 32
67a9643ea8Slogwang
68a9643ea8Slogwang #define MAX_RX_QUEUE_PER_LCORE 16
69a9643ea8Slogwang #define MAX_TX_QUEUE_PER_PORT 16
70a9643ea8Slogwang struct lcore_queue_conf {
71a9643ea8Slogwang unsigned n_rx_port;
72a9643ea8Slogwang unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
73a9643ea8Slogwang unsigned tx_queue_id;
74a9643ea8Slogwang } __rte_cache_aligned;
75a9643ea8Slogwang struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
76a9643ea8Slogwang
77a9643ea8Slogwang struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
78a9643ea8Slogwang
79d30ea906Sjfb8856606 static struct rte_eth_conf port_conf = {
80a9643ea8Slogwang .rxmode = {
81a9643ea8Slogwang .split_hdr_size = 0,
82a9643ea8Slogwang },
83a9643ea8Slogwang .txmode = {
84a9643ea8Slogwang .mq_mode = ETH_MQ_TX_NONE,
85a9643ea8Slogwang },
86a9643ea8Slogwang .intr_conf = {
87a9643ea8Slogwang .lsc = 1, /**< lsc interrupt feature enabled */
88a9643ea8Slogwang },
89a9643ea8Slogwang };
90a9643ea8Slogwang
91a9643ea8Slogwang struct rte_mempool * lsi_pktmbuf_pool = NULL;
92a9643ea8Slogwang
93a9643ea8Slogwang /* Per-port statistics struct */
94a9643ea8Slogwang struct lsi_port_statistics {
95a9643ea8Slogwang uint64_t tx;
96a9643ea8Slogwang uint64_t rx;
97a9643ea8Slogwang uint64_t dropped;
98a9643ea8Slogwang } __rte_cache_aligned;
99a9643ea8Slogwang struct lsi_port_statistics port_statistics[RTE_MAX_ETHPORTS];
100a9643ea8Slogwang
101a9643ea8Slogwang /* A tsc-based timer responsible for triggering statistics printout */
102a9643ea8Slogwang #define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
103a9643ea8Slogwang #define MAX_TIMER_PERIOD 86400 /* 1 day max */
104a9643ea8Slogwang static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
105a9643ea8Slogwang
106a9643ea8Slogwang /* Print out statistics on packets dropped */
107a9643ea8Slogwang static void
print_stats(void)108a9643ea8Slogwang print_stats(void)
109a9643ea8Slogwang {
110a9643ea8Slogwang struct rte_eth_link link;
111a9643ea8Slogwang uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
1122bfe3f2eSlogwang uint16_t portid;
113a9643ea8Slogwang
114a9643ea8Slogwang total_packets_dropped = 0;
115a9643ea8Slogwang total_packets_tx = 0;
116a9643ea8Slogwang total_packets_rx = 0;
117a9643ea8Slogwang
118a9643ea8Slogwang const char clr[] = { 27, '[', '2', 'J', '\0' };
119a9643ea8Slogwang const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
1204418919fSjohnjiang int link_get_err;
121a9643ea8Slogwang
122a9643ea8Slogwang /* Clear screen and move to top left */
123a9643ea8Slogwang printf("%s%s", clr, topLeft);
124a9643ea8Slogwang
125a9643ea8Slogwang printf("\nPort statistics ====================================");
126a9643ea8Slogwang
127a9643ea8Slogwang for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
128a9643ea8Slogwang /* skip ports that are not enabled */
129a9643ea8Slogwang if ((lsi_enabled_port_mask & (1 << portid)) == 0)
130a9643ea8Slogwang continue;
131a9643ea8Slogwang
132a9643ea8Slogwang memset(&link, 0, sizeof(link));
1334418919fSjohnjiang link_get_err = rte_eth_link_get_nowait(portid, &link);
134a9643ea8Slogwang printf("\nStatistics for port %u ------------------------------"
135a9643ea8Slogwang "\nLink status: %25s"
136*2d9fd380Sjfb8856606 "\nLink speed: %26s"
137a9643ea8Slogwang "\nLink duplex: %25s"
138a9643ea8Slogwang "\nPackets sent: %24"PRIu64
139a9643ea8Slogwang "\nPackets received: %20"PRIu64
140a9643ea8Slogwang "\nPackets dropped: %21"PRIu64,
141a9643ea8Slogwang portid,
1424418919fSjohnjiang link_get_err < 0 ? "Link get failed" :
143a9643ea8Slogwang (link.link_status ? "Link up" : "Link down"),
144*2d9fd380Sjfb8856606 link_get_err < 0 ? "0" :
145*2d9fd380Sjfb8856606 rte_eth_link_speed_to_str(link.link_speed),
1464418919fSjohnjiang link_get_err < 0 ? "Link get failed" :
147a9643ea8Slogwang (link.link_duplex == ETH_LINK_FULL_DUPLEX ? \
148a9643ea8Slogwang "full-duplex" : "half-duplex"),
149a9643ea8Slogwang port_statistics[portid].tx,
150a9643ea8Slogwang port_statistics[portid].rx,
151a9643ea8Slogwang port_statistics[portid].dropped);
152a9643ea8Slogwang
153a9643ea8Slogwang total_packets_dropped += port_statistics[portid].dropped;
154a9643ea8Slogwang total_packets_tx += port_statistics[portid].tx;
155a9643ea8Slogwang total_packets_rx += port_statistics[portid].rx;
156a9643ea8Slogwang }
157a9643ea8Slogwang printf("\nAggregate statistics ==============================="
158a9643ea8Slogwang "\nTotal packets sent: %18"PRIu64
159a9643ea8Slogwang "\nTotal packets received: %14"PRIu64
160a9643ea8Slogwang "\nTotal packets dropped: %15"PRIu64,
161a9643ea8Slogwang total_packets_tx,
162a9643ea8Slogwang total_packets_rx,
163a9643ea8Slogwang total_packets_dropped);
164a9643ea8Slogwang printf("\n====================================================\n");
1650c6bd470Sfengbojiang
1660c6bd470Sfengbojiang fflush(stdout);
167a9643ea8Slogwang }
168a9643ea8Slogwang
169a9643ea8Slogwang static void
lsi_simple_forward(struct rte_mbuf * m,unsigned portid)170a9643ea8Slogwang lsi_simple_forward(struct rte_mbuf *m, unsigned portid)
171a9643ea8Slogwang {
1724418919fSjohnjiang struct rte_ether_hdr *eth;
173a9643ea8Slogwang void *tmp;
174a9643ea8Slogwang unsigned dst_port = lsi_dst_ports[portid];
175a9643ea8Slogwang int sent;
176a9643ea8Slogwang struct rte_eth_dev_tx_buffer *buffer;
177a9643ea8Slogwang
1784418919fSjohnjiang eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
179a9643ea8Slogwang
180a9643ea8Slogwang /* 02:00:00:00:00:xx */
181a9643ea8Slogwang tmp = ð->d_addr.addr_bytes[0];
182a9643ea8Slogwang *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
183a9643ea8Slogwang
184a9643ea8Slogwang /* src addr */
1854418919fSjohnjiang rte_ether_addr_copy(&lsi_ports_eth_addr[dst_port], ð->s_addr);
186a9643ea8Slogwang
187a9643ea8Slogwang buffer = tx_buffer[dst_port];
188a9643ea8Slogwang sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
189a9643ea8Slogwang if (sent)
190a9643ea8Slogwang port_statistics[dst_port].tx += sent;
191a9643ea8Slogwang }
192a9643ea8Slogwang
193a9643ea8Slogwang /* main processing loop */
194a9643ea8Slogwang static void
lsi_main_loop(void)195a9643ea8Slogwang lsi_main_loop(void)
196a9643ea8Slogwang {
197a9643ea8Slogwang struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
198a9643ea8Slogwang struct rte_mbuf *m;
199a9643ea8Slogwang unsigned lcore_id;
200a9643ea8Slogwang unsigned sent;
201a9643ea8Slogwang uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
202a9643ea8Slogwang unsigned i, j, portid, nb_rx;
203a9643ea8Slogwang struct lcore_queue_conf *qconf;
204a9643ea8Slogwang const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
205a9643ea8Slogwang BURST_TX_DRAIN_US;
206a9643ea8Slogwang struct rte_eth_dev_tx_buffer *buffer;
207a9643ea8Slogwang
208a9643ea8Slogwang prev_tsc = 0;
209a9643ea8Slogwang timer_tsc = 0;
210a9643ea8Slogwang
211a9643ea8Slogwang lcore_id = rte_lcore_id();
212a9643ea8Slogwang qconf = &lcore_queue_conf[lcore_id];
213a9643ea8Slogwang
214a9643ea8Slogwang if (qconf->n_rx_port == 0) {
215a9643ea8Slogwang RTE_LOG(INFO, LSI, "lcore %u has nothing to do\n", lcore_id);
216a9643ea8Slogwang return;
217a9643ea8Slogwang }
218a9643ea8Slogwang
219a9643ea8Slogwang RTE_LOG(INFO, LSI, "entering main loop on lcore %u\n", lcore_id);
220a9643ea8Slogwang
221a9643ea8Slogwang for (i = 0; i < qconf->n_rx_port; i++) {
222a9643ea8Slogwang
223a9643ea8Slogwang portid = qconf->rx_port_list[i];
224a9643ea8Slogwang RTE_LOG(INFO, LSI, " -- lcoreid=%u portid=%u\n", lcore_id,
225a9643ea8Slogwang portid);
226a9643ea8Slogwang }
227a9643ea8Slogwang
228a9643ea8Slogwang while (1) {
229a9643ea8Slogwang
230a9643ea8Slogwang cur_tsc = rte_rdtsc();
231a9643ea8Slogwang
232a9643ea8Slogwang /*
233a9643ea8Slogwang * TX burst queue drain
234a9643ea8Slogwang */
235a9643ea8Slogwang diff_tsc = cur_tsc - prev_tsc;
236a9643ea8Slogwang if (unlikely(diff_tsc > drain_tsc)) {
237a9643ea8Slogwang
238a9643ea8Slogwang for (i = 0; i < qconf->n_rx_port; i++) {
239a9643ea8Slogwang
240a9643ea8Slogwang portid = lsi_dst_ports[qconf->rx_port_list[i]];
241a9643ea8Slogwang buffer = tx_buffer[portid];
242a9643ea8Slogwang
243a9643ea8Slogwang sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
244a9643ea8Slogwang if (sent)
245a9643ea8Slogwang port_statistics[portid].tx += sent;
246a9643ea8Slogwang
247a9643ea8Slogwang }
248a9643ea8Slogwang
249a9643ea8Slogwang /* if timer is enabled */
250a9643ea8Slogwang if (timer_period > 0) {
251a9643ea8Slogwang
252a9643ea8Slogwang /* advance the timer */
253a9643ea8Slogwang timer_tsc += diff_tsc;
254a9643ea8Slogwang
255a9643ea8Slogwang /* if timer has reached its timeout */
256a9643ea8Slogwang if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
257a9643ea8Slogwang
258*2d9fd380Sjfb8856606 /* do this only on main core */
259*2d9fd380Sjfb8856606 if (lcore_id == rte_get_main_lcore()) {
260a9643ea8Slogwang print_stats();
261a9643ea8Slogwang /* reset the timer */
262a9643ea8Slogwang timer_tsc = 0;
263a9643ea8Slogwang }
264a9643ea8Slogwang }
265a9643ea8Slogwang }
266a9643ea8Slogwang
267a9643ea8Slogwang prev_tsc = cur_tsc;
268a9643ea8Slogwang }
269a9643ea8Slogwang
270a9643ea8Slogwang /*
271a9643ea8Slogwang * Read packet from RX queues
272a9643ea8Slogwang */
273a9643ea8Slogwang for (i = 0; i < qconf->n_rx_port; i++) {
274a9643ea8Slogwang
275a9643ea8Slogwang portid = qconf->rx_port_list[i];
276a9643ea8Slogwang nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
277a9643ea8Slogwang pkts_burst, MAX_PKT_BURST);
278a9643ea8Slogwang
279a9643ea8Slogwang port_statistics[portid].rx += nb_rx;
280a9643ea8Slogwang
281a9643ea8Slogwang for (j = 0; j < nb_rx; j++) {
282a9643ea8Slogwang m = pkts_burst[j];
283a9643ea8Slogwang rte_prefetch0(rte_pktmbuf_mtod(m, void *));
284a9643ea8Slogwang lsi_simple_forward(m, portid);
285a9643ea8Slogwang }
286a9643ea8Slogwang }
287a9643ea8Slogwang }
288a9643ea8Slogwang }
289a9643ea8Slogwang
290a9643ea8Slogwang static int
lsi_launch_one_lcore(__rte_unused void * dummy)291*2d9fd380Sjfb8856606 lsi_launch_one_lcore(__rte_unused void *dummy)
292a9643ea8Slogwang {
293a9643ea8Slogwang lsi_main_loop();
294a9643ea8Slogwang return 0;
295a9643ea8Slogwang }
296a9643ea8Slogwang
297a9643ea8Slogwang /* display usage */
298a9643ea8Slogwang static void
lsi_usage(const char * prgname)299a9643ea8Slogwang lsi_usage(const char *prgname)
300a9643ea8Slogwang {
301a9643ea8Slogwang printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
302a9643ea8Slogwang " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
303a9643ea8Slogwang " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
304a9643ea8Slogwang " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
305a9643ea8Slogwang prgname);
306a9643ea8Slogwang }
307a9643ea8Slogwang
308a9643ea8Slogwang static int
lsi_parse_portmask(const char * portmask)309a9643ea8Slogwang lsi_parse_portmask(const char *portmask)
310a9643ea8Slogwang {
311a9643ea8Slogwang char *end = NULL;
312a9643ea8Slogwang unsigned long pm;
313a9643ea8Slogwang
314a9643ea8Slogwang /* parse hexadecimal string */
315a9643ea8Slogwang pm = strtoul(portmask, &end, 16);
316a9643ea8Slogwang if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
317*2d9fd380Sjfb8856606 return 0;
318a9643ea8Slogwang
319a9643ea8Slogwang return pm;
320a9643ea8Slogwang }
321a9643ea8Slogwang
322a9643ea8Slogwang static unsigned int
lsi_parse_nqueue(const char * q_arg)323a9643ea8Slogwang lsi_parse_nqueue(const char *q_arg)
324a9643ea8Slogwang {
325a9643ea8Slogwang char *end = NULL;
326a9643ea8Slogwang unsigned long n;
327a9643ea8Slogwang
328a9643ea8Slogwang /* parse hexadecimal string */
329a9643ea8Slogwang n = strtoul(q_arg, &end, 10);
330a9643ea8Slogwang if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
331a9643ea8Slogwang return 0;
332a9643ea8Slogwang if (n == 0)
333a9643ea8Slogwang return 0;
334a9643ea8Slogwang if (n >= MAX_RX_QUEUE_PER_LCORE)
335a9643ea8Slogwang return 0;
336a9643ea8Slogwang
337a9643ea8Slogwang return n;
338a9643ea8Slogwang }
339a9643ea8Slogwang
340a9643ea8Slogwang static int
lsi_parse_timer_period(const char * q_arg)341a9643ea8Slogwang lsi_parse_timer_period(const char *q_arg)
342a9643ea8Slogwang {
343a9643ea8Slogwang char *end = NULL;
344a9643ea8Slogwang int n;
345a9643ea8Slogwang
346a9643ea8Slogwang /* parse number string */
347a9643ea8Slogwang n = strtol(q_arg, &end, 10);
348a9643ea8Slogwang if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
349a9643ea8Slogwang return -1;
350a9643ea8Slogwang if (n >= MAX_TIMER_PERIOD)
351a9643ea8Slogwang return -1;
352a9643ea8Slogwang
353a9643ea8Slogwang return n;
354a9643ea8Slogwang }
355a9643ea8Slogwang
356a9643ea8Slogwang /* Parse the argument given in the command line of the application */
357a9643ea8Slogwang static int
lsi_parse_args(int argc,char ** argv)358a9643ea8Slogwang lsi_parse_args(int argc, char **argv)
359a9643ea8Slogwang {
360a9643ea8Slogwang int opt, ret;
361a9643ea8Slogwang char **argvopt;
362a9643ea8Slogwang int option_index;
363a9643ea8Slogwang char *prgname = argv[0];
364a9643ea8Slogwang static struct option lgopts[] = {
365a9643ea8Slogwang {NULL, 0, 0, 0}
366a9643ea8Slogwang };
367a9643ea8Slogwang
368a9643ea8Slogwang argvopt = argv;
369a9643ea8Slogwang
370a9643ea8Slogwang while ((opt = getopt_long(argc, argvopt, "p:q:T:",
371a9643ea8Slogwang lgopts, &option_index)) != EOF) {
372a9643ea8Slogwang
373a9643ea8Slogwang switch (opt) {
374a9643ea8Slogwang /* portmask */
375a9643ea8Slogwang case 'p':
376a9643ea8Slogwang lsi_enabled_port_mask = lsi_parse_portmask(optarg);
377a9643ea8Slogwang if (lsi_enabled_port_mask == 0) {
378a9643ea8Slogwang printf("invalid portmask\n");
379a9643ea8Slogwang lsi_usage(prgname);
380a9643ea8Slogwang return -1;
381a9643ea8Slogwang }
382a9643ea8Slogwang break;
383a9643ea8Slogwang
384a9643ea8Slogwang /* nqueue */
385a9643ea8Slogwang case 'q':
386a9643ea8Slogwang lsi_rx_queue_per_lcore = lsi_parse_nqueue(optarg);
387a9643ea8Slogwang if (lsi_rx_queue_per_lcore == 0) {
388a9643ea8Slogwang printf("invalid queue number\n");
389a9643ea8Slogwang lsi_usage(prgname);
390a9643ea8Slogwang return -1;
391a9643ea8Slogwang }
392a9643ea8Slogwang break;
393a9643ea8Slogwang
394a9643ea8Slogwang /* timer period */
395a9643ea8Slogwang case 'T':
396a9643ea8Slogwang timer_period = lsi_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
397a9643ea8Slogwang if (timer_period < 0) {
398a9643ea8Slogwang printf("invalid timer period\n");
399a9643ea8Slogwang lsi_usage(prgname);
400a9643ea8Slogwang return -1;
401a9643ea8Slogwang }
402a9643ea8Slogwang break;
403a9643ea8Slogwang
404a9643ea8Slogwang /* long options */
405a9643ea8Slogwang case 0:
406a9643ea8Slogwang lsi_usage(prgname);
407a9643ea8Slogwang return -1;
408a9643ea8Slogwang
409a9643ea8Slogwang default:
410a9643ea8Slogwang lsi_usage(prgname);
411a9643ea8Slogwang return -1;
412a9643ea8Slogwang }
413a9643ea8Slogwang }
414a9643ea8Slogwang
415a9643ea8Slogwang if (optind >= 0)
416a9643ea8Slogwang argv[optind-1] = prgname;
417a9643ea8Slogwang
418a9643ea8Slogwang ret = optind-1;
4192bfe3f2eSlogwang optind = 1; /* reset getopt lib */
420a9643ea8Slogwang return ret;
421a9643ea8Slogwang }
422a9643ea8Slogwang
423a9643ea8Slogwang /**
424a9643ea8Slogwang * It will be called as the callback for specified port after a LSI interrupt
425a9643ea8Slogwang * has been fully handled. This callback needs to be implemented carefully as
426a9643ea8Slogwang * it will be called in the interrupt host thread which is different from the
427a9643ea8Slogwang * application main thread.
428a9643ea8Slogwang *
429a9643ea8Slogwang * @param port_id
430a9643ea8Slogwang * Port id.
431a9643ea8Slogwang * @param type
432a9643ea8Slogwang * event type.
433a9643ea8Slogwang * @param param
434a9643ea8Slogwang * Pointer to(address of) the parameters.
435a9643ea8Slogwang *
436a9643ea8Slogwang * @return
4372bfe3f2eSlogwang * int.
438a9643ea8Slogwang */
4392bfe3f2eSlogwang static int
lsi_event_callback(uint16_t port_id,enum rte_eth_event_type type,void * param,void * ret_param)4402bfe3f2eSlogwang lsi_event_callback(uint16_t port_id, enum rte_eth_event_type type, void *param,
4412bfe3f2eSlogwang void *ret_param)
442a9643ea8Slogwang {
443a9643ea8Slogwang struct rte_eth_link link;
4444418919fSjohnjiang int ret;
445*2d9fd380Sjfb8856606 char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
446a9643ea8Slogwang
447a9643ea8Slogwang RTE_SET_USED(param);
4482bfe3f2eSlogwang RTE_SET_USED(ret_param);
449a9643ea8Slogwang
450a9643ea8Slogwang printf("\n\nIn registered callback...\n");
451a9643ea8Slogwang printf("Event type: %s\n", type == RTE_ETH_EVENT_INTR_LSC ? "LSC interrupt" : "unknown event");
4524418919fSjohnjiang ret = rte_eth_link_get_nowait(port_id, &link);
4534418919fSjohnjiang if (ret < 0) {
4544418919fSjohnjiang printf("Failed link get on port %d: %s\n",
4554418919fSjohnjiang port_id, rte_strerror(-ret));
4564418919fSjohnjiang return ret;
4574418919fSjohnjiang }
458*2d9fd380Sjfb8856606 rte_eth_link_to_str(link_status_text, sizeof(link_status_text), &link);
459*2d9fd380Sjfb8856606 printf("Port %d %s\n\n", port_id, link_status_text);
4602bfe3f2eSlogwang
4612bfe3f2eSlogwang return 0;
462a9643ea8Slogwang }
463a9643ea8Slogwang
464a9643ea8Slogwang /* Check the link status of all ports in up to 9s, and print them finally */
465a9643ea8Slogwang static void
check_all_ports_link_status(uint16_t port_num,uint32_t port_mask)4662bfe3f2eSlogwang check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
467a9643ea8Slogwang {
468a9643ea8Slogwang #define CHECK_INTERVAL 100 /* 100ms */
469a9643ea8Slogwang #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
4702bfe3f2eSlogwang uint8_t count, all_ports_up, print_flag = 0;
4712bfe3f2eSlogwang uint16_t portid;
472a9643ea8Slogwang struct rte_eth_link link;
4734418919fSjohnjiang int ret;
474*2d9fd380Sjfb8856606 char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
475a9643ea8Slogwang
476a9643ea8Slogwang printf("\nChecking link status");
477a9643ea8Slogwang fflush(stdout);
478a9643ea8Slogwang for (count = 0; count <= MAX_CHECK_TIME; count++) {
479a9643ea8Slogwang all_ports_up = 1;
480a9643ea8Slogwang for (portid = 0; portid < port_num; portid++) {
481a9643ea8Slogwang if ((port_mask & (1 << portid)) == 0)
482a9643ea8Slogwang continue;
483a9643ea8Slogwang memset(&link, 0, sizeof(link));
4844418919fSjohnjiang ret = rte_eth_link_get_nowait(portid, &link);
4854418919fSjohnjiang if (ret < 0) {
4864418919fSjohnjiang all_ports_up = 0;
4874418919fSjohnjiang if (print_flag == 1)
4884418919fSjohnjiang printf("Port %u link get failed: %s\n",
4894418919fSjohnjiang portid, rte_strerror(-ret));
4904418919fSjohnjiang continue;
4914418919fSjohnjiang }
492a9643ea8Slogwang /* print link status if flag set */
493a9643ea8Slogwang if (print_flag == 1) {
494*2d9fd380Sjfb8856606 rte_eth_link_to_str(link_status_text,
495*2d9fd380Sjfb8856606 sizeof(link_status_text), &link);
496*2d9fd380Sjfb8856606 printf("Port %d %s", portid,
497*2d9fd380Sjfb8856606 link_status_text);
498a9643ea8Slogwang continue;
499a9643ea8Slogwang }
500a9643ea8Slogwang /* clear all_ports_up flag if any link down */
501a9643ea8Slogwang if (link.link_status == ETH_LINK_DOWN) {
502a9643ea8Slogwang all_ports_up = 0;
503a9643ea8Slogwang break;
504a9643ea8Slogwang }
505a9643ea8Slogwang }
506a9643ea8Slogwang /* after finally printing all link status, get out */
507a9643ea8Slogwang if (print_flag == 1)
508a9643ea8Slogwang break;
509a9643ea8Slogwang
510a9643ea8Slogwang if (all_ports_up == 0) {
511a9643ea8Slogwang printf(".");
512a9643ea8Slogwang fflush(stdout);
513a9643ea8Slogwang rte_delay_ms(CHECK_INTERVAL);
514a9643ea8Slogwang }
515a9643ea8Slogwang
516a9643ea8Slogwang /* set the print_flag if all ports up or timeout */
517a9643ea8Slogwang if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
518a9643ea8Slogwang print_flag = 1;
519a9643ea8Slogwang printf("done\n");
520a9643ea8Slogwang }
521a9643ea8Slogwang }
522a9643ea8Slogwang }
523a9643ea8Slogwang
524a9643ea8Slogwang int
main(int argc,char ** argv)525a9643ea8Slogwang main(int argc, char **argv)
526a9643ea8Slogwang {
527a9643ea8Slogwang struct lcore_queue_conf *qconf;
528a9643ea8Slogwang int ret;
5292bfe3f2eSlogwang uint16_t nb_ports;
5302bfe3f2eSlogwang uint16_t portid, portid_last = 0;
531a9643ea8Slogwang unsigned lcore_id, rx_lcore_id;
532a9643ea8Slogwang unsigned nb_ports_in_mask = 0;
533a9643ea8Slogwang
534a9643ea8Slogwang /* init EAL */
535a9643ea8Slogwang ret = rte_eal_init(argc, argv);
536a9643ea8Slogwang if (ret < 0)
537a9643ea8Slogwang rte_exit(EXIT_FAILURE, "rte_eal_init failed");
538a9643ea8Slogwang argc -= ret;
539a9643ea8Slogwang argv += ret;
540a9643ea8Slogwang
541a9643ea8Slogwang /* parse application arguments (after the EAL ones) */
542a9643ea8Slogwang ret = lsi_parse_args(argc, argv);
543a9643ea8Slogwang if (ret < 0)
544a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Invalid arguments");
545a9643ea8Slogwang
546a9643ea8Slogwang /* create the mbuf pool */
547a9643ea8Slogwang lsi_pktmbuf_pool =
548a9643ea8Slogwang rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32, 0,
549a9643ea8Slogwang RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
550a9643ea8Slogwang if (lsi_pktmbuf_pool == NULL)
551a9643ea8Slogwang rte_panic("Cannot init mbuf pool\n");
552a9643ea8Slogwang
553d30ea906Sjfb8856606 nb_ports = rte_eth_dev_count_avail();
554a9643ea8Slogwang if (nb_ports == 0)
555a9643ea8Slogwang rte_panic("No Ethernet port - bye\n");
556a9643ea8Slogwang
557a9643ea8Slogwang /*
558a9643ea8Slogwang * Each logical core is assigned a dedicated TX queue on each port.
559a9643ea8Slogwang */
560a9643ea8Slogwang for (portid = 0; portid < nb_ports; portid++) {
561a9643ea8Slogwang /* skip ports that are not enabled */
562a9643ea8Slogwang if ((lsi_enabled_port_mask & (1 << portid)) == 0)
563a9643ea8Slogwang continue;
564a9643ea8Slogwang
565a9643ea8Slogwang /* save the destination port id */
566a9643ea8Slogwang if (nb_ports_in_mask % 2) {
567a9643ea8Slogwang lsi_dst_ports[portid] = portid_last;
568a9643ea8Slogwang lsi_dst_ports[portid_last] = portid;
569a9643ea8Slogwang }
570a9643ea8Slogwang else
571a9643ea8Slogwang portid_last = portid;
572a9643ea8Slogwang
573a9643ea8Slogwang nb_ports_in_mask++;
574a9643ea8Slogwang }
575a9643ea8Slogwang if (nb_ports_in_mask < 2 || nb_ports_in_mask % 2)
576a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Current enabled port number is %u, "
577a9643ea8Slogwang "but it should be even and at least 2\n",
578a9643ea8Slogwang nb_ports_in_mask);
579a9643ea8Slogwang
580a9643ea8Slogwang rx_lcore_id = 0;
581a9643ea8Slogwang qconf = &lcore_queue_conf[rx_lcore_id];
582a9643ea8Slogwang
583a9643ea8Slogwang /* Initialize the port/queue configuration of each logical core */
584a9643ea8Slogwang for (portid = 0; portid < nb_ports; portid++) {
585a9643ea8Slogwang /* skip ports that are not enabled */
586a9643ea8Slogwang if ((lsi_enabled_port_mask & (1 << portid)) == 0)
587a9643ea8Slogwang continue;
588a9643ea8Slogwang
589a9643ea8Slogwang /* get the lcore_id for this port */
590a9643ea8Slogwang while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
591a9643ea8Slogwang lcore_queue_conf[rx_lcore_id].n_rx_port ==
592a9643ea8Slogwang lsi_rx_queue_per_lcore) {
593a9643ea8Slogwang
594a9643ea8Slogwang rx_lcore_id++;
595a9643ea8Slogwang if (rx_lcore_id >= RTE_MAX_LCORE)
596a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Not enough cores\n");
597a9643ea8Slogwang }
598a9643ea8Slogwang if (qconf != &lcore_queue_conf[rx_lcore_id])
599a9643ea8Slogwang /* Assigned a new logical core in the loop above. */
600a9643ea8Slogwang qconf = &lcore_queue_conf[rx_lcore_id];
601a9643ea8Slogwang
602a9643ea8Slogwang qconf->rx_port_list[qconf->n_rx_port] = portid;
603a9643ea8Slogwang qconf->n_rx_port++;
604a9643ea8Slogwang printf("Lcore %u: RX port %u\n",rx_lcore_id, (unsigned) portid);
605a9643ea8Slogwang }
606a9643ea8Slogwang
607a9643ea8Slogwang /* Initialise each port */
608a9643ea8Slogwang for (portid = 0; portid < nb_ports; portid++) {
609d30ea906Sjfb8856606 struct rte_eth_rxconf rxq_conf;
610d30ea906Sjfb8856606 struct rte_eth_txconf txq_conf;
611d30ea906Sjfb8856606 struct rte_eth_conf local_port_conf = port_conf;
612d30ea906Sjfb8856606 struct rte_eth_dev_info dev_info;
613d30ea906Sjfb8856606
614a9643ea8Slogwang /* skip ports that are not enabled */
615a9643ea8Slogwang if ((lsi_enabled_port_mask & (1 << portid)) == 0) {
616a9643ea8Slogwang printf("Skipping disabled port %u\n", (unsigned) portid);
617a9643ea8Slogwang continue;
618a9643ea8Slogwang }
619a9643ea8Slogwang /* init port */
620a9643ea8Slogwang printf("Initializing port %u... ", (unsigned) portid);
621a9643ea8Slogwang fflush(stdout);
6224418919fSjohnjiang
6234418919fSjohnjiang ret = rte_eth_dev_info_get(portid, &dev_info);
6244418919fSjohnjiang if (ret != 0)
6254418919fSjohnjiang rte_exit(EXIT_FAILURE,
6264418919fSjohnjiang "Error during getting device (port %u) info: %s\n",
6274418919fSjohnjiang portid, strerror(-ret));
6284418919fSjohnjiang
629d30ea906Sjfb8856606 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
630d30ea906Sjfb8856606 local_port_conf.txmode.offloads |=
631d30ea906Sjfb8856606 DEV_TX_OFFLOAD_MBUF_FAST_FREE;
632d30ea906Sjfb8856606 ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
633a9643ea8Slogwang if (ret < 0)
634a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
635a9643ea8Slogwang ret, (unsigned) portid);
636a9643ea8Slogwang
6372bfe3f2eSlogwang ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
6382bfe3f2eSlogwang &nb_txd);
6392bfe3f2eSlogwang if (ret < 0)
6402bfe3f2eSlogwang rte_exit(EXIT_FAILURE,
6412bfe3f2eSlogwang "rte_eth_dev_adjust_nb_rx_tx_desc: err=%d, port=%u\n",
6422bfe3f2eSlogwang ret, (unsigned) portid);
6432bfe3f2eSlogwang
644a9643ea8Slogwang /* register lsi interrupt callback, need to be after
645a9643ea8Slogwang * rte_eth_dev_configure(). if (intr_conf.lsc == 0), no
646a9643ea8Slogwang * lsc interrupt will be present, and below callback to
647a9643ea8Slogwang * be registered will never be called.
648a9643ea8Slogwang */
649a9643ea8Slogwang rte_eth_dev_callback_register(portid,
650a9643ea8Slogwang RTE_ETH_EVENT_INTR_LSC, lsi_event_callback, NULL);
651a9643ea8Slogwang
6524418919fSjohnjiang ret = rte_eth_macaddr_get(portid,
653a9643ea8Slogwang &lsi_ports_eth_addr[portid]);
6544418919fSjohnjiang if (ret < 0)
6554418919fSjohnjiang rte_exit(EXIT_FAILURE,
6564418919fSjohnjiang "rte_eth_macaddr_get: err=%d, port=%u\n",
6574418919fSjohnjiang ret, (unsigned int)portid);
658a9643ea8Slogwang
659a9643ea8Slogwang /* init one RX queue */
660a9643ea8Slogwang fflush(stdout);
661d30ea906Sjfb8856606 rxq_conf = dev_info.default_rxconf;
662d30ea906Sjfb8856606 rxq_conf.offloads = local_port_conf.rxmode.offloads;
663a9643ea8Slogwang ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
664a9643ea8Slogwang rte_eth_dev_socket_id(portid),
665d30ea906Sjfb8856606 &rxq_conf,
666a9643ea8Slogwang lsi_pktmbuf_pool);
667a9643ea8Slogwang if (ret < 0)
668a9643ea8Slogwang rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d, port=%u\n",
669a9643ea8Slogwang ret, (unsigned) portid);
670a9643ea8Slogwang
671a9643ea8Slogwang /* init one TX queue logical core on each port */
672a9643ea8Slogwang fflush(stdout);
673d30ea906Sjfb8856606 txq_conf = dev_info.default_txconf;
674d30ea906Sjfb8856606 txq_conf.offloads = local_port_conf.txmode.offloads;
675a9643ea8Slogwang ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
676a9643ea8Slogwang rte_eth_dev_socket_id(portid),
677d30ea906Sjfb8856606 &txq_conf);
678a9643ea8Slogwang if (ret < 0)
679a9643ea8Slogwang rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d,port=%u\n",
680a9643ea8Slogwang ret, (unsigned) portid);
681a9643ea8Slogwang
682a9643ea8Slogwang /* Initialize TX buffers */
683a9643ea8Slogwang tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
684a9643ea8Slogwang RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
685a9643ea8Slogwang rte_eth_dev_socket_id(portid));
686a9643ea8Slogwang if (tx_buffer[portid] == NULL)
687a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
688a9643ea8Slogwang (unsigned) portid);
689a9643ea8Slogwang
690a9643ea8Slogwang rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
691a9643ea8Slogwang
692a9643ea8Slogwang ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
693a9643ea8Slogwang rte_eth_tx_buffer_count_callback,
694a9643ea8Slogwang &port_statistics[portid].dropped);
695a9643ea8Slogwang if (ret < 0)
696a9643ea8Slogwang rte_exit(EXIT_FAILURE, "Cannot set error callback for "
697a9643ea8Slogwang "tx buffer on port %u\n", (unsigned) portid);
698a9643ea8Slogwang
699a9643ea8Slogwang /* Start device */
700a9643ea8Slogwang ret = rte_eth_dev_start(portid);
701a9643ea8Slogwang if (ret < 0)
702a9643ea8Slogwang rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%u\n",
703a9643ea8Slogwang ret, (unsigned) portid);
704a9643ea8Slogwang printf("done:\n");
705a9643ea8Slogwang
7064418919fSjohnjiang ret = rte_eth_promiscuous_enable(portid);
7074418919fSjohnjiang if (ret != 0)
7084418919fSjohnjiang rte_exit(EXIT_FAILURE,
7094418919fSjohnjiang "rte_eth_promiscuous_enable: err=%s, port=%u\n",
7104418919fSjohnjiang rte_strerror(-ret), portid);
711a9643ea8Slogwang
712a9643ea8Slogwang printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
713a9643ea8Slogwang (unsigned) portid,
714a9643ea8Slogwang lsi_ports_eth_addr[portid].addr_bytes[0],
715a9643ea8Slogwang lsi_ports_eth_addr[portid].addr_bytes[1],
716a9643ea8Slogwang lsi_ports_eth_addr[portid].addr_bytes[2],
717a9643ea8Slogwang lsi_ports_eth_addr[portid].addr_bytes[3],
718a9643ea8Slogwang lsi_ports_eth_addr[portid].addr_bytes[4],
719a9643ea8Slogwang lsi_ports_eth_addr[portid].addr_bytes[5]);
720a9643ea8Slogwang
721a9643ea8Slogwang /* initialize port stats */
722a9643ea8Slogwang memset(&port_statistics, 0, sizeof(port_statistics));
723a9643ea8Slogwang }
724a9643ea8Slogwang
725a9643ea8Slogwang check_all_ports_link_status(nb_ports, lsi_enabled_port_mask);
726a9643ea8Slogwang
727a9643ea8Slogwang /* launch per-lcore init on every lcore */
728*2d9fd380Sjfb8856606 rte_eal_mp_remote_launch(lsi_launch_one_lcore, NULL, CALL_MAIN);
729*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(lcore_id) {
730a9643ea8Slogwang if (rte_eal_wait_lcore(lcore_id) < 0)
731a9643ea8Slogwang return -1;
732a9643ea8Slogwang }
733a9643ea8Slogwang
734a9643ea8Slogwang return 0;
735a9643ea8Slogwang }
736