xref: /dpdk/examples/l3fwd/lpm_route_parse.c (revision e1a06e391ba74f9c4d46a6ecef6d8ee084f4229e)
152def963SSean Morrissey /* SPDX-License-Identifier: BSD-3-Clause
252def963SSean Morrissey  * Copyright(c) 2022 Intel Corporation
352def963SSean Morrissey  */
452def963SSean Morrissey 
552def963SSean Morrissey #include <stdio.h>
652def963SSean Morrissey #include <stdint.h>
752def963SSean Morrissey #include <errno.h>
852def963SSean Morrissey #include <sys/socket.h>
952def963SSean Morrissey 
1052def963SSean Morrissey #include "l3fwd.h"
1152def963SSean Morrissey #include "l3fwd_route.h"
1252def963SSean Morrissey 
1352def963SSean Morrissey enum {
1452def963SSean Morrissey 	CB_FLD_DST_ADDR,
1552def963SSean Morrissey 	CB_FLD_IF_OUT,
1652def963SSean Morrissey 	CB_FLD_MAX
1752def963SSean Morrissey };
1852def963SSean Morrissey 
1952def963SSean Morrissey struct lpm_route_rule *route_base_v4;
2052def963SSean Morrissey struct lpm_route_rule *route_base_v6;
2152def963SSean Morrissey int route_num_v4;
2252def963SSean Morrissey int route_num_v6;
2352def963SSean Morrissey 
2452def963SSean Morrissey /* Bypass comment and empty lines */
2552def963SSean Morrissey int
2652def963SSean Morrissey is_bypass_line(const char *buff)
2752def963SSean Morrissey {
2852def963SSean Morrissey 	int i = 0;
2952def963SSean Morrissey 
3052def963SSean Morrissey 	/* comment line */
3152def963SSean Morrissey 	if (buff[0] == COMMENT_LEAD_CHAR)
3252def963SSean Morrissey 		return 1;
3352def963SSean Morrissey 	/* empty line */
3452def963SSean Morrissey 	while (buff[i] != '\0') {
3552def963SSean Morrissey 		if (!isspace(buff[i]))
3652def963SSean Morrissey 			return 0;
3752def963SSean Morrissey 		i++;
3852def963SSean Morrissey 	}
3952def963SSean Morrissey 	return 1;
4052def963SSean Morrissey }
4152def963SSean Morrissey 
4252def963SSean Morrissey static int
43*e1a06e39SRobin Jarry parse_ipv6_addr_mask(char *token, struct rte_ipv6_addr *ipv6, uint8_t *mask)
4452def963SSean Morrissey {
4552def963SSean Morrissey 	char *sa, *sm, *sv;
4652def963SSean Morrissey 	const char *dlm =  "/";
4752def963SSean Morrissey 
4852def963SSean Morrissey 	sv = NULL;
4952def963SSean Morrissey 	sa = strtok_r(token, dlm, &sv);
5052def963SSean Morrissey 	if (sa == NULL)
5152def963SSean Morrissey 		return -EINVAL;
5252def963SSean Morrissey 	sm = strtok_r(NULL, dlm, &sv);
5352def963SSean Morrissey 	if (sm == NULL)
5452def963SSean Morrissey 		return -EINVAL;
5552def963SSean Morrissey 
5652def963SSean Morrissey 	if (inet_pton(AF_INET6, sa, ipv6) != 1)
5752def963SSean Morrissey 		return -EINVAL;
5852def963SSean Morrissey 
5952def963SSean Morrissey 	GET_CB_FIELD(sm, *mask, 0, 128, 0);
6052def963SSean Morrissey 	return 0;
6152def963SSean Morrissey }
6252def963SSean Morrissey 
6352def963SSean Morrissey static int
6452def963SSean Morrissey parse_ipv4_addr_mask(char *token, uint32_t *ipv4, uint8_t *mask)
6552def963SSean Morrissey {
6652def963SSean Morrissey 	char *sa, *sm, *sv;
6752def963SSean Morrissey 	const char *dlm =  "/";
6852def963SSean Morrissey 
6952def963SSean Morrissey 	sv = NULL;
7052def963SSean Morrissey 	sa = strtok_r(token, dlm, &sv);
7152def963SSean Morrissey 	if (sa == NULL)
7252def963SSean Morrissey 		return -EINVAL;
7352def963SSean Morrissey 	sm = strtok_r(NULL, dlm, &sv);
7452def963SSean Morrissey 	if (sm == NULL)
7552def963SSean Morrissey 		return -EINVAL;
7652def963SSean Morrissey 
7752def963SSean Morrissey 	if (inet_pton(AF_INET, sa, ipv4) != 1)
7852def963SSean Morrissey 		return -EINVAL;
7952def963SSean Morrissey 
8052def963SSean Morrissey 	GET_CB_FIELD(sm, *mask, 0, 32, 0);
8152def963SSean Morrissey 	*ipv4 = ntohl(*ipv4);
8252def963SSean Morrissey 	return 0;
8352def963SSean Morrissey }
8452def963SSean Morrissey 
8552def963SSean Morrissey static int
86*e1a06e39SRobin Jarry lpm_parse_v6_net(char *in, struct rte_ipv6_addr *v, uint8_t *mask_len)
8752def963SSean Morrissey {
8852def963SSean Morrissey 	int32_t rc;
8952def963SSean Morrissey 
9052def963SSean Morrissey 	/* get address. */
9152def963SSean Morrissey 	rc = parse_ipv6_addr_mask(in, v, mask_len);
9252def963SSean Morrissey 
9352def963SSean Morrissey 	return rc;
9452def963SSean Morrissey }
9552def963SSean Morrissey 
9652def963SSean Morrissey static int
9752def963SSean Morrissey lpm_parse_v6_rule(char *str, struct lpm_route_rule *v)
9852def963SSean Morrissey {
9952def963SSean Morrissey 	int i, rc;
10052def963SSean Morrissey 	char *s, *sp, *in[CB_FLD_MAX];
10152def963SSean Morrissey 	static const char *dlm = " \t\n";
10252def963SSean Morrissey 	int dim = CB_FLD_MAX;
10352def963SSean Morrissey 	s = str;
10452def963SSean Morrissey 
10552def963SSean Morrissey 	for (i = 0; i != dim; i++, s = NULL) {
10652def963SSean Morrissey 		in[i] = strtok_r(s, dlm, &sp);
10752def963SSean Morrissey 		if (in[i] == NULL)
10852def963SSean Morrissey 			return -EINVAL;
10952def963SSean Morrissey 	}
11052def963SSean Morrissey 
111*e1a06e39SRobin Jarry 	rc = lpm_parse_v6_net(in[CB_FLD_DST_ADDR], &v->ip6, &v->depth);
11252def963SSean Morrissey 
11352def963SSean Morrissey 	GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
11452def963SSean Morrissey 
11552def963SSean Morrissey 	return rc;
11652def963SSean Morrissey }
11752def963SSean Morrissey 
11852def963SSean Morrissey static int
11952def963SSean Morrissey lpm_parse_v4_rule(char *str, struct lpm_route_rule *v)
12052def963SSean Morrissey {
12152def963SSean Morrissey 	int i, rc;
12252def963SSean Morrissey 	char *s, *sp, *in[CB_FLD_MAX];
12352def963SSean Morrissey 	static const char *dlm = " \t\n";
12452def963SSean Morrissey 	int dim = CB_FLD_MAX;
12552def963SSean Morrissey 	s = str;
12652def963SSean Morrissey 
12752def963SSean Morrissey 	for (i = 0; i != dim; i++, s = NULL) {
12852def963SSean Morrissey 		in[i] = strtok_r(s, dlm, &sp);
12952def963SSean Morrissey 		if (in[i] == NULL)
13052def963SSean Morrissey 			return -EINVAL;
13152def963SSean Morrissey 	}
13252def963SSean Morrissey 
13352def963SSean Morrissey 	rc = parse_ipv4_addr_mask(in[CB_FLD_DST_ADDR], &v->ip, &v->depth);
13452def963SSean Morrissey 
13552def963SSean Morrissey 	GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
13652def963SSean Morrissey 
13752def963SSean Morrissey 	return rc;
13852def963SSean Morrissey }
13952def963SSean Morrissey 
14052def963SSean Morrissey static int
14152def963SSean Morrissey lpm_add_default_v4_rules(void)
14252def963SSean Morrissey {
14352def963SSean Morrissey 	/* populate the LPM IPv4 table */
14452def963SSean Morrissey 	unsigned int i, rule_size = sizeof(*route_base_v4);
14552def963SSean Morrissey 	route_num_v4 = RTE_DIM(ipv4_l3fwd_route_array);
14652def963SSean Morrissey 
14752def963SSean Morrissey 	route_base_v4 = calloc(route_num_v4, rule_size);
14852def963SSean Morrissey 
14952def963SSean Morrissey 	for (i = 0; i < (unsigned int)route_num_v4; i++) {
15052def963SSean Morrissey 		route_base_v4[i].ip = ipv4_l3fwd_route_array[i].ip;
15152def963SSean Morrissey 		route_base_v4[i].depth = ipv4_l3fwd_route_array[i].depth;
15252def963SSean Morrissey 		route_base_v4[i].if_out = ipv4_l3fwd_route_array[i].if_out;
15352def963SSean Morrissey 	}
15452def963SSean Morrissey 	return 0;
15552def963SSean Morrissey }
15652def963SSean Morrissey 
15752def963SSean Morrissey static int
15852def963SSean Morrissey lpm_add_default_v6_rules(void)
15952def963SSean Morrissey {
16052def963SSean Morrissey 	/* populate the LPM IPv6 table */
16152def963SSean Morrissey 	unsigned int i, rule_size = sizeof(*route_base_v6);
16252def963SSean Morrissey 	route_num_v6 = RTE_DIM(ipv6_l3fwd_route_array);
16352def963SSean Morrissey 
16452def963SSean Morrissey 	route_base_v6 = calloc(route_num_v6, rule_size);
16552def963SSean Morrissey 
16652def963SSean Morrissey 	for (i = 0; i < (unsigned int)route_num_v6; i++) {
167*e1a06e39SRobin Jarry 		route_base_v6[i].ip6 = ipv6_l3fwd_route_array[i].ip;
16852def963SSean Morrissey 		route_base_v6[i].depth = ipv6_l3fwd_route_array[i].depth;
16952def963SSean Morrissey 		route_base_v6[i].if_out = ipv6_l3fwd_route_array[i].if_out;
17052def963SSean Morrissey 	}
17152def963SSean Morrissey 	return 0;
17252def963SSean Morrissey }
17352def963SSean Morrissey 
17452def963SSean Morrissey static int
17552def963SSean Morrissey lpm_add_rules(const char *rule_path,
17652def963SSean Morrissey 		struct lpm_route_rule **proute_base,
17752def963SSean Morrissey 		int (*parser)(char *, struct lpm_route_rule *))
17852def963SSean Morrissey {
17952def963SSean Morrissey 	struct lpm_route_rule *route_rules;
18052def963SSean Morrissey 	struct lpm_route_rule *next;
18152def963SSean Morrissey 	unsigned int route_num = 0;
18252def963SSean Morrissey 	unsigned int route_cnt = 0;
18352def963SSean Morrissey 	char buff[LINE_MAX];
18452def963SSean Morrissey 	FILE *fh;
18552def963SSean Morrissey 	unsigned int i = 0, rule_size = sizeof(*next);
18652def963SSean Morrissey 	int val;
18752def963SSean Morrissey 
18852def963SSean Morrissey 	*proute_base = NULL;
18952def963SSean Morrissey 	fh = fopen(rule_path, "rb");
19052def963SSean Morrissey 	if (fh == NULL)
19152def963SSean Morrissey 		return -EINVAL;
19252def963SSean Morrissey 
19352def963SSean Morrissey 	while ((fgets(buff, LINE_MAX, fh) != NULL)) {
19452def963SSean Morrissey 		if (buff[0] == ROUTE_LEAD_CHAR)
19552def963SSean Morrissey 			route_num++;
19652def963SSean Morrissey 	}
19752def963SSean Morrissey 
19852def963SSean Morrissey 	if (route_num == 0) {
19952def963SSean Morrissey 		fclose(fh);
20052def963SSean Morrissey 		return -EINVAL;
20152def963SSean Morrissey 	}
20252def963SSean Morrissey 
20352def963SSean Morrissey 	val = fseek(fh, 0, SEEK_SET);
20452def963SSean Morrissey 	if (val < 0) {
20552def963SSean Morrissey 		fclose(fh);
20652def963SSean Morrissey 		return -EINVAL;
20752def963SSean Morrissey 	}
20852def963SSean Morrissey 
20952def963SSean Morrissey 	route_rules = calloc(route_num, rule_size);
21052def963SSean Morrissey 
21152def963SSean Morrissey 	if (route_rules == NULL) {
21252def963SSean Morrissey 		fclose(fh);
21352def963SSean Morrissey 		return -EINVAL;
21452def963SSean Morrissey 	}
21552def963SSean Morrissey 
21652def963SSean Morrissey 	i = 0;
21752def963SSean Morrissey 	while (fgets(buff, LINE_MAX, fh) != NULL) {
21852def963SSean Morrissey 		i++;
21952def963SSean Morrissey 		if (is_bypass_line(buff))
22052def963SSean Morrissey 			continue;
22152def963SSean Morrissey 
22252def963SSean Morrissey 		char s = buff[0];
22352def963SSean Morrissey 
22452def963SSean Morrissey 		/* Route entry */
22552def963SSean Morrissey 		if (s == ROUTE_LEAD_CHAR)
22652def963SSean Morrissey 			next = &route_rules[route_cnt];
22752def963SSean Morrissey 
22852def963SSean Morrissey 		/* Illegal line */
22952def963SSean Morrissey 		else {
23052def963SSean Morrissey 			RTE_LOG(ERR, L3FWD,
23152def963SSean Morrissey 				"%s Line %u: should start with leading "
23252def963SSean Morrissey 				"char %c\n",
23352def963SSean Morrissey 				rule_path, i, ROUTE_LEAD_CHAR);
23452def963SSean Morrissey 			fclose(fh);
23552def963SSean Morrissey 			free(route_rules);
23652def963SSean Morrissey 			return -EINVAL;
23752def963SSean Morrissey 		}
23852def963SSean Morrissey 
23952def963SSean Morrissey 		if (parser(buff + 1, next) != 0) {
24052def963SSean Morrissey 			RTE_LOG(ERR, L3FWD,
24152def963SSean Morrissey 				"%s Line %u: parse rules error\n",
24252def963SSean Morrissey 				rule_path, i);
24352def963SSean Morrissey 			fclose(fh);
24452def963SSean Morrissey 			free(route_rules);
24552def963SSean Morrissey 			return -EINVAL;
24652def963SSean Morrissey 		}
24752def963SSean Morrissey 
24852def963SSean Morrissey 		route_cnt++;
24952def963SSean Morrissey 	}
25052def963SSean Morrissey 
25152def963SSean Morrissey 	fclose(fh);
25252def963SSean Morrissey 
25352def963SSean Morrissey 	*proute_base = route_rules;
25452def963SSean Morrissey 
25552def963SSean Morrissey 	return route_cnt;
25652def963SSean Morrissey }
25752def963SSean Morrissey 
25852def963SSean Morrissey void
25952def963SSean Morrissey lpm_free_routes(void)
26052def963SSean Morrissey {
26152def963SSean Morrissey 	free(route_base_v4);
26252def963SSean Morrissey 	free(route_base_v6);
26352def963SSean Morrissey 	route_base_v4 = NULL;
26452def963SSean Morrissey 	route_base_v6 = NULL;
26552def963SSean Morrissey 	route_num_v4 = 0;
26652def963SSean Morrissey 	route_num_v6 = 0;
26752def963SSean Morrissey }
26852def963SSean Morrissey 
26952def963SSean Morrissey /* Load rules from the input file */
27052def963SSean Morrissey void
27152def963SSean Morrissey read_config_files_lpm(void)
27252def963SSean Morrissey {
27352def963SSean Morrissey 	if (parm_config.rule_ipv4_name != NULL &&
27452def963SSean Morrissey 			parm_config.rule_ipv6_name != NULL) {
27552def963SSean Morrissey 		/* ipv4 check */
27652def963SSean Morrissey 		route_num_v4 = lpm_add_rules(parm_config.rule_ipv4_name,
27752def963SSean Morrissey 					&route_base_v4, &lpm_parse_v4_rule);
27852def963SSean Morrissey 		if (route_num_v4 < 0) {
27952def963SSean Morrissey 			lpm_free_routes();
28052def963SSean Morrissey 			rte_exit(EXIT_FAILURE, "Failed to add IPv4 rules\n");
28152def963SSean Morrissey 		}
28252def963SSean Morrissey 
28352def963SSean Morrissey 		/* ipv6 check */
28452def963SSean Morrissey 		route_num_v6 = lpm_add_rules(parm_config.rule_ipv6_name,
28552def963SSean Morrissey 					&route_base_v6, &lpm_parse_v6_rule);
28652def963SSean Morrissey 		if (route_num_v6 < 0) {
28752def963SSean Morrissey 			lpm_free_routes();
28852def963SSean Morrissey 			rte_exit(EXIT_FAILURE, "Failed to add IPv6 rules\n");
28952def963SSean Morrissey 		}
29052def963SSean Morrissey 	} else {
29152def963SSean Morrissey 		RTE_LOG(INFO, L3FWD, "Missing 1 or more rule files, using default instead\n");
29252def963SSean Morrissey 		if (lpm_add_default_v4_rules() < 0) {
29352def963SSean Morrissey 			lpm_free_routes();
29452def963SSean Morrissey 			rte_exit(EXIT_FAILURE, "Failed to add default IPv4 rules\n");
29552def963SSean Morrissey 		}
29652def963SSean Morrissey 		if (lpm_add_default_v6_rules() < 0) {
29752def963SSean Morrissey 			lpm_free_routes();
29852def963SSean Morrissey 			rte_exit(EXIT_FAILURE, "Failed to add default IPv6 rules\n");
29952def963SSean Morrissey 		}
30052def963SSean Morrissey 	}
30152def963SSean Morrissey }
302