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 #include <stdint.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <ctype.h> 11 #include <getopt.h> 12 #include <errno.h> 13 #include <stdarg.h> 14 #include <string.h> 15 #include <libgen.h> 16 #include <unistd.h> 17 #include <sys/wait.h> 18 #include <arpa/inet.h> 19 #include <sys/socket.h> 20 21 #include <rte_errno.h> 22 #include <rte_string_fns.h> 23 24 #include "parser.h" 25 26 static uint32_t 27 get_hex_val(char c) 28 { 29 switch (c) { 30 case '0': case '1': case '2': case '3': case '4': case '5': 31 case '6': case '7': case '8': case '9': 32 return c - '0'; 33 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 34 return c - 'A' + 10; 35 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 36 return c - 'a' + 10; 37 default: 38 return 0; 39 } 40 } 41 42 int 43 parser_read_arg_bool(const char *p) 44 { 45 p = rte_str_skip_leading_spaces(p); 46 int result = -EINVAL; 47 48 if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) || 49 ((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) { 50 p += 3; 51 result = 1; 52 } 53 54 if (((p[0] == 'o') && (p[1] == 'n')) || 55 ((p[0] == 'O') && (p[1] == 'N'))) { 56 p += 2; 57 result = 1; 58 } 59 60 if (((p[0] == 'n') && (p[1] == 'o')) || 61 ((p[0] == 'N') && (p[1] == 'O'))) { 62 p += 2; 63 result = 0; 64 } 65 66 if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) || 67 ((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) { 68 p += 3; 69 result = 0; 70 } 71 72 p = rte_str_skip_leading_spaces(p); 73 74 if (p[0] != '\0') 75 return -EINVAL; 76 77 return result; 78 } 79 80 int 81 parser_read_uint64(uint64_t *value, const char *p) 82 { 83 char *next; 84 uint64_t val; 85 86 p = rte_str_skip_leading_spaces(p); 87 if (!isdigit(*p)) 88 return -EINVAL; 89 90 val = strtoul(p, &next, 10); 91 if (p == next) 92 return -EINVAL; 93 94 p = next; 95 switch (*p) { 96 case 'T': 97 val *= 1024ULL; 98 /* fall through */ 99 case 'G': 100 val *= 1024ULL; 101 /* fall through */ 102 case 'M': 103 val *= 1024ULL; 104 /* fall through */ 105 case 'k': 106 case 'K': 107 val *= 1024ULL; 108 p++; 109 break; 110 } 111 112 p = rte_str_skip_leading_spaces(p); 113 if (*p != '\0') 114 return -EINVAL; 115 116 *value = val; 117 return 0; 118 } 119 120 int 121 parser_read_uint64_hex(uint64_t *value, const char *p) 122 { 123 char *next; 124 uint64_t val; 125 126 p = rte_str_skip_leading_spaces(p); 127 128 val = strtoul(p, &next, 16); 129 if (p == next) 130 return -EINVAL; 131 132 p = rte_str_skip_leading_spaces(next); 133 if (*p != '\0') 134 return -EINVAL; 135 136 *value = val; 137 return 0; 138 } 139 140 int 141 parser_read_uint32(uint32_t *value, const char *p) 142 { 143 uint64_t val = 0; 144 int ret = parser_read_uint64(&val, p); 145 146 if (ret < 0) 147 return ret; 148 149 if (val > UINT32_MAX) 150 return -ERANGE; 151 152 *value = val; 153 return 0; 154 } 155 156 int 157 parser_read_uint32_hex(uint32_t *value, const char *p) 158 { 159 uint64_t val = 0; 160 int ret = parser_read_uint64_hex(&val, p); 161 162 if (ret < 0) 163 return ret; 164 165 if (val > UINT32_MAX) 166 return -ERANGE; 167 168 *value = val; 169 return 0; 170 } 171 172 int 173 parser_read_uint16(uint16_t *value, const char *p) 174 { 175 uint64_t val = 0; 176 int ret = parser_read_uint64(&val, p); 177 178 if (ret < 0) 179 return ret; 180 181 if (val > UINT16_MAX) 182 return -ERANGE; 183 184 *value = val; 185 return 0; 186 } 187 188 int 189 parser_read_uint16_hex(uint16_t *value, const char *p) 190 { 191 uint64_t val = 0; 192 int ret = parser_read_uint64_hex(&val, p); 193 194 if (ret < 0) 195 return ret; 196 197 if (val > UINT16_MAX) 198 return -ERANGE; 199 200 *value = val; 201 return 0; 202 } 203 204 int 205 parser_read_uint8(uint8_t *value, const char *p) 206 { 207 uint64_t val = 0; 208 int ret = parser_read_uint64(&val, p); 209 210 if (ret < 0) 211 return ret; 212 213 if (val > UINT8_MAX) 214 return -ERANGE; 215 216 *value = val; 217 return 0; 218 } 219 220 int 221 parser_read_uint8_hex(uint8_t *value, const char *p) 222 { 223 uint64_t val = 0; 224 int ret = parser_read_uint64_hex(&val, p); 225 226 if (ret < 0) 227 return ret; 228 229 if (val > UINT8_MAX) 230 return -ERANGE; 231 232 *value = val; 233 return 0; 234 } 235 236 int 237 parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens) 238 { 239 uint32_t i; 240 241 if ((string == NULL) || 242 (tokens == NULL) || 243 (*n_tokens < 1)) 244 return -EINVAL; 245 246 for (i = 0; i < *n_tokens; i++) { 247 tokens[i] = strtok_r(string, PARSE_DELIMITER, &string); 248 if (tokens[i] == NULL) 249 break; 250 } 251 252 if ((i == *n_tokens) && 253 (NULL != strtok_r(string, PARSE_DELIMITER, &string))) 254 return -E2BIG; 255 256 *n_tokens = i; 257 return 0; 258 } 259 260 int 261 parse_hex_string(char *src, uint8_t *dst, uint32_t *size) 262 { 263 char *c; 264 uint32_t len, i; 265 266 /* Check input parameters */ 267 if ((src == NULL) || 268 (dst == NULL) || 269 (size == NULL) || 270 (*size == 0)) 271 return -1; 272 273 len = strlen(src); 274 if (((len & 3) != 0) || 275 (len > (*size) * 2)) 276 return -1; 277 *size = len / 2; 278 279 for (c = src; *c != 0; c++) { 280 if ((((*c) >= '0') && ((*c) <= '9')) || 281 (((*c) >= 'A') && ((*c) <= 'F')) || 282 (((*c) >= 'a') && ((*c) <= 'f'))) 283 continue; 284 285 return -1; 286 } 287 288 /* Convert chars to bytes */ 289 for (i = 0; i < *size; i++) 290 dst[i] = get_hex_val(src[2 * i]) * 16 + 291 get_hex_val(src[2 * i + 1]); 292 293 return 0; 294 } 295 296 int 297 parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels) 298 { 299 uint32_t n_max_labels = *n_labels, count = 0; 300 301 /* Check for void list of labels */ 302 if (strcmp(string, "<void>") == 0) { 303 *n_labels = 0; 304 return 0; 305 } 306 307 /* At least one label should be present */ 308 for ( ; (*string != '\0'); ) { 309 char *next; 310 int value; 311 312 if (count >= n_max_labels) 313 return -1; 314 315 if (count > 0) { 316 if (string[0] != ':') 317 return -1; 318 319 string++; 320 } 321 322 value = strtol(string, &next, 10); 323 if (next == string) 324 return -1; 325 string = next; 326 327 labels[count++] = (uint32_t) value; 328 } 329 330 *n_labels = count; 331 return 0; 332 } 333 334 static struct rte_ether_addr * 335 my_ether_aton(const char *a) 336 { 337 int i; 338 char *end; 339 unsigned long o[RTE_ETHER_ADDR_LEN]; 340 static struct rte_ether_addr ether_addr; 341 342 i = 0; 343 do { 344 errno = 0; 345 o[i] = strtoul(a, &end, 16); 346 if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0)) 347 return NULL; 348 a = end + 1; 349 } while (++i != RTE_DIM(o) && end[0] != 0); 350 351 /* Junk at the end of line */ 352 if (end[0] != 0) 353 return NULL; 354 355 /* Support the format XX:XX:XX:XX:XX:XX */ 356 if (i == RTE_ETHER_ADDR_LEN) { 357 while (i-- != 0) { 358 if (o[i] > UINT8_MAX) 359 return NULL; 360 ether_addr.addr_bytes[i] = (uint8_t)o[i]; 361 } 362 /* Support the format XXXX:XXXX:XXXX */ 363 } else if (i == RTE_ETHER_ADDR_LEN / 2) { 364 while (i-- != 0) { 365 if (o[i] > UINT16_MAX) 366 return NULL; 367 ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8); 368 ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff); 369 } 370 /* unknown format */ 371 } else 372 return NULL; 373 374 return (struct rte_ether_addr *)ðer_addr; 375 } 376 377 int 378 parse_ipv4_addr(const char *token, struct in_addr *ipv4) 379 { 380 if (strlen(token) >= INET_ADDRSTRLEN) 381 return -EINVAL; 382 383 if (inet_pton(AF_INET, token, ipv4) != 1) 384 return -EINVAL; 385 386 return 0; 387 } 388 389 int 390 parse_ipv6_addr(const char *token, struct rte_ipv6_addr *ipv6) 391 { 392 if (strlen(token) >= INET6_ADDRSTRLEN) 393 return -EINVAL; 394 395 if (inet_pton(AF_INET6, token, ipv6) != 1) 396 return -EINVAL; 397 398 return 0; 399 } 400 401 int 402 parse_mac_addr(const char *token, struct rte_ether_addr *addr) 403 { 404 struct rte_ether_addr *tmp; 405 406 tmp = my_ether_aton(token); 407 if (tmp == NULL) 408 return -1; 409 410 memcpy(addr, tmp, sizeof(struct rte_ether_addr)); 411 return 0; 412 } 413 414 int 415 parse_cpu_core(const char *entry, 416 struct cpu_core_params *p) 417 { 418 size_t num_len; 419 char num[8]; 420 421 uint32_t s = 0, c = 0, h = 0, val; 422 uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0; 423 const char *next = rte_str_skip_leading_spaces(entry); 424 char type; 425 426 if (p == NULL) 427 return -EINVAL; 428 429 /* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */ 430 while (*next != '\0') { 431 /* If everything parsed nothing should left */ 432 if (s_parsed && c_parsed && h_parsed) 433 return -EINVAL; 434 435 type = *next; 436 switch (type) { 437 case 's': 438 case 'S': 439 if (s_parsed || c_parsed || h_parsed) 440 return -EINVAL; 441 s_parsed = 1; 442 next++; 443 break; 444 case 'c': 445 case 'C': 446 if (c_parsed || h_parsed) 447 return -EINVAL; 448 c_parsed = 1; 449 next++; 450 break; 451 case 'h': 452 case 'H': 453 if (h_parsed) 454 return -EINVAL; 455 h_parsed = 1; 456 next++; 457 break; 458 default: 459 /* If it start from digit it must be only core id. */ 460 if (!isdigit(*next) || s_parsed || c_parsed || h_parsed) 461 return -EINVAL; 462 463 type = 'C'; 464 } 465 466 for (num_len = 0; *next != '\0'; next++, num_len++) { 467 if (num_len == RTE_DIM(num)) 468 return -EINVAL; 469 470 if (!isdigit(*next)) 471 break; 472 473 num[num_len] = *next; 474 } 475 476 if (num_len == 0 && type != 'h' && type != 'H') 477 return -EINVAL; 478 479 if (num_len != 0 && (type == 'h' || type == 'H')) 480 return -EINVAL; 481 482 num[num_len] = '\0'; 483 val = strtol(num, NULL, 10); 484 485 h = 0; 486 switch (type) { 487 case 's': 488 case 'S': 489 s = val; 490 break; 491 case 'c': 492 case 'C': 493 c = val; 494 break; 495 case 'h': 496 case 'H': 497 h = 1; 498 break; 499 } 500 } 501 502 p->socket_id = s; 503 p->core_id = c; 504 p->thread_id = h; 505 return 0; 506 } 507