From 6c7bf006b747bfc3edaedb489e65cdbf06e0b7e2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 11 Jun 2016 11:30:16 +0000 Subject: [PATCH] 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. --- src/runmode-netmap.c | 243 +++++++++++++++++++++---------------------- src/source-netmap.c | 51 ++++----- src/source-netmap.h | 27 +++-- 3 files changed, 163 insertions(+), 158 deletions(-) diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index e476dd0403..81c409c283 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -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", ©modestr) == 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", ©modestr) == 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() diff --git a/src/source-netmap.c b/src/source-netmap.c index d9223fe653..b9ce7a843f 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -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: diff --git a/src/source-netmap.h b/src/source-netmap.h index c6f7b6c23f..00b0b44274 100644 --- a/src/source-netmap.h +++ b/src/source-netmap.h @@ -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;