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 #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 23 #include "parser.h" 24 25 static uint32_t 26 get_hex_val(char c) 27 { 28 switch (c) { 29 case '0': case '1': case '2': case '3': case '4': case '5': 30 case '6': case '7': case '8': case '9': 31 return c - '0'; 32 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 33 return c - 'A' + 10; 34 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 35 return c - 'a' + 10; 36 default: 37 return 0; 38 } 39 } 40 41 int 42 softnic_parser_read_arg_bool(const char *p) 43 { 44 p = skip_white_spaces(p); 45 int result = -EINVAL; 46 47 if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) || 48 ((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) { 49 p += 3; 50 result = 1; 51 } 52 53 if (((p[0] == 'o') && (p[1] == 'n')) || 54 ((p[0] == 'O') && (p[1] == 'N'))) { 55 p += 2; 56 result = 1; 57 } 58 59 if (((p[0] == 'n') && (p[1] == 'o')) || 60 ((p[0] == 'N') && (p[1] == 'O'))) { 61 p += 2; 62 result = 0; 63 } 64 65 if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) || 66 ((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) { 67 p += 3; 68 result = 0; 69 } 70 71 p = skip_white_spaces(p); 72 73 if (p[0] != '\0') 74 return -EINVAL; 75 76 return result; 77 } 78 79 int 80 softnic_parser_read_int32(int32_t *value, const char *p) 81 { 82 char *next; 83 int32_t val; 84 85 p = skip_white_spaces(p); 86 if (!isdigit(*p)) 87 return -EINVAL; 88 89 val = strtol(p, &next, 10); 90 if (p == next) 91 return -EINVAL; 92 93 *value = val; 94 return 0; 95 } 96 97 int 98 softnic_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 softnic_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 softnic_parser_read_uint32(uint32_t *value, const char *p) 159 { 160 uint64_t val = 0; 161 int ret = softnic_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 softnic_parser_read_uint32_hex(uint32_t *value, const char *p) 175 { 176 uint64_t val = 0; 177 int ret = softnic_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 softnic_parser_read_uint16(uint16_t *value, const char *p) 191 { 192 uint64_t val = 0; 193 int ret = softnic_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 softnic_parser_read_uint16_hex(uint16_t *value, const char *p) 207 { 208 uint64_t val = 0; 209 int ret = softnic_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 softnic_parser_read_uint8(uint8_t *value, const char *p) 223 { 224 uint64_t val = 0; 225 int ret = softnic_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 softnic_parser_read_uint8_hex(uint8_t *value, const char *p) 239 { 240 uint64_t val = 0; 241 int ret = softnic_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 softnic_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 strtok_r(string, PARSE_DELIMITER, &string) != NULL) 271 return -E2BIG; 272 273 *n_tokens = i; 274 return 0; 275 } 276 277 int 278 softnic_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 softnic_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 static struct rte_ether_addr * 352 my_ether_aton(const char *a) 353 { 354 int i; 355 char *end; 356 unsigned long o[RTE_ETHER_ADDR_LEN]; 357 static struct rte_ether_addr ether_addr; 358 359 i = 0; 360 do { 361 errno = 0; 362 o[i] = strtoul(a, &end, 16); 363 if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0)) 364 return NULL; 365 a = end + 1; 366 } while (++i != sizeof(o) / sizeof(o[0]) && end[0] != 0); 367 368 /* Junk at the end of line */ 369 if (end[0] != 0) 370 return NULL; 371 372 /* Support the format XX:XX:XX:XX:XX:XX */ 373 if (i == RTE_ETHER_ADDR_LEN) { 374 while (i-- != 0) { 375 if (o[i] > UINT8_MAX) 376 return NULL; 377 ether_addr.addr_bytes[i] = (uint8_t)o[i]; 378 } 379 /* Support the format XXXX:XXXX:XXXX */ 380 } else if (i == RTE_ETHER_ADDR_LEN / 2) { 381 while (i-- != 0) { 382 if (o[i] > UINT16_MAX) 383 return NULL; 384 ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8); 385 ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff); 386 } 387 /* unknown format */ 388 } else 389 return NULL; 390 391 return (struct rte_ether_addr *)ðer_addr; 392 } 393 394 int 395 softnic_parse_ipv4_addr(const char *token, struct in_addr *ipv4) 396 { 397 if (strlen(token) >= INET_ADDRSTRLEN) 398 return -EINVAL; 399 400 if (inet_pton(AF_INET, token, ipv4) != 1) 401 return -EINVAL; 402 403 return 0; 404 } 405 406 int 407 softnic_parse_ipv6_addr(const char *token, struct in6_addr *ipv6) 408 { 409 if (strlen(token) >= INET6_ADDRSTRLEN) 410 return -EINVAL; 411 412 if (inet_pton(AF_INET6, token, ipv6) != 1) 413 return -EINVAL; 414 415 return 0; 416 } 417 418 int 419 softnic_parse_mac_addr(const char *token, struct rte_ether_addr *addr) 420 { 421 struct rte_ether_addr *tmp; 422 423 tmp = my_ether_aton(token); 424 if (tmp == NULL) 425 return -1; 426 427 memcpy(addr, tmp, sizeof(struct rte_ether_addr)); 428 return 0; 429 } 430 431 int 432 softnic_parse_cpu_core(const char *entry, 433 struct softnic_cpu_core_params *p) 434 { 435 size_t num_len; 436 char num[8]; 437 438 uint32_t s = 0, c = 0, h = 0, val; 439 uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0; 440 const char *next = skip_white_spaces(entry); 441 char type; 442 443 if (p == NULL) 444 return -EINVAL; 445 446 /* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */ 447 while (*next != '\0') { 448 /* If everything parsed nothing should left */ 449 if (s_parsed && c_parsed && h_parsed) 450 return -EINVAL; 451 452 type = *next; 453 switch (type) { 454 case 's': 455 case 'S': 456 if (s_parsed || c_parsed || h_parsed) 457 return -EINVAL; 458 s_parsed = 1; 459 next++; 460 break; 461 case 'c': 462 case 'C': 463 if (c_parsed || h_parsed) 464 return -EINVAL; 465 c_parsed = 1; 466 next++; 467 break; 468 case 'h': 469 case 'H': 470 if (h_parsed) 471 return -EINVAL; 472 h_parsed = 1; 473 next++; 474 break; 475 default: 476 /* If it start from digit it must be only core id. */ 477 if (!isdigit(*next) || s_parsed || c_parsed || h_parsed) 478 return -EINVAL; 479 480 type = 'C'; 481 } 482 483 for (num_len = 0; *next != '\0'; next++, num_len++) { 484 if (num_len == RTE_DIM(num)) 485 return -EINVAL; 486 487 if (!isdigit(*next)) 488 break; 489 490 num[num_len] = *next; 491 } 492 493 if (num_len == 0 && type != 'h' && type != 'H') 494 return -EINVAL; 495 496 if (num_len != 0 && (type == 'h' || type == 'H')) 497 return -EINVAL; 498 499 num[num_len] = '\0'; 500 val = strtol(num, NULL, 10); 501 502 h = 0; 503 switch (type) { 504 case 's': 505 case 'S': 506 s = val; 507 break; 508 case 'c': 509 case 'C': 510 c = val; 511 break; 512 case 'h': 513 case 'H': 514 h = 1; 515 break; 516 } 517 } 518 519 p->socket_id = s; 520 p->core_id = c; 521 p->thread_id = h; 522 return 0; 523 } 524