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