xref: /dpdk/examples/ip_pipeline/parser.c (revision f399b0171e6e64c8bbce42599afa35591a9d28f1)
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 /*
8  * For inet_pton4() and inet_pton6() functions:
9  *
10  * Copyright (c) 1996 by Internet Software Consortium.
11  *
12  * Permission to use, copy, modify, and distribute this software for any
13  * purpose with or without fee is hereby granted, provided that the above
14  * copyright notice and this permission notice appear in all copies.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
17  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
19  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
21  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
22  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23  * SOFTWARE.
24  */
25 
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <getopt.h>
31 #include <errno.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <libgen.h>
35 #include <unistd.h>
36 #include <sys/wait.h>
37 
38 #include <rte_errno.h>
39 #include <rte_string_fns.h>
40 
41 #include "parser.h"
42 
43 static uint32_t
44 get_hex_val(char c)
45 {
46 	switch (c) {
47 	case '0': case '1': case '2': case '3': case '4': case '5':
48 	case '6': case '7': case '8': case '9':
49 		return c - '0';
50 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
51 		return c - 'A' + 10;
52 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
53 		return c - 'a' + 10;
54 	default:
55 		return 0;
56 	}
57 }
58 
59 int
60 parser_read_arg_bool(const char *p)
61 {
62 	p = skip_white_spaces(p);
63 	int result = -EINVAL;
64 
65 	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
66 		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
67 		p += 3;
68 		result = 1;
69 	}
70 
71 	if (((p[0] == 'o') && (p[1] == 'n')) ||
72 		((p[0] == 'O') && (p[1] == 'N'))) {
73 		p += 2;
74 		result = 1;
75 	}
76 
77 	if (((p[0] == 'n') && (p[1] == 'o')) ||
78 		((p[0] == 'N') && (p[1] == 'O'))) {
79 		p += 2;
80 		result = 0;
81 	}
82 
83 	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
84 		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
85 		p += 3;
86 		result = 0;
87 	}
88 
89 	p = skip_white_spaces(p);
90 
91 	if (p[0] != '\0')
92 		return -EINVAL;
93 
94 	return result;
95 }
96 
97 int
98 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 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 parser_read_uint32(uint32_t *value, const char *p)
159 {
160 	uint64_t val = 0;
161 	int ret = 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 parser_read_uint32_hex(uint32_t *value, const char *p)
175 {
176 	uint64_t val = 0;
177 	int ret = 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 parser_read_uint16(uint16_t *value, const char *p)
191 {
192 	uint64_t val = 0;
193 	int ret = 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 parser_read_uint16_hex(uint16_t *value, const char *p)
207 {
208 	uint64_t val = 0;
209 	int ret = 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 parser_read_uint8(uint8_t *value, const char *p)
223 {
224 	uint64_t val = 0;
225 	int ret = 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 parser_read_uint8_hex(uint8_t *value, const char *p)
239 {
240 	uint64_t val = 0;
241 	int ret = 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 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 		(NULL != strtok_r(string, PARSE_DELIMITER, &string)))
271 		return -E2BIG;
272 
273 	*n_tokens = i;
274 	return 0;
275 }
276 
277 int
278 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 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 #define INADDRSZ 4
352 #define IN6ADDRSZ 16
353 
354 /* int
355  * inet_pton4(src, dst)
356  *      like inet_aton() but without all the hexadecimal and shorthand.
357  * return:
358  *      1 if `src' is a valid dotted quad, else 0.
359  * notice:
360  *      does not touch `dst' unless it's returning 1.
361  * author:
362  *      Paul Vixie, 1996.
363  */
364 static int
365 inet_pton4(const char *src, unsigned char *dst)
366 {
367 	static const char digits[] = "0123456789";
368 	int saw_digit, octets, ch;
369 	unsigned char tmp[INADDRSZ], *tp;
370 
371 	saw_digit = 0;
372 	octets = 0;
373 	*(tp = tmp) = 0;
374 	while ((ch = *src++) != '\0') {
375 		const char *pch;
376 
377 		pch = strchr(digits, ch);
378 		if (pch != NULL) {
379 			unsigned int new = *tp * 10 + (pch - digits);
380 
381 			if (new > 255)
382 				return 0;
383 			if (!saw_digit) {
384 				if (++octets > 4)
385 					return 0;
386 				saw_digit = 1;
387 			}
388 			*tp = (unsigned char)new;
389 		} else if (ch == '.' && saw_digit) {
390 			if (octets == 4)
391 				return 0;
392 			*++tp = 0;
393 			saw_digit = 0;
394 		} else
395 			return 0;
396 	}
397 	if (octets < 4)
398 		return 0;
399 
400 	memcpy(dst, tmp, INADDRSZ);
401 	return 1;
402 }
403 
404 /* int
405  * inet_pton6(src, dst)
406  *      convert presentation level address to network order binary form.
407  * return:
408  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
409  * notice:
410  *      (1) does not touch `dst' unless it's returning 1.
411  *      (2) :: in a full address is silently ignored.
412  * credit:
413  *      inspired by Mark Andrews.
414  * author:
415  *      Paul Vixie, 1996.
416  */
417 static int
418 inet_pton6(const char *src, unsigned char *dst)
419 {
420 	static const char xdigits_l[] = "0123456789abcdef",
421 		xdigits_u[] = "0123456789ABCDEF";
422 	unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
423 	const char *xdigits = 0, *curtok = 0;
424 	int ch = 0, saw_xdigit = 0, count_xdigit = 0;
425 	unsigned int val = 0;
426 	unsigned dbloct_count = 0;
427 
428 	memset((tp = tmp), '\0', IN6ADDRSZ);
429 	endp = tp + IN6ADDRSZ;
430 	colonp = NULL;
431 	/* Leading :: requires some special handling. */
432 	if (*src == ':')
433 		if (*++src != ':')
434 			return 0;
435 	curtok = src;
436 	saw_xdigit = count_xdigit = 0;
437 	val = 0;
438 
439 	while ((ch = *src++) != '\0') {
440 		const char *pch;
441 
442 		pch = strchr((xdigits = xdigits_l), ch);
443 		if (pch == NULL)
444 			pch = strchr((xdigits = xdigits_u), ch);
445 		if (pch != NULL) {
446 			if (count_xdigit >= 4)
447 				return 0;
448 			val <<= 4;
449 			val |= (pch - xdigits);
450 			if (val > 0xffff)
451 				return 0;
452 			saw_xdigit = 1;
453 			count_xdigit++;
454 			continue;
455 		}
456 		if (ch == ':') {
457 			curtok = src;
458 			if (!saw_xdigit) {
459 				if (colonp)
460 					return 0;
461 				colonp = tp;
462 				continue;
463 			} else if (*src == '\0') {
464 				return 0;
465 			}
466 			if (tp + sizeof(int16_t) > endp)
467 				return 0;
468 			*tp++ = (unsigned char) ((val >> 8) & 0xff);
469 			*tp++ = (unsigned char) (val & 0xff);
470 			saw_xdigit = 0;
471 			count_xdigit = 0;
472 			val = 0;
473 			dbloct_count++;
474 			continue;
475 		}
476 		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
477 		    inet_pton4(curtok, tp) > 0) {
478 			tp += INADDRSZ;
479 			saw_xdigit = 0;
480 			dbloct_count += 2;
481 			break;  /* '\0' was seen by inet_pton4(). */
482 		}
483 		return 0;
484 	}
485 	if (saw_xdigit) {
486 		if (tp + sizeof(int16_t) > endp)
487 			return 0;
488 		*tp++ = (unsigned char) ((val >> 8) & 0xff);
489 		*tp++ = (unsigned char) (val & 0xff);
490 		dbloct_count++;
491 	}
492 	if (colonp != NULL) {
493 		/* if we already have 8 double octets, having a colon means error */
494 		if (dbloct_count == 8)
495 			return 0;
496 
497 		/*
498 		 * Since some memmove()'s erroneously fail to handle
499 		 * overlapping regions, we'll do the shift by hand.
500 		 */
501 		const int n = tp - colonp;
502 		int i;
503 
504 		for (i = 1; i <= n; i++) {
505 			endp[-i] = colonp[n - i];
506 			colonp[n - i] = 0;
507 		}
508 		tp = endp;
509 	}
510 	if (tp != endp)
511 		return 0;
512 	memcpy(dst, tmp, IN6ADDRSZ);
513 	return 1;
514 }
515 
516 static struct rte_ether_addr *
517 my_ether_aton(const char *a)
518 {
519 	int i;
520 	char *end;
521 	unsigned long o[RTE_ETHER_ADDR_LEN];
522 	static struct rte_ether_addr ether_addr;
523 
524 	i = 0;
525 	do {
526 		errno = 0;
527 		o[i] = strtoul(a, &end, 16);
528 		if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
529 			return NULL;
530 		a = end + 1;
531 	} while (++i != RTE_DIM(o) && end[0] != 0);
532 
533 	/* Junk at the end of line */
534 	if (end[0] != 0)
535 		return NULL;
536 
537 	/* Support the format XX:XX:XX:XX:XX:XX */
538 	if (i == RTE_ETHER_ADDR_LEN) {
539 		while (i-- != 0) {
540 			if (o[i] > UINT8_MAX)
541 				return NULL;
542 			ether_addr.addr_bytes[i] = (uint8_t)o[i];
543 		}
544 	/* Support the format XXXX:XXXX:XXXX */
545 	} else if (i == RTE_ETHER_ADDR_LEN / 2) {
546 		while (i-- != 0) {
547 			if (o[i] > UINT16_MAX)
548 				return NULL;
549 			ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8);
550 			ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff);
551 		}
552 	/* unknown format */
553 	} else
554 		return NULL;
555 
556 	return (struct rte_ether_addr *)&ether_addr;
557 }
558 
559 int
560 parse_ipv4_addr(const char *token, struct in_addr *ipv4)
561 {
562 	if (strlen(token) >= INET_ADDRSTRLEN)
563 		return -EINVAL;
564 
565 	if (inet_pton4(token, (unsigned char *)ipv4) != 1)
566 		return -EINVAL;
567 
568 	return 0;
569 }
570 
571 int
572 parse_ipv6_addr(const char *token, struct in6_addr *ipv6)
573 {
574 	if (strlen(token) >= INET6_ADDRSTRLEN)
575 		return -EINVAL;
576 
577 	if (inet_pton6(token, (unsigned char *)ipv6) != 1)
578 		return -EINVAL;
579 
580 	return 0;
581 }
582 
583 int
584 parse_mac_addr(const char *token, struct rte_ether_addr *addr)
585 {
586 	struct rte_ether_addr *tmp;
587 
588 	tmp = my_ether_aton(token);
589 	if (tmp == NULL)
590 		return -1;
591 
592 	memcpy(addr, tmp, sizeof(struct rte_ether_addr));
593 	return 0;
594 }
595 
596 int
597 parse_cpu_core(const char *entry,
598 	struct cpu_core_params *p)
599 {
600 	size_t num_len;
601 	char num[8];
602 
603 	uint32_t s = 0, c = 0, h = 0, val;
604 	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
605 	const char *next = skip_white_spaces(entry);
606 	char type;
607 
608 	if (p == NULL)
609 		return -EINVAL;
610 
611 	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
612 	while (*next != '\0') {
613 		/* If everything parsed nothing should left */
614 		if (s_parsed && c_parsed && h_parsed)
615 			return -EINVAL;
616 
617 		type = *next;
618 		switch (type) {
619 		case 's':
620 		case 'S':
621 			if (s_parsed || c_parsed || h_parsed)
622 				return -EINVAL;
623 			s_parsed = 1;
624 			next++;
625 			break;
626 		case 'c':
627 		case 'C':
628 			if (c_parsed || h_parsed)
629 				return -EINVAL;
630 			c_parsed = 1;
631 			next++;
632 			break;
633 		case 'h':
634 		case 'H':
635 			if (h_parsed)
636 				return -EINVAL;
637 			h_parsed = 1;
638 			next++;
639 			break;
640 		default:
641 			/* If it start from digit it must be only core id. */
642 			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
643 				return -EINVAL;
644 
645 			type = 'C';
646 		}
647 
648 		for (num_len = 0; *next != '\0'; next++, num_len++) {
649 			if (num_len == RTE_DIM(num))
650 				return -EINVAL;
651 
652 			if (!isdigit(*next))
653 				break;
654 
655 			num[num_len] = *next;
656 		}
657 
658 		if (num_len == 0 && type != 'h' && type != 'H')
659 			return -EINVAL;
660 
661 		if (num_len != 0 && (type == 'h' || type == 'H'))
662 			return -EINVAL;
663 
664 		num[num_len] = '\0';
665 		val = strtol(num, NULL, 10);
666 
667 		h = 0;
668 		switch (type) {
669 		case 's':
670 		case 'S':
671 			s = val;
672 			break;
673 		case 'c':
674 		case 'C':
675 			c = val;
676 			break;
677 		case 'h':
678 		case 'H':
679 			h = 1;
680 			break;
681 		}
682 	}
683 
684 	p->socket_id = s;
685 	p->core_id = c;
686 	p->thread_id = h;
687 	return 0;
688 }
689