xref: /f-stack/lib/ff_config.c (revision 3da8d17d)
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                     sprintf(buf, "%llx%s", (unsigned long long)1<<shift, zero);
121                     cfg->dpdk.proc_mask = strdup(buf);
122 		}
123                 count++;
124             }
125         }
126     }
127 
128     for (; i >= 0; i--)
129         if (coremask[i] != '0')
130             return 0;
131 
132     if (cfg->dpdk.proc_id >= count)
133         return 0;
134 
135     cfg->dpdk.nb_procs = count;
136 
137     return 1;
138 }
139 
140 static int
141 is_integer(const char *s)
142 {
143     if (*s == '-' || *s == '+')
144         s++;
145     if (*s < '0' || '9' < *s)
146         return 0;
147     s++;
148     while ('0' <= *s && *s <= '9')
149         s++;
150     return (*s == '\0');
151 }
152 
153 static int
154 freebsd_conf_handler(struct ff_config *cfg, const char *section,
155     const char *name, const char *value)
156 {
157     struct ff_freebsd_cfg *newconf, **cur;
158     newconf = (struct ff_freebsd_cfg *)malloc(sizeof(struct ff_freebsd_cfg));
159     if (newconf == NULL) {
160         fprintf(stderr, "freebsd conf malloc failed\n");
161         return 0;
162     }
163 
164     newconf->name = strdup(name);
165     newconf->str = strdup(value);
166 
167     if (strcmp(section, "boot") == 0) {
168         cur = &cfg->freebsd.boot;
169 
170         newconf->value = (void *)newconf->str;
171         newconf->vlen = strlen(value);
172     } else if (strcmp(section, "sysctl") == 0) {
173         cur = &cfg->freebsd.sysctl;
174 
175         if (is_integer(value)) {
176             if (strcmp(name, "kern.ipc.maxsockbuf") == 0) {
177                 long *p = (long *)malloc(sizeof(long));
178                 *p = atol(value);
179                 newconf->value = (void *)p;
180                 newconf->vlen = sizeof(*p);
181             } else {
182                  int *p = (int *)malloc(sizeof(int));
183                  *p = atoi(value);
184                  newconf->value = (void *)p;
185                  newconf->vlen = sizeof(*p);
186             }
187         } else {
188             newconf->value = (void *)newconf->str;
189             newconf->vlen = strlen(value);
190         }
191     } else {
192         fprintf(stderr, "freebsd conf section[%s] error\n", section);
193         return 0;
194     }
195 
196     if (*cur == NULL) {
197         newconf->next = NULL;
198         *cur = newconf;
199     } else {
200         newconf->next = (*cur)->next;
201         (*cur)->next = newconf;
202     }
203 
204     return 1;
205 }
206 // A recursive binary search function. It returns location of x in
207 // given array arr[l..r] is present, otherwise -1
208 static int
209 uint16_binary_search(uint16_t arr[], int l, int r, uint16_t x)
210 {
211     if (r >= l) {
212         int mid = l + (r - l)/2;
213 
214         // If the element is present at the middle itself
215         if (arr[mid] == x)  return mid;
216 
217         // If element is smaller than mid, then it can only be present
218         // in left subarray
219         if (arr[mid] > x) return uint16_binary_search(arr, l, mid-1, x);
220 
221         // Else the element can only be present in right subarray
222         return uint16_binary_search(arr, mid+1, r, x);
223     }
224 
225     // We reach here when element is not present in array
226     return -1;
227 }
228 
229 static int
230 uint16_cmp (const void * a, const void * b)
231 {
232     return ( *(uint16_t*)a - *(uint16_t*)b );
233 }
234 
235 static inline void
236 sort_uint16_array(uint16_t arr[], int n)
237 {
238     qsort(arr, n, sizeof(uint16_t), uint16_cmp);
239 }
240 
241 static inline char *
242 __strstrip(char *s)
243 {
244     char *end = s + strlen(s) - 1;
245     while(*s == ' ') s++;
246     for (; end >= s; --end) {
247         if (*end != ' ') break;
248     }
249     *(++end) = '\0';
250     return s;
251 }
252 
253 static int
254 __parse_config_list(uint16_t *arr, int *sz, const char *value) {
255     int i, j;
256     char input[4096];
257     char *tokens[128];
258     int nTokens = 0;
259     char *endptr;
260     int nr_ele = 0;
261     int max_ele = *sz;
262 
263     strncpy(input, value, 4096);
264     nTokens = rte_strsplit(input, sizeof(input), tokens, 128, ',');
265     for (i = 0; i < nTokens; i++) {
266         char *tok = tokens[i];
267         char *middle = strchr(tok, '-');
268         if (middle == NULL) {
269             tok = __strstrip(tok);
270             long v = strtol(tok, &endptr, 10);
271             if (*endptr != '\0') {
272                 fprintf(stderr, "%s is not a integer.", tok);
273                 return 0;
274             }
275             if (nr_ele > max_ele) {
276                 fprintf(stderr, "too many elements in list %s\n", value);
277                 return 0;
278             }
279             arr[nr_ele++] = (uint16_t)v;
280         } else {
281             *middle = '\0';
282             char *lbound = __strstrip(tok);
283             char *rbound = __strstrip(middle+1);
284             long lv = strtol(lbound, &endptr, 10);
285             if (*endptr != '\0') {
286                 fprintf(stderr, "%s is not a integer.", lbound);
287                 return 0;
288             }
289             long rv = strtol(rbound, &endptr, 10);
290             if (*endptr != '\0') {
291                 fprintf(stderr, "%s is not a integer.", rbound);
292                 return 0;
293             }
294             for (j = lv; j <= rv; ++j) {
295                 if (nr_ele > max_ele) {
296                     fprintf(stderr, "too many elements in list %s.\n", value);
297                     return 0;
298                 }
299                 arr[nr_ele++] = (uint16_t)j;
300             }
301         }
302     }
303     if (nr_ele <= 0) {
304         fprintf(stderr, "list %s is empty\n", value);
305         return 1;
306     }
307     sort_uint16_array(arr, nr_ele);
308     *sz = nr_ele;
309     return 1;
310 }
311 
312 static int
313 parse_port_lcore_list(struct ff_port_cfg *cfg, const char *v_str)
314 {
315     cfg->nb_lcores = DPDK_MAX_LCORE;
316     uint16_t *cores = cfg->lcore_list;
317     return __parse_config_list(cores, &cfg->nb_lcores, v_str);
318 }
319 
320 static int
321 parse_port_list(struct ff_config *cfg, const char *v_str)
322 {
323     int res;
324     uint16_t ports[RTE_MAX_ETHPORTS];
325     int sz = RTE_MAX_ETHPORTS;
326 
327     res = __parse_config_list(ports, &sz, v_str);
328     if (! res) return res;
329 
330     uint16_t *portid_list = malloc(sizeof(uint16_t)*sz);
331 
332     if (portid_list == NULL) {
333         fprintf(stderr, "parse_port_list malloc failed\n");
334         return 0;
335     }
336     memcpy(portid_list, ports, sz*sizeof(uint16_t));
337 
338     cfg->dpdk.portid_list = portid_list;
339     cfg->dpdk.nb_ports = sz;
340     cfg->dpdk.max_portid = portid_list[sz-1];
341     return res;
342 }
343 
344 static int
345 parse_port_slave_list(struct ff_port_cfg *cfg, const char *v_str)
346 {
347     int res;
348     uint16_t ports[RTE_MAX_ETHPORTS];
349     int sz = RTE_MAX_ETHPORTS;
350 
351     res = __parse_config_list(ports, &sz, v_str);
352     if (! res) return res;
353 
354     uint16_t *portid_list = malloc(sizeof(uint16_t)*sz);
355 
356     if (portid_list == NULL) {
357         fprintf(stderr, "parse_port_slave_list malloc failed\n");
358         return 0;
359     }
360     memcpy(portid_list, ports, sz*sizeof(uint16_t));
361 
362     cfg->slave_portid_list = portid_list;
363     cfg->nb_slaves = sz;
364 
365     return res;
366 }
367 
368 static int
369 port_cfg_handler(struct ff_config *cfg, const char *section,
370     const char *name, const char *value) {
371 
372     if (cfg->dpdk.nb_ports == 0) {
373         fprintf(stderr, "port_cfg_handler: must config dpdk.port_list first\n");
374         return 0;
375     }
376 
377     if (cfg->dpdk.port_cfgs == NULL) {
378         struct ff_port_cfg *pc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_port_cfg));
379         if (pc == NULL) {
380             fprintf(stderr, "port_cfg_handler malloc failed\n");
381             return 0;
382         }
383         // initialize lcore list and nb_lcores
384         int i;
385         for (i = 0; i < cfg->dpdk.nb_ports; ++i) {
386             uint16_t portid = cfg->dpdk.portid_list[i];
387 
388             struct ff_port_cfg *pconf = &pc[portid];
389             pconf->port_id = portid;
390             pconf->nb_lcores = ff_global_cfg.dpdk.nb_procs;
391             memcpy(pconf->lcore_list, ff_global_cfg.dpdk.proc_lcore,
392                    pconf->nb_lcores*sizeof(uint16_t));
393         }
394         cfg->dpdk.port_cfgs = pc;
395     }
396 
397     int portid;
398     int ret = sscanf(section, "port%d", &portid);
399     if (ret != 1) {
400         fprintf(stderr, "port_cfg_handler section[%s] error\n", section);
401         return 0;
402     }
403 
404     /* just return true if portid >= nb_ports because it has no effect */
405     if (portid > cfg->dpdk.max_portid) {
406         fprintf(stderr, "port_cfg_handler section[%s] bigger than max port id\n", section);
407         return 1;
408     }
409 
410     struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid];
411     if (cur->name == NULL) {
412         cur->name = strdup(section);
413         cur->port_id = portid;
414     }
415 
416     if (strcmp(name, "addr") == 0) {
417         cur->addr = strdup(value);
418     } else if (strcmp(name, "netmask") == 0) {
419         cur->netmask = strdup(value);
420     } else if (strcmp(name, "broadcast") == 0) {
421         cur->broadcast = strdup(value);
422     } else if (strcmp(name, "gateway") == 0) {
423         cur->gateway = strdup(value);
424     } else if (strcmp(name, "pcap") == 0) {
425         cur->pcap = strdup(value);
426     } else if (strcmp(name, "lcore_list") == 0) {
427         return parse_port_lcore_list(cur, value);
428     } else if (strcmp(name, "slave_port_list") == 0) {
429         return parse_port_slave_list(cur, value);
430     }
431 
432     return 1;
433 }
434 
435 static int
436 vdev_cfg_handler(struct ff_config *cfg, const char *section,
437     const char *name, const char *value) {
438 
439     if (cfg->dpdk.nb_vdev == 0) {
440         fprintf(stderr, "vdev_cfg_handler: must config dpdk.nb_vdev first\n");
441         return 0;
442     }
443 
444     if (cfg->dpdk.vdev_cfgs == NULL) {
445         struct ff_vdev_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_vdev_cfg));
446         if (vc == NULL) {
447             fprintf(stderr, "vdev_cfg_handler malloc failed\n");
448             return 0;
449         }
450         cfg->dpdk.vdev_cfgs = vc;
451     }
452 
453     int vdevid;
454     int ret = sscanf(section, "vdev%d", &vdevid);
455     if (ret != 1) {
456         fprintf(stderr, "vdev_cfg_handler section[%s] error\n", section);
457         return 0;
458     }
459 
460     /* just return true if vdevid >= nb_vdev because it has no effect */
461     if (vdevid > cfg->dpdk.nb_vdev) {
462         fprintf(stderr, "vdev_cfg_handler section[%s] bigger than max vdev id\n", section);
463         return 1;
464     }
465 
466     struct ff_vdev_cfg *cur = &cfg->dpdk.vdev_cfgs[vdevid];
467     if (cur->name == NULL) {
468         cur->name = strdup(section);
469         cur->vdev_id = vdevid;
470     }
471 
472     if (strcmp(name, "iface") == 0) {
473         cur->iface = strdup(value);
474     } else if (strcmp(name, "path") == 0) {
475         cur->path = strdup(value);
476     } else if (strcmp(name, "queues") == 0) {
477         cur->nb_queues = atoi(value);
478     } else if (strcmp(name, "queue_size") == 0) {
479         cur->queue_size = atoi(value);
480     } else if (strcmp(name, "mac") == 0) {
481         cur->mac = strdup(value);
482     } else if (strcmp(name, "cq") == 0) {
483         cur->nb_cq = atoi(value);
484     }
485 
486     return 1;
487 }
488 
489 static int
490 bond_cfg_handler(struct ff_config *cfg, const char *section,
491     const char *name, const char *value) {
492 
493     if (cfg->dpdk.nb_bond == 0) {
494         fprintf(stderr, "bond_cfg_handler: must config dpdk.nb_bond first\n");
495         return 0;
496     }
497 
498     if (cfg->dpdk.bond_cfgs == NULL) {
499         struct ff_bond_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_bond_cfg));
500         if (vc == NULL) {
501             fprintf(stderr, "ff_bond_cfg malloc failed\n");
502             return 0;
503         }
504         cfg->dpdk.bond_cfgs = vc;
505     }
506 
507     int bondid;
508     int ret = sscanf(section, "bond%d", &bondid);
509     if (ret != 1) {
510         fprintf(stderr, "bond_cfg_handler section[%s] error\n", section);
511         return 0;
512     }
513 
514     /* just return true if bondid >= nb_vdev because it has no effect */
515     if (bondid > cfg->dpdk.nb_bond) {
516         fprintf(stderr, "bond_cfg_handler section[%s] bigger than max bond id\n", section);
517         return 1;
518     }
519 
520     struct ff_bond_cfg *cur = &cfg->dpdk.bond_cfgs[bondid];
521     if (cur->name == NULL) {
522         cur->name = strdup(section);
523         cur->bond_id = bondid;
524     }
525 
526     if (strcmp(name, "mode") == 0) {
527         cur->mode = atoi(value);
528     } else if (strcmp(name, "slave") == 0) {
529         cur->slave = strdup(value);
530     } else if (strcmp(name, "primary") == 0) {
531         cur->primary = strdup(value);
532     } else if (strcmp(name, "socket_id") == 0) {
533         cur->socket_id = atoi(value);
534     } else if (strcmp(name, "mac") == 0) {
535         cur->bond_mac = strdup(value);
536     } else if (strcmp(name, "xmit_policy") == 0) {
537         cur->xmit_policy = strdup(value);
538     } else if (strcmp(name, "lsc_poll_period_ms") == 0) {
539         cur->lsc_poll_period_ms = atoi(value);
540     } else if (strcmp(name, "up_delay") == 0) {
541         cur->up_delay = atoi(value);
542     } else if (strcmp(name, "down_delay") == 0) {
543         cur->down_delay = atoi(value);
544     }
545 
546     return 1;
547 }
548 
549 static int
550 ini_parse_handler(void* user, const char* section, const char* name,
551     const char* value)
552 {
553     struct ff_config *pconfig = (struct ff_config*)user;
554 
555     printf("[%s]: %s=%s\n", section, name, value);
556 
557     #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
558     if (MATCH("dpdk", "channel")) {
559         pconfig->dpdk.nb_channel = atoi(value);
560     } else if (MATCH("dpdk", "memory")) {
561         pconfig->dpdk.memory = atoi(value);
562     } else if (MATCH("dpdk", "no_huge")) {
563         pconfig->dpdk.no_huge = atoi(value);
564     } else if (MATCH("dpdk", "lcore_mask")) {
565         pconfig->dpdk.lcore_mask = strdup(value);
566         return parse_lcore_mask(pconfig, pconfig->dpdk.lcore_mask);
567     } else if (MATCH("dpdk", "base_virtaddr")) {
568         pconfig->dpdk.base_virtaddr= strdup(value);
569     } else if (MATCH("dpdk", "port_list")) {
570         return parse_port_list(pconfig, value);
571     } else if (MATCH("dpdk", "nb_vdev")) {
572         pconfig->dpdk.nb_vdev = atoi(value);
573     } else if (MATCH("dpdk", "nb_bond")) {
574         pconfig->dpdk.nb_bond = atoi(value);
575     } else if (MATCH("dpdk", "promiscuous")) {
576         pconfig->dpdk.promiscuous = atoi(value);
577     } else if (MATCH("dpdk", "numa_on")) {
578         pconfig->dpdk.numa_on = atoi(value);
579     } else if (MATCH("dpdk", "tso")) {
580         pconfig->dpdk.tso = atoi(value);
581     } else if (MATCH("dpdk", "vlan_strip")) {
582         pconfig->dpdk.vlan_strip = atoi(value);
583     } else if (MATCH("dpdk", "idle_sleep")) {
584         pconfig->dpdk.idle_sleep = atoi(value);
585     } else if (MATCH("dpdk", "pkt_tx_delay")) {
586         pconfig->dpdk.pkt_tx_delay = atoi(value);
587     } else if (MATCH("kni", "enable")) {
588         pconfig->kni.enable= atoi(value);
589     } else if (MATCH("kni", "method")) {
590         pconfig->kni.method= strdup(value);
591     } else if (MATCH("kni", "tcp_port")) {
592         pconfig->kni.tcp_port = strdup(value);
593     } else if (MATCH("kni", "udp_port")) {
594         pconfig->kni.udp_port= strdup(value);
595     } else if (strcmp(section, "freebsd.boot") == 0) {
596         if (strcmp(name, "hz") == 0) {
597             pconfig->freebsd.hz = atoi(value);
598         } else if (strcmp(name, "physmem") == 0) {
599             pconfig->freebsd.physmem = atol(value);
600         } else if (strcmp(name, "fd_reserve") == 0) {
601             pconfig->freebsd.fd_reserve = atoi(value);
602         } else if (strcmp(name, "memsz_MB") == 0) {
603             pconfig->freebsd.mem_size = atoi(value);
604         } else {
605             return freebsd_conf_handler(pconfig, "boot", name, value);
606         }
607     } else if (strcmp(section, "freebsd.sysctl") == 0) {
608         return freebsd_conf_handler(pconfig, "sysctl", name, value);
609     } else if (strncmp(section, "port", 4) == 0) {
610         return port_cfg_handler(pconfig, section, name, value);
611     } else if (strncmp(section, "vdev", 4) == 0) {
612         return vdev_cfg_handler(pconfig, section, name, value);
613     } else if (strncmp(section, "bond", 4) == 0) {
614         return bond_cfg_handler(pconfig, section, name, value);
615     }
616 
617     return 1;
618 }
619 
620 static int
621 dpdk_args_setup(struct ff_config *cfg)
622 {
623     int n = 0, i;
624     dpdk_argv[n++] = strdup("f-stack");
625     char temp[DPDK_CONFIG_MAXLEN] = {0};
626 
627     if (cfg->dpdk.no_huge) {
628         dpdk_argv[n++] = strdup("--no-huge");
629     }
630     if (cfg->dpdk.proc_mask) {
631         sprintf(temp, "-c%s", cfg->dpdk.proc_mask);
632         dpdk_argv[n++] = strdup(temp);
633     }
634     if (cfg->dpdk.nb_channel) {
635         sprintf(temp, "-n%d", cfg->dpdk.nb_channel);
636         dpdk_argv[n++] = strdup(temp);
637     }
638     if (cfg->dpdk.memory) {
639         sprintf(temp, "-m%d", cfg->dpdk.memory);
640         dpdk_argv[n++] = strdup(temp);
641     }
642     if (cfg->dpdk.proc_type) {
643         sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type);
644         dpdk_argv[n++] = strdup(temp);
645     }
646     if (cfg->dpdk.base_virtaddr) {
647         sprintf(temp, "--base-virtaddr=%s", cfg->dpdk.base_virtaddr);
648         dpdk_argv[n++] = strdup(temp);
649     }
650 
651     if (cfg->dpdk.nb_vdev) {
652         for (i=0; i<cfg->dpdk.nb_vdev; i++) {
653             sprintf(temp, "--vdev=virtio_user%d,path=%s",
654                 cfg->dpdk.vdev_cfgs[i].vdev_id,
655                 cfg->dpdk.vdev_cfgs[i].path);
656             if (cfg->dpdk.vdev_cfgs[i].nb_queues) {
657                 sprintf(temp, "%s,queues=%u",
658                     temp, cfg->dpdk.vdev_cfgs[i].nb_queues);
659             }
660             if (cfg->dpdk.vdev_cfgs[i].nb_cq) {
661                 sprintf(temp, "%s,cq=%u",
662                     temp, cfg->dpdk.vdev_cfgs[i].nb_cq);
663             }
664             if (cfg->dpdk.vdev_cfgs[i].queue_size) {
665                 sprintf(temp, "%s,queue_size=%u",
666                     temp, cfg->dpdk.vdev_cfgs[i].queue_size);
667             }
668             if (cfg->dpdk.vdev_cfgs[i].mac) {
669                 sprintf(temp, "%s,mac=%s",
670                     temp, cfg->dpdk.vdev_cfgs[i].mac);
671             }
672             dpdk_argv[n++] = strdup(temp);
673         }
674         sprintf(temp, "--no-pci");
675         dpdk_argv[n++] = strdup(temp);
676         sprintf(temp, "--file-prefix=container");
677         dpdk_argv[n++] = strdup(temp);
678     }
679 
680     if (cfg->dpdk.nb_bond) {
681         for (i=0; i<cfg->dpdk.nb_bond; i++) {
682             sprintf(temp, "--vdev");
683             dpdk_argv[n++] = strdup(temp);
684             sprintf(temp, "net_bonding%d,mode=%d,slave=%s",
685                 cfg->dpdk.bond_cfgs[i].bond_id,
686                 cfg->dpdk.bond_cfgs[i].mode,
687                 cfg->dpdk.bond_cfgs[i].slave);
688 
689                 if (cfg->dpdk.bond_cfgs[i].primary) {
690                     sprintf(temp, "%s,primary=%s",
691                     temp, cfg->dpdk.bond_cfgs[i].primary);
692                 }
693 
694                 if (cfg->dpdk.bond_cfgs[i].socket_id) {
695                     sprintf(temp, "%s,socket_id=%d",
696                     temp, cfg->dpdk.bond_cfgs[i].socket_id);
697                 }
698 
699                 if (cfg->dpdk.bond_cfgs[i].bond_mac) {
700                     sprintf(temp, "%s,mac=%s",
701                     temp, cfg->dpdk.bond_cfgs[i].bond_mac);
702                 }
703 
704                 if (cfg->dpdk.bond_cfgs[i].xmit_policy) {
705                     sprintf(temp, "%s,xmit_policy=%s",
706                     temp, cfg->dpdk.bond_cfgs[i].xmit_policy);
707                 }
708 
709                 if (cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms) {
710                     sprintf(temp, "%s,lsc_poll_period_ms=%d",
711                     temp, cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms);
712                 }
713 
714                 if (cfg->dpdk.bond_cfgs[i].up_delay) {
715                     sprintf(temp, "%s,up_delay=%d",
716                     temp, cfg->dpdk.bond_cfgs[i].up_delay);
717                 }
718 
719                 if (cfg->dpdk.bond_cfgs[i].down_delay) {
720                     sprintf(temp, "%s,down_delay=%d",
721                     temp, cfg->dpdk.bond_cfgs[i].down_delay);
722                 }
723                 dpdk_argv[n++] = strdup(temp);
724         }
725     }
726 
727     dpdk_argc = n;
728 
729     for (i=0; i<n; i++)
730         printf("%s ", dpdk_argv[i]);
731 
732     return n;
733 }
734 
735 static int
736 ff_parse_args(struct ff_config *cfg, int argc, char *const argv[])
737 {
738     int c;
739     int index = 0;
740     optind = 1;
741     while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
742         switch (c) {
743             case 'c':
744                 cfg->filename = strdup(optarg);
745                 break;
746             case 'p':
747                 cfg->dpdk.proc_id = atoi(optarg);
748                 break;
749             case 't':
750                 cfg->dpdk.proc_type = strdup(optarg);
751                 break;
752             default:
753                 return -1;
754         }
755     }
756 
757     if (cfg->dpdk.proc_type == NULL) {
758         cfg->dpdk.proc_type = strdup("auto");
759     }
760 
761     if (strcmp(cfg->dpdk.proc_type, "primary") &&
762         strcmp(cfg->dpdk.proc_type, "secondary") &&
763         strcmp(cfg->dpdk.proc_type, "auto")) {
764         printf("invalid proc-type:%s\n", cfg->dpdk.proc_type);
765         return -1;
766     }
767 
768     if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) {
769         printf("invalid proc_id:%d, use default 0\n", cfg->dpdk.proc_id);
770         cfg->dpdk.proc_id = 0;
771     }
772 
773     return 0;
774 }
775 
776 static int
777 ff_check_config(struct ff_config *cfg)
778 {
779     if(cfg->kni.enable && !cfg->kni.method) {
780         fprintf(stderr, "conf dpdk.method is necessary\n");
781         return -1;
782     }
783 
784     if(cfg->kni.method) {
785         if(strcasecmp(cfg->kni.method,"accept") &&
786             strcasecmp(cfg->kni.method,"reject")) {
787             fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n",
788                 cfg->kni.method);
789             return -1;
790         }
791     }
792 
793     #define CHECK_VALID(n) \
794         do { \
795             if (!pc->n) { \
796                 fprintf(stderr, "port%d if config error: no %s\n", \
797                     pc->port_id, #n); \
798                 return -1; \
799             } \
800         } while (0)
801 
802     int i;
803     for (i = 0; i < cfg->dpdk.nb_ports; i++) {
804         uint16_t portid = cfg->dpdk.portid_list[i];
805         struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[portid];
806         CHECK_VALID(addr);
807         CHECK_VALID(netmask);
808         CHECK_VALID(broadcast);
809         CHECK_VALID(gateway);
810         // check if the lcores in lcore_list are enabled.
811         int k;
812         for (k = 0; k < pc->nb_lcores; k++) {
813             uint16_t lcore_id = pc->lcore_list[k];
814             if (uint16_binary_search(cfg->dpdk.proc_lcore, 0,
815                                      cfg->dpdk.nb_procs-1, lcore_id) < 0) {
816                 fprintf(stderr, "lcore %d is not enabled.\n", lcore_id);
817                 return -1;
818             }
819         }
820         /*
821          * only primary process process KNI, so if KNI enabled,
822          * primary lcore must stay in every enabled ports' lcore_list
823          */
824         if (cfg->kni.enable &&
825             strcmp(cfg->dpdk.proc_type, "primary") == 0) {
826             int found = 0;
827             int j;
828             uint16_t lcore_id = cfg->dpdk.proc_lcore[cfg->dpdk.proc_id];
829             for (j = 0; j < pc->nb_lcores; j++) {
830                 if (pc->lcore_list[j] == lcore_id) {
831                     found = 1;
832                 }
833             }
834             if (! found) {
835                 fprintf(stderr,
836                          "primary lcore %d should stay in port %d's lcore_list.\n",
837                          lcore_id, pc->port_id);
838                 return -1;
839             }
840         }
841     }
842 
843     return 0;
844 }
845 
846 static void
847 ff_default_config(struct ff_config *cfg)
848 {
849     memset(cfg, 0, sizeof(struct ff_config));
850 
851     cfg->filename = DEFAULT_CONFIG_FILE;
852 
853     cfg->dpdk.proc_id = -1;
854     cfg->dpdk.numa_on = 1;
855     cfg->dpdk.promiscuous = 1;
856     cfg->dpdk.pkt_tx_delay = BURST_TX_DRAIN_US;
857 
858     cfg->freebsd.hz = 100;
859     cfg->freebsd.physmem = 1048576*256;
860     cfg->freebsd.fd_reserve = 0;
861     cfg->freebsd.mem_size = 256;
862 }
863 
864 int
865 ff_load_config(int argc, char *const argv[])
866 {
867     ff_default_config(&ff_global_cfg);
868 
869     int ret = ff_parse_args(&ff_global_cfg, argc, argv);
870     if (ret < 0) {
871         return ret;
872     }
873 
874     ret = ini_parse(ff_global_cfg.filename, ini_parse_handler,
875         &ff_global_cfg);
876     if (ret != 0) {
877         printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret);
878         return -1;
879     }
880 
881     if (ff_check_config(&ff_global_cfg)) {
882         return -1;
883     }
884 
885     if (dpdk_args_setup(&ff_global_cfg) <= 0) {
886         return -1;
887     }
888 
889     return 0;
890 }
891