examples/l3fwd: fix validation for queue id of config tuple
[dpdk.git] / examples / l3fwd / main.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37 #include <inttypes.h>
38 #include <sys/types.h>
39 #include <string.h>
40 #include <sys/queue.h>
41 #include <stdarg.h>
42 #include <errno.h>
43 #include <getopt.h>
44 #include <signal.h>
45 #include <stdbool.h>
46
47 #include <rte_common.h>
48 #include <rte_vect.h>
49 #include <rte_byteorder.h>
50 #include <rte_log.h>
51 #include <rte_memory.h>
52 #include <rte_memcpy.h>
53 #include <rte_memzone.h>
54 #include <rte_eal.h>
55 #include <rte_per_lcore.h>
56 #include <rte_launch.h>
57 #include <rte_atomic.h>
58 #include <rte_cycles.h>
59 #include <rte_prefetch.h>
60 #include <rte_lcore.h>
61 #include <rte_per_lcore.h>
62 #include <rte_branch_prediction.h>
63 #include <rte_interrupts.h>
64 #include <rte_pci.h>
65 #include <rte_random.h>
66 #include <rte_debug.h>
67 #include <rte_ether.h>
68 #include <rte_ethdev.h>
69 #include <rte_ring.h>
70 #include <rte_mempool.h>
71 #include <rte_mbuf.h>
72 #include <rte_ip.h>
73 #include <rte_tcp.h>
74 #include <rte_udp.h>
75 #include <rte_string_fns.h>
76 #include <rte_cpuflags.h>
77
78 #include <cmdline_parse.h>
79 #include <cmdline_parse_etheraddr.h>
80
81 #include "l3fwd.h"
82
83 /*
84  * Configurable number of RX/TX ring descriptors
85  */
86 #define RTE_TEST_RX_DESC_DEFAULT 128
87 #define RTE_TEST_TX_DESC_DEFAULT 512
88
89 #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS
90 #define MAX_RX_QUEUE_PER_PORT 128
91
92 #define MAX_LCORE_PARAMS 1024
93
94 /* Static global variables used within this file. */
95 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
96 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
97
98 /**< Ports set in promiscuous mode off by default. */
99 static int promiscuous_on;
100
101 /* Select Longest-Prefix or Exact match. */
102 static int l3fwd_lpm_on;
103 static int l3fwd_em_on;
104
105 static int numa_on = 1; /**< NUMA is enabled by default. */
106
107 /* Global variables. */
108
109 volatile bool force_quit;
110
111 /* ethernet addresses of ports */
112 uint64_t dest_eth_addr[RTE_MAX_ETHPORTS];
113 struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
114
115 xmm_t val_eth[RTE_MAX_ETHPORTS];
116
117 /* mask of enabled ports */
118 uint32_t enabled_port_mask;
119
120 /* Used only in exact match mode. */
121 int ipv6; /**< ipv6 is false by default. */
122 uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
123
124 struct lcore_conf lcore_conf[RTE_MAX_LCORE];
125
126 struct lcore_params {
127         uint8_t port_id;
128         uint8_t queue_id;
129         uint8_t lcore_id;
130 } __rte_cache_aligned;
131
132 static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
133 static struct lcore_params lcore_params_array_default[] = {
134         {0, 0, 2},
135         {0, 1, 2},
136         {0, 2, 2},
137         {1, 0, 2},
138         {1, 1, 2},
139         {1, 2, 2},
140         {2, 0, 2},
141         {3, 0, 3},
142         {3, 1, 3},
143 };
144
145 static struct lcore_params * lcore_params = lcore_params_array_default;
146 static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
147                                 sizeof(lcore_params_array_default[0]);
148
149 static struct rte_eth_conf port_conf = {
150         .rxmode = {
151                 .mq_mode = ETH_MQ_RX_RSS,
152                 .max_rx_pkt_len = ETHER_MAX_LEN,
153                 .split_hdr_size = 0,
154                 .header_split   = 0, /**< Header Split disabled */
155                 .hw_ip_checksum = 1, /**< IP checksum offload enabled */
156                 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
157                 .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
158                 .hw_strip_crc   = 0, /**< CRC stripped by hardware */
159         },
160         .rx_adv_conf = {
161                 .rss_conf = {
162                         .rss_key = NULL,
163                         .rss_hf = ETH_RSS_IP,
164                 },
165         },
166         .txmode = {
167                 .mq_mode = ETH_MQ_TX_NONE,
168         },
169 };
170
171 static struct rte_mempool * pktmbuf_pool[NB_SOCKETS];
172
173 struct l3fwd_lkp_mode {
174         void  (*setup)(int);
175         int   (*main_loop)(void *);
176         void* (*get_ipv4_lookup_struct)(int);
177         void* (*get_ipv6_lookup_struct)(int);
178 };
179
180 static struct l3fwd_lkp_mode l3fwd_lkp;
181
182 static struct l3fwd_lkp_mode l3fwd_em_lkp = {
183         .setup                  = setup_hash,
184         .main_loop              = em_main_loop,
185         .get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct,
186         .get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct,
187 };
188
189 static struct l3fwd_lkp_mode l3fwd_lpm_lkp = {
190         .setup                  = setup_lpm,
191         .main_loop              = lpm_main_loop,
192         .get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct,
193         .get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct,
194 };
195
196 /*
197  * Setup lookup methods for forwarding.
198  * Currently exact-match and longest-prefix-match
199  * are supported ones.
200  */
201 static void
202 setup_l3fwd_lookup_tables(void)
203 {
204         /* Setup HASH lookup functions. */
205         if (l3fwd_em_on)
206                 l3fwd_lkp = l3fwd_em_lkp;
207         /* Setup LPM lookup functions. */
208         else
209                 l3fwd_lkp = l3fwd_lpm_lkp;
210 }
211
212 static int
213 check_lcore_params(void)
214 {
215         uint8_t queue, lcore;
216         uint16_t i;
217         int socketid;
218
219         for (i = 0; i < nb_lcore_params; ++i) {
220                 queue = lcore_params[i].queue_id;
221                 if (queue >= MAX_RX_QUEUE_PER_PORT) {
222                         printf("invalid queue number: %hhu\n", queue);
223                         return -1;
224                 }
225                 lcore = lcore_params[i].lcore_id;
226                 if (!rte_lcore_is_enabled(lcore)) {
227                         printf("error: lcore %hhu is not enabled in lcore mask\n", lcore);
228                         return -1;
229                 }
230                 if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
231                         (numa_on == 0)) {
232                         printf("warning: lcore %hhu is on socket %d with numa off \n",
233                                 lcore, socketid);
234                 }
235         }
236         return 0;
237 }
238
239 static int
240 check_port_config(const unsigned nb_ports)
241 {
242         unsigned portid;
243         uint16_t i;
244
245         for (i = 0; i < nb_lcore_params; ++i) {
246                 portid = lcore_params[i].port_id;
247                 if ((enabled_port_mask & (1 << portid)) == 0) {
248                         printf("port %u is not enabled in port mask\n", portid);
249                         return -1;
250                 }
251                 if (portid >= nb_ports) {
252                         printf("port %u is not present on the board\n", portid);
253                         return -1;
254                 }
255         }
256         return 0;
257 }
258
259 static uint8_t
260 get_port_n_rx_queues(const uint8_t port)
261 {
262         int queue = -1;
263         uint16_t i;
264
265         for (i = 0; i < nb_lcore_params; ++i) {
266                 if (lcore_params[i].port_id == port) {
267                         if (lcore_params[i].queue_id == queue+1)
268                                 queue = lcore_params[i].queue_id;
269                         else
270                                 rte_exit(EXIT_FAILURE, "queue ids of the port %d must be"
271                                                 " in sequence and must start with 0\n",
272                                                 lcore_params[i].port_id);
273                 }
274         }
275         return (uint8_t)(++queue);
276 }
277
278 static int
279 init_lcore_rx_queues(void)
280 {
281         uint16_t i, nb_rx_queue;
282         uint8_t lcore;
283
284         for (i = 0; i < nb_lcore_params; ++i) {
285                 lcore = lcore_params[i].lcore_id;
286                 nb_rx_queue = lcore_conf[lcore].n_rx_queue;
287                 if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
288                         printf("error: too many queues (%u) for lcore: %u\n",
289                                 (unsigned)nb_rx_queue + 1, (unsigned)lcore);
290                         return -1;
291                 } else {
292                         lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
293                                 lcore_params[i].port_id;
294                         lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
295                                 lcore_params[i].queue_id;
296                         lcore_conf[lcore].n_rx_queue++;
297                 }
298         }
299         return 0;
300 }
301
302 /* display usage */
303 static void
304 print_usage(const char *prgname)
305 {
306         printf ("%s [EAL options] -- -p PORTMASK -P"
307                 "  [--config (port,queue,lcore)[,(port,queue,lcore]]"
308                 "  [--enable-jumbo [--max-pkt-len PKTLEN]]\n"
309                 "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
310                 "  -P : enable promiscuous mode\n"
311                 "  -E : enable exact match\n"
312                 "  -L : enable longest prefix match\n"
313                 "  --config (port,queue,lcore): rx queues configuration\n"
314                 "  --eth-dest=X,MM:MM:MM:MM:MM:MM: optional, ethernet destination for port X\n"
315                 "  --no-numa: optional, disable numa awareness\n"
316                 "  --ipv6: optional, specify it if running ipv6 packets\n"
317                 "  --enable-jumbo: enable jumbo frame"
318                 " which max packet len is PKTLEN in decimal (64-9600)\n"
319                 "  --hash-entry-num: specify the hash entry number in hexadecimal to be setup\n",
320                 prgname);
321 }
322
323 static int
324 parse_max_pkt_len(const char *pktlen)
325 {
326         char *end = NULL;
327         unsigned long len;
328
329         /* parse decimal string */
330         len = strtoul(pktlen, &end, 10);
331         if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
332                 return -1;
333
334         if (len == 0)
335                 return -1;
336
337         return len;
338 }
339
340 static int
341 parse_portmask(const char *portmask)
342 {
343         char *end = NULL;
344         unsigned long pm;
345
346         /* parse hexadecimal string */
347         pm = strtoul(portmask, &end, 16);
348         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
349                 return -1;
350
351         if (pm == 0)
352                 return -1;
353
354         return pm;
355 }
356
357 static int
358 parse_hash_entry_number(const char *hash_entry_num)
359 {
360         char *end = NULL;
361         unsigned long hash_en;
362         /* parse hexadecimal string */
363         hash_en = strtoul(hash_entry_num, &end, 16);
364         if ((hash_entry_num[0] == '\0') || (end == NULL) || (*end != '\0'))
365                 return -1;
366
367         if (hash_en == 0)
368                 return -1;
369
370         return hash_en;
371 }
372
373 static int
374 parse_config(const char *q_arg)
375 {
376         char s[256];
377         const char *p, *p0 = q_arg;
378         char *end;
379         enum fieldnames {
380                 FLD_PORT = 0,
381                 FLD_QUEUE,
382                 FLD_LCORE,
383                 _NUM_FLD
384         };
385         unsigned long int_fld[_NUM_FLD];
386         char *str_fld[_NUM_FLD];
387         int i;
388         unsigned size;
389
390         nb_lcore_params = 0;
391
392         while ((p = strchr(p0,'(')) != NULL) {
393                 ++p;
394                 if((p0 = strchr(p,')')) == NULL)
395                         return -1;
396
397                 size = p0 - p;
398                 if(size >= sizeof(s))
399                         return -1;
400
401                 snprintf(s, sizeof(s), "%.*s", size, p);
402                 if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
403                         return -1;
404                 for (i = 0; i < _NUM_FLD; i++){
405                         errno = 0;
406                         int_fld[i] = strtoul(str_fld[i], &end, 0);
407                         if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
408                                 return -1;
409                 }
410                 if (nb_lcore_params >= MAX_LCORE_PARAMS) {
411                         printf("exceeded max number of lcore params: %hu\n",
412                                 nb_lcore_params);
413                         return -1;
414                 }
415                 lcore_params_array[nb_lcore_params].port_id =
416                         (uint8_t)int_fld[FLD_PORT];
417                 lcore_params_array[nb_lcore_params].queue_id =
418                         (uint8_t)int_fld[FLD_QUEUE];
419                 lcore_params_array[nb_lcore_params].lcore_id =
420                         (uint8_t)int_fld[FLD_LCORE];
421                 ++nb_lcore_params;
422         }
423         lcore_params = lcore_params_array;
424         return 0;
425 }
426
427 static void
428 parse_eth_dest(const char *optarg)
429 {
430         uint8_t portid;
431         char *port_end;
432         uint8_t c, *dest, peer_addr[6];
433
434         errno = 0;
435         portid = strtoul(optarg, &port_end, 10);
436         if (errno != 0 || port_end == optarg || *port_end++ != ',')
437                 rte_exit(EXIT_FAILURE,
438                 "Invalid eth-dest: %s", optarg);
439         if (portid >= RTE_MAX_ETHPORTS)
440                 rte_exit(EXIT_FAILURE,
441                 "eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n",
442                 portid, RTE_MAX_ETHPORTS);
443
444         if (cmdline_parse_etheraddr(NULL, port_end,
445                 &peer_addr, sizeof(peer_addr)) < 0)
446                 rte_exit(EXIT_FAILURE,
447                 "Invalid ethernet address: %s\n",
448                 port_end);
449         dest = (uint8_t *)&dest_eth_addr[portid];
450         for (c = 0; c < 6; c++)
451                 dest[c] = peer_addr[c];
452         *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
453 }
454
455 #define MAX_JUMBO_PKT_LEN  9600
456 #define MEMPOOL_CACHE_SIZE 256
457
458 #define CMD_LINE_OPT_CONFIG "config"
459 #define CMD_LINE_OPT_ETH_DEST "eth-dest"
460 #define CMD_LINE_OPT_NO_NUMA "no-numa"
461 #define CMD_LINE_OPT_IPV6 "ipv6"
462 #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
463 #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
464
465 /*
466  * This expression is used to calculate the number of mbufs needed
467  * depending on user input, taking  into account memory for rx and
468  * tx hardware rings, cache per lcore and mtable per port per lcore.
469  * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum
470  * value of 8192
471  */
472 #define NB_MBUF RTE_MAX(        \
473         (nb_ports*nb_rx_queue*RTE_TEST_RX_DESC_DEFAULT +        \
474         nb_ports*nb_lcores*MAX_PKT_BURST +                      \
475         nb_ports*n_tx_queue*RTE_TEST_TX_DESC_DEFAULT +          \
476         nb_lcores*MEMPOOL_CACHE_SIZE),                          \
477         (unsigned)8192)
478
479 /* Parse the argument given in the command line of the application */
480 static int
481 parse_args(int argc, char **argv)
482 {
483         int opt, ret;
484         char **argvopt;
485         int option_index;
486         char *prgname = argv[0];
487         static struct option lgopts[] = {
488                 {CMD_LINE_OPT_CONFIG, 1, 0, 0},
489                 {CMD_LINE_OPT_ETH_DEST, 1, 0, 0},
490                 {CMD_LINE_OPT_NO_NUMA, 0, 0, 0},
491                 {CMD_LINE_OPT_IPV6, 0, 0, 0},
492                 {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0},
493                 {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0},
494                 {NULL, 0, 0, 0}
495         };
496
497         argvopt = argv;
498
499         /* Error or normal output strings. */
500         const char *str1 = "L3FWD: Invalid portmask";
501         const char *str2 = "L3FWD: Promiscuous mode selected";
502         const char *str3 = "L3FWD: Exact match selected";
503         const char *str4 = "L3FWD: Longest-prefix match selected";
504         const char *str5 = "L3FWD: Invalid config";
505         const char *str6 = "L3FWD: NUMA is disabled";
506         const char *str7 = "L3FWD: IPV6 is specified";
507         const char *str8 =
508                 "L3FWD: Jumbo frame is enabled - disabling simple TX path";
509         const char *str9 = "L3FWD: Invalid packet length";
510         const char *str10 = "L3FWD: Set jumbo frame max packet len to ";
511         const char *str11 = "L3FWD: Invalid hash entry number";
512         const char *str12 =
513                 "L3FWD: LPM and EM are mutually exclusive, select only one";
514         const char *str13 = "L3FWD: LPM or EM none selected, default LPM on";
515
516         while ((opt = getopt_long(argc, argvopt, "p:PLE",
517                                 lgopts, &option_index)) != EOF) {
518
519                 switch (opt) {
520                 /* portmask */
521                 case 'p':
522                         enabled_port_mask = parse_portmask(optarg);
523                         if (enabled_port_mask == 0) {
524                                 printf("%s\n", str1);
525                                 print_usage(prgname);
526                                 return -1;
527                         }
528                         break;
529                 case 'P':
530                         printf("%s\n", str2);
531                         promiscuous_on = 1;
532                         break;
533
534                 case 'E':
535                         printf("%s\n", str3);
536                         l3fwd_em_on = 1;
537                         break;
538
539                 case 'L':
540                         printf("%s\n", str4);
541                         l3fwd_lpm_on = 1;
542                         break;
543
544                 /* long options */
545                 case 0:
546                         if (!strncmp(lgopts[option_index].name,
547                                         CMD_LINE_OPT_CONFIG,
548                                         sizeof(CMD_LINE_OPT_CONFIG))) {
549
550                                 ret = parse_config(optarg);
551                                 if (ret) {
552                                         printf("%s\n", str5);
553                                         print_usage(prgname);
554                                         return -1;
555                                 }
556                         }
557
558                         if (!strncmp(lgopts[option_index].name,
559                                         CMD_LINE_OPT_ETH_DEST,
560                                         sizeof(CMD_LINE_OPT_ETH_DEST))) {
561                                         parse_eth_dest(optarg);
562                         }
563
564                         if (!strncmp(lgopts[option_index].name,
565                                         CMD_LINE_OPT_NO_NUMA,
566                                         sizeof(CMD_LINE_OPT_NO_NUMA))) {
567                                 printf("%s\n", str6);
568                                 numa_on = 0;
569                         }
570
571                         if (!strncmp(lgopts[option_index].name,
572                                 CMD_LINE_OPT_IPV6,
573                                 sizeof(CMD_LINE_OPT_IPV6))) {
574                                 printf("%sn", str7);
575                                 ipv6 = 1;
576                         }
577
578                         if (!strncmp(lgopts[option_index].name,
579                                         CMD_LINE_OPT_ENABLE_JUMBO,
580                                         sizeof(CMD_LINE_OPT_ENABLE_JUMBO))) {
581                                 struct option lenopts = {
582                                         "max-pkt-len", required_argument, 0, 0
583                                 };
584
585                                 printf("%s\n", str8);
586                                 port_conf.rxmode.jumbo_frame = 1;
587
588                                 /*
589                                  * if no max-pkt-len set, use the default
590                                  * value ETHER_MAX_LEN.
591                                  */
592                                 if (0 == getopt_long(argc, argvopt, "",
593                                                 &lenopts, &option_index)) {
594                                         ret = parse_max_pkt_len(optarg);
595                                         if ((ret < 64) ||
596                                                 (ret > MAX_JUMBO_PKT_LEN)) {
597                                                 printf("%s\n", str9);
598                                                 print_usage(prgname);
599                                                 return -1;
600                                         }
601                                         port_conf.rxmode.max_rx_pkt_len = ret;
602                                 }
603                                 printf("%s %u\n", str10,
604                                 (unsigned int)port_conf.rxmode.max_rx_pkt_len);
605                         }
606
607                         if (!strncmp(lgopts[option_index].name,
608                                 CMD_LINE_OPT_HASH_ENTRY_NUM,
609                                 sizeof(CMD_LINE_OPT_HASH_ENTRY_NUM))) {
610
611                                 ret = parse_hash_entry_number(optarg);
612                                 if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) {
613                                         hash_entry_number = ret;
614                                 } else {
615                                         printf("%s\n", str11);
616                                         print_usage(prgname);
617                                         return -1;
618                                 }
619                         }
620                         break;
621
622                 default:
623                         print_usage(prgname);
624                         return -1;
625                 }
626         }
627
628         /* If both LPM and EM are selected, return error. */
629         if (l3fwd_lpm_on && l3fwd_em_on) {
630                 printf("%s\n", str12);
631                 return -1;
632         }
633
634         /*
635          * Nothing is selected, pick longest-prefix match
636          * as default match.
637          */
638         if (!l3fwd_lpm_on && !l3fwd_em_on) {
639                 l3fwd_lpm_on = 1;
640                 printf("%s\n", str13);
641         }
642
643         /*
644          * ipv6 and hash flags are valid only for
645          * exact macth, reset them to default for
646          * longest-prefix match.
647          */
648         if (l3fwd_lpm_on) {
649                 ipv6 = 0;
650                 hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
651         }
652
653         if (optind >= 0)
654                 argv[optind-1] = prgname;
655
656         ret = optind-1;
657         optind = 0; /* reset getopt lib */
658         return ret;
659 }
660
661 static void
662 print_ethaddr(const char *name, const struct ether_addr *eth_addr)
663 {
664         char buf[ETHER_ADDR_FMT_SIZE];
665         ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
666         printf("%s%s", name, buf);
667 }
668
669 static int
670 init_mem(unsigned nb_mbuf)
671 {
672         struct lcore_conf *qconf;
673         int socketid;
674         unsigned lcore_id;
675         char s[64];
676
677         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
678                 if (rte_lcore_is_enabled(lcore_id) == 0)
679                         continue;
680
681                 if (numa_on)
682                         socketid = rte_lcore_to_socket_id(lcore_id);
683                 else
684                         socketid = 0;
685
686                 if (socketid >= NB_SOCKETS) {
687                         rte_exit(EXIT_FAILURE,
688                                 "Socket %d of lcore %u is out of range %d\n",
689                                 socketid, lcore_id, NB_SOCKETS);
690                 }
691
692                 if (pktmbuf_pool[socketid] == NULL) {
693                         snprintf(s, sizeof(s), "mbuf_pool_%d", socketid);
694                         pktmbuf_pool[socketid] =
695                                 rte_pktmbuf_pool_create(s, nb_mbuf,
696                                         MEMPOOL_CACHE_SIZE, 0,
697                                         RTE_MBUF_DEFAULT_BUF_SIZE, socketid);
698                         if (pktmbuf_pool[socketid] == NULL)
699                                 rte_exit(EXIT_FAILURE,
700                                         "Cannot init mbuf pool on socket %d\n",
701                                         socketid);
702                         else
703                                 printf("Allocated mbuf pool on socket %d\n",
704                                         socketid);
705
706                         /* Setup either LPM or EM(f.e Hash).  */
707                         l3fwd_lkp.setup(socketid);
708                 }
709                 qconf = &lcore_conf[lcore_id];
710                 qconf->ipv4_lookup_struct =
711                         l3fwd_lkp.get_ipv4_lookup_struct(socketid);
712                 qconf->ipv6_lookup_struct =
713                         l3fwd_lkp.get_ipv6_lookup_struct(socketid);
714         }
715         return 0;
716 }
717
718 /* Check the link status of all ports in up to 9s, and print them finally */
719 static void
720 check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
721 {
722 #define CHECK_INTERVAL 100 /* 100ms */
723 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
724         uint8_t portid, count, all_ports_up, print_flag = 0;
725         struct rte_eth_link link;
726
727         printf("\nChecking link status");
728         fflush(stdout);
729         for (count = 0; count <= MAX_CHECK_TIME; count++) {
730                 if (force_quit)
731                         return;
732                 all_ports_up = 1;
733                 for (portid = 0; portid < port_num; portid++) {
734                         if (force_quit)
735                                 return;
736                         if ((port_mask & (1 << portid)) == 0)
737                                 continue;
738                         memset(&link, 0, sizeof(link));
739                         rte_eth_link_get_nowait(portid, &link);
740                         /* print link status if flag set */
741                         if (print_flag == 1) {
742                                 if (link.link_status)
743                                         printf("Port %d Link Up - speed %u "
744                                                 "Mbps - %s\n", (uint8_t)portid,
745                                                 (unsigned)link.link_speed,
746                                 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
747                                         ("full-duplex") : ("half-duplex\n"));
748                                 else
749                                         printf("Port %d Link Down\n",
750                                                 (uint8_t)portid);
751                                 continue;
752                         }
753                         /* clear all_ports_up flag if any link down */
754                         if (link.link_status == 0) {
755                                 all_ports_up = 0;
756                                 break;
757                         }
758                 }
759                 /* after finally printing all link status, get out */
760                 if (print_flag == 1)
761                         break;
762
763                 if (all_ports_up == 0) {
764                         printf(".");
765                         fflush(stdout);
766                         rte_delay_ms(CHECK_INTERVAL);
767                 }
768
769                 /* set the print_flag if all ports up or timeout */
770                 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
771                         print_flag = 1;
772                         printf("done\n");
773                 }
774         }
775 }
776
777 static void
778 signal_handler(int signum)
779 {
780         if (signum == SIGINT || signum == SIGTERM) {
781                 printf("\n\nSignal %d received, preparing to exit...\n",
782                                 signum);
783                 force_quit = true;
784         }
785 }
786
787 int
788 main(int argc, char **argv)
789 {
790         struct lcore_conf *qconf;
791         struct rte_eth_dev_info dev_info;
792         struct rte_eth_txconf *txconf;
793         int ret;
794         unsigned nb_ports;
795         uint16_t queueid;
796         unsigned lcore_id;
797         uint32_t n_tx_queue, nb_lcores;
798         uint8_t portid, nb_rx_queue, queue, socketid;
799         uint8_t nb_tx_port;
800
801         /* init EAL */
802         ret = rte_eal_init(argc, argv);
803         if (ret < 0)
804                 rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
805         argc -= ret;
806         argv += ret;
807
808         force_quit = false;
809         signal(SIGINT, signal_handler);
810         signal(SIGTERM, signal_handler);
811
812         /* pre-init dst MACs for all ports to 02:00:00:00:00:xx */
813         for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
814                 dest_eth_addr[portid] =
815                         ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40);
816                 *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
817         }
818
819         /* parse application arguments (after the EAL ones) */
820         ret = parse_args(argc, argv);
821         if (ret < 0)
822                 rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
823
824         if (check_lcore_params() < 0)
825                 rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
826
827         ret = init_lcore_rx_queues();
828         if (ret < 0)
829                 rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
830
831         nb_ports = rte_eth_dev_count();
832         if (nb_ports > RTE_MAX_ETHPORTS)
833                 nb_ports = RTE_MAX_ETHPORTS;
834
835         if (check_port_config(nb_ports) < 0)
836                 rte_exit(EXIT_FAILURE, "check_port_config failed\n");
837
838         nb_lcores = rte_lcore_count();
839         nb_tx_port = 0;
840
841         /* Setup function pointers for lookup method. */
842         setup_l3fwd_lookup_tables();
843
844         /* initialize all ports */
845         for (portid = 0; portid < nb_ports; portid++) {
846                 /* skip ports that are not enabled */
847                 if ((enabled_port_mask & (1 << portid)) == 0) {
848                         printf("\nSkipping disabled port %d\n", portid);
849                         continue;
850                 }
851
852                 /* init port */
853                 printf("Initializing port %d ... ", portid );
854                 fflush(stdout);
855
856                 nb_rx_queue = get_port_n_rx_queues(portid);
857                 n_tx_queue = nb_lcores;
858                 if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
859                         n_tx_queue = MAX_TX_QUEUE_PER_PORT;
860                 printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
861                         nb_rx_queue, (unsigned)n_tx_queue );
862                 ret = rte_eth_dev_configure(portid, nb_rx_queue,
863                                         (uint16_t)n_tx_queue, &port_conf);
864                 if (ret < 0)
865                         rte_exit(EXIT_FAILURE,
866                                 "Cannot configure device: err=%d, port=%d\n",
867                                 ret, portid);
868
869                 rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
870                 print_ethaddr(" Address:", &ports_eth_addr[portid]);
871                 printf(", ");
872                 print_ethaddr("Destination:",
873                         (const struct ether_addr *)&dest_eth_addr[portid]);
874                 printf(", ");
875
876                 /*
877                  * prepare src MACs for each port.
878                  */
879                 ether_addr_copy(&ports_eth_addr[portid],
880                         (struct ether_addr *)(val_eth + portid) + 1);
881
882                 /* init memory */
883                 ret = init_mem(NB_MBUF);
884                 if (ret < 0)
885                         rte_exit(EXIT_FAILURE, "init_mem failed\n");
886
887                 /* init one TX queue per couple (lcore,port) */
888                 queueid = 0;
889                 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
890                         if (rte_lcore_is_enabled(lcore_id) == 0)
891                                 continue;
892
893                         if (numa_on)
894                                 socketid =
895                                 (uint8_t)rte_lcore_to_socket_id(lcore_id);
896                         else
897                                 socketid = 0;
898
899                         printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
900                         fflush(stdout);
901
902                         rte_eth_dev_info_get(portid, &dev_info);
903                         txconf = &dev_info.default_txconf;
904                         if (port_conf.rxmode.jumbo_frame)
905                                 txconf->txq_flags = 0;
906                         ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
907                                                      socketid, txconf);
908                         if (ret < 0)
909                                 rte_exit(EXIT_FAILURE,
910                                         "rte_eth_tx_queue_setup: err=%d, "
911                                         "port=%d\n", ret, portid);
912
913                         qconf = &lcore_conf[lcore_id];
914                         qconf->tx_queue_id[portid] = queueid;
915                         queueid++;
916
917                         qconf->n_tx_port = nb_tx_port;
918                         qconf->tx_port_id[qconf->n_tx_port] = portid;
919                 }
920                 printf("\n");
921
922                 nb_tx_port++;
923         }
924
925         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
926                 if (rte_lcore_is_enabled(lcore_id) == 0)
927                         continue;
928                 qconf = &lcore_conf[lcore_id];
929                 printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
930                 fflush(stdout);
931                 /* init RX queues */
932                 for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
933                         portid = qconf->rx_queue_list[queue].port_id;
934                         queueid = qconf->rx_queue_list[queue].queue_id;
935
936                         if (numa_on)
937                                 socketid =
938                                 (uint8_t)rte_lcore_to_socket_id(lcore_id);
939                         else
940                                 socketid = 0;
941
942                         printf("rxq=%d,%d,%d ", portid, queueid, socketid);
943                         fflush(stdout);
944
945                         ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd,
946                                         socketid,
947                                         NULL,
948                                         pktmbuf_pool[socketid]);
949                         if (ret < 0)
950                                 rte_exit(EXIT_FAILURE,
951                                 "rte_eth_rx_queue_setup: err=%d, port=%d\n",
952                                 ret, portid);
953                 }
954         }
955
956         printf("\n");
957
958         /* start ports */
959         for (portid = 0; portid < nb_ports; portid++) {
960                 if ((enabled_port_mask & (1 << portid)) == 0) {
961                         continue;
962                 }
963                 /* Start device */
964                 ret = rte_eth_dev_start(portid);
965                 if (ret < 0)
966                         rte_exit(EXIT_FAILURE,
967                                 "rte_eth_dev_start: err=%d, port=%d\n",
968                                 ret, portid);
969
970                 /*
971                  * If enabled, put device in promiscuous mode.
972                  * This allows IO forwarding mode to forward packets
973                  * to itself through 2 cross-connected  ports of the
974                  * target machine.
975                  */
976                 if (promiscuous_on)
977                         rte_eth_promiscuous_enable(portid);
978         }
979
980         check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask);
981
982         ret = 0;
983         /* launch per-lcore init on every lcore */
984         rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MASTER);
985         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
986                 if (rte_eal_wait_lcore(lcore_id) < 0) {
987                         ret = -1;
988                         break;
989                 }
990         }
991
992         /* stop ports */
993         for (portid = 0; portid < nb_ports; portid++) {
994                 if ((enabled_port_mask & (1 << portid)) == 0)
995                         continue;
996                 printf("Closing port %d...", portid);
997                 rte_eth_dev_stop(portid);
998                 rte_eth_dev_close(portid);
999                 printf(" Done\n");
1000         }
1001         printf("Bye...\n");
1002
1003         return ret;
1004 }