Merge "Fix latency accuracy and dumping latencies to file"
[samplevnf.git] / VNFs / DPPD-PROX / parse_utils.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <float.h>
20 #include <math.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stdarg.h>
24
25 #include <rte_ether.h>
26 #include <rte_string_fns.h>
27
28 #include "quit.h"
29 #include "cfgfile.h"
30 #include "ip6_addr.h"
31 #include "parse_utils.h"
32 #include "prox_globals.h"
33 #include "prox_cfg.h"
34 #include "log.h"
35 #include "prox_lua.h"
36 #include "prox_lua_types.h"
37
38 #define MAX_NB_PORT_NAMES PROX_MAX_PORTS
39 #define MAX_LEN_PORT_NAME 24
40 #define MAX_LEN_VAR_NAME  24
41 #define MAX_LEN_VAL       512
42 #define MAX_NB_VARS       32
43
44 #if MAX_WT_PER_LB > MAX_INDEX
45 #error MAX_WT_PER_LB > MAX_INDEX
46 #endif
47
48 /* The CPU topology of the system is used to parse "socket
49    notation". This notation allows to refer to cores on specific
50    sockets and the hyper-thread of those cores. The CPU topology is
51    loaded only if the socket notation is used at least once. */
52
53 struct cpu_topology {
54         int socket[MAX_SOCKETS][RTE_MAX_LCORE][2];
55         uint32_t n_cores[MAX_SOCKETS];
56         uint32_t n_sockets;
57 };
58
59 struct cpu_topology cpu_topo;
60
61 struct port_name {
62         uint32_t id;
63         char     name[MAX_LEN_PORT_NAME];
64 };
65
66 static struct port_name port_names[MAX_NB_PORT_NAMES];
67 static uint8_t nb_port_names;
68
69 struct var {
70         uint8_t  cli;
71         char     name[MAX_LEN_VAR_NAME];
72         char     val[MAX_LEN_VAL];
73 };
74
75 static struct var vars[MAX_NB_VARS];
76 static uint8_t nb_vars;
77
78 static char format_err_str[256];
79 static const char *err_str = "";
80
81 const char *get_parse_err(void)
82 {
83         return err_str;
84 }
85
86 static int read_cpu_topology(void);
87
88 static int parse_core(int *socket, int *core, int *ht, const char* str);
89
90 static void set_errf(const char *format, ...)
91 {
92         va_list ap;
93         va_start(ap, format);
94         vsnprintf(format_err_str, sizeof(format_err_str), format, ap);
95         va_end(ap);
96         err_str = format_err_str;
97 }
98
99 static struct var *var_lookup(const char *name)
100 {
101         for (uint8_t i = 0; i < nb_vars; ++i) {
102                 if (!strcmp(name, vars[i].name)) {
103                         return &vars[i];
104                 }
105         }
106         return NULL;
107 }
108
109 static int parse_single_var(char *val, size_t len, const char *name)
110 {
111         struct var *match;
112
113         match = var_lookup(name);
114         if (match) {
115                 if (strlen(match->val) + 1 > len) {
116                         set_errf("Variables '%s' with value '%s' is too long\n",
117                                  match->name, match->val);
118                         return -1;
119                 }
120                 strncpy(val, match->val, len);
121                 return 0;
122         }
123         else {
124                 /* name + 1 to skip leading '$' */
125                 if (lua_to_string(prox_lua(), GLOBAL, name + 1, val, len) >= 0)
126                         return 0;
127         }
128
129         set_errf("Variable '%s' not defined!", name);
130         return 1;
131 }
132
133 /* Replace $... and each occurrence of ${...} with variable values */
134 int parse_vars(char *val, size_t len, const char *name)
135 {
136         static char result[MAX_CFG_STRING_LEN];
137         static char cur_var[MAX_CFG_STRING_LEN];
138         char parsed[2048];
139         size_t name_len = strlen(name);
140         enum parse_vars_state {NO_VAR, WHOLE_VAR, INLINE_VAR} state = NO_VAR;
141         size_t result_len = 0;
142         size_t start_var = 0;
143
144         memset(result, 0, sizeof(result));
145         PROX_PANIC(name_len > sizeof(result), "\tUnable to parse var %s: too long\n", name);
146
147         for (size_t i = 0; i < name_len; ++i) {
148                 switch (state) {
149                 case NO_VAR:
150                         if (name[i] == '$') {
151                                 if (i != name_len - 1 && name[i + 1] == '{') {
152                                         start_var = i + 2;
153                                         state = INLINE_VAR;
154                                         i = i + 1;
155                                 }
156                                 else if (i == 0 && i != name_len - 1) {
157                                         state = WHOLE_VAR;
158                                 }
159                                 else {
160                                         set_errf("Invalid variable syntax");
161                                         return -1;
162                                 }
163                         }
164                         else {
165                                 result[result_len++] = name[i];
166                         }
167                         break;
168                 case INLINE_VAR:
169                         if (name[i] == '}') {
170                                 cur_var[0] = '$';
171                                 size_t var_len = i - start_var;
172                                 if (var_len == 0) {
173                                         set_errf("Empty variable are not allowed");
174                                         return -1;
175                                 }
176
177                                 strncpy(&cur_var[1], &name[start_var], var_len);
178                                 cur_var[1 + var_len] = 0;
179                                 if (parse_single_var(parsed, sizeof(parsed), cur_var)) {
180                                         return -1;
181                                 }
182                                 strcpy(&result[result_len], parsed);
183                                 result_len += strlen(parsed);
184                                 state = NO_VAR;
185                         }
186                         else if (i == name_len - 1) {
187                                 set_errf("Invalid variable syntax, expected '}'.");
188                                 return -1;
189                         }
190                         break;
191                 case WHOLE_VAR:
192                         if (i == name_len - 1) {
193                                 return parse_single_var(val, len, name);
194                         }
195                         break;
196                 }
197         }
198         strncpy(val, result, len);
199
200         return 0;
201 }
202
203 int parse_int_mask(uint32_t *val, uint32_t *mask, const char *str2)
204 {
205         char str[MAX_STR_LEN_PROC];
206         char *mask_str;
207
208         if (parse_vars(str, sizeof(str), str2))
209                 return -1;
210
211         mask_str = strchr(str, '&');
212
213         if (mask_str == NULL) {
214                 set_errf("Missing '&' when parsing mask");
215                 return -2;
216         }
217
218         *mask_str = 0;
219
220         if (parse_int(val, str))
221                 return -1;
222         if (parse_int(mask, mask_str + 1))
223                 return -1;
224
225         return 0;
226 }
227
228 int parse_range(uint32_t* lo, uint32_t* hi, const char *str2)
229 {
230         char str[MAX_STR_LEN_PROC];
231         char *dash;
232
233         if (parse_vars(str, sizeof(str), str2))
234                 return -1;
235
236         dash = strstr(str, "-");
237
238         if (dash == NULL) {
239                 set_errf("Missing '-' when parsing mask");
240                 return -2;
241         }
242
243         *dash = 0;
244
245         if (parse_int(lo, str))
246                 return -1;
247         if (parse_int(hi, dash + 1))
248                 return -1;
249
250         int64_t tmp = strtol(str, 0, 0);
251         if (tmp > UINT32_MAX) {
252                 set_errf("Integer is bigger than %u", UINT32_MAX);
253                 return -1;
254         }
255         if (tmp < 0) {
256                 set_errf("Integer is negative");
257                 return -2;
258         }
259
260         *lo = tmp;
261
262         tmp = strtol(dash + 1, 0, 0);
263         if (tmp > UINT32_MAX) {
264                 set_errf("Integer is bigger than %u", UINT32_MAX);
265                 return -1;
266         }
267         if (tmp < 0) {
268                 set_errf("Integer is negative");
269                 return -2;
270         }
271
272         *hi = tmp;
273
274         if (*lo > *hi) {
275                 set_errf("Low boundary is above high boundary in range");
276                 return -2;
277         }
278
279         return 0;
280 }
281
282 int parse_ip(uint32_t *addr, const char *str2)
283 {
284         char str[MAX_STR_LEN_PROC];
285
286         if (parse_vars(str, sizeof(str), str2))
287                 return -1;
288
289         char *ip_parts[5];
290
291         if (strlen(str) > MAX_STR_LEN_PROC) {
292                 set_errf("String too long (max supported: %d)", MAX_STR_LEN_PROC);
293                 return -2;
294         }
295
296         if (4 != rte_strsplit(str, strlen(str), ip_parts, 5, '.')) {
297                 set_errf("Expecting 4 octets in ip.");
298                 return -1;
299         }
300
301         uint32_t val;
302         for (uint8_t i = 0; i < 4; ++i) {
303                 val = atoi(ip_parts[i]);
304                 if (val > 255) {
305                         set_errf("Maximum value for octet is 255 but octet %u is %u", i, val);
306                         return -1;
307                 }
308                 *addr = *addr << 8 | val;
309         }
310         return 0;
311 }
312
313 int parse_ip4_cidr(struct ip4_subnet *val, const char *str2)
314 {
315         char str[MAX_STR_LEN_PROC];
316         char *slash;
317         int prefix;
318
319         if (parse_vars(str, sizeof(str), str2))
320                 return -1;
321
322         slash = strstr(str, "/");
323
324         if (slash == NULL) {
325                 set_errf("Missing '/' when parsing CIDR notation");
326                 return -2;
327         }
328
329         *slash = 0;
330         prefix = atoi(slash + 1);
331         val->prefix = prefix;
332
333         if (prefix > 32) {
334                 set_errf("Prefix %d is too big", prefix);
335                 return -2;
336         }
337         if (prefix < 1) {
338                 set_errf("Prefix %d is too small", prefix);
339         }
340         if (parse_ip(&val->ip, str))
341                 return -2;
342
343         /* Apply mask making all bits outside the prefix zero */
344         val->ip &= ((int)(1 << 31)) >> (prefix - 1);
345
346         return 0;
347 }
348
349 int parse_ip6_cidr(struct ip6_subnet *val, const char *str2)
350 {
351         char str[MAX_STR_LEN_PROC];
352         char *slash;
353         int prefix;
354
355         if (parse_vars(str, sizeof(str), str2))
356                 return -1;
357
358         slash = strstr(str, "/");
359
360         if (slash == NULL) {
361                 set_errf("Missing '/' when parsing CIDR notation");
362                 return -2;
363         }
364
365         *slash = 0;
366         prefix = atoi(slash + 1);
367         val->prefix = prefix;
368
369         parse_ip6((struct ipv6_addr *)&val->ip, str);
370
371         /* Apply mask making all bits outside the prefix zero */
372
373         int p = 120;
374         int cnt = 0;
375
376         while (p >= prefix) {
377                 val->ip[15-cnt] = 0;
378                 p -= 8;
379                 cnt++;
380         }
381
382         if (prefix % 8 != 0) {
383                 val->ip[15-cnt] &= ((int8_t)(1 << 7)) >> ((prefix %8) - 1);
384         }
385
386         return 0;
387 }
388
389 int parse_ip6(struct ipv6_addr *addr, const char *str2)
390 {
391         char str[MAX_STR_LEN_PROC];
392         char *addr_parts[9];
393
394         if (parse_vars(str, sizeof(str), str2))
395                 return -1;
396
397         uint8_t ret = rte_strsplit(str, strlen(str), addr_parts, 9, ':');
398
399         if (ret == 9) {
400                 set_errf("Invalid IPv6 address");
401                 return -1;
402         }
403
404         uint8_t omitted = 0;
405
406         for (uint8_t i = 0, j = 0; i < ret; ++i, ++j) {
407                 if (*addr_parts[i] == 0) {
408                         if (omitted == 0) {
409                                 set_errf("Can only omit zeros once");
410                                 return -1;
411                         }
412                         omitted = 1;
413                         j += 8 - ret;
414                 }
415                 else {
416                         uint16_t w = strtoll(addr_parts[i], NULL, 16);
417                         addr->bytes[j++] = (w >> 8) & 0xff;
418                         addr->bytes[j] = w & 0xff;
419                 }
420         }
421         return 0;
422 }
423
424 int parse_mac(struct ether_addr *ether_addr, const char *str2)
425 {
426         char str[MAX_STR_LEN_PROC];
427         char *addr_parts[7];
428
429         if (parse_vars(str, sizeof(str), str2))
430                 return -1;
431
432         uint8_t ret = rte_strsplit(str, strlen(str), addr_parts, 7, ':');
433
434         if (ret != 6) {
435                 set_errf("Invalid MAC address format");
436                 return -1;
437         }
438
439         for (uint8_t i = 0; i < 6; ++i) {
440                 if (2 != strlen(addr_parts[i])) {
441                         set_errf("Invalid MAC address format");
442                         return -1;
443                 }
444                 ether_addr->addr_bytes[i] = strtol(addr_parts[i], NULL, 16);
445         }
446
447         return 0;
448 }
449
450 char* get_cfg_key(char *str)
451 {
452         char *pkey = strchr(str, '=');
453
454         if (pkey == NULL) {
455                 return NULL;
456         }
457         *pkey++ = '\0';
458
459         /* remove leading spaces */
460         while (isspace(*pkey)) {
461                 pkey++;
462         }
463         if (*pkey == '\0') { /* an empty key */
464                 return NULL;
465         }
466
467         return pkey;
468 }
469
470 void strip_spaces(char *strings[], const uint32_t count)
471 {
472         for (uint32_t i = 0; i < count; ++i) {
473                 while (isspace(strings[i][0])) {
474                         ++strings[i];
475                 }
476                 size_t len = strlen(strings[i]);
477
478                 while (len && isspace(strings[i][len - 1])) {
479                         strings[i][len - 1] = '\0';
480                         --len;
481                 }
482         }
483 }
484
485 int is_virtualized(void)
486 {
487         char buf[1024]= "/proc/cpuinfo";
488         int virtualized = 0;
489         FILE* fd = fopen(buf, "r");
490         if (fd == NULL) {
491                 set_errf("Could not open %s", buf);
492                 return -1;
493         }
494         while (fgets(buf, sizeof(buf), fd) != NULL) {
495                 if ((strstr(buf, "flags") != NULL) && (strstr(buf, "hypervisor") != NULL))
496                         virtualized = 1;
497         }
498         fclose(fd);
499         return virtualized;
500 }
501
502 static int get_phys_core(uint32_t *dst, int lcore_id)
503 {
504         uint32_t ret;
505         char buf[1024];
506         snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%u/topology/thread_siblings_list", lcore_id);
507         FILE* ht_fd = fopen(buf, "r");
508
509         if (ht_fd == NULL) {
510                 set_errf("Could not open cpu topology %s", buf);
511                 return -1;
512         }
513
514         if (fgets(buf, sizeof(buf), ht_fd) == NULL) {
515                 set_errf("Could not read cpu topology");
516                 return -1;
517         }
518         fclose(ht_fd);
519
520         uint32_t list[2] = {-1,-1};
521         parse_list_set(list, buf, 2);
522
523         *dst = list[0];
524
525         return 0;
526 }
527
528 static int get_socket(uint32_t core_id, uint32_t *socket)
529 {
530         int ret = -1;
531         char buf[1024];
532         snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%u/topology/physical_package_id", core_id);
533         FILE* fd = fopen(buf, "r");
534
535         if (fd == NULL) {
536                 set_errf("%s", buf);
537                 return -1;
538         }
539
540         if (fgets(buf, sizeof(buf), fd) != NULL) {
541                 ret = atoi(buf);
542         }
543         fclose(fd);
544
545         if (socket)
546                 *socket = (ret == -1 ? 0 : ret);
547
548         return 0;
549 }
550
551 int lcore_to_socket_core_ht(uint32_t lcore_id, char *dst, size_t len)
552 {
553         if (cpu_topo.n_sockets == 0) {
554                 if (read_cpu_topology() == -1) {
555                         return -1;
556                 }
557         }
558
559         for (uint32_t s = 0; s < cpu_topo.n_sockets; s++) {
560                 for (uint32_t i = 0; i < cpu_topo.n_cores[s]; ++i) {
561                         if ((uint32_t)cpu_topo.socket[s][i][0] == lcore_id) {
562                                 snprintf(dst, len, "%us%u", i, s);
563                                 return 0;
564                         } else if ((uint32_t)cpu_topo.socket[s][i][1] == lcore_id) {
565                                 snprintf(dst, len, "%us%uh", i, s);
566                                 return 0;
567                         }
568                 }
569         }
570
571         return -1;
572 }
573
574 static int get_lcore_id(uint32_t socket_id, uint32_t core_id, int ht)
575 {
576         if (cpu_topo.n_sockets == 0) {
577                 if (read_cpu_topology() == -1) {
578                         return -1;
579                 }
580         }
581
582         if (socket_id == UINT32_MAX)
583                 socket_id = 0;
584
585         if (socket_id >= MAX_SOCKETS) {
586                 set_errf("Socket id %d too high (max allowed is %d)", MAX_SOCKETS);
587                 return -1;
588         }
589         if (core_id >= RTE_MAX_LCORE) {
590                 set_errf("Core id %d too high (max allowed is %d)", RTE_MAX_LCORE);
591                 return -1;
592         }
593         if (socket_id >= cpu_topo.n_sockets) {
594                 set_errf("Current CPU topology reported that there are %u CPU sockets, CPU topology = %u socket(s), %u physical cores per socket, %u thread(s) per physical core",
595                          cpu_topo.n_sockets, cpu_topo.n_sockets, cpu_topo.n_cores[0], cpu_topo.socket[0][0][1] == -1? 1: 2);
596                 return -1;
597         }
598         if (core_id >= cpu_topo.n_cores[socket_id]) {
599                 set_errf("Core %u on socket %u does not exist, CPU topology = %u socket(s), %u physical cores per socket, %u thread(s) per physical core",
600                          core_id, socket_id, cpu_topo.n_sockets, cpu_topo.n_cores[0], cpu_topo.socket[socket_id][0][1] == -1? 1: 2);
601                 return -1;
602         }
603         if (cpu_topo.socket[socket_id][core_id][!!ht] == -1) {
604                 set_errf("Core %u %son socket %u has no hyper-thread, CPU topology = %u socket(s), %u physical cores per socket, %u thread(s) per physical core",
605                          core_id, ht ? "(hyper-thread) " : "", socket_id, cpu_topo.n_sockets, cpu_topo.n_cores[0], cpu_topo.socket[socket_id][core_id][1] == -1? 1: 2);
606
607                 return -1;
608         }
609         return cpu_topo.socket[socket_id][core_id][!!ht];
610 }
611
612 /* Returns 0 on success, negative on error. Parses the syntax XsYh
613    where sYh is optional. If sY is specified, Y is stored in the
614    socket argument. If, in addition, h is specified, *ht is set to
615    1. In case the input is only a number, socket and ht are set to
616    -1.*/
617 static int parse_core(int *socket, int *core, int *ht, const char* str)
618 {
619         *socket = -1;
620         *core = -1;
621         *ht = -1;
622
623         char* end;
624
625         *core = strtol(str, &end, 10);
626
627         if (*end == 's') {
628                 *socket = 0;
629                 *ht = 0;
630
631                 if (cpu_topo.n_sockets == 0) {
632                         if (read_cpu_topology() == -1) {
633                                 return -1;
634                         }
635                 }
636
637                 ++end;
638                 *socket = strtol(end, &end, 10);
639                 if (*socket >= MAX_SOCKETS) {
640                         set_errf("Socket id %d too high (max allowed is %d)", *socket, MAX_SOCKETS - 1);
641                         return -1;
642                 }
643
644                 if (*end == 'h') {
645                         ++end;
646                         *ht = 1;
647                 }
648
649                 return 0;
650         }
651
652         if (*end == 'h') {
653                 set_errf("Can't find hyper-thread since socket has not been specified");
654                 return -1;
655         }
656
657         return 0;
658 }
659
660 static int parse_task(const char *str, uint32_t *socket, uint32_t *core, uint32_t *task, uint32_t *ht, enum ctrl_type *type)
661 {
662         const char *str_beg = str;
663         char *end;
664
665         *core = strtol(str, &end, 10);
666         if (str == end) {
667                 set_errf("Expected number to in core-task definition:\n"
668                          "\t(i.e. 5s1t0 for task 0 on core 5 on socket 1)\n"
669                          "\tHave: '%s'.", end);
670                 return -1;
671         }
672
673         *task = 0;
674         *socket = -1;
675         *ht = -1;
676         *type = 0;
677
678         str = end;
679
680         if (*str == 's') {
681                 str++;
682                 *socket = 0;
683                 *ht = 0;
684
685                 *socket = strtol(str, &end, 10);
686                 str = end;
687
688                 if (*str == 'h') {
689                         str++;
690                         *ht = 1;
691                 }
692                 if (*str == 't') {
693                         str++;
694                         *task = strtol(str, &end, 10);
695                         str = end;
696                         if (*str == 'p') {
697                                 *type = CTRL_TYPE_PKT;
698                                 str += 1;
699                         }
700                         else if (*str == 'm') {
701                                 *type = CTRL_TYPE_MSG;
702                                 str += 1;
703                         }
704                 }
705         } else {
706                 if (*str == 'h') {
707                         set_errf("Can't find hyper-thread since socket has not been specified");
708                         return -1;
709                 }
710                 if (*str == 't') {
711                         str++;
712                         *task = strtol(str, &end, 10);
713                         str = end;
714                         if (*str == 'p') {
715                                 *type = CTRL_TYPE_PKT;
716                                 str += 1;
717                         }
718                         else if (*str == 'm') {
719                                 *type = CTRL_TYPE_MSG;
720                                 str += 1;
721                         }
722                 }
723         }
724         return str - str_beg;
725 }
726
727 static int core_task_set_add(struct core_task_set *val, uint32_t core, uint32_t task, enum ctrl_type type)
728 {
729         if (val->n_elems == sizeof(val->core_task)/sizeof(val->core_task[0]))
730                 return -1;
731
732         val->core_task[val->n_elems].core = core;
733         val->core_task[val->n_elems].task = task;
734         val->core_task[val->n_elems].type = type;
735         val->n_elems++;
736
737         return 0;
738 }
739
740 int parse_task_set(struct core_task_set *cts, const char *str2)
741 {
742         char str[MAX_STR_LEN_PROC];
743
744         if (parse_vars(str, sizeof(str), str2))
745                 return -1;
746         cts->n_elems = 0;
747
748         char *str3 = str;
749         int ret;
750
751         uint32_t socket_beg, core_beg, task_beg, ht_beg,
752                 socket_end, core_end, task_end, ht_end;
753         enum ctrl_type type_beg, type_end;
754         uint32_t task_group_start = -1;
755
756         while (*str3 && *str3 != ' ') {
757                 if (*str3 == '(') {
758                         task_group_start = cts->n_elems;
759                         str3 += 1;
760                         continue;
761                 }
762                 if (*str3 == ')' && *(str3 + 1) == 't') {
763                         str3 += 2;
764                         char *end;
765                         uint32_t t = strtol(str3, &end, 10);
766                         enum ctrl_type type = 0;
767                         str3 = end;
768
769                         if (*str3 == 'p') {
770                                 type = CTRL_TYPE_PKT;
771                                 str3 += 1;
772                         }
773                         else if (*str3 == 'm') {
774                                 type = CTRL_TYPE_MSG;
775                                 str3 += 1;
776                         }
777
778                         for (uint32_t i = task_group_start; i < cts->n_elems; ++i) {
779                                 cts->core_task[i].task = t;
780                                 cts->core_task[i].type = type;
781                         }
782                         continue;
783                 }
784                 ret = parse_task(str3, &socket_beg, &core_beg, &task_beg, &ht_beg, &type_beg);
785                 if (ret < 0)
786                         return -1;
787                 str3 += ret;
788                 socket_end = socket_beg;
789                 core_end = core_beg;
790                 task_end = task_beg;
791                 ht_end = ht_beg;
792                 type_end = type_beg;
793
794                 if (*str3 == '-') {
795                         str3 += 1;
796                         ret = parse_task(str3, &socket_end, &core_end, &task_end, &ht_end, &type_end);
797                         if (ret < 0)
798                                 return -1;
799                         str3 += ret;
800                 }
801
802                 if (*str3 == ',')
803                         str3 += 1;
804
805                 if (socket_end != socket_beg) {
806                         set_errf("Same socket must be used in range syntax.");
807                         return -1;
808                 } else if (ht_beg != ht_end) {
809                         set_errf("If 'h' syntax is in range, it must be specified everywhere.\n");
810                         return -1;
811                 } else if (task_end != task_beg && core_end != core_beg) {
812                         set_errf("Same task must be used in range syntax when cores are different.\n");
813                         return -1;
814                 } else if (task_end < task_beg) {
815                         set_errf("Task for end of range must be higher than task for beginning of range.\n");
816                         return -1;
817                 } else if (type_end != type_beg) {
818                         set_errf("Task type for end of range must be the same as  task type for beginning.\n");
819                         return -1;
820                 } else if (core_end < core_beg) {
821                         set_errf("Core for end of range must be higher than core for beginning of range.\n");
822                         return -1;
823                 }
824
825                 for (uint32_t j = core_beg; j <= core_end; ++j) {
826                         if (socket_beg != UINT32_MAX && ht_beg != UINT32_MAX)
827                                 ret = get_lcore_id(socket_beg, j, ht_beg);
828                         else
829                                 ret = j;
830                         if (ret < 0)
831                                 return -1;
832                         for (uint32_t k = task_beg; k <= task_end; ++k) {
833                                 core_task_set_add(cts, ret, k, type_beg);
834                         }
835                 }
836         }
837         return 0;
838 }
839
840 int parse_list_set(uint32_t *list, const char *str2, uint32_t max_list)
841 {
842         char str[MAX_STR_LEN_PROC];
843         char *parts[MAX_STR_LEN_PROC];
844
845         if (parse_vars(str, sizeof(str), str2))
846                 return -1;
847
848         int n_parts = rte_strsplit(str, strlen(str), parts, MAX_STR_LEN_PROC, ',');
849         size_t list_count = 0;
850
851         for (int i = 0; i < n_parts; ++i) {
852                 char *cur_part = parts[i];
853                 char *sub_parts[3];
854                 int n_sub_parts = rte_strsplit(cur_part, strlen(cur_part), sub_parts, 3, '-');
855                 int socket1, socket2;
856                 int ht1, ht2;
857                 int core1, core2;
858                 int ret = 0;
859
860                 if (n_sub_parts == 1) {
861                         if (parse_core(&socket1, &core1, &ht1, sub_parts[0]))
862                                 return -1;
863
864                         socket2 = socket1;
865                         core2 = core1;
866                         ht2 = ht1;
867                 } else if (n_sub_parts == 2) {
868                         if (parse_core(&socket1, &core1, &ht1, sub_parts[0]))
869                                 return -1;
870                         if (parse_core(&socket2, &core2, &ht2, sub_parts[1]))
871                                 return -1;
872                 } else if (n_sub_parts >= 3) {
873                         set_errf("Multiple '-' characters in range syntax found");
874                         return -1;
875                 } else {
876                         set_errf("Invalid list syntax");
877                         return -1;
878                 }
879
880                 if (socket1 != socket2) {
881                         set_errf("Same socket must be used in range syntax");
882                         return -1;
883                 }
884                 else if (ht1 != ht2) {
885                         set_errf("If 'h' syntax is in range, it must be specified everywhere.");
886                         return -1;
887                 }
888
889                 for (int cur_core = core1; cur_core <= core2; ++cur_core) {
890                         int effective_core;
891
892                         if (socket1 != -1)
893                                 effective_core = get_lcore_id(socket1, cur_core, ht1);
894                         else
895                                 effective_core = cur_core;
896
897                         if (list_count >= max_list) {
898                                 set_errf("Too many elements in list\n");
899                                 return -1;
900                         }
901                         list[list_count++] = effective_core;
902                 }
903         }
904
905         return list_count;
906 }
907
908 int parse_kmg(uint32_t* val, const char *str2)
909 {
910         char str[MAX_STR_LEN_PROC];
911
912         if (parse_vars(str, sizeof(str), str2))
913                 return -1;
914
915         char c = str[strlen(str) - 1];
916         *val = atoi(str);
917
918         switch (c) {
919         case 'G':
920                 if (*val >> 22)
921                         return -2;
922                 *val <<= 10;
923         case 'M':
924                 if (*val >> 22)
925                         return -2;
926                 *val <<= 10;
927         case 'K':
928                 if (*val >> 22)
929                         return -2;
930                 *val <<= 10;
931                 break;
932         default:
933                 /* only support optional KMG suffix */
934                 if (c < '0' || c > '9') {
935                         set_errf("Unknown syntax for KMG suffix '%c' (expected K, M or G)", c);
936                         return -1;
937                 }
938         }
939
940         return 0;
941 }
942
943 int parse_bool(uint32_t* val, const char *str2)
944 {
945         char str[MAX_STR_LEN_PROC];
946
947         if (parse_vars(str, sizeof(str), str2))
948                 return -1;
949
950         if (!strcmp(str, "yes")) {
951                 *val = 1;
952                 return 0;
953         }
954         else if (!strcmp(str, "no")) {
955                 *val = 0;
956                 return 0;
957         }
958         set_errf("Unknown syntax for bool '%s' (expected yes or no)", str);
959         return -1;
960 }
961
962 int parse_flag(uint32_t* val, uint32_t flag, const char *str2)
963 {
964         char str[MAX_STR_LEN_PROC];
965
966         if (parse_vars(str, sizeof(str), str2))
967                 return -1;
968
969         uint32_t tmp;
970         if (parse_bool(&tmp, str))
971                 return -1;
972
973         if (tmp)
974                 *val |= flag;
975         else
976                 *val &= ~flag;
977
978         return 0;
979 }
980
981 int parse_int(uint32_t* val, const char *str2)
982 {
983         char str[MAX_STR_LEN_PROC];
984
985         if (parse_vars(str, sizeof(str), str2))
986                 return -1;
987
988         int64_t tmp = strtol(str, 0, 0);
989         if (tmp > UINT32_MAX) {
990                 set_errf("Integer is bigger than %u", UINT32_MAX);
991                 return -1;
992         }
993         if (tmp < 0) {
994                 set_errf("Integer is negative");
995                 return -2;
996         }
997         *val = tmp;
998
999         return 0;
1000 }
1001
1002 int parse_float(float* val, const char *str2)
1003 {
1004         char str[MAX_STR_LEN_PROC];
1005
1006         if (parse_vars(str, sizeof(str), str2))
1007                 return -1;
1008
1009         float tmp = strtof(str, 0);
1010         if ((tmp >= HUGE_VALF) || (tmp <= -HUGE_VALF)) {
1011                 set_errf("Unable to parse float\n");
1012                 return -1;
1013         }
1014         *val = tmp;
1015
1016         return 0;
1017 }
1018
1019 int parse_u64(uint64_t* val, const char *str2)
1020 {
1021         char str[MAX_STR_LEN_PROC];
1022
1023         if (parse_vars(str, sizeof(str), str2))
1024                 return -1;
1025
1026         errno = 0;
1027         uint64_t tmp = strtoul(str, NULL, 0);
1028         if (errno != 0) {
1029                 set_errf("Invalid u64 '%s' (%s)", str, strerror(errno));
1030                 return -2;
1031         }
1032         *val = tmp;
1033
1034         return 0;
1035 }
1036
1037 int parse_str(char* dst, const char *str2, size_t max_len)
1038 {
1039         char str[MAX_STR_LEN_PROC];
1040
1041         if (parse_vars(str, sizeof(str), str2))
1042                 return -1;
1043
1044         if (strlen(str) > max_len - 1) {
1045                 set_errf("String too long (%u > %u)", strlen(str), max_len - 1);
1046                 return -2;
1047         }
1048
1049         strncpy(dst, str, max_len);
1050         return 0;
1051 }
1052
1053 int parse_path(char *dst, const char *str, size_t max_len)
1054 {
1055         if (parse_str(dst, str, max_len))
1056                 return -1;
1057         if (access(dst, F_OK)) {
1058                 set_errf("Invalid file '%s' (%s)", dst, strerror(errno));
1059                 return -1;
1060         }
1061         return 0;
1062 }
1063
1064 int parse_port_name(uint32_t *val, const char *str2)
1065 {
1066         char str[MAX_STR_LEN_PROC];
1067
1068         if (parse_vars(str, sizeof(str), str2))
1069                 return -1;
1070
1071         for (uint8_t i = 0; i < nb_port_names; ++i) {
1072                 if (!strcmp(str, port_names[i].name)) {
1073                         *val = port_names[i].id;
1074                         return 0;
1075                 }
1076         }
1077         set_errf("Port with name %s not defined", str);
1078         return 1;
1079 }
1080
1081 int parse_port_name_list(uint32_t *val, uint32_t* tot, uint8_t max_vals, const char *str2)
1082 {
1083         char *elements[PROX_MAX_PORTS + 1];
1084         char str[MAX_STR_LEN_PROC];
1085         uint32_t cur;
1086         int ret;
1087
1088         if (parse_str(str, str2, sizeof(str)))
1089                 return -1;
1090
1091         ret = rte_strsplit(str, strlen(str), elements, PROX_MAX_PORTS + 1, ',');
1092
1093         if (ret == PROX_MAX_PORTS + 1 || ret > max_vals) {
1094                 set_errf("Too many ports in port list");
1095                 return -1;
1096         }
1097
1098         strip_spaces(elements, ret);
1099         for (uint8_t i = 0; i < ret; ++i) {
1100                 if (parse_port_name(&cur, elements[i])) {
1101                         return -1;
1102                 }
1103                 val[i] = cur;
1104         }
1105         if (tot) {
1106                 *tot = ret;
1107         }
1108         return 0;
1109 }
1110
1111 int parse_remap(uint8_t *mapping, const char *str)
1112 {
1113         char *elements[PROX_MAX_PORTS + 1];
1114         char *elements2[PROX_MAX_PORTS + 1];
1115         char str_cpy[MAX_STR_LEN_PROC];
1116         uint32_t val;
1117         int ret, ret2;
1118
1119         if (strlen(str) > MAX_STR_LEN_PROC) {
1120                 set_errf("String too long (max supported: %d)", MAX_STR_LEN_PROC);
1121                 return -2;
1122         }
1123         strncpy(str_cpy, str, MAX_STR_LEN_PROC);
1124
1125         ret = rte_strsplit(str_cpy, strlen(str_cpy), elements, PROX_MAX_PORTS + 1, ',');
1126         if (ret <= 0) {
1127                 set_errf("Invalid remap syntax");
1128                 return -1;
1129         }
1130         else if (ret > PROX_MAX_PORTS) {
1131                 set_errf("Too many remaps");
1132                 return -2;
1133         }
1134
1135         strip_spaces(elements, ret);
1136         for (uint8_t i = 0; i < ret; ++i) {
1137                 ret2 = rte_strsplit(elements[i], strlen(elements[i]), elements2, PROX_MAX_PORTS + 1, '|');
1138                 strip_spaces(elements2, ret2);
1139                 if (ret2 > PROX_MAX_PORTS) {
1140                         set_errf("Too many remaps");
1141                         return -2;
1142                 }
1143                 for (uint8_t j = 0; j < ret2; ++j) {
1144                         if (parse_port_name(&val, elements2[j])) {
1145                                 return -1;
1146                         }
1147
1148                         /* This port will be mapped to the i'th
1149                            element specified before remap=. */
1150                         mapping[val] = i;
1151                 }
1152         }
1153
1154         return ret;
1155 }
1156
1157 int add_port_name(uint32_t val, const char *str2)
1158 {
1159         char str[MAX_STR_LEN_PROC];
1160
1161         if (parse_vars(str, sizeof(str), str2))
1162                 return -1;
1163
1164         struct port_name* pn;
1165
1166         if (nb_port_names == MAX_NB_PORT_NAMES) {
1167                 set_errf("Too many ports defined (can define %d)", MAX_NB_PORT_NAMES);
1168                 return -1;
1169         }
1170
1171         for (uint8_t i = 0; i < nb_port_names; ++i) {
1172                 /* each port has to have a unique name*/
1173                 if (!strcmp(str, port_names[i].name)) {
1174                         set_errf("Port with name %s is already defined", str);
1175                         return -2;
1176                 }
1177         }
1178
1179         pn = &port_names[nb_port_names];
1180         strncpy(pn->name, str, sizeof(pn->name));
1181         pn->id = val;
1182
1183         ++nb_port_names;
1184         return 0;
1185 }
1186
1187 int set_self_var(const char *str)
1188 {
1189         for (uint8_t i = 0; i < nb_vars; ++i) {
1190                 if (!strcmp("$self", vars[i].name)) {
1191                         sprintf(vars[i].val, "%s", str);
1192                         return 0;
1193                 }
1194         }
1195
1196         struct var *v = &vars[nb_vars];
1197
1198         strncpy(v->name, "$self", strlen("$self"));
1199         sprintf(v->val, "%s", str);
1200         nb_vars++;
1201
1202         return 0;
1203 }
1204
1205 int add_var(const char* name, const char *str2, uint8_t cli)
1206 {
1207         struct var* v;
1208
1209         char str[MAX_STR_LEN_PROC];
1210
1211         if (parse_vars(str, sizeof(str), str2))
1212                 return -1;
1213
1214         if (strlen(name) == 0 || strlen(name) == 1) {
1215                 set_errf("Can't define variables with empty name");
1216                 return -1;
1217         }
1218
1219         if (name[0] != '$') {
1220                 set_errf("Each variable should start with the $ character");
1221                 return -1;
1222         }
1223
1224         if (nb_vars == MAX_NB_VARS) {
1225                 set_errf("Too many variables defined (can define %d)", MAX_NB_VARS);
1226                 return -2;
1227         }
1228
1229         for (uint8_t i = 0; i < nb_vars; ++i) {
1230                 if (!strcmp(name, vars[i].name)) {
1231
1232                         /* Variables defined through program arguments
1233                            take precedence. */
1234                         if (!cli && vars[i].cli) {
1235                                 return 0;
1236                         }
1237
1238                         set_errf("Variable with name %s is already defined", name);
1239                         return -3;
1240                 }
1241         }
1242
1243         v = &vars[nb_vars];
1244         PROX_PANIC(strlen(name) > sizeof(v->name), "\tUnable to parse var %s: too long\n", name);
1245         PROX_PANIC(strlen(str) > sizeof(v->val), "\tUnable to parse var %s=%s: too long\n", name,str);
1246         strncpy(v->name, name, sizeof(v->name));
1247         strncpy(v->val, str, sizeof(v->val));
1248         v->cli = cli;
1249
1250         ++nb_vars;
1251         return 0;
1252 }
1253
1254 static int read_cores_present(uint32_t *cores, int max_cores, int *res)
1255 {
1256         FILE* fd = fopen("/sys/devices/system/cpu/present", "r");
1257         char buf[1024];
1258
1259         if (fd == NULL) {
1260                 set_errf("Could not opening file /sys/devices/system/cpu/present");
1261                 return -1;
1262         }
1263
1264         if (fgets(buf, sizeof(buf), fd) == NULL) {
1265                 set_errf("Could not read cores range");
1266                 return -1;
1267         }
1268
1269         fclose(fd);
1270
1271         int ret = parse_list_set(cores, buf, max_cores);
1272
1273         if (ret < 0)
1274                 return -1;
1275
1276         *res = ret;
1277         return 0;
1278 }
1279
1280 static int set_dummy_topology(void)
1281 {
1282         int core_count = 0;
1283
1284         for (int s = 0; s < MAX_SOCKETS; s++) {
1285                 for (int i = 0; i < 32; ++i) {
1286                         cpu_topo.socket[s][i][0] = core_count++;
1287                         cpu_topo.socket[s][i][1] = core_count++;
1288                         cpu_topo.n_cores[s]++;
1289                 }
1290         }
1291         cpu_topo.n_sockets = MAX_SOCKETS;
1292         return 0;
1293 }
1294
1295 static int read_cpu_topology(void)
1296 {
1297         if (cpu_topo.n_sockets != 0)
1298                 return 0;
1299         if (prox_cfg.flags & DSF_USE_DUMMY_CPU_TOPO)
1300                 return set_dummy_topology();
1301
1302         uint32_t cores[RTE_MAX_LCORE];
1303         int n_cores = 0;
1304
1305         if (read_cores_present(cores, sizeof(cores)/sizeof(cores[0]), &n_cores) != 0)
1306                 return -1;
1307
1308         for (int s = 0; s < MAX_SOCKETS; s++) {
1309                 for (int i = 0; i < RTE_MAX_LCORE; ++i) {
1310                         cpu_topo.socket[s][i][0] = -1;
1311                         cpu_topo.socket[s][i][1] = -1;
1312                 }
1313         }
1314
1315         for (int i = 0; i < n_cores; ++i) {
1316                 uint32_t socket_id, lcore_id, phys;
1317
1318                 lcore_id = cores[i];
1319                 if (get_socket(lcore_id, &socket_id) != 0)
1320                         return -1;
1321                 if (socket_id >= MAX_SOCKETS) {
1322                         set_errf("Can't read CPU topology due too high socket ID (max allowed is %d)",
1323                                  MAX_SOCKETS);
1324                         return -1;
1325                 }
1326                 if (socket_id >= cpu_topo.n_sockets) {
1327                         cpu_topo.n_sockets = socket_id + 1;
1328                 }
1329                 if (get_phys_core(&phys, lcore_id) != 0)
1330                         return -1;
1331                 if (phys >= RTE_MAX_LCORE) {
1332                         set_errf("Core ID %u too high", phys);
1333                         return -1;
1334                 }
1335
1336                 if (cpu_topo.socket[socket_id][phys][0] == -1) {
1337                         cpu_topo.socket[socket_id][phys][0] = lcore_id;
1338                         cpu_topo.n_cores[socket_id]++;
1339                 }
1340                 else if (cpu_topo.socket[socket_id][phys][1] == -1) {
1341                         cpu_topo.socket[socket_id][phys][1] = lcore_id;
1342                 }
1343                 else {
1344                         set_errf("Too many core siblings");
1345                         return -1;
1346                 }
1347         }
1348
1349         /* There can be holes in the cpu_topo description at this
1350            point. An example for this is a CPU topology where the
1351            lowest core ID of 2 hyper-threads is always an even
1352            number. Before finished up this phase, compact all the
1353            cores to make the numbers consecutive. */
1354
1355         for (uint32_t i = 0; i < cpu_topo.n_sockets; ++i) {
1356                 int spread = 0, compact = 0;
1357                 while (cpu_topo.socket[i][spread][0] == -1)
1358                         spread++;
1359
1360                 for (uint32_t c = 0; c < cpu_topo.n_cores[i]; ++c) {
1361                         cpu_topo.socket[i][compact][0] = cpu_topo.socket[i][spread][0];
1362                         cpu_topo.socket[i][compact][1] = cpu_topo.socket[i][spread][1];
1363                         compact++;
1364                         spread++;
1365                         /* Skip gaps */
1366                         while (cpu_topo.socket[i][spread][0] == -1)
1367                                 spread++;
1368                 }
1369         }
1370
1371         return 0;
1372 }
1373
1374 static int bit_len_valid(uint32_t len, const char *str)
1375 {
1376         if (len > 32) {
1377                 set_errf("Maximum random length is 32, but length of '%s' is %zu\n", str, len);
1378                 return 0;
1379         }
1380         if (len % 8) {
1381                 plog_err("Random should be multiple of 8 long\n");
1382                 return 0;
1383         }
1384         if (len == 0) {
1385                 plog_err("Random should be at least 1 byte long\n");
1386                 return 0;
1387         }
1388         return -1;
1389 }
1390
1391 int parse_random_str(uint32_t *mask, uint32_t *fixed, uint32_t *len, const char *str)
1392 {
1393         const size_t len_bits = strlen(str);
1394
1395         if (!bit_len_valid(len_bits, str))
1396                 return -1;
1397
1398         *mask = 0;
1399         *fixed = 0;
1400         *len = len_bits / 8;
1401
1402         for (uint32_t j = 0; j < len_bits; ++j) {
1403                 /* Store in the lower bits the value of the rand string (note
1404                    that these are the higher bits in LE). */
1405                 switch (str[j]) {
1406                 case 'X':
1407                         *mask |= 1 << (len_bits - 1 - j);
1408                         break;
1409                 case '1':
1410                         *fixed |= 1 << (len_bits - 1 - j);
1411                         break;
1412                 case '0':
1413                         break;
1414                 default:
1415                         set_errf("Unexpected %c\n", str[j]);
1416                         return -1;
1417                 }
1418         }
1419         return 0;
1420 }