]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/examples/ipsec-secgw/parser.c
98f8176651ae184db05c37853c7da747e7fe6958
[ceph.git] / ceph / src / seastar / dpdk / examples / ipsec-secgw / parser.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016 Intel Corporation
3 */
4 #include <stdlib.h>
5 #include <arpa/inet.h>
6 #include <sys/socket.h>
7
8 #include <rte_common.h>
9 #include <rte_crypto.h>
10 #include <rte_string_fns.h>
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
18 #include "flow.h"
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
47 int
48 parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask)
49 {
50 char ip_str[INET_ADDRSTRLEN] = {0};
51 char *pch;
52
53 pch = strchr(token, '/');
54 if (pch != NULL) {
55 strlcpy(ip_str, token,
56 RTE_MIN((unsigned int long)(pch - token + 1),
57 sizeof(ip_str)));
58 pch += 1;
59 if (is_str_num(pch) != 0)
60 return -EINVAL;
61 if (mask)
62 *mask = atoi(pch);
63 } else {
64 strlcpy(ip_str, token, sizeof(ip_str));
65 if (mask)
66 *mask = 0;
67 }
68 if (strlen(ip_str) >= INET_ADDRSTRLEN)
69 return -EINVAL;
70
71 if (inet_pton(AF_INET, ip_str, ipv4) != 1)
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) {
85 strlcpy(ip_str, token,
86 RTE_MIN((unsigned int long)(pch - token + 1),
87 sizeof(ip_str)));
88 pch += 1;
89 if (is_str_num(pch) != 0)
90 return -EINVAL;
91 if (mask)
92 *mask = atoi(pch);
93 } else {
94 strlcpy(ip_str, token, sizeof(ip_str));
95 if (mask)
96 *mask = 0;
97 }
98
99 if (strlen(ip_str) >= INET6_ADDRSTRLEN)
100 return -EINVAL;
101
102 if (inet_pton(AF_INET6, ip_str, ipv6) != 1)
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
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
166 parse_mac(const char *str, struct rte_ether_addr *addr)
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
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
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
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;
384 struct rte_ether_addr mac;
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 =
401 TOKEN_NUM_INITIALIZER(struct cfg_neigh_add_item, port, RTE_UINT16);
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
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,
423 (cmdline_parse_inst_t *)&cfg_flow_add_rule,
424 (cmdline_parse_inst_t *)&cfg_neigh_add_rule,
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;
450 cfg_flow_add_rule.data = &status;
451 cfg_neigh_add_rule.data = &status;
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
497 strcpy(str + strlen(str), oneline);
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 }
508 strcpy(str + strlen(str), oneline);
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
529 sa_sort_arr();
530 sp4_sort_arr();
531 sp6_sort_arr();
532
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 }