xref: /f-stack/lib/ff_config.c (revision 22ce4aff)
1 /*
2  * Copyright (C) 2017 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
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
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
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
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         return 0;
195     }
196 
197     if (*cur == NULL) {
198         newconf->next = NULL;
199         *cur = newconf;
200     } else {
201         newconf->next = (*cur)->next;
202         (*cur)->next = newconf;
203     }
204 
205     return 1;
206 }
207 // A recursive binary search function. It returns location of x in
208 // given array arr[l..r] is present, otherwise -1
209 static int
210 uint16_binary_search(uint16_t arr[], int l, int r, uint16_t x)
211 {
212     if (r >= l) {
213         int mid = l + (r - l)/2;
214 
215         // If the element is present at the middle itself
216         if (arr[mid] == x)  return mid;
217 
218         // If element is smaller than mid, then it can only be present
219         // in left subarray
220         if (arr[mid] > x) return uint16_binary_search(arr, l, mid-1, x);
221 
222         // Else the element can only be present in right subarray
223         return uint16_binary_search(arr, mid+1, r, x);
224     }
225 
226     // We reach here when element is not present in array
227     return -1;
228 }
229 
230 static int
231 uint16_cmp (const void * a, const void * b)
232 {
233     return ( *(uint16_t*)a - *(uint16_t*)b );
234 }
235 
236 static inline void
237 sort_uint16_array(uint16_t arr[], int n)
238 {
239     qsort(arr, n, sizeof(uint16_t), uint16_cmp);
240 }
241 
242 static inline char *
243 __strstrip(char *s)
244 {
245     char *end = s + strlen(s) - 1;
246     while(*s == ' ') s++;
247     for (; end >= s; --end) {
248         if (*end != ' ') break;
249     }
250     *(++end) = '\0';
251     return s;
252 }
253 
254 static int
255 __parse_config_list(uint16_t *arr, int *sz, const char *value) {
256     int i, j;
257     char input[4096];
258     char *tokens[128];
259     int nTokens = 0;
260     char *endptr;
261     int nr_ele = 0;
262     int max_ele = *sz;
263 
264     strncpy(input, value, sizeof(input) - 1);
265     nTokens = rte_strsplit(input, sizeof(input), tokens, 128, ',');
266     for (i = 0; i < nTokens; i++) {
267         char *tok = tokens[i];
268         char *middle = strchr(tok, '-');
269         if (middle == NULL) {
270             tok = __strstrip(tok);
271             long v = strtol(tok, &endptr, 10);
272             if (*endptr != '\0') {
273                 fprintf(stderr, "%s is not a integer.", tok);
274                 return 0;
275             }
276             if (nr_ele > max_ele) {
277                 fprintf(stderr, "too many elements in list %s\n", value);
278                 return 0;
279             }
280             arr[nr_ele++] = (uint16_t)v;
281         } else {
282             *middle = '\0';
283             char *lbound = __strstrip(tok);
284             char *rbound = __strstrip(middle+1);
285             long lv = strtol(lbound, &endptr, 10);
286             if (*endptr != '\0') {
287                 fprintf(stderr, "%s is not a integer.", lbound);
288                 return 0;
289             }
290             long rv = strtol(rbound, &endptr, 10);
291             if (*endptr != '\0') {
292                 fprintf(stderr, "%s is not a integer.", rbound);
293                 return 0;
294             }
295             for (j = lv; j <= rv; ++j) {
296                 if (nr_ele > max_ele) {
297                     fprintf(stderr, "too many elements in list %s.\n", value);
298                     return 0;
299                 }
300                 arr[nr_ele++] = (uint16_t)j;
301             }
302         }
303     }
304     if (nr_ele <= 0) {
305         fprintf(stderr, "list %s is empty\n", value);
306         return 1;
307     }
308     sort_uint16_array(arr, nr_ele);
309     *sz = nr_ele;
310     return 1;
311 }
312 
313 static int
314 parse_port_lcore_list(struct ff_port_cfg *cfg, const char *v_str)
315 {
316     cfg->nb_lcores = DPDK_MAX_LCORE;
317     uint16_t *cores = cfg->lcore_list;
318     return __parse_config_list(cores, &cfg->nb_lcores, v_str);
319 }
320 
321 static int
322 parse_port_list(struct ff_config *cfg, const char *v_str)
323 {
324     int res;
325     uint16_t ports[RTE_MAX_ETHPORTS];
326     int sz = RTE_MAX_ETHPORTS;
327 
328     res = __parse_config_list(ports, &sz, v_str);
329     if (! res) return res;
330 
331     uint16_t *portid_list = malloc(sizeof(uint16_t)*sz);
332 
333     if (portid_list == NULL) {
334         fprintf(stderr, "parse_port_list malloc failed\n");
335         return 0;
336     }
337     memcpy(portid_list, ports, sz*sizeof(uint16_t));
338 
339     cfg->dpdk.portid_list = portid_list;
340     cfg->dpdk.nb_ports = sz;
341     cfg->dpdk.max_portid = portid_list[sz-1];
342     return res;
343 }
344 
345 static int
346 parse_port_slave_list(struct ff_port_cfg *cfg, const char *v_str)
347 {
348     int res;
349     uint16_t ports[RTE_MAX_ETHPORTS];
350     int sz = RTE_MAX_ETHPORTS;
351 
352     res = __parse_config_list(ports, &sz, v_str);
353     if (! res) return res;
354 
355     uint16_t *portid_list = malloc(sizeof(uint16_t)*sz);
356 
357     if (portid_list == NULL) {
358         fprintf(stderr, "parse_port_slave_list malloc failed\n");
359         return 0;
360     }
361     memcpy(portid_list, ports, sz*sizeof(uint16_t));
362 
363     cfg->slave_portid_list = portid_list;
364     cfg->nb_slaves = sz;
365 
366     return res;
367 }
368 
369 static int
370 vip_cfg_hander(struct ff_port_cfg *cur)
371 {
372     //vip cfg
373     int ret;
374     char *vip_addr_array[VIP_MAX_NUM];
375 
376     ret = rte_strsplit(cur->vip_addr_str, strlen(cur->vip_addr_str), &vip_addr_array[0], VIP_MAX_NUM, ';');
377     if (ret <= 0) {
378         fprintf(stdout, "vip_cfg_hander nb_vip is 0, not set vip_addr or set invalid vip_addr %s\n",
379             cur->vip_addr_str);
380         return 1;
381     }
382 
383     cur->nb_vip = ret;
384 
385     cur->vip_addr_array = (char **)calloc(cur->nb_vip, sizeof(char *));
386     if (cur->vip_addr_array == NULL) {
387         fprintf(stderr, "vip_cfg_hander malloc failed\n");
388         goto err;
389     }
390 
391     memcpy(cur->vip_addr_array, vip_addr_array, cur->nb_vip * sizeof(char *));
392 
393     return 1;
394 
395 err:
396     cur->nb_vip = 0;
397     if (cur->vip_addr_array) {
398         free(cur->vip_addr_array);
399         cur->vip_addr_array = NULL;
400     }
401 
402     return 0;
403 }
404 
405 #ifdef INET6
406 static int
407 vip6_cfg_hander(struct ff_port_cfg *cur)
408 {
409     //vip6 cfg
410     int ret;
411     char *vip_addr6_array[VIP_MAX_NUM];
412 
413     ret = rte_strsplit(cur->vip_addr6_str, strlen(cur->vip_addr6_str),
414                                     &vip_addr6_array[0], VIP_MAX_NUM, ';');
415     if (ret == 0) {
416         fprintf(stdout, "vip6_cfg_hander nb_vip6 is 0, not set vip_addr6 or set invalid vip_addr6 %s\n",
417             cur->vip_addr6_str);
418         return 1;
419     }
420 
421     cur->nb_vip6 = ret;
422 
423     cur->vip_addr6_array = (char **) calloc(cur->nb_vip6, sizeof(char *));
424     if (cur->vip_addr6_array == NULL) {
425         fprintf(stderr, "port_cfg_handler malloc failed\n");
426         goto fail;
427     }
428 
429     memcpy(cur->vip_addr6_array, vip_addr6_array, cur->nb_vip6 * sizeof(char *));
430 
431     return 1;
432 
433 fail:
434     cur->nb_vip6 = 0;
435     if (cur->vip_addr6_array) {
436         free(cur->vip_addr6_array);
437         cur->vip_addr6_array = NULL;
438     }
439 
440     return 0;
441 }
442 #endif
443 
444 static int
445 port_cfg_handler(struct ff_config *cfg, const char *section,
446     const char *name, const char *value) {
447 
448     if (cfg->dpdk.nb_ports == 0) {
449         fprintf(stderr, "port_cfg_handler: must config dpdk.port_list first\n");
450         return 0;
451     }
452 
453     if (cfg->dpdk.port_cfgs == NULL) {
454         struct ff_port_cfg *pc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_port_cfg));
455         if (pc == NULL) {
456             fprintf(stderr, "port_cfg_handler malloc failed\n");
457             return 0;
458         }
459         // initialize lcore list and nb_lcores
460         int i;
461         for (i = 0; i < cfg->dpdk.nb_ports; ++i) {
462             uint16_t portid = cfg->dpdk.portid_list[i];
463 
464             struct ff_port_cfg *pconf = &pc[portid];
465             pconf->port_id = portid;
466             pconf->nb_lcores = ff_global_cfg.dpdk.nb_procs;
467             memcpy(pconf->lcore_list, ff_global_cfg.dpdk.proc_lcore,
468                    pconf->nb_lcores*sizeof(uint16_t));
469         }
470         cfg->dpdk.port_cfgs = pc;
471     }
472 
473     int portid;
474     int ret = sscanf(section, "port%d", &portid);
475     if (ret != 1) {
476         fprintf(stderr, "port_cfg_handler section[%s] error\n", section);
477         return 0;
478     }
479 
480     /* just return true if portid >= nb_ports because it has no effect */
481     if (portid > cfg->dpdk.max_portid) {
482         fprintf(stderr, "port_cfg_handler section[%s] bigger than max port id\n", section);
483         return 1;
484     }
485 
486     struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid];
487     if (cur->name == NULL) {
488         cur->name = strdup(section);
489         cur->port_id = portid;
490     }
491 
492     if (strcmp(name, "addr") == 0) {
493         cur->addr = strdup(value);
494     } else if (strcmp(name, "netmask") == 0) {
495         cur->netmask = strdup(value);
496     } else if (strcmp(name, "broadcast") == 0) {
497         cur->broadcast = strdup(value);
498     } else if (strcmp(name, "gateway") == 0) {
499         cur->gateway = strdup(value);
500     } else if (strcmp(name, "lcore_list") == 0) {
501         return parse_port_lcore_list(cur, value);
502     } else if (strcmp(name, "slave_port_list") == 0) {
503         return parse_port_slave_list(cur, value);
504     } else if (strcmp(name, "vip_addr") == 0) {
505         cur->vip_addr_str = strdup(value);
506         if (cur->vip_addr_str) {
507             return vip_cfg_hander(cur);
508         }
509     } else if (strcmp(name, "vip_ifname") == 0) {
510         cur->vip_ifname = strdup(value);
511     }
512 
513 #ifdef INET6
514     else if (0 == strcmp(name, "addr6")) {
515         cur->addr6_str = strdup(value);
516     } else if (0 == strcmp(name, "prefix_len")) {
517         cur->prefix_len = atoi(value);
518     } else if (0 == strcmp(name, "gateway6")) {
519         cur->gateway6_str = strdup(value);
520     } else if (strcmp(name, "vip_addr6") == 0) {
521         cur->vip_addr6_str = strdup(value);
522         if (cur->vip_addr_str) {
523             return vip6_cfg_hander(cur);
524         }
525     } else if (0 == strcmp(name, "vip_prefix_len")) {
526         cur->vip_prefix_len = atoi(value);
527     }
528 #endif
529 
530     return 1;
531 }
532 
533 static int
534 vdev_cfg_handler(struct ff_config *cfg, const char *section,
535     const char *name, const char *value) {
536 
537     if (cfg->dpdk.nb_vdev == 0) {
538         fprintf(stderr, "vdev_cfg_handler: must config dpdk.nb_vdev first\n");
539         return 0;
540     }
541 
542     if (cfg->dpdk.vdev_cfgs == NULL) {
543         struct ff_vdev_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_vdev_cfg));
544         if (vc == NULL) {
545             fprintf(stderr, "vdev_cfg_handler malloc failed\n");
546             return 0;
547         }
548         cfg->dpdk.vdev_cfgs = vc;
549     }
550 
551     int vdevid;
552     int ret = sscanf(section, "vdev%d", &vdevid);
553     if (ret != 1) {
554         fprintf(stderr, "vdev_cfg_handler section[%s] error\n", section);
555         return 0;
556     }
557 
558     /* just return true if vdevid >= nb_vdev because it has no effect */
559     if (vdevid > cfg->dpdk.nb_vdev) {
560         fprintf(stderr, "vdev_cfg_handler section[%s] bigger than max vdev id\n", section);
561         return 1;
562     }
563 
564     struct ff_vdev_cfg *cur = &cfg->dpdk.vdev_cfgs[vdevid];
565     if (cur->name == NULL) {
566         cur->name = strdup(section);
567         cur->vdev_id = vdevid;
568     }
569 
570     if (strcmp(name, "iface") == 0) {
571         cur->iface = strdup(value);
572     } else if (strcmp(name, "path") == 0) {
573         cur->path = strdup(value);
574     } else if (strcmp(name, "queues") == 0) {
575         cur->nb_queues = atoi(value);
576     } else if (strcmp(name, "queue_size") == 0) {
577         cur->queue_size = atoi(value);
578     } else if (strcmp(name, "mac") == 0) {
579         cur->mac = strdup(value);
580     } else if (strcmp(name, "cq") == 0) {
581         cur->nb_cq = atoi(value);
582     }
583 
584     return 1;
585 }
586 
587 static int
588 bond_cfg_handler(struct ff_config *cfg, const char *section,
589     const char *name, const char *value) {
590 
591     if (cfg->dpdk.nb_bond == 0) {
592         fprintf(stderr, "bond_cfg_handler: must config dpdk.nb_bond first\n");
593         return 0;
594     }
595 
596     if (cfg->dpdk.bond_cfgs == NULL) {
597         struct ff_bond_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_bond_cfg));
598         if (vc == NULL) {
599             fprintf(stderr, "ff_bond_cfg malloc failed\n");
600             return 0;
601         }
602         cfg->dpdk.bond_cfgs = vc;
603     }
604 
605     int bondid;
606     int ret = sscanf(section, "bond%d", &bondid);
607     if (ret != 1) {
608         fprintf(stderr, "bond_cfg_handler section[%s] error\n", section);
609         return 0;
610     }
611 
612     /* just return true if bondid >= nb_vdev because it has no effect */
613     if (bondid > cfg->dpdk.nb_bond) {
614         fprintf(stderr, "bond_cfg_handler section[%s] bigger than max bond id\n", section);
615         return 1;
616     }
617 
618     struct ff_bond_cfg *cur = &cfg->dpdk.bond_cfgs[bondid];
619     if (cur->name == NULL) {
620         cur->name = strdup(section);
621         cur->bond_id = bondid;
622     }
623 
624     if (strcmp(name, "mode") == 0) {
625         cur->mode = atoi(value);
626     } else if (strcmp(name, "slave") == 0) {
627         cur->slave = strdup(value);
628     } else if (strcmp(name, "primary") == 0) {
629         cur->primary = strdup(value);
630     } else if (strcmp(name, "socket_id") == 0) {
631         cur->socket_id = atoi(value);
632     } else if (strcmp(name, "mac") == 0) {
633         cur->bond_mac = strdup(value);
634     } else if (strcmp(name, "xmit_policy") == 0) {
635         cur->xmit_policy = strdup(value);
636     } else if (strcmp(name, "lsc_poll_period_ms") == 0) {
637         cur->lsc_poll_period_ms = atoi(value);
638     } else if (strcmp(name, "up_delay") == 0) {
639         cur->up_delay = atoi(value);
640     } else if (strcmp(name, "down_delay") == 0) {
641         cur->down_delay = atoi(value);
642     }
643 
644     return 1;
645 }
646 
647 static int
648 ini_parse_handler(void* user, const char* section, const char* name,
649     const char* value)
650 {
651     struct ff_config *pconfig = (struct ff_config*)user;
652 
653     printf("[%s]: %s=%s\n", section, name, value);
654 
655     #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
656     if (MATCH("dpdk", "channel")) {
657         pconfig->dpdk.nb_channel = atoi(value);
658     } else if (MATCH("dpdk", "memory")) {
659         pconfig->dpdk.memory = atoi(value);
660     } else if (MATCH("dpdk", "no_huge")) {
661         pconfig->dpdk.no_huge = atoi(value);
662     } else if (MATCH("dpdk", "lcore_mask")) {
663         pconfig->dpdk.lcore_mask = strdup(value);
664         return parse_lcore_mask(pconfig, pconfig->dpdk.lcore_mask);
665     } else if (MATCH("dpdk", "base_virtaddr")) {
666         pconfig->dpdk.base_virtaddr= strdup(value);
667     } else if (MATCH("dpdk", "file_prefix")) {
668         pconfig->dpdk.file_prefix = strdup(value);
669     } else if (MATCH("dpdk", "pci_whitelist")) {
670         pconfig->dpdk.pci_whitelist = strdup(value);
671     } else if (MATCH("dpdk", "port_list")) {
672         return parse_port_list(pconfig, value);
673     } else if (MATCH("dpdk", "nb_vdev")) {
674         pconfig->dpdk.nb_vdev = atoi(value);
675     } else if (MATCH("dpdk", "nb_bond")) {
676         pconfig->dpdk.nb_bond = atoi(value);
677     } else if (MATCH("dpdk", "promiscuous")) {
678         pconfig->dpdk.promiscuous = atoi(value);
679     } else if (MATCH("dpdk", "numa_on")) {
680         pconfig->dpdk.numa_on = atoi(value);
681     } else if (MATCH("dpdk", "tso")) {
682         pconfig->dpdk.tso = atoi(value);
683     } else if (MATCH("dpdk", "tx_csum_offoad_skip")) {
684         pconfig->dpdk.tx_csum_offoad_skip = atoi(value);
685     } else if (MATCH("dpdk", "vlan_strip")) {
686         pconfig->dpdk.vlan_strip = atoi(value);
687     } else if (MATCH("dpdk", "idle_sleep")) {
688         pconfig->dpdk.idle_sleep = atoi(value);
689     } else if (MATCH("dpdk", "pkt_tx_delay")) {
690         pconfig->dpdk.pkt_tx_delay = atoi(value);
691     } else if (MATCH("dpdk", "symmetric_rss")) {
692         pconfig->dpdk.symmetric_rss = atoi(value);
693     } else if (MATCH("kni", "enable")) {
694         pconfig->kni.enable= atoi(value);
695     } else if (MATCH("kni", "kni_action")) {
696         pconfig->kni.kni_action= strdup(value);
697     } else if (MATCH("kni", "method")) {
698         pconfig->kni.method= strdup(value);
699     } else if (MATCH("kni", "tcp_port")) {
700         pconfig->kni.tcp_port = strdup(value);
701     } else if (MATCH("kni", "udp_port")) {
702         pconfig->kni.udp_port= strdup(value);
703     } else if (strcmp(section, "freebsd.boot") == 0) {
704         if (strcmp(name, "hz") == 0) {
705             pconfig->freebsd.hz = atoi(value);
706         } else if (strcmp(name, "physmem") == 0) {
707             pconfig->freebsd.physmem = atol(value);
708         } else if (strcmp(name, "fd_reserve") == 0) {
709             pconfig->freebsd.fd_reserve = atoi(value);
710         } else if (strcmp(name, "memsz_MB") == 0) {
711             pconfig->freebsd.mem_size = atoi(value);
712         } else {
713             return freebsd_conf_handler(pconfig, "boot", name, value);
714         }
715     } else if (strcmp(section, "freebsd.sysctl") == 0) {
716         return freebsd_conf_handler(pconfig, "sysctl", name, value);
717     } else if (strncmp(section, "port", 4) == 0) {
718         return port_cfg_handler(pconfig, section, name, value);
719     } else if (strncmp(section, "vdev", 4) == 0) {
720         return vdev_cfg_handler(pconfig, section, name, value);
721     } else if (strncmp(section, "bond", 4) == 0) {
722         return bond_cfg_handler(pconfig, section, name, value);
723     } else if (strcmp(section, "pcap") == 0) {
724         if (strcmp(name, "snaplen") == 0) {
725             pconfig->pcap.snap_len = (uint16_t)atoi(value);
726         } else if (strcmp(name, "savelen") == 0) {
727             pconfig->pcap.save_len = (uint32_t)atoi(value);
728         } else if (strcmp(name, "enable") == 0) {
729             pconfig->pcap.enable = (uint16_t)atoi(value);
730         } else if (strcmp(name, "savepath") == 0) {
731             pconfig->pcap.save_path = strdup(value);
732         }
733     }
734 
735     return 1;
736 }
737 
738 static int
739 dpdk_args_setup(struct ff_config *cfg)
740 {
741     int n = 0, i;
742     dpdk_argv[n++] = strdup("f-stack");
743     char temp[DPDK_CONFIG_MAXLEN] = {0}, temp2[DPDK_CONFIG_MAXLEN] = {0};
744 
745     if (cfg->dpdk.no_huge) {
746         dpdk_argv[n++] = strdup("--no-huge");
747     }
748     if (cfg->dpdk.proc_mask) {
749         sprintf(temp, "-c%s", cfg->dpdk.proc_mask);
750         dpdk_argv[n++] = strdup(temp);
751     }
752     if (cfg->dpdk.nb_channel) {
753         sprintf(temp, "-n%d", cfg->dpdk.nb_channel);
754         dpdk_argv[n++] = strdup(temp);
755     }
756     if (cfg->dpdk.memory) {
757         sprintf(temp, "-m%d", cfg->dpdk.memory);
758         dpdk_argv[n++] = strdup(temp);
759     }
760     if (cfg->dpdk.proc_type) {
761         sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type);
762         dpdk_argv[n++] = strdup(temp);
763     }
764     if (cfg->dpdk.base_virtaddr) {
765         sprintf(temp, "--base-virtaddr=%s", cfg->dpdk.base_virtaddr);
766         dpdk_argv[n++] = strdup(temp);
767     }
768     if (cfg->dpdk.file_prefix) {
769         sprintf(temp, "--file-prefix=container-%s", cfg->dpdk.file_prefix);
770         dpdk_argv[n++] = strdup(temp);
771     }
772     if (cfg->dpdk.pci_whitelist) {
773         sprintf(temp, "--pci-whitelist=%s", cfg->dpdk.pci_whitelist);
774         dpdk_argv[n++] = strdup(temp);
775     }
776 
777     if (cfg->dpdk.nb_vdev) {
778         for (i=0; i<cfg->dpdk.nb_vdev; i++) {
779             sprintf(temp, "--vdev=virtio_user%d,path=%s",
780                 cfg->dpdk.vdev_cfgs[i].vdev_id,
781                 cfg->dpdk.vdev_cfgs[i].path);
782             if (cfg->dpdk.vdev_cfgs[i].nb_queues) {
783                 sprintf(temp2, ",queues=%u",
784                     cfg->dpdk.vdev_cfgs[i].nb_queues);
785                 strcat(temp, temp2);
786             }
787             if (cfg->dpdk.vdev_cfgs[i].nb_cq) {
788                 sprintf(temp2, ",cq=%u",
789                     cfg->dpdk.vdev_cfgs[i].nb_cq);
790                 strcat(temp, temp2);
791             }
792             if (cfg->dpdk.vdev_cfgs[i].queue_size) {
793                 sprintf(temp2, ",queue_size=%u",
794                     cfg->dpdk.vdev_cfgs[i].queue_size);
795                 strcat(temp, temp2);
796             }
797             if (cfg->dpdk.vdev_cfgs[i].mac) {
798                 sprintf(temp2, ",mac=%s",
799                     cfg->dpdk.vdev_cfgs[i].mac);
800                 strcat(temp, temp2);
801             }
802             dpdk_argv[n++] = strdup(temp);
803         }
804         sprintf(temp, "--no-pci");
805         dpdk_argv[n++] = strdup(temp);
806         if (!cfg->dpdk.file_prefix) {
807             sprintf(temp, "--file-prefix=container");
808             dpdk_argv[n++] = strdup(temp);
809         }
810     }
811 
812     if (cfg->dpdk.nb_bond) {
813         for (i=0; i<cfg->dpdk.nb_bond; i++) {
814             sprintf(temp, "--vdev");
815             dpdk_argv[n++] = strdup(temp);
816             sprintf(temp, "net_bonding%d,mode=%d,slave=%s",
817                 cfg->dpdk.bond_cfgs[i].bond_id,
818                 cfg->dpdk.bond_cfgs[i].mode,
819                 cfg->dpdk.bond_cfgs[i].slave);
820 
821                 if (cfg->dpdk.bond_cfgs[i].primary) {
822                     sprintf(temp2, ",primary=%s",
823                         cfg->dpdk.bond_cfgs[i].primary);
824                     strcat(temp, temp2);
825                 }
826 
827                 if (cfg->dpdk.bond_cfgs[i].socket_id) {
828                     sprintf(temp2, ",socket_id=%d",
829                         cfg->dpdk.bond_cfgs[i].socket_id);
830                     strcat(temp, temp2);
831                 }
832 
833                 if (cfg->dpdk.bond_cfgs[i].bond_mac) {
834                     sprintf(temp2, ",mac=%s",
835                         cfg->dpdk.bond_cfgs[i].bond_mac);
836                     strcat(temp, temp2);
837                 }
838 
839                 if (cfg->dpdk.bond_cfgs[i].xmit_policy) {
840                     sprintf(temp2, ",xmit_policy=%s",
841                         cfg->dpdk.bond_cfgs[i].xmit_policy);
842                     strcat(temp, temp2);
843                 }
844 
845                 if (cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms) {
846                     sprintf(temp2, ",lsc_poll_period_ms=%d",
847                         cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms);
848                     strcat(temp, temp2);
849                 }
850 
851                 if (cfg->dpdk.bond_cfgs[i].up_delay) {
852                     sprintf(temp2, ",up_delay=%d",
853                         cfg->dpdk.bond_cfgs[i].up_delay);
854                     strcat(temp, temp2);
855                 }
856 
857                 if (cfg->dpdk.bond_cfgs[i].down_delay) {
858                     sprintf(temp2, ",down_delay=%d",
859                         cfg->dpdk.bond_cfgs[i].down_delay);
860                     strcat(temp, temp2);
861                 }
862                 dpdk_argv[n++] = strdup(temp);
863         }
864     }
865 
866     dpdk_argc = n;
867 
868     for (i=0; i<n; i++)
869         printf("%s ", dpdk_argv[i]);
870 
871     return n;
872 }
873 
874 static int
875 ff_parse_args(struct ff_config *cfg, int argc, char *const argv[])
876 {
877     int c;
878     int index = 0;
879     optind = 1;
880     while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
881         switch (c) {
882             case 'c':
883                 cfg->filename = strdup(optarg);
884                 break;
885             case 'p':
886                 cfg->dpdk.proc_id = atoi(optarg);
887                 break;
888             case 't':
889                 cfg->dpdk.proc_type = strdup(optarg);
890                 break;
891             default:
892                 return -1;
893         }
894     }
895 
896     if (cfg->dpdk.proc_type == NULL) {
897         cfg->dpdk.proc_type = strdup("auto");
898     }
899 
900     if (strcmp(cfg->dpdk.proc_type, "primary") &&
901         strcmp(cfg->dpdk.proc_type, "secondary") &&
902         strcmp(cfg->dpdk.proc_type, "auto")) {
903         printf("invalid proc-type:%s\n", cfg->dpdk.proc_type);
904         return -1;
905     }
906 
907     if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) {
908         printf("invalid proc_id:%d, use default 0\n", cfg->dpdk.proc_id);
909         cfg->dpdk.proc_id = 0;
910     }
911 
912     return 0;
913 }
914 
915 static int
916 ff_check_config(struct ff_config *cfg)
917 {
918     if(cfg->kni.enable && !cfg->kni.method) {
919         fprintf(stderr, "conf dpdk.method is necessary\n");
920         return -1;
921     }
922 
923     if(cfg->kni.method) {
924         if(strcasecmp(cfg->kni.method,"accept") &&
925             strcasecmp(cfg->kni.method,"reject")) {
926             fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n",
927                 cfg->kni.method);
928             return -1;
929         }
930     }
931 
932     if(cfg->kni.kni_action) {
933         if (strcasecmp(cfg->kni.kni_action,"alltokni") &&
934             strcasecmp(cfg->kni.kni_action,"alltoff") &&
935             strcasecmp(cfg->kni.kni_action,"default")){
936                 fprintf(stderr, "conf kni.kni_action[alltokni|alltoff|default] is error(%s)\n",
937                 cfg->kni.kni_action);
938                 return -1;
939         }
940     }
941 
942     if (cfg->pcap.save_len < PCAP_SAVE_MINLEN)
943         cfg->pcap.save_len = PCAP_SAVE_MINLEN;
944     if (cfg->pcap.snap_len < PCAP_SNAP_MINLEN)
945         cfg->pcap.snap_len = PCAP_SNAP_MINLEN;
946     if (cfg->pcap.save_path==NULL || strlen(cfg->pcap.save_path) ==0)
947         cfg->pcap.save_path = strdup(".");
948 
949     #define CHECK_VALID(n) \
950         do { \
951             if (!pc->n) { \
952                 fprintf(stderr, "port%d if config error: no %s\n", \
953                     pc->port_id, #n); \
954                 return -1; \
955             } \
956         } while (0)
957 
958     int i;
959     for (i = 0; i < cfg->dpdk.nb_ports; i++) {
960         uint16_t portid = cfg->dpdk.portid_list[i];
961         struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[portid];
962         CHECK_VALID(addr);
963         CHECK_VALID(netmask);
964         CHECK_VALID(broadcast);
965         CHECK_VALID(gateway);
966         // check if the lcores in lcore_list are enabled.
967         int k;
968         for (k = 0; k < pc->nb_lcores; k++) {
969             uint16_t lcore_id = pc->lcore_list[k];
970             if (uint16_binary_search(cfg->dpdk.proc_lcore, 0,
971                                      cfg->dpdk.nb_procs-1, lcore_id) < 0) {
972                 fprintf(stderr, "lcore %d is not enabled.\n", lcore_id);
973                 return -1;
974             }
975         }
976         /*
977          * only primary process process KNI, so if KNI enabled,
978          * primary lcore must stay in every enabled ports' lcore_list
979          */
980         if (cfg->kni.enable &&
981             strcmp(cfg->dpdk.proc_type, "primary") == 0) {
982             int found = 0;
983             int j;
984             uint16_t lcore_id = cfg->dpdk.proc_lcore[cfg->dpdk.proc_id];
985             for (j = 0; j < pc->nb_lcores; j++) {
986                 if (pc->lcore_list[j] == lcore_id) {
987                     found = 1;
988                 }
989             }
990             if (! found) {
991                 fprintf(stderr,
992                          "primary lcore %d should stay in port %d's lcore_list.\n",
993                          lcore_id, pc->port_id);
994                 return -1;
995             }
996         }
997     }
998 
999     return 0;
1000 }
1001 
1002 static void
1003 ff_default_config(struct ff_config *cfg)
1004 {
1005     memset(cfg, 0, sizeof(struct ff_config));
1006 
1007     cfg->filename = DEFAULT_CONFIG_FILE;
1008 
1009     cfg->dpdk.proc_id = -1;
1010     cfg->dpdk.numa_on = 1;
1011     cfg->dpdk.promiscuous = 1;
1012     cfg->dpdk.pkt_tx_delay = BURST_TX_DRAIN_US;
1013 
1014     cfg->freebsd.hz = 100;
1015     cfg->freebsd.physmem = 1048576*256;
1016     cfg->freebsd.fd_reserve = 0;
1017     cfg->freebsd.mem_size = 256;
1018 }
1019 
1020 int
1021 ff_load_config(int argc, char *const argv[])
1022 {
1023     ff_default_config(&ff_global_cfg);
1024 
1025     int ret = ff_parse_args(&ff_global_cfg, argc, argv);
1026     if (ret < 0) {
1027         return ret;
1028     }
1029 
1030     ret = ini_parse(ff_global_cfg.filename, ini_parse_handler,
1031         &ff_global_cfg);
1032     if (ret != 0) {
1033         printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret);
1034         return -1;
1035     }
1036 
1037     if (ff_check_config(&ff_global_cfg)) {
1038         return -1;
1039     }
1040 
1041     if (dpdk_args_setup(&ff_global_cfg) <= 0) {
1042         return -1;
1043     }
1044 
1045     return 0;
1046 }
1047