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