1 /* 2 * Copyright (C) 2017-2021 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 free(newconf); 195 return 0; 196 } 197 198 if (*cur == NULL) { 199 newconf->next = NULL; 200 *cur = newconf; 201 } else { 202 newconf->next = (*cur)->next; 203 (*cur)->next = newconf; 204 } 205 206 return 1; 207 } 208 // A recursive binary search function. It returns location of x in 209 // given array arr[l..r] is present, otherwise -1 210 static int 211 uint16_binary_search(uint16_t arr[], int l, int r, uint16_t x) 212 { 213 if (r >= l) { 214 int mid = l + (r - l)/2; 215 216 // If the element is present at the middle itself 217 if (arr[mid] == x) return mid; 218 219 // If element is smaller than mid, then it can only be present 220 // in left subarray 221 if (arr[mid] > x) return uint16_binary_search(arr, l, mid-1, x); 222 223 // Else the element can only be present in right subarray 224 return uint16_binary_search(arr, mid+1, r, x); 225 } 226 227 // We reach here when element is not present in array 228 return -1; 229 } 230 231 static int 232 uint16_cmp (const void * a, const void * b) 233 { 234 return ( *(uint16_t*)a - *(uint16_t*)b ); 235 } 236 237 static inline void 238 sort_uint16_array(uint16_t arr[], int n) 239 { 240 qsort(arr, n, sizeof(uint16_t), uint16_cmp); 241 } 242 243 static inline char * 244 __strstrip(char *s) 245 { 246 char *end = s + strlen(s) - 1; 247 while(*s == ' ') s++; 248 for (; end >= s; --end) { 249 if (*end != ' ') break; 250 } 251 *(++end) = '\0'; 252 return s; 253 } 254 255 static int 256 __parse_config_list(uint16_t *arr, int *sz, const char *value) { 257 int i, j; 258 char input[4096]; 259 char *tokens[128]; 260 int nTokens = 0; 261 char *endptr; 262 int nr_ele = 0; 263 int max_ele = *sz; 264 265 strncpy(input, value, sizeof(input) - 1); 266 nTokens = rte_strsplit(input, sizeof(input), tokens, 128, ','); 267 for (i = 0; i < nTokens; i++) { 268 char *tok = tokens[i]; 269 char *middle = strchr(tok, '-'); 270 if (middle == NULL) { 271 tok = __strstrip(tok); 272 long v = strtol(tok, &endptr, 10); 273 if (*endptr != '\0') { 274 fprintf(stderr, "%s is not a integer.", tok); 275 return 0; 276 } 277 if (nr_ele > max_ele) { 278 fprintf(stderr, "too many elements in list %s\n", value); 279 return 0; 280 } 281 arr[nr_ele++] = (uint16_t)v; 282 } else { 283 *middle = '\0'; 284 char *lbound = __strstrip(tok); 285 char *rbound = __strstrip(middle+1); 286 long lv = strtol(lbound, &endptr, 10); 287 if (*endptr != '\0') { 288 fprintf(stderr, "%s is not a integer.", lbound); 289 return 0; 290 } 291 long rv = strtol(rbound, &endptr, 10); 292 if (*endptr != '\0') { 293 fprintf(stderr, "%s is not a integer.", rbound); 294 return 0; 295 } 296 for (j = lv; j <= rv; ++j) { 297 if (nr_ele > max_ele) { 298 fprintf(stderr, "too many elements in list %s.\n", value); 299 return 0; 300 } 301 arr[nr_ele++] = (uint16_t)j; 302 } 303 } 304 } 305 if (nr_ele <= 0) { 306 fprintf(stderr, "list %s is empty\n", value); 307 return 1; 308 } 309 sort_uint16_array(arr, nr_ele); 310 *sz = nr_ele; 311 return 1; 312 } 313 314 static int 315 parse_port_lcore_list(struct ff_port_cfg *cfg, const char *v_str) 316 { 317 cfg->nb_lcores = DPDK_MAX_LCORE; 318 uint16_t *cores = cfg->lcore_list; 319 return __parse_config_list(cores, &cfg->nb_lcores, v_str); 320 } 321 322 static int 323 parse_port_list(struct ff_config *cfg, const char *v_str) 324 { 325 int res; 326 uint16_t ports[RTE_MAX_ETHPORTS]; 327 int sz = RTE_MAX_ETHPORTS; 328 329 res = __parse_config_list(ports, &sz, v_str); 330 if (! res) return res; 331 332 uint16_t *portid_list = malloc(sizeof(uint16_t)*sz); 333 334 if (portid_list == NULL) { 335 fprintf(stderr, "parse_port_list malloc failed\n"); 336 return 0; 337 } 338 memcpy(portid_list, ports, sz*sizeof(uint16_t)); 339 340 cfg->dpdk.portid_list = portid_list; 341 cfg->dpdk.nb_ports = sz; 342 cfg->dpdk.max_portid = portid_list[sz-1]; 343 return res; 344 } 345 346 static int 347 parse_port_slave_list(struct ff_port_cfg *cfg, const char *v_str) 348 { 349 int res; 350 uint16_t ports[RTE_MAX_ETHPORTS]; 351 int sz = RTE_MAX_ETHPORTS; 352 353 res = __parse_config_list(ports, &sz, v_str); 354 if (! res) return res; 355 356 uint16_t *portid_list = malloc(sizeof(uint16_t)*sz); 357 358 if (portid_list == NULL) { 359 fprintf(stderr, "parse_port_slave_list malloc failed\n"); 360 return 0; 361 } 362 memcpy(portid_list, ports, sz*sizeof(uint16_t)); 363 364 cfg->slave_portid_list = portid_list; 365 cfg->nb_slaves = sz; 366 367 return res; 368 } 369 370 static int 371 vip_cfg_handler(struct ff_port_cfg *cur) 372 { 373 //vip cfg 374 int ret; 375 char *vip_addr_array[VIP_MAX_NUM]; 376 377 ret = rte_strsplit(cur->vip_addr_str, strlen(cur->vip_addr_str), &vip_addr_array[0], VIP_MAX_NUM, ';'); 378 if (ret <= 0) { 379 fprintf(stdout, "vip_cfg_handler nb_vip is 0, not set vip_addr or set invalid vip_addr %s\n", 380 cur->vip_addr_str); 381 return 1; 382 } 383 384 cur->nb_vip = ret; 385 386 cur->vip_addr_array = (char **)calloc(cur->nb_vip, sizeof(char *)); 387 if (cur->vip_addr_array == NULL) { 388 fprintf(stderr, "vip_cfg_handler malloc failed\n"); 389 goto err; 390 } 391 392 memcpy(cur->vip_addr_array, vip_addr_array, cur->nb_vip * sizeof(char *)); 393 394 return 1; 395 396 err: 397 cur->nb_vip = 0; 398 if (cur->vip_addr_array) { 399 free(cur->vip_addr_array); 400 cur->vip_addr_array = NULL; 401 } 402 403 return 0; 404 } 405 406 #ifdef INET6 407 static int 408 vip6_cfg_handler(struct ff_port_cfg *cur) 409 { 410 //vip6 cfg 411 int ret; 412 char *vip_addr6_array[VIP_MAX_NUM]; 413 414 ret = rte_strsplit(cur->vip_addr6_str, strlen(cur->vip_addr6_str), 415 &vip_addr6_array[0], VIP_MAX_NUM, ';'); 416 if (ret == 0) { 417 fprintf(stdout, "vip6_cfg_handler nb_vip6 is 0, not set vip_addr6 or set invalid vip_addr6 %s\n", 418 cur->vip_addr6_str); 419 return 1; 420 } 421 422 cur->nb_vip6 = ret; 423 424 cur->vip_addr6_array = (char **) calloc(cur->nb_vip6, sizeof(char *)); 425 if (cur->vip_addr6_array == NULL) { 426 fprintf(stderr, "vip6_cfg_handler malloc failed\n"); 427 goto fail; 428 } 429 430 memcpy(cur->vip_addr6_array, vip_addr6_array, cur->nb_vip6 * sizeof(char *)); 431 432 return 1; 433 434 fail: 435 cur->nb_vip6 = 0; 436 if (cur->vip_addr6_array) { 437 free(cur->vip_addr6_array); 438 cur->vip_addr6_array = NULL; 439 } 440 441 return 0; 442 } 443 #endif 444 445 static int 446 port_cfg_handler(struct ff_config *cfg, const char *section, 447 const char *name, const char *value) { 448 449 if (cfg->dpdk.nb_ports == 0) { 450 fprintf(stderr, "port_cfg_handler: must config dpdk.port_list first\n"); 451 return 0; 452 } 453 454 if (cfg->dpdk.port_cfgs == NULL) { 455 struct ff_port_cfg *pc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_port_cfg)); 456 if (pc == NULL) { 457 fprintf(stderr, "port_cfg_handler malloc failed\n"); 458 return 0; 459 } 460 // initialize lcore list and nb_lcores 461 int i; 462 for (i = 0; i < cfg->dpdk.nb_ports; ++i) { 463 uint16_t portid = cfg->dpdk.portid_list[i]; 464 465 struct ff_port_cfg *pconf = &pc[portid]; 466 pconf->port_id = portid; 467 pconf->nb_lcores = ff_global_cfg.dpdk.nb_procs; 468 memcpy(pconf->lcore_list, ff_global_cfg.dpdk.proc_lcore, 469 pconf->nb_lcores*sizeof(uint16_t)); 470 } 471 cfg->dpdk.port_cfgs = pc; 472 } 473 474 int portid; 475 int ret = sscanf(section, "port%d", &portid); 476 if (ret != 1) { 477 fprintf(stderr, "port_cfg_handler section[%s] error\n", section); 478 return 0; 479 } 480 481 /* just return true if portid >= nb_ports because it has no effect */ 482 if (portid > cfg->dpdk.max_portid) { 483 fprintf(stderr, "port_cfg_handler section[%s] bigger than max port id\n", section); 484 return 1; 485 } 486 487 struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid]; 488 if (cur->name == NULL) { 489 cur->name = strdup(section); 490 cur->port_id = portid; 491 } 492 493 if (strcmp(name, "ifc_name") == 0) { 494 cur->ifname = strdup(value); 495 } else if (strcmp(name, "addr") == 0) { 496 cur->addr = strdup(value); 497 } else if (strcmp(name, "netmask") == 0) { 498 cur->netmask = strdup(value); 499 } else if (strcmp(name, "broadcast") == 0) { 500 cur->broadcast = strdup(value); 501 } else if (strcmp(name, "gateway") == 0) { 502 cur->gateway = strdup(value); 503 } else if (strcmp(name, "lcore_list") == 0) { 504 return parse_port_lcore_list(cur, value); 505 } else if (strcmp(name, "slave_port_list") == 0) { 506 return parse_port_slave_list(cur, value); 507 } else if (strcmp(name, "vip_addr") == 0) { 508 cur->vip_addr_str = strdup(value); 509 if (cur->vip_addr_str) { 510 return vip_cfg_handler(cur); 511 } 512 } else if (strcmp(name, "vip_ifname") == 0) { 513 cur->vip_ifname = strdup(value); 514 } 515 516 #ifdef INET6 517 else if (0 == strcmp(name, "addr6")) { 518 cur->addr6_str = strdup(value); 519 } else if (0 == strcmp(name, "prefix_len")) { 520 cur->prefix_len = atoi(value); 521 } else if (0 == strcmp(name, "gateway6")) { 522 cur->gateway6_str = strdup(value); 523 } else if (strcmp(name, "vip_addr6") == 0) { 524 cur->vip_addr6_str = strdup(value); 525 if (cur->vip_addr6_str) { 526 return vip6_cfg_handler(cur); 527 } 528 } else if (0 == strcmp(name, "vip_prefix_len")) { 529 cur->vip_prefix_len = atoi(value); 530 } 531 #endif 532 533 return 1; 534 } 535 536 static int 537 vdev_cfg_handler(struct ff_config *cfg, const char *section, 538 const char *name, const char *value) { 539 540 if (cfg->dpdk.nb_vdev == 0) { 541 fprintf(stderr, "vdev_cfg_handler: must config dpdk.nb_vdev first\n"); 542 return 0; 543 } 544 545 if (cfg->dpdk.vdev_cfgs == NULL) { 546 struct ff_vdev_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_vdev_cfg)); 547 if (vc == NULL) { 548 fprintf(stderr, "vdev_cfg_handler malloc failed\n"); 549 return 0; 550 } 551 cfg->dpdk.vdev_cfgs = vc; 552 } 553 554 int vdevid; 555 int ret = sscanf(section, "vdev%d", &vdevid); 556 if (ret != 1) { 557 fprintf(stderr, "vdev_cfg_handler section[%s] error\n", section); 558 return 0; 559 } 560 561 /* just return true if vdevid >= nb_vdev because it has no effect */ 562 if (vdevid > cfg->dpdk.nb_vdev) { 563 fprintf(stderr, "vdev_cfg_handler section[%s] bigger than max vdev id\n", section); 564 return 1; 565 } 566 567 struct ff_vdev_cfg *cur = &cfg->dpdk.vdev_cfgs[vdevid]; 568 if (cur->name == NULL) { 569 cur->name = strdup(section); 570 cur->vdev_id = vdevid; 571 } 572 573 if (strcmp(name, "iface") == 0) { 574 cur->iface = strdup(value); 575 } else if (strcmp(name, "path") == 0) { 576 cur->path = strdup(value); 577 } else if (strcmp(name, "queues") == 0) { 578 cur->nb_queues = atoi(value); 579 } else if (strcmp(name, "queue_size") == 0) { 580 cur->queue_size = atoi(value); 581 } else if (strcmp(name, "mac") == 0) { 582 cur->mac = strdup(value); 583 } else if (strcmp(name, "cq") == 0) { 584 cur->nb_cq = atoi(value); 585 } 586 587 return 1; 588 } 589 590 static int 591 bond_cfg_handler(struct ff_config *cfg, const char *section, 592 const char *name, const char *value) { 593 594 if (cfg->dpdk.nb_bond == 0) { 595 fprintf(stderr, "bond_cfg_handler: must config dpdk.nb_bond first\n"); 596 return 0; 597 } 598 599 if (cfg->dpdk.bond_cfgs == NULL) { 600 struct ff_bond_cfg *vc = calloc(RTE_MAX_ETHPORTS, sizeof(struct ff_bond_cfg)); 601 if (vc == NULL) { 602 fprintf(stderr, "ff_bond_cfg malloc failed\n"); 603 return 0; 604 } 605 cfg->dpdk.bond_cfgs = vc; 606 } 607 608 int bondid; 609 int ret = sscanf(section, "bond%d", &bondid); 610 if (ret != 1) { 611 fprintf(stderr, "bond_cfg_handler section[%s] error\n", section); 612 return 0; 613 } 614 615 /* just return true if bondid >= nb_vdev because it has no effect */ 616 if (bondid > cfg->dpdk.nb_bond) { 617 fprintf(stderr, "bond_cfg_handler section[%s] bigger than max bond id\n", section); 618 return 1; 619 } 620 621 struct ff_bond_cfg *cur = &cfg->dpdk.bond_cfgs[bondid]; 622 if (cur->name == NULL) { 623 cur->name = strdup(section); 624 cur->bond_id = bondid; 625 } 626 627 if (strcmp(name, "mode") == 0) { 628 cur->mode = atoi(value); 629 } else if (strcmp(name, "slave") == 0) { 630 cur->slave = strdup(value); 631 } else if (strcmp(name, "primary") == 0) { 632 cur->primary = strdup(value); 633 } else if (strcmp(name, "socket_id") == 0) { 634 cur->socket_id = atoi(value); 635 } else if (strcmp(name, "mac") == 0) { 636 cur->bond_mac = strdup(value); 637 } else if (strcmp(name, "xmit_policy") == 0) { 638 cur->xmit_policy = strdup(value); 639 } else if (strcmp(name, "lsc_poll_period_ms") == 0) { 640 cur->lsc_poll_period_ms = atoi(value); 641 } else if (strcmp(name, "up_delay") == 0) { 642 cur->up_delay = atoi(value); 643 } else if (strcmp(name, "down_delay") == 0) { 644 cur->down_delay = atoi(value); 645 } 646 647 return 1; 648 } 649 650 static int 651 ini_parse_handler(void* user, const char* section, const char* name, 652 const char* value) 653 { 654 struct ff_config *pconfig = (struct ff_config*)user; 655 656 printf("[%s]: %s=%s\n", section, name, value); 657 658 #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 659 if (MATCH("dpdk", "channel")) { 660 pconfig->dpdk.nb_channel = atoi(value); 661 } else if (MATCH("dpdk", "memory")) { 662 pconfig->dpdk.memory = atoi(value); 663 } else if (MATCH("dpdk", "no_huge")) { 664 pconfig->dpdk.no_huge = atoi(value); 665 } else if (MATCH("dpdk", "lcore_mask")) { 666 pconfig->dpdk.lcore_mask = strdup(value); 667 return parse_lcore_mask(pconfig, pconfig->dpdk.lcore_mask); 668 } else if (MATCH("dpdk", "base_virtaddr")) { 669 pconfig->dpdk.base_virtaddr= strdup(value); 670 } else if (MATCH("dpdk", "file_prefix")) { 671 pconfig->dpdk.file_prefix = strdup(value); 672 } else if (MATCH("dpdk", "pci_whitelist")) { 673 pconfig->dpdk.pci_whitelist = strdup(value); 674 } else if (MATCH("dpdk", "port_list")) { 675 return parse_port_list(pconfig, value); 676 } else if (MATCH("dpdk", "nb_vdev")) { 677 pconfig->dpdk.nb_vdev = atoi(value); 678 } else if (MATCH("dpdk", "nb_bond")) { 679 pconfig->dpdk.nb_bond = atoi(value); 680 } else if (MATCH("dpdk", "promiscuous")) { 681 pconfig->dpdk.promiscuous = atoi(value); 682 } else if (MATCH("dpdk", "numa_on")) { 683 pconfig->dpdk.numa_on = atoi(value); 684 } else if (MATCH("dpdk", "tso")) { 685 pconfig->dpdk.tso = atoi(value); 686 } else if (MATCH("dpdk", "tx_csum_offoad_skip")) { 687 pconfig->dpdk.tx_csum_offoad_skip = atoi(value); 688 } else if (MATCH("dpdk", "vlan_strip")) { 689 pconfig->dpdk.vlan_strip = atoi(value); 690 } else if (MATCH("dpdk", "idle_sleep")) { 691 pconfig->dpdk.idle_sleep = atoi(value); 692 } else if (MATCH("dpdk", "pkt_tx_delay")) { 693 pconfig->dpdk.pkt_tx_delay = atoi(value); 694 } else if (MATCH("dpdk", "symmetric_rss")) { 695 pconfig->dpdk.symmetric_rss = atoi(value); 696 } else if (MATCH("kni", "enable")) { 697 pconfig->kni.enable= atoi(value); 698 } else if (MATCH("kni", "kni_action")) { 699 pconfig->kni.kni_action= strdup(value); 700 } else if (MATCH("kni", "method")) { 701 pconfig->kni.method= strdup(value); 702 } else if (MATCH("kni", "tcp_port")) { 703 pconfig->kni.tcp_port = strdup(value); 704 } else if (MATCH("kni", "udp_port")) { 705 pconfig->kni.udp_port= strdup(value); 706 } else if (strcmp(section, "freebsd.boot") == 0) { 707 if (strcmp(name, "hz") == 0) { 708 pconfig->freebsd.hz = atoi(value); 709 } else if (strcmp(name, "physmem") == 0) { 710 pconfig->freebsd.physmem = atol(value); 711 } else if (strcmp(name, "fd_reserve") == 0) { 712 pconfig->freebsd.fd_reserve = atoi(value); 713 } else if (strcmp(name, "memsz_MB") == 0) { 714 pconfig->freebsd.mem_size = atoi(value); 715 } else { 716 return freebsd_conf_handler(pconfig, "boot", name, value); 717 } 718 } else if (strcmp(section, "freebsd.sysctl") == 0) { 719 return freebsd_conf_handler(pconfig, "sysctl", name, value); 720 } else if (strncmp(section, "port", 4) == 0) { 721 return port_cfg_handler(pconfig, section, name, value); 722 } else if (strncmp(section, "vdev", 4) == 0) { 723 return vdev_cfg_handler(pconfig, section, name, value); 724 } else if (strncmp(section, "bond", 4) == 0) { 725 return bond_cfg_handler(pconfig, section, name, value); 726 } else if (strcmp(section, "pcap") == 0) { 727 if (strcmp(name, "snaplen") == 0) { 728 pconfig->pcap.snap_len = (uint16_t)atoi(value); 729 } else if (strcmp(name, "savelen") == 0) { 730 pconfig->pcap.save_len = (uint32_t)atoi(value); 731 } else if (strcmp(name, "enable") == 0) { 732 pconfig->pcap.enable = (uint16_t)atoi(value); 733 } else if (strcmp(name, "savepath") == 0) { 734 pconfig->pcap.save_path = strdup(value); 735 } 736 } 737 738 return 1; 739 } 740 741 static int 742 dpdk_args_setup(struct ff_config *cfg) 743 { 744 int n = 0, i; 745 dpdk_argv[n++] = strdup("f-stack"); 746 char temp[DPDK_CONFIG_MAXLEN] = {0}, temp2[DPDK_CONFIG_MAXLEN] = {0}; 747 748 if (cfg->dpdk.no_huge) { 749 dpdk_argv[n++] = strdup("--no-huge"); 750 } 751 if (cfg->dpdk.proc_mask) { 752 sprintf(temp, "-c%s", cfg->dpdk.proc_mask); 753 dpdk_argv[n++] = strdup(temp); 754 } 755 if (cfg->dpdk.nb_channel) { 756 sprintf(temp, "-n%d", cfg->dpdk.nb_channel); 757 dpdk_argv[n++] = strdup(temp); 758 } 759 if (cfg->dpdk.memory) { 760 sprintf(temp, "-m%d", cfg->dpdk.memory); 761 dpdk_argv[n++] = strdup(temp); 762 } 763 if (cfg->dpdk.proc_type) { 764 sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type); 765 dpdk_argv[n++] = strdup(temp); 766 } 767 if (cfg->dpdk.base_virtaddr) { 768 sprintf(temp, "--base-virtaddr=%s", cfg->dpdk.base_virtaddr); 769 dpdk_argv[n++] = strdup(temp); 770 } 771 if (cfg->dpdk.file_prefix) { 772 sprintf(temp, "--file-prefix=container-%s", cfg->dpdk.file_prefix); 773 dpdk_argv[n++] = strdup(temp); 774 } 775 if (cfg->dpdk.pci_whitelist) { 776 char* token; 777 char* rest = cfg->dpdk.pci_whitelist; 778 779 while ((token = strtok_r(rest, ",", &rest))){ 780 sprintf(temp, "--pci-whitelist=%s", token); 781 dpdk_argv[n++] = strdup(temp); 782 } 783 784 } 785 786 if (cfg->dpdk.nb_vdev) { 787 for (i=0; i<cfg->dpdk.nb_vdev; i++) { 788 sprintf(temp, "--vdev=virtio_user%d,path=%s", 789 cfg->dpdk.vdev_cfgs[i].vdev_id, 790 cfg->dpdk.vdev_cfgs[i].path); 791 if (cfg->dpdk.vdev_cfgs[i].nb_queues) { 792 sprintf(temp2, ",queues=%u", 793 cfg->dpdk.vdev_cfgs[i].nb_queues); 794 strcat(temp, temp2); 795 } 796 if (cfg->dpdk.vdev_cfgs[i].nb_cq) { 797 sprintf(temp2, ",cq=%u", 798 cfg->dpdk.vdev_cfgs[i].nb_cq); 799 strcat(temp, temp2); 800 } 801 if (cfg->dpdk.vdev_cfgs[i].queue_size) { 802 sprintf(temp2, ",queue_size=%u", 803 cfg->dpdk.vdev_cfgs[i].queue_size); 804 strcat(temp, temp2); 805 } 806 if (cfg->dpdk.vdev_cfgs[i].mac) { 807 sprintf(temp2, ",mac=%s", 808 cfg->dpdk.vdev_cfgs[i].mac); 809 strcat(temp, temp2); 810 } 811 dpdk_argv[n++] = strdup(temp); 812 } 813 sprintf(temp, "--no-pci"); 814 dpdk_argv[n++] = strdup(temp); 815 if (!cfg->dpdk.file_prefix) { 816 sprintf(temp, "--file-prefix=container"); 817 dpdk_argv[n++] = strdup(temp); 818 } 819 } 820 821 if (cfg->dpdk.nb_bond) { 822 for (i=0; i<cfg->dpdk.nb_bond; i++) { 823 sprintf(temp, "--vdev"); 824 dpdk_argv[n++] = strdup(temp); 825 sprintf(temp, "net_bonding%d,mode=%d,slave=%s", 826 cfg->dpdk.bond_cfgs[i].bond_id, 827 cfg->dpdk.bond_cfgs[i].mode, 828 cfg->dpdk.bond_cfgs[i].slave); 829 830 if (cfg->dpdk.bond_cfgs[i].primary) { 831 sprintf(temp2, ",primary=%s", 832 cfg->dpdk.bond_cfgs[i].primary); 833 strcat(temp, temp2); 834 } 835 836 if (cfg->dpdk.bond_cfgs[i].socket_id) { 837 sprintf(temp2, ",socket_id=%d", 838 cfg->dpdk.bond_cfgs[i].socket_id); 839 strcat(temp, temp2); 840 } 841 842 if (cfg->dpdk.bond_cfgs[i].bond_mac) { 843 sprintf(temp2, ",mac=%s", 844 cfg->dpdk.bond_cfgs[i].bond_mac); 845 strcat(temp, temp2); 846 } 847 848 if (cfg->dpdk.bond_cfgs[i].xmit_policy) { 849 sprintf(temp2, ",xmit_policy=%s", 850 cfg->dpdk.bond_cfgs[i].xmit_policy); 851 strcat(temp, temp2); 852 } 853 854 if (cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms) { 855 sprintf(temp2, ",lsc_poll_period_ms=%d", 856 cfg->dpdk.bond_cfgs[i].lsc_poll_period_ms); 857 strcat(temp, temp2); 858 } 859 860 if (cfg->dpdk.bond_cfgs[i].up_delay) { 861 sprintf(temp2, ",up_delay=%d", 862 cfg->dpdk.bond_cfgs[i].up_delay); 863 strcat(temp, temp2); 864 } 865 866 if (cfg->dpdk.bond_cfgs[i].down_delay) { 867 sprintf(temp2, ",down_delay=%d", 868 cfg->dpdk.bond_cfgs[i].down_delay); 869 strcat(temp, temp2); 870 } 871 dpdk_argv[n++] = strdup(temp); 872 } 873 } 874 875 dpdk_argc = n; 876 877 for (i=0; i<n; i++) 878 printf("%s ", dpdk_argv[i]); 879 880 return n; 881 } 882 883 static int 884 ff_parse_args(struct ff_config *cfg, int argc, char *const argv[]) 885 { 886 int c; 887 int index = 0; 888 optind = 1; 889 while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) { 890 switch (c) { 891 case 'c': 892 cfg->filename = strdup(optarg); 893 break; 894 case 'p': 895 cfg->dpdk.proc_id = atoi(optarg); 896 break; 897 case 't': 898 cfg->dpdk.proc_type = strdup(optarg); 899 break; 900 default: 901 return -1; 902 } 903 } 904 905 if (cfg->dpdk.proc_type == NULL) { 906 cfg->dpdk.proc_type = strdup("auto"); 907 } 908 909 if (strcmp(cfg->dpdk.proc_type, "primary") && 910 strcmp(cfg->dpdk.proc_type, "secondary") && 911 strcmp(cfg->dpdk.proc_type, "auto")) { 912 printf("invalid proc-type:%s\n", cfg->dpdk.proc_type); 913 return -1; 914 } 915 916 if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) { 917 printf("invalid proc_id:%d, use default 0\n", cfg->dpdk.proc_id); 918 cfg->dpdk.proc_id = 0; 919 } 920 921 return 0; 922 } 923 924 static int 925 ff_check_config(struct ff_config *cfg) 926 { 927 if(cfg->kni.enable && !cfg->kni.method) { 928 fprintf(stderr, "conf dpdk.method is necessary\n"); 929 return -1; 930 } 931 932 if(cfg->kni.method) { 933 if(strcasecmp(cfg->kni.method,"accept") && 934 strcasecmp(cfg->kni.method,"reject")) { 935 fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n", 936 cfg->kni.method); 937 return -1; 938 } 939 } 940 941 if(cfg->kni.kni_action) { 942 if (strcasecmp(cfg->kni.kni_action,"alltokni") && 943 strcasecmp(cfg->kni.kni_action,"alltoff") && 944 strcasecmp(cfg->kni.kni_action,"default")){ 945 fprintf(stderr, "conf kni.kni_action[alltokni|alltoff|default] is error(%s)\n", 946 cfg->kni.kni_action); 947 return -1; 948 } 949 } 950 951 if (cfg->pcap.save_len < PCAP_SAVE_MINLEN) 952 cfg->pcap.save_len = PCAP_SAVE_MINLEN; 953 if (cfg->pcap.snap_len < PCAP_SNAP_MINLEN) 954 cfg->pcap.snap_len = PCAP_SNAP_MINLEN; 955 if (cfg->pcap.save_path==NULL || strlen(cfg->pcap.save_path) ==0) 956 cfg->pcap.save_path = strdup("."); 957 958 #define CHECK_VALID(n) \ 959 do { \ 960 if (!pc->n) { \ 961 fprintf(stderr, "port%d if config error: no %s\n", \ 962 pc->port_id, #n); \ 963 return -1; \ 964 } \ 965 } while (0) 966 967 int i; 968 for (i = 0; i < cfg->dpdk.nb_ports; i++) { 969 uint16_t portid = cfg->dpdk.portid_list[i]; 970 struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[portid]; 971 CHECK_VALID(addr); 972 CHECK_VALID(netmask); 973 CHECK_VALID(broadcast); 974 CHECK_VALID(gateway); 975 // check if the lcores in lcore_list are enabled. 976 int k; 977 for (k = 0; k < pc->nb_lcores; k++) { 978 uint16_t lcore_id = pc->lcore_list[k]; 979 if (uint16_binary_search(cfg->dpdk.proc_lcore, 0, 980 cfg->dpdk.nb_procs-1, lcore_id) < 0) { 981 fprintf(stderr, "lcore %d is not enabled.\n", lcore_id); 982 return -1; 983 } 984 } 985 /* 986 * only primary process process KNI, so if KNI enabled, 987 * primary lcore must stay in every enabled ports' lcore_list 988 */ 989 if (cfg->kni.enable && 990 strcmp(cfg->dpdk.proc_type, "primary") == 0) { 991 int found = 0; 992 int j; 993 uint16_t lcore_id = cfg->dpdk.proc_lcore[cfg->dpdk.proc_id]; 994 for (j = 0; j < pc->nb_lcores; j++) { 995 if (pc->lcore_list[j] == lcore_id) { 996 found = 1; 997 } 998 } 999 if (! found) { 1000 fprintf(stderr, 1001 "primary lcore %d should stay in port %d's lcore_list.\n", 1002 lcore_id, pc->port_id); 1003 return -1; 1004 } 1005 } 1006 } 1007 1008 return 0; 1009 } 1010 1011 static void 1012 ff_default_config(struct ff_config *cfg) 1013 { 1014 memset(cfg, 0, sizeof(struct ff_config)); 1015 1016 cfg->filename = DEFAULT_CONFIG_FILE; 1017 1018 cfg->dpdk.proc_id = -1; 1019 cfg->dpdk.numa_on = 1; 1020 cfg->dpdk.promiscuous = 1; 1021 cfg->dpdk.pkt_tx_delay = BURST_TX_DRAIN_US; 1022 1023 cfg->freebsd.hz = 100; 1024 cfg->freebsd.physmem = 1048576*256; 1025 cfg->freebsd.fd_reserve = 0; 1026 cfg->freebsd.mem_size = 256; 1027 } 1028 1029 int 1030 ff_load_config(int argc, char *const argv[]) 1031 { 1032 ff_default_config(&ff_global_cfg); 1033 1034 int ret = ff_parse_args(&ff_global_cfg, argc, argv); 1035 if (ret < 0) { 1036 return ret; 1037 } 1038 1039 ret = ini_parse(ff_global_cfg.filename, ini_parse_handler, 1040 &ff_global_cfg); 1041 if (ret != 0) { 1042 printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret); 1043 return -1; 1044 } 1045 1046 if (ff_check_config(&ff_global_cfg)) { 1047 return -1; 1048 } 1049 1050 if (dpdk_args_setup(&ff_global_cfg) <= 0) { 1051 return -1; 1052 } 1053 1054 return 0; 1055 } 1056