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