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