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("kni", "enable")) { 276 pconfig->kni.enable= atoi(value); 277 } else if (MATCH("kni", "method")) { 278 pconfig->kni.method= strdup(value); 279 } else if (MATCH("kni", "tcp_port")) { 280 pconfig->kni.tcp_port = strdup(value); 281 } else if (MATCH("kni", "udp_port")) { 282 pconfig->kni.udp_port= strdup(value); 283 } else if (strcmp(section, "freebsd.boot") == 0) { 284 if (strcmp(name, "hz") == 0) { 285 pconfig->freebsd.hz = atoi(value); 286 } else if (strcmp(name, "physmem") == 0) { 287 pconfig->freebsd.physmem = atol(value); 288 } else if (strcmp(name, "fd_reserve") == 0) { 289 pconfig->freebsd.fd_reserve = atoi(value); 290 } else { 291 return freebsd_conf_handler(pconfig, "boot", name, value); 292 } 293 } else if (strcmp(section, "freebsd.sysctl") == 0) { 294 return freebsd_conf_handler(pconfig, "sysctl", name, value); 295 } else if (strncmp(section, "port", 4) == 0) { 296 return port_cfg_handler(pconfig, section, name, value); 297 } 298 299 return 1; 300 } 301 302 static int 303 dpdk_args_setup(struct ff_config *cfg) 304 { 305 int n = 0, i; 306 dpdk_argv[n++] = strdup("f-stack"); 307 char temp[DPDK_CONFIG_MAXLEN] = {0}; 308 309 if (cfg->dpdk.no_huge) { 310 dpdk_argv[n++] = strdup("--no-huge"); 311 } 312 if (cfg->dpdk.proc_mask) { 313 sprintf(temp, "-c%s", cfg->dpdk.proc_mask); 314 dpdk_argv[n++] = strdup(temp); 315 } 316 if (cfg->dpdk.nb_channel) { 317 sprintf(temp, "-n%d", cfg->dpdk.nb_channel); 318 dpdk_argv[n++] = strdup(temp); 319 } 320 if (cfg->dpdk.memory) { 321 sprintf(temp, "-m%d", cfg->dpdk.memory); 322 dpdk_argv[n++] = strdup(temp); 323 } 324 if (cfg->dpdk.proc_type) { 325 sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type); 326 dpdk_argv[n++] = strdup(temp); 327 } 328 329 dpdk_argc = n; 330 331 return n; 332 } 333 334 static int 335 ff_parse_args(struct ff_config *cfg, int argc, char *const argv[]) 336 { 337 int c; 338 int index = 0; 339 while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) { 340 switch (c) { 341 case 'c': 342 cfg->filename = strdup(optarg); 343 break; 344 case 'p': 345 cfg->dpdk.proc_id = atoi(optarg); 346 break; 347 case 't': 348 cfg->dpdk.proc_type = strdup(optarg); 349 break; 350 default: 351 return -1; 352 } 353 } 354 355 if (cfg->dpdk.proc_type == NULL || 356 (strcmp(cfg->dpdk.proc_type, "primary") && 357 strcmp(cfg->dpdk.proc_type, "secondary"))) { 358 printf("invalid proc-type\n"); 359 return -1; 360 } 361 362 if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) { 363 printf("proc_id:%d is too large\n", cfg->dpdk.proc_id); 364 return -1; 365 } 366 367 return 0; 368 } 369 370 static int 371 ff_check_config(struct ff_config *cfg) 372 { 373 if(cfg->kni.enable && !cfg->kni.method) { 374 fprintf(stderr, "conf dpdk.method is necessary\n"); 375 return -1; 376 } 377 378 if(cfg->kni.method) { 379 if(strcasecmp(cfg->kni.method,"accept") && 380 strcasecmp(cfg->kni.method,"reject")) { 381 fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n", 382 cfg->kni.method); 383 return -1; 384 } 385 } 386 387 #define CHECK_VALID(n) \ 388 do { \ 389 if (!pc->n) { \ 390 fprintf(stderr, "port%d if config error: no %s\n", \ 391 pc->port_id, #n); \ 392 return -1; \ 393 } \ 394 } while (0) 395 396 int i; 397 for (i = 0; i < cfg->dpdk.nb_ports; i++) { 398 struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[i]; 399 CHECK_VALID(addr); 400 CHECK_VALID(netmask); 401 CHECK_VALID(broadcast); 402 CHECK_VALID(gateway); 403 } 404 405 return 0; 406 } 407 408 static void 409 ff_default_config(struct ff_config *cfg) 410 { 411 memset(cfg, 0, sizeof(struct ff_config)); 412 413 cfg->filename = DEFAULT_CONFIG_FILE; 414 415 cfg->dpdk.proc_id = -1; 416 cfg->dpdk.numa_on = 1; 417 cfg->dpdk.promiscuous = 1; 418 419 cfg->freebsd.hz = 100; 420 cfg->freebsd.physmem = 1048576*256; 421 cfg->freebsd.fd_reserve = 0; 422 } 423 424 int 425 ff_load_config(int argc, char *const argv[]) 426 { 427 ff_default_config(&ff_global_cfg); 428 429 int ret = ff_parse_args(&ff_global_cfg, argc, argv); 430 if (ret < 0) { 431 return ret; 432 } 433 434 ret = ini_parse(ff_global_cfg.filename, ini_parse_handler, 435 &ff_global_cfg); 436 if (ret != 0) { 437 printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret); 438 return -1; 439 } 440 441 if (ff_check_config(&ff_global_cfg)) { 442 return -1; 443 } 444 445 if (dpdk_args_setup(&ff_global_cfg) <= 0) { 446 return -1; 447 } 448 449 return 0; 450 } 451 452