From fcc87595611e23eec4749e22d402644f9487b06e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Tue, 19 Nov 2013 15:59:17 +0100 Subject: [PATCH] util-ioctl: add GRO/LRO detection capabilities 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 | 1 + src/util-ioctl.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util-ioctl.h | 1 + 3 files changed, 86 insertions(+) diff --git a/configure.ac b/configure.ac index b7b1ebe651..4b394c6907 100644 --- a/configure.ac +++ b/configure.ac @@ -136,6 +136,7 @@ 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 diff --git a/src/util-ioctl.c b/src/util-ioctl.c index ca600d4608..30b9c1a45c 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -28,6 +28,15 @@ #include #endif +#ifdef HAVE_LINUX_ETHTOOL_H +#include +#ifdef HAVE_LINUX_SOCKIOS_H +#include +#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 #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 *) ðv; + 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 *) ðv; + 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 +} + diff --git a/src/util-ioctl.h b/src/util-ioctl.h index 7378aeeef4..7bc5055710 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -23,3 +23,4 @@ int GetIfaceMTU(char *pcap_dev); int GetIfaceMaxPacketSize(char *pcap_dev); +int GetIfaceOffloading(char *pcap_dev);