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