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