examples/ipsec-secgw: use HW parsed packet type in poll mode
[dpdk.git] / examples / l3fwd / lpm_route_parse.c
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 enum {
14         CB_FLD_DST_ADDR,
15         CB_FLD_IF_OUT,
16         CB_FLD_MAX
17 };
18
19 struct lpm_route_rule *route_base_v4;
20 struct lpm_route_rule *route_base_v6;
21 int route_num_v4;
22 int route_num_v6;
23
24 /* Bypass comment and empty lines */
25 int
26 is_bypass_line(const char *buff)
27 {
28         int i = 0;
29
30         /* comment line */
31         if (buff[0] == COMMENT_LEAD_CHAR)
32                 return 1;
33         /* empty line */
34         while (buff[i] != '\0') {
35                 if (!isspace(buff[i]))
36                         return 0;
37                 i++;
38         }
39         return 1;
40 }
41
42 static int
43 parse_ipv6_addr_mask(char *token, uint32_t *ipv6, uint8_t *mask)
44 {
45         char *sa, *sm, *sv;
46         const char *dlm =  "/";
47
48         sv = NULL;
49         sa = strtok_r(token, dlm, &sv);
50         if (sa == NULL)
51                 return -EINVAL;
52         sm = strtok_r(NULL, dlm, &sv);
53         if (sm == NULL)
54                 return -EINVAL;
55
56         if (inet_pton(AF_INET6, sa, ipv6) != 1)
57                 return -EINVAL;
58
59         GET_CB_FIELD(sm, *mask, 0, 128, 0);
60         return 0;
61 }
62
63 static int
64 parse_ipv4_addr_mask(char *token, uint32_t *ipv4, uint8_t *mask)
65 {
66         char *sa, *sm, *sv;
67         const char *dlm =  "/";
68
69         sv = NULL;
70         sa = strtok_r(token, dlm, &sv);
71         if (sa == NULL)
72                 return -EINVAL;
73         sm = strtok_r(NULL, dlm, &sv);
74         if (sm == NULL)
75                 return -EINVAL;
76
77         if (inet_pton(AF_INET, sa, ipv4) != 1)
78                 return -EINVAL;
79
80         GET_CB_FIELD(sm, *mask, 0, 32, 0);
81         *ipv4 = ntohl(*ipv4);
82         return 0;
83 }
84
85 static int
86 lpm_parse_v6_net(char *in, uint32_t *v, uint8_t *mask_len)
87 {
88         int32_t rc;
89
90         /* get address. */
91         rc = parse_ipv6_addr_mask(in, v, mask_len);
92
93         return rc;
94 }
95
96 static int
97 lpm_parse_v6_rule(char *str, struct lpm_route_rule *v)
98 {
99         int i, rc;
100         char *s, *sp, *in[CB_FLD_MAX];
101         static const char *dlm = " \t\n";
102         int dim = CB_FLD_MAX;
103         s = str;
104
105         for (i = 0; i != dim; i++, s = NULL) {
106                 in[i] = strtok_r(s, dlm, &sp);
107                 if (in[i] == NULL)
108                         return -EINVAL;
109         }
110
111         rc = lpm_parse_v6_net(in[CB_FLD_DST_ADDR], v->ip_32, &v->depth);
112
113         GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
114
115         return rc;
116 }
117
118 static int
119 lpm_parse_v4_rule(char *str, struct lpm_route_rule *v)
120 {
121         int i, rc;
122         char *s, *sp, *in[CB_FLD_MAX];
123         static const char *dlm = " \t\n";
124         int dim = CB_FLD_MAX;
125         s = str;
126
127         for (i = 0; i != dim; i++, s = NULL) {
128                 in[i] = strtok_r(s, dlm, &sp);
129                 if (in[i] == NULL)
130                         return -EINVAL;
131         }
132
133         rc = parse_ipv4_addr_mask(in[CB_FLD_DST_ADDR], &v->ip, &v->depth);
134
135         GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
136
137         return rc;
138 }
139
140 static int
141 lpm_add_default_v4_rules(void)
142 {
143         /* populate the LPM IPv4 table */
144         unsigned int i, rule_size = sizeof(*route_base_v4);
145         route_num_v4 = RTE_DIM(ipv4_l3fwd_route_array);
146
147         route_base_v4 = calloc(route_num_v4, rule_size);
148
149         for (i = 0; i < (unsigned int)route_num_v4; i++) {
150                 route_base_v4[i].ip = ipv4_l3fwd_route_array[i].ip;
151                 route_base_v4[i].depth = ipv4_l3fwd_route_array[i].depth;
152                 route_base_v4[i].if_out = ipv4_l3fwd_route_array[i].if_out;
153         }
154         return 0;
155 }
156
157 static int
158 lpm_add_default_v6_rules(void)
159 {
160         /* populate the LPM IPv6 table */
161         unsigned int i, rule_size = sizeof(*route_base_v6);
162         route_num_v6 = RTE_DIM(ipv6_l3fwd_route_array);
163
164         route_base_v6 = calloc(route_num_v6, rule_size);
165
166         for (i = 0; i < (unsigned int)route_num_v6; i++) {
167                 memcpy(route_base_v6[i].ip_8, ipv6_l3fwd_route_array[i].ip,
168                            sizeof(route_base_v6[i].ip_8));
169                 route_base_v6[i].depth = ipv6_l3fwd_route_array[i].depth;
170                 route_base_v6[i].if_out = ipv6_l3fwd_route_array[i].if_out;
171         }
172         return 0;
173 }
174
175 static int
176 lpm_add_rules(const char *rule_path,
177                 struct lpm_route_rule **proute_base,
178                 int (*parser)(char *, struct lpm_route_rule *))
179 {
180         struct lpm_route_rule *route_rules;
181         struct lpm_route_rule *next;
182         unsigned int route_num = 0;
183         unsigned int route_cnt = 0;
184         char buff[LINE_MAX];
185         FILE *fh;
186         unsigned int i = 0, rule_size = sizeof(*next);
187         int val;
188
189         *proute_base = NULL;
190         fh = fopen(rule_path, "rb");
191         if (fh == NULL)
192                 return -EINVAL;
193
194         while ((fgets(buff, LINE_MAX, fh) != NULL)) {
195                 if (buff[0] == ROUTE_LEAD_CHAR)
196                         route_num++;
197         }
198
199         if (route_num == 0) {
200                 fclose(fh);
201                 return -EINVAL;
202         }
203
204         val = fseek(fh, 0, SEEK_SET);
205         if (val < 0) {
206                 fclose(fh);
207                 return -EINVAL;
208         }
209
210         route_rules = calloc(route_num, rule_size);
211
212         if (route_rules == NULL) {
213                 fclose(fh);
214                 return -EINVAL;
215         }
216
217         i = 0;
218         while (fgets(buff, LINE_MAX, fh) != NULL) {
219                 i++;
220                 if (is_bypass_line(buff))
221                         continue;
222
223                 char s = buff[0];
224
225                 /* Route entry */
226                 if (s == ROUTE_LEAD_CHAR)
227                         next = &route_rules[route_cnt];
228
229                 /* Illegal line */
230                 else {
231                         RTE_LOG(ERR, L3FWD,
232                                 "%s Line %u: should start with leading "
233                                 "char %c\n",
234                                 rule_path, i, ROUTE_LEAD_CHAR);
235                         fclose(fh);
236                         free(route_rules);
237                         return -EINVAL;
238                 }
239
240                 if (parser(buff + 1, next) != 0) {
241                         RTE_LOG(ERR, L3FWD,
242                                 "%s Line %u: parse rules error\n",
243                                 rule_path, i);
244                         fclose(fh);
245                         free(route_rules);
246                         return -EINVAL;
247                 }
248
249                 route_cnt++;
250         }
251
252         fclose(fh);
253
254         *proute_base = route_rules;
255
256         return route_cnt;
257 }
258
259 void
260 lpm_free_routes(void)
261 {
262         free(route_base_v4);
263         free(route_base_v6);
264         route_base_v4 = NULL;
265         route_base_v6 = NULL;
266         route_num_v4 = 0;
267         route_num_v6 = 0;
268 }
269
270 /* Load rules from the input file */
271 void
272 read_config_files_lpm(void)
273 {
274         if (parm_config.rule_ipv4_name != NULL &&
275                         parm_config.rule_ipv6_name != NULL) {
276                 /* ipv4 check */
277                 route_num_v4 = lpm_add_rules(parm_config.rule_ipv4_name,
278                                         &route_base_v4, &lpm_parse_v4_rule);
279                 if (route_num_v4 < 0) {
280                         lpm_free_routes();
281                         rte_exit(EXIT_FAILURE, "Failed to add IPv4 rules\n");
282                 }
283
284                 /* ipv6 check */
285                 route_num_v6 = lpm_add_rules(parm_config.rule_ipv6_name,
286                                         &route_base_v6, &lpm_parse_v6_rule);
287                 if (route_num_v6 < 0) {
288                         lpm_free_routes();
289                         rte_exit(EXIT_FAILURE, "Failed to add IPv6 rules\n");
290                 }
291         } else {
292                 RTE_LOG(INFO, L3FWD, "Missing 1 or more rule files, using default instead\n");
293                 if (lpm_add_default_v4_rules() < 0) {
294                         lpm_free_routes();
295                         rte_exit(EXIT_FAILURE, "Failed to add default IPv4 rules\n");
296                 }
297                 if (lpm_add_default_v6_rules() < 0) {
298                         lpm_free_routes();
299                         rte_exit(EXIT_FAILURE, "Failed to add default IPv6 rules\n");
300                 }
301         }
302 }