diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 65ba213b3b..959617889b 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -459,7 +459,7 @@ finalize: "Using AF_PACKET with offloading activated leads to capture problems"); } } else { - DisableIfaceOffloading(iface, 0, 1); + DisableIfaceOffloading(LiveGetDevice(iface), 0, 1); } break; case -1: diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 1cf08bc829..88d2de3f60 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -269,6 +269,13 @@ static void *ParseNetmapConfig(const char *iface_name) SCLogPerf("Using %d threads for interface %s", aconf->in.threads, aconf->iface_name); + /* netmap needs all offloading to be disabled */ + if (LiveGetOffload() == 0) { + (void)GetIfaceOffloading(aconf->in.iface, 1, 1); + } else { + DisableIfaceOffloading(LiveGetDevice(aconf->in.iface), 1, 1); + } + return aconf; } diff --git a/src/source-netmap.c b/src/source-netmap.c index 48c16fe55d..5f81f1a694 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -293,13 +293,6 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver } } - /* netmap needs all offloading to be disabled */ - if (LiveGetOffload() == 0) { - (void)GetIfaceOffloading(ifname, 1, 1); - } else { - DisableIfaceOffloading(ifname, 1, 1); - } - /* not found, create new record */ pdev = SCMalloc(sizeof(*pdev)); if (unlikely(pdev == NULL)) { diff --git a/src/source-pcap.c b/src/source-pcap.c index 4385231b0b..33d8c72529 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -398,7 +398,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) if (LiveGetOffload() == 0) { (void)GetIfaceOffloading((char *)pcapconfig->iface, 1, 1); } else { - DisableIfaceOffloading((char *)pcapconfig->iface, 1, 1); + DisableIfaceOffloading(ptv->livedev, 1, 1); } ptv->checksum_mode = pcapconfig->checksum_mode; diff --git a/src/util-device.c b/src/util-device.c index 2a37bffc5a..f8afbc239c 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -18,6 +18,7 @@ #include "suricata-common.h" #include "conf.h" #include "util-device.h" +#include "util-ioctl.h" #define MAX_DEVNAME 10 @@ -66,7 +67,7 @@ int LiveGetOffload(void) */ int LiveRegisterDevice(const char *dev) { - LiveDevice *pd = SCMalloc(sizeof(LiveDevice)); + LiveDevice *pd = SCCalloc(1, sizeof(LiveDevice)); if (unlikely(pd == NULL)) { return -1; } @@ -281,6 +282,9 @@ int LiveDeviceListClean() 100 * (SC_ATOMIC_GET(pd->drop) * 1.0) / SC_ATOMIC_GET(pd->pkts), SC_ATOMIC_GET(pd->invalid_checksums)); } + + RestoreIfaceOffloading(pd); + if (pd->dev) SCFree(pd->dev); SC_ATOMIC_DESTROY(pd->pkts); diff --git a/src/util-device.h b/src/util-device.h index 307e4634ec..5c4e76c09f 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -21,6 +21,19 @@ #include "queue.h" #include "unix-manager.h" +#define OFFLOAD_FLAG_SG (1<<0) +#define OFFLOAD_FLAG_TSO (1<<1) +#define OFFLOAD_FLAG_GSO (1<<2) +#define OFFLOAD_FLAG_GRO (1<<3) +#define OFFLOAD_FLAG_LRO (1<<4) +#define OFFLOAD_FLAG_RXCSUM (1<<5) +#define OFFLOAD_FLAG_TXCSUM (1<<6) +#define OFFLOAD_FLAG_TOE (1<<7) + +void LiveSetOffloadDisable(void); +void LiveSetOffloadWarn(void); +int LiveGetOffload(void); + #define MAX_DEVNAME 10 /** storage for live device names */ @@ -32,11 +45,9 @@ typedef struct LiveDevice_ { SC_ATOMIC_DECLARE(uint64_t, drop); SC_ATOMIC_DECLARE(uint64_t, invalid_checksums); TAILQ_ENTRY(LiveDevice_) next; -} LiveDevice; -void LiveSetOffloadDisable(void); -void LiveSetOffloadWarn(void); -int LiveGetOffload(void); + uint32_t offload_orig; /**< original offload settings to restore @exit */ +} LiveDevice; int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); diff --git a/src/util-ioctl.c b/src/util-ioctl.c index ae1bded7e5..ff6646adc5 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -24,6 +24,7 @@ #include "suricata-common.h" #include "conf.h" +#include "util-device.h" #ifdef HAVE_SYS_IOCTL_H #include @@ -400,22 +401,29 @@ static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) return ret; } -static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) +static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) { int ret = 0; uint32_t value = 0; + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + if (csum) { #ifdef ETHTOOL_GRXCSUM if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { SCLogInfo("%s: disabling rxcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; } #endif #ifdef ETHTOOL_GTXCSUM if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { SCLogInfo("%s: disabling txcsum offloading", dev); SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM; } #endif } @@ -424,24 +432,28 @@ static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { SCLogInfo("%s: disabling gro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGRO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GRO; } #endif #ifdef ETHTOOL_GTSO if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { SCLogInfo("%s: disabling tso offloading", dev); SetEthtoolValue(dev, ETHTOOL_STSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TSO; } #endif #ifdef ETHTOOL_GGSO if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { SCLogInfo("%s: disabling gso offloading", dev); SetEthtoolValue(dev, ETHTOOL_SGSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GSO; } #endif #ifdef ETHTOOL_GSG if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { SCLogInfo("%s: disabling sg offloading", dev); SetEthtoolValue(dev, ETHTOOL_SSG, 0); + ldev->offload_orig |= OFFLOAD_FLAG_SG; } #endif #ifdef ETHTOOL_GFLAGS @@ -449,6 +461,7 @@ static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) if (value & ETH_FLAG_LRO) { SCLogInfo("%s: disabling lro offloading", dev); SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); + ldev->offload_orig |= OFFLOAD_FLAG_LRO; } } #endif @@ -456,6 +469,61 @@ static int DisableIfaceOffloadingLinux(const char *dev, int csum, int other) return ret; } +static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) +{ + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + +#ifdef ETHTOOL_GRXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { + SCLogInfo("%s: restoring rxcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) { + SCLogInfo("%s: restoring txcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GGRO + if (ldev->offload_orig & OFFLOAD_FLAG_GRO) { + SCLogInfo("%s: restoring gro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGRO, 1); + } +#endif +#ifdef ETHTOOL_GTSO + if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { + SCLogInfo("%s: restoring tso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STSO, 1); + } +#endif +#ifdef ETHTOOL_GGSO + if (ldev->offload_orig & OFFLOAD_FLAG_GSO) { + SCLogInfo("%s: restoring gso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGSO, 1); + } +#endif +#ifdef ETHTOOL_GSG + if (ldev->offload_orig & OFFLOAD_FLAG_SG) { + SCLogInfo("%s: restoring sg offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SSG, 1); + } +#endif +#ifdef ETHTOOL_GFLAGS + if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { + uint32_t value = 0; + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + SCLogInfo("%s: restoring lro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO); + } + } +#endif + return 0; +} + #endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ #ifdef SIOCGIFCAP @@ -554,7 +622,7 @@ int GetIfaceOffloading(const char *dev, int csum, int other) #endif } -int DisableIfaceOffloading(const char *dev, int csum, int other) +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other) { #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL return DisableIfaceOffloadingLinux(dev, csum, other); @@ -566,6 +634,15 @@ int DisableIfaceOffloading(const char *dev, int csum, int other) } +void RestoreIfaceOffloading(LiveDevice *dev) +{ + if (dev->offload_orig != 0) { +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + RestoreIfaceOffloadingLinux(dev); +#endif + } +} + int GetIfaceRSSQueuesNum(const char *pcap_dev) { #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS diff --git a/src/util-ioctl.h b/src/util-ioctl.h index da3bd61691..54020e4c7c 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -21,6 +21,8 @@ * \author Eric Leblond */ +#include "util-device.h" + int GetIfaceMTU(const char *pcap_dev); int GetIfaceMaxPacketSize(const char *pcap_dev); int GetIfaceOffloading(const char *dev, int csum, int other); @@ -34,4 +36,5 @@ int SetIfaceFlags(const char *ifname, int flags); #ifdef SIOCGIFCAP int GetIfaceCaps(const char *ifname); #endif -int DisableIfaceOffloading(const char *dev, int csum, int other); +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other); +void RestoreIfaceOffloading(LiveDevice *dev);