examples/l3fwd: support config file for LPM/FIB
authorSean Morrissey <sean.morrissey@intel.com>
Tue, 1 Mar 2022 14:49:07 +0000 (14:49 +0000)
committerThomas Monjalon <thomas@monjalon.net>
Tue, 8 Mar 2022 08:59:42 +0000 (09:59 +0100)
Add support to define ipv4 and ipv6 forwarding tables
from reading from a config file for LPM and FIB,
with format similar to l3fwd-acl one.

Users can now use the default hardcoded route tables
or optionally config files. Default config files have
been provided for use with LPM and FIB.

Signed-off-by: Sean Morrissey <sean.morrissey@intel.com>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Tested-by: Yingya Han <yingyax.han@intel.com>
examples/l3fwd/em_route_parse.c [new file with mode: 0644]
examples/l3fwd/l3fwd.h
examples/l3fwd/l3fwd_em.c
examples/l3fwd/l3fwd_fib.c
examples/l3fwd/l3fwd_lpm.c
examples/l3fwd/l3fwd_route.h
examples/l3fwd/lpm_default_v4.cfg [new file with mode: 0644]
examples/l3fwd/lpm_default_v6.cfg [new file with mode: 0644]
examples/l3fwd/lpm_route_parse.c [new file with mode: 0644]
examples/l3fwd/main.c

diff --git a/examples/l3fwd/em_route_parse.c b/examples/l3fwd/em_route_parse.c
new file mode 100644 (file)
index 0000000..11d83d9
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+
+#include "l3fwd_route.h"
+
+void
+em_free_routes(void)
+{
+       /* Empty till config file support added to EM */
+}
+
+/* Load rules from the input file */
+void
+read_config_files_em(void)
+{
+       /* Empty till config file support added to EM */
+}
index 38ca191..002510b 100644 (file)
 #endif
 #define HASH_ENTRY_NUMBER_DEFAULT      16
 
+struct parm_cfg {
+       const char *rule_ipv4_name;
+       const char *rule_ipv6_name;
+};
+
 struct mbuf_table {
        uint16_t len;
        struct rte_mbuf *m_table[MAX_PKT_BURST];
@@ -96,6 +101,8 @@ extern xmm_t val_eth[RTE_MAX_ETHPORTS];
 
 extern struct lcore_conf lcore_conf[RTE_MAX_LCORE];
 
+extern struct parm_cfg parm_config;
+
 /* Send burst of packets on an output interface */
 static inline int
 send_burst(struct lcore_conf *qconf, uint16_t n, uint16_t port)
index 5cc4a4d..de5be9e 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "l3fwd.h"
 #include "l3fwd_event.h"
+#include "em_route_parse.c"
 
 #if defined(RTE_ARCH_X86) || defined(__ARM_FEATURE_CRC32)
 #define EM_HASH_CRC 1
index 2110459..6e0054b 100644 (file)
@@ -583,7 +583,7 @@ setup_fib(const int socketid)
        struct rte_eth_dev_info dev_info;
        struct rte_fib6_conf config;
        struct rte_fib_conf config_ipv4;
-       unsigned int i;
+       int i;
        int ret;
        char s[64];
        char abuf[INET6_ADDRSTRLEN];
@@ -603,37 +603,39 @@ setup_fib(const int socketid)
                        "Unable to create the l3fwd FIB table on socket %d\n",
                        socketid);
 
+
        /* Populate the fib ipv4 table. */
-       for (i = 0; i < RTE_DIM(ipv4_l3fwd_route_array); i++) {
+       for (i = 0; i < route_num_v4; i++) {
                struct in_addr in;
 
                /* Skip unused ports. */
-               if ((1 << ipv4_l3fwd_route_array[i].if_out &
+               if ((1 << route_base_v4[i].if_out &
                                enabled_port_mask) == 0)
                        continue;
 
-               rte_eth_dev_info_get(ipv4_l3fwd_route_array[i].if_out,
+               rte_eth_dev_info_get(route_base_v4[i].if_out,
                                     &dev_info);
                ret = rte_fib_add(ipv4_l3fwd_fib_lookup_struct[socketid],
-                       ipv4_l3fwd_route_array[i].ip,
-                       ipv4_l3fwd_route_array[i].depth,
-                       ipv4_l3fwd_route_array[i].if_out);
+                       route_base_v4[i].ip,
+                       route_base_v4[i].depth,
+                       route_base_v4[i].if_out);
 
                if (ret < 0) {
+                       free(route_base_v4);
                        rte_exit(EXIT_FAILURE,
                                        "Unable to add entry %u to the l3fwd FIB table on socket %d\n",
                                        i, socketid);
                }
 
-               in.s_addr = htonl(ipv4_l3fwd_route_array[i].ip);
+               in.s_addr = htonl(route_base_v4[i].ip);
                if (inet_ntop(AF_INET, &in, abuf, sizeof(abuf)) != NULL) {
                        printf("FIB: Adding route %s / %d (%d) [%s]\n", abuf,
-                              ipv4_l3fwd_route_array[i].depth,
-                              ipv4_l3fwd_route_array[i].if_out,
+                              route_base_v4[i].depth,
+                              route_base_v4[i].if_out,
                               dev_info.device->name);
                } else {
                        printf("FIB: IPv4 route added to port %d [%s]\n",
-                              ipv4_l3fwd_route_array[i].if_out,
+                              route_base_v4[i].if_out,
                               dev_info.device->name);
                }
        }
@@ -650,41 +652,45 @@ setup_fib(const int socketid)
        config.trie.num_tbl8 = (1 << 15);
        ipv6_l3fwd_fib_lookup_struct[socketid] = rte_fib6_create(s, socketid,
                        &config);
-       if (ipv6_l3fwd_fib_lookup_struct[socketid] == NULL)
+       if (ipv6_l3fwd_fib_lookup_struct[socketid] == NULL) {
+               free(route_base_v4);
                rte_exit(EXIT_FAILURE,
                                "Unable to create the l3fwd FIB table on socket %d\n",
                                socketid);
+       }
 
        /* Populate the fib IPv6 table. */
-       for (i = 0; i < RTE_DIM(ipv6_l3fwd_route_array); i++) {
+       for (i = 0; i < route_num_v6; i++) {
 
                /* Skip unused ports. */
-               if ((1 << ipv6_l3fwd_route_array[i].if_out &
+               if ((1 << route_base_v6[i].if_out &
                                enabled_port_mask) == 0)
                        continue;
 
-               rte_eth_dev_info_get(ipv6_l3fwd_route_array[i].if_out,
+               rte_eth_dev_info_get(route_base_v6[i].if_out,
                                     &dev_info);
                ret = rte_fib6_add(ipv6_l3fwd_fib_lookup_struct[socketid],
-                       ipv6_l3fwd_route_array[i].ip,
-                       ipv6_l3fwd_route_array[i].depth,
-                       ipv6_l3fwd_route_array[i].if_out);
+                       route_base_v6[i].ip_8,
+                       route_base_v6[i].depth,
+                       route_base_v6[i].if_out);
 
                if (ret < 0) {
+                       free(route_base_v4);
+                       free(route_base_v6);
                        rte_exit(EXIT_FAILURE,
                                        "Unable to add entry %u to the l3fwd FIB table on socket %d\n",
                                        i, socketid);
                }
 
-               if (inet_ntop(AF_INET6, ipv6_l3fwd_route_array[i].ip,
+               if (inet_ntop(AF_INET6, route_base_v6[i].ip_8,
                                abuf, sizeof(abuf)) != NULL) {
                        printf("FIB: Adding route %s / %d (%d) [%s]\n", abuf,
-                              ipv6_l3fwd_route_array[i].depth,
-                              ipv6_l3fwd_route_array[i].if_out,
+                              route_base_v6[i].depth,
+                              route_base_v6[i].if_out,
                               dev_info.device->name);
                } else {
                        printf("FIB: IPv6 route added to port %d [%s]\n",
-                              ipv6_l3fwd_route_array[i].if_out,
+                              route_base_v6[i].if_out,
                               dev_info.device->name);
                }
        }
index a5b476c..bec22c4 100644 (file)
@@ -30,7 +30,7 @@
 #include "l3fwd.h"
 #include "l3fwd_event.h"
 
-#include "l3fwd_route.h"
+#include "lpm_route_parse.c"
 
 #define IPV4_L3FWD_LPM_MAX_RULES         1024
 #define IPV4_L3FWD_LPM_NUMBER_TBL8S (1 << 8)
@@ -554,7 +554,7 @@ setup_lpm(const int socketid)
        struct rte_eth_dev_info dev_info;
        struct rte_lpm6_config config;
        struct rte_lpm_config config_ipv4;
-       unsigned i;
+       int i;
        int ret;
        char s[64];
        char abuf[INET6_ADDRSTRLEN];
@@ -572,32 +572,33 @@ setup_lpm(const int socketid)
                        socketid);
 
        /* populate the LPM table */
-       for (i = 0; i < RTE_DIM(ipv4_l3fwd_route_array); i++) {
+       for (i = 0; i < route_num_v4; i++) {
                struct in_addr in;
 
                /* skip unused ports */
-               if ((1 << ipv4_l3fwd_route_array[i].if_out &
+               if ((1 << route_base_v4[i].if_out &
                                enabled_port_mask) == 0)
                        continue;
 
-               rte_eth_dev_info_get(ipv4_l3fwd_route_array[i].if_out,
+               rte_eth_dev_info_get(route_base_v4[i].if_out,
                                     &dev_info);
                ret = rte_lpm_add(ipv4_l3fwd_lpm_lookup_struct[socketid],
-                       ipv4_l3fwd_route_array[i].ip,
-                       ipv4_l3fwd_route_array[i].depth,
-                       ipv4_l3fwd_route_array[i].if_out);
+                       route_base_v4[i].ip,
+                       route_base_v4[i].depth,
+                       route_base_v4[i].if_out);
 
                if (ret < 0) {
+                       lpm_free_routes();
                        rte_exit(EXIT_FAILURE,
                                "Unable to add entry %u to the l3fwd LPM table on socket %d\n",
                                i, socketid);
                }
 
-               in.s_addr = htonl(ipv4_l3fwd_route_array[i].ip);
+               in.s_addr = htonl(route_base_v4[i].ip);
                printf("LPM: Adding route %s / %d (%d) [%s]\n",
                       inet_ntop(AF_INET, &in, abuf, sizeof(abuf)),
-                      ipv4_l3fwd_route_array[i].depth,
-                      ipv4_l3fwd_route_array[i].if_out, dev_info.device->name);
+                      route_base_v4[i].depth,
+                      route_base_v4[i].if_out, dev_info.device->name);
        }
 
        /* create the LPM6 table */
@@ -608,37 +609,40 @@ setup_lpm(const int socketid)
        config.flags = 0;
        ipv6_l3fwd_lpm_lookup_struct[socketid] = rte_lpm6_create(s, socketid,
                                &config);
-       if (ipv6_l3fwd_lpm_lookup_struct[socketid] == NULL)
+       if (ipv6_l3fwd_lpm_lookup_struct[socketid] == NULL) {
+               lpm_free_routes();
                rte_exit(EXIT_FAILURE,
                        "Unable to create the l3fwd LPM table on socket %d\n",
                        socketid);
+       }
 
        /* populate the LPM table */
-       for (i = 0; i < RTE_DIM(ipv6_l3fwd_route_array); i++) {
+       for (i = 0; i < route_num_v6; i++) {
 
                /* skip unused ports */
-               if ((1 << ipv6_l3fwd_route_array[i].if_out &
+               if ((1 << route_base_v6[i].if_out &
                                enabled_port_mask) == 0)
                        continue;
 
-               rte_eth_dev_info_get(ipv4_l3fwd_route_array[i].if_out,
+               rte_eth_dev_info_get(route_base_v6[i].if_out,
                                     &dev_info);
                ret = rte_lpm6_add(ipv6_l3fwd_lpm_lookup_struct[socketid],
-                       ipv6_l3fwd_route_array[i].ip,
-                       ipv6_l3fwd_route_array[i].depth,
-                       ipv6_l3fwd_route_array[i].if_out);
+                       route_base_v6[i].ip_8,
+                       route_base_v6[i].depth,
+                       route_base_v6[i].if_out);
 
                if (ret < 0) {
+                       lpm_free_routes();
                        rte_exit(EXIT_FAILURE,
                                "Unable to add entry %u to the l3fwd LPM table on socket %d\n",
                                i, socketid);
                }
 
                printf("LPM: Adding route %s / %d (%d) [%s]\n",
-                      inet_ntop(AF_INET6, ipv6_l3fwd_route_array[i].ip, abuf,
+                      inet_ntop(AF_INET6, route_base_v6[i].ip_8, abuf,
                                 sizeof(abuf)),
-                      ipv6_l3fwd_route_array[i].depth,
-                      ipv6_l3fwd_route_array[i].if_out, dev_info.device->name);
+                      route_base_v6[i].depth,
+                      route_base_v6[i].if_out, dev_info.device->name);
        }
 }
 
index c7eba06..48b4972 100644 (file)
@@ -2,6 +2,25 @@
  * Copyright(c) 2021 Intel Corporation
  */
 
+/* Log file related character defs. */
+#define COMMENT_LEAD_CHAR      ('#')
+#define ROUTE_LEAD_CHAR                ('R')
+
+#define        IPV6_ADDR_LEN   16
+#define        IPV6_ADDR_U16   (IPV6_ADDR_LEN / sizeof(uint16_t))
+#define        IPV6_ADDR_U32   (IPV6_ADDR_LEN / sizeof(uint32_t))
+
+#define GET_CB_FIELD(in, fd, base, lim, dlm)   do {            \
+       unsigned long val;                                      \
+       char *end;                                              \
+       errno = 0;                                              \
+       val = strtoul((in), &end, (base));                      \
+       if (errno != 0 || end[0] != (dlm) || val > (lim))       \
+               return -EINVAL;                                 \
+       (fd) = (typeof(fd))val;                                 \
+       (in) = end + 1;                                         \
+} while (0)
+
 struct ipv4_l3fwd_route {
        uint32_t ip;
        uint8_t  depth;
@@ -14,6 +33,38 @@ struct ipv6_l3fwd_route {
        uint8_t if_out;
 };
 
+struct lpm_route_rule {
+       union {
+               uint32_t ip;
+               union {
+                       uint32_t ip_32[IPV6_ADDR_U32];
+                       uint8_t ip_8[IPV6_ADDR_LEN];
+               };
+       };
+       uint8_t depth;
+       uint8_t if_out;
+};
+
+extern struct lpm_route_rule *route_base_v4;
+extern struct lpm_route_rule *route_base_v6;
+extern int route_num_v4;
+extern int route_num_v6;
+
 extern const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[16];
 
 extern const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[16];
+
+void
+read_config_files_lpm(void);
+
+void
+read_config_files_em(void);
+
+void
+em_free_routes(void);
+
+void
+lpm_free_routes(void);
+
+int
+is_bypass_line(const char *buff);
diff --git a/examples/l3fwd/lpm_default_v4.cfg b/examples/l3fwd/lpm_default_v4.cfg
new file mode 100644 (file)
index 0000000..15224ca
--- /dev/null
@@ -0,0 +1,17 @@
+# Copy of hard-coded IPv4 FWD table for L3FWD LPM
+R198.18.0.0/24 0
+R198.18.1.0/24 1
+R198.18.2.0/24 2
+R198.18.3.0/24 3
+R198.18.4.0/24 4
+R198.18.5.0/24 5
+R198.18.6.0/24 6
+R198.18.7.0/24 7
+R198.18.8.0/24 8
+R198.18.9.0/24 9
+R198.18.10.0/24 10
+R198.18.11.0/24 11
+R198.18.12.0/24 12
+R198.18.13.0/24 13
+R198.18.14.0/24 14
+R198.18.15.0/24 15
diff --git a/examples/l3fwd/lpm_default_v6.cfg b/examples/l3fwd/lpm_default_v6.cfg
new file mode 100644 (file)
index 0000000..c69b241
--- /dev/null
@@ -0,0 +1,17 @@
+# Copy of hard-coded IPv6 FWD table for L3FWD LPM
+R2001:0200:0000:0000:0000:0000:0000:0000/64 0
+R2001:0200:0000:0001:0000:0000:0000:0000/64 1
+R2001:0200:0000:0002:0000:0000:0000:0000/64 2
+R2001:0200:0000:0003:0000:0000:0000:0000/64 3
+R2001:0200:0000:0004:0000:0000:0000:0000/64 4
+R2001:0200:0000:0005:0000:0000:0000:0000/64 5
+R2001:0200:0000:0006:0000:0000:0000:0000/64 6
+R2001:0200:0000:0007:0000:0000:0000:0000/64 7
+R2001:0200:0000:0008:0000:0000:0000:0000/64 8
+R2001:0200:0000:0009:0000:0000:0000:0000/64 9
+R2001:0200:0000:000A:0000:0000:0000:0000/64 10
+R2001:0200:0000:000B:0000:0000:0000:0000/64 11
+R2001:0200:0000:000C:0000:0000:0000:0000/64 12
+R2001:0200:0000:000D:0000:0000:0000:0000/64 13
+R2001:0200:0000:000E:0000:0000:0000:0000/64 14
+R2001:0200:0000:000F:0000:0000:0000:0000/64 15
diff --git a/examples/l3fwd/lpm_route_parse.c b/examples/l3fwd/lpm_route_parse.c
new file mode 100644 (file)
index 0000000..f2028d7
--- /dev/null
@@ -0,0 +1,302 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+#include "l3fwd.h"
+#include "l3fwd_route.h"
+
+enum {
+       CB_FLD_DST_ADDR,
+       CB_FLD_IF_OUT,
+       CB_FLD_MAX
+};
+
+struct lpm_route_rule *route_base_v4;
+struct lpm_route_rule *route_base_v6;
+int route_num_v4;
+int route_num_v6;
+
+/* Bypass comment and empty lines */
+int
+is_bypass_line(const char *buff)
+{
+       int i = 0;
+
+       /* comment line */
+       if (buff[0] == COMMENT_LEAD_CHAR)
+               return 1;
+       /* empty line */
+       while (buff[i] != '\0') {
+               if (!isspace(buff[i]))
+                       return 0;
+               i++;
+       }
+       return 1;
+}
+
+static int
+parse_ipv6_addr_mask(char *token, uint32_t *ipv6, uint8_t *mask)
+{
+       char *sa, *sm, *sv;
+       const char *dlm =  "/";
+
+       sv = NULL;
+       sa = strtok_r(token, dlm, &sv);
+       if (sa == NULL)
+               return -EINVAL;
+       sm = strtok_r(NULL, dlm, &sv);
+       if (sm == NULL)
+               return -EINVAL;
+
+       if (inet_pton(AF_INET6, sa, ipv6) != 1)
+               return -EINVAL;
+
+       GET_CB_FIELD(sm, *mask, 0, 128, 0);
+       return 0;
+}
+
+static int
+parse_ipv4_addr_mask(char *token, uint32_t *ipv4, uint8_t *mask)
+{
+       char *sa, *sm, *sv;
+       const char *dlm =  "/";
+
+       sv = NULL;
+       sa = strtok_r(token, dlm, &sv);
+       if (sa == NULL)
+               return -EINVAL;
+       sm = strtok_r(NULL, dlm, &sv);
+       if (sm == NULL)
+               return -EINVAL;
+
+       if (inet_pton(AF_INET, sa, ipv4) != 1)
+               return -EINVAL;
+
+       GET_CB_FIELD(sm, *mask, 0, 32, 0);
+       *ipv4 = ntohl(*ipv4);
+       return 0;
+}
+
+static int
+lpm_parse_v6_net(char *in, uint32_t *v, uint8_t *mask_len)
+{
+       int32_t rc;
+
+       /* get address. */
+       rc = parse_ipv6_addr_mask(in, v, mask_len);
+
+       return rc;
+}
+
+static int
+lpm_parse_v6_rule(char *str, struct lpm_route_rule *v)
+{
+       int i, rc;
+       char *s, *sp, *in[CB_FLD_MAX];
+       static const char *dlm = " \t\n";
+       int dim = CB_FLD_MAX;
+       s = str;
+
+       for (i = 0; i != dim; i++, s = NULL) {
+               in[i] = strtok_r(s, dlm, &sp);
+               if (in[i] == NULL)
+                       return -EINVAL;
+       }
+
+       rc = lpm_parse_v6_net(in[CB_FLD_DST_ADDR], v->ip_32, &v->depth);
+
+       GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
+
+       return rc;
+}
+
+static int
+lpm_parse_v4_rule(char *str, struct lpm_route_rule *v)
+{
+       int i, rc;
+       char *s, *sp, *in[CB_FLD_MAX];
+       static const char *dlm = " \t\n";
+       int dim = CB_FLD_MAX;
+       s = str;
+
+       for (i = 0; i != dim; i++, s = NULL) {
+               in[i] = strtok_r(s, dlm, &sp);
+               if (in[i] == NULL)
+                       return -EINVAL;
+       }
+
+       rc = parse_ipv4_addr_mask(in[CB_FLD_DST_ADDR], &v->ip, &v->depth);
+
+       GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
+
+       return rc;
+}
+
+static int
+lpm_add_default_v4_rules(void)
+{
+       /* populate the LPM IPv4 table */
+       unsigned int i, rule_size = sizeof(*route_base_v4);
+       route_num_v4 = RTE_DIM(ipv4_l3fwd_route_array);
+
+       route_base_v4 = calloc(route_num_v4, rule_size);
+
+       for (i = 0; i < (unsigned int)route_num_v4; i++) {
+               route_base_v4[i].ip = ipv4_l3fwd_route_array[i].ip;
+               route_base_v4[i].depth = ipv4_l3fwd_route_array[i].depth;
+               route_base_v4[i].if_out = ipv4_l3fwd_route_array[i].if_out;
+       }
+       return 0;
+}
+
+static int
+lpm_add_default_v6_rules(void)
+{
+       /* populate the LPM IPv6 table */
+       unsigned int i, rule_size = sizeof(*route_base_v6);
+       route_num_v6 = RTE_DIM(ipv6_l3fwd_route_array);
+
+       route_base_v6 = calloc(route_num_v6, rule_size);
+
+       for (i = 0; i < (unsigned int)route_num_v6; i++) {
+               memcpy(route_base_v6[i].ip_8, ipv6_l3fwd_route_array[i].ip,
+                          sizeof(route_base_v6[i].ip_8));
+               route_base_v6[i].depth = ipv6_l3fwd_route_array[i].depth;
+               route_base_v6[i].if_out = ipv6_l3fwd_route_array[i].if_out;
+       }
+       return 0;
+}
+
+static int
+lpm_add_rules(const char *rule_path,
+               struct lpm_route_rule **proute_base,
+               int (*parser)(char *, struct lpm_route_rule *))
+{
+       struct lpm_route_rule *route_rules;
+       struct lpm_route_rule *next;
+       unsigned int route_num = 0;
+       unsigned int route_cnt = 0;
+       char buff[LINE_MAX];
+       FILE *fh;
+       unsigned int i = 0, rule_size = sizeof(*next);
+       int val;
+
+       *proute_base = NULL;
+       fh = fopen(rule_path, "rb");
+       if (fh == NULL)
+               return -EINVAL;
+
+       while ((fgets(buff, LINE_MAX, fh) != NULL)) {
+               if (buff[0] == ROUTE_LEAD_CHAR)
+                       route_num++;
+       }
+
+       if (route_num == 0) {
+               fclose(fh);
+               return -EINVAL;
+       }
+
+       val = fseek(fh, 0, SEEK_SET);
+       if (val < 0) {
+               fclose(fh);
+               return -EINVAL;
+       }
+
+       route_rules = calloc(route_num, rule_size);
+
+       if (route_rules == NULL) {
+               fclose(fh);
+               return -EINVAL;
+       }
+
+       i = 0;
+       while (fgets(buff, LINE_MAX, fh) != NULL) {
+               i++;
+               if (is_bypass_line(buff))
+                       continue;
+
+               char s = buff[0];
+
+               /* Route entry */
+               if (s == ROUTE_LEAD_CHAR)
+                       next = &route_rules[route_cnt];
+
+               /* Illegal line */
+               else {
+                       RTE_LOG(ERR, L3FWD,
+                               "%s Line %u: should start with leading "
+                               "char %c\n",
+                               rule_path, i, ROUTE_LEAD_CHAR);
+                       fclose(fh);
+                       free(route_rules);
+                       return -EINVAL;
+               }
+
+               if (parser(buff + 1, next) != 0) {
+                       RTE_LOG(ERR, L3FWD,
+                               "%s Line %u: parse rules error\n",
+                               rule_path, i);
+                       fclose(fh);
+                       free(route_rules);
+                       return -EINVAL;
+               }
+
+               route_cnt++;
+       }
+
+       fclose(fh);
+
+       *proute_base = route_rules;
+
+       return route_cnt;
+}
+
+void
+lpm_free_routes(void)
+{
+       free(route_base_v4);
+       free(route_base_v6);
+       route_base_v4 = NULL;
+       route_base_v6 = NULL;
+       route_num_v4 = 0;
+       route_num_v6 = 0;
+}
+
+/* Load rules from the input file */
+void
+read_config_files_lpm(void)
+{
+       if (parm_config.rule_ipv4_name != NULL &&
+                       parm_config.rule_ipv6_name != NULL) {
+               /* ipv4 check */
+               route_num_v4 = lpm_add_rules(parm_config.rule_ipv4_name,
+                                       &route_base_v4, &lpm_parse_v4_rule);
+               if (route_num_v4 < 0) {
+                       lpm_free_routes();
+                       rte_exit(EXIT_FAILURE, "Failed to add IPv4 rules\n");
+               }
+
+               /* ipv6 check */
+               route_num_v6 = lpm_add_rules(parm_config.rule_ipv6_name,
+                                       &route_base_v6, &lpm_parse_v6_rule);
+               if (route_num_v6 < 0) {
+                       lpm_free_routes();
+                       rte_exit(EXIT_FAILURE, "Failed to add IPv6 rules\n");
+               }
+       } else {
+               RTE_LOG(INFO, L3FWD, "Missing 1 or more rule files, using default instead\n");
+               if (lpm_add_default_v4_rules() < 0) {
+                       lpm_free_routes();
+                       rte_exit(EXIT_FAILURE, "Failed to add default IPv4 rules\n");
+               }
+               if (lpm_add_default_v6_rules() < 0) {
+                       lpm_free_routes();
+                       rte_exit(EXIT_FAILURE, "Failed to add default IPv6 rules\n");
+               }
+       }
+}
index eb68ffc..05652a5 100644 (file)
@@ -94,6 +94,8 @@ uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
 
 struct lcore_conf lcore_conf[RTE_MAX_LCORE];
 
+struct parm_cfg parm_config;
+
 struct lcore_params {
        uint16_t port_id;
        uint8_t queue_id;
@@ -141,41 +143,49 @@ static struct rte_mempool *vector_pool[RTE_MAX_ETHPORTS];
 static uint8_t lkp_per_socket[NB_SOCKETS];
 
 struct l3fwd_lkp_mode {
+       void  (*read_config_files)(void);
        void  (*setup)(int);
        int   (*check_ptype)(int);
        rte_rx_callback_fn cb_parse_ptype;
        int   (*main_loop)(void *);
        void* (*get_ipv4_lookup_struct)(int);
        void* (*get_ipv6_lookup_struct)(int);
+       void  (*free_routes)(void);
 };
 
 static struct l3fwd_lkp_mode l3fwd_lkp;
 
 static struct l3fwd_lkp_mode l3fwd_em_lkp = {
+       .read_config_files              = read_config_files_em,
        .setup                  = setup_hash,
        .check_ptype            = em_check_ptype,
        .cb_parse_ptype         = em_cb_parse_ptype,
        .main_loop              = em_main_loop,
        .get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct,
        .get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct,
+       .free_routes                    = em_free_routes,
 };
 
 static struct l3fwd_lkp_mode l3fwd_lpm_lkp = {
+       .read_config_files              = read_config_files_lpm,
        .setup                  = setup_lpm,
        .check_ptype            = lpm_check_ptype,
        .cb_parse_ptype         = lpm_cb_parse_ptype,
        .main_loop              = lpm_main_loop,
        .get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct,
        .get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct,
+       .free_routes                    = lpm_free_routes,
 };
 
 static struct l3fwd_lkp_mode l3fwd_fib_lkp = {
+       .read_config_files              = read_config_files_lpm,
        .setup                  = setup_fib,
        .check_ptype            = lpm_check_ptype,
        .cb_parse_ptype         = lpm_cb_parse_ptype,
        .main_loop              = fib_main_loop,
        .get_ipv4_lookup_struct = fib_get_ipv4_l3fwd_lookup_struct,
        .get_ipv6_lookup_struct = fib_get_ipv6_l3fwd_lookup_struct,
+       .free_routes                    = lpm_free_routes,
 };
 
 /*
@@ -224,6 +234,21 @@ const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
        {{32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 15},
 };
 
+/*
+ * API's called during initialization to setup ACL/EM/LPM rules.
+ */
+static void
+l3fwd_set_rule_ipv4_name(const char *optarg)
+{
+       parm_config.rule_ipv4_name = optarg;
+}
+
+static void
+l3fwd_set_rule_ipv6_name(const char *optarg)
+{
+       parm_config.rule_ipv6_name = optarg;
+}
+
 /*
  * Setup lookup methods for forwarding.
  * Currently exact-match, longest-prefix-match and forwarding information
@@ -339,6 +364,8 @@ print_usage(const char *prgname)
 {
        fprintf(stderr, "%s [EAL options] --"
                " -p PORTMASK"
+               "  --rule_ipv4=FILE"
+               "  --rule_ipv6=FILE"
                " [-P]"
                " [--lookup]"
                " --config (port,queue,lcore)[,(port,queue,lcore)]"
@@ -381,7 +408,10 @@ print_usage(const char *prgname)
                "  --event-vector-size: Max vector size if event vectorization is enabled.\n"
                "  --event-vector-tmo: Max timeout to form vector in nanoseconds if event vectorization is enabled\n"
                "  -E : Enable exact match, legacy flag please use --lookup=em instead\n"
-               "  -L : Enable longest prefix match, legacy flag please use --lookup=lpm instead\n\n",
+               "  -L : Enable longest prefix match, legacy flag please use --lookup=lpm instead\n"
+               "  --rule_ipv4=FILE: Specify the ipv4 rules entries file.\n"
+               "                    Each rule occupies one line.\n"
+               "  --rule_ipv6=FILE: Specify the ipv6 rules entries file.\n\n",
                prgname);
 }
 
@@ -596,6 +626,8 @@ static const char short_options[] =
 #define CMD_LINE_OPT_ENABLE_VECTOR "event-vector"
 #define CMD_LINE_OPT_VECTOR_SIZE "event-vector-size"
 #define CMD_LINE_OPT_VECTOR_TMO_NS "event-vector-tmo"
+#define CMD_LINE_OPT_RULE_IPV4 "rule_ipv4"
+#define CMD_LINE_OPT_RULE_IPV6 "rule_ipv6"
 
 enum {
        /* long options mapped to a short option */
@@ -610,6 +642,8 @@ enum {
        CMD_LINE_OPT_MAX_PKT_LEN_NUM,
        CMD_LINE_OPT_HASH_ENTRY_NUM_NUM,
        CMD_LINE_OPT_PARSE_PTYPE_NUM,
+       CMD_LINE_OPT_RULE_IPV4_NUM,
+       CMD_LINE_OPT_RULE_IPV6_NUM,
        CMD_LINE_OPT_PARSE_PER_PORT_POOL,
        CMD_LINE_OPT_MODE_NUM,
        CMD_LINE_OPT_EVENTQ_SYNC_NUM,
@@ -637,6 +671,8 @@ static const struct option lgopts[] = {
        {CMD_LINE_OPT_ENABLE_VECTOR, 0, 0, CMD_LINE_OPT_ENABLE_VECTOR_NUM},
        {CMD_LINE_OPT_VECTOR_SIZE, 1, 0, CMD_LINE_OPT_VECTOR_SIZE_NUM},
        {CMD_LINE_OPT_VECTOR_TMO_NS, 1, 0, CMD_LINE_OPT_VECTOR_TMO_NS_NUM},
+       {CMD_LINE_OPT_RULE_IPV4,   1, 0, CMD_LINE_OPT_RULE_IPV4_NUM},
+       {CMD_LINE_OPT_RULE_IPV6,   1, 0, CMD_LINE_OPT_RULE_IPV6_NUM},
        {NULL, 0, 0, 0}
 };
 
@@ -791,6 +827,12 @@ parse_args(int argc, char **argv)
                case CMD_LINE_OPT_VECTOR_TMO_NS_NUM:
                        evt_rsrc->vector_tmo_ns = strtoull(optarg, NULL, 10);
                        break;
+               case CMD_LINE_OPT_RULE_IPV4_NUM:
+                       l3fwd_set_rule_ipv4_name(optarg);
+                       break;
+               case CMD_LINE_OPT_RULE_IPV6_NUM:
+                       l3fwd_set_rule_ipv6_name(optarg);
+                       break;
                default:
                        print_usage(prgname);
                        return -1;
@@ -1395,6 +1437,9 @@ main(int argc, char **argv)
        /* Setup function pointers for lookup method. */
        setup_l3fwd_lookup_tables();
 
+       /* Add the config file rules */
+       l3fwd_lkp.read_config_files();
+
        evt_rsrc->per_port_pool = per_port_pool;
        evt_rsrc->pkt_pool = pktmbuf_pool;
        evt_rsrc->vec_pool = vector_pool;
@@ -1501,6 +1546,9 @@ main(int argc, char **argv)
                }
        }
 
+       /* clean up config file routes */
+       l3fwd_lkp.free_routes();
+
        /* clean up the EAL */
        rte_eal_cleanup();