]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
offloading: improve checks on FreeBSD
authorVictor Julien <victor@inliniac.net>
Mon, 13 Jun 2016 08:16:33 +0000 (10:16 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 20 Jun 2016 15:57:59 +0000 (17:57 +0200)
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.

src/source-netmap.c
src/source-pcap.c
src/util-error.c
src/util-error.h
src/util-ioctl.c
src/util-ioctl.h

index 738da5af13e302bdc07bf74671349e937e5a8af0..21d21579bfa23a0e83e9714bda736441a51bddb6 100644 (file)
@@ -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));
index 7b9a6161d325912efaaac45806de3ea2ec84db0c..304e713304e485e53824fc8561576788940f3d26 100644 (file)
@@ -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);
 
index 2cd58e5c2ec1fb6080d46714dc3bcac1a6e7ba45..672430adcaecf2e33b22dc9b101364577451e32f 100644 (file)
@@ -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";
index 1825b77005ea2c714a81e2ba7cf86954824419d9..99c8f1375d0fa5957bd13250cda3c57ff566d55e 100644 (file)
@@ -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);
index 436d39a49ba1a88ceecc1f0e85e3b57bb6b00020..4e949686b9976d496425060427b4a2fcf581359b 100644 (file)
@@ -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)
index 3931c1fe0919d4864ec551921fd323958184efbf..76195ac76fdc9caaee99452a7af30c7e5172dccd 100644 (file)
@@ -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