net: add macro to extract MAC address bytes
[dpdk.git] / examples / l2fwd-jobstats / main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4
5 #include <locale.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <ctype.h>
10 #include <getopt.h>
11
12 #include <rte_common.h>
13 #include <rte_log.h>
14 #include <rte_malloc.h>
15 #include <rte_memory.h>
16 #include <rte_memcpy.h>
17 #include <rte_eal.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>
30 #include <rte_mbuf.h>
31 #include <rte_spinlock.h>
32
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>
38
39 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
40
41 #define NB_MBUF   8192
42
43 #define MAX_PKT_BURST 32
44 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
45
46 /*
47  * Configurable number of RX/TX ring descriptors
48  */
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;
53
54 /* ethernet addresses of ports */
55 static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
56
57 /* mask of enabled ports */
58 static uint32_t l2fwd_enabled_port_mask;
59
60 /* list of enabled ports */
61 static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
62
63 #define UPDATE_STEP_UP 1
64 #define UPDATE_STEP_DOWN 32
65
66 static unsigned int l2fwd_rx_queue_per_lcore = 1;
67
68 #define MAX_RX_QUEUE_PER_LCORE 16
69 #define MAX_TX_QUEUE_PER_PORT 16
70 /* List of queues to be polled for given lcore. 8< */
71 struct lcore_queue_conf {
72         unsigned n_rx_port;
73         unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
74         uint64_t next_flush_time[RTE_MAX_ETHPORTS];
75
76         struct rte_timer rx_timers[MAX_RX_QUEUE_PER_LCORE];
77         struct rte_jobstats port_fwd_jobs[MAX_RX_QUEUE_PER_LCORE];
78
79         struct rte_timer flush_timer;
80         struct rte_jobstats flush_job;
81         struct rte_jobstats idle_job;
82         struct rte_jobstats_context jobs_context;
83
84         rte_atomic16_t stats_read_pending;
85         rte_spinlock_t lock;
86 } __rte_cache_aligned;
87 /* >8 End of list of queues to be polled for given lcore. */
88 struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
89
90 struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
91
92 static struct rte_eth_conf port_conf = {
93         .rxmode = {
94                 .split_hdr_size = 0,
95         },
96         .txmode = {
97                 .mq_mode = ETH_MQ_TX_NONE,
98         },
99 };
100
101 struct rte_mempool *l2fwd_pktmbuf_pool = NULL;
102
103 /* Per-port statistics struct */
104 struct l2fwd_port_statistics {
105         uint64_t tx;
106         uint64_t rx;
107         uint64_t dropped;
108 } __rte_cache_aligned;
109 struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
110
111 /* 1 day max */
112 #define MAX_TIMER_PERIOD 86400
113 /* default period is 10 seconds */
114 static int64_t timer_period = 10;
115 /* default timer frequency */
116 static double hz;
117 /* BURST_TX_DRAIN_US converted to cycles */
118 uint64_t drain_tsc;
119 /* Convert cycles to ns */
120 static inline double
121 cycles_to_ns(uint64_t cycles)
122 {
123         double t = cycles;
124
125         t *= (double)NS_PER_S;
126         t /= hz;
127         return t;
128 }
129
130 static void
131 show_lcore_stats(unsigned lcore_id)
132 {
133         struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id];
134         struct rte_jobstats_context *ctx = &qconf->jobs_context;
135         struct rte_jobstats *job;
136         uint8_t i;
137
138         /* LCore statistics. */
139         uint64_t stats_period, loop_count;
140         uint64_t exec, exec_min, exec_max;
141         uint64_t management, management_min, management_max;
142         uint64_t busy, busy_min, busy_max;
143
144         /* Jobs statistics. */
145         const uint16_t port_cnt = qconf->n_rx_port;
146         uint64_t jobs_exec_cnt[port_cnt], jobs_period[port_cnt];
147         uint64_t jobs_exec[port_cnt], jobs_exec_min[port_cnt],
148                                 jobs_exec_max[port_cnt];
149
150         uint64_t flush_exec_cnt, flush_period;
151         uint64_t flush_exec, flush_exec_min, flush_exec_max;
152
153         uint64_t idle_exec_cnt;
154         uint64_t idle_exec, idle_exec_min, idle_exec_max;
155         uint64_t collection_time = rte_get_timer_cycles();
156
157         /* Ask forwarding thread to give us stats. */
158         rte_atomic16_set(&qconf->stats_read_pending, 1);
159         rte_spinlock_lock(&qconf->lock);
160         rte_atomic16_set(&qconf->stats_read_pending, 0);
161
162         /* Collect context statistics. */
163         stats_period = ctx->state_time - ctx->start_time;
164         loop_count = ctx->loop_cnt;
165
166         exec = ctx->exec_time;
167         exec_min = ctx->min_exec_time;
168         exec_max = ctx->max_exec_time;
169
170         management = ctx->management_time;
171         management_min = ctx->min_management_time;
172         management_max = ctx->max_management_time;
173
174         rte_jobstats_context_reset(ctx);
175
176         for (i = 0; i < port_cnt; i++) {
177                 job = &qconf->port_fwd_jobs[i];
178
179                 jobs_exec_cnt[i] = job->exec_cnt;
180                 jobs_period[i] = job->period;
181
182                 jobs_exec[i] = job->exec_time;
183                 jobs_exec_min[i] = job->min_exec_time;
184                 jobs_exec_max[i] = job->max_exec_time;
185
186                 rte_jobstats_reset(job);
187         }
188
189         flush_exec_cnt = qconf->flush_job.exec_cnt;
190         flush_period = qconf->flush_job.period;
191         flush_exec = qconf->flush_job.exec_time;
192         flush_exec_min = qconf->flush_job.min_exec_time;
193         flush_exec_max = qconf->flush_job.max_exec_time;
194         rte_jobstats_reset(&qconf->flush_job);
195
196         idle_exec_cnt = qconf->idle_job.exec_cnt;
197         idle_exec = qconf->idle_job.exec_time;
198         idle_exec_min = qconf->idle_job.min_exec_time;
199         idle_exec_max = qconf->idle_job.max_exec_time;
200         rte_jobstats_reset(&qconf->idle_job);
201
202         rte_spinlock_unlock(&qconf->lock);
203
204         exec -= idle_exec;
205         busy = exec + management;
206         busy_min = exec_min + management_min;
207         busy_max = exec_max + management_max;
208
209
210         collection_time = rte_get_timer_cycles() - collection_time;
211
212 #define STAT_FMT "\n%-18s %'14.0f %6.1f%% %'10.0f %'10.0f %'10.0f"
213
214         printf("\n----------------"
215                         "\nLCore %3u: statistics (time in ns, collected in %'9.0f)"
216                         "\n%-18s %14s %7s %10s %10s %10s "
217                         "\n%-18s %'14.0f"
218                         "\n%-18s %'14" PRIu64
219                         STAT_FMT /* Exec */
220                         STAT_FMT /* Management */
221                         STAT_FMT /* Busy */
222                         STAT_FMT, /* Idle  */
223                         lcore_id, cycles_to_ns(collection_time),
224                         "Stat type", "total", "%total", "avg", "min", "max",
225                         "Stats duration:", cycles_to_ns(stats_period),
226                         "Loop count:", loop_count,
227                         "Exec time",
228                         cycles_to_ns(exec), exec * 100.0 / stats_period,
229                         cycles_to_ns(loop_count  ? exec / loop_count : 0),
230                         cycles_to_ns(exec_min),
231                         cycles_to_ns(exec_max),
232                         "Management time",
233                         cycles_to_ns(management), management * 100.0 / stats_period,
234                         cycles_to_ns(loop_count  ? management / loop_count : 0),
235                         cycles_to_ns(management_min),
236                         cycles_to_ns(management_max),
237                         "Exec + management",
238                         cycles_to_ns(busy),  busy * 100.0 / stats_period,
239                         cycles_to_ns(loop_count ? busy / loop_count : 0),
240                         cycles_to_ns(busy_min),
241                         cycles_to_ns(busy_max),
242                         "Idle (job)",
243                         cycles_to_ns(idle_exec), idle_exec * 100.0 / stats_period,
244                         cycles_to_ns(idle_exec_cnt ? idle_exec / idle_exec_cnt : 0),
245                         cycles_to_ns(idle_exec_min),
246                         cycles_to_ns(idle_exec_max));
247
248         for (i = 0; i < qconf->n_rx_port; i++) {
249                 job = &qconf->port_fwd_jobs[i];
250                 printf("\n\nJob %" PRIu32 ": %-20s "
251                                 "\n%-18s %'14" PRIu64
252                                 "\n%-18s %'14.0f"
253                                 STAT_FMT,
254                                 i, job->name,
255                                 "Exec count:", jobs_exec_cnt[i],
256                                 "Exec period: ", cycles_to_ns(jobs_period[i]),
257                                 "Exec time",
258                                 cycles_to_ns(jobs_exec[i]), jobs_exec[i] * 100.0 / stats_period,
259                                 cycles_to_ns(jobs_exec_cnt[i] ? jobs_exec[i] / jobs_exec_cnt[i]
260                                                 : 0),
261                                 cycles_to_ns(jobs_exec_min[i]),
262                                 cycles_to_ns(jobs_exec_max[i]));
263         }
264
265         if (qconf->n_rx_port > 0) {
266                 job = &qconf->flush_job;
267                 printf("\n\nJob %" PRIu32 ": %-20s "
268                                 "\n%-18s %'14" PRIu64
269                                 "\n%-18s %'14.0f"
270                                 STAT_FMT,
271                                 i, job->name,
272                                 "Exec count:", flush_exec_cnt,
273                                 "Exec period: ", cycles_to_ns(flush_period),
274                                 "Exec time",
275                                 cycles_to_ns(flush_exec), flush_exec * 100.0 / stats_period,
276                                 cycles_to_ns(flush_exec_cnt ? flush_exec / flush_exec_cnt : 0),
277                                 cycles_to_ns(flush_exec_min),
278                                 cycles_to_ns(flush_exec_max));
279         }
280 }
281
282 /* Print out statistics on packets dropped */
283 static void
284 show_stats_cb(__rte_unused void *param)
285 {
286         uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
287         unsigned portid, lcore_id;
288
289         total_packets_dropped = 0;
290         total_packets_tx = 0;
291         total_packets_rx = 0;
292
293         const char clr[] = { 27, '[', '2', 'J', '\0' };
294         const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
295
296         /* Clear screen and move to top left */
297         printf("%s%s"
298                         "\nPort statistics ===================================",
299                         clr, topLeft);
300
301         for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
302                 /* skip disabled ports */
303                 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
304                         continue;
305                 printf("\nStatistics for port %u ------------------------------"
306                                 "\nPackets sent: %24"PRIu64
307                                 "\nPackets received: %20"PRIu64
308                                 "\nPackets dropped: %21"PRIu64,
309                                 portid,
310                                 port_statistics[portid].tx,
311                                 port_statistics[portid].rx,
312                                 port_statistics[portid].dropped);
313
314                 total_packets_dropped += port_statistics[portid].dropped;
315                 total_packets_tx += port_statistics[portid].tx;
316                 total_packets_rx += port_statistics[portid].rx;
317         }
318
319         printf("\nAggregate statistics ==============================="
320                         "\nTotal packets sent: %18"PRIu64
321                         "\nTotal packets received: %14"PRIu64
322                         "\nTotal packets dropped: %15"PRIu64
323                         "\n====================================================",
324                         total_packets_tx,
325                         total_packets_rx,
326                         total_packets_dropped);
327
328         RTE_LCORE_FOREACH(lcore_id) {
329                 if (lcore_queue_conf[lcore_id].n_rx_port > 0)
330                         show_lcore_stats(lcore_id);
331         }
332
333         printf("\n====================================================\n");
334
335         fflush(stdout);
336
337         rte_eal_alarm_set(timer_period * US_PER_S, show_stats_cb, NULL);
338 }
339
340 /* Start of l2fwd_simple_forward. 8< */
341 static void
342 l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
343 {
344         struct rte_ether_hdr *eth;
345         void *tmp;
346         int sent;
347         unsigned dst_port;
348         struct rte_eth_dev_tx_buffer *buffer;
349
350         dst_port = l2fwd_dst_ports[portid];
351         eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
352
353         /* 02:00:00:00:00:xx */
354         tmp = &eth->d_addr.addr_bytes[0];
355         *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
356
357         /* src addr */
358         rte_ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
359
360         buffer = tx_buffer[dst_port];
361         sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
362         if (sent)
363                 port_statistics[dst_port].tx += sent;
364 }
365 /* >8 End of l2fwd_simple_forward. */
366
367 static void
368 l2fwd_job_update_cb(struct rte_jobstats *job, int64_t result)
369 {
370         int64_t err = job->target - result;
371         int64_t histeresis = job->target / 8;
372
373         if (err < -histeresis) {
374                 if (job->min_period + UPDATE_STEP_DOWN < job->period)
375                         job->period -= UPDATE_STEP_DOWN;
376         } else if (err > histeresis) {
377                 if (job->period + UPDATE_STEP_UP < job->max_period)
378                         job->period += UPDATE_STEP_UP;
379         }
380 }
381
382 static void
383 l2fwd_fwd_job(__rte_unused struct rte_timer *timer, void *arg)
384 {
385         struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
386         struct rte_mbuf *m;
387
388         const uint16_t port_idx = (uintptr_t) arg;
389         const unsigned lcore_id = rte_lcore_id();
390         struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id];
391         struct rte_jobstats *job = &qconf->port_fwd_jobs[port_idx];
392         const uint16_t portid = qconf->rx_port_list[port_idx];
393
394         uint8_t j;
395         uint16_t total_nb_rx;
396
397         rte_jobstats_start(&qconf->jobs_context, job);
398
399         /* Call rx burst 2 times. This allow rte_jobstats logic to see if this
400          * function must be called more frequently. */
401
402         /* Call rx burst 2 times. 8< */
403         total_nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst,
404                         MAX_PKT_BURST);
405
406         for (j = 0; j < total_nb_rx; j++) {
407                 m = pkts_burst[j];
408                 rte_prefetch0(rte_pktmbuf_mtod(m, void *));
409                 l2fwd_simple_forward(m, portid);
410         }
411         /* >8 End of call rx burst 2 times. */
412
413         /* Read second try. 8< */
414         if (total_nb_rx == MAX_PKT_BURST) {
415                 const uint16_t nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst,
416                                 MAX_PKT_BURST);
417
418                 total_nb_rx += nb_rx;
419                 for (j = 0; j < nb_rx; j++) {
420                         m = pkts_burst[j];
421                         rte_prefetch0(rte_pktmbuf_mtod(m, void *));
422                         l2fwd_simple_forward(m, portid);
423                 }
424         }
425         /* >8 End of read second try. */
426
427         port_statistics[portid].rx += total_nb_rx;
428
429         /* Adjust period time in which we are running here. 8< */
430         if (rte_jobstats_finish(job, total_nb_rx) != 0) {
431                 rte_timer_reset(&qconf->rx_timers[port_idx], job->period, PERIODICAL,
432                                 lcore_id, l2fwd_fwd_job, arg);
433         }
434         /* >8 End of adjust period time in which we are running. */
435 }
436
437 /* Draining TX queue of each port. 8< */
438 static void
439 l2fwd_flush_job(__rte_unused struct rte_timer *timer, __rte_unused void *arg)
440 {
441         uint64_t now;
442         unsigned lcore_id;
443         struct lcore_queue_conf *qconf;
444         uint16_t portid;
445         unsigned i;
446         uint32_t sent;
447         struct rte_eth_dev_tx_buffer *buffer;
448
449         lcore_id = rte_lcore_id();
450         qconf = &lcore_queue_conf[lcore_id];
451
452         rte_jobstats_start(&qconf->jobs_context, &qconf->flush_job);
453
454         now = rte_get_timer_cycles();
455         lcore_id = rte_lcore_id();
456         qconf = &lcore_queue_conf[lcore_id];
457
458         for (i = 0; i < qconf->n_rx_port; i++) {
459                 portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
460
461                 if (qconf->next_flush_time[portid] <= now)
462                         continue;
463
464                 buffer = tx_buffer[portid];
465                 sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
466                 if (sent)
467                         port_statistics[portid].tx += sent;
468
469                 qconf->next_flush_time[portid] = rte_get_timer_cycles() + drain_tsc;
470         }
471
472         /* Pass target to indicate that this job is happy of time interwal
473          * in which it was called. */
474         rte_jobstats_finish(&qconf->flush_job, qconf->flush_job.target);
475 }
476 /* >8 End of draining TX queue of each port. */
477
478 /* main processing loop */
479 static void
480 l2fwd_main_loop(void)
481 {
482         unsigned lcore_id;
483         unsigned i, portid;
484         struct lcore_queue_conf *qconf;
485         uint8_t stats_read_pending = 0;
486         uint8_t need_manage;
487
488         lcore_id = rte_lcore_id();
489         qconf = &lcore_queue_conf[lcore_id];
490
491         if (qconf->n_rx_port == 0) {
492                 RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
493                 return;
494         }
495
496         RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
497
498         for (i = 0; i < qconf->n_rx_port; i++) {
499
500                 portid = qconf->rx_port_list[i];
501                 RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
502                         portid);
503         }
504
505         rte_jobstats_init(&qconf->idle_job, "idle", 0, 0, 0, 0);
506
507         /* Minimize impact of stats reading. 8< */
508         for (;;) {
509                 rte_spinlock_lock(&qconf->lock);
510
511                 do {
512                         rte_jobstats_context_start(&qconf->jobs_context);
513
514                         /* Do the Idle job:
515                          * - Read stats_read_pending flag
516                          * - check if some real job need to be executed
517                          */
518                         rte_jobstats_start(&qconf->jobs_context, &qconf->idle_job);
519
520                         uint64_t repeats = 0;
521
522                         do {
523                                 uint8_t i;
524                                 uint64_t now = rte_get_timer_cycles();
525
526                                 repeats++;
527                                 need_manage = qconf->flush_timer.expire < now;
528                                 /* Check if we was esked to give a stats. */
529                                 stats_read_pending =
530                                                 rte_atomic16_read(&qconf->stats_read_pending);
531                                 need_manage |= stats_read_pending;
532
533                                 for (i = 0; i < qconf->n_rx_port && !need_manage; i++)
534                                         need_manage = qconf->rx_timers[i].expire < now;
535
536                         } while (!need_manage);
537
538                         if (likely(repeats != 1))
539                                 rte_jobstats_finish(&qconf->idle_job, qconf->idle_job.target);
540                         else
541                                 rte_jobstats_abort(&qconf->idle_job);
542
543                         rte_timer_manage();
544                         rte_jobstats_context_finish(&qconf->jobs_context);
545                 } while (likely(stats_read_pending == 0));
546
547                 rte_spinlock_unlock(&qconf->lock);
548                 rte_pause();
549         }
550         /* >8 End of minimize impact of stats reading. */
551 }
552
553 static int
554 l2fwd_launch_one_lcore(__rte_unused void *dummy)
555 {
556         l2fwd_main_loop();
557         return 0;
558 }
559
560 /* display usage */
561 static void
562 l2fwd_usage(const char *prgname)
563 {
564         printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
565                "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
566                "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
567                    "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
568                    "  -l set system default locale instead of default (\"C\" locale) for thousands separator in stats.",
569                prgname);
570 }
571
572 static int
573 l2fwd_parse_portmask(const char *portmask)
574 {
575         char *end = NULL;
576         unsigned long pm;
577
578         /* parse hexadecimal string */
579         pm = strtoul(portmask, &end, 16);
580         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
581                 return 0;
582
583         return pm;
584 }
585
586 static unsigned int
587 l2fwd_parse_nqueue(const char *q_arg)
588 {
589         char *end = NULL;
590         unsigned long n;
591
592         /* parse hexadecimal string */
593         n = strtoul(q_arg, &end, 10);
594         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
595                 return 0;
596         if (n == 0)
597                 return 0;
598         if (n >= MAX_RX_QUEUE_PER_LCORE)
599                 return 0;
600
601         return n;
602 }
603
604 static int
605 l2fwd_parse_timer_period(const char *q_arg)
606 {
607         char *end = NULL;
608         int n;
609
610         /* parse number string */
611         n = strtol(q_arg, &end, 10);
612         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
613                 return -1;
614         if (n >= MAX_TIMER_PERIOD)
615                 return -1;
616
617         return n;
618 }
619
620 /* Parse the argument given in the command line of the application */
621 static int
622 l2fwd_parse_args(int argc, char **argv)
623 {
624         int opt, ret;
625         char **argvopt;
626         int option_index;
627         char *prgname = argv[0];
628         static struct option lgopts[] = {
629                 {NULL, 0, 0, 0}
630         };
631
632         argvopt = argv;
633
634         while ((opt = getopt_long(argc, argvopt, "p:q:T:l",
635                                   lgopts, &option_index)) != EOF) {
636
637                 switch (opt) {
638                 /* portmask */
639                 case 'p':
640                         l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
641                         if (l2fwd_enabled_port_mask == 0) {
642                                 printf("invalid portmask\n");
643                                 l2fwd_usage(prgname);
644                                 return -1;
645                         }
646                         break;
647
648                 /* nqueue */
649                 case 'q':
650                         l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
651                         if (l2fwd_rx_queue_per_lcore == 0) {
652                                 printf("invalid queue number\n");
653                                 l2fwd_usage(prgname);
654                                 return -1;
655                         }
656                         break;
657
658                 /* timer period */
659                 case 'T':
660                         timer_period = l2fwd_parse_timer_period(optarg);
661                         if (timer_period < 0) {
662                                 printf("invalid timer period\n");
663                                 l2fwd_usage(prgname);
664                                 return -1;
665                         }
666                         break;
667
668                 /* For thousands separator in printf. */
669                 case 'l':
670                         setlocale(LC_ALL, "");
671                         break;
672
673                 /* long options */
674                 case 0:
675                         l2fwd_usage(prgname);
676                         return -1;
677
678                 default:
679                         l2fwd_usage(prgname);
680                         return -1;
681                 }
682         }
683
684         if (optind >= 0)
685                 argv[optind-1] = prgname;
686
687         ret = optind-1;
688         optind = 1; /* reset getopt lib */
689         return ret;
690 }
691
692 /* Check the link status of all ports in up to 9s, and print them finally */
693 static void
694 check_all_ports_link_status(uint32_t port_mask)
695 {
696 #define CHECK_INTERVAL 100 /* 100ms */
697 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
698         uint16_t portid;
699         uint8_t count, all_ports_up, print_flag = 0;
700         struct rte_eth_link link;
701         int ret;
702         char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
703
704         printf("\nChecking link status");
705         fflush(stdout);
706         for (count = 0; count <= MAX_CHECK_TIME; count++) {
707                 all_ports_up = 1;
708                 RTE_ETH_FOREACH_DEV(portid) {
709                         if ((port_mask & (1 << portid)) == 0)
710                                 continue;
711                         memset(&link, 0, sizeof(link));
712                         ret = rte_eth_link_get_nowait(portid, &link);
713                         if (ret < 0) {
714                                 all_ports_up = 0;
715                                 if (print_flag == 1)
716                                         printf("Port %u link get failed: %s\n",
717                                                 portid, rte_strerror(-ret));
718                                 continue;
719                         }
720                         /* print link status if flag set */
721                         if (print_flag == 1) {
722                                 rte_eth_link_to_str(link_status_text,
723                                         sizeof(link_status_text), &link);
724                                 printf("Port %d %s\n", portid,
725                                        link_status_text);
726                                 continue;
727                         }
728                         /* clear all_ports_up flag if any link down */
729                         if (link.link_status == ETH_LINK_DOWN) {
730                                 all_ports_up = 0;
731                                 break;
732                         }
733                 }
734                 /* after finally printing all link status, get out */
735                 if (print_flag == 1)
736                         break;
737
738                 if (all_ports_up == 0) {
739                         printf(".");
740                         fflush(stdout);
741                         rte_delay_ms(CHECK_INTERVAL);
742                 }
743
744                 /* set the print_flag if all ports up or timeout */
745                 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
746                         print_flag = 1;
747                         printf("done\n");
748                 }
749         }
750 }
751
752 int
753 main(int argc, char **argv)
754 {
755         struct lcore_queue_conf *qconf;
756         unsigned lcore_id, rx_lcore_id;
757         unsigned nb_ports_in_mask = 0;
758         int ret;
759         char name[RTE_JOBSTATS_NAMESIZE];
760         uint16_t nb_ports;
761         uint16_t nb_ports_available = 0;
762         uint16_t portid, last_port;
763         uint8_t i;
764
765         /* Init EAL. 8< */
766         ret = rte_eal_init(argc, argv);
767         if (ret < 0)
768                 rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
769         argc -= ret;
770         argv += ret;
771
772         /* parse application arguments (after the EAL ones) */
773         ret = l2fwd_parse_args(argc, argv);
774         if (ret < 0)
775                 rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
776                 /* >8 End of init EAL. */
777
778         rte_timer_subsystem_init();
779
780         /* fetch default timer frequency. */
781         hz = rte_get_timer_hz();
782
783         /* Create the mbuf pool. 8< */
784         l2fwd_pktmbuf_pool =
785                 rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
786                         0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
787         if (l2fwd_pktmbuf_pool == NULL)
788                 rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
789         /* >8 End of creation of mbuf pool. */
790         nb_ports = rte_eth_dev_count_avail();
791         if (nb_ports == 0)
792                 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
793
794         /* Reset l2fwd_dst_ports. 8< */
795         for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
796                 l2fwd_dst_ports[portid] = 0;
797         last_port = 0;
798
799         /*
800          * Each logical core is assigned a dedicated TX queue on each port.
801          */
802         RTE_ETH_FOREACH_DEV(portid) {
803                 /* skip ports that are not enabled */
804                 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
805                         continue;
806
807                 if (nb_ports_in_mask % 2) {
808                         l2fwd_dst_ports[portid] = last_port;
809                         l2fwd_dst_ports[last_port] = portid;
810                 } else
811                         last_port = portid;
812
813                 nb_ports_in_mask++;
814         }
815         /* >8 End of reset l2fwd_dst_ports. */
816         if (nb_ports_in_mask % 2) {
817                 printf("Notice: odd number of ports in portmask.\n");
818                 l2fwd_dst_ports[last_port] = last_port;
819         }
820
821         rx_lcore_id = 0;
822         qconf = NULL;
823
824         /* Initialize the port/queue configuration of each logical core */
825         RTE_ETH_FOREACH_DEV(portid) {
826                 /* skip ports that are not enabled */
827                 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
828                         continue;
829
830                 /* get the lcore_id for this port */
831                 while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
832                        lcore_queue_conf[rx_lcore_id].n_rx_port ==
833                        l2fwd_rx_queue_per_lcore) {
834                         rx_lcore_id++;
835                         if (rx_lcore_id >= RTE_MAX_LCORE)
836                                 rte_exit(EXIT_FAILURE, "Not enough cores\n");
837                 }
838
839                 if (qconf != &lcore_queue_conf[rx_lcore_id])
840                         /* Assigned a new logical core in the loop above. */
841                         qconf = &lcore_queue_conf[rx_lcore_id];
842
843                 qconf->rx_port_list[qconf->n_rx_port] = portid;
844                 qconf->n_rx_port++;
845                 printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
846         }
847
848         /* Initialise each port */
849         RTE_ETH_FOREACH_DEV(portid) {
850                 struct rte_eth_dev_info dev_info;
851                 struct rte_eth_rxconf rxq_conf;
852                 struct rte_eth_txconf txq_conf;
853                 struct rte_eth_conf local_port_conf = port_conf;
854
855                 /* skip ports that are not enabled */
856                 if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
857                         printf("Skipping disabled port %u\n", portid);
858                         continue;
859                 }
860                 nb_ports_available++;
861
862                 /* init port */
863                 printf("Initializing port %u... ", portid);
864                 fflush(stdout);
865
866                 ret = rte_eth_dev_info_get(portid, &dev_info);
867                 if (ret != 0)
868                         rte_exit(EXIT_FAILURE,
869                                 "Error during getting device (port %u) info: %s\n",
870                                 portid, strerror(-ret));
871
872                 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
873                         local_port_conf.txmode.offloads |=
874                                 DEV_TX_OFFLOAD_MBUF_FAST_FREE;
875                 /* Configure the RX and TX queues. 8< */
876                 ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
877                 if (ret < 0)
878                         rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
879                                   ret, portid);
880                 /* >8 End of configuring the RX and TX queues. */
881
882                 ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
883                                                        &nb_txd);
884                 if (ret < 0)
885                         rte_exit(EXIT_FAILURE,
886                                  "Cannot adjust number of descriptors: err=%d, port=%u\n",
887                                  ret, portid);
888
889                 ret = rte_eth_macaddr_get(portid,
890                                           &l2fwd_ports_eth_addr[portid]);
891                 if (ret < 0)
892                         rte_exit(EXIT_FAILURE,
893                                  "Cannot get MAC address: err=%d, port=%u\n",
894                                  ret, portid);
895
896                 /* init one RX queue */
897                 fflush(stdout);
898                 rxq_conf = dev_info.default_rxconf;
899                 rxq_conf.offloads = local_port_conf.rxmode.offloads;
900                 /* RX queue initialization. 8< */
901                 ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
902                                              rte_eth_dev_socket_id(portid),
903                                              &rxq_conf,
904                                              l2fwd_pktmbuf_pool);
905                 if (ret < 0)
906                         rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
907                                   ret, portid);
908                 /* >8 End of RX queue initialization. */
909
910                 /* Init one TX queue on each port. 8< */
911                 txq_conf = dev_info.default_txconf;
912                 txq_conf.offloads = local_port_conf.txmode.offloads;
913                 fflush(stdout);
914                 ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
915                                 rte_eth_dev_socket_id(portid),
916                                 &txq_conf);
917                 if (ret < 0)
918                         rte_exit(EXIT_FAILURE,
919                         "rte_eth_tx_queue_setup:err=%d, port=%u\n",
920                                 ret, portid);
921                 /* >8 End of init one TX queue on each port. */
922
923                 /* Initialize TX buffers */
924                 tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
925                                 RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
926                                 rte_eth_dev_socket_id(portid));
927                 if (tx_buffer[portid] == NULL)
928                         rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
929                                         portid);
930
931                 rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
932
933                 ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
934                                 rte_eth_tx_buffer_count_callback,
935                                 &port_statistics[portid].dropped);
936                 if (ret < 0)
937                         rte_exit(EXIT_FAILURE,
938                         "Cannot set error callback for tx buffer on port %u\n",
939                                  portid);
940
941                 /* Start device */
942                 ret = rte_eth_dev_start(portid);
943                 if (ret < 0)
944                         rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
945                                   ret, portid);
946
947                 printf("done:\n");
948
949                 ret = rte_eth_promiscuous_enable(portid);
950                 if (ret != 0) {
951                         rte_exit(EXIT_FAILURE,
952                                  "rte_eth_promiscuous_enable:err=%s, port=%u\n",
953                                  rte_strerror(-ret), portid);
954                         return ret;
955
956                 }
957
958                 printf("Port %u, MAC address: " RTE_ETHER_ADDR_PRT_FMT "\n\n",
959                         portid,
960                         RTE_ETHER_ADDR_BYTES(&l2fwd_ports_eth_addr[portid]));
961
962                 /* initialize port stats */
963                 memset(&port_statistics, 0, sizeof(port_statistics));
964         }
965
966         if (!nb_ports_available) {
967                 rte_exit(EXIT_FAILURE,
968                         "All available ports are disabled. Please set portmask.\n");
969         }
970
971         check_all_ports_link_status(l2fwd_enabled_port_mask);
972
973         drain_tsc = (hz + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
974
975         RTE_LCORE_FOREACH(lcore_id) {
976                 qconf = &lcore_queue_conf[lcore_id];
977
978                 rte_spinlock_init(&qconf->lock);
979
980                 if (rte_jobstats_context_init(&qconf->jobs_context) != 0)
981                         rte_panic("Jobs stats context for core %u init failed\n", lcore_id);
982
983                 if (qconf->n_rx_port == 0) {
984                         RTE_LOG(INFO, L2FWD,
985                                 "lcore %u: no ports so no jobs stats context initialization\n",
986                                 lcore_id);
987                         continue;
988                 }
989                 /* Add flush job. 8< */
990
991                 /* Set fixed period by setting min = max = initial period. Set target to
992                  * zero as it is irrelevant for this job.
993                  */
994                 rte_jobstats_init(&qconf->flush_job, "flush", drain_tsc, drain_tsc,
995                                 drain_tsc, 0);
996
997                 rte_timer_init(&qconf->flush_timer);
998                 ret = rte_timer_reset(&qconf->flush_timer, drain_tsc, PERIODICAL,
999                                 lcore_id, &l2fwd_flush_job, NULL);
1000
1001                 if (ret < 0) {
1002                         rte_exit(1, "Failed to reset flush job timer for lcore %u: %s",
1003                                         lcore_id, rte_strerror(-ret));
1004                 }
1005                 /* >8 End of add flush job. */
1006
1007                 for (i = 0; i < qconf->n_rx_port; i++) {
1008                         struct rte_jobstats *job = &qconf->port_fwd_jobs[i];
1009
1010                         portid = qconf->rx_port_list[i];
1011                         printf("Setting forward job for port %u\n", portid);
1012
1013                         snprintf(name, RTE_DIM(name), "port %u fwd", portid);
1014                         /* Setup forward job. 8< */
1015
1016                         /* Set min, max and initial period. Set target to MAX_PKT_BURST as
1017                          * this is desired optimal RX/TX burst size.
1018                          */
1019                         rte_jobstats_init(job, name, 0, drain_tsc, 0, MAX_PKT_BURST);
1020                         rte_jobstats_set_update_period_function(job, l2fwd_job_update_cb);
1021
1022                         rte_timer_init(&qconf->rx_timers[i]);
1023                         ret = rte_timer_reset(&qconf->rx_timers[i], 0, PERIODICAL, lcore_id,
1024                                         &l2fwd_fwd_job, (void *)(uintptr_t)i);
1025
1026                         if (ret < 0) {
1027                                 rte_exit(1, "Failed to reset lcore %u port %u job timer: %s",
1028                                                 lcore_id, qconf->rx_port_list[i], rte_strerror(-ret));
1029                         }
1030                         /* >8 End of forward job. */
1031                 }
1032         }
1033
1034         if (timer_period)
1035                 rte_eal_alarm_set(timer_period * MS_PER_S, show_stats_cb, NULL);
1036         else
1037                 RTE_LOG(INFO, L2FWD, "Stats display disabled\n");
1038
1039         /* launch per-lcore init on every lcore */
1040         rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
1041         RTE_LCORE_FOREACH_WORKER(lcore_id) {
1042                 if (rte_eal_wait_lcore(lcore_id) < 0)
1043                         return -1;
1044         }
1045
1046         /* clean up the EAL */
1047         rte_eal_cleanup();
1048
1049         return 0;
1050 }