xref: /f-stack/lib/ff_config.c (revision e6804bae)
1 /*
2  * Copyright (C) 2017-2021 THL A29 Limited, a Tencent company.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *   list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *   this list of conditions and the following disclaimer in the documentation
12  *   and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <getopt.h>
32 #include <ctype.h>
33 #include <rte_config.h>
34 #include <rte_string_fns.h>
35 
36 #include "ff_config.h"
37 #include "ff_ini_parser.h"
38 
39 #define DEFAULT_CONFIG_FILE   "config.ini"
40 
41 #define BITS_PER_HEX 4
42 
43 struct ff_config ff_global_cfg;
44 int dpdk_argc;
45 char *dpdk_argv[DPDK_CONFIG_NUM + 1];
46 
47 char* const short_options = "c:t:p:";
48 struct option long_options[] = {
49     { "conf", 1, NULL, 'c'},
50     { "proc-type", 1, NULL, 't'},
51     { "proc-id", 1, NULL, 'p'},
52     { 0, 0, 0, 0},
53 };
54 
55 static int
xdigit2val(unsigned char c)56 xdigit2val(unsigned char c)
57 {
58     int val;
59 
60     if (isdigit(c))
61         val = c - '0';
62     else if (isupper(c))
63         val = c - 'A' + 10;
64     else
65         val = c - 'a' + 10;
66     return val;
67 }
68 
69 static int
parse_lcore_mask(struct ff_config * cfg,const char * coremask)70 parse_lcore_mask(struct ff_config *cfg, const char *coremask)
71 {
72     int i, j, idx = 0, shift = 0, zero_num = 0;
73     unsigned count = 0;
74     char c;
75     int val;
76     uint16_t *proc_lcore;
77     char buf[RTE_MAX_LCORE] = {0};
78     char zero[RTE_MAX_LCORE] = {0};
79 
80     if (coremask == NULL)
81         return 0;
82 
83     cfg->dpdk.proc_lcore = (uint16_t *)calloc(RTE_MAX_LCORE, sizeof(uint16_t));
84     if (cfg->dpdk.proc_lcore == NULL) {
85         fprintf(stderr, "parse_lcore_mask malloc failed\n");
86         return 0;
87     }
88     proc_lcore = cfg->dpdk.proc_lcore;
89 
90     /*
91      * Remove all blank characters ahead and after.
92      * Remove 0x/0X if exists.
93      */
94     while (isblank(*coremask))
95         coremask++;
96     if (coremask[0] == '0' && ((coremask[1] == 'x')
97         || (coremask[1] == 'X')))
98         coremask += 2;
99 
100     i = strlen(coremask);
101     while ((i > 0) && isblank(coremask[i - 1]))
102         i--;
103 
104     if (i == 0)
105         return 0;
106 
107     for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) {
108         c = coremask[i];
109         if (isxdigit(c) == 0) {
110             return 0;
111         }
112         val = xdigit2val(c);
113         for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++) {
114             if ((1 << j) & val) {
115                 proc_lcore[count] = idx;
116                 if (cfg->dpdk.proc_id == count) {
117                     zero_num = idx >> 2;
118                     shift = idx & 0x3;
119                     memset(zero,'0',zero_num);
120                     snprintf(buf, sizeof(buf) - 1, "%llx%s",
121                         (unsigned long long)1<<shift, zero);
122                     cfg->dpdk.proc_mask = strdup(buf);
123 		}
124                 count++;
125             }
126         }
127     }
128 
129     for (; i >= 0; i--)
130         if (coremask[i] != '0')
131             return 0;
132 
133     if (cfg->dpdk.proc_id >= count)
134         return 0;
135 
136     cfg->dpdk.nb_procs = count;
137 
138     return 1;
139 }
140 
141 static int
is_integer(const char * s)142 is_integer(const char *s)
143 {
144     if (*s == '-' || *s == '+')
145         s++;
146     if (*s < '0' || '9' < *s)
147         return 0;
148     s++;
149     while ('0' <= *s && *s <= '9')
150         s++;
151     return (*s == '\0');
152 }
153 
154 static int
freebsd_conf_handler(struct ff_config * cfg,const char * section,const char * name,const char * value)155 freebsd_conf_handler(struct ff_config *cfg, const char *section,
156     const char *name, const char *value)
157 {
158     struct ff_freebsd_cfg *newconf, **cur;
159     newconf = (struct ff_freebsd_cfg *)malloc(sizeof(struct ff_freebsd_cfg));
160     if (newconf == NULL) {
161         fprintf(stderr, "freebsd conf malloc failed\n");
162         return 0;
163     }
164 
165     newconf->name = strdup(name);
166     newconf->str = strdup(value);
167 
168     if (strcmp(section, "boot") == 0) {
169         cur = &cfg->freebsd.boot;
170 
171         newconf->value = (void *)newconf->str;
172         newconf->vlen = strlen(value);
173     } else if (strcmp(section, "sysctl") == 0) {
174         cur = &cfg->freebsd.sysctl;
175 
176         if (is_integer(value)) {
177             if (strcmp(name, "kern.ipc.maxsockbuf") == 0) {
178                 long *p = (long *)malloc(sizeof(long));
179                 *p = atol(value);
180                 newconf->value = (void *)p;
181                 newconf->vlen = sizeof(*p);
182             } else {
183                  int *p = (int *)malloc(sizeof(int));
184                  *p = atoi(value);
185                  newconf->value = (void *)p;
186                  newconf->vlen = sizeof(*p);
187             }
188         } else {
189             newconf->value = (void *)newconf->str;
190             newconf->vlen = strlen(value);
191         }
192     } else {
193         fprintf(stderr, "freebsd conf section[%s] error\n", section);
194         free(newconf);
195         return 0;
196     }
197 
198     if (*cur == NULL) {
199         newconf->next = NULL;
200         *cur = newconf;
201     } else {
202         newconf->next = (*cur)->next;
203         (*cur)->next = newconf;
204     }
205 
206     return 1;
207 }
208 // A recursive binary search function. It returns location of x in
209 // given array arr[l..r] is present, otherwise -1
210 static int
uint16_binary_search(uint16_t arr[],int l,int r,uint16_t x)211 uint16_binary_search(uint16_t arr[], int l, int r, uint16_t x)
212 {
213     if (r >= l) {
214         int mid = l + (r - l)/2;
215 
216         // If the element is present at the middle itself
217         if (arr[mid] == x)  return mid;
218 
219         // If element is smaller than mid, then it can only be present
220         // in left subarray
221         if (arr[mid] > x) return uint16_binary_search(arr, l, mid-1, x);
222 
223         // Else the element can only be present in right subarray
224         return uint16_binary_search(arr, mid+1, r, x);
225     }
226 
227     // We reach here when element is not present in array
228     return -1;
229 }
230 
231 static int
uint16_cmp(const void * a,const void * b)232 uint16_cmp (const void * a, const void * b)
233 {
234     return ( *(uint16_t*)a - *(uint16_t*)b );
235 }
236 
237 static inline void
sort_uint16_array(uint16_t arr[],int n)238 sort_uint16_array(uint16_t arr[], int n)
239 {
240     qsort(arr, n, sizeof(uint16_t), uint16_cmp);
241 }
242 
243 static inline char *
__strstrip(char * s)244 __strstrip(char *s)
245 {
246     char *end = s + strlen(s) - 1;
247     while(*s == ' ') s++;
248     for (; end >= s; --end) {
249         if (*end != ' ') break;
250     }
251     *(++end) = '\0';
252     return s;
253 }
254 
255 static int
__parse_config_list(uint16_t * arr,int * sz,const char * value)256 __parse_config_list(uint16_t *arr, int *sz, const char *value) {
257     int i, j;
258     char input[4096];
259     char *tokens[128];
260     int nTokens = 0;
261     char *endptr;
262     int nr_ele = 0;
263     int max_ele = *sz;
264 
265     strncpy(input, value, sizeof(input) - 1);
266     nTokens = rte_strsplit(input, sizeof(input), tokens, 128, ',');
267     for (i = 0; i < nTokens; i++) {
268         char *tok = tokens[i];
269         char *middle = strchr(tok, '-');
270         if (middle == NULL) {
271             tok = __strstrip(tok);
272             long v = strtol(tok, &endptr, 10);
273             if (*endptr != '\0') {
274                 fprintf(stderr, "%s is not a integer.", tok);
275                 return 0;
276             }
277             if (nr_ele > max_ele) {
278                 fprintf(stderr, "too many elements in list %s\n", value);
279                 return 0;
280             }
281             arr[nr_ele++] = (uint16_t)v;
282         } else {
283             *middle = '\0';
284             char *lbound = __strstrip(tok);
285             char *rbound = __strstrip(middle+1);
286             long lv = strtol(lbound, &endptr, 10);
287             if (*endptr != '\0') {
288                 fprintf(stderr, "%s is not a integer.", lbound);
289                 return 0;
290             }
291             long rv = strtol(rbound, &endptr, 10);
292             if (*endptr != '\0') {
293                 fprintf(stderr, "%s is not a integer.", rbound);
294                 return 0;
295             }
296             for (j = lv; j <= rv; ++j) {
297                 if (nr_ele > max_ele) {
298                     fprintf(stderr, "too many elements in list %s.\n", value);
299                     return 0;
300                 }
301                 arr[nr_ele++] = (uint16_t)j;
302             }
303         }
304     }
305     if (nr_ele <= 0) {
306         fprintf(stderr, "list %s is empty\n", value);
307         return 1;
308     }
309     sort_uint16_array(arr, nr_ele);
310     *sz = nr_ele;
311     return 1;
312 }
313 
314 static int
parse_port_lcore_list(struct ff_port_cfg * cfg,const char * v_str)315 parse_port_lcore_list(struct ff_port_cfg *cfg, const char *v_str)
316 {
317     cfg->nb_lcores = DPDK_MAX_LCORE;
318     uint16_t *cores = cfg->lcore_list;
319     return __parse_config_list(cores, &cfg->nb_lcores, v_str);
320 }
321 
322 static int
parse_port_list(struct ff_config * cfg,const char * v_str)323 parse_port_list(struct ff_config *cfg, const char *v_str)
324 {
325     int res;
326     uint16_t ports[RTE_MAX_ETHPORTS];
327     int sz = RTE_MAX_ETHPORTS;
328 
329     res = __parse_config_list(ports, &sz, v_str);
330     if (! res) return res;
331 
332     uint16_t *portid_list = malloc(sizeof(uint16_t)*sz);
333 
334     if (portid_list == NULL) {
335         fprintf(stderr, "parse_port_list malloc failed\n");
336         return 0;
337     }
338     memcpy(portid_list, ports, sz*sizeof(uint16_t));
339 
340     cfg->dpdk.portid_list = portid_list;
341     cfg->dpdk.nb_ports = sz;
342     cfg->dpdk.max_portid = portid_list[sz-1];
343     return res;
344 }
345 
346 static int
parse_port_slave_list(struct ff_port_cfg * cfg,const char * v_str)347 parse_port_slave_list(struct ff_port_cfg *cfg, const char *v_str)
348 {
349     int res;
350     uint16_t ports[RTE_MAX_ETHPORTS];
351     int sz = RTE_MAX_ETHPORTS;
352 
353     res = __parse_config_list(ports, &sz, v_str);
354     if (! res) return res;
355 
356     uint16_t *portid_list = malloc(sizeof(uint16_t)*sz);
357 
358     if (portid_list == NULL) {
359         fprintf(stderr, "parse_port_slave_list malloc failed\n");
360         return 0;
361     }
362     memcpy(portid_list, ports, sz*sizeof(uint16_t));
363 
364     cfg->slave_portid_list = portid_list;
365     cfg->nb_slaves = sz;
366 
367     return res;
368 }
369 
370 static int
vip_cfg_handler(struct ff_port_cfg * cur)371 vip_cfg_handler(struct ff_port_cfg *cur)
372 {
373     //vip cfg
374     int ret;
375     char *vip_addr_array[VIP_MAX_NUM];
376 
377     ret = rte_strsplit(cur->vip_addr_str, strlen(cur->vip_addr_str), &vip_addr_array[0], VIP_MAX_NUM, ';');
378     if (ret <= 0) {
379         fprintf(stdout, "vip_cfg_handler nb_vip is 0, not set vip_addr or set invalid vip_addr %s\n",
380             cur->vip_addr_str);
381         return 1;
382     }
383 
384     cur->nb_vip = ret;
385 
386     cur->vip_addr_array = (char **)calloc(cur->nb_vip, sizeof(char *));
387     if (cur->vip_addr_array == NULL) {
388         fprintf(stderr, "vip_cfg_handler malloc failed\n");
389         goto err;
390     }
391 
392     memcpy(cur->vip_addr_array, vip_addr_array, cur->nb_vip * sizeof(char *));
393 
394     return 1;
395 
396 err:
397     cur->nb_vip = 0;
398     if (cur->vip_addr_array) {
399         free(cur->vip_addr_array);
400         cur->vip_addr_array = NULL;
401     }
402 
403     return 0;
404 }
405 
406 #ifdef INET6
407 static int
vip6_cfg_handler(struct ff_port_cfg * cur)408 vip6_cfg_handler(struct ff_port_cfg *cur)
409 {
410     //vip6 cfg
411     int ret;
412     char *vip_addr6_array[VIP_MAX_NUM];
413 
414     ret = rte_strsplit(cur->vip_addr6_str, strlen(cur->vip_addr6_str),
415                                     &vip_addr6_array[0], VIP_MAX_NUM, ';');
416     if (ret == 0) {
417         fprintf(stdout, "vip6_cfg_handler nb_vip6 is 0, not set vip_addr6 or set invalid vip_addr6 %s\n",
418             cur->vip_addr6_str);
419         return 1;
420     }
421 
422     cur->nb_vip6 = ret;
423 
424     cur->vip_addr6_array = (char **) calloc(cur->nb_vip6, sizeof(char *));
425     if (cur->vip_addr6_array == NULL) {
426         fprintf(stderr, "vip6_cfg_handler malloc failed\n");
427         goto fail;
428     }
429 
430     memcpy(cur->vip_addr6_array, vip_addr6_array, cur->nb_vip6 * sizeof(char *));
431 
432     return 1;
433 
434 fail:
435     cur->nb_vip6 = 0;
436     if (cur->vip_addr6_array) {
437         free(cur->vip_addr6_array);
438         cur->vip_addr6_array = NULL;
439     }
440 
441     return 0;
442 }
443 #endif
444 
445 static int
port_cfg_handler(struct ff_config * cfg,const char * section,const char * name,const char * value)446 port_cfg_handler(struct ff_config *cfg, const char *section,
447     const char *name, const char *value) {
448 
449     if (cfg->dpdk.nb_ports == 0) {
450         fprintf(stderr, "port_cfg_handler: must config dpdk.port_list first\n");
451         return 0;
452     }
453 
454     if (cfg->dpdk.port_cfgs == NULL) {
455         struct ff_port_cfg *pc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_port_cfg));
456         if (pc == NULL) {
457             fprintf(stderr, "port_cfg_handler malloc failed\n");
458             return 0;
459         }
460         // initialize lcore list and nb_lcores
461         int i;
462         for (i = 0; i < cfg->dpdk.nb_ports; ++i) {
463             uint16_t portid = cfg->dpdk.portid_list[i];
464 
465             struct ff_port_cfg *pconf = &pc[portid];
466             pconf->port_id = portid;
467             pconf->nb_lcores = ff_global_cfg.dpdk.nb_procs;
468             memcpy(pconf->lcore_list, ff_global_cfg.dpdk.proc_lcore,
469                    pconf->nb_lcores*sizeof(uint16_t));
470         }
471         cfg->dpdk.port_cfgs = pc;
472     }
473 
474     int portid;
475     int ret = sscanf(section, "port%d", &portid);
476     if (ret != 1) {
477         fprintf(stderr, "port_cfg_handler section[%s] error\n", section);
478         return 0;
479     }
480 
481     /* just return true if portid >= nb_ports because it has no effect */
482     if (portid > cfg->dpdk.max_portid) {
483         fprintf(stderr, "port_cfg_handler section[%s] bigger than max port id\n", section);
484         return 1;
485     }
486 
487     struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid];
488     if (cur->name == NULL) {
489         cur->name = strdup(section);
490         cur->port_id = portid;
491     }
492 
493     if (strcmp(name, "ifc_name") == 0) {
494         cur->ifname = strdup(value);
495     } else if (strcmp(name, "addr") == 0) {
496         cur->addr = strdup(value);
497     } else if (strcmp(name, "netmask") == 0) {
498         cur->netmask = strdup(value);
499     } else if (strcmp(name, "broadcast") == 0) {
500         cur->broadcast = strdup(value);
501     } else if (strcmp(name, "gateway") == 0) {
502         cur->gateway = strdup(value);
503     } else if (strcmp(name, "lcore_list") == 0) {
504         return parse_port_lcore_list(cur, value);
505     } else if (strcmp(name, "slave_port_list") == 0) {
506         return parse_port_slave_list(cur, value);
507     } else if (strcmp(name, "vip_addr") == 0) {
508         cur->vip_addr_str = strdup(value);
509         if (cur->vip_addr_str) {
510             return vip_cfg_handler(cur);
511         }
512     } else if (strcmp(name, "vip_ifname") == 0) {
513         cur->vip_ifname = strdup(value);
514     }
515 
516 #ifdef INET6
517     else if (0 == strcmp(name, "addr6")) {
518         cur->addr6_str = strdup(value);
519     } else if (0 == strcmp(name, "prefix_len")) {
520         cur->prefix_len = atoi(value);
521     } else if (0 == strcmp(name, "gateway6")) {
522         cur->gateway6_str = strdup(value);
523     } else if (strcmp(name, "vip_addr6") == 0) {
524         cur->vip_addr6_str = strdup(value);
525         if (cur->vip_addr6_str) {
526             return vip6_cfg_handler(cur);
527         }
528     } else if (0 == strcmp(name, "vip_prefix_len")) {
529         cur->vip_prefix_len = atoi(value);
530     }
531 #endif
532 
533     return 1;
534 }
535 
536 static int
vdev_cfg_handler(struct ff_config * cfg,const char * section,const char * name,const char * value)537 vdev_cfg_handler(struct ff_config *cfg, const char *section,
538     const char *name, const char *value) {
539 
540     if (cfg->dpdk.nb_vdev == 0) {
541         fprintf(stderr, "vdev_cfg_handler: must config dpdk.nb_vdev first\n");
542         return 0;
543     }
544 
545     if (cfg->dpdk.vdev_cfgs == NULL) {
546         struct ff_vdev_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_vdev_cfg));
547         if (vc == NULL) {
548             fprintf(stderr, "vdev_cfg_handler malloc failed\n");
549             return 0;
550         }
551         cfg->dpdk.vdev_cfgs = vc;
552     }
553 
554     int vdevid;
555     int ret = sscanf(section, "vdev%d", &vdevid);
556     if (ret != 1) {
557         fprintf(stderr, "vdev_cfg_handler section[%s] error\n", section);
558         return 0;
559     }
560 
561     /* just return true if vdevid >= nb_vdev because it has no effect */
562     if (vdevid > cfg->dpdk.nb_vdev) {
563         fprintf(stderr, "vdev_cfg_handler section[%s] bigger than max vdev id\n", section);
564         return 1;
565     }
566 
567     struct ff_vdev_cfg *cur = &cfg->dpdk.vdev_cfgs[vdevid];
568     if (cur->name == NULL) {
569         cur->name = strdup(section);
570         cur->vdev_id = vdevid;
571     }
572 
573     if (strcmp(name, "iface") == 0) {
574         cur->iface = strdup(value);
575     } else if (strcmp(name, "path") == 0) {
576         cur->path = strdup(value);
577     } else if (strcmp(name, "queues") == 0) {
578         cur->nb_queues = atoi(value);
579     } else if (strcmp(name, "queue_size") == 0) {
580         cur->queue_size = atoi(value);
581     } else if (strcmp(name, "mac") == 0) {
582         cur->mac = strdup(value);
583     } else if (strcmp(name, "cq") == 0) {
584         cur->nb_cq = atoi(value);
585     }
586 
587     return 1;
588 }
589 
590 static int
bond_cfg_handler(struct ff_config * cfg,const char * section,const char * name,const char * value)591 bond_cfg_handler(struct ff_config *cfg, const char *section,
592     const char *name, const char *value) {
593 
594     if (cfg->dpdk.nb_bond == 0) {
595         fprintf(stderr, "bond_cfg_handler: must config dpdk.nb_bond first\n");
596         return 0;
597     }
598 
599     if (cfg->dpdk.bond_cfgs == NULL) {
600         struct ff_bond_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_bond_cfg));
601         if (vc == NULL) {
602             fprintf(stderr, "ff_bond_cfg malloc failed\n");
603             return 0;
604         }
605         cfg->dpdk.bond_cfgs = vc;
606     }
607 
608     int bondid;
609     int ret = sscanf(section, "bond%d", &bondid);
610     if (ret != 1) {
611         fprintf(stderr, "bond_cfg_handler section[%s] error\n", section);
612         return 0;
613     }
614 
615     /* just return true if bondid >= nb_vdev because it has no effect */
616     if (bondid > cfg->dpdk.nb_bond) {
617         fprintf(stderr, "bond_cfg_handler section[%s] bigger than max bond id\n", section);
618         return 1;
619     }
620 
621     struct ff_bond_cfg *cur = &cfg->dpdk.bond_cfgs[bondid];
622     if (cur->name == NULL) {
623         cur->name = strdup(section);
624         cur->bond_id = bondid;
625     }
626 
627     if (strcmp(name, "mode") == 0) {
628         cur->mode = atoi(value);
629     } else if (strcmp(name, "slave") == 0) {
630         cur->slave = strdup(value);
631     } else if (strcmp(name, "primary") == 0) {
632         cur->primary = strdup(value);
633     } else if (strcmp(name, "socket_id") == 0) {
634         cur->socket_id = atoi(value);
635     } else if (strcmp(name, "mac") == 0) {
636         cur->bond_mac = strdup(value);
637     } else if (strcmp(name, "xmit_policy") == 0) {
638         cur->xmit_policy = strdup(value);
639     } else if (strcmp(name, "lsc_poll_period_ms") == 0) {
640         cur->lsc_poll_period_ms = atoi(value);
641     } else if (strcmp(name, "up_delay") == 0) {
642         cur->up_delay = atoi(value);
643     } else if (strcmp(name, "down_delay") == 0) {
644         cur->down_delay = atoi(value);
645     }
646 
647     return 1;
648 }
649 
650 static int
ini_parse_handler(void * user,const char * section,const char * name,const char * value)651 ini_parse_handler(void* user, const char* section, const char* name,
652     const char* value)
653 {
654     struct ff_config *pconfig = (struct ff_config*)user;
655 
656     printf("[%s]: %s=%s\n", section, name, value);
657 
658     #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
659     if (MATCH("dpdk", "channel")) {
660         pconfig->dpdk.nb_channel = atoi(value);
661     } else if (MATCH("dpdk", "memory")) {
662         pconfig->dpdk.memory = atoi(value);
663     } else if (MATCH("dpdk", "no_huge")) {
664         pconfig->dpdk.no_huge = atoi(value);
665     } else if (MATCH("dpdk", "lcore_mask")) {
666         pconfig->dpdk.lcore_mask = strdup(value);
667         return parse_lcore_mask(pconfig, pconfig->dpdk.lcore_mask);
668     } else if (MATCH("dpdk", "base_virtaddr")) {
669         pconfig->dpdk.base_virtaddr= strdup(value);
670     } else if (MATCH("dpdk", "file_prefix")) {
671         pconfig->dpdk.file_prefix = strdup(value);
672     } else if (MATCH("dpdk", "pci_whitelist")) {
673         pconfig->dpdk.pci_whitelist = strdup(value);
674     } else if (MATCH("dpdk", "port_list")) {
675         return parse_port_list(pconfig, value);
676     } else if (MATCH("dpdk", "nb_vdev")) {
677         pconfig->dpdk.nb_vdev = atoi(value);
678     } else if (MATCH("dpdk", "nb_bond")) {
679         pconfig->dpdk.nb_bond = atoi(value);
680     } else if (MATCH("dpdk", "promiscuous")) {
681         pconfig->dpdk.promiscuous = atoi(value);
682     } else if (MATCH("dpdk", "numa_on")) {
683         pconfig->dpdk.numa_on = atoi(value);
684     } else if (MATCH("dpdk", "tso")) {
685         pconfig->dpdk.tso = atoi(value);
686     } else if (MATCH("dpdk", "tx_csum_offoad_skip")) {
687         pconfig->dpdk.tx_csum_offoad_skip = atoi(value);
688     } else if (MATCH("dpdk", "vlan_strip")) {
689         pconfig->dpdk.vlan_strip = atoi(value);
690     } else if (MATCH("dpdk", "idle_sleep")) {
691         pconfig->dpdk.idle_sleep = atoi(value);
692     } else if (MATCH("dpdk", "pkt_tx_delay")) {
693         pconfig->dpdk.pkt_tx_delay = atoi(value);
694     } else if (MATCH("dpdk", "symmetric_rss")) {
695         pconfig->dpdk.symmetric_rss = atoi(value);
696     } else if (MATCH("kni", "enable")) {
697         pconfig->kni.enable= atoi(value);
698     } else if (MATCH("kni", "kni_action")) {
699         pconfig->kni.kni_action= strdup(value);
700     } else if (MATCH("kni", "method")) {
701         pconfig->kni.method= strdup(value);
702     } else if (MATCH("kni", "tcp_port")) {
703         pconfig->kni.tcp_port = strdup(value);
704     } else if (MATCH("kni", "udp_port")) {
705         pconfig->kni.udp_port= strdup(value);
706     } else if (strcmp(section, "freebsd.boot") == 0) {
707         if (strcmp(name, "hz") == 0) {
708             pconfig->freebsd.hz = atoi(value);
709         } else if (strcmp(name, "physmem") == 0) {
710             pconfig->freebsd.physmem = atol(value);
711         } else if (strcmp(name, "fd_reserve") == 0) {
712             pconfig->freebsd.fd_reserve = atoi(value);
713         } else if (strcmp(name, "memsz_MB") == 0) {
714             pconfig->freebsd.mem_size = atoi(value);
715         } else {
716             return freebsd_conf_handler(pconfig, "boot", name, value);
717         }
718     } else if (strcmp(section, "freebsd.sysctl") == 0) {
719         return freebsd_conf_handler(pconfig, "sysctl", name, value);
720     } else if (strncmp(section, "port", 4) == 0) {
721         return port_cfg_handler(pconfig, section, name, value);
722     } else if (strncmp(section, "vdev", 4) == 0) {
723         return vdev_cfg_handler(pconfig, section, name, value);
724     } else if (strncmp(section, "bond", 4) == 0) {
725         return bond_cfg_handler(pconfig, section, name, value);
726     } else if (strcmp(section, "pcap") == 0) {
727         if (strcmp(name, "snaplen") == 0) {
728             pconfig->pcap.snap_len = (uint16_t)atoi(value);
729         } else if (strcmp(name, "savelen") == 0) {
730             pconfig->pcap.save_len = (uint32_t)atoi(value);
731         } else if (strcmp(name, "enable") == 0) {
732             pconfig->pcap.enable = (uint16_t)atoi(value);
733         } else if (strcmp(name, "savepath") == 0) {
734             pconfig->pcap.save_path = strdup(value);
735         }
736     }
737 
738     return 1;
739 }
740 
741 static int
dpdk_args_setup(struct ff_config * cfg)742 dpdk_args_setup(struct ff_config *cfg)
743 {
744     int n = 0, i;
745     dpdk_argv[n++] = strdup("f-stack");
746     char temp[DPDK_CONFIG_MAXLEN] = {0}, temp2[DPDK_CONFIG_MAXLEN] = {0};
747 
748     if (cfg->dpdk.no_huge) {
749         dpdk_argv[n++] = strdup("--no-huge");
750     }
751     if (cfg->dpdk.proc_mask) {
752         sprintf(temp, "-c%s", cfg->dpdk.proc_mask);
753         dpdk_argv[n++] = strdup(temp);
754     }
755     if (cfg->dpdk.nb_channel) {
756         sprintf(temp, "-n%d", cfg->dpdk.nb_channel);
757         dpdk_argv[n++] = strdup(temp);
758     }
759     if (cfg->dpdk.memory) {
760         sprintf(temp, "-m%d", cfg->dpdk.memory);
761         dpdk_argv[n++] = strdup(temp);
762     }
763     if (cfg->dpdk.proc_type) {
764         sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type);
765         dpdk_argv[n++] = strdup(temp);
766     }
767     if (cfg->dpdk.base_virtaddr) {
768         sprintf(temp, "--base-virtaddr=%s", cfg->dpdk.base_virtaddr);
769         dpdk_argv[n++] = strdup(temp);
770     }
771     if (cfg->dpdk.file_prefix) {
772         sprintf(temp, "--file-prefix=container-%s", cfg->dpdk.file_prefix);
773         dpdk_argv[n++] = strdup(temp);
774     }
775     if (cfg->dpdk.pci_whitelist) {
776         char* token;
777         char* rest = cfg->dpdk.pci_whitelist;
778 
779         while ((token = strtok_r(rest, ",", &rest))){
780             sprintf(temp, "--pci-whitelist=%s", token);
781             dpdk_argv[n++] = strdup(temp);
782         }
783 
784     }
785 
786     if (cfg->dpdk.nb_vdev) {
787         for (i=0; i<cfg->dpdk.nb_vdev; i++) {
788             sprintf(temp, "--vdev=virtio_user%d,path=%s",
789                 cfg->dpdk.vdev_cfgs[i].vdev_id,
790                 cfg->dpdk.vdev_cfgs[i].path);
791             if (cfg->dpdk.vdev_cfgs[i].nb_queues) {
792                 sprintf(temp2, ",queues=%u",
793                     cfg->dpdk.vdev_cfgs[i].nb_queues);
794                 strcat(temp, temp2);
795             }
796             if (cfg->dpdk.vdev_cfgs[i].nb_cq) {
797                 sprintf(temp2, ",cq=%u",
798                     cfg->dpdk.vdev_cfgs[i].nb_cq);
799                 strcat(temp, temp2);
800             }
801             if (cfg->dpdk.vdev_cfgs[i].queue_size) {
802                 sprintf(temp2, ",queue_size=%u",
803                     cfg->dpdk.vdev_cfgs[i].queue_size);
804                 strcat(temp, temp2);
805             }
806             if (cfg->dpdk.vdev_cfgs[i].mac) {
807                 sprintf(temp2, ",mac=%s",
808                     cfg->dpdk.vdev_cfgs[i].mac);
809                 strcat(temp, temp2);
810             }
811             dpdk_argv[n++] = strdup(temp);
812         }
813         sprintf(temp, "--no-pci");
814         dpdk_argv[n++] = strdup(temp);
815         if (!cfg->dpdk.file_prefix) {
816             sprintf(temp, "--file-prefix=container");
817             dpdk_argv[n++] = strdup(temp);
818         }
819     }
820 
821     if (cfg->dpdk.nb_bond) {
822         for (i=0; i<cfg->dpdk.nb_bond; i++) {
823             sprintf(temp, "--vdev");
824             dpdk_argv[n++] = strdup(temp);
825             sprintf(temp, "net_bonding%d,mode=%d,slave=%s",
826                 cfg->dpdk.bond_cfgs[i].bond_id,
827                 cfg->dpdk.bond_cfgs[i].mode,
828                 cfg->dpdk.bond_cfgs[i].slave);
829 
830                 if (cfg->dpdk.bond_cfgs[i].primary) {
831                     sprintf(temp2, ",primary=%s",
832                         cfg->dpdk.bond_cfgs[i].primary);
833                     strcat(temp, temp2);
834                 }
835 
836                 if (cfg->dpdk.bond_cfgs[i].socket_id) {
837                     sprintf(temp2, ",socket_id=%d",
838                         cfg->dpdk.bond_cfgs[i].socket_id);
839                     strcat(temp, temp2);
840                 }
841 
842                 if (cfg->dpdk.bond_cfgs[i].bond_mac) {
843                     sprintf(temp2, ",mac=%s",
844                         cfg->dpdk.bond_cfgs[i].bond_mac);
845                     strcat(temp, temp2);
846                 }
847 
848                 if (cfg->dpdk.bond_cfgs[i].xmit_policy) {
849                     sprintf(temp2, ",xmit_policy=%s",
850                         cfg->dpdk.bond_cfgs[i].xmit_policy);
851                     strcat(temp, temp2);
852                 }
853 
854                 if (cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms) {
855                     sprintf(temp2, ",lsc_poll_period_ms=%d",
856                         cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms);
857                     strcat(temp, temp2);
858                 }
859 
860                 if (cfg->dpdk.bond_cfgs[i].up_delay) {
861                     sprintf(temp2, ",up_delay=%d",
862                         cfg->dpdk.bond_cfgs[i].up_delay);
863                     strcat(temp, temp2);
864                 }
865 
866                 if (cfg->dpdk.bond_cfgs[i].down_delay) {
867                     sprintf(temp2, ",down_delay=%d",
868                         cfg->dpdk.bond_cfgs[i].down_delay);
869                     strcat(temp, temp2);
870                 }
871                 dpdk_argv[n++] = strdup(temp);
872         }
873     }
874 
875     dpdk_argc = n;
876 
877     for (i=0; i<n; i++)
878         printf("%s ", dpdk_argv[i]);
879 
880     return n;
881 }
882 
883 static int
ff_parse_args(struct ff_config * cfg,int argc,char * const argv[])884 ff_parse_args(struct ff_config *cfg, int argc, char *const argv[])
885 {
886     int c;
887     int index = 0;
888     optind = 1;
889     while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
890         switch (c) {
891             case 'c':
892                 cfg->filename = strdup(optarg);
893                 break;
894             case 'p':
895                 cfg->dpdk.proc_id = atoi(optarg);
896                 break;
897             case 't':
898                 cfg->dpdk.proc_type = strdup(optarg);
899                 break;
900             default:
901                 return -1;
902         }
903     }
904 
905     if (cfg->dpdk.proc_type == NULL) {
906         cfg->dpdk.proc_type = strdup("auto");
907     }
908 
909     if (strcmp(cfg->dpdk.proc_type, "primary") &&
910         strcmp(cfg->dpdk.proc_type, "secondary") &&
911         strcmp(cfg->dpdk.proc_type, "auto")) {
912         printf("invalid proc-type:%s\n", cfg->dpdk.proc_type);
913         return -1;
914     }
915 
916     if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) {
917         printf("invalid proc_id:%d, use default 0\n", cfg->dpdk.proc_id);
918         cfg->dpdk.proc_id = 0;
919     }
920 
921     return 0;
922 }
923 
924 static int
ff_check_config(struct ff_config * cfg)925 ff_check_config(struct ff_config *cfg)
926 {
927     if(cfg->kni.enable && !cfg->kni.method) {
928         fprintf(stderr, "conf dpdk.method is necessary\n");
929         return -1;
930     }
931 
932     if(cfg->kni.method) {
933         if(strcasecmp(cfg->kni.method,"accept") &&
934             strcasecmp(cfg->kni.method,"reject")) {
935             fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n",
936                 cfg->kni.method);
937             return -1;
938         }
939     }
940 
941     if(cfg->kni.kni_action) {
942         if (strcasecmp(cfg->kni.kni_action,"alltokni") &&
943             strcasecmp(cfg->kni.kni_action,"alltoff") &&
944             strcasecmp(cfg->kni.kni_action,"default")){
945                 fprintf(stderr, "conf kni.kni_action[alltokni|alltoff|default] is error(%s)\n",
946                 cfg->kni.kni_action);
947                 return -1;
948         }
949     }
950 
951     if (cfg->pcap.save_len < PCAP_SAVE_MINLEN)
952         cfg->pcap.save_len = PCAP_SAVE_MINLEN;
953     if (cfg->pcap.snap_len < PCAP_SNAP_MINLEN)
954         cfg->pcap.snap_len = PCAP_SNAP_MINLEN;
955     if (cfg->pcap.save_path==NULL || strlen(cfg->pcap.save_path) ==0)
956         cfg->pcap.save_path = strdup(".");
957 
958     #define CHECK_VALID(n) \
959         do { \
960             if (!pc->n) { \
961                 fprintf(stderr, "port%d if config error: no %s\n", \
962                     pc->port_id, #n); \
963                 return -1; \
964             } \
965         } while (0)
966 
967     int i;
968     for (i = 0; i < cfg->dpdk.nb_ports; i++) {
969         uint16_t portid = cfg->dpdk.portid_list[i];
970         struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[portid];
971         CHECK_VALID(addr);
972         CHECK_VALID(netmask);
973         CHECK_VALID(broadcast);
974         CHECK_VALID(gateway);
975         // check if the lcores in lcore_list are enabled.
976         int k;
977         for (k = 0; k < pc->nb_lcores; k++) {
978             uint16_t lcore_id = pc->lcore_list[k];
979             if (uint16_binary_search(cfg->dpdk.proc_lcore, 0,
980                                      cfg->dpdk.nb_procs-1, lcore_id) < 0) {
981                 fprintf(stderr, "lcore %d is not enabled.\n", lcore_id);
982                 return -1;
983             }
984         }
985         /*
986          * only primary process process KNI, so if KNI enabled,
987          * primary lcore must stay in every enabled ports' lcore_list
988          */
989         if (cfg->kni.enable &&
990             strcmp(cfg->dpdk.proc_type, "primary") == 0) {
991             int found = 0;
992             int j;
993             uint16_t lcore_id = cfg->dpdk.proc_lcore[cfg->dpdk.proc_id];
994             for (j = 0; j < pc->nb_lcores; j++) {
995                 if (pc->lcore_list[j] == lcore_id) {
996                     found = 1;
997                 }
998             }
999             if (! found) {
1000                 fprintf(stderr,
1001                          "primary lcore %d should stay in port %d's lcore_list.\n",
1002                          lcore_id, pc->port_id);
1003                 return -1;
1004             }
1005         }
1006     }
1007 
1008     return 0;
1009 }
1010 
1011 static void
ff_default_config(struct ff_config * cfg)1012 ff_default_config(struct ff_config *cfg)
1013 {
1014     memset(cfg, 0, sizeof(struct ff_config));
1015 
1016     cfg->filename = DEFAULT_CONFIG_FILE;
1017 
1018     cfg->dpdk.proc_id = -1;
1019     cfg->dpdk.numa_on = 1;
1020     cfg->dpdk.promiscuous = 1;
1021     cfg->dpdk.pkt_tx_delay = BURST_TX_DRAIN_US;
1022 
1023     cfg->freebsd.hz = 100;
1024     cfg->freebsd.physmem = 1048576*256;
1025     cfg->freebsd.fd_reserve = 0;
1026     cfg->freebsd.mem_size = 256;
1027 }
1028 
1029 int
ff_load_config(int argc,char * const argv[])1030 ff_load_config(int argc, char *const argv[])
1031 {
1032     ff_default_config(&ff_global_cfg);
1033 
1034     int ret = ff_parse_args(&ff_global_cfg, argc, argv);
1035     if (ret < 0) {
1036         return ret;
1037     }
1038 
1039     ret = ini_parse(ff_global_cfg.filename, ini_parse_handler,
1040         &ff_global_cfg);
1041     if (ret != 0) {
1042         printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret);
1043         return -1;
1044     }
1045 
1046     if (ff_check_config(&ff_global_cfg)) {
1047         return -1;
1048     }
1049 
1050     if (dpdk_args_setup(&ff_global_cfg) <= 0) {
1051         return -1;
1052     }
1053 
1054     return 0;
1055 }
1056