netmap: redo config parsing

Normally we parse the config per interface only. But to properly
setup the bridge, netmap also needs the config of it's peering
interface. Instead of using a complicated peering scheme like in
afpacket, simply parse the peers config too.
pull/2160/head
Victor Julien 10 years ago
parent 0e9134930d
commit 6c7bf006b7

@ -93,183 +93,178 @@ static void NetmapDerefConfig(void *conf)
}
}
/**
* \brief extract information from config file
*
* The returned structure will be freed by the thread init function.
* This is thus necessary to or copy the structure before giving it
* to thread or to reparse the file for each thread (and thus have
* new structure.
*
* \return a NetmapIfaceConfig corresponding to the interface name
*/
static void *ParseNetmapConfig(const char *iface_name)
static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface,
ConfNode *if_root, ConfNode *if_default)
{
char *threadsstr = NULL;
ConfNode *if_root;
ConfNode *if_default = NULL;
ConfNode *netmap_node;
char *tmpctype;
char *copymodestr;
int boolval;
char *bpf_filter = NULL;
char *out_iface = NULL;
if (iface_name == NULL) {
return NULL;
}
NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf));
if (unlikely(aconf == NULL)) {
return NULL;
}
memset(aconf, 0, sizeof(*aconf));
aconf->DerefFunc = NetmapDerefConfig;
aconf->threads = 0;
aconf->promisc = 1;
aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO;
aconf->copy_mode = NETMAP_COPY_MODE_NONE;
strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name));
SC_ATOMIC_INIT(aconf->ref);
(void) SC_ATOMIC_ADD(aconf->ref, 1);
strlcpy(aconf->iface, aconf->iface_name, sizeof(aconf->iface));
if (aconf->iface[0]) {
size_t len = strlen(aconf->iface);
if (aconf->iface[len-1] == '+') {
aconf->iface[len-1] = '\0';
aconf->iface_sw = 1;
ns->threads = 0;
ns->promisc = 1;
ns->checksum_mode = CHECKSUM_VALIDATION_AUTO;
ns->copy_mode = NETMAP_COPY_MODE_NONE;
strlcpy(ns->iface, iface, sizeof(ns->iface));
if (ns->iface[0]) {
size_t len = strlen(ns->iface);
if (ns->iface[len-1] == '+') {
ns->iface[len-1] = '\0';
ns->sw_ring = 1;
}
}
char *bpf_filter = NULL;
if (ConfGet("bpf-filter", &bpf_filter) == 1) {
if (strlen(bpf_filter) > 0) {
aconf->bpf_filter = bpf_filter;
ns->bpf_filter = bpf_filter;
SCLogInfo("Going to use command-line provided bpf filter '%s'",
aconf->bpf_filter);
ns->bpf_filter);
}
}
/* Find initial node */
netmap_node = ConfGetNode("netmap");
if (netmap_node == NULL) {
SCLogInfo("Unable to find netmap config using default value");
goto finalize;
}
if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name);
if_default = ConfFindDeviceConfig(netmap_node, "default");
if (if_root == NULL && if_default == NULL) {
SCLogInfo("Unable to find netmap config for "
"interface \"%s\" or \"default\", using default value",
aconf->iface_name);
"interface \"%s\" or \"default\", using default values",
iface);
goto finalize;
}
/* If there is no setting for current interface use default one as main iface */
if (if_root == NULL) {
} else if (if_root == NULL) {
if_root = if_default;
if_default = NULL;
}
char *threadsstr = NULL;
if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) {
aconf->threads = 0;
ns->threads = 0;
} else {
if (strcmp(threadsstr, "auto") == 0) {
aconf->threads = 0;
} else {
aconf->threads = (uint8_t)atoi(threadsstr);
}
}
if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) {
if (strlen(out_iface) > 0) {
aconf->out_iface_name = out_iface;
}
}
if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
if (aconf->out_iface_name == NULL) {
SCLogInfo("Copy mode activated but no destination"
" iface. Disabling feature");
} else if (strlen(copymodestr) <= 0) {
aconf->out_iface_name = NULL;
} else if (strcmp(copymodestr, "ips") == 0) {
SCLogInfo("Netmap IPS mode activated %s->%s",
aconf->iface_name,
aconf->out_iface_name);
aconf->copy_mode = NETMAP_COPY_MODE_IPS;
} else if (strcmp(copymodestr, "tap") == 0) {
SCLogInfo("Netmap TAP mode activated %s->%s",
aconf->iface_name,
aconf->out_iface_name);
aconf->copy_mode = NETMAP_COPY_MODE_TAP;
ns->threads = 0;
} else {
SCLogInfo("Invalid mode (not in tap, ips)");
}
}
if (aconf->out_iface_name && aconf->out_iface_name[0]) {
strlcpy(aconf->out_iface, aconf->out_iface_name,
sizeof(aconf->out_iface));
size_t len = strlen(aconf->out_iface);
if (aconf->out_iface[len-1] == '+') {
aconf->out_iface[len-1] = '\0';
aconf->out_iface_sw = 1;
ns->threads = (uint8_t)atoi(threadsstr);
}
}
/* load netmap bpf filter */
/* command line value has precedence */
if (ConfGet("bpf-filter", &bpf_filter) != 1) {
if (ns->bpf_filter == NULL) {
if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) {
if (strlen(bpf_filter) > 0) {
aconf->bpf_filter = bpf_filter;
SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter);
ns->bpf_filter = bpf_filter;
SCLogInfo("Going to use bpf filter %s", ns->bpf_filter);
}
}
}
int boolval = 0;
(void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval);
if (boolval) {
SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface);
aconf->promisc = 0;
SCLogInfo("Disabling promiscuous mode on iface %s", ns->iface);
ns->promisc = 0;
}
if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) {
char *tmpctype;
if (ConfGetChildValueWithDefault(if_root, if_default,
"checksum-checks", &tmpctype) == 1)
{
if (strcmp(tmpctype, "auto") == 0) {
aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO;
ns->checksum_mode = CHECKSUM_VALIDATION_AUTO;
} else if (ConfValIsTrue(tmpctype)) {
aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
ns->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
} else if (ConfValIsFalse(tmpctype)) {
aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
ns->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
} else {
SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface_name);
SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid value for "
"checksum-checks for %s", iface);
}
}
char *copymodestr;
if (ConfGetChildValueWithDefault(if_root, if_default,
"copy-mode", &copymodestr) == 1)
{
if (strcmp(copymodestr, "ips") == 0) {
ns->copy_mode = NETMAP_COPY_MODE_IPS;
} else if (strcmp(copymodestr, "tap") == 0) {
ns->copy_mode = NETMAP_COPY_MODE_TAP;
} else {
SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid copy-mode "
"(valid are tap, ips)");
}
}
finalize:
if (aconf->iface_sw) {
if (ns->sw_ring) {
/* just one thread per interface supported */
aconf->threads = 1;
} else if (aconf->threads == 0) {
ns->threads = 1;
} else if (ns->threads == 0) {
/* As NetmapGetRSSCount is broken on Linux, first run
* GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */
aconf->threads = GetIfaceRSSQueuesNum(aconf->iface);
if (aconf->threads == 0) {
aconf->threads = NetmapGetRSSCount(aconf->iface);
ns->threads = GetIfaceRSSQueuesNum(ns->iface);
if (ns->threads == 0) {
ns->threads = NetmapGetRSSCount(ns->iface);
}
}
if (aconf->threads <= 0) {
aconf->threads = 1;
if (ns->threads <= 0) {
ns->threads = 1;
}
return 0;
}
/**
* \brief extract information from config file
*
* The returned structure will be freed by the thread init function.
* This is thus necessary to or copy the structure before giving it
* to thread or to reparse the file for each thread (and thus have
* new structure.
*
* \return a NetmapIfaceConfig corresponding to the interface name
*/
static void *ParseNetmapConfig(const char *iface_name)
{
ConfNode *if_root = NULL;
ConfNode *if_default = NULL;
ConfNode *netmap_node;
char *out_iface = NULL;
if (iface_name == NULL) {
return NULL;
}
NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf));
if (unlikely(aconf == NULL)) {
return NULL;
}
memset(aconf, 0, sizeof(*aconf));
aconf->DerefFunc = NetmapDerefConfig;
strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name));
SC_ATOMIC_INIT(aconf->ref);
(void) SC_ATOMIC_ADD(aconf->ref, 1);
/* Find initial node */
netmap_node = ConfGetNode("netmap");
if (netmap_node == NULL) {
SCLogInfo("Unable to find netmap config using default value");
} else {
if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name);
if_default = ConfFindDeviceConfig(netmap_node, "default");
}
/* parse settings for capture iface */
ParseNetmapSettings(&aconf->in, aconf->iface_name, if_root, if_default);
/* if we have a copy iface, parse that as well */
if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) {
if (strlen(out_iface) > 0) {
if_root = ConfFindDeviceConfig(netmap_node, out_iface);
ParseNetmapSettings(&aconf->out, out_iface, if_root, if_default);
}
}
SC_ATOMIC_RESET(aconf->ref);
(void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
SCLogPerf("Using %d threads for interface %s", aconf->threads,
(void) SC_ATOMIC_ADD(aconf->ref, aconf->in.threads);
SCLogPerf("Using %d threads for interface %s", aconf->in.threads,
aconf->iface_name);
return aconf;
@ -278,7 +273,7 @@ finalize:
static int NetmapConfigGeThreadsCount(void *conf)
{
NetmapIfaceConfig *aconf = (NetmapIfaceConfig *)conf;
return aconf->threads;
return aconf->in.threads;
}
int NetmapRunModeIsIPS()

@ -622,8 +622,8 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da
memset(ntv, 0, sizeof(*ntv));
ntv->tv = tv;
ntv->checksum_mode = aconf->checksum_mode;
ntv->copy_mode = aconf->copy_mode;
ntv->checksum_mode = aconf->in.checksum_mode;
ntv->copy_mode = aconf->in.copy_mode;
ntv->livedev = LiveGetDevice(aconf->iface_name);
if (ntv->livedev == NULL) {
@ -631,32 +631,32 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da
goto error_ntv;
}
if (NetmapOpen(aconf->iface, aconf->promisc, &ntv->ifsrc, 1) != 0) {
if (NetmapOpen(aconf->in.iface, aconf->in.promisc, &ntv->ifsrc, 1) != 0) {
goto error_ntv;
}
if (unlikely(!aconf->iface_sw && !ntv->ifsrc->rx_rings_cnt)) {
if (unlikely(!aconf->in.sw_ring && !ntv->ifsrc->rx_rings_cnt)) {
SCLogError(SC_ERR_NETMAP_CREATE,
"Input interface '%s' does not have Rx rings",
aconf->iface_name);
goto error_src;
}
if (unlikely(aconf->iface_sw && aconf->threads > 1)) {
if (unlikely(aconf->in.sw_ring && aconf->in.threads > 1)) {
SCLogError(SC_ERR_INVALID_VALUE,
"Interface '%s+'. "
"Thread count can't be greater than 1 for SW ring.",
aconf->iface_name);
goto error_src;
} else if (unlikely(aconf->threads > ntv->ifsrc->rx_rings_cnt)) {
} else if (unlikely(aconf->in.threads > ntv->ifsrc->rx_rings_cnt)) {
SCLogError(SC_ERR_INVALID_VALUE,
"Thread count can't be greater than Rx ring count. "
"Configured %d threads for interface '%s' with %d Rx rings.",
aconf->threads, aconf->iface_name, ntv->ifsrc->rx_rings_cnt);
aconf->in.threads, aconf->iface_name, ntv->ifsrc->rx_rings_cnt);
goto error_src;
}
if (aconf->iface_sw) {
if (aconf->in.sw_ring) {
ntv->thread_idx = 0;
} else {
do {
@ -665,35 +665,35 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da
}
/* calculate thread rings binding */
if (aconf->iface_sw) {
if (aconf->in.sw_ring) {
ntv->src_ring_from = ntv->src_ring_to = ntv->ifsrc->rings_cnt;
} else {
int tmp = (ntv->ifsrc->rx_rings_cnt + 1) / aconf->threads;
int tmp = (ntv->ifsrc->rx_rings_cnt + 1) / aconf->in.threads;
ntv->src_ring_from = ntv->thread_idx * tmp;
ntv->src_ring_to = ntv->src_ring_from + tmp - 1;
if (ntv->thread_idx == (aconf->threads - 1)) {
if (ntv->thread_idx == (aconf->in.threads - 1)) {
ntv->src_ring_to = ntv->ifsrc->rx_rings_cnt - 1;
}
}
SCLogDebug("netmap: %s thread:%d rings:%d-%d", aconf->iface_name,
ntv->thread_idx, ntv->src_ring_from, ntv->src_ring_to);
if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) {
if (NetmapOpen(aconf->out_iface, 0, &ntv->ifdst, 1) != 0) {
if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) {
if (NetmapOpen(aconf->out.iface, aconf->out.promisc, &ntv->ifdst, 1) != 0) {
goto error_src;
}
if (unlikely(!aconf->out_iface_sw && !ntv->ifdst->tx_rings_cnt)) {
if (unlikely(!aconf->out.sw_ring && !ntv->ifdst->tx_rings_cnt)) {
SCLogError(SC_ERR_NETMAP_CREATE,
"Output interface '%s' does not have Tx rings",
aconf->out_iface_name);
aconf->out.iface);
goto error_dst;
}
/* calculate dst rings bindings */
for (int i = ntv->src_ring_from; i <= ntv->src_ring_to; i++) {
NetmapRing *ring = &ntv->ifsrc->rings[i];
if (aconf->out_iface_sw) {
if (aconf->out.sw_ring) {
ring->dst_ring_from = ring->dst_ring_to = ntv->ifdst->rings_cnt;
} else if (ntv->ifdst->tx_rings_cnt > ntv->ifsrc->rx_rings_cnt) {
int tmp = (ntv->ifdst->tx_rings_cnt + 1) / ntv->ifsrc->rx_rings_cnt;
@ -709,7 +709,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da
ring->dst_next_ring = ring->dst_ring_from;
SCLogDebug("netmap: %s(%d)->%s(%d-%d)",
aconf->iface_name, i, aconf->out_iface_name,
aconf->in.iface, i, aconf->out.iface,
ring->dst_ring_from, ring->dst_ring_to);
}
}
@ -722,11 +722,11 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da
/* enable zero-copy mode for workers runmode */
char const *active_runmode = RunmodeGetActive();
if ((aconf->copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode
&& !strcmp("workers", active_runmode)) {
if ((aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode &&
strcmp("workers", active_runmode) == 0) {
ntv->flags |= NETMAP_FLAG_ZERO_COPY;
SCLogPerf("Enabling zero copy mode for %s->%s",
aconf->iface_name, aconf->out_iface_name);
aconf->in.iface, aconf->out.iface);
} else {
uint16_t ring_size = ntv->ifsrc->rings[0].rx->num_slots;
if (ring_size > max_pending_packets) {
@ -738,16 +738,17 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da
}
}
if (aconf->bpf_filter) {
if (aconf->in.bpf_filter) {
SCLogConfig("Using BPF '%s' on iface '%s'",
aconf->bpf_filter, ntv->ifsrc->ifname);
aconf->in.bpf_filter, ntv->ifsrc->ifname);
if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */
LINKTYPE_ETHERNET, /* linktype_arg */
&ntv->bpf_prog, /* program */
aconf->bpf_filter, /* const char *buf */
aconf->in.bpf_filter, /* const char *buf */
1, /* optimize */
PCAP_NETMASK_UNKNOWN /* mask */
) == -1) {
) == -1)
{
SCLogError(SC_ERR_NETMAP_CREATE, "Filter compilation failed.");
goto error_dst;
}
@ -758,7 +759,7 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **da
SCReturnInt(TM_ECODE_OK);
error_dst:
if (aconf->copy_mode != NETMAP_COPY_MODE_NONE) {
if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) {
NetmapClose(ntv->ifdst);
}
error_src:

@ -35,25 +35,34 @@ enum {
#define NETMAP_IFACE_NAME_LENGTH 48
typedef struct NetmapIfaceConfig_
typedef struct NetmapIfaceSettings_
{
/* semantic interface name */
char iface_name[NETMAP_IFACE_NAME_LENGTH];
/* real inner interface name */
char iface[NETMAP_IFACE_NAME_LENGTH];
/* sw ring flag for iface */
int iface_sw;
int threads;
/* sw ring flag for out_iface */
int sw_ring;
int promisc;
int copy_mode;
ChecksumValidationMode checksum_mode;
char *bpf_filter;
} NetmapIfaceSettings;
typedef struct NetmapIfaceConfig_
{
/* semantic interface name */
char iface_name[NETMAP_IFACE_NAME_LENGTH];
/* settings for out capture device*/
NetmapIfaceSettings in;
/* semantic interface name */
char *out_iface_name;
/* real inner interface name */
char out_iface[NETMAP_IFACE_NAME_LENGTH];
/* sw ring flag for out_iface */
int out_iface_sw;
/* settings for outgoing iface for IPS/TAP */
NetmapIfaceSettings out;
SC_ATOMIC_DECLARE(unsigned int, ref);
void (*DerefFunc)(void *);
} NetmapIfaceConfig;

Loading…
Cancel
Save