xref: /dpdk/examples/ip_pipeline/parser.c (revision 5ac1abdd37aa43692603cd8670111c354014766f)
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 #include <stdint.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <getopt.h>
12 #include <errno.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #include <libgen.h>
16 #include <unistd.h>
17 #include <sys/wait.h>
18 #include <arpa/inet.h>
19 #include <sys/socket.h>
20 
21 #include <rte_errno.h>
22 #include <rte_string_fns.h>
23 
24 #include "parser.h"
25 
26 static uint32_t
27 get_hex_val(char c)
28 {
29 	switch (c) {
30 	case '0': case '1': case '2': case '3': case '4': case '5':
31 	case '6': case '7': case '8': case '9':
32 		return c - '0';
33 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
34 		return c - 'A' + 10;
35 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
36 		return c - 'a' + 10;
37 	default:
38 		return 0;
39 	}
40 }
41 
42 int
43 parser_read_arg_bool(const char *p)
44 {
45 	p = rte_str_skip_leading_spaces(p);
46 	int result = -EINVAL;
47 
48 	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
49 		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
50 		p += 3;
51 		result = 1;
52 	}
53 
54 	if (((p[0] == 'o') && (p[1] == 'n')) ||
55 		((p[0] == 'O') && (p[1] == 'N'))) {
56 		p += 2;
57 		result = 1;
58 	}
59 
60 	if (((p[0] == 'n') && (p[1] == 'o')) ||
61 		((p[0] == 'N') && (p[1] == 'O'))) {
62 		p += 2;
63 		result = 0;
64 	}
65 
66 	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
67 		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
68 		p += 3;
69 		result = 0;
70 	}
71 
72 	p = rte_str_skip_leading_spaces(p);
73 
74 	if (p[0] != '\0')
75 		return -EINVAL;
76 
77 	return result;
78 }
79 
80 int
81 parser_read_uint64(uint64_t *value, const char *p)
82 {
83 	char *next;
84 	uint64_t val;
85 
86 	p = rte_str_skip_leading_spaces(p);
87 	if (!isdigit(*p))
88 		return -EINVAL;
89 
90 	val = strtoul(p, &next, 10);
91 	if (p == next)
92 		return -EINVAL;
93 
94 	p = next;
95 	switch (*p) {
96 	case 'T':
97 		val *= 1024ULL;
98 		/* fall through */
99 	case 'G':
100 		val *= 1024ULL;
101 		/* fall through */
102 	case 'M':
103 		val *= 1024ULL;
104 		/* fall through */
105 	case 'k':
106 	case 'K':
107 		val *= 1024ULL;
108 		p++;
109 		break;
110 	}
111 
112 	p = rte_str_skip_leading_spaces(p);
113 	if (*p != '\0')
114 		return -EINVAL;
115 
116 	*value = val;
117 	return 0;
118 }
119 
120 int
121 parser_read_uint64_hex(uint64_t *value, const char *p)
122 {
123 	char *next;
124 	uint64_t val;
125 
126 	p = rte_str_skip_leading_spaces(p);
127 
128 	val = strtoul(p, &next, 16);
129 	if (p == next)
130 		return -EINVAL;
131 
132 	p = rte_str_skip_leading_spaces(next);
133 	if (*p != '\0')
134 		return -EINVAL;
135 
136 	*value = val;
137 	return 0;
138 }
139 
140 int
141 parser_read_uint32(uint32_t *value, const char *p)
142 {
143 	uint64_t val = 0;
144 	int ret = parser_read_uint64(&val, p);
145 
146 	if (ret < 0)
147 		return ret;
148 
149 	if (val > UINT32_MAX)
150 		return -ERANGE;
151 
152 	*value = val;
153 	return 0;
154 }
155 
156 int
157 parser_read_uint32_hex(uint32_t *value, const char *p)
158 {
159 	uint64_t val = 0;
160 	int ret = parser_read_uint64_hex(&val, p);
161 
162 	if (ret < 0)
163 		return ret;
164 
165 	if (val > UINT32_MAX)
166 		return -ERANGE;
167 
168 	*value = val;
169 	return 0;
170 }
171 
172 int
173 parser_read_uint16(uint16_t *value, const char *p)
174 {
175 	uint64_t val = 0;
176 	int ret = parser_read_uint64(&val, p);
177 
178 	if (ret < 0)
179 		return ret;
180 
181 	if (val > UINT16_MAX)
182 		return -ERANGE;
183 
184 	*value = val;
185 	return 0;
186 }
187 
188 int
189 parser_read_uint16_hex(uint16_t *value, const char *p)
190 {
191 	uint64_t val = 0;
192 	int ret = parser_read_uint64_hex(&val, p);
193 
194 	if (ret < 0)
195 		return ret;
196 
197 	if (val > UINT16_MAX)
198 		return -ERANGE;
199 
200 	*value = val;
201 	return 0;
202 }
203 
204 int
205 parser_read_uint8(uint8_t *value, const char *p)
206 {
207 	uint64_t val = 0;
208 	int ret = parser_read_uint64(&val, p);
209 
210 	if (ret < 0)
211 		return ret;
212 
213 	if (val > UINT8_MAX)
214 		return -ERANGE;
215 
216 	*value = val;
217 	return 0;
218 }
219 
220 int
221 parser_read_uint8_hex(uint8_t *value, const char *p)
222 {
223 	uint64_t val = 0;
224 	int ret = parser_read_uint64_hex(&val, p);
225 
226 	if (ret < 0)
227 		return ret;
228 
229 	if (val > UINT8_MAX)
230 		return -ERANGE;
231 
232 	*value = val;
233 	return 0;
234 }
235 
236 int
237 parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
238 {
239 	uint32_t i;
240 
241 	if ((string == NULL) ||
242 		(tokens == NULL) ||
243 		(*n_tokens < 1))
244 		return -EINVAL;
245 
246 	for (i = 0; i < *n_tokens; i++) {
247 		tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
248 		if (tokens[i] == NULL)
249 			break;
250 	}
251 
252 	if ((i == *n_tokens) &&
253 		(NULL != strtok_r(string, PARSE_DELIMITER, &string)))
254 		return -E2BIG;
255 
256 	*n_tokens = i;
257 	return 0;
258 }
259 
260 int
261 parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
262 {
263 	char *c;
264 	uint32_t len, i;
265 
266 	/* Check input parameters */
267 	if ((src == NULL) ||
268 		(dst == NULL) ||
269 		(size == NULL) ||
270 		(*size == 0))
271 		return -1;
272 
273 	len = strlen(src);
274 	if (((len & 3) != 0) ||
275 		(len > (*size) * 2))
276 		return -1;
277 	*size = len / 2;
278 
279 	for (c = src; *c != 0; c++) {
280 		if ((((*c) >= '0') && ((*c) <= '9')) ||
281 			(((*c) >= 'A') && ((*c) <= 'F')) ||
282 			(((*c) >= 'a') && ((*c) <= 'f')))
283 			continue;
284 
285 		return -1;
286 	}
287 
288 	/* Convert chars to bytes */
289 	for (i = 0; i < *size; i++)
290 		dst[i] = get_hex_val(src[2 * i]) * 16 +
291 			get_hex_val(src[2 * i + 1]);
292 
293 	return 0;
294 }
295 
296 int
297 parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels)
298 {
299 	uint32_t n_max_labels = *n_labels, count = 0;
300 
301 	/* Check for void list of labels */
302 	if (strcmp(string, "<void>") == 0) {
303 		*n_labels = 0;
304 		return 0;
305 	}
306 
307 	/* At least one label should be present */
308 	for ( ; (*string != '\0'); ) {
309 		char *next;
310 		int value;
311 
312 		if (count >= n_max_labels)
313 			return -1;
314 
315 		if (count > 0) {
316 			if (string[0] != ':')
317 				return -1;
318 
319 			string++;
320 		}
321 
322 		value = strtol(string, &next, 10);
323 		if (next == string)
324 			return -1;
325 		string = next;
326 
327 		labels[count++] = (uint32_t) value;
328 	}
329 
330 	*n_labels = count;
331 	return 0;
332 }
333 
334 static struct rte_ether_addr *
335 my_ether_aton(const char *a)
336 {
337 	int i;
338 	char *end;
339 	unsigned long o[RTE_ETHER_ADDR_LEN];
340 	static struct rte_ether_addr ether_addr;
341 
342 	i = 0;
343 	do {
344 		errno = 0;
345 		o[i] = strtoul(a, &end, 16);
346 		if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
347 			return NULL;
348 		a = end + 1;
349 	} while (++i != RTE_DIM(o) && end[0] != 0);
350 
351 	/* Junk at the end of line */
352 	if (end[0] != 0)
353 		return NULL;
354 
355 	/* Support the format XX:XX:XX:XX:XX:XX */
356 	if (i == RTE_ETHER_ADDR_LEN) {
357 		while (i-- != 0) {
358 			if (o[i] > UINT8_MAX)
359 				return NULL;
360 			ether_addr.addr_bytes[i] = (uint8_t)o[i];
361 		}
362 	/* Support the format XXXX:XXXX:XXXX */
363 	} else if (i == RTE_ETHER_ADDR_LEN / 2) {
364 		while (i-- != 0) {
365 			if (o[i] > UINT16_MAX)
366 				return NULL;
367 			ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8);
368 			ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff);
369 		}
370 	/* unknown format */
371 	} else
372 		return NULL;
373 
374 	return (struct rte_ether_addr *)&ether_addr;
375 }
376 
377 int
378 parse_ipv4_addr(const char *token, struct in_addr *ipv4)
379 {
380 	if (strlen(token) >= INET_ADDRSTRLEN)
381 		return -EINVAL;
382 
383 	if (inet_pton(AF_INET, token, ipv4) != 1)
384 		return -EINVAL;
385 
386 	return 0;
387 }
388 
389 int
390 parse_ipv6_addr(const char *token, struct rte_ipv6_addr *ipv6)
391 {
392 	if (strlen(token) >= INET6_ADDRSTRLEN)
393 		return -EINVAL;
394 
395 	if (inet_pton(AF_INET6, token, ipv6) != 1)
396 		return -EINVAL;
397 
398 	return 0;
399 }
400 
401 int
402 parse_mac_addr(const char *token, struct rte_ether_addr *addr)
403 {
404 	struct rte_ether_addr *tmp;
405 
406 	tmp = my_ether_aton(token);
407 	if (tmp == NULL)
408 		return -1;
409 
410 	memcpy(addr, tmp, sizeof(struct rte_ether_addr));
411 	return 0;
412 }
413 
414 int
415 parse_cpu_core(const char *entry,
416 	struct cpu_core_params *p)
417 {
418 	size_t num_len;
419 	char num[8];
420 
421 	uint32_t s = 0, c = 0, h = 0, val;
422 	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
423 	const char *next = rte_str_skip_leading_spaces(entry);
424 	char type;
425 
426 	if (p == NULL)
427 		return -EINVAL;
428 
429 	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
430 	while (*next != '\0') {
431 		/* If everything parsed nothing should left */
432 		if (s_parsed && c_parsed && h_parsed)
433 			return -EINVAL;
434 
435 		type = *next;
436 		switch (type) {
437 		case 's':
438 		case 'S':
439 			if (s_parsed || c_parsed || h_parsed)
440 				return -EINVAL;
441 			s_parsed = 1;
442 			next++;
443 			break;
444 		case 'c':
445 		case 'C':
446 			if (c_parsed || h_parsed)
447 				return -EINVAL;
448 			c_parsed = 1;
449 			next++;
450 			break;
451 		case 'h':
452 		case 'H':
453 			if (h_parsed)
454 				return -EINVAL;
455 			h_parsed = 1;
456 			next++;
457 			break;
458 		default:
459 			/* If it start from digit it must be only core id. */
460 			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
461 				return -EINVAL;
462 
463 			type = 'C';
464 		}
465 
466 		for (num_len = 0; *next != '\0'; next++, num_len++) {
467 			if (num_len == RTE_DIM(num))
468 				return -EINVAL;
469 
470 			if (!isdigit(*next))
471 				break;
472 
473 			num[num_len] = *next;
474 		}
475 
476 		if (num_len == 0 && type != 'h' && type != 'H')
477 			return -EINVAL;
478 
479 		if (num_len != 0 && (type == 'h' || type == 'H'))
480 			return -EINVAL;
481 
482 		num[num_len] = '\0';
483 		val = strtol(num, NULL, 10);
484 
485 		h = 0;
486 		switch (type) {
487 		case 's':
488 		case 'S':
489 			s = val;
490 			break;
491 		case 'c':
492 		case 'C':
493 			c = val;
494 			break;
495 		case 'h':
496 		case 'H':
497 			h = 1;
498 			break;
499 		}
500 	}
501 
502 	p->socket_id = s;
503 	p->core_id = c;
504 	p->thread_id = h;
505 	return 0;
506 }
507