Imported Upstream version 16.07-rc2
[deb_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 static int parse_ptype; /**< Parse packet type using rx callback, and */
107                         /**< disabled by default */
108
109 /* Global variables. */
110
111 volatile bool force_quit;
112
113 /* ethernet addresses of ports */
114 uint64_t dest_eth_addr[RTE_MAX_ETHPORTS];
115 struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
116
117 xmm_t val_eth[RTE_MAX_ETHPORTS];
118
119 /* mask of enabled ports */
120 uint32_t enabled_port_mask;
121
122 /* Used only in exact match mode. */
123 int ipv6; /**< ipv6 is false by default. */
124 uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
125
126 struct lcore_conf lcore_conf[RTE_MAX_LCORE];
127
128 struct lcore_params {
129         uint8_t port_id;
130         uint8_t queue_id;
131         uint8_t lcore_id;
132 } __rte_cache_aligned;
133
134 static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
135 static struct lcore_params lcore_params_array_default[] = {
136         {0, 0, 2},
137         {0, 1, 2},
138         {0, 2, 2},
139         {1, 0, 2},
140         {1, 1, 2},
141         {1, 2, 2},
142         {2, 0, 2},
143         {3, 0, 3},
144         {3, 1, 3},
145 };
146
147 static struct lcore_params * lcore_params = lcore_params_array_default;
148 static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
149                                 sizeof(lcore_params_array_default[0]);
150
151 static struct rte_eth_conf port_conf = {
152         .rxmode = {
153                 .mq_mode = ETH_MQ_RX_RSS,
154                 .max_rx_pkt_len = ETHER_MAX_LEN,
155                 .split_hdr_size = 0,
156                 .header_split   = 0, /**< Header Split disabled */
157                 .hw_ip_checksum = 1, /**< IP checksum offload enabled */
158                 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
159                 .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
160                 .hw_strip_crc   = 0, /**< CRC stripped by hardware */
161         },
162         .rx_adv_conf = {
163                 .rss_conf = {
164                         .rss_key = NULL,
165                         .rss_hf = ETH_RSS_IP,
166                 },
167         },
168         .txmode = {
169                 .mq_mode = ETH_MQ_TX_NONE,
170         },
171 };
172
173 static struct rte_mempool * pktmbuf_pool[NB_SOCKETS];
174
175 struct l3fwd_lkp_mode {
176         void  (*setup)(int);
177         int   (*check_ptype)(int);
178         rte_rx_callback_fn cb_parse_ptype;
179         int   (*main_loop)(void *);
180         void* (*get_ipv4_lookup_struct)(int);
181         void* (*get_ipv6_lookup_struct)(int);
182 };
183
184 static struct l3fwd_lkp_mode l3fwd_lkp;
185
186 static struct l3fwd_lkp_mode l3fwd_em_lkp = {
187         .setup                  = setup_hash,
188         .check_ptype            = em_check_ptype,
189         .cb_parse_ptype         = em_cb_parse_ptype,
190         .main_loop              = em_main_loop,
191         .get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct,
192         .get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct,
193 };
194
195 static struct l3fwd_lkp_mode l3fwd_lpm_lkp = {
196         .setup                  = setup_lpm,
197         .check_ptype            = lpm_check_ptype,
198         .cb_parse_ptype         = lpm_cb_parse_ptype,
199         .main_loop              = lpm_main_loop,
200         .get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct,
201         .get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct,
202 };
203
204 /*
205  * Setup lookup methods for forwarding.
206  * Currently exact-match and longest-prefix-match
207  * are supported ones.
208  */
209 static void
210 setup_l3fwd_lookup_tables(void)
211 {
212         /* Setup HASH lookup functions. */
213         if (l3fwd_em_on)
214                 l3fwd_lkp = l3fwd_em_lkp;
215         /* Setup LPM lookup functions. */
216         else
217                 l3fwd_lkp = l3fwd_lpm_lkp;
218 }
219
220 static int
221 check_lcore_params(void)
222 {
223         uint8_t queue, lcore;
224         uint16_t i;
225         int socketid;
226
227         for (i = 0; i < nb_lcore_params; ++i) {
228                 queue = lcore_params[i].queue_id;
229                 if (queue >= MAX_RX_QUEUE_PER_PORT) {
230                         printf("invalid queue number: %hhu\n", queue);
231                         return -1;
232                 }
233                 lcore = lcore_params[i].lcore_id;
234                 if (!rte_lcore_is_enabled(lcore)) {
235                         printf("error: lcore %hhu is not enabled in lcore mask\n", lcore);
236                         return -1;
237                 }
238                 if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
239                         (numa_on == 0)) {
240                         printf("warning: lcore %hhu is on socket %d with numa off \n",
241                                 lcore, socketid);
242                 }
243         }
244         return 0;
245 }
246
247 static int
248 check_port_config(const unsigned nb_ports)
249 {
250         unsigned portid;
251         uint16_t i;
252
253         for (i = 0; i < nb_lcore_params; ++i) {
254                 portid = lcore_params[i].port_id;
255                 if ((enabled_port_mask & (1 << portid)) == 0) {
256                         printf("port %u is not enabled in port mask\n", portid);
257                         return -1;
258                 }
259                 if (portid >= nb_ports) {
260                         printf("port %u is not present on the board\n", portid);
261                         return -1;
262                 }
263         }
264         return 0;
265 }
266
267 static uint8_t
268 get_port_n_rx_queues(const uint8_t port)
269 {
270         int queue = -1;
271         uint16_t i;
272
273         for (i = 0; i < nb_lcore_params; ++i) {
274                 if (lcore_params[i].port_id == port) {
275                         if (lcore_params[i].queue_id == queue+1)
276                                 queue = lcore_params[i].queue_id;
277                         else
278                                 rte_exit(EXIT_FAILURE, "queue ids of the port %d must be"
279                                                 " in sequence and must start with 0\n",
280                                                 lcore_params[i].port_id);
281                 }
282         }
283         return (uint8_t)(++queue);
284 }
285
286 static int
287 init_lcore_rx_queues(void)
288 {
289         uint16_t i, nb_rx_queue;
290         uint8_t lcore;
291
292         for (i = 0; i < nb_lcore_params; ++i) {
293                 lcore = lcore_params[i].lcore_id;
294                 nb_rx_queue = lcore_conf[lcore].n_rx_queue;
295                 if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
296                         printf("error: too many queues (%u) for lcore: %u\n",
297                                 (unsigned)nb_rx_queue + 1, (unsigned)lcore);
298                         return -1;
299                 } else {
300                         lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
301                                 lcore_params[i].port_id;
302                         lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
303                                 lcore_params[i].queue_id;
304                         lcore_conf[lcore].n_rx_queue++;
305                 }
306         }
307         return 0;
308 }
309
310 /* display usage */
311 static void
312 print_usage(const char *prgname)
313 {
314         printf("%s [EAL options] --"
315                 " -p PORTMASK"
316                 " [-P]"
317                 " [-E]"
318                 " [-L]"
319                 " --config (port,queue,lcore)[,(port,queue,lcore)]"
320                 " [--eth-dest=X,MM:MM:MM:MM:MM:MM]"
321                 " [--enable-jumbo [--max-pkt-len PKTLEN]]"
322                 " [--no-numa]"
323                 " [--hash-entry-num]"
324                 " [--ipv6]"
325                 " [--parse-ptype]\n\n"
326
327                 "  -p PORTMASK: Hexadecimal bitmask of ports to configure\n"
328                 "  -P : Enable promiscuous mode\n"
329                 "  -E : Enable exact match\n"
330                 "  -L : Enable longest prefix match (default)\n"
331                 "  --config (port,queue,lcore): Rx queue configuration\n"
332                 "  --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n"
333                 "  --enable-jumbo: Enable jumbo frames\n"
334                 "  --max-pkt-len: Under the premise of enabling jumbo,\n"
335                 "                 maximum packet length in decimal (64-9600)\n"
336                 "  --no-numa: Disable numa awareness\n"
337                 "  --hash-entry-num: Specify the hash entry number in hexadecimal to be setup\n"
338                 "  --ipv6: Set if running ipv6 packets\n"
339                 "  --parse-ptype: Set to use software to analyze packet type\n\n",
340                 prgname);
341 }
342
343 static int
344 parse_max_pkt_len(const char *pktlen)
345 {
346         char *end = NULL;
347         unsigned long len;
348
349         /* parse decimal string */
350         len = strtoul(pktlen, &end, 10);
351         if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
352                 return -1;
353
354         if (len == 0)
355                 return -1;
356
357         return len;
358 }
359
360 static int
361 parse_portmask(const char *portmask)
362 {
363         char *end = NULL;
364         unsigned long pm;
365
366         /* parse hexadecimal string */
367         pm = strtoul(portmask, &end, 16);
368         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
369                 return -1;
370
371         if (pm == 0)
372                 return -1;
373
374         return pm;
375 }
376
377 static int
378 parse_hash_entry_number(const char *hash_entry_num)
379 {
380         char *end = NULL;
381         unsigned long hash_en;
382         /* parse hexadecimal string */
383         hash_en = strtoul(hash_entry_num, &end, 16);
384         if ((hash_entry_num[0] == '\0') || (end == NULL) || (*end != '\0'))
385                 return -1;
386
387         if (hash_en == 0)
388                 return -1;
389
390         return hash_en;
391 }
392
393 static int
394 parse_config(const char *q_arg)
395 {
396         char s[256];
397         const char *p, *p0 = q_arg;
398         char *end;
399         enum fieldnames {
400                 FLD_PORT = 0,
401                 FLD_QUEUE,
402                 FLD_LCORE,
403                 _NUM_FLD
404         };
405         unsigned long int_fld[_NUM_FLD];
406         char *str_fld[_NUM_FLD];
407         int i;
408         unsigned size;
409
410         nb_lcore_params = 0;
411
412         while ((p = strchr(p0,'(')) != NULL) {
413                 ++p;
414                 if((p0 = strchr(p,')')) == NULL)
415                         return -1;
416
417                 size = p0 - p;
418                 if(size >= sizeof(s))
419                         return -1;
420
421                 snprintf(s, sizeof(s), "%.*s", size, p);
422                 if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
423                         return -1;
424                 for (i = 0; i < _NUM_FLD; i++){
425                         errno = 0;
426                         int_fld[i] = strtoul(str_fld[i], &end, 0);
427                         if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
428                                 return -1;
429                 }
430                 if (nb_lcore_params >= MAX_LCORE_PARAMS) {
431                         printf("exceeded max number of lcore params: %hu\n",
432                                 nb_lcore_params);
433                         return -1;
434                 }
435                 lcore_params_array[nb_lcore_params].port_id =
436                         (uint8_t)int_fld[FLD_PORT];
437                 lcore_params_array[nb_lcore_params].queue_id =
438                         (uint8_t)int_fld[FLD_QUEUE];
439                 lcore_params_array[nb_lcore_params].lcore_id =
440                         (uint8_t)int_fld[FLD_LCORE];
441                 ++nb_lcore_params;
442         }
443         lcore_params = lcore_params_array;
444         return 0;
445 }
446
447 static void
448 parse_eth_dest(const char *optarg)
449 {
450         uint8_t portid;
451         char *port_end;
452         uint8_t c, *dest, peer_addr[6];
453
454         errno = 0;
455         portid = strtoul(optarg, &port_end, 10);
456         if (errno != 0 || port_end == optarg || *port_end++ != ',')
457                 rte_exit(EXIT_FAILURE,
458                 "Invalid eth-dest: %s", optarg);
459         if (portid >= RTE_MAX_ETHPORTS)
460                 rte_exit(EXIT_FAILURE,
461                 "eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n",
462                 portid, RTE_MAX_ETHPORTS);
463
464         if (cmdline_parse_etheraddr(NULL, port_end,
465                 &peer_addr, sizeof(peer_addr)) < 0)
466                 rte_exit(EXIT_FAILURE,
467                 "Invalid ethernet address: %s\n",
468                 port_end);
469         dest = (uint8_t *)&dest_eth_addr[portid];
470         for (c = 0; c < 6; c++)
471                 dest[c] = peer_addr[c];
472         *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
473 }
474
475 #define MAX_JUMBO_PKT_LEN  9600
476 #define MEMPOOL_CACHE_SIZE 256
477
478 #define CMD_LINE_OPT_CONFIG "config"
479 #define CMD_LINE_OPT_ETH_DEST "eth-dest"
480 #define CMD_LINE_OPT_NO_NUMA "no-numa"
481 #define CMD_LINE_OPT_IPV6 "ipv6"
482 #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
483 #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
484 #define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
485
486 /*
487  * This expression is used to calculate the number of mbufs needed
488  * depending on user input, taking  into account memory for rx and
489  * tx hardware rings, cache per lcore and mtable per port per lcore.
490  * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum
491  * value of 8192
492  */
493 #define NB_MBUF RTE_MAX(        \
494         (nb_ports*nb_rx_queue*RTE_TEST_RX_DESC_DEFAULT +        \
495         nb_ports*nb_lcores*MAX_PKT_BURST +                      \
496         nb_ports*n_tx_queue*RTE_TEST_TX_DESC_DEFAULT +          \
497         nb_lcores*MEMPOOL_CACHE_SIZE),                          \
498         (unsigned)8192)
499
500 /* Parse the argument given in the command line of the application */
501 static int
502 parse_args(int argc, char **argv)
503 {
504         int opt, ret;
505         char **argvopt;
506         int option_index;
507         char *prgname = argv[0];
508         static struct option lgopts[] = {
509                 {CMD_LINE_OPT_CONFIG, 1, 0, 0},
510                 {CMD_LINE_OPT_ETH_DEST, 1, 0, 0},
511                 {CMD_LINE_OPT_NO_NUMA, 0, 0, 0},
512                 {CMD_LINE_OPT_IPV6, 0, 0, 0},
513                 {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0},
514                 {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0},
515                 {CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0},
516                 {NULL, 0, 0, 0}
517         };
518
519         argvopt = argv;
520
521         /* Error or normal output strings. */
522         const char *str1 = "L3FWD: Invalid portmask";
523         const char *str2 = "L3FWD: Promiscuous mode selected";
524         const char *str3 = "L3FWD: Exact match selected";
525         const char *str4 = "L3FWD: Longest-prefix match selected";
526         const char *str5 = "L3FWD: Invalid config";
527         const char *str6 = "L3FWD: NUMA is disabled";
528         const char *str7 = "L3FWD: IPV6 is specified";
529         const char *str8 =
530                 "L3FWD: Jumbo frame is enabled - disabling simple TX path";
531         const char *str9 = "L3FWD: Invalid packet length";
532         const char *str10 = "L3FWD: Set jumbo frame max packet len to ";
533         const char *str11 = "L3FWD: Invalid hash entry number";
534         const char *str12 =
535                 "L3FWD: LPM and EM are mutually exclusive, select only one";
536         const char *str13 = "L3FWD: LPM or EM none selected, default LPM on";
537
538         while ((opt = getopt_long(argc, argvopt, "p:PLE",
539                                 lgopts, &option_index)) != EOF) {
540
541                 switch (opt) {
542                 /* portmask */
543                 case 'p':
544                         enabled_port_mask = parse_portmask(optarg);
545                         if (enabled_port_mask == 0) {
546                                 printf("%s\n", str1);
547                                 print_usage(prgname);
548                                 return -1;
549                         }
550                         break;
551                 case 'P':
552                         printf("%s\n", str2);
553                         promiscuous_on = 1;
554                         break;
555
556                 case 'E':
557                         printf("%s\n", str3);
558                         l3fwd_em_on = 1;
559                         break;
560
561                 case 'L':
562                         printf("%s\n", str4);
563                         l3fwd_lpm_on = 1;
564                         break;
565
566                 /* long options */
567                 case 0:
568                         if (!strncmp(lgopts[option_index].name,
569                                         CMD_LINE_OPT_CONFIG,
570                                         sizeof(CMD_LINE_OPT_CONFIG))) {
571
572                                 ret = parse_config(optarg);
573                                 if (ret) {
574                                         printf("%s\n", str5);
575                                         print_usage(prgname);
576                                         return -1;
577                                 }
578                         }
579
580                         if (!strncmp(lgopts[option_index].name,
581                                         CMD_LINE_OPT_ETH_DEST,
582                                         sizeof(CMD_LINE_OPT_ETH_DEST))) {
583                                         parse_eth_dest(optarg);
584                         }
585
586                         if (!strncmp(lgopts[option_index].name,
587                                         CMD_LINE_OPT_NO_NUMA,
588                                         sizeof(CMD_LINE_OPT_NO_NUMA))) {
589                                 printf("%s\n", str6);
590                                 numa_on = 0;
591                         }
592
593                         if (!strncmp(lgopts[option_index].name,
594                                 CMD_LINE_OPT_IPV6,
595                                 sizeof(CMD_LINE_OPT_IPV6))) {
596                                 printf("%sn", str7);
597                                 ipv6 = 1;
598                         }
599
600                         if (!strncmp(lgopts[option_index].name,
601                                         CMD_LINE_OPT_ENABLE_JUMBO,
602                                         sizeof(CMD_LINE_OPT_ENABLE_JUMBO))) {
603                                 struct option lenopts = {
604                                         "max-pkt-len", required_argument, 0, 0
605                                 };
606
607                                 printf("%s\n", str8);
608                                 port_conf.rxmode.jumbo_frame = 1;
609
610                                 /*
611                                  * if no max-pkt-len set, use the default
612                                  * value ETHER_MAX_LEN.
613                                  */
614                                 if (0 == getopt_long(argc, argvopt, "",
615                                                 &lenopts, &option_index)) {
616                                         ret = parse_max_pkt_len(optarg);
617                                         if ((ret < 64) ||
618                                                 (ret > MAX_JUMBO_PKT_LEN)) {
619                                                 printf("%s\n", str9);
620                                                 print_usage(prgname);
621                                                 return -1;
622                                         }
623                                         port_conf.rxmode.max_rx_pkt_len = ret;
624                                 }
625                                 printf("%s %u\n", str10,
626                                 (unsigned int)port_conf.rxmode.max_rx_pkt_len);
627                         }
628
629                         if (!strncmp(lgopts[option_index].name,
630                                 CMD_LINE_OPT_HASH_ENTRY_NUM,
631                                 sizeof(CMD_LINE_OPT_HASH_ENTRY_NUM))) {
632
633                                 ret = parse_hash_entry_number(optarg);
634                                 if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) {
635                                         hash_entry_number = ret;
636                                 } else {
637                                         printf("%s\n", str11);
638                                         print_usage(prgname);
639                                         return -1;
640                                 }
641                         }
642
643                         if (!strncmp(lgopts[option_index].name,
644                                      CMD_LINE_OPT_PARSE_PTYPE,
645                                      sizeof(CMD_LINE_OPT_PARSE_PTYPE))) {
646                                 printf("soft parse-ptype is enabled\n");
647                                 parse_ptype = 1;
648                         }
649
650                         break;
651
652                 default:
653                         print_usage(prgname);
654                         return -1;
655                 }
656         }
657
658         /* If both LPM and EM are selected, return error. */
659         if (l3fwd_lpm_on && l3fwd_em_on) {
660                 printf("%s\n", str12);
661                 return -1;
662         }
663
664         /*
665          * Nothing is selected, pick longest-prefix match
666          * as default match.
667          */
668         if (!l3fwd_lpm_on && !l3fwd_em_on) {
669                 l3fwd_lpm_on = 1;
670                 printf("%s\n", str13);
671         }
672
673         /*
674          * ipv6 and hash flags are valid only for
675          * exact macth, reset them to default for
676          * longest-prefix match.
677          */
678         if (l3fwd_lpm_on) {
679                 ipv6 = 0;
680                 hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
681         }
682
683         if (optind >= 0)
684                 argv[optind-1] = prgname;
685
686         ret = optind-1;
687         optind = 0; /* reset getopt lib */
688         return ret;
689 }
690
691 static void
692 print_ethaddr(const char *name, const struct ether_addr *eth_addr)
693 {
694         char buf[ETHER_ADDR_FMT_SIZE];
695         ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
696         printf("%s%s", name, buf);
697 }
698
699 static int
700 init_mem(unsigned nb_mbuf)
701 {
702         struct lcore_conf *qconf;
703         int socketid;
704         unsigned lcore_id;
705         char s[64];
706
707         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
708                 if (rte_lcore_is_enabled(lcore_id) == 0)
709                         continue;
710
711                 if (numa_on)
712                         socketid = rte_lcore_to_socket_id(lcore_id);
713                 else
714                         socketid = 0;
715
716                 if (socketid >= NB_SOCKETS) {
717                         rte_exit(EXIT_FAILURE,
718                                 "Socket %d of lcore %u is out of range %d\n",
719                                 socketid, lcore_id, NB_SOCKETS);
720                 }
721
722                 if (pktmbuf_pool[socketid] == NULL) {
723                         snprintf(s, sizeof(s), "mbuf_pool_%d", socketid);
724                         pktmbuf_pool[socketid] =
725                                 rte_pktmbuf_pool_create(s, nb_mbuf,
726                                         MEMPOOL_CACHE_SIZE, 0,
727                                         RTE_MBUF_DEFAULT_BUF_SIZE, socketid);
728                         if (pktmbuf_pool[socketid] == NULL)
729                                 rte_exit(EXIT_FAILURE,
730                                         "Cannot init mbuf pool on socket %d\n",
731                                         socketid);
732                         else
733                                 printf("Allocated mbuf pool on socket %d\n",
734                                         socketid);
735
736                         /* Setup either LPM or EM(f.e Hash).  */
737                         l3fwd_lkp.setup(socketid);
738                 }
739                 qconf = &lcore_conf[lcore_id];
740                 qconf->ipv4_lookup_struct =
741                         l3fwd_lkp.get_ipv4_lookup_struct(socketid);
742                 qconf->ipv6_lookup_struct =
743                         l3fwd_lkp.get_ipv6_lookup_struct(socketid);
744         }
745         return 0;
746 }
747
748 /* Check the link status of all ports in up to 9s, and print them finally */
749 static void
750 check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
751 {
752 #define CHECK_INTERVAL 100 /* 100ms */
753 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
754         uint8_t portid, count, all_ports_up, print_flag = 0;
755         struct rte_eth_link link;
756
757         printf("\nChecking link status");
758         fflush(stdout);
759         for (count = 0; count <= MAX_CHECK_TIME; count++) {
760                 if (force_quit)
761                         return;
762                 all_ports_up = 1;
763                 for (portid = 0; portid < port_num; portid++) {
764                         if (force_quit)
765                                 return;
766                         if ((port_mask & (1 << portid)) == 0)
767                                 continue;
768                         memset(&link, 0, sizeof(link));
769                         rte_eth_link_get_nowait(portid, &link);
770                         /* print link status if flag set */
771                         if (print_flag == 1) {
772                                 if (link.link_status)
773                                         printf("Port %d Link Up - speed %u "
774                                                 "Mbps - %s\n", (uint8_t)portid,
775                                                 (unsigned)link.link_speed,
776                                 (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
777                                         ("full-duplex") : ("half-duplex\n"));
778                                 else
779                                         printf("Port %d Link Down\n",
780                                                 (uint8_t)portid);
781                                 continue;
782                         }
783                         /* clear all_ports_up flag if any link down */
784                         if (link.link_status == ETH_LINK_DOWN) {
785                                 all_ports_up = 0;
786                                 break;
787                         }
788                 }
789                 /* after finally printing all link status, get out */
790                 if (print_flag == 1)
791                         break;
792
793                 if (all_ports_up == 0) {
794                         printf(".");
795                         fflush(stdout);
796                         rte_delay_ms(CHECK_INTERVAL);
797                 }
798
799                 /* set the print_flag if all ports up or timeout */
800                 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
801                         print_flag = 1;
802                         printf("done\n");
803                 }
804         }
805 }
806
807 static void
808 signal_handler(int signum)
809 {
810         if (signum == SIGINT || signum == SIGTERM) {
811                 printf("\n\nSignal %d received, preparing to exit...\n",
812                                 signum);
813                 force_quit = true;
814         }
815 }
816
817 static int
818 prepare_ptype_parser(uint8_t portid, uint16_t queueid)
819 {
820         if (parse_ptype) {
821                 printf("Port %d: softly parse packet type info\n", portid);
822                 if (rte_eth_add_rx_callback(portid, queueid,
823                                             l3fwd_lkp.cb_parse_ptype,
824                                             NULL))
825                         return 1;
826
827                 printf("Failed to add rx callback: port=%d\n", portid);
828                 return 0;
829         }
830
831         if (l3fwd_lkp.check_ptype(portid))
832                 return 1;
833
834         printf("port %d cannot parse packet type, please add --%s\n",
835                portid, CMD_LINE_OPT_PARSE_PTYPE);
836         return 0;
837 }
838
839 int
840 main(int argc, char **argv)
841 {
842         struct lcore_conf *qconf;
843         struct rte_eth_dev_info dev_info;
844         struct rte_eth_txconf *txconf;
845         int ret;
846         unsigned nb_ports;
847         uint16_t queueid;
848         unsigned lcore_id;
849         uint32_t n_tx_queue, nb_lcores;
850         uint8_t portid, nb_rx_queue, queue, socketid;
851
852         /* init EAL */
853         ret = rte_eal_init(argc, argv);
854         if (ret < 0)
855                 rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
856         argc -= ret;
857         argv += ret;
858
859         force_quit = false;
860         signal(SIGINT, signal_handler);
861         signal(SIGTERM, signal_handler);
862
863         /* pre-init dst MACs for all ports to 02:00:00:00:00:xx */
864         for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
865                 dest_eth_addr[portid] =
866                         ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40);
867                 *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
868         }
869
870         /* parse application arguments (after the EAL ones) */
871         ret = parse_args(argc, argv);
872         if (ret < 0)
873                 rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
874
875         if (check_lcore_params() < 0)
876                 rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
877
878         ret = init_lcore_rx_queues();
879         if (ret < 0)
880                 rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
881
882         nb_ports = rte_eth_dev_count();
883
884         if (check_port_config(nb_ports) < 0)
885                 rte_exit(EXIT_FAILURE, "check_port_config failed\n");
886
887         nb_lcores = rte_lcore_count();
888
889         /* Setup function pointers for lookup method. */
890         setup_l3fwd_lookup_tables();
891
892         /* initialize all ports */
893         for (portid = 0; portid < nb_ports; portid++) {
894                 /* skip ports that are not enabled */
895                 if ((enabled_port_mask & (1 << portid)) == 0) {
896                         printf("\nSkipping disabled port %d\n", portid);
897                         continue;
898                 }
899
900                 /* init port */
901                 printf("Initializing port %d ... ", portid );
902                 fflush(stdout);
903
904                 nb_rx_queue = get_port_n_rx_queues(portid);
905                 n_tx_queue = nb_lcores;
906                 if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
907                         n_tx_queue = MAX_TX_QUEUE_PER_PORT;
908                 printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
909                         nb_rx_queue, (unsigned)n_tx_queue );
910                 ret = rte_eth_dev_configure(portid, nb_rx_queue,
911                                         (uint16_t)n_tx_queue, &port_conf);
912                 if (ret < 0)
913                         rte_exit(EXIT_FAILURE,
914                                 "Cannot configure device: err=%d, port=%d\n",
915                                 ret, portid);
916
917                 rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
918                 print_ethaddr(" Address:", &ports_eth_addr[portid]);
919                 printf(", ");
920                 print_ethaddr("Destination:",
921                         (const struct ether_addr *)&dest_eth_addr[portid]);
922                 printf(", ");
923
924                 /*
925                  * prepare src MACs for each port.
926                  */
927                 ether_addr_copy(&ports_eth_addr[portid],
928                         (struct ether_addr *)(val_eth + portid) + 1);
929
930                 /* init memory */
931                 ret = init_mem(NB_MBUF);
932                 if (ret < 0)
933                         rte_exit(EXIT_FAILURE, "init_mem failed\n");
934
935                 /* init one TX queue per couple (lcore,port) */
936                 queueid = 0;
937                 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
938                         if (rte_lcore_is_enabled(lcore_id) == 0)
939                                 continue;
940
941                         if (numa_on)
942                                 socketid =
943                                 (uint8_t)rte_lcore_to_socket_id(lcore_id);
944                         else
945                                 socketid = 0;
946
947                         printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
948                         fflush(stdout);
949
950                         rte_eth_dev_info_get(portid, &dev_info);
951                         txconf = &dev_info.default_txconf;
952                         if (port_conf.rxmode.jumbo_frame)
953                                 txconf->txq_flags = 0;
954                         ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
955                                                      socketid, txconf);
956                         if (ret < 0)
957                                 rte_exit(EXIT_FAILURE,
958                                         "rte_eth_tx_queue_setup: err=%d, "
959                                         "port=%d\n", ret, portid);
960
961                         qconf = &lcore_conf[lcore_id];
962                         qconf->tx_queue_id[portid] = queueid;
963                         queueid++;
964
965                         qconf->tx_port_id[qconf->n_tx_port] = portid;
966                         qconf->n_tx_port++;
967                 }
968                 printf("\n");
969         }
970
971         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
972                 if (rte_lcore_is_enabled(lcore_id) == 0)
973                         continue;
974                 qconf = &lcore_conf[lcore_id];
975                 printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
976                 fflush(stdout);
977                 /* init RX queues */
978                 for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
979                         portid = qconf->rx_queue_list[queue].port_id;
980                         queueid = qconf->rx_queue_list[queue].queue_id;
981
982                         if (numa_on)
983                                 socketid =
984                                 (uint8_t)rte_lcore_to_socket_id(lcore_id);
985                         else
986                                 socketid = 0;
987
988                         printf("rxq=%d,%d,%d ", portid, queueid, socketid);
989                         fflush(stdout);
990
991                         ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd,
992                                         socketid,
993                                         NULL,
994                                         pktmbuf_pool[socketid]);
995                         if (ret < 0)
996                                 rte_exit(EXIT_FAILURE,
997                                 "rte_eth_rx_queue_setup: err=%d, port=%d\n",
998                                 ret, portid);
999                 }
1000         }
1001
1002         printf("\n");
1003
1004         /* start ports */
1005         for (portid = 0; portid < nb_ports; portid++) {
1006                 if ((enabled_port_mask & (1 << portid)) == 0) {
1007                         continue;
1008                 }
1009                 /* Start device */
1010                 ret = rte_eth_dev_start(portid);
1011                 if (ret < 0)
1012                         rte_exit(EXIT_FAILURE,
1013                                 "rte_eth_dev_start: err=%d, port=%d\n",
1014                                 ret, portid);
1015
1016                 /*
1017                  * If enabled, put device in promiscuous mode.
1018                  * This allows IO forwarding mode to forward packets
1019                  * to itself through 2 cross-connected  ports of the
1020                  * target machine.
1021                  */
1022                 if (promiscuous_on)
1023                         rte_eth_promiscuous_enable(portid);
1024         }
1025
1026         printf("\n");
1027
1028         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1029                 if (rte_lcore_is_enabled(lcore_id) == 0)
1030                         continue;
1031                 qconf = &lcore_conf[lcore_id];
1032                 for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
1033                         portid = qconf->rx_queue_list[queue].port_id;
1034                         queueid = qconf->rx_queue_list[queue].queue_id;
1035                         if (prepare_ptype_parser(portid, queueid) == 0)
1036                                 rte_exit(EXIT_FAILURE, "ptype check fails\n");
1037                 }
1038         }
1039
1040
1041         check_all_ports_link_status((uint8_t)nb_ports, enabled_port_mask);
1042
1043         ret = 0;
1044         /* launch per-lcore init on every lcore */
1045         rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MASTER);
1046         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1047                 if (rte_eal_wait_lcore(lcore_id) < 0) {
1048                         ret = -1;
1049                         break;
1050                 }
1051         }
1052
1053         /* stop ports */
1054         for (portid = 0; portid < nb_ports; portid++) {
1055                 if ((enabled_port_mask & (1 << portid)) == 0)
1056                         continue;
1057                 printf("Closing port %d...", portid);
1058                 rte_eth_dev_stop(portid);
1059                 rte_eth_dev_close(portid);
1060                 printf(" Done\n");
1061         }
1062         printf("Bye...\n");
1063
1064         return ret;
1065 }