From: Victor Julien Date: Mon, 13 Jun 2016 08:16:33 +0000 (+0200) Subject: offloading: improve checks on FreeBSD X-Git-Tag: suricata-3.1.1~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45fa25eb0ca96612298389aa1041d58599bb5c86;p=thirdparty%2Fsuricata.git offloading: improve checks on FreeBSD Move FreeBSD specific (but not netmap specific) checks from the netmap code to the general ioctl wrapper code. Warn from the check functions now, so callers no longer need to. --- diff --git a/src/source-netmap.c b/src/source-netmap.c index 738da5af13..21d21579bf 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -80,6 +80,8 @@ #endif /* HAVE_NETMAP */ +#include "util-ioctl.h" + extern intmax_t max_pending_packets; #ifndef HAVE_NETMAP @@ -224,113 +226,6 @@ typedef TAILQ_HEAD(NetmapDeviceList_, NetmapDevice_) NetmapDeviceList; static NetmapDeviceList netmap_devlist = TAILQ_HEAD_INITIALIZER(netmap_devlist); static SCMutex netmap_devlist_lock = SCMUTEX_INITIALIZER; -/** - * \brief Get interface flags. - * \param fd Network susbystem file descritor. - * \param ifname Inteface name. - * \return Interface flags or -1 on error - */ -static int NetmapGetIfaceFlags(int fd, const char *ifname) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Unable to get flags for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - -#ifdef OS_FREEBSD - int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); - return flags; -#else - return ifr.ifr_flags; -#endif -} - -#ifdef SIOCGIFCAP -static int NetmapGetIfaceCaps(int fd, const char *ifname) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Unable to get caps for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - - return ifr.ifr_curcap; -} -#endif - -static void NetmapCheckOffloading(int fd, const char *ifname) -{ -#ifdef SIOCGIFCAP - int if_caps = NetmapGetIfaceCaps(fd, ifname); - if (if_caps == -1) { - return; - } - SCLogDebug("if_caps %X", if_caps); - - if (if_caps & IFCAP_RXCSUM) { - SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using NETMAP with RXCSUM activated can lead to capture " - "problems: ifconfig %s -rxcsum", ifname); - } - if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { - SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using NETMAP with TSO, TOE or LRO activated can lead to " - "capture problems: ifconfig %s -tso -toe -lro", ifname); - } -#else - if (GetIfaceOffloading(ifname) == 1) { - SCLogWarning(SC_ERR_NETMAP_CREATE, - "Using NETMAP with GRO or LRO activated can lead to " - "capture problems: " - "ethtool -K %s rx off sg off gro off gso off tso off", - ifname); - } -#endif -} - -/** - * \brief Set interface flags. - * \param fd Network susbystem file descritor. - * \param ifname Inteface name. - * \param flags Flags to set. - * \return Zero on success. - */ -static int NetmapSetIfaceFlags(int fd, const char *ifname, int flags) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); -#ifdef OS_FREEBSD - ifr.ifr_flags = flags & 0xffff; - ifr.ifr_flagshigh = flags >> 16; -#else - ifr.ifr_flags = flags; -#endif - - if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Unable to set flags for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - - return 0; -} - /** \brief get RSS RX-queue count * \retval rx_rings RSS RX queue count or 1 on error */ @@ -398,6 +293,8 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } } + (void)GetIfaceOffloading(ifname); + /* not found, create new record */ pdev = SCMalloc(sizeof(*pdev)); if (unlikely(pdev == NULL)) { @@ -419,39 +316,25 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } /* check interface is up */ - int if_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (if_fd < 0) { - SCLogError(SC_ERR_NETMAP_CREATE, - "Couldn't create control socket for '%s' interface", - ifname); - goto error_fd; - } - int if_flags = NetmapGetIfaceFlags(if_fd, ifname); + int if_flags = GetIfaceFlags(ifname); if (if_flags == -1) { if (verbose) { SCLogError(SC_ERR_NETMAP_CREATE, "Can not access to interface '%s'", ifname); } - close(if_fd); goto error_fd; } if ((if_flags & IFF_UP) == 0) { - if (verbose) { - SCLogError(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname); - } - close(if_fd); + SCLogWarning(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname); goto error_fd; } /* if needed, try to set iface in promisc mode */ if (promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) { if_flags |= IFF_PPROMISC; - NetmapSetIfaceFlags(if_fd, ifname, if_flags); + SetIfaceFlags(ifname, if_flags); } - NetmapCheckOffloading(if_fd, ifname); - close(if_fd); - /* query netmap info */ memset(&nm_req, 0, sizeof(nm_req)); strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name)); diff --git a/src/source-pcap.c b/src/source-pcap.c index 7b9a6161d3..304e713304 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -510,15 +510,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) SCMutexUnlock(&pcap_bpf_compile_lock); } - /* Making it conditional to Linux even if GetIfaceOffloading return 0 - * for non Linux. */ -#ifdef HAVE_LINUX_ETHTOOL_H - if (GetIfaceOffloading(pcapconfig->iface) == 1) { - SCLogWarning(SC_ERR_PCAP_CREATE, - "Using Pcap capture with GRO or LRO activated can lead to " - "capture problems."); - } -#endif /* HAVE_LINUX_ETHTOOL_H */ + (void)GetIfaceOffloading(pcapconfig->iface); ptv->datalink = pcap_datalink(ptv->pcap_handle); diff --git a/src/util-error.c b/src/util-error.c index 2cd58e5c2e..672430adca 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -324,6 +324,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_NETFLOW_LOG_GENERIC); CASE_CODE (SC_ERR_SMTP_LOG_GENERIC); CASE_CODE (SC_ERR_SSH_LOG_GENERIC); + CASE_CODE (SC_ERR_NIC_OFFLOADING); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 1825b77005..99c8f1375d 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -314,6 +314,7 @@ typedef enum { SC_ERR_NETFLOW_LOG_GENERIC, SC_ERR_SMTP_LOG_GENERIC, SC_ERR_SSH_LOG_GENERIC, + SC_ERR_NIC_OFFLOADING, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-ioctl.c b/src/util-ioctl.c index 436d39a49b..4e949686b9 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -137,6 +137,106 @@ int GetIfaceMaxPacketSize(const char *pcap_dev) return ll_header + mtu; } +#ifdef SIOCGIFFLAGS +/** + * \brief Get interface flags. + * \param ifname Inteface name. + * \return Interface flags or -1 on error + */ +int GetIfaceFlags(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to get flags for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); +#ifdef OS_FREEBSD + int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + return flags; +#else + return ifr.ifr_flags; +#endif +} +#endif + +#ifdef SIOCSIFFLAGS +/** + * \brief Set interface flags. + * \param ifname Inteface name. + * \param flags Flags to set. + * \return Zero on success. + */ +int SetIfaceFlags(const char *ifname, int flags) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +#ifdef OS_FREEBSD + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; +#else + ifr.ifr_flags = flags; +#endif + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to set flags for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} +#endif /* SIOCGIFFLAGS */ + +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to get caps for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return ifr.ifr_curcap; +} +#endif + #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) { @@ -204,13 +304,47 @@ static int GetIfaceOffloadingLinux(const char *dev) } } #endif - SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " - "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); + if (ret == 0) { + SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " + "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); + } else { + SCLogWarning(SC_ERR_NIC_OFFLOADING, "NIC offloading on %s: SG: %s, " + " GRO: %s, LRO: %s, TSO: %s, GSO: %s: " + "ethtool -K %s sg off gro off lro off tso off gso off", + dev, sg, gro, lro, tso, gso, dev); + } return ret; } #endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ +#ifdef SIOCGIFCAP +static int GetIfaceOffloadingBSD(const char *ifname) +{ + int ret = 0; + int if_caps = GetIfaceCaps(ifname); + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with RXCSUM activated can lead to capture " + "problems: ifconfig %s -rxcsum", ifname, ifname); + ret = 1; + } + if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with TSO, TOE or LRO activated can lead to " + "capture problems: ifconfig %s -tso -toe -lro", + ifname, ifname); + ret = 1; + } + return ret; +} +#endif + /** * \brief output offloading status of the link * @@ -227,8 +361,11 @@ int GetIfaceOffloading(const char *dev) { #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL return GetIfaceOffloadingLinux(dev); -#endif +#elif defined SIOCGIFCAP + return GetIfaceOffloadingBSD(dev); +#else return 0; +#endif } int GetIfaceRSSQueuesNum(const char *pcap_dev) diff --git a/src/util-ioctl.h b/src/util-ioctl.h index 3931c1fe09..76195ac76f 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -25,3 +25,12 @@ int GetIfaceMTU(const char *pcap_dev); int GetIfaceMaxPacketSize(const char *pcap_dev); int GetIfaceOffloading(const char *pcap_dev); int GetIfaceRSSQueuesNum(const char *pcap_dev); +#ifdef SIOCGIFFLAGS +int GetIfaceFlags(const char *ifname); +#endif +#ifdef SIOCSIFFLAGS +int SetIfaceFlags(const char *ifname, int flags); +#endif +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname); +#endif