parser.c revision 809f0800
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
101static uint32_t
102get_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
117int
118parser_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
155int
156parser_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
195int
196parser_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
215int
216parser_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
231int
232parser_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
247int
248parser_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
263int
264parser_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
279int
280parser_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
295int
296parser_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
311int
312parse_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
335int
336parse_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
371int
372parse_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 */
422static int
423inet_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 */
475static int
476inet_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
574static struct ether_addr *
575my_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
617int
618parse_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
629int
630parse_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
641int
642parse_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
654int
655parse_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