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 } 542