]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
util-ioctl: add GRO/LRO detection capabilities
authorEric Leblond <eric@regit.org>
Tue, 19 Nov 2013 14:59:17 +0000 (15:59 +0100)
committerEric Leblond <eric@regit.org>
Mon, 25 Nov 2013 14:08:54 +0000 (15:08 +0100)
This patch adds a new function GetIfaceOffloading which return 0
if LRO and GRO are not set on a interface and 1 if not the case.

configure.ac
src/util-ioctl.c
src/util-ioctl.h

index b7b1ebe6518a969bf10e375e2834da47e8bf26d9..4b394c6907ca110a60be1736cf2eb43f33a33cfc 100644 (file)
     AC_CHECK_HEADERS([syslog.h sys/prctl.h sys/socket.h sys/stat.h sys/syscall.h])
     AC_CHECK_HEADERS([sys/time.h time.h unistd.h])
     AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h])
+    AC_CHECK_HEADERS([linux/ethtool.h linux/sockios.h])
 
     AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [],
     [[#ifdef HAVE_SYS_SOCKET_H
index ca600d46085c5caf96356d1fff0b9dd5290f3c93..30b9c1a45cb391a708700ad9be7199784621206b 100644 (file)
 #include <sys/ioctl.h>
 #endif
 
+#ifdef HAVE_LINUX_ETHTOOL_H
+#include <linux/ethtool.h>
+#ifdef HAVE_LINUX_SOCKIOS_H
+#include <linux/sockios.h>
+#else
+#error "ethtool.h present but sockios.h is missing"
+#endif /* HAVE_LINUX_SOCKIOS_H */
+#endif /* HAVE_LINUX_ETHTOOL_H */
+
 #ifdef HAVE_NET_IF_H
 #include <net/if.h>
 #endif
@@ -119,3 +128,78 @@ int GetIfaceMaxPacketSize(char *pcap_dev)
     }
     return ll_header + mtu;
 }
+
+/**
+ * \brief output offloading status of the link
+ *
+ * Test interface for GRO and LRO features. If one of them is
+ * activated then suricata mays received packets merge at reception.
+ * The result is oversized packets and this may cause some serious
+ * problem in some capture mode where the size of the packet is
+ * limited (AF_PACKET in V2 more for example).
+ *
+ * ETHTOOL_GGRO ETH_FLAG_LRO
+ *
+ * \param Name of link
+ * \retval -1 in case of error, 0 if none, 1 if some
+ */
+int GetIfaceOffloading(char *pcap_dev)
+{
+#ifdef ETHTOOL_GGRO
+    struct ifreq ifr;
+    int fd;
+    struct ethtool_value ethv;
+    int ret = 0;
+
+    fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (fd == -1) {
+        return -1;
+    }
+    (void)strlcpy(ifr.ifr_name, pcap_dev, sizeof(ifr.ifr_name));
+
+    /* First get GRO */
+    ethv.cmd = ETHTOOL_GGRO;
+    ifr.ifr_data = (void *) &ethv;
+    if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
+        SCLogWarning(SC_ERR_SYSCALL,
+                  "Failure when trying to get feature via ioctl: %s (%d)",
+                  strerror(errno), errno);
+        close(fd);
+        return -1;
+    } else {
+        if (ethv.data) {
+            SCLogInfo("Generic Receive Offload is set on %s", pcap_dev);
+            ret = 1;
+        } else {
+            SCLogInfo("Generic Receive Offload is unset on %s", pcap_dev);
+        }
+    }
+
+    /* Then get LRO which is set in a flag */
+    ethv.data = 0;
+    ethv.cmd = ETHTOOL_GFLAGS;
+    ifr.ifr_data = (void *) &ethv;
+    if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
+        SCLogWarning(SC_ERR_SYSCALL,
+                  "Failure when trying to get feature via ioctl: %s (%d)",
+                  strerror(errno), errno);
+        close(fd);
+        return -1;
+    } else {
+        if (ethv.data & ETH_FLAG_LRO) {
+            SCLogInfo("Large Receive Offload is set on %s", pcap_dev);
+            ret = 1;
+        } else {
+            SCLogInfo("Large Receive Offload is unset on %s", pcap_dev);
+        }
+    }
+
+    close(fd);
+
+    return ret;
+#else
+    /* ioctl is not defined, let's pretend returning 0 is ok */
+    return 0;
+#endif
+}
+
index 7378aeeef4f7647988bd51e7ac8d8e6a0525fd31..7bc5055710ba98d631f5b882c217d52fd4219345 100644 (file)
@@ -23,3 +23,4 @@
 
 int GetIfaceMTU(char *pcap_dev);
 int GetIfaceMaxPacketSize(char *pcap_dev);
+int GetIfaceOffloading(char *pcap_dev);