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