xref: /f-stack/lib/ff_config.c (revision a9643ea8)
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("kni", "enable")) {
188         pconfig->kni.enable= atoi(value);
189     } else if (MATCH("kni", "method")) {
190         pconfig->kni.method= strdup(value);
191     } else if (MATCH("kni", "tcp_port")) {
192         pconfig->kni.tcp_port = strdup(value);
193     } else if (MATCH("kni", "upd_port")) {
194         pconfig->kni.udp_port= strdup(value);
195     } else if (strcmp(section, "freebsd.boot") == 0) {
196         if (strcmp(name, "hz") == 0) {
197             pconfig->freebsd.hz = atoi(value);
198         } else if (strcmp(name, "physmem") == 0) {
199             pconfig->freebsd.physmem = atol(value);
200         } else {
201             return freebsd_conf_handler(pconfig, "boot", name, value);
202         }
203     } else if (strcmp(section, "freebsd.sysctl") == 0) {
204         return freebsd_conf_handler(pconfig, "sysctl", name, value);
205     } else if (strncmp(section, "port", 4) == 0) {
206         return port_cfg_handler(pconfig, section, name, value);
207     }
208 
209     return 1;
210 }
211 
212 static int
213 dpdk_argc_argv_setup(struct ff_config *cfg)
214 {
215     int n = 0, i;
216     dpdk_argv[n++] = strdup("f-stack");
217     char temp[DPDK_CONFIG_MAXLEN] = {0};
218 
219     if (cfg->dpdk.no_huge) {
220         dpdk_argv[n++] = strdup("--no-huge");
221     }
222     if (cfg->dpdk.proc_mask) {
223         sprintf(temp, "-c%s", cfg->dpdk.proc_mask);
224         dpdk_argv[n++] = strdup(temp);
225     }
226     if (cfg->dpdk.nb_channel) {
227         sprintf(temp, "-n%d", cfg->dpdk.nb_channel);
228         dpdk_argv[n++] = strdup(temp);
229     }
230     if (cfg->dpdk.memory) {
231         sprintf(temp, "-m%d", cfg->dpdk.memory);
232         dpdk_argv[n++] = strdup(temp);
233     }
234 
235     for(i = 0; i < dpdk_argc_arg; ++i) {
236         dpdk_argv[n++] = dpdk_argv_arg[i];
237     }
238 
239     dpdk_argc = n;
240 
241     return n;
242 }
243 
244 static void
245 ff_load_arg(struct ff_config *cfg, int argc, char *const argv[])
246 {
247     dpdk_argc_arg = 0;
248     int c;
249     int index = 0;
250     while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
251         switch (c) {
252             case 'c':
253                 cfg->dpdk.proc_mask = strdup(optarg);
254                 break;
255             case 0:
256                 if (0 == strcmp(long_options[index].name, "num-procs")) {
257                     cfg->dpdk.nb_procs = atoi(optarg);
258                 } else if(0 == strcmp(long_options[index].name, "proc-id")) {
259                     cfg->dpdk.proc_id = atoi(optarg);
260                 } else if(0 == strcmp(long_options[index].name, "proc-type")) {
261                     char temp[DPDK_CONFIG_MAXLEN] = {0};
262                     sprintf(temp, "--proc-type=%s",optarg);
263                     dpdk_argv_arg[dpdk_argc_arg++] = strdup(temp);
264                 }
265                 break;
266             default:
267                 break;
268         }
269     }
270     return;
271 }
272 
273 static int
274 ff_check_config(struct ff_config *cfg)
275 {
276     if(cfg->kni.enable && !cfg->kni.method) {
277         fprintf(stderr, "conf dpdk.method is necessary\n");
278         return -1;
279     }
280 
281     if(cfg->kni.method) {
282         if(strcasecmp(cfg->kni.method,"accept") &&
283             strcasecmp(cfg->kni.method,"reject")) {
284             fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n",
285                 cfg->kni.method);
286             return -1;
287         }
288     }
289 
290     #define CHECK_VALID(n) \
291         do { \
292             if (!pc->n) { \
293                 fprintf(stderr, "port%d if config error: no %s\n", \
294                     pc->port_id, #n); \
295                 return -1; \
296             } \
297         } while (0)
298 
299     int i;
300     for (i = 0; i < cfg->dpdk.nb_ports; i++) {
301         struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[i];
302         CHECK_VALID(addr);
303         CHECK_VALID(netmask);
304         CHECK_VALID(broadcast);
305         CHECK_VALID(gateway);
306     }
307 
308     return 0;
309 }
310 
311 static void
312 ff_default_config(struct ff_config *cfg)
313 {
314     memset(cfg, 0, sizeof(struct ff_config));
315 
316     cfg->dpdk.numa_on = 1;
317     cfg->dpdk.promiscuous = 1;
318 
319     cfg->freebsd.hz = 100;
320     cfg->freebsd.physmem = 1048576*256;
321 }
322 
323 int
324 ff_load_config(const char *conf, int argc, char * const argv[])
325 {
326     ff_default_config(&ff_global_cfg);
327 
328     int ret = ini_parse(conf, handler, &ff_global_cfg);
329     if (ret != 0) {
330         printf("parse %s failed on line %d\n", conf, ret);
331         return -1;
332     }
333 
334     if (ff_check_config(&ff_global_cfg)) {
335         return -1;
336     }
337 
338     ff_load_arg(&ff_global_cfg, argc, argv);
339     if (dpdk_argc_argv_setup(&ff_global_cfg) <= 0) {
340         return -1;
341     }
342 
343     return 0;
344 }
345 
346