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 #include <rte_string_fns.h> 35 36 #include "ff_config.h" 37 #include "ff_ini_parser.h" 38 39 #define DEFAULT_CONFIG_FILE "config.ini" 40 41 #define BITS_PER_HEX 4 42 43 struct ff_config ff_global_cfg; 44 int dpdk_argc; 45 char *dpdk_argv[DPDK_CONFIG_NUM + 1]; 46 47 char* const short_options = "c:t:p:"; 48 struct option long_options[] = { 49 { "conf", 1, NULL, 'c'}, 50 { "proc-type", 1, NULL, 't'}, 51 { "proc-id", 1, NULL, 'p'}, 52 { 0, 0, 0, 0}, 53 }; 54 55 static int 56 xdigit2val(unsigned char c) 57 { 58 int val; 59 60 if (isdigit(c)) 61 val = c - '0'; 62 else if (isupper(c)) 63 val = c - 'A' + 10; 64 else 65 val = c - 'a' + 10; 66 return val; 67 } 68 69 static int 70 parse_lcore_mask(struct ff_config *cfg, const char *coremask) 71 { 72 int i, j, idx = 0, shift = 0, zero_num = 0; 73 unsigned count = 0; 74 char c; 75 int val; 76 uint16_t *proc_lcore; 77 char buf[RTE_MAX_LCORE] = {0}; 78 char zero[RTE_MAX_LCORE] = {0}; 79 80 if (coremask == NULL) 81 return 0; 82 83 cfg->dpdk.proc_lcore = (uint16_t *)calloc(RTE_MAX_LCORE, sizeof(uint16_t)); 84 if (cfg->dpdk.proc_lcore == NULL) { 85 fprintf(stderr, "parse_lcore_mask malloc failed\n"); 86 return 0; 87 } 88 proc_lcore = cfg->dpdk.proc_lcore; 89 90 /* 91 * Remove all blank characters ahead and after. 92 * Remove 0x/0X if exists. 93 */ 94 while (isblank(*coremask)) 95 coremask++; 96 if (coremask[0] == '0' && ((coremask[1] == 'x') 97 || (coremask[1] == 'X'))) 98 coremask += 2; 99 100 i = strlen(coremask); 101 while ((i > 0) && isblank(coremask[i - 1])) 102 i--; 103 104 if (i == 0) 105 return 0; 106 107 for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) { 108 c = coremask[i]; 109 if (isxdigit(c) == 0) { 110 return 0; 111 } 112 val = xdigit2val(c); 113 for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++) { 114 if ((1 << j) & val) { 115 proc_lcore[count] = idx; 116 if (cfg->dpdk.proc_id == count) { 117 zero_num = idx >> 2; 118 shift = idx & 0x3; 119 memset(zero,'0',zero_num); 120 snprintf(buf, sizeof(buf) - 1, "%llx%s", 121 (unsigned long long)1<<shift, zero); 122 cfg->dpdk.proc_mask = strdup(buf); 123 } 124 count++; 125 } 126 } 127 } 128 129 for (; i >= 0; i--) 130 if (coremask[i] != '0') 131 return 0; 132 133 if (cfg->dpdk.proc_id >= count) 134 return 0; 135 136 cfg->dpdk.nb_procs = count; 137 138 return 1; 139 } 140 141 static int 142 is_integer(const char *s) 143 { 144 if (*s == '-' || *s == '+') 145 s++; 146 if (*s < '0' || '9' < *s) 147 return 0; 148 s++; 149 while ('0' <= *s && *s <= '9') 150 s++; 151 return (*s == '\0'); 152 } 153 154 static int 155 freebsd_conf_handler(struct ff_config *cfg, const char *section, 156 const char *name, const char *value) 157 { 158 struct ff_freebsd_cfg *newconf, **cur; 159 newconf = (struct ff_freebsd_cfg *)malloc(sizeof(struct ff_freebsd_cfg)); 160 if (newconf == NULL) { 161 fprintf(stderr, "freebsd conf malloc failed\n"); 162 return 0; 163 } 164 165 newconf->name = strdup(name); 166 newconf->str = strdup(value); 167 168 if (strcmp(section, "boot") == 0) { 169 cur = &cfg->freebsd.boot; 170 171 newconf->value = (void *)newconf->str; 172 newconf->vlen = strlen(value); 173 } else if (strcmp(section, "sysctl") == 0) { 174 cur = &cfg->freebsd.sysctl; 175 176 if (is_integer(value)) { 177 if (strcmp(name, "kern.ipc.maxsockbuf") == 0) { 178 long *p = (long *)malloc(sizeof(long)); 179 *p = atol(value); 180 newconf->value = (void *)p; 181 newconf->vlen = sizeof(*p); 182 } else { 183 int *p = (int *)malloc(sizeof(int)); 184 *p = atoi(value); 185 newconf->value = (void *)p; 186 newconf->vlen = sizeof(*p); 187 } 188 } else { 189 newconf->value = (void *)newconf->str; 190 newconf->vlen = strlen(value); 191 } 192 } else { 193 fprintf(stderr, "freebsd conf section[%s] error\n", section); 194 return 0; 195 } 196 197 if (*cur == NULL) { 198 newconf->next = NULL; 199 *cur = newconf; 200 } else { 201 newconf->next = (*cur)->next; 202 (*cur)->next = newconf; 203 } 204 205 return 1; 206 } 207 // A recursive binary search function. It returns location of x in 208 // given array arr[l..r] is present, otherwise -1 209 static int 210 uint16_binary_search(uint16_t arr[], int l, int r, uint16_t x) 211 { 212 if (r >= l) { 213 int mid = l + (r - l)/2; 214 215 // If the element is present at the middle itself 216 if (arr[mid] == x) return mid; 217 218 // If element is smaller than mid, then it can only be present 219 // in left subarray 220 if (arr[mid] > x) return uint16_binary_search(arr, l, mid-1, x); 221 222 // Else the element can only be present in right subarray 223 return uint16_binary_search(arr, mid+1, r, x); 224 } 225 226 // We reach here when element is not present in array 227 return -1; 228 } 229 230 static int 231 uint16_cmp (const void * a, const void * b) 232 { 233 return ( *(uint16_t*)a - *(uint16_t*)b ); 234 } 235 236 static inline void 237 sort_uint16_array(uint16_t arr[], int n) 238 { 239 qsort(arr, n, sizeof(uint16_t), uint16_cmp); 240 } 241 242 static inline char * 243 __strstrip(char *s) 244 { 245 char *end = s + strlen(s) - 1; 246 while(*s == ' ') s++; 247 for (; end >= s; --end) { 248 if (*end != ' ') break; 249 } 250 *(++end) = '\0'; 251 return s; 252 } 253 254 static int 255 __parse_config_list(uint16_t *arr, int *sz, const char *value) { 256 int i, j; 257 char input[4096]; 258 char *tokens[128]; 259 int nTokens = 0; 260 char *endptr; 261 int nr_ele = 0; 262 int max_ele = *sz; 263 264 strncpy(input, value, sizeof(input) - 1); 265 nTokens = rte_strsplit(input, sizeof(input), tokens, 128, ','); 266 for (i = 0; i < nTokens; i++) { 267 char *tok = tokens[i]; 268 char *middle = strchr(tok, '-'); 269 if (middle == NULL) { 270 tok = __strstrip(tok); 271 long v = strtol(tok, &endptr, 10); 272 if (*endptr != '\0') { 273 fprintf(stderr, "%s is not a integer.", tok); 274 return 0; 275 } 276 if (nr_ele > max_ele) { 277 fprintf(stderr, "too many elements in list %s\n", value); 278 return 0; 279 } 280 arr[nr_ele++] = (uint16_t)v; 281 } else { 282 *middle = '\0'; 283 char *lbound = __strstrip(tok); 284 char *rbound = __strstrip(middle+1); 285 long lv = strtol(lbound, &endptr, 10); 286 if (*endptr != '\0') { 287 fprintf(stderr, "%s is not a integer.", lbound); 288 return 0; 289 } 290 long rv = strtol(rbound, &endptr, 10); 291 if (*endptr != '\0') { 292 fprintf(stderr, "%s is not a integer.", rbound); 293 return 0; 294 } 295 for (j = lv; j <= rv; ++j) { 296 if (nr_ele > max_ele) { 297 fprintf(stderr, "too many elements in list %s.\n", value); 298 return 0; 299 } 300 arr[nr_ele++] = (uint16_t)j; 301 } 302 } 303 } 304 if (nr_ele <= 0) { 305 fprintf(stderr, "list %s is empty\n", value); 306 return 1; 307 } 308 sort_uint16_array(arr, nr_ele); 309 *sz = nr_ele; 310 return 1; 311 } 312 313 static int 314 parse_port_lcore_list(struct ff_port_cfg *cfg, const char *v_str) 315 { 316 cfg->nb_lcores = DPDK_MAX_LCORE; 317 uint16_t *cores = cfg->lcore_list; 318 return __parse_config_list(cores, &cfg->nb_lcores, v_str); 319 } 320 321 static int 322 parse_port_list(struct ff_config *cfg, const char *v_str) 323 { 324 int res; 325 uint16_t ports[RTE_MAX_ETHPORTS]; 326 int sz = RTE_MAX_ETHPORTS; 327 328 res = __parse_config_list(ports, &sz, v_str); 329 if (! res) return res; 330 331 uint16_t *portid_list = malloc(sizeof(uint16_t)*sz); 332 333 if (portid_list == NULL) { 334 fprintf(stderr, "parse_port_list malloc failed\n"); 335 return 0; 336 } 337 memcpy(portid_list, ports, sz*sizeof(uint16_t)); 338 339 cfg->dpdk.portid_list = portid_list; 340 cfg->dpdk.nb_ports = sz; 341 cfg->dpdk.max_portid = portid_list[sz-1]; 342 return res; 343 } 344 345 static int 346 parse_port_slave_list(struct ff_port_cfg *cfg, const char *v_str) 347 { 348 int res; 349 uint16_t ports[RTE_MAX_ETHPORTS]; 350 int sz = RTE_MAX_ETHPORTS; 351 352 res = __parse_config_list(ports, &sz, v_str); 353 if (! res) return res; 354 355 uint16_t *portid_list = malloc(sizeof(uint16_t)*sz); 356 357 if (portid_list == NULL) { 358 fprintf(stderr, "parse_port_slave_list malloc failed\n"); 359 return 0; 360 } 361 memcpy(portid_list, ports, sz*sizeof(uint16_t)); 362 363 cfg->slave_portid_list = portid_list; 364 cfg->nb_slaves = sz; 365 366 return res; 367 } 368 369 static int 370 port_cfg_handler(struct ff_config *cfg, const char *section, 371 const char *name, const char *value) { 372 373 if (cfg->dpdk.nb_ports == 0) { 374 fprintf(stderr, "port_cfg_handler: must config dpdk.port_list first\n"); 375 return 0; 376 } 377 378 if (cfg->dpdk.port_cfgs == NULL) { 379 struct ff_port_cfg *pc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_port_cfg)); 380 if (pc == NULL) { 381 fprintf(stderr, "port_cfg_handler malloc failed\n"); 382 return 0; 383 } 384 // initialize lcore list and nb_lcores 385 int i; 386 for (i = 0; i < cfg->dpdk.nb_ports; ++i) { 387 uint16_t portid = cfg->dpdk.portid_list[i]; 388 389 struct ff_port_cfg *pconf = &pc[portid]; 390 pconf->port_id = portid; 391 pconf->nb_lcores = ff_global_cfg.dpdk.nb_procs; 392 memcpy(pconf->lcore_list, ff_global_cfg.dpdk.proc_lcore, 393 pconf->nb_lcores*sizeof(uint16_t)); 394 } 395 cfg->dpdk.port_cfgs = pc; 396 } 397 398 int portid; 399 int ret = sscanf(section, "port%d", &portid); 400 if (ret != 1) { 401 fprintf(stderr, "port_cfg_handler section[%s] error\n", section); 402 return 0; 403 } 404 405 /* just return true if portid >= nb_ports because it has no effect */ 406 if (portid > cfg->dpdk.max_portid) { 407 fprintf(stderr, "port_cfg_handler section[%s] bigger than max port id\n", section); 408 return 1; 409 } 410 411 struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid]; 412 if (cur->name == NULL) { 413 cur->name = strdup(section); 414 cur->port_id = portid; 415 } 416 417 if (strcmp(name, "addr") == 0) { 418 cur->addr = strdup(value); 419 } else if (strcmp(name, "netmask") == 0) { 420 cur->netmask = strdup(value); 421 } else if (strcmp(name, "broadcast") == 0) { 422 cur->broadcast = strdup(value); 423 } else if (strcmp(name, "gateway") == 0) { 424 cur->gateway = strdup(value); 425 } else if (strcmp(name, "pcap") == 0) { 426 cur->pcap = strdup(value); 427 } else if (strcmp(name, "lcore_list") == 0) { 428 return parse_port_lcore_list(cur, value); 429 } else if (strcmp(name, "slave_port_list") == 0) { 430 return parse_port_slave_list(cur, value); 431 } 432 433 #ifdef INET6 434 else if (0 == strcmp(name, "addr6")) 435 { 436 cur->addr6_str = strdup(value); 437 } 438 else if (0 == strcmp(name, "prefix_len")) 439 { 440 cur->prefix_len = atoi(value); 441 } 442 else if (0 == strcmp(name, "gateway6")) 443 { 444 cur->gateway6_str = strdup(value); 445 } 446 #endif 447 448 return 1; 449 } 450 451 static int 452 vdev_cfg_handler(struct ff_config *cfg, const char *section, 453 const char *name, const char *value) { 454 455 if (cfg->dpdk.nb_vdev == 0) { 456 fprintf(stderr, "vdev_cfg_handler: must config dpdk.nb_vdev first\n"); 457 return 0; 458 } 459 460 if (cfg->dpdk.vdev_cfgs == NULL) { 461 struct ff_vdev_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_vdev_cfg)); 462 if (vc == NULL) { 463 fprintf(stderr, "vdev_cfg_handler malloc failed\n"); 464 return 0; 465 } 466 cfg->dpdk.vdev_cfgs = vc; 467 } 468 469 int vdevid; 470 int ret = sscanf(section, "vdev%d", &vdevid); 471 if (ret != 1) { 472 fprintf(stderr, "vdev_cfg_handler section[%s] error\n", section); 473 return 0; 474 } 475 476 /* just return true if vdevid >= nb_vdev because it has no effect */ 477 if (vdevid > cfg->dpdk.nb_vdev) { 478 fprintf(stderr, "vdev_cfg_handler section[%s] bigger than max vdev id\n", section); 479 return 1; 480 } 481 482 struct ff_vdev_cfg *cur = &cfg->dpdk.vdev_cfgs[vdevid]; 483 if (cur->name == NULL) { 484 cur->name = strdup(section); 485 cur->vdev_id = vdevid; 486 } 487 488 if (strcmp(name, "iface") == 0) { 489 cur->iface = strdup(value); 490 } else if (strcmp(name, "path") == 0) { 491 cur->path = strdup(value); 492 } else if (strcmp(name, "queues") == 0) { 493 cur->nb_queues = atoi(value); 494 } else if (strcmp(name, "queue_size") == 0) { 495 cur->queue_size = atoi(value); 496 } else if (strcmp(name, "mac") == 0) { 497 cur->mac = strdup(value); 498 } else if (strcmp(name, "cq") == 0) { 499 cur->nb_cq = atoi(value); 500 } 501 502 return 1; 503 } 504 505 static int 506 bond_cfg_handler(struct ff_config *cfg, const char *section, 507 const char *name, const char *value) { 508 509 if (cfg->dpdk.nb_bond == 0) { 510 fprintf(stderr, "bond_cfg_handler: must config dpdk.nb_bond first\n"); 511 return 0; 512 } 513 514 if (cfg->dpdk.bond_cfgs == NULL) { 515 struct ff_bond_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_bond_cfg)); 516 if (vc == NULL) { 517 fprintf(stderr, "ff_bond_cfg malloc failed\n"); 518 return 0; 519 } 520 cfg->dpdk.bond_cfgs = vc; 521 } 522 523 int bondid; 524 int ret = sscanf(section, "bond%d", &bondid); 525 if (ret != 1) { 526 fprintf(stderr, "bond_cfg_handler section[%s] error\n", section); 527 return 0; 528 } 529 530 /* just return true if bondid >= nb_vdev because it has no effect */ 531 if (bondid > cfg->dpdk.nb_bond) { 532 fprintf(stderr, "bond_cfg_handler section[%s] bigger than max bond id\n", section); 533 return 1; 534 } 535 536 struct ff_bond_cfg *cur = &cfg->dpdk.bond_cfgs[bondid]; 537 if (cur->name == NULL) { 538 cur->name = strdup(section); 539 cur->bond_id = bondid; 540 } 541 542 if (strcmp(name, "mode") == 0) { 543 cur->mode = atoi(value); 544 } else if (strcmp(name, "slave") == 0) { 545 cur->slave = strdup(value); 546 } else if (strcmp(name, "primary") == 0) { 547 cur->primary = strdup(value); 548 } else if (strcmp(name, "socket_id") == 0) { 549 cur->socket_id = atoi(value); 550 } else if (strcmp(name, "mac") == 0) { 551 cur->bond_mac = strdup(value); 552 } else if (strcmp(name, "xmit_policy") == 0) { 553 cur->xmit_policy = strdup(value); 554 } else if (strcmp(name, "lsc_poll_period_ms") == 0) { 555 cur->lsc_poll_period_ms = atoi(value); 556 } else if (strcmp(name, "up_delay") == 0) { 557 cur->up_delay = atoi(value); 558 } else if (strcmp(name, "down_delay") == 0) { 559 cur->down_delay = atoi(value); 560 } 561 562 return 1; 563 } 564 565 static int 566 ini_parse_handler(void* user, const char* section, const char* name, 567 const char* value) 568 { 569 struct ff_config *pconfig = (struct ff_config*)user; 570 571 printf("[%s]: %s=%s\n", section, name, value); 572 573 #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 574 if (MATCH("dpdk", "channel")) { 575 pconfig->dpdk.nb_channel = atoi(value); 576 } else if (MATCH("dpdk", "memory")) { 577 pconfig->dpdk.memory = atoi(value); 578 } else if (MATCH("dpdk", "no_huge")) { 579 pconfig->dpdk.no_huge = atoi(value); 580 } else if (MATCH("dpdk", "lcore_mask")) { 581 pconfig->dpdk.lcore_mask = strdup(value); 582 return parse_lcore_mask(pconfig, pconfig->dpdk.lcore_mask); 583 } else if (MATCH("dpdk", "base_virtaddr")) { 584 pconfig->dpdk.base_virtaddr= strdup(value); 585 } else if (MATCH("dpdk", "file_prefix")) { 586 pconfig->dpdk.file_prefix = strdup(value); 587 } else if (MATCH("dpdk", "pci_whitelist")) { 588 pconfig->dpdk.pci_whitelist = strdup(value); 589 } else if (MATCH("dpdk", "port_list")) { 590 return parse_port_list(pconfig, value); 591 } else if (MATCH("dpdk", "nb_vdev")) { 592 pconfig->dpdk.nb_vdev = atoi(value); 593 } else if (MATCH("dpdk", "nb_bond")) { 594 pconfig->dpdk.nb_bond = atoi(value); 595 } else if (MATCH("dpdk", "promiscuous")) { 596 pconfig->dpdk.promiscuous = atoi(value); 597 } else if (MATCH("dpdk", "numa_on")) { 598 pconfig->dpdk.numa_on = atoi(value); 599 } else if (MATCH("dpdk", "tso")) { 600 pconfig->dpdk.tso = atoi(value); 601 } else if (MATCH("dpdk", "tx_csum_offoad_skip")) { 602 pconfig->dpdk.tx_csum_offoad_skip = atoi(value); 603 } else if (MATCH("dpdk", "vlan_strip")) { 604 pconfig->dpdk.vlan_strip = atoi(value); 605 } else if (MATCH("dpdk", "idle_sleep")) { 606 pconfig->dpdk.idle_sleep = atoi(value); 607 } else if (MATCH("dpdk", "pkt_tx_delay")) { 608 pconfig->dpdk.pkt_tx_delay = atoi(value); 609 } else if (MATCH("dpdk", "symmetric_rss")) { 610 pconfig->dpdk.symmetric_rss = atoi(value); 611 } else if (MATCH("kni", "enable")) { 612 pconfig->kni.enable= atoi(value); 613 } else if (MATCH("kni", "kni_action")) { 614 pconfig->kni.kni_action= strdup(value); 615 } else if (MATCH("kni", "method")) { 616 pconfig->kni.method= strdup(value); 617 } else if (MATCH("kni", "tcp_port")) { 618 pconfig->kni.tcp_port = strdup(value); 619 } else if (MATCH("kni", "udp_port")) { 620 pconfig->kni.udp_port= strdup(value); 621 } else if (strcmp(section, "freebsd.boot") == 0) { 622 if (strcmp(name, "hz") == 0) { 623 pconfig->freebsd.hz = atoi(value); 624 } else if (strcmp(name, "physmem") == 0) { 625 pconfig->freebsd.physmem = atol(value); 626 } else if (strcmp(name, "fd_reserve") == 0) { 627 pconfig->freebsd.fd_reserve = atoi(value); 628 } else if (strcmp(name, "memsz_MB") == 0) { 629 pconfig->freebsd.mem_size = atoi(value); 630 } else { 631 return freebsd_conf_handler(pconfig, "boot", name, value); 632 } 633 } else if (strcmp(section, "freebsd.sysctl") == 0) { 634 return freebsd_conf_handler(pconfig, "sysctl", name, value); 635 } else if (strncmp(section, "port", 4) == 0) { 636 return port_cfg_handler(pconfig, section, name, value); 637 } else if (strncmp(section, "vdev", 4) == 0) { 638 return vdev_cfg_handler(pconfig, section, name, value); 639 } else if (strncmp(section, "bond", 4) == 0) { 640 return bond_cfg_handler(pconfig, section, name, value); 641 } else if (strcmp(section, "pcap") == 0) { 642 if (strcmp(name, "snaplen") == 0) { 643 pconfig->pcap.snap_len = (uint16_t)atoi(value); 644 } else if (strcmp(name, "savelen") == 0) { 645 pconfig->pcap.save_len = (uint32_t)atoi(value); 646 } else if (strcmp(name, "enable") == 0) { 647 pconfig->pcap.enable = (uint16_t)atoi(value); 648 } else if (strcmp(name, "savepath") == 0) { 649 pconfig->pcap.save_path = strdup(value); 650 } 651 } 652 653 return 1; 654 } 655 656 static int 657 dpdk_args_setup(struct ff_config *cfg) 658 { 659 int n = 0, i; 660 dpdk_argv[n++] = strdup("f-stack"); 661 char temp[DPDK_CONFIG_MAXLEN] = {0}, temp2[DPDK_CONFIG_MAXLEN] = {0}; 662 663 if (cfg->dpdk.no_huge) { 664 dpdk_argv[n++] = strdup("--no-huge"); 665 } 666 if (cfg->dpdk.proc_mask) { 667 sprintf(temp, "-c%s", cfg->dpdk.proc_mask); 668 dpdk_argv[n++] = strdup(temp); 669 } 670 if (cfg->dpdk.nb_channel) { 671 sprintf(temp, "-n%d", cfg->dpdk.nb_channel); 672 dpdk_argv[n++] = strdup(temp); 673 } 674 if (cfg->dpdk.memory) { 675 sprintf(temp, "-m%d", cfg->dpdk.memory); 676 dpdk_argv[n++] = strdup(temp); 677 } 678 if (cfg->dpdk.proc_type) { 679 sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type); 680 dpdk_argv[n++] = strdup(temp); 681 } 682 if (cfg->dpdk.base_virtaddr) { 683 sprintf(temp, "--base-virtaddr=%s", cfg->dpdk.base_virtaddr); 684 dpdk_argv[n++] = strdup(temp); 685 } 686 if (cfg->dpdk.file_prefix) { 687 sprintf(temp, "--file-prefix=container-%s", cfg->dpdk.file_prefix); 688 dpdk_argv[n++] = strdup(temp); 689 } 690 if (cfg->dpdk.pci_whitelist) { 691 sprintf(temp, "--pci-whitelist=%s", cfg->dpdk.pci_whitelist); 692 dpdk_argv[n++] = strdup(temp); 693 } 694 695 if (cfg->dpdk.nb_vdev) { 696 for (i=0; i<cfg->dpdk.nb_vdev; i++) { 697 sprintf(temp, "--vdev=virtio_user%d,path=%s", 698 cfg->dpdk.vdev_cfgs[i].vdev_id, 699 cfg->dpdk.vdev_cfgs[i].path); 700 if (cfg->dpdk.vdev_cfgs[i].nb_queues) { 701 sprintf(temp2, ",queues=%u", 702 cfg->dpdk.vdev_cfgs[i].nb_queues); 703 strcat(temp, temp2); 704 } 705 if (cfg->dpdk.vdev_cfgs[i].nb_cq) { 706 sprintf(temp2, ",cq=%u", 707 cfg->dpdk.vdev_cfgs[i].nb_cq); 708 strcat(temp, temp2); 709 } 710 if (cfg->dpdk.vdev_cfgs[i].queue_size) { 711 sprintf(temp2, ",queue_size=%u", 712 cfg->dpdk.vdev_cfgs[i].queue_size); 713 strcat(temp, temp2); 714 } 715 if (cfg->dpdk.vdev_cfgs[i].mac) { 716 sprintf(temp2, ",mac=%s", 717 cfg->dpdk.vdev_cfgs[i].mac); 718 strcat(temp, temp2); 719 } 720 dpdk_argv[n++] = strdup(temp); 721 } 722 sprintf(temp, "--no-pci"); 723 dpdk_argv[n++] = strdup(temp); 724 if (!cfg->dpdk.file_prefix) { 725 sprintf(temp, "--file-prefix=container"); 726 dpdk_argv[n++] = strdup(temp); 727 } 728 } 729 730 if (cfg->dpdk.nb_bond) { 731 for (i=0; i<cfg->dpdk.nb_bond; i++) { 732 sprintf(temp, "--vdev"); 733 dpdk_argv[n++] = strdup(temp); 734 sprintf(temp, "net_bonding%d,mode=%d,slave=%s", 735 cfg->dpdk.bond_cfgs[i].bond_id, 736 cfg->dpdk.bond_cfgs[i].mode, 737 cfg->dpdk.bond_cfgs[i].slave); 738 739 if (cfg->dpdk.bond_cfgs[i].primary) { 740 sprintf(temp2, ",primary=%s", 741 cfg->dpdk.bond_cfgs[i].primary); 742 strcat(temp, temp2); 743 } 744 745 if (cfg->dpdk.bond_cfgs[i].socket_id) { 746 sprintf(temp2, ",socket_id=%d", 747 cfg->dpdk.bond_cfgs[i].socket_id); 748 strcat(temp, temp2); 749 } 750 751 if (cfg->dpdk.bond_cfgs[i].bond_mac) { 752 sprintf(temp2, ",mac=%s", 753 cfg->dpdk.bond_cfgs[i].bond_mac); 754 strcat(temp, temp2); 755 } 756 757 if (cfg->dpdk.bond_cfgs[i].xmit_policy) { 758 sprintf(temp2, ",xmit_policy=%s", 759 cfg->dpdk.bond_cfgs[i].xmit_policy); 760 strcat(temp, temp2); 761 } 762 763 if (cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms) { 764 sprintf(temp2, ",lsc_poll_period_ms=%d", 765 cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms); 766 strcat(temp, temp2); 767 } 768 769 if (cfg->dpdk.bond_cfgs[i].up_delay) { 770 sprintf(temp2, ",up_delay=%d", 771 cfg->dpdk.bond_cfgs[i].up_delay); 772 strcat(temp, temp2); 773 } 774 775 if (cfg->dpdk.bond_cfgs[i].down_delay) { 776 sprintf(temp2, ",down_delay=%d", 777 cfg->dpdk.bond_cfgs[i].down_delay); 778 strcat(temp, temp2); 779 } 780 dpdk_argv[n++] = strdup(temp); 781 } 782 } 783 784 dpdk_argc = n; 785 786 for (i=0; i<n; i++) 787 printf("%s ", dpdk_argv[i]); 788 789 return n; 790 } 791 792 static int 793 ff_parse_args(struct ff_config *cfg, int argc, char *const argv[]) 794 { 795 int c; 796 int index = 0; 797 optind = 1; 798 while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) { 799 switch (c) { 800 case 'c': 801 cfg->filename = strdup(optarg); 802 break; 803 case 'p': 804 cfg->dpdk.proc_id = atoi(optarg); 805 break; 806 case 't': 807 cfg->dpdk.proc_type = strdup(optarg); 808 break; 809 default: 810 return -1; 811 } 812 } 813 814 if (cfg->dpdk.proc_type == NULL) { 815 cfg->dpdk.proc_type = strdup("auto"); 816 } 817 818 if (strcmp(cfg->dpdk.proc_type, "primary") && 819 strcmp(cfg->dpdk.proc_type, "secondary") && 820 strcmp(cfg->dpdk.proc_type, "auto")) { 821 printf("invalid proc-type:%s\n", cfg->dpdk.proc_type); 822 return -1; 823 } 824 825 if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) { 826 printf("invalid proc_id:%d, use default 0\n", cfg->dpdk.proc_id); 827 cfg->dpdk.proc_id = 0; 828 } 829 830 return 0; 831 } 832 833 static int 834 ff_check_config(struct ff_config *cfg) 835 { 836 if(cfg->kni.enable && !cfg->kni.method) { 837 fprintf(stderr, "conf dpdk.method is necessary\n"); 838 return -1; 839 } 840 841 if(cfg->kni.method) { 842 if(strcasecmp(cfg->kni.method,"accept") && 843 strcasecmp(cfg->kni.method,"reject")) { 844 fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n", 845 cfg->kni.method); 846 return -1; 847 } 848 } 849 850 if(cfg->kni.kni_action) { 851 if (strcasecmp(cfg->kni.kni_action,"alltokni") && 852 strcasecmp(cfg->kni.kni_action,"alltoff") && 853 strcasecmp(cfg->kni.kni_action,"default")){ 854 fprintf(stderr, "conf kni.kni_action[alltokni|alltoff|default] is error(%s)\n", 855 cfg->kni.kni_action); 856 return -1; 857 } 858 } 859 860 if (cfg->pcap.save_len < PCAP_SAVE_MINLEN) 861 cfg->pcap.save_len = PCAP_SAVE_MINLEN; 862 if (cfg->pcap.snap_len < PCAP_SNAP_MINLEN) 863 cfg->pcap.snap_len = PCAP_SNAP_MINLEN; 864 if (cfg->pcap.save_path==NULL || strlen(cfg->pcap.save_path) ==0) 865 cfg->pcap.save_path = strdup("."); 866 867 #define CHECK_VALID(n) \ 868 do { \ 869 if (!pc->n) { \ 870 fprintf(stderr, "port%d if config error: no %s\n", \ 871 pc->port_id, #n); \ 872 return -1; \ 873 } \ 874 } while (0) 875 876 int i; 877 for (i = 0; i < cfg->dpdk.nb_ports; i++) { 878 uint16_t portid = cfg->dpdk.portid_list[i]; 879 struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[portid]; 880 CHECK_VALID(addr); 881 CHECK_VALID(netmask); 882 CHECK_VALID(broadcast); 883 CHECK_VALID(gateway); 884 // check if the lcores in lcore_list are enabled. 885 int k; 886 for (k = 0; k < pc->nb_lcores; k++) { 887 uint16_t lcore_id = pc->lcore_list[k]; 888 if (uint16_binary_search(cfg->dpdk.proc_lcore, 0, 889 cfg->dpdk.nb_procs-1, lcore_id) < 0) { 890 fprintf(stderr, "lcore %d is not enabled.\n", lcore_id); 891 return -1; 892 } 893 } 894 /* 895 * only primary process process KNI, so if KNI enabled, 896 * primary lcore must stay in every enabled ports' lcore_list 897 */ 898 if (cfg->kni.enable && 899 strcmp(cfg->dpdk.proc_type, "primary") == 0) { 900 int found = 0; 901 int j; 902 uint16_t lcore_id = cfg->dpdk.proc_lcore[cfg->dpdk.proc_id]; 903 for (j = 0; j < pc->nb_lcores; j++) { 904 if (pc->lcore_list[j] == lcore_id) { 905 found = 1; 906 } 907 } 908 if (! found) { 909 fprintf(stderr, 910 "primary lcore %d should stay in port %d's lcore_list.\n", 911 lcore_id, pc->port_id); 912 return -1; 913 } 914 } 915 } 916 917 return 0; 918 } 919 920 static void 921 ff_default_config(struct ff_config *cfg) 922 { 923 memset(cfg, 0, sizeof(struct ff_config)); 924 925 cfg->filename = DEFAULT_CONFIG_FILE; 926 927 cfg->dpdk.proc_id = -1; 928 cfg->dpdk.numa_on = 1; 929 cfg->dpdk.promiscuous = 1; 930 cfg->dpdk.pkt_tx_delay = BURST_TX_DRAIN_US; 931 932 cfg->freebsd.hz = 100; 933 cfg->freebsd.physmem = 1048576*256; 934 cfg->freebsd.fd_reserve = 0; 935 cfg->freebsd.mem_size = 256; 936 } 937 938 int 939 ff_load_config(int argc, char *const argv[]) 940 { 941 ff_default_config(&ff_global_cfg); 942 943 int ret = ff_parse_args(&ff_global_cfg, argc, argv); 944 if (ret < 0) { 945 return ret; 946 } 947 948 ret = ini_parse(ff_global_cfg.filename, ini_parse_handler, 949 &ff_global_cfg); 950 if (ret != 0) { 951 printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret); 952 return -1; 953 } 954 955 if (ff_check_config(&ff_global_cfg)) { 956 return -1; 957 } 958 959 if (dpdk_args_setup(&ff_global_cfg) <= 0) { 960 return -1; 961 } 962 963 return 0; 964 } 965