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