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