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