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
parse_tokenize_string(char * string,char * tokens[],uint32_t * n_tokens)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
parse_ipv4_addr(const char * token,struct in_addr * ipv4,uint32_t * mask)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
parse_ipv6_addr(const char * token,struct in6_addr * ipv6,uint32_t * mask)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
parse_range(const char * token,uint16_t * low,uint16_t * high)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 *
parse_uint8x16(const char * s,uint8_t * v,uint8_t ls)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
parse_mac(const char * str,struct rte_ether_addr * addr)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
cfg_sp_add_cfg_item_parsed(void * parsed_result,__rte_unused struct cmdline * cl,void * data)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
cfg_sa_add_cfg_item_parsed(void * parsed_result,__rte_unused struct cmdline * cl,void * data)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
cfg_rt_add_cfg_item_parsed(void * parsed_result,__rte_unused struct cmdline * cl,void * data)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
cfg_flow_add_cfg_item_parsed(void * parsed_result,__rte_unused struct cmdline * cl,void * data)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
cfg_parse_neigh(void * parsed_result,__rte_unused struct cmdline * cl,void * data)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
parse_cfg_file(const char * cfg_filename)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 }
542