xref: /f-stack/lib/ff_config.c (revision 8cf1d457)
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 
35 #include "ff_config.h"
36 #include "ff_ini_parser.h"
37 
38 #define DEFAULT_CONFIG_FILE   "config.ini"
39 
40 #define BITS_PER_HEX 4
41 
42 struct ff_config ff_global_cfg;
43 int dpdk_argc;
44 char *dpdk_argv[DPDK_CONFIG_NUM + 1];
45 
46 char* const short_options = "c:t:p:";
47 struct option long_options[] = {
48     { "conf", 1, NULL, 'c'},
49     { "proc-type", 1, NULL, 't'},
50     { "proc-id", 1, NULL, 'p'},
51     { 0, 0, 0, 0},
52 };
53 
54 static int
55 xdigit2val(unsigned char c)
56 {
57     int val;
58 
59     if (isdigit(c))
60         val = c - '0';
61     else if (isupper(c))
62         val = c - 'A' + 10;
63     else
64         val = c - 'a' + 10;
65     return val;
66 }
67 
68 static int
69 parse_lcore_mask(struct ff_config *cfg, const char *coremask)
70 {
71     int i, j, idx = 0;
72     unsigned count = 0;
73     char c;
74     int val;
75     uint16_t *proc_lcore;
76     char buf[RTE_MAX_LCORE] = {0};
77 
78     if (coremask == NULL)
79         return 0;
80 
81     cfg->dpdk.proc_lcore = (uint16_t *)calloc(RTE_MAX_LCORE, sizeof(uint16_t));
82     if (cfg->dpdk.proc_lcore == NULL) {
83         fprintf(stderr, "parse_lcore_mask malloc failed\n");
84         return 0;
85     }
86     proc_lcore = cfg->dpdk.proc_lcore;
87 
88     /*
89      * Remove all blank characters ahead and after.
90      * Remove 0x/0X if exists.
91      */
92     while (isblank(*coremask))
93         coremask++;
94     if (coremask[0] == '0' && ((coremask[1] == 'x')
95         || (coremask[1] == 'X')))
96         coremask += 2;
97 
98     i = strlen(coremask);
99     while ((i > 0) && isblank(coremask[i - 1]))
100         i--;
101 
102     if (i == 0)
103         return 0;
104 
105     for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) {
106         c = coremask[i];
107         if (isxdigit(c) == 0) {
108             return 0;
109         }
110         val = xdigit2val(c);
111         for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++) {
112             if ((1 << j) & val) {
113                 proc_lcore[count] = idx;
114                 if (cfg->dpdk.proc_id == count) {
115                     sprintf(buf, "%x", 1<<idx);
116                     cfg->dpdk.proc_mask = strdup(buf);
117                 }
118                 count++;
119             }
120         }
121     }
122 
123     for (; i >= 0; i--)
124         if (coremask[i] != '0')
125             return 0;
126 
127     if (cfg->dpdk.proc_id >= count)
128         return 0;
129 
130     cfg->dpdk.nb_procs = count;
131 
132     return 1;
133 }
134 
135 static int
136 is_integer(const char *s)
137 {
138     if (*s == '-' || *s == '+')
139         s++;
140     if (*s < '0' || '9' < *s)
141         return 0;
142     s++;
143     while ('0' <= *s && *s <= '9')
144         s++;
145     return (*s == '\0');
146 }
147 
148 static int
149 freebsd_conf_handler(struct ff_config *cfg, const char *section,
150     const char *name, const char *value)
151 {
152     struct ff_freebsd_cfg *newconf, **cur;
153     newconf = (struct ff_freebsd_cfg *)malloc(sizeof(struct ff_freebsd_cfg));
154     if (newconf == NULL) {
155         fprintf(stderr, "freebsd conf malloc failed\n");
156         return 0;
157     }
158 
159     newconf->name = strdup(name);
160     newconf->str = strdup(value);
161 
162     if (strcmp(section, "boot") == 0) {
163         cur = &cfg->freebsd.boot;
164 
165         newconf->value = (void *)newconf->str;
166         newconf->vlen = strlen(value);
167     } else if (strcmp(section, "sysctl") == 0) {
168         cur = &cfg->freebsd.sysctl;
169 
170         if (is_integer(value)) {
171             int *p = (int *)malloc(sizeof(int));
172             *p = atoi(value);
173             newconf->value = (void *)p;
174             newconf->vlen = sizeof(*p);
175         } else {
176             newconf->value = (void *)newconf->str;
177             newconf->vlen = strlen(value);
178         }
179     } else {
180         fprintf(stderr, "freebsd conf section[%s] error\n", section);
181         return 0;
182     }
183 
184     if (*cur == NULL) {
185         *cur = newconf;
186     } else {
187         (*cur)->next = newconf;
188         newconf->next = NULL;
189     }
190 
191     return 1;
192 }
193 
194 static int
195 port_cfg_handler(struct ff_config *cfg, const char *section,
196     const char *name, const char *value) {
197 
198     if (cfg->dpdk.nb_ports == 0) {
199         fprintf(stderr, "port_cfg_handler: must config dpdk.nb_ports first\n");
200         return 0;
201     }
202 
203     if (cfg->dpdk.port_cfgs == NULL) {
204         struct ff_port_cfg *pc = calloc(cfg->dpdk.nb_ports, sizeof(struct ff_port_cfg));
205         if (pc == NULL) {
206             fprintf(stderr, "port_cfg_handler malloc failed\n");
207             return 0;
208         }
209 
210         cfg->dpdk.port_cfgs = pc;
211     }
212 
213     int portid;
214     int ret = sscanf(section, "port%d", &portid);
215     if (ret != 1) {
216         fprintf(stderr, "port_cfg_handler section[%s] error\n", section);
217         return 0;
218     }
219 
220     /* just return true if portid >= nb_ports because it has no effect */
221     if (portid >= cfg->dpdk.nb_ports) {
222         fprintf(stderr, "port_cfg_handler section[%s] max than nb_ports\n", section);
223         return 1;
224     }
225 
226     struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid];
227     if (cur->name == NULL) {
228         cur->name = strdup(section);
229         cur->port_id = portid;
230     }
231 
232     if (strcmp(name, "addr") == 0) {
233         cur->addr = strdup(value);
234     } else if (strcmp(name, "netmask") == 0) {
235         cur->netmask = strdup(value);
236     } else if (strcmp(name, "broadcast") == 0) {
237         cur->broadcast = strdup(value);
238     } else if (strcmp(name, "gateway") == 0) {
239         cur->gateway = strdup(value);
240     } else if (strcmp(name, "pcap") == 0) {
241         cur->pcap = strdup(value);
242     }
243 
244     return 1;
245 }
246 
247 static int
248 ini_parse_handler(void* user, const char* section, const char* name,
249     const char* value)
250 {
251     struct ff_config *pconfig = (struct ff_config*)user;
252 
253     printf("[%s]: %s=%s\n", section, name, value);
254 
255     #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
256     if (MATCH("dpdk", "channel")) {
257         pconfig->dpdk.nb_channel = atoi(value);
258     } else if (MATCH("dpdk", "memory")) {
259         pconfig->dpdk.memory = atoi(value);
260     } else if (MATCH("dpdk", "no_huge")) {
261         pconfig->dpdk.no_huge = atoi(value);
262     } else if (MATCH("dpdk", "lcore_mask")) {
263         pconfig->dpdk.lcore_mask = strdup(value);
264         return parse_lcore_mask(pconfig, pconfig->dpdk.lcore_mask);
265     } else if (MATCH("dpdk", "port_mask")) {
266         pconfig->dpdk.port_mask = atoi(value);
267     } else if (MATCH("dpdk", "nb_ports")) {
268         pconfig->dpdk.nb_ports = atoi(value);
269     } else if (MATCH("dpdk", "promiscuous")) {
270         pconfig->dpdk.promiscuous = atoi(value);
271     } else if (MATCH("dpdk", "numa_on")) {
272         pconfig->dpdk.numa_on = atoi(value);
273     } else if (MATCH("dpdk", "tso")) {
274         pconfig->dpdk.tso = atoi(value);
275     } else if (MATCH("dpdk", "vlan_strip")) {
276         pconfig->dpdk.vlan_strip = atoi(value);
277     } else if (MATCH("kni", "enable")) {
278         pconfig->kni.enable= atoi(value);
279     } else if (MATCH("kni", "method")) {
280         pconfig->kni.method= strdup(value);
281     } else if (MATCH("kni", "tcp_port")) {
282         pconfig->kni.tcp_port = strdup(value);
283     } else if (MATCH("kni", "udp_port")) {
284         pconfig->kni.udp_port= strdup(value);
285     } else if (strcmp(section, "freebsd.boot") == 0) {
286         if (strcmp(name, "hz") == 0) {
287             pconfig->freebsd.hz = atoi(value);
288         } else if (strcmp(name, "physmem") == 0) {
289             pconfig->freebsd.physmem = atol(value);
290         } else if (strcmp(name, "fd_reserve") == 0) {
291             pconfig->freebsd.fd_reserve = atoi(value);
292         } else {
293             return freebsd_conf_handler(pconfig, "boot", name, value);
294         }
295     } else if (strcmp(section, "freebsd.sysctl") == 0) {
296         return freebsd_conf_handler(pconfig, "sysctl", name, value);
297     } else if (strncmp(section, "port", 4) == 0) {
298         return port_cfg_handler(pconfig, section, name, value);
299     }
300 
301     return 1;
302 }
303 
304 static int
305 dpdk_args_setup(struct ff_config *cfg)
306 {
307     int n = 0, i;
308     dpdk_argv[n++] = strdup("f-stack");
309     char temp[DPDK_CONFIG_MAXLEN] = {0};
310 
311     if (cfg->dpdk.no_huge) {
312         dpdk_argv[n++] = strdup("--no-huge");
313     }
314     if (cfg->dpdk.proc_mask) {
315         sprintf(temp, "-c%s", cfg->dpdk.proc_mask);
316         dpdk_argv[n++] = strdup(temp);
317     }
318     if (cfg->dpdk.nb_channel) {
319         sprintf(temp, "-n%d", cfg->dpdk.nb_channel);
320         dpdk_argv[n++] = strdup(temp);
321     }
322     if (cfg->dpdk.memory) {
323         sprintf(temp, "-m%d", cfg->dpdk.memory);
324         dpdk_argv[n++] = strdup(temp);
325     }
326     if (cfg->dpdk.proc_type) {
327         sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type);
328         dpdk_argv[n++] = strdup(temp);
329     }
330 
331     dpdk_argc = n;
332 
333     return n;
334 }
335 
336 static int
337 ff_parse_args(struct ff_config *cfg, int argc, char *const argv[])
338 {
339     int c;
340     int index = 0;
341     optind = 1;
342     while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
343         switch (c) {
344             case 'c':
345                 cfg->filename = strdup(optarg);
346                 break;
347             case 'p':
348                 cfg->dpdk.proc_id = atoi(optarg);
349                 break;
350             case 't':
351                 cfg->dpdk.proc_type = strdup(optarg);
352                 break;
353             default:
354                 return -1;
355         }
356     }
357 
358     if (cfg->dpdk.proc_type == NULL ||
359         (strcmp(cfg->dpdk.proc_type, "primary") &&
360         strcmp(cfg->dpdk.proc_type, "secondary"))) {
361         printf("invalid proc-type\n");
362         return -1;
363     }
364 
365     if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) {
366         printf("proc_id:%d is too large\n", cfg->dpdk.proc_id);
367         return -1;
368     }
369 
370     return 0;
371 }
372 
373 static int
374 ff_check_config(struct ff_config *cfg)
375 {
376     if(cfg->kni.enable && !cfg->kni.method) {
377         fprintf(stderr, "conf dpdk.method is necessary\n");
378         return -1;
379     }
380 
381     if(cfg->kni.method) {
382         if(strcasecmp(cfg->kni.method,"accept") &&
383             strcasecmp(cfg->kni.method,"reject")) {
384             fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n",
385                 cfg->kni.method);
386             return -1;
387         }
388     }
389 
390     #define CHECK_VALID(n) \
391         do { \
392             if (!pc->n) { \
393                 fprintf(stderr, "port%d if config error: no %s\n", \
394                     pc->port_id, #n); \
395                 return -1; \
396             } \
397         } while (0)
398 
399     int i;
400     for (i = 0; i < cfg->dpdk.nb_ports; i++) {
401         struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[i];
402         CHECK_VALID(addr);
403         CHECK_VALID(netmask);
404         CHECK_VALID(broadcast);
405         CHECK_VALID(gateway);
406     }
407 
408     return 0;
409 }
410 
411 static void
412 ff_default_config(struct ff_config *cfg)
413 {
414     memset(cfg, 0, sizeof(struct ff_config));
415 
416     cfg->filename = DEFAULT_CONFIG_FILE;
417 
418     cfg->dpdk.proc_id = -1;
419     cfg->dpdk.numa_on = 1;
420     cfg->dpdk.promiscuous = 1;
421 
422     cfg->freebsd.hz = 100;
423     cfg->freebsd.physmem = 1048576*256;
424     cfg->freebsd.fd_reserve = 0;
425 }
426 
427 int
428 ff_load_config(int argc, char *const argv[])
429 {
430     ff_default_config(&ff_global_cfg);
431 
432     int ret = ff_parse_args(&ff_global_cfg, argc, argv);
433     if (ret < 0) {
434         return ret;
435     }
436 
437     ret = ini_parse(ff_global_cfg.filename, ini_parse_handler,
438         &ff_global_cfg);
439     if (ret != 0) {
440         printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret);
441         return -1;
442     }
443 
444     if (ff_check_config(&ff_global_cfg)) {
445         return -1;
446     }
447 
448     if (dpdk_args_setup(&ff_global_cfg) <= 0) {
449         return -1;
450     }
451 
452     return 0;
453 }
454 
455