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