1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016 Intel Corporation. 3 * Copyright (c) 2009, Olivier MATZ <[email protected]> 4 * All rights reserved. 5 */ 6 7 /* For inet_pton4() and inet_pton6() functions: 8 * 9 * Copyright (c) 1996 by Internet Software Consortium. 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 16 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 18 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 19 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 20 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 21 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 22 * SOFTWARE. 23 */ 24 25 #include <stdint.h> 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <ctype.h> 29 #include <getopt.h> 30 #include <errno.h> 31 #include <stdarg.h> 32 #include <string.h> 33 #include <libgen.h> 34 #include <unistd.h> 35 #include <sys/wait.h> 36 37 #include <rte_errno.h> 38 39 #include "parser.h" 40 41 static uint32_t 42 get_hex_val(char c) 43 { 44 switch (c) { 45 case '0': case '1': case '2': case '3': case '4': case '5': 46 case '6': case '7': case '8': case '9': 47 return c - '0'; 48 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 49 return c - 'A' + 10; 50 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 51 return c - 'a' + 10; 52 default: 53 return 0; 54 } 55 } 56 57 int 58 softnic_parser_read_arg_bool(const char *p) 59 { 60 p = skip_white_spaces(p); 61 int result = -EINVAL; 62 63 if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) || 64 ((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) { 65 p += 3; 66 result = 1; 67 } 68 69 if (((p[0] == 'o') && (p[1] == 'n')) || 70 ((p[0] == 'O') && (p[1] == 'N'))) { 71 p += 2; 72 result = 1; 73 } 74 75 if (((p[0] == 'n') && (p[1] == 'o')) || 76 ((p[0] == 'N') && (p[1] == 'O'))) { 77 p += 2; 78 result = 0; 79 } 80 81 if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) || 82 ((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) { 83 p += 3; 84 result = 0; 85 } 86 87 p = skip_white_spaces(p); 88 89 if (p[0] != '\0') 90 return -EINVAL; 91 92 return result; 93 } 94 95 int 96 softnic_parser_read_uint64(uint64_t *value, const char *p) 97 { 98 char *next; 99 uint64_t val; 100 101 p = skip_white_spaces(p); 102 if (!isdigit(*p)) 103 return -EINVAL; 104 105 val = strtoul(p, &next, 10); 106 if (p == next) 107 return -EINVAL; 108 109 p = next; 110 switch (*p) { 111 case 'T': 112 val *= 1024ULL; 113 /* fall through */ 114 case 'G': 115 val *= 1024ULL; 116 /* fall through */ 117 case 'M': 118 val *= 1024ULL; 119 /* fall through */ 120 case 'k': 121 case 'K': 122 val *= 1024ULL; 123 p++; 124 break; 125 } 126 127 p = skip_white_spaces(p); 128 if (*p != '\0') 129 return -EINVAL; 130 131 *value = val; 132 return 0; 133 } 134 135 int 136 softnic_parser_read_uint64_hex(uint64_t *value, const char *p) 137 { 138 char *next; 139 uint64_t val; 140 141 p = skip_white_spaces(p); 142 143 val = strtoul(p, &next, 16); 144 if (p == next) 145 return -EINVAL; 146 147 p = skip_white_spaces(next); 148 if (*p != '\0') 149 return -EINVAL; 150 151 *value = val; 152 return 0; 153 } 154 155 int 156 softnic_parser_read_uint32(uint32_t *value, const char *p) 157 { 158 uint64_t val = 0; 159 int ret = softnic_parser_read_uint64(&val, p); 160 161 if (ret < 0) 162 return ret; 163 164 if (val > UINT32_MAX) 165 return -ERANGE; 166 167 *value = val; 168 return 0; 169 } 170 171 int 172 softnic_parser_read_uint32_hex(uint32_t *value, const char *p) 173 { 174 uint64_t val = 0; 175 int ret = softnic_parser_read_uint64_hex(&val, p); 176 177 if (ret < 0) 178 return ret; 179 180 if (val > UINT32_MAX) 181 return -ERANGE; 182 183 *value = val; 184 return 0; 185 } 186 187 int 188 softnic_parser_read_uint16(uint16_t *value, const char *p) 189 { 190 uint64_t val = 0; 191 int ret = softnic_parser_read_uint64(&val, p); 192 193 if (ret < 0) 194 return ret; 195 196 if (val > UINT16_MAX) 197 return -ERANGE; 198 199 *value = val; 200 return 0; 201 } 202 203 int 204 softnic_parser_read_uint16_hex(uint16_t *value, const char *p) 205 { 206 uint64_t val = 0; 207 int ret = softnic_parser_read_uint64_hex(&val, p); 208 209 if (ret < 0) 210 return ret; 211 212 if (val > UINT16_MAX) 213 return -ERANGE; 214 215 *value = val; 216 return 0; 217 } 218 219 int 220 softnic_parser_read_uint8(uint8_t *value, const char *p) 221 { 222 uint64_t val = 0; 223 int ret = softnic_parser_read_uint64(&val, p); 224 225 if (ret < 0) 226 return ret; 227 228 if (val > UINT8_MAX) 229 return -ERANGE; 230 231 *value = val; 232 return 0; 233 } 234 235 int 236 softnic_parser_read_uint8_hex(uint8_t *value, const char *p) 237 { 238 uint64_t val = 0; 239 int ret = softnic_parser_read_uint64_hex(&val, p); 240 241 if (ret < 0) 242 return ret; 243 244 if (val > UINT8_MAX) 245 return -ERANGE; 246 247 *value = val; 248 return 0; 249 } 250 251 int 252 softnic_parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens) 253 { 254 uint32_t i; 255 256 if (string == NULL || 257 tokens == NULL || 258 (*n_tokens < 1)) 259 return -EINVAL; 260 261 for (i = 0; i < *n_tokens; i++) { 262 tokens[i] = strtok_r(string, PARSE_DELIMITER, &string); 263 if (tokens[i] == NULL) 264 break; 265 } 266 267 if (i == *n_tokens && 268 strtok_r(string, PARSE_DELIMITER, &string) != NULL) 269 return -E2BIG; 270 271 *n_tokens = i; 272 return 0; 273 } 274 275 int 276 softnic_parse_hex_string(char *src, uint8_t *dst, uint32_t *size) 277 { 278 char *c; 279 uint32_t len, i; 280 281 /* Check input parameters */ 282 if (src == NULL || 283 dst == NULL || 284 size == NULL || 285 (*size == 0)) 286 return -1; 287 288 len = strlen(src); 289 if (((len & 3) != 0) || 290 (len > (*size) * 2)) 291 return -1; 292 *size = len / 2; 293 294 for (c = src; *c != 0; c++) { 295 if ((((*c) >= '0') && ((*c) <= '9')) || 296 (((*c) >= 'A') && ((*c) <= 'F')) || 297 (((*c) >= 'a') && ((*c) <= 'f'))) 298 continue; 299 300 return -1; 301 } 302 303 /* Convert chars to bytes */ 304 for (i = 0; i < *size; i++) 305 dst[i] = get_hex_val(src[2 * i]) * 16 + 306 get_hex_val(src[2 * i + 1]); 307 308 return 0; 309 } 310 311 int 312 softnic_parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels) 313 { 314 uint32_t n_max_labels = *n_labels, count = 0; 315 316 /* Check for void list of labels */ 317 if (strcmp(string, "<void>") == 0) { 318 *n_labels = 0; 319 return 0; 320 } 321 322 /* At least one label should be present */ 323 for ( ; (*string != '\0'); ) { 324 char *next; 325 int value; 326 327 if (count >= n_max_labels) 328 return -1; 329 330 if (count > 0) { 331 if (string[0] != ':') 332 return -1; 333 334 string++; 335 } 336 337 value = strtol(string, &next, 10); 338 if (next == string) 339 return -1; 340 string = next; 341 342 labels[count++] = (uint32_t)value; 343 } 344 345 *n_labels = count; 346 return 0; 347 } 348 349 #define INADDRSZ 4 350 #define IN6ADDRSZ 16 351 352 /* int 353 * inet_pton4(src, dst) 354 * like inet_aton() but without all the hexadecimal and shorthand. 355 * return: 356 * 1 if `src' is a valid dotted quad, else 0. 357 * notice: 358 * does not touch `dst' unless it's returning 1. 359 * author: 360 * Paul Vixie, 1996. 361 */ 362 static int 363 inet_pton4(const char *src, unsigned char *dst) 364 { 365 static const char digits[] = "0123456789"; 366 int saw_digit, octets, ch; 367 unsigned char tmp[INADDRSZ], *tp; 368 369 saw_digit = 0; 370 octets = 0; 371 *(tp = tmp) = 0; 372 while ((ch = *src++) != '\0') { 373 const char *pch; 374 375 pch = strchr(digits, ch); 376 if (pch != NULL) { 377 unsigned int new = *tp * 10 + (pch - digits); 378 379 if (new > 255) 380 return 0; 381 if (!saw_digit) { 382 if (++octets > 4) 383 return 0; 384 saw_digit = 1; 385 } 386 *tp = (unsigned char)new; 387 } else if (ch == '.' && saw_digit) { 388 if (octets == 4) 389 return 0; 390 *++tp = 0; 391 saw_digit = 0; 392 } else 393 return 0; 394 } 395 if (octets < 4) 396 return 0; 397 398 memcpy(dst, tmp, INADDRSZ); 399 return 1; 400 } 401 402 /* int 403 * inet_pton6(src, dst) 404 * convert presentation level address to network order binary form. 405 * return: 406 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 407 * notice: 408 * (1) does not touch `dst' unless it's returning 1. 409 * (2) :: in a full address is silently ignored. 410 * credit: 411 * inspired by Mark Andrews. 412 * author: 413 * Paul Vixie, 1996. 414 */ 415 static int 416 inet_pton6(const char *src, unsigned char *dst) 417 { 418 static const char xdigits_l[] = "0123456789abcdef", 419 xdigits_u[] = "0123456789ABCDEF"; 420 unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0; 421 const char *xdigits = 0, *curtok = 0; 422 int ch = 0, saw_xdigit = 0, count_xdigit = 0; 423 unsigned int val = 0; 424 unsigned int dbloct_count = 0; 425 426 memset((tp = tmp), '\0', IN6ADDRSZ); 427 endp = tp + IN6ADDRSZ; 428 colonp = NULL; 429 /* Leading :: requires some special handling. */ 430 if (*src == ':') 431 if (*++src != ':') 432 return 0; 433 curtok = src; 434 saw_xdigit = count_xdigit = 0; 435 val = 0; 436 437 while ((ch = *src++) != '\0') { 438 const char *pch; 439 440 pch = strchr((xdigits = xdigits_l), ch); 441 if (pch == NULL) 442 pch = strchr((xdigits = xdigits_u), ch); 443 if (pch != NULL) { 444 if (count_xdigit >= 4) 445 return 0; 446 val <<= 4; 447 val |= (pch - xdigits); 448 if (val > 0xffff) 449 return 0; 450 saw_xdigit = 1; 451 count_xdigit++; 452 continue; 453 } 454 if (ch == ':') { 455 curtok = src; 456 if (!saw_xdigit) { 457 if (colonp) 458 return 0; 459 colonp = tp; 460 continue; 461 } else if (*src == '\0') { 462 return 0; 463 } 464 if (tp + sizeof(int16_t) > endp) 465 return 0; 466 *tp++ = (unsigned char)((val >> 8) & 0xff); 467 *tp++ = (unsigned char)(val & 0xff); 468 saw_xdigit = 0; 469 count_xdigit = 0; 470 val = 0; 471 dbloct_count++; 472 continue; 473 } 474 if (ch == '.' && ((tp + INADDRSZ) <= endp) && 475 inet_pton4(curtok, tp) > 0) { 476 tp += INADDRSZ; 477 saw_xdigit = 0; 478 dbloct_count += 2; 479 break; /* '\0' was seen by inet_pton4(). */ 480 } 481 return 0; 482 } 483 if (saw_xdigit) { 484 if (tp + sizeof(int16_t) > endp) 485 return 0; 486 *tp++ = (unsigned char)((val >> 8) & 0xff); 487 *tp++ = (unsigned char)(val & 0xff); 488 dbloct_count++; 489 } 490 if (colonp != NULL) { 491 /* if we already have 8 double octets, having a colon means error */ 492 if (dbloct_count == 8) 493 return 0; 494 495 /* Since some memmove()'s erroneously fail to handle 496 * overlapping regions, we'll do the shift by hand. 497 */ 498 const int n = tp - colonp; 499 int i; 500 501 for (i = 1; i <= n; i++) { 502 endp[-i] = colonp[n - i]; 503 colonp[n - i] = 0; 504 } 505 tp = endp; 506 } 507 if (tp != endp) 508 return 0; 509 memcpy(dst, tmp, IN6ADDRSZ); 510 return 1; 511 } 512 513 static struct ether_addr * 514 my_ether_aton(const char *a) 515 { 516 int i; 517 char *end; 518 unsigned long o[ETHER_ADDR_LEN]; 519 static struct ether_addr ether_addr; 520 521 i = 0; 522 do { 523 errno = 0; 524 o[i] = strtoul(a, &end, 16); 525 if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0)) 526 return NULL; 527 a = end + 1; 528 } while (++i != sizeof(o) / sizeof(o[0]) && end[0] != 0); 529 530 /* Junk at the end of line */ 531 if (end[0] != 0) 532 return NULL; 533 534 /* Support the format XX:XX:XX:XX:XX:XX */ 535 if (i == ETHER_ADDR_LEN) { 536 while (i-- != 0) { 537 if (o[i] > UINT8_MAX) 538 return NULL; 539 ether_addr.addr_bytes[i] = (uint8_t)o[i]; 540 } 541 /* Support the format XXXX:XXXX:XXXX */ 542 } else if (i == ETHER_ADDR_LEN / 2) { 543 while (i-- != 0) { 544 if (o[i] > UINT16_MAX) 545 return NULL; 546 ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8); 547 ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff); 548 } 549 /* unknown format */ 550 } else 551 return NULL; 552 553 return (struct ether_addr *)ðer_addr; 554 } 555 556 int 557 softnic_parse_ipv4_addr(const char *token, struct in_addr *ipv4) 558 { 559 if (strlen(token) >= INET_ADDRSTRLEN) 560 return -EINVAL; 561 562 if (inet_pton4(token, (unsigned char *)ipv4) != 1) 563 return -EINVAL; 564 565 return 0; 566 } 567 568 int 569 softnic_parse_ipv6_addr(const char *token, struct in6_addr *ipv6) 570 { 571 if (strlen(token) >= INET6_ADDRSTRLEN) 572 return -EINVAL; 573 574 if (inet_pton6(token, (unsigned char *)ipv6) != 1) 575 return -EINVAL; 576 577 return 0; 578 } 579 580 int 581 softnic_parse_mac_addr(const char *token, struct ether_addr *addr) 582 { 583 struct ether_addr *tmp; 584 585 tmp = my_ether_aton(token); 586 if (tmp == NULL) 587 return -1; 588 589 memcpy(addr, tmp, sizeof(struct ether_addr)); 590 return 0; 591 } 592 593 int 594 softnic_parse_cpu_core(const char *entry, 595 struct softnic_cpu_core_params *p) 596 { 597 size_t num_len; 598 char num[8]; 599 600 uint32_t s = 0, c = 0, h = 0, val; 601 uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0; 602 const char *next = skip_white_spaces(entry); 603 char type; 604 605 if (p == NULL) 606 return -EINVAL; 607 608 /* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */ 609 while (*next != '\0') { 610 /* If everything parsed nothing should left */ 611 if (s_parsed && c_parsed && h_parsed) 612 return -EINVAL; 613 614 type = *next; 615 switch (type) { 616 case 's': 617 case 'S': 618 if (s_parsed || c_parsed || h_parsed) 619 return -EINVAL; 620 s_parsed = 1; 621 next++; 622 break; 623 case 'c': 624 case 'C': 625 if (c_parsed || h_parsed) 626 return -EINVAL; 627 c_parsed = 1; 628 next++; 629 break; 630 case 'h': 631 case 'H': 632 if (h_parsed) 633 return -EINVAL; 634 h_parsed = 1; 635 next++; 636 break; 637 default: 638 /* If it start from digit it must be only core id. */ 639 if (!isdigit(*next) || s_parsed || c_parsed || h_parsed) 640 return -EINVAL; 641 642 type = 'C'; 643 } 644 645 for (num_len = 0; *next != '\0'; next++, num_len++) { 646 if (num_len == RTE_DIM(num)) 647 return -EINVAL; 648 649 if (!isdigit(*next)) 650 break; 651 652 num[num_len] = *next; 653 } 654 655 if (num_len == 0 && type != 'h' && type != 'H') 656 return -EINVAL; 657 658 if (num_len != 0 && (type == 'h' || type == 'H')) 659 return -EINVAL; 660 661 num[num_len] = '\0'; 662 val = strtol(num, NULL, 10); 663 664 h = 0; 665 switch (type) { 666 case 's': 667 case 'S': 668 s = val; 669 break; 670 case 'c': 671 case 'C': 672 c = val; 673 break; 674 case 'h': 675 case 'H': 676 h = 1; 677 break; 678 } 679 } 680 681 p->socket_id = s; 682 p->core_id = c; 683 p->thread_id = h; 684 return 0; 685 } 686