32 #ifdef HAVE_SYS_IOCTL_H
33 #include <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"
59 static 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))
84 #if defined SIOCGIFMTU
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;
150 int 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;
185 int 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));
215 int 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;
238 int 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
264 static 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));
289 static 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));
314 static 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) {
371 #ifdef ETHTOOL_GFLAGS
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);
392 static 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);
447 #ifdef ETHTOOL_GFLAGS
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);
460 static 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);
503 #ifdef ETHTOOL_GFLAGS
506 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
507 SCLogPerf(
"%s: restoring lro offloading", dev);
508 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
518 static 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",
552 static 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);
615 static 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;