mbuf: fix reset on mbuf free
[dpdk.git] / examples / ipsec-secgw / parser.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016 Intel Corporation
3  */
4 #include <arpa/inet.h>
5 #include <sys/socket.h>
6
7 #include <rte_common.h>
8 #include <rte_crypto.h>
9 #include <rte_string_fns.h>
10
11 #include <cmdline_parse_string.h>
12 #include <cmdline_parse_num.h>
13 #include <cmdline_parse_ipaddr.h>
14 #include <cmdline_socket.h>
15 #include <cmdline.h>
16
17 #include "flow.h"
18 #include "ipsec.h"
19 #include "parser.h"
20
21 #define PARSE_DELIMITER         " \f\n\r\t\v"
22 static int
23 parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
24 {
25         uint32_t i;
26
27         if ((string == NULL) ||
28                 (tokens == NULL) ||
29                 (*n_tokens < 1))
30                 return -EINVAL;
31
32         for (i = 0; i < *n_tokens; i++) {
33                 tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
34                 if (tokens[i] == NULL)
35                         break;
36         }
37
38         if ((i == *n_tokens) &&
39                 (NULL != strtok_r(string, PARSE_DELIMITER, &string)))
40                 return -E2BIG;
41
42         *n_tokens = i;
43         return 0;
44 }
45
46 int
47 parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask)
48 {
49         char ip_str[INET_ADDRSTRLEN] = {0};
50         char *pch;
51
52         pch = strchr(token, '/');
53         if (pch != NULL) {
54                 strlcpy(ip_str, token,
55                         RTE_MIN((unsigned int long)(pch - token + 1),
56                         sizeof(ip_str)));
57                 pch += 1;
58                 if (is_str_num(pch) != 0)
59                         return -EINVAL;
60                 if (mask)
61                         *mask = atoi(pch);
62         } else {
63                 strlcpy(ip_str, token, sizeof(ip_str));
64                 if (mask)
65                         *mask = 0;
66         }
67         if (strlen(ip_str) >= INET_ADDRSTRLEN)
68                 return -EINVAL;
69
70         if (inet_pton(AF_INET, ip_str, ipv4) != 1)
71                 return -EINVAL;
72
73         return 0;
74 }
75
76 int
77 parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask)
78 {
79         char ip_str[256] = {0};
80         char *pch;
81
82         pch = strchr(token, '/');
83         if (pch != NULL) {
84                 strlcpy(ip_str, token,
85                         RTE_MIN((unsigned int long)(pch - token + 1),
86                                         sizeof(ip_str)));
87                 pch += 1;
88                 if (is_str_num(pch) != 0)
89                         return -EINVAL;
90                 if (mask)
91                         *mask = atoi(pch);
92         } else {
93                 strlcpy(ip_str, token, sizeof(ip_str));
94                 if (mask)
95                         *mask = 0;
96         }
97
98         if (strlen(ip_str) >= INET6_ADDRSTRLEN)
99                 return -EINVAL;
100
101         if (inet_pton(AF_INET6, ip_str, ipv6) != 1)
102                 return -EINVAL;
103
104         return 0;
105 }
106
107 int
108 parse_range(const char *token, uint16_t *low, uint16_t *high)
109 {
110         char ch;
111         char num_str[20];
112         uint32_t pos;
113         int range_low = -1;
114         int range_high = -1;
115
116         if (!low || !high)
117                 return -1;
118
119         memset(num_str, 0, 20);
120         pos = 0;
121
122         while ((ch = *token++) != '\0') {
123                 if (isdigit(ch)) {
124                         if (pos >= 19)
125                                 return -1;
126                         num_str[pos++] = ch;
127                 } else if (ch == ':') {
128                         if (range_low != -1)
129                                 return -1;
130                         range_low = atoi(num_str);
131                         memset(num_str, 0, 20);
132                         pos = 0;
133                 }
134         }
135
136         if (strlen(num_str) == 0)
137                 return -1;
138
139         range_high = atoi(num_str);
140
141         *low = (uint16_t)range_low;
142         *high = (uint16_t)range_high;
143
144         return 0;
145 }
146
147 /*
148  * helper function for parse_mac, parse one section of the ether addr.
149  */
150 static const char *
151 parse_uint8x16(const char *s, uint8_t *v, uint8_t ls)
152 {
153         char *end;
154         unsigned long t;
155
156         errno = 0;
157         t = strtoul(s, &end, 16);
158         if (errno != 0 || end[0] != ls || t > UINT8_MAX)
159                 return NULL;
160         v[0] = t;
161         return end + 1;
162 }
163
164 static int
165 parse_mac(const char *str, struct rte_ether_addr *addr)
166 {
167         uint32_t i;
168
169         static const uint8_t stop_sym[RTE_DIM(addr->addr_bytes)] = {
170                 [0] = ':',
171                 [1] = ':',
172                 [2] = ':',
173                 [3] = ':',
174                 [4] = ':',
175                 [5] = 0,
176         };
177
178         for (i = 0; i != RTE_DIM(addr->addr_bytes); i++) {
179                 str = parse_uint8x16(str, addr->addr_bytes + i, stop_sym[i]);
180                 if (str == NULL)
181                         return -EINVAL;
182         }
183
184         return 0;
185 }
186
187 /** sp add parse */
188 struct cfg_sp_add_cfg_item {
189         cmdline_fixed_string_t sp_keyword;
190         cmdline_multi_string_t multi_string;
191 };
192
193 static void
194 cfg_sp_add_cfg_item_parsed(void *parsed_result,
195         __rte_unused struct cmdline *cl, void *data)
196 {
197         struct cfg_sp_add_cfg_item *params = parsed_result;
198         char *tokens[32];
199         uint32_t n_tokens = RTE_DIM(tokens);
200         struct parse_status *status = (struct parse_status *)data;
201
202         APP_CHECK((parse_tokenize_string(params->multi_string, tokens,
203                 &n_tokens) == 0), status, "too many arguments");
204
205         if (status->status < 0)
206                 return;
207
208         if (strcmp(tokens[0], "ipv4") == 0) {
209                 parse_sp4_tokens(tokens, n_tokens, status);
210                 if (status->status < 0)
211                         return;
212         } else if (strcmp(tokens[0], "ipv6") == 0) {
213                 parse_sp6_tokens(tokens, n_tokens, status);
214                 if (status->status < 0)
215                         return;
216         } else {
217                 APP_CHECK(0, status, "unrecognizable input %s\n",
218                         tokens[0]);
219                 return;
220         }
221 }
222
223 static cmdline_parse_token_string_t cfg_sp_add_sp_str =
224         TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item,
225                 sp_keyword, "sp");
226
227 static cmdline_parse_token_string_t cfg_sp_add_multi_str =
228         TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item, multi_string,
229                 TOKEN_STRING_MULTI);
230
231 cmdline_parse_inst_t cfg_sp_add_rule = {
232         .f = cfg_sp_add_cfg_item_parsed,
233         .data = NULL,
234         .help_str = "",
235         .tokens = {
236                 (void *) &cfg_sp_add_sp_str,
237                 (void *) &cfg_sp_add_multi_str,
238                 NULL,
239         },
240 };
241
242 /* sa add parse */
243 struct cfg_sa_add_cfg_item {
244         cmdline_fixed_string_t sa_keyword;
245         cmdline_multi_string_t multi_string;
246 };
247
248 static void
249 cfg_sa_add_cfg_item_parsed(void *parsed_result,
250         __rte_unused struct cmdline *cl, void *data)
251 {
252         struct cfg_sa_add_cfg_item *params = parsed_result;
253         char *tokens[32];
254         uint32_t n_tokens = RTE_DIM(tokens);
255         struct parse_status *status = (struct parse_status *)data;
256
257         APP_CHECK(parse_tokenize_string(params->multi_string, tokens,
258                 &n_tokens) == 0, status, "too many arguments\n");
259
260         parse_sa_tokens(tokens, n_tokens, status);
261 }
262
263 static cmdline_parse_token_string_t cfg_sa_add_sa_str =
264         TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item,
265                 sa_keyword, "sa");
266
267 static cmdline_parse_token_string_t cfg_sa_add_multi_str =
268         TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item, multi_string,
269                 TOKEN_STRING_MULTI);
270
271 cmdline_parse_inst_t cfg_sa_add_rule = {
272         .f = cfg_sa_add_cfg_item_parsed,
273         .data = NULL,
274         .help_str = "",
275         .tokens = {
276                 (void *) &cfg_sa_add_sa_str,
277                 (void *) &cfg_sa_add_multi_str,
278                 NULL,
279         },
280 };
281
282 /* rt add parse */
283 struct cfg_rt_add_cfg_item {
284         cmdline_fixed_string_t rt_keyword;
285         cmdline_multi_string_t multi_string;
286 };
287
288 static void
289 cfg_rt_add_cfg_item_parsed(void *parsed_result,
290         __rte_unused struct cmdline *cl, void *data)
291 {
292         struct cfg_rt_add_cfg_item *params = parsed_result;
293         char *tokens[32];
294         uint32_t n_tokens = RTE_DIM(tokens);
295         struct parse_status *status = (struct parse_status *)data;
296
297         APP_CHECK(parse_tokenize_string(
298                 params->multi_string, tokens, &n_tokens) == 0,
299                 status, "too many arguments\n");
300         if (status->status < 0)
301                 return;
302
303         parse_rt_tokens(tokens, n_tokens, status);
304 }
305
306 static cmdline_parse_token_string_t cfg_rt_add_rt_str =
307         TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item,
308                 rt_keyword, "rt");
309
310 static cmdline_parse_token_string_t cfg_rt_add_multi_str =
311         TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item, multi_string,
312                 TOKEN_STRING_MULTI);
313
314 cmdline_parse_inst_t cfg_rt_add_rule = {
315         .f = cfg_rt_add_cfg_item_parsed,
316         .data = NULL,
317         .help_str = "",
318         .tokens = {
319                 (void *) &cfg_rt_add_rt_str,
320                 (void *) &cfg_rt_add_multi_str,
321                 NULL,
322         },
323 };
324
325 /* flow add parse */
326 struct cfg_flow_add_cfg_item {
327         cmdline_fixed_string_t flow_keyword;
328         cmdline_multi_string_t multi_string;
329 };
330
331 static void
332 cfg_flow_add_cfg_item_parsed(void *parsed_result,
333         __rte_unused struct cmdline *cl, void *data)
334 {
335         struct cfg_flow_add_cfg_item *params = parsed_result;
336         char *tokens[32];
337         uint32_t n_tokens = RTE_DIM(tokens);
338         struct parse_status *status = (struct parse_status *)data;
339
340         APP_CHECK(parse_tokenize_string(
341                 params->multi_string, tokens, &n_tokens) == 0,
342                 status, "too many arguments\n");
343         if (status->status < 0)
344                 return;
345
346         parse_flow_tokens(tokens, n_tokens, status);
347 }
348
349 static cmdline_parse_token_string_t cfg_flow_add_flow_str =
350         TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item,
351                 flow_keyword, "flow");
352
353 static cmdline_parse_token_string_t cfg_flow_add_multi_str =
354         TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item, multi_string,
355                 TOKEN_STRING_MULTI);
356
357 cmdline_parse_inst_t cfg_flow_add_rule = {
358         .f = cfg_flow_add_cfg_item_parsed,
359         .data = NULL,
360         .help_str = "",
361         .tokens = {
362                 (void *) &cfg_flow_add_flow_str,
363                 (void *) &cfg_flow_add_multi_str,
364                 NULL,
365         },
366 };
367
368 /* neigh add parse */
369 struct cfg_neigh_add_item {
370         cmdline_fixed_string_t neigh;
371         cmdline_fixed_string_t pstr;
372         uint16_t port;
373         cmdline_fixed_string_t mac;
374 };
375
376 static void
377 cfg_parse_neigh(void *parsed_result, __rte_unused struct cmdline *cl,
378         void *data)
379 {
380         int32_t rc;
381         struct cfg_neigh_add_item *res;
382         struct parse_status *st;
383         struct rte_ether_addr mac;
384
385         st = data;
386         res = parsed_result;
387         rc = parse_mac(res->mac, &mac);
388         APP_CHECK(rc == 0, st, "invalid ether addr:%s", res->mac);
389         rc = add_dst_ethaddr(res->port, &mac);
390         APP_CHECK(rc == 0, st, "invalid port numer:%hu", res->port);
391         if (st->status < 0)
392                 return;
393 }
394
395 cmdline_parse_token_string_t cfg_add_neigh_start =
396         TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, neigh, "neigh");
397 cmdline_parse_token_string_t cfg_add_neigh_pstr =
398         TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, pstr, "port");
399 cmdline_parse_token_num_t cfg_add_neigh_port =
400         TOKEN_NUM_INITIALIZER(struct cfg_neigh_add_item, port, RTE_UINT16);
401 cmdline_parse_token_string_t cfg_add_neigh_mac =
402         TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, mac, NULL);
403
404 cmdline_parse_inst_t cfg_neigh_add_rule = {
405         .f = cfg_parse_neigh,
406         .data = NULL,
407         .help_str = "",
408         .tokens = {
409                 (void *)&cfg_add_neigh_start,
410                 (void *)&cfg_add_neigh_pstr,
411                 (void *)&cfg_add_neigh_port,
412                 (void *)&cfg_add_neigh_mac,
413                 NULL,
414         },
415 };
416
417 /** set of cfg items */
418 cmdline_parse_ctx_t ipsec_ctx[] = {
419         (cmdline_parse_inst_t *)&cfg_sp_add_rule,
420         (cmdline_parse_inst_t *)&cfg_sa_add_rule,
421         (cmdline_parse_inst_t *)&cfg_rt_add_rule,
422         (cmdline_parse_inst_t *)&cfg_flow_add_rule,
423         (cmdline_parse_inst_t *)&cfg_neigh_add_rule,
424         NULL,
425 };
426
427 int
428 parse_cfg_file(const char *cfg_filename)
429 {
430         struct cmdline *cl = cmdline_stdin_new(ipsec_ctx, "");
431         FILE *f = fopen(cfg_filename, "r");
432         char str[1024] = {0}, *get_s = NULL;
433         uint32_t line_num = 0;
434         struct parse_status status = {0};
435
436         if (f == NULL) {
437                 rte_panic("Error: invalid file descriptor %s\n", cfg_filename);
438                 goto error_exit;
439         }
440
441         if (cl == NULL) {
442                 rte_panic("Error: cannot create cmdline instance\n");
443                 goto error_exit;
444         }
445
446         cfg_sp_add_rule.data = &status;
447         cfg_sa_add_rule.data = &status;
448         cfg_rt_add_rule.data = &status;
449         cfg_flow_add_rule.data = &status;
450         cfg_neigh_add_rule.data = &status;
451
452         do {
453                 char oneline[1024];
454                 char *pos;
455                 get_s = fgets(oneline, 1024, f);
456
457                 if (!get_s)
458                         break;
459
460                 line_num++;
461
462                 if (strlen(oneline) > 1022) {
463                         rte_panic("%s:%u: error: "
464                                 "the line contains more characters the parser can handle\n",
465                                 cfg_filename, line_num);
466                         goto error_exit;
467                 }
468
469                 /* process comment char '#' */
470                 if (oneline[0] == '#')
471                         continue;
472
473                 pos = strchr(oneline, '#');
474                 if (pos != NULL)
475                         *pos = '\0';
476
477                 /* process line concatenator '\' */
478                 pos = strchr(oneline, 92);
479                 if (pos != NULL) {
480                         if (pos != oneline+strlen(oneline) - 2) {
481                                 rte_panic("%s:%u: error: "
482                                         "no character should exist after '\\'\n",
483                                         cfg_filename, line_num);
484                                 goto error_exit;
485                         }
486
487                         *pos = '\0';
488
489                         if (strlen(oneline) + strlen(str) > 1022) {
490                                 rte_panic("%s:%u: error: "
491                                         "the concatenated line contains more characters the parser can handle\n",
492                                         cfg_filename, line_num);
493                                 goto error_exit;
494                         }
495
496                         strcpy(str + strlen(str), oneline);
497                         continue;
498                 }
499
500                 /* copy the line to str and process */
501                 if (strlen(oneline) + strlen(str) > 1022) {
502                         rte_panic("%s:%u: error: "
503                                 "the line contains more characters the parser can handle\n",
504                                 cfg_filename, line_num);
505                         goto error_exit;
506                 }
507                 strcpy(str + strlen(str), oneline);
508
509                 str[strlen(str)] = '\n';
510                 if (cmdline_parse(cl, str) < 0) {
511                         rte_panic("%s:%u: error: parsing \"%s\" failed\n",
512                                 cfg_filename, line_num, str);
513                         goto error_exit;
514                 }
515
516                 if (status.status < 0) {
517                         rte_panic("%s:%u: error: %s", cfg_filename,
518                                 line_num, status.parse_msg);
519                         goto error_exit;
520                 }
521
522                 memset(str, 0, 1024);
523         } while (1);
524
525         cmdline_stdin_exit(cl);
526         fclose(f);
527
528         sa_sort_arr();
529         sp4_sort_arr();
530         sp6_sort_arr();
531
532         return 0;
533
534 error_exit:
535         if (cl)
536                 cmdline_stdin_exit(cl);
537         if (f)
538                 fclose(f);
539
540         return -1;
541 }