xref: /f-stack/lib/ff_config.c (revision 7991c745)
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 "ff_config.h"
33 #include "ff_ini_parser.h"
34 
35 struct ff_config ff_global_cfg;
36 int dpdk_argc;
37 char *dpdk_argv[DPDK_CONFIG_NUM + 1];
38 
39 int dpdk_argc_arg;
40 char *dpdk_argv_arg[DPDK_CONFIG_NUM + 1];
41 
42 char* const short_options = "c:";
43 struct option long_options[] = {
44     { "proc-type", 1, NULL, 0 },
45     { "num-procs", 1, NULL, 0 },
46     { "proc-id", 1, NULL, 0 },
47     { 0, 0, 0, 0},
48 };
49 
50 static int
51 is_integer(const char *s)
52 {
53     if (*s == '-' || *s == '+')
54         s++;
55     if (*s < '0' || '9' < *s)
56         return 0;
57     s++;
58     while ('0' <= *s && *s <= '9')
59         s++;
60     return (*s == '\0');
61 }
62 
63 static int
64 freebsd_conf_handler(struct ff_config *cfg, const char *section,
65     const char *name, const char *value)
66 {
67     struct ff_freebsd_cfg *newconf, **cur;
68     newconf = (struct ff_freebsd_cfg *)malloc(sizeof(struct ff_freebsd_cfg));
69     if (newconf == NULL) {
70         fprintf(stderr, "freebsd conf malloc failed\n");
71         return 0;
72     }
73 
74     newconf->name = strdup(name);
75     newconf->str = strdup(value);
76 
77     if (strcmp(section, "boot") == 0) {
78         cur = &cfg->freebsd.boot;
79 
80         newconf->value = (void *)newconf->str;
81         newconf->vlen = strlen(value);
82     } else if (strcmp(section, "sysctl") == 0) {
83         cur = &cfg->freebsd.sysctl;
84 
85         if (is_integer(value)) {
86             int *p = (int *)malloc(sizeof(int));
87             *p = atoi(value);
88             newconf->value = (void *)p;
89             newconf->vlen = sizeof(*p);
90         } else {
91             newconf->value = (void *)newconf->str;
92             newconf->vlen = strlen(value);
93         }
94     } else {
95         fprintf(stderr, "freebsd conf section[%s] error\n", section);
96         return 0;
97     }
98 
99     if (*cur == NULL) {
100         *cur = newconf;
101     } else {
102         (*cur)->next = newconf;
103         newconf->next = NULL;
104     }
105 
106     return 1;
107 }
108 
109 static int
110 port_cfg_handler(struct ff_config *cfg, const char *section,
111     const char *name, const char *value) {
112 
113     if (cfg->dpdk.nb_ports == 0) {
114         fprintf(stderr, "port_cfg_handler: must config dpdk.nb_ports first\n");
115         return 0;
116     }
117 
118     if (cfg->dpdk.port_cfgs == NULL) {
119         struct ff_port_cfg *pc = calloc(cfg->dpdk.nb_ports, sizeof(struct ff_port_cfg));
120         if (pc == NULL) {
121             fprintf(stderr, "port_cfg_handler malloc failed\n");
122             return 0;
123         }
124 
125         cfg->dpdk.port_cfgs = pc;
126     }
127 
128     int portid;
129     int ret = sscanf(section, "port%d", &portid);
130     if (ret != 1) {
131         fprintf(stderr, "port_cfg_handler section[%s] error\n", section);
132         return 0;
133     }
134 
135     /* just return true if portid >= nb_ports because it has no effect */
136     if (portid >= cfg->dpdk.nb_ports) {
137         fprintf(stderr, "port_cfg_handler section[%s] max than nb_ports\n", section);
138         return 1;
139     }
140 
141     struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid];
142     if (cur->name == NULL) {
143         cur->name = strdup(section);
144         cur->port_id = portid;
145     }
146 
147     if (strcmp(name, "addr") == 0) {
148         cur->addr = strdup(value);
149     } else if (strcmp(name, "netmask") == 0) {
150         cur->netmask = strdup(value);
151     } else if (strcmp(name, "broadcast") == 0) {
152         cur->broadcast = strdup(value);
153     } else if (strcmp(name, "gateway") == 0) {
154         cur->gateway = strdup(value);
155     } else if (strcmp(name, "pcap") == 0) {
156         cur->pcap = strdup(value);
157     }
158 
159     return 1;
160 }
161 
162 static int
163 handler(void* user, const char* section, const char* name,
164     const char* value)
165 {
166     struct ff_config* pconfig = (struct ff_config*)user;
167 
168     printf("[%s]: %s=%s\n", section, name, value);
169 
170     #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
171     if (MATCH("dpdk", "channel")) {
172         pconfig->dpdk.nb_channel = atoi(value);
173     } else if (MATCH("dpdk", "memory")) {
174         pconfig->dpdk.memory = atoi(value);
175     } else if (MATCH("dpdk", "no_huge")) {
176         pconfig->dpdk.no_huge = atoi(value);
177     } else if (MATCH("dpdk", "lcore_mask")) {
178         pconfig->dpdk.lcore_mask = strdup(value);
179     } else if (MATCH("dpdk", "port_mask")) {
180         pconfig->dpdk.port_mask = atoi(value);
181     } else if (MATCH("dpdk", "nb_ports")) {
182         pconfig->dpdk.nb_ports = atoi(value);
183     } else if (MATCH("dpdk", "promiscuous")) {
184         pconfig->dpdk.promiscuous = atoi(value);
185     } else if (MATCH("dpdk", "numa_on")) {
186         pconfig->dpdk.numa_on = atoi(value);
187     } else if (MATCH("dpdk", "tso")) {
188         pconfig->dpdk.tso = atoi(value);
189     } else if (MATCH("kni", "enable")) {
190         pconfig->kni.enable= atoi(value);
191     } else if (MATCH("kni", "method")) {
192         pconfig->kni.method= strdup(value);
193     } else if (MATCH("kni", "tcp_port")) {
194         pconfig->kni.tcp_port = strdup(value);
195     } else if (MATCH("kni", "udp_port")) {
196         pconfig->kni.udp_port= strdup(value);
197     } else if (strcmp(section, "freebsd.boot") == 0) {
198         if (strcmp(name, "hz") == 0) {
199             pconfig->freebsd.hz = atoi(value);
200         } else if (strcmp(name, "physmem") == 0) {
201             pconfig->freebsd.physmem = atol(value);
202         } else {
203             return freebsd_conf_handler(pconfig, "boot", name, value);
204         }
205     } else if (strcmp(section, "freebsd.sysctl") == 0) {
206         return freebsd_conf_handler(pconfig, "sysctl", name, value);
207     } else if (strncmp(section, "port", 4) == 0) {
208         return port_cfg_handler(pconfig, section, name, value);
209     }
210 
211     return 1;
212 }
213 
214 static int
215 dpdk_argc_argv_setup(struct ff_config *cfg)
216 {
217     int n = 0, i;
218     dpdk_argv[n++] = strdup("f-stack");
219     char temp[DPDK_CONFIG_MAXLEN] = {0};
220 
221     if (cfg->dpdk.no_huge) {
222         dpdk_argv[n++] = strdup("--no-huge");
223     }
224     if (cfg->dpdk.proc_mask) {
225         sprintf(temp, "-c%s", cfg->dpdk.proc_mask);
226         dpdk_argv[n++] = strdup(temp);
227     }
228     if (cfg->dpdk.nb_channel) {
229         sprintf(temp, "-n%d", cfg->dpdk.nb_channel);
230         dpdk_argv[n++] = strdup(temp);
231     }
232     if (cfg->dpdk.memory) {
233         sprintf(temp, "-m%d", cfg->dpdk.memory);
234         dpdk_argv[n++] = strdup(temp);
235     }
236 
237     for(i = 0; i < dpdk_argc_arg; ++i) {
238         dpdk_argv[n++] = dpdk_argv_arg[i];
239     }
240 
241     dpdk_argc = n;
242 
243     return n;
244 }
245 
246 static void
247 ff_load_arg(struct ff_config *cfg, int argc, char *const argv[])
248 {
249     dpdk_argc_arg = 0;
250     int c;
251     int index = 0;
252     while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
253         switch (c) {
254             case 'c':
255                 cfg->dpdk.proc_mask = strdup(optarg);
256                 break;
257             case 0:
258                 if (0 == strcmp(long_options[index].name, "num-procs")) {
259                     cfg->dpdk.nb_procs = atoi(optarg);
260                 } else if(0 == strcmp(long_options[index].name, "proc-id")) {
261                     cfg->dpdk.proc_id = atoi(optarg);
262                 } else if(0 == strcmp(long_options[index].name, "proc-type")) {
263                     char temp[DPDK_CONFIG_MAXLEN] = {0};
264                     sprintf(temp, "--proc-type=%s",optarg);
265                     dpdk_argv_arg[dpdk_argc_arg++] = strdup(temp);
266                 }
267                 break;
268             default:
269                 break;
270         }
271     }
272     return;
273 }
274 
275 static int
276 ff_check_config(struct ff_config *cfg)
277 {
278     if(cfg->kni.enable && !cfg->kni.method) {
279         fprintf(stderr, "conf dpdk.method is necessary\n");
280         return -1;
281     }
282 
283     if(cfg->kni.method) {
284         if(strcasecmp(cfg->kni.method,"accept") &&
285             strcasecmp(cfg->kni.method,"reject")) {
286             fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n",
287                 cfg->kni.method);
288             return -1;
289         }
290     }
291 
292     #define CHECK_VALID(n) \
293         do { \
294             if (!pc->n) { \
295                 fprintf(stderr, "port%d if config error: no %s\n", \
296                     pc->port_id, #n); \
297                 return -1; \
298             } \
299         } while (0)
300 
301     int i;
302     for (i = 0; i < cfg->dpdk.nb_ports; i++) {
303         struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[i];
304         CHECK_VALID(addr);
305         CHECK_VALID(netmask);
306         CHECK_VALID(broadcast);
307         CHECK_VALID(gateway);
308     }
309 
310     return 0;
311 }
312 
313 static void
314 ff_default_config(struct ff_config *cfg)
315 {
316     memset(cfg, 0, sizeof(struct ff_config));
317 
318     cfg->dpdk.numa_on = 1;
319     cfg->dpdk.promiscuous = 1;
320 
321     cfg->freebsd.hz = 100;
322     cfg->freebsd.physmem = 1048576*256;
323 }
324 
325 int
326 ff_load_config(const char *conf, int argc, char * const argv[])
327 {
328     ff_default_config(&ff_global_cfg);
329 
330     int ret = ini_parse(conf, handler, &ff_global_cfg);
331     if (ret != 0) {
332         printf("parse %s failed on line %d\n", conf, ret);
333         return -1;
334     }
335 
336     if (ff_check_config(&ff_global_cfg)) {
337         return -1;
338     }
339 
340     ff_load_arg(&ff_global_cfg, argc, argv);
341     if (dpdk_argc_argv_setup(&ff_global_cfg) <= 0) {
342         return -1;
343     }
344 
345     return 0;
346 }
347 
348