32#ifdef HAVE_SYS_IOCTL_H
36#ifdef HAVE_LINUX_ETHTOOL_H
37#include <linux/types.h>
38#include <linux/ethtool.h>
39#ifdef HAVE_LINUX_SOCKIOS_H
40#include <linux/sockios.h>
42#error "ethtool.h present but sockios.h is missing"
59static int GetIfaceMaxHWHeaderLength(
const char *dev)
61 if ((!strcmp(
"eth", dev)) || (!strcmp(
"br", dev)) || (!strcmp(
"bond", dev)) ||
62 (!strcmp(
"wlan", dev)) || (!strcmp(
"tun", dev)) || (!strcmp(
"tap", dev)) ||
63 (!strcmp(
"lo", dev))) {
68 if (!strcmp(
"ppp", dev))
88 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
89 fd = socket(AF_INET, SOCK_DGRAM, 0);
94 if (ioctl(fd, SIOCGIFMTU, (
char *)&ifr) < 0) {
95 SCLogWarning(
"Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev,
96 strerror(errno), errno);
101 SCLogInfo(
"%s: MTU %d", dev, ifr.ifr_mtu);
103#elif defined OS_WIN32
104 return GetIfaceMTUWin32(dev);
126 const char *dev = ld->
dev;
127 if ((dev == NULL) || strlen(dev) == 0)
140 int ll_header = GetIfaceMaxHWHeaderLength(dev);
141 return ll_header + mtu;
150int GetIfaceFlags(
const char *ifname)
154 int fd = socket(AF_INET, SOCK_DGRAM, 0);
159 memset(&ifr, 0,
sizeof(ifr));
160 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
162 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
163 SCLogError(
"%s: failed to get device flags: %s", ifname, strerror(errno));
170 int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
173 return ifr.ifr_flags;
185int SetIfaceFlags(
const char *ifname,
int flags)
189 int fd = socket(AF_INET, SOCK_DGRAM, 0);
194 memset(&ifr, 0,
sizeof(ifr));
195 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
197 ifr.ifr_flags =
flags & 0xffff;
198 ifr.ifr_flagshigh =
flags >> 16;
200 ifr.ifr_flags = (uint16_t)
flags;
203 if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
204 SCLogError(
"%s: unable to set device flags: %s", ifname, strerror(errno));
215int GetIfaceCaps(
const char *ifname)
219 int fd = socket(AF_INET, SOCK_DGRAM, 0);
224 memset(&ifr, 0,
sizeof(ifr));
225 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
227 if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
228 SCLogError(
"%s: unable to get device caps: %s", ifname, strerror(errno));
234 return ifr.ifr_curcap;
238int SetIfaceCaps(
const char *ifname,
int caps)
242 int fd = socket(AF_INET, SOCK_DGRAM, 0);
247 memset(&ifr, 0,
sizeof(ifr));
248 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
249 ifr.ifr_reqcap = caps;
251 if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) {
252 SCLogError(
"%s: unable to set caps: %s", ifname, strerror(errno));
263#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
264static int GetEthtoolValue(
const char *dev,
int cmd, uint32_t *value)
268 struct ethtool_value ethv;
270 fd = socket(AF_INET, SOCK_DGRAM, 0);
274 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
277 ifr.ifr_data = (
void *) ðv;
278 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
279 SCLogWarning(
"%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno));
289static int SetEthtoolValue(
const char *dev,
int cmd, uint32_t value)
293 struct ethtool_value ethv;
295 fd = socket(AF_INET, SOCK_DGRAM, 0);
299 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
303 ifr.ifr_data = (
void *) ðv;
304 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
305 SCLogWarning(
"%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno));
314static int GetIfaceOffloadingLinux(
const char *dev,
int csum,
int other)
320 const char *rx =
"unset", *tx =
"unset";
322#ifdef ETHTOOL_GRXCSUM
323 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
328#ifdef ETHTOOL_GTXCSUM
329 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
335 SCLogPerf(
"%s: NIC offloading: RX %s TX %s", dev, rx, tx);
337 SCLogWarning(
"%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev,
344 const char *lro =
"unset", *gro =
"unset", *tso =
"unset", *gso =
"unset";
345 const char *sg =
"unset";
348 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
354 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
360 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
366 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
372 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
373 if (value & ETH_FLAG_LRO) {
379 if (other_ret == 0) {
380 SCLogPerf(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg,
383 SCLogWarning(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: "
384 "ethtool -K %s sg off gro off lro off tso off gso off",
385 dev, sg, gro, lro, tso, gso, dev);
392static int DisableIfaceOffloadingLinux(
LiveDevice *ldev,
int csum,
int other)
400 const char *dev = ldev->
dev;
403#ifdef ETHTOOL_GRXCSUM
404 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
405 SCLogPerf(
"%s: disabling rxcsum offloading", dev);
406 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0);
410#ifdef ETHTOOL_GTXCSUM
411 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
412 SCLogPerf(
"%s: disabling txcsum offloading", dev);
413 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0);
420 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
421 SCLogPerf(
"%s: disabling gro offloading", dev);
422 SetEthtoolValue(dev, ETHTOOL_SGRO, 0);
427 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
428 SCLogPerf(
"%s: disabling tso offloading", dev);
429 SetEthtoolValue(dev, ETHTOOL_STSO, 0);
434 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
435 SCLogPerf(
"%s: disabling gso offloading", dev);
436 SetEthtoolValue(dev, ETHTOOL_SGSO, 0);
441 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
442 SCLogPerf(
"%s: disabling sg offloading", dev);
443 SetEthtoolValue(dev, ETHTOOL_SSG, 0);
448 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
449 if (value & ETH_FLAG_LRO) {
450 SCLogPerf(
"%s: disabling lro offloading", dev);
451 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO);
460static int RestoreIfaceOffloadingLinux(
LiveDevice *ldev)
465 const char *dev = ldev->
dev;
467#ifdef ETHTOOL_GRXCSUM
469 SCLogPerf(
"%s: restoring rxcsum offloading", dev);
470 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1);
473#ifdef ETHTOOL_GTXCSUM
475 SCLogPerf(
"%s: restoring txcsum offloading", dev);
476 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1);
481 SCLogPerf(
"%s: restoring gro offloading", dev);
482 SetEthtoolValue(dev, ETHTOOL_SGRO, 1);
487 SCLogPerf(
"%s: restoring tso offloading", dev);
488 SetEthtoolValue(dev, ETHTOOL_STSO, 1);
493 SCLogPerf(
"%s: restoring gso offloading", dev);
494 SetEthtoolValue(dev, ETHTOOL_SGSO, 1);
499 SCLogPerf(
"%s: restoring sg offloading", dev);
500 SetEthtoolValue(dev, ETHTOOL_SSG, 1);
506 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
507 SCLogPerf(
"%s: restoring lro offloading", dev);
508 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
518static int GetIfaceOffloadingBSD(
const char *ifname)
521 int if_caps = GetIfaceCaps(ifname);
527 if (if_caps & IFCAP_RXCSUM) {
528 SCLogWarning(
"%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum",
533 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
534 SCLogWarning(
"%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s "
540 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
542 "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro",
552static int DisableIfaceOffloadingBSD(
LiveDevice *ldev)
559 const char *ifname = ldev->
dev;
560 int if_caps = GetIfaceCaps(ifname);
561 int set_caps = if_caps;
567 if (if_caps & IFCAP_RXCSUM) {
568 SCLogPerf(
"%s: disabling rxcsum offloading", ifname);
569 set_caps &= ~IFCAP_RXCSUM;
571 if (if_caps & IFCAP_TXCSUM) {
572 SCLogPerf(
"%s: disabling txcsum offloading", ifname);
573 set_caps &= ~IFCAP_TXCSUM;
575#ifdef IFCAP_RXCSUM_IPV6
576 if (if_caps & IFCAP_RXCSUM_IPV6) {
577 SCLogPerf(
"%s: disabling rxcsum6 offloading", ifname);
578 set_caps &= ~IFCAP_RXCSUM_IPV6;
581#ifdef IFCAP_TXCSUM_IPV6
582 if (if_caps & IFCAP_TXCSUM_IPV6) {
583 SCLogPerf(
"%s: disabling txcsum6 offloading", ifname);
584 set_caps &= ~IFCAP_TXCSUM_IPV6;
588 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
589 SCLogPerf(
"%s: disabling tso|toe|lro offloading", ifname);
590 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
593 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
594 SCLogPerf(
"%s: disabling tso|lro offloading", ifname);
595 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
598 if (set_caps != if_caps) {
599 if (if_caps & IFCAP_RXCSUM)
601 if (if_caps & IFCAP_TSO)
604 if (if_caps & IFCAP_TOE)
607 if (if_caps & IFCAP_LRO)
610 SetIfaceCaps(ifname, set_caps);
615static int RestoreIfaceOffloadingBSD(
LiveDevice *ldev)
622 const char *ifname = ldev->
dev;
623 int if_caps = GetIfaceCaps(ifname);
624 int set_caps = if_caps;
631 SCLogPerf(
"%s: restoring rxcsum offloading", ifname);
632 set_caps |= IFCAP_RXCSUM;
635 SCLogPerf(
"%s: restoring tso offloading", ifname);
636 set_caps |= IFCAP_TSO;
640 SCLogPerf(
"%s: restoring toe offloading", ifname);
641 set_caps |= IFCAP_TOE;
645 SCLogPerf(
"%s: restoring lro offloading", ifname);
646 set_caps |= IFCAP_LRO;
649 if (set_caps != if_caps) {
650 SetIfaceCaps(ifname, set_caps);
672#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
673 return GetIfaceOffloadingLinux(dev, csum, other);
674#elif defined SIOCGIFCAP
675 return GetIfaceOffloadingBSD(dev);
676#elif defined OS_WIN32
677 return GetIfaceOffloadingWin32(dev, csum, other);
688#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
689 return DisableIfaceOffloadingLinux(dev, csum, other);
690#elif defined SIOCSIFCAP
691 return DisableIfaceOffloadingBSD(dev);
692#elif defined OS_WIN32
693 return DisableIfaceOffloadingWin32(dev, csum, other);
703#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
704 RestoreIfaceOffloadingLinux(dev);
705#elif defined SIOCSIFCAP
706 RestoreIfaceOffloadingBSD(dev);
707#elif defined OS_WIN32
708 RestoreIfaceOffloadingWin32(dev);
715#if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS
717 struct ethtool_rxnfc nfccmd;
720 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
721 fd = socket(AF_INET, SOCK_DGRAM, 0);
723 SCLogWarning(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
727 nfccmd.cmd = ETHTOOL_GRXRINGS;
728 ifr.ifr_data = (
void*) &nfccmd;
730 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
731 if (errno != ENOTSUP) {
732 SCLogWarning(
"%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno));
738 SCLogInfo(
"%s: RX RSS queues: %d", dev, (
int)nfccmd.data);
739 return (
int)nfccmd.data;
#define ETHERNET_HEADER_LEN
size_t strlcpy(char *dst, const char *src, size_t siz)
#define SCLogWarning(...)
Macro used to log WARNING messages.
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
#define SCLogError(...)
Macro used to log ERROR messages.
#define OFFLOAD_FLAG_TXCSUM
#define OFFLOAD_FLAG_RXCSUM
int GetIfaceMaxPacketSize(LiveDevice *ld)
output max packet size for a link
int GetIfaceRSSQueuesNum(const char *dev)
int GetIfaceOffloading(const char *dev, int csum, int other)
output offloading status of the link
int DisableIfaceOffloading(LiveDevice *dev, int csum, int other)
int GetIfaceMTU(const char *dev)
output the link MTU
void RestoreIfaceOffloading(LiveDevice *dev)