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