New upstream version 18.02
[deb_dpdk.git] / examples / ip_pipeline / parser.c
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 }