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_int32(int32_t *value, const char *p) 97 { 98 char *next; 99 int32_t val; 100 101 p = skip_white_spaces(p); 102 if (!isdigit(*p)) 103 return -EINVAL; 104 105 val = strtol(p, &next, 10); 106 if (p == next) 107 return -EINVAL; 108 109 *value = val; 110 return 0; 111 } 112 113 int 114 softnic_parser_read_uint64(uint64_t *value, const char *p) 115 { 116 char *next; 117 uint64_t val; 118 119 p = skip_white_spaces(p); 120 if (!isdigit(*p)) 121 return -EINVAL; 122 123 val = strtoul(p, &next, 10); 124 if (p == next) 125 return -EINVAL; 126 127 p = next; 128 switch (*p) { 129 case 'T': 130 val *= 1024ULL; 131 /* fall through */ 132 case 'G': 133 val *= 1024ULL; 134 /* fall through */ 135 case 'M': 136 val *= 1024ULL; 137 /* fall through */ 138 case 'k': 139 case 'K': 140 val *= 1024ULL; 141 p++; 142 break; 143 } 144 145 p = skip_white_spaces(p); 146 if (*p != '\0') 147 return -EINVAL; 148 149 *value = val; 150 return 0; 151 } 152 153 int 154 softnic_parser_read_uint64_hex(uint64_t *value, const char *p) 155 { 156 char *next; 157 uint64_t val; 158 159 p = skip_white_spaces(p); 160 161 val = strtoul(p, &next, 16); 162 if (p == next) 163 return -EINVAL; 164 165 p = skip_white_spaces(next); 166 if (*p != '\0') 167 return -EINVAL; 168 169 *value = val; 170 return 0; 171 } 172 173 int 174 softnic_parser_read_uint32(uint32_t *value, const char *p) 175 { 176 uint64_t val = 0; 177 int ret = softnic_parser_read_uint64(&val, p); 178 179 if (ret < 0) 180 return ret; 181 182 if (val > UINT32_MAX) 183 return -ERANGE; 184 185 *value = val; 186 return 0; 187 } 188 189 int 190 softnic_parser_read_uint32_hex(uint32_t *value, const char *p) 191 { 192 uint64_t val = 0; 193 int ret = softnic_parser_read_uint64_hex(&val, p); 194 195 if (ret < 0) 196 return ret; 197 198 if (val > UINT32_MAX) 199 return -ERANGE; 200 201 *value = val; 202 return 0; 203 } 204 205 int 206 softnic_parser_read_uint16(uint16_t *value, const char *p) 207 { 208 uint64_t val = 0; 209 int ret = softnic_parser_read_uint64(&val, p); 210 211 if (ret < 0) 212 return ret; 213 214 if (val > UINT16_MAX) 215 return -ERANGE; 216 217 *value = val; 218 return 0; 219 } 220 221 int 222 softnic_parser_read_uint16_hex(uint16_t *value, const char *p) 223 { 224 uint64_t val = 0; 225 int ret = softnic_parser_read_uint64_hex(&val, p); 226 227 if (ret < 0) 228 return ret; 229 230 if (val > UINT16_MAX) 231 return -ERANGE; 232 233 *value = val; 234 return 0; 235 } 236 237 int 238 softnic_parser_read_uint8(uint8_t *value, const char *p) 239 { 240 uint64_t val = 0; 241 int ret = softnic_parser_read_uint64(&val, p); 242 243 if (ret < 0) 244 return ret; 245 246 if (val > UINT8_MAX) 247 return -ERANGE; 248 249 *value = val; 250 return 0; 251 } 252 253 int 254 softnic_parser_read_uint8_hex(uint8_t *value, const char *p) 255 { 256 uint64_t val = 0; 257 int ret = softnic_parser_read_uint64_hex(&val, p); 258 259 if (ret < 0) 260 return ret; 261 262 if (val > UINT8_MAX) 263 return -ERANGE; 264 265 *value = val; 266 return 0; 267 } 268 269 int 270 softnic_parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens) 271 { 272 uint32_t i; 273 274 if (string == NULL || 275 tokens == NULL || 276 (*n_tokens < 1)) 277 return -EINVAL; 278 279 for (i = 0; i < *n_tokens; i++) { 280 tokens[i] = strtok_r(string, PARSE_DELIMITER, &string); 281 if (tokens[i] == NULL) 282 break; 283 } 284 285 if (i == *n_tokens && 286 strtok_r(string, PARSE_DELIMITER, &string) != NULL) 287 return -E2BIG; 288 289 *n_tokens = i; 290 return 0; 291 } 292 293 int 294 softnic_parse_hex_string(char *src, uint8_t *dst, uint32_t *size) 295 { 296 char *c; 297 uint32_t len, i; 298 299 /* Check input parameters */ 300 if (src == NULL || 301 dst == NULL || 302 size == NULL || 303 (*size == 0)) 304 return -1; 305 306 len = strlen(src); 307 if (((len & 3) != 0) || 308 (len > (*size) * 2)) 309 return -1; 310 *size = len / 2; 311 312 for (c = src; *c != 0; c++) { 313 if ((((*c) >= '0') && ((*c) <= '9')) || 314 (((*c) >= 'A') && ((*c) <= 'F')) || 315 (((*c) >= 'a') && ((*c) <= 'f'))) 316 continue; 317 318 return -1; 319 } 320 321 /* Convert chars to bytes */ 322 for (i = 0; i < *size; i++) 323 dst[i] = get_hex_val(src[2 * i]) * 16 + 324 get_hex_val(src[2 * i + 1]); 325 326 return 0; 327 } 328 329 int 330 softnic_parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels) 331 { 332 uint32_t n_max_labels = *n_labels, count = 0; 333 334 /* Check for void list of labels */ 335 if (strcmp(string, "<void>") == 0) { 336 *n_labels = 0; 337 return 0; 338 } 339 340 /* At least one label should be present */ 341 for ( ; (*string != '\0'); ) { 342 char *next; 343 int value; 344 345 if (count >= n_max_labels) 346 return -1; 347 348 if (count > 0) { 349 if (string[0] != ':') 350 return -1; 351 352 string++; 353 } 354 355 value = strtol(string, &next, 10); 356 if (next == string) 357 return -1; 358 string = next; 359 360 labels[count++] = (uint32_t)value; 361 } 362 363 *n_labels = count; 364 return 0; 365 } 366 367 #define INADDRSZ 4 368 #define IN6ADDRSZ 16 369 370 /* int 371 * inet_pton4(src, dst) 372 * like inet_aton() but without all the hexadecimal and shorthand. 373 * return: 374 * 1 if `src' is a valid dotted quad, else 0. 375 * notice: 376 * does not touch `dst' unless it's returning 1. 377 * author: 378 * Paul Vixie, 1996. 379 */ 380 static int 381 inet_pton4(const char *src, unsigned char *dst) 382 { 383 static const char digits[] = "0123456789"; 384 int saw_digit, octets, ch; 385 unsigned char tmp[INADDRSZ], *tp; 386 387 saw_digit = 0; 388 octets = 0; 389 *(tp = tmp) = 0; 390 while ((ch = *src++) != '\0') { 391 const char *pch; 392 393 pch = strchr(digits, ch); 394 if (pch != NULL) { 395 unsigned int new = *tp * 10 + (pch - digits); 396 397 if (new > 255) 398 return 0; 399 if (!saw_digit) { 400 if (++octets > 4) 401 return 0; 402 saw_digit = 1; 403 } 404 *tp = (unsigned char)new; 405 } else if (ch == '.' && saw_digit) { 406 if (octets == 4) 407 return 0; 408 *++tp = 0; 409 saw_digit = 0; 410 } else 411 return 0; 412 } 413 if (octets < 4) 414 return 0; 415 416 memcpy(dst, tmp, INADDRSZ); 417 return 1; 418 } 419 420 /* int 421 * inet_pton6(src, dst) 422 * convert presentation level address to network order binary form. 423 * return: 424 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 425 * notice: 426 * (1) does not touch `dst' unless it's returning 1. 427 * (2) :: in a full address is silently ignored. 428 * credit: 429 * inspired by Mark Andrews. 430 * author: 431 * Paul Vixie, 1996. 432 */ 433 static int 434 inet_pton6(const char *src, unsigned char *dst) 435 { 436 static const char xdigits_l[] = "0123456789abcdef", 437 xdigits_u[] = "0123456789ABCDEF"; 438 unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0; 439 const char *xdigits = 0, *curtok = 0; 440 int ch = 0, saw_xdigit = 0, count_xdigit = 0; 441 unsigned int val = 0; 442 unsigned int dbloct_count = 0; 443 444 memset((tp = tmp), '\0', IN6ADDRSZ); 445 endp = tp + IN6ADDRSZ; 446 colonp = NULL; 447 /* Leading :: requires some special handling. */ 448 if (*src == ':') 449 if (*++src != ':') 450 return 0; 451 curtok = src; 452 saw_xdigit = count_xdigit = 0; 453 val = 0; 454 455 while ((ch = *src++) != '\0') { 456 const char *pch; 457 458 pch = strchr((xdigits = xdigits_l), ch); 459 if (pch == NULL) 460 pch = strchr((xdigits = xdigits_u), ch); 461 if (pch != NULL) { 462 if (count_xdigit >= 4) 463 return 0; 464 val <<= 4; 465 val |= (pch - xdigits); 466 if (val > 0xffff) 467 return 0; 468 saw_xdigit = 1; 469 count_xdigit++; 470 continue; 471 } 472 if (ch == ':') { 473 curtok = src; 474 if (!saw_xdigit) { 475 if (colonp) 476 return 0; 477 colonp = tp; 478 continue; 479 } else if (*src == '\0') { 480 return 0; 481 } 482 if (tp + sizeof(int16_t) > endp) 483 return 0; 484 *tp++ = (unsigned char)((val >> 8) & 0xff); 485 *tp++ = (unsigned char)(val & 0xff); 486 saw_xdigit = 0; 487 count_xdigit = 0; 488 val = 0; 489 dbloct_count++; 490 continue; 491 } 492 if (ch == '.' && ((tp + INADDRSZ) <= endp) && 493 inet_pton4(curtok, tp) > 0) { 494 tp += INADDRSZ; 495 saw_xdigit = 0; 496 dbloct_count += 2; 497 break; /* '\0' was seen by inet_pton4(). */ 498 } 499 return 0; 500 } 501 if (saw_xdigit) { 502 if (tp + sizeof(int16_t) > endp) 503 return 0; 504 *tp++ = (unsigned char)((val >> 8) & 0xff); 505 *tp++ = (unsigned char)(val & 0xff); 506 dbloct_count++; 507 } 508 if (colonp != NULL) { 509 /* if we already have 8 double octets, having a colon means error */ 510 if (dbloct_count == 8) 511 return 0; 512 513 /* Since some memmove()'s erroneously fail to handle 514 * overlapping regions, we'll do the shift by hand. 515 */ 516 const int n = tp - colonp; 517 int i; 518 519 for (i = 1; i <= n; i++) { 520 endp[-i] = colonp[n - i]; 521 colonp[n - i] = 0; 522 } 523 tp = endp; 524 } 525 if (tp != endp) 526 return 0; 527 memcpy(dst, tmp, IN6ADDRSZ); 528 return 1; 529 } 530 531 static struct ether_addr * 532 my_ether_aton(const char *a) 533 { 534 int i; 535 char *end; 536 unsigned long o[ETHER_ADDR_LEN]; 537 static struct ether_addr ether_addr; 538 539 i = 0; 540 do { 541 errno = 0; 542 o[i] = strtoul(a, &end, 16); 543 if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0)) 544 return NULL; 545 a = end + 1; 546 } while (++i != sizeof(o) / sizeof(o[0]) && end[0] != 0); 547 548 /* Junk at the end of line */ 549 if (end[0] != 0) 550 return NULL; 551 552 /* Support the format XX:XX:XX:XX:XX:XX */ 553 if (i == ETHER_ADDR_LEN) { 554 while (i-- != 0) { 555 if (o[i] > UINT8_MAX) 556 return NULL; 557 ether_addr.addr_bytes[i] = (uint8_t)o[i]; 558 } 559 /* Support the format XXXX:XXXX:XXXX */ 560 } else if (i == ETHER_ADDR_LEN / 2) { 561 while (i-- != 0) { 562 if (o[i] > UINT16_MAX) 563 return NULL; 564 ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8); 565 ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff); 566 } 567 /* unknown format */ 568 } else 569 return NULL; 570 571 return (struct ether_addr *)ðer_addr; 572 } 573 574 int 575 softnic_parse_ipv4_addr(const char *token, struct in_addr *ipv4) 576 { 577 if (strlen(token) >= INET_ADDRSTRLEN) 578 return -EINVAL; 579 580 if (inet_pton4(token, (unsigned char *)ipv4) != 1) 581 return -EINVAL; 582 583 return 0; 584 } 585 586 int 587 softnic_parse_ipv6_addr(const char *token, struct in6_addr *ipv6) 588 { 589 if (strlen(token) >= INET6_ADDRSTRLEN) 590 return -EINVAL; 591 592 if (inet_pton6(token, (unsigned char *)ipv6) != 1) 593 return -EINVAL; 594 595 return 0; 596 } 597 598 int 599 softnic_parse_mac_addr(const char *token, struct ether_addr *addr) 600 { 601 struct ether_addr *tmp; 602 603 tmp = my_ether_aton(token); 604 if (tmp == NULL) 605 return -1; 606 607 memcpy(addr, tmp, sizeof(struct ether_addr)); 608 return 0; 609 } 610 611 int 612 softnic_parse_cpu_core(const char *entry, 613 struct softnic_cpu_core_params *p) 614 { 615 size_t num_len; 616 char num[8]; 617 618 uint32_t s = 0, c = 0, h = 0, val; 619 uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0; 620 const char *next = skip_white_spaces(entry); 621 char type; 622 623 if (p == NULL) 624 return -EINVAL; 625 626 /* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */ 627 while (*next != '\0') { 628 /* If everything parsed nothing should left */ 629 if (s_parsed && c_parsed && h_parsed) 630 return -EINVAL; 631 632 type = *next; 633 switch (type) { 634 case 's': 635 case 'S': 636 if (s_parsed || c_parsed || h_parsed) 637 return -EINVAL; 638 s_parsed = 1; 639 next++; 640 break; 641 case 'c': 642 case 'C': 643 if (c_parsed || h_parsed) 644 return -EINVAL; 645 c_parsed = 1; 646 next++; 647 break; 648 case 'h': 649 case 'H': 650 if (h_parsed) 651 return -EINVAL; 652 h_parsed = 1; 653 next++; 654 break; 655 default: 656 /* If it start from digit it must be only core id. */ 657 if (!isdigit(*next) || s_parsed || c_parsed || h_parsed) 658 return -EINVAL; 659 660 type = 'C'; 661 } 662 663 for (num_len = 0; *next != '\0'; next++, num_len++) { 664 if (num_len == RTE_DIM(num)) 665 return -EINVAL; 666 667 if (!isdigit(*next)) 668 break; 669 670 num[num_len] = *next; 671 } 672 673 if (num_len == 0 && type != 'h' && type != 'H') 674 return -EINVAL; 675 676 if (num_len != 0 && (type == 'h' || type == 'H')) 677 return -EINVAL; 678 679 num[num_len] = '\0'; 680 val = strtol(num, NULL, 10); 681 682 h = 0; 683 switch (type) { 684 case 's': 685 case 'S': 686 s = val; 687 break; 688 case 'c': 689 case 'C': 690 c = val; 691 break; 692 case 'h': 693 case 'H': 694 h = 1; 695 break; 696 } 697 } 698 699 p->socket_id = s; 700 p->core_id = c; 701 p->thread_id = h; 702 return 0; 703 } 704