]> git.proxmox.com Git - ceph.git/blob - ceph/src/dpdk/examples/ip_pipeline/parser.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / dpdk / examples / ip_pipeline / parser.c
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 }