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