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