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