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