[v3,1/2] examples/l3fwd: add config file support for LPM/FIB

Message ID 20211221123037.1037203-2-sean.morrissey@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers
Series Add config file support for l3fwd |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Sean Morrissey Dec. 21, 2021, 12:30 p.m. UTC
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.

With the removal of the hardcoded route tables for IPv4
and IPv6, these routes have been moved to a separate
default config file for use with LPM and FIB.

Signed-off-by: Sean Morrissey <sean.morrissey@intel.com>
Signed-off-by: Ravi Kerur <rkerur@gmail.com>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
---
 examples/l3fwd/l3fwd.h            |  35 ++++
 examples/l3fwd/l3fwd_em.c         |   7 +
 examples/l3fwd/l3fwd_fib.c        |  52 +++---
 examples/l3fwd/l3fwd_lpm.c        | 281 +++++++++++++++++++++++++++---
 examples/l3fwd/l3fwd_route.h      |  17 +-
 examples/l3fwd/lpm_default_v4.cfg |  17 ++
 examples/l3fwd/lpm_default_v6.cfg |  17 ++
 examples/l3fwd/main.c             |  99 ++++++-----
 8 files changed, 438 insertions(+), 87 deletions(-)
 create mode 100644 examples/l3fwd/lpm_default_v4.cfg
 create mode 100644 examples/l3fwd/lpm_default_v6.cfg
  

Patch

diff --git a/examples/l3fwd/l3fwd.h b/examples/l3fwd/l3fwd.h
index 38ca19133c..d8b1f971e1 100644
--- a/examples/l3fwd/l3fwd.h
+++ b/examples/l3fwd/l3fwd.h
@@ -58,6 +58,30 @@ 
 #endif
 #define HASH_ENTRY_NUMBER_DEFAULT	16
 
+/*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 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 +120,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)
@@ -183,6 +209,12 @@  int
 init_mem(uint16_t portid, unsigned int nb_mbuf);
 
 /* Function pointers for LPM, EM or FIB functionality. */
+void
+read_config_files_lpm(void);
+
+void
+read_config_files_em(void);
+
 void
 setup_lpm(const int socketid);
 
@@ -286,4 +318,7 @@  fib_get_ipv4_l3fwd_lookup_struct(const int socketid);
 void *
 fib_get_ipv6_l3fwd_lookup_struct(const int socketid);
 
+int
+is_bypass_line(const char *buff);
+
 #endif  /* __L3_FWD_H__ */
diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c
index 5cc4a4d979..4953cdae4e 100644
--- a/examples/l3fwd/l3fwd_em.c
+++ b/examples/l3fwd/l3fwd_em.c
@@ -972,6 +972,13 @@  em_event_main_loop_tx_q_burst_vector(__rte_unused void *dummy)
 	return 0;
 }
 
+/* Load rules from the input file */
+void
+read_config_files_em(void)
+{
+	/* Empty till config file support added to EM */
+}
+
 /* Initialize exact match (hash) parameters. 8< */
 void
 setup_hash(const int socketid)
diff --git a/examples/l3fwd/l3fwd_fib.c b/examples/l3fwd/l3fwd_fib.c
index 2110459cc3..003721c908 100644
--- a/examples/l3fwd/l3fwd_fib.c
+++ b/examples/l3fwd/l3fwd_fib.c
@@ -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,44 +652,50 @@  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);
 		}
 	}
+	free(route_base_v4);
+	free(route_base_v6);
 }
 
 /* Return ipv4 fib lookup struct. */
diff --git a/examples/l3fwd/l3fwd_lpm.c b/examples/l3fwd/l3fwd_lpm.c
index a5b476ced3..4157f16c07 100644
--- a/examples/l3fwd/l3fwd_lpm.c
+++ b/examples/l3fwd/l3fwd_lpm.c
@@ -39,6 +39,16 @@ 
 
 static struct rte_lpm *ipv4_l3fwd_lpm_lookup_struct[NB_SOCKETS];
 static struct rte_lpm6 *ipv6_l3fwd_lpm_lookup_struct[NB_SOCKETS];
+struct lpm_route_rule *route_base_v4;
+struct lpm_route_rule *route_base_v6;
+int route_num_v4;
+int route_num_v6;
+
+enum {
+	CB_FLD_DST_ADDR,
+	CB_FLD_IF_OUT,
+	CB_FLD_MAX
+};
 
 /* Performing LPM-based lookups. 8< */
 static inline uint16_t
@@ -139,6 +149,199 @@  lpm_get_dst_port_with_ipv4(const struct lcore_conf *qconf, struct rte_mbuf *pkt,
 #include "l3fwd_lpm.h"
 #endif
 
+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_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;
+}
+
+static void
+free_lpm_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;
+}
+
 /* main processing loop */
 int
 lpm_main_loop(__rte_unused void *dummy)
@@ -153,6 +356,9 @@  lpm_main_loop(__rte_unused void *dummy)
 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
 		US_PER_S * BURST_TX_DRAIN_US;
 
+	/* Config read and setup, free structs */
+	free_lpm_routes();
+
 	lcore_id = rte_lcore_id();
 	qconf = &lcore_conf[lcore_id];
 
@@ -548,13 +754,44 @@  lpm_event_main_loop_tx_q_burst_vector(__rte_unused void *dummy)
 	return 0;
 }
 
+/* Load rules from the input file */
+void
+read_config_files_lpm(void)
+{
+	/* ipv4 check */
+	if (parm_config.rule_ipv4_name != NULL) {
+		route_num_v4 = lpm_add_rules(parm_config.rule_ipv4_name,
+					&route_base_v4, &lpm_parse_v4_rule);
+		if (route_num_v4 < 0) {
+			free_lpm_routes();
+			rte_exit(EXIT_FAILURE, "Failed to add IPv4 rules\n");
+		}
+	} else {
+		RTE_LOG(ERR, L3FWD, "IPv4 rule file not specified\n");
+		rte_exit(EXIT_FAILURE, "Failed to get valid route options\n");
+	}
+
+	/* ipv6 check */
+	if (parm_config.rule_ipv6_name != NULL) {
+		route_num_v6 = lpm_add_rules(parm_config.rule_ipv6_name,
+					&route_base_v6, &lpm_parse_v6_rule);
+		if (route_num_v6 < 0) {
+			free_lpm_routes();
+			rte_exit(EXIT_FAILURE, "Failed to add IPv6 rules\n");
+		}
+	} else {
+		RTE_LOG(ERR, L3FWD, "IPv6 rule file not specified\n");
+		rte_exit(EXIT_FAILURE, "Failed to get valid route options\n");
+	}
+}
+
 void
 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 +809,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) {
+			free_lpm_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 +846,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) {
+		free_lpm_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) {
+			free_lpm_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);
 	}
 }
 
diff --git a/examples/l3fwd/l3fwd_route.h b/examples/l3fwd/l3fwd_route.h
index c7eba06c4d..7ddd4d9c2d 100644
--- a/examples/l3fwd/l3fwd_route.h
+++ b/examples/l3fwd/l3fwd_route.h
@@ -14,6 +14,19 @@  struct ipv6_l3fwd_route {
 	uint8_t if_out;
 };
 
-extern const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[16];
+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 const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[16];
+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;
diff --git a/examples/l3fwd/lpm_default_v4.cfg b/examples/l3fwd/lpm_default_v4.cfg
new file mode 100644
index 0000000000..4db5597ed8
--- /dev/null
+++ b/examples/l3fwd/lpm_default_v4.cfg
@@ -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
index 0000000000..c50233e0ba
--- /dev/null
+++ b/examples/l3fwd/lpm_default_v6.cfg
@@ -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/main.c b/examples/l3fwd/main.c
index eb68ffc5aa..927164561e 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -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,6 +143,7 @@  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;
@@ -152,6 +155,7 @@  struct l3fwd_lkp_mode {
 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,
@@ -161,6 +165,7 @@  static struct l3fwd_lkp_mode l3fwd_em_lkp = {
 };
 
 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,
@@ -170,6 +175,7 @@  static struct l3fwd_lkp_mode l3fwd_lpm_lkp = {
 };
 
 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,
@@ -179,50 +185,19 @@  static struct l3fwd_lkp_mode l3fwd_fib_lkp = {
 };
 
 /*
- * 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735).
- * 198.18.{0-15}.0/24 = Port {0-15}
+ * API's called during initialization to setup ACL/EM/LPM rules.
  */
-const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
-	{RTE_IPV4(198, 18, 0, 0), 24, 0},
-	{RTE_IPV4(198, 18, 1, 0), 24, 1},
-	{RTE_IPV4(198, 18, 2, 0), 24, 2},
-	{RTE_IPV4(198, 18, 3, 0), 24, 3},
-	{RTE_IPV4(198, 18, 4, 0), 24, 4},
-	{RTE_IPV4(198, 18, 5, 0), 24, 5},
-	{RTE_IPV4(198, 18, 6, 0), 24, 6},
-	{RTE_IPV4(198, 18, 7, 0), 24, 7},
-	{RTE_IPV4(198, 18, 8, 0), 24, 8},
-	{RTE_IPV4(198, 18, 9, 0), 24, 9},
-	{RTE_IPV4(198, 18, 10, 0), 24, 10},
-	{RTE_IPV4(198, 18, 11, 0), 24, 11},
-	{RTE_IPV4(198, 18, 12, 0), 24, 12},
-	{RTE_IPV4(198, 18, 13, 0), 24, 13},
-	{RTE_IPV4(198, 18, 14, 0), 24, 14},
-	{RTE_IPV4(198, 18, 15, 0), 24, 15},
-};
+static void
+l3fwd_set_rule_ipv4_name(const char *optarg)
+{
+	parm_config.rule_ipv4_name = optarg;
+}
 
-/*
- * 2001:200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180).
- * 2001:200:0:{0-f}::/64 = Port {0-15}
- */
-const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
-	{{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 0},
-	{{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 1},
-	{{32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 2},
-	{{32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 3},
-	{{32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 4},
-	{{32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 5},
-	{{32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 6},
-	{{32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 7},
-	{{32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 8},
-	{{32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 9},
-	{{32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 10},
-	{{32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 11},
-	{{32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 12},
-	{{32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 13},
-	{{32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 14},
-	{{32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 15},
-};
+static void
+l3fwd_set_rule_ipv6_name(const char *optarg)
+{
+	parm_config.rule_ipv6_name = optarg;
+}
 
 /*
  * Setup lookup methods for forwarding.
@@ -339,6 +314,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 +358,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 +576,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 +592,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 +621,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 +777,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;
@@ -1358,6 +1350,24 @@  l3fwd_event_service_setup(void)
 	}
 }
 
+/* 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;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1395,6 +1405,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;