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