mirror of https://github.com/F-Stack/f-stack.git
455 lines
12 KiB
C
455 lines
12 KiB
C
/*
|
|
* Copyright (C) 2017 THL A29 Limited, a Tencent company.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <getopt.h>
|
|
#include <ctype.h>
|
|
#include <rte_config.h>
|
|
|
|
#include "ff_config.h"
|
|
#include "ff_ini_parser.h"
|
|
|
|
#define DEFAULT_CONFIG_FILE "config.ini"
|
|
|
|
#define BITS_PER_HEX 4
|
|
|
|
struct ff_config ff_global_cfg;
|
|
int dpdk_argc;
|
|
char *dpdk_argv[DPDK_CONFIG_NUM + 1];
|
|
|
|
char* const short_options = "c:t:p:";
|
|
struct option long_options[] = {
|
|
{ "conf", 1, NULL, 'c'},
|
|
{ "proc-type", 1, NULL, 't'},
|
|
{ "proc-id", 1, NULL, 'p'},
|
|
{ 0, 0, 0, 0},
|
|
};
|
|
|
|
static int
|
|
xdigit2val(unsigned char c)
|
|
{
|
|
int val;
|
|
|
|
if (isdigit(c))
|
|
val = c - '0';
|
|
else if (isupper(c))
|
|
val = c - 'A' + 10;
|
|
else
|
|
val = c - 'a' + 10;
|
|
return val;
|
|
}
|
|
|
|
static int
|
|
parse_lcore_mask(struct ff_config *cfg, const char *coremask)
|
|
{
|
|
int i, j, idx = 0;
|
|
unsigned count = 0;
|
|
char c;
|
|
int val;
|
|
uint16_t *proc_lcore;
|
|
char buf[RTE_MAX_LCORE] = {0};
|
|
|
|
if (coremask == NULL)
|
|
return 0;
|
|
|
|
cfg->dpdk.proc_lcore = (uint16_t *)calloc(RTE_MAX_LCORE, sizeof(uint16_t));
|
|
if (cfg->dpdk.proc_lcore == NULL) {
|
|
fprintf(stderr, "parse_lcore_mask malloc failed\n");
|
|
return 0;
|
|
}
|
|
proc_lcore = cfg->dpdk.proc_lcore;
|
|
|
|
/*
|
|
* Remove all blank characters ahead and after.
|
|
* Remove 0x/0X if exists.
|
|
*/
|
|
while (isblank(*coremask))
|
|
coremask++;
|
|
if (coremask[0] == '0' && ((coremask[1] == 'x')
|
|
|| (coremask[1] == 'X')))
|
|
coremask += 2;
|
|
|
|
i = strlen(coremask);
|
|
while ((i > 0) && isblank(coremask[i - 1]))
|
|
i--;
|
|
|
|
if (i == 0)
|
|
return 0;
|
|
|
|
for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) {
|
|
c = coremask[i];
|
|
if (isxdigit(c) == 0) {
|
|
return 0;
|
|
}
|
|
val = xdigit2val(c);
|
|
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++) {
|
|
if ((1 << j) & val) {
|
|
proc_lcore[count] = idx;
|
|
if (cfg->dpdk.proc_id == count) {
|
|
sprintf(buf, "%x", 1<<idx);
|
|
cfg->dpdk.proc_mask = strdup(buf);
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (; i >= 0; i--)
|
|
if (coremask[i] != '0')
|
|
return 0;
|
|
|
|
if (cfg->dpdk.proc_id >= count)
|
|
return 0;
|
|
|
|
cfg->dpdk.nb_procs = count;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
is_integer(const char *s)
|
|
{
|
|
if (*s == '-' || *s == '+')
|
|
s++;
|
|
if (*s < '0' || '9' < *s)
|
|
return 0;
|
|
s++;
|
|
while ('0' <= *s && *s <= '9')
|
|
s++;
|
|
return (*s == '\0');
|
|
}
|
|
|
|
static int
|
|
freebsd_conf_handler(struct ff_config *cfg, const char *section,
|
|
const char *name, const char *value)
|
|
{
|
|
struct ff_freebsd_cfg *newconf, **cur;
|
|
newconf = (struct ff_freebsd_cfg *)malloc(sizeof(struct ff_freebsd_cfg));
|
|
if (newconf == NULL) {
|
|
fprintf(stderr, "freebsd conf malloc failed\n");
|
|
return 0;
|
|
}
|
|
|
|
newconf->name = strdup(name);
|
|
newconf->str = strdup(value);
|
|
|
|
if (strcmp(section, "boot") == 0) {
|
|
cur = &cfg->freebsd.boot;
|
|
|
|
newconf->value = (void *)newconf->str;
|
|
newconf->vlen = strlen(value);
|
|
} else if (strcmp(section, "sysctl") == 0) {
|
|
cur = &cfg->freebsd.sysctl;
|
|
|
|
if (is_integer(value)) {
|
|
int *p = (int *)malloc(sizeof(int));
|
|
*p = atoi(value);
|
|
newconf->value = (void *)p;
|
|
newconf->vlen = sizeof(*p);
|
|
} else {
|
|
newconf->value = (void *)newconf->str;
|
|
newconf->vlen = strlen(value);
|
|
}
|
|
} else {
|
|
fprintf(stderr, "freebsd conf section[%s] error\n", section);
|
|
return 0;
|
|
}
|
|
|
|
if (*cur == NULL) {
|
|
*cur = newconf;
|
|
} else {
|
|
(*cur)->next = newconf;
|
|
newconf->next = NULL;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
port_cfg_handler(struct ff_config *cfg, const char *section,
|
|
const char *name, const char *value) {
|
|
|
|
if (cfg->dpdk.nb_ports == 0) {
|
|
fprintf(stderr, "port_cfg_handler: must config dpdk.nb_ports first\n");
|
|
return 0;
|
|
}
|
|
|
|
if (cfg->dpdk.port_cfgs == NULL) {
|
|
struct ff_port_cfg *pc = calloc(cfg->dpdk.nb_ports, sizeof(struct ff_port_cfg));
|
|
if (pc == NULL) {
|
|
fprintf(stderr, "port_cfg_handler malloc failed\n");
|
|
return 0;
|
|
}
|
|
|
|
cfg->dpdk.port_cfgs = pc;
|
|
}
|
|
|
|
int portid;
|
|
int ret = sscanf(section, "port%d", &portid);
|
|
if (ret != 1) {
|
|
fprintf(stderr, "port_cfg_handler section[%s] error\n", section);
|
|
return 0;
|
|
}
|
|
|
|
/* just return true if portid >= nb_ports because it has no effect */
|
|
if (portid >= cfg->dpdk.nb_ports) {
|
|
fprintf(stderr, "port_cfg_handler section[%s] max than nb_ports\n", section);
|
|
return 1;
|
|
}
|
|
|
|
struct ff_port_cfg *cur = &cfg->dpdk.port_cfgs[portid];
|
|
if (cur->name == NULL) {
|
|
cur->name = strdup(section);
|
|
cur->port_id = portid;
|
|
}
|
|
|
|
if (strcmp(name, "addr") == 0) {
|
|
cur->addr = strdup(value);
|
|
} else if (strcmp(name, "netmask") == 0) {
|
|
cur->netmask = strdup(value);
|
|
} else if (strcmp(name, "broadcast") == 0) {
|
|
cur->broadcast = strdup(value);
|
|
} else if (strcmp(name, "gateway") == 0) {
|
|
cur->gateway = strdup(value);
|
|
} else if (strcmp(name, "pcap") == 0) {
|
|
cur->pcap = strdup(value);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
ini_parse_handler(void* user, const char* section, const char* name,
|
|
const char* value)
|
|
{
|
|
struct ff_config *pconfig = (struct ff_config*)user;
|
|
|
|
printf("[%s]: %s=%s\n", section, name, value);
|
|
|
|
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
|
if (MATCH("dpdk", "channel")) {
|
|
pconfig->dpdk.nb_channel = atoi(value);
|
|
} else if (MATCH("dpdk", "memory")) {
|
|
pconfig->dpdk.memory = atoi(value);
|
|
} else if (MATCH("dpdk", "no_huge")) {
|
|
pconfig->dpdk.no_huge = atoi(value);
|
|
} else if (MATCH("dpdk", "lcore_mask")) {
|
|
pconfig->dpdk.lcore_mask = strdup(value);
|
|
return parse_lcore_mask(pconfig, pconfig->dpdk.lcore_mask);
|
|
} else if (MATCH("dpdk", "port_mask")) {
|
|
pconfig->dpdk.port_mask = atoi(value);
|
|
} else if (MATCH("dpdk", "nb_ports")) {
|
|
pconfig->dpdk.nb_ports = atoi(value);
|
|
} else if (MATCH("dpdk", "promiscuous")) {
|
|
pconfig->dpdk.promiscuous = atoi(value);
|
|
} else if (MATCH("dpdk", "numa_on")) {
|
|
pconfig->dpdk.numa_on = atoi(value);
|
|
} else if (MATCH("dpdk", "tso")) {
|
|
pconfig->dpdk.tso = atoi(value);
|
|
} else if (MATCH("dpdk", "vlan_strip")) {
|
|
pconfig->dpdk.vlan_strip = atoi(value);
|
|
} else if (MATCH("kni", "enable")) {
|
|
pconfig->kni.enable= atoi(value);
|
|
} else if (MATCH("kni", "method")) {
|
|
pconfig->kni.method= strdup(value);
|
|
} else if (MATCH("kni", "tcp_port")) {
|
|
pconfig->kni.tcp_port = strdup(value);
|
|
} else if (MATCH("kni", "udp_port")) {
|
|
pconfig->kni.udp_port= strdup(value);
|
|
} else if (strcmp(section, "freebsd.boot") == 0) {
|
|
if (strcmp(name, "hz") == 0) {
|
|
pconfig->freebsd.hz = atoi(value);
|
|
} else if (strcmp(name, "physmem") == 0) {
|
|
pconfig->freebsd.physmem = atol(value);
|
|
} else if (strcmp(name, "fd_reserve") == 0) {
|
|
pconfig->freebsd.fd_reserve = atoi(value);
|
|
} else {
|
|
return freebsd_conf_handler(pconfig, "boot", name, value);
|
|
}
|
|
} else if (strcmp(section, "freebsd.sysctl") == 0) {
|
|
return freebsd_conf_handler(pconfig, "sysctl", name, value);
|
|
} else if (strncmp(section, "port", 4) == 0) {
|
|
return port_cfg_handler(pconfig, section, name, value);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
dpdk_args_setup(struct ff_config *cfg)
|
|
{
|
|
int n = 0, i;
|
|
dpdk_argv[n++] = strdup("f-stack");
|
|
char temp[DPDK_CONFIG_MAXLEN] = {0};
|
|
|
|
if (cfg->dpdk.no_huge) {
|
|
dpdk_argv[n++] = strdup("--no-huge");
|
|
}
|
|
if (cfg->dpdk.proc_mask) {
|
|
sprintf(temp, "-c%s", cfg->dpdk.proc_mask);
|
|
dpdk_argv[n++] = strdup(temp);
|
|
}
|
|
if (cfg->dpdk.nb_channel) {
|
|
sprintf(temp, "-n%d", cfg->dpdk.nb_channel);
|
|
dpdk_argv[n++] = strdup(temp);
|
|
}
|
|
if (cfg->dpdk.memory) {
|
|
sprintf(temp, "-m%d", cfg->dpdk.memory);
|
|
dpdk_argv[n++] = strdup(temp);
|
|
}
|
|
if (cfg->dpdk.proc_type) {
|
|
sprintf(temp, "--proc-type=%s", cfg->dpdk.proc_type);
|
|
dpdk_argv[n++] = strdup(temp);
|
|
}
|
|
|
|
dpdk_argc = n;
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
ff_parse_args(struct ff_config *cfg, int argc, char *const argv[])
|
|
{
|
|
int c;
|
|
int index = 0;
|
|
optind = 1;
|
|
while((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
|
|
switch (c) {
|
|
case 'c':
|
|
cfg->filename = strdup(optarg);
|
|
break;
|
|
case 'p':
|
|
cfg->dpdk.proc_id = atoi(optarg);
|
|
break;
|
|
case 't':
|
|
cfg->dpdk.proc_type = strdup(optarg);
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (cfg->dpdk.proc_type == NULL ||
|
|
(strcmp(cfg->dpdk.proc_type, "primary") &&
|
|
strcmp(cfg->dpdk.proc_type, "secondary"))) {
|
|
printf("invalid proc-type\n");
|
|
return -1;
|
|
}
|
|
|
|
if ((uint16_t)cfg->dpdk.proc_id > RTE_MAX_LCORE) {
|
|
printf("proc_id:%d is too large\n", cfg->dpdk.proc_id);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ff_check_config(struct ff_config *cfg)
|
|
{
|
|
if(cfg->kni.enable && !cfg->kni.method) {
|
|
fprintf(stderr, "conf dpdk.method is necessary\n");
|
|
return -1;
|
|
}
|
|
|
|
if(cfg->kni.method) {
|
|
if(strcasecmp(cfg->kni.method,"accept") &&
|
|
strcasecmp(cfg->kni.method,"reject")) {
|
|
fprintf(stderr, "conf kni.method[accept|reject] is error(%s)\n",
|
|
cfg->kni.method);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
#define CHECK_VALID(n) \
|
|
do { \
|
|
if (!pc->n) { \
|
|
fprintf(stderr, "port%d if config error: no %s\n", \
|
|
pc->port_id, #n); \
|
|
return -1; \
|
|
} \
|
|
} while (0)
|
|
|
|
int i;
|
|
for (i = 0; i < cfg->dpdk.nb_ports; i++) {
|
|
struct ff_port_cfg *pc = &cfg->dpdk.port_cfgs[i];
|
|
CHECK_VALID(addr);
|
|
CHECK_VALID(netmask);
|
|
CHECK_VALID(broadcast);
|
|
CHECK_VALID(gateway);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
ff_default_config(struct ff_config *cfg)
|
|
{
|
|
memset(cfg, 0, sizeof(struct ff_config));
|
|
|
|
cfg->filename = DEFAULT_CONFIG_FILE;
|
|
|
|
cfg->dpdk.proc_id = -1;
|
|
cfg->dpdk.numa_on = 1;
|
|
cfg->dpdk.promiscuous = 1;
|
|
|
|
cfg->freebsd.hz = 100;
|
|
cfg->freebsd.physmem = 1048576*256;
|
|
cfg->freebsd.fd_reserve = 0;
|
|
}
|
|
|
|
int
|
|
ff_load_config(int argc, char *const argv[])
|
|
{
|
|
ff_default_config(&ff_global_cfg);
|
|
|
|
int ret = ff_parse_args(&ff_global_cfg, argc, argv);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = ini_parse(ff_global_cfg.filename, ini_parse_handler,
|
|
&ff_global_cfg);
|
|
if (ret != 0) {
|
|
printf("parse %s failed on line %d\n", ff_global_cfg.filename, ret);
|
|
return -1;
|
|
}
|
|
|
|
if (ff_check_config(&ff_global_cfg)) {
|
|
return -1;
|
|
}
|
|
|
|
if (dpdk_args_setup(&ff_global_cfg) <= 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|