xref: /dpdk/examples/l3fwd/em_route_parse.c (revision e7e6dd6430921edbf215c0fb99f49d3cdff868c2)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2022 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <errno.h>
8 #include <sys/socket.h>
9 
10 #include "l3fwd.h"
11 #include "l3fwd_route.h"
12 
13 static struct em_rule *em_route_base_v4;
14 static struct em_rule *em_route_base_v6;
15 
16 enum {
17 	CB_FLD_DST_ADDR,
18 	CB_FLD_SRC_ADDR,
19 	CB_FLD_DST_PORT,
20 	CB_FLD_SRC_PORT,
21 	CB_FLD_PROTO,
22 	CB_FLD_IF_OUT,
23 	CB_FLD_MAX
24 };
25 
26 static int
em_parse_v6_net(const char * in,uint8_t * v)27 em_parse_v6_net(const char *in, uint8_t *v)
28 {
29 	int32_t rc;
30 
31 	/* get address. */
32 	rc = inet_pton(AF_INET6, in, v);
33 	if (rc != 1)
34 		return -EINVAL;
35 
36 	return 0;
37 }
38 
39 static int
em_parse_v6_rule(char * str,struct em_rule * v)40 em_parse_v6_rule(char *str, struct em_rule *v)
41 {
42 	int i, rc;
43 	char *s, *sp, *in[CB_FLD_MAX];
44 	static const char *dlm = " \t\n";
45 	int dim = CB_FLD_MAX;
46 	s = str;
47 
48 	for (i = 0; i != dim; i++, s = NULL) {
49 		in[i] = strtok_r(s, dlm, &sp);
50 		if (in[i] == NULL)
51 			return -EINVAL;
52 	}
53 
54 	rc = em_parse_v6_net(in[CB_FLD_DST_ADDR], v->v6_key.ip_dst);
55 	if (rc != 0)
56 		return rc;
57 	rc = em_parse_v6_net(in[CB_FLD_SRC_ADDR], v->v6_key.ip_src);
58 	if (rc != 0)
59 		return rc;
60 
61 	/* source port. */
62 	GET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v6_key.port_src, 0, UINT16_MAX, 0);
63 	/* destination port. */
64 	GET_CB_FIELD(in[CB_FLD_DST_PORT], v->v6_key.port_dst, 0, UINT16_MAX, 0);
65 	/* protocol. */
66 	GET_CB_FIELD(in[CB_FLD_PROTO], v->v6_key.proto, 0, UINT8_MAX, 0);
67 	/* out interface. */
68 	GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
69 
70 	return 0;
71 }
72 
73 static int
em_parse_v4_rule(char * str,struct em_rule * v)74 em_parse_v4_rule(char *str, struct em_rule *v)
75 {
76 	int i, rc;
77 	char *s, *sp, *in[CB_FLD_MAX];
78 	static const char *dlm = " \t\n";
79 	int dim = CB_FLD_MAX;
80 	s = str;
81 
82 	for (i = 0; i != dim; i++, s = NULL) {
83 		in[i] = strtok_r(s, dlm, &sp);
84 		if (in[i] == NULL)
85 			return -EINVAL;
86 	}
87 
88 	rc = inet_pton(AF_INET, in[CB_FLD_DST_ADDR], &(v->v4_key.ip_dst));
89 	v->v4_key.ip_dst = ntohl(v->v4_key.ip_dst);
90 	if (rc != 1)
91 		return rc;
92 
93 	rc = inet_pton(AF_INET, in[CB_FLD_SRC_ADDR], &(v->v4_key.ip_src));
94 	v->v4_key.ip_src = ntohl(v->v4_key.ip_src);
95 	if (rc != 1)
96 		return rc;
97 
98 	/* source port. */
99 	GET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v4_key.port_src, 0, UINT16_MAX, 0);
100 	/* destination port. */
101 	GET_CB_FIELD(in[CB_FLD_DST_PORT], v->v4_key.port_dst, 0, UINT16_MAX, 0);
102 	/* protocol. */
103 	GET_CB_FIELD(in[CB_FLD_PROTO], v->v4_key.proto, 0, UINT8_MAX, 0);
104 	/* out interface. */
105 	GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
106 
107 	return 0;
108 }
109 
110 static int
em_add_rules(const char * rule_path,struct em_rule ** proute_base,int (* parser)(char *,struct em_rule *))111 em_add_rules(const char *rule_path,
112 		struct em_rule **proute_base,
113 		int (*parser)(char *, struct em_rule *))
114 {
115 	struct em_rule *route_rules;
116 	struct em_rule *next;
117 	unsigned int route_num = 0;
118 	unsigned int route_cnt = 0;
119 	char buff[LINE_MAX];
120 	FILE *fh;
121 	unsigned int i = 0, rule_size = sizeof(*next);
122 	int val;
123 
124 	*proute_base = NULL;
125 	fh = fopen(rule_path, "rb");
126 	if (fh == NULL)
127 		return -EINVAL;
128 
129 	while ((fgets(buff, LINE_MAX, fh) != NULL)) {
130 		if (buff[0] == ROUTE_LEAD_CHAR)
131 			route_num++;
132 	}
133 
134 	if (route_num == 0) {
135 		fclose(fh);
136 		return -EINVAL;
137 	}
138 
139 	val = fseek(fh, 0, SEEK_SET);
140 	if (val < 0) {
141 		fclose(fh);
142 		return -EINVAL;
143 	}
144 
145 	route_rules = calloc(route_num, rule_size);
146 
147 	if (route_rules == NULL) {
148 		fclose(fh);
149 		return -EINVAL;
150 	}
151 
152 	i = 0;
153 	while (fgets(buff, LINE_MAX, fh) != NULL) {
154 		i++;
155 		if (is_bypass_line(buff))
156 			continue;
157 
158 		char s = buff[0];
159 
160 		/* Route entry */
161 		if (s == ROUTE_LEAD_CHAR)
162 			next = &route_rules[route_cnt];
163 
164 		/* Illegal line */
165 		else {
166 			RTE_LOG(ERR, L3FWD,
167 				"%s Line %u: should start with leading "
168 				"char %c\n",
169 				rule_path, i, ROUTE_LEAD_CHAR);
170 			fclose(fh);
171 			free(route_rules);
172 			return -EINVAL;
173 		}
174 
175 		if (parser(buff + 1, next) != 0) {
176 			RTE_LOG(ERR, L3FWD,
177 				"%s Line %u: parse rules error\n",
178 				rule_path, i);
179 			fclose(fh);
180 			free(route_rules);
181 			return -EINVAL;
182 		}
183 
184 		route_cnt++;
185 	}
186 
187 	fclose(fh);
188 
189 	*proute_base = route_rules;
190 
191 	return route_cnt;
192 }
193 
194 static int
em_add_default_v4_rules(void)195 em_add_default_v4_rules(void)
196 {
197 	/* populate the LPM IPv4 table */
198 	unsigned int i, rule_size = sizeof(*em_route_base_v4);
199 	route_num_v4 = RTE_DIM(ipv4_l3fwd_em_route_array);
200 
201 	em_route_base_v4 = calloc(route_num_v4, rule_size);
202 
203 	for (i = 0; i < (unsigned int)route_num_v4; i++) {
204 		em_route_base_v4[i].v4_key.ip_dst = ipv4_l3fwd_em_route_array[i].key.ip_dst;
205 		em_route_base_v4[i].v4_key.ip_src = ipv4_l3fwd_em_route_array[i].key.ip_src;
206 		em_route_base_v4[i].v4_key.port_dst = ipv4_l3fwd_em_route_array[i].key.port_dst;
207 		em_route_base_v4[i].v4_key.port_src = ipv4_l3fwd_em_route_array[i].key.port_src;
208 		em_route_base_v4[i].v4_key.proto = ipv4_l3fwd_em_route_array[i].key.proto;
209 		em_route_base_v4[i].if_out = ipv4_l3fwd_em_route_array[i].if_out;
210 	}
211 	return 0;
212 }
213 
214 static int
em_add_default_v6_rules(void)215 em_add_default_v6_rules(void)
216 {
217 	/* populate the LPM IPv6 table */
218 	unsigned int i, rule_size = sizeof(*em_route_base_v6);
219 	route_num_v6 = RTE_DIM(ipv6_l3fwd_em_route_array);
220 
221 	em_route_base_v6 = calloc(route_num_v6, rule_size);
222 
223 	for (i = 0; i < (unsigned int)route_num_v6; i++) {
224 		memcpy(em_route_base_v6[i].v6_key.ip_dst, ipv6_l3fwd_em_route_array[i].key.ip_dst,
225 			   sizeof(em_route_base_v6[i].v6_key.ip_dst));
226 		memcpy(em_route_base_v6[i].v6_key.ip_src, ipv6_l3fwd_em_route_array[i].key.ip_src,
227 			   sizeof(em_route_base_v6[i].v6_key.ip_src));
228 		em_route_base_v6[i].v6_key.port_dst = ipv6_l3fwd_em_route_array[i].key.port_dst;
229 		em_route_base_v6[i].v6_key.port_src = ipv6_l3fwd_em_route_array[i].key.port_src;
230 		em_route_base_v6[i].v6_key.proto = ipv6_l3fwd_em_route_array[i].key.proto;
231 		em_route_base_v6[i].if_out = ipv6_l3fwd_em_route_array[i].if_out;
232 	}
233 	return 0;
234 }
235 
236 void
em_free_routes(void)237 em_free_routes(void)
238 {
239 	free(em_route_base_v4);
240 	free(em_route_base_v6);
241 	em_route_base_v4 = NULL;
242 	em_route_base_v6 = NULL;
243 	route_num_v4 = 0;
244 	route_num_v6 = 0;
245 }
246 
247 /* Load rules from the input file */
248 void
read_config_files_em(void)249 read_config_files_em(void)
250 {
251 	/* ipv4 check */
252 	if (parm_config.rule_ipv4_name != NULL &&
253 			parm_config.rule_ipv6_name != NULL) {
254 		/* ipv4 check */
255 		route_num_v4 = em_add_rules(parm_config.rule_ipv4_name,
256 					&em_route_base_v4, &em_parse_v4_rule);
257 		if (route_num_v4 < 0) {
258 			em_free_routes();
259 			rte_exit(EXIT_FAILURE, "Failed to add EM IPv4 rules\n");
260 		}
261 
262 		/* ipv6 check */
263 		route_num_v6 = em_add_rules(parm_config.rule_ipv6_name,
264 					&em_route_base_v6, &em_parse_v6_rule);
265 		if (route_num_v6 < 0) {
266 			em_free_routes();
267 			rte_exit(EXIT_FAILURE, "Failed to add EM IPv6 rules\n");
268 		}
269 	} else {
270 		RTE_LOG(INFO, L3FWD, "Missing 1 or more rule files, using default instead\n");
271 		if (em_add_default_v4_rules() < 0) {
272 			em_free_routes();
273 			rte_exit(EXIT_FAILURE, "Failed to add default IPv4 rules\n");
274 		}
275 		if (em_add_default_v6_rules() < 0) {
276 			em_free_routes();
277 			rte_exit(EXIT_FAILURE, "Failed to add default IPv6 rules\n");
278 		}
279 	}
280 }
281