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