31 #ifdef HAVE_SYS_IOCTL_H
32 #include <sys/ioctl.h>
35 #ifdef HAVE_LINUX_ETHTOOL_H
36 #include <linux/types.h>
37 #include <linux/ethtool.h>
38 #ifdef HAVE_LINUX_SOCKIOS_H
39 #include <linux/sockios.h>
41 #error "ethtool.h present but sockios.h is missing"
58 static int GetIfaceMaxHWHeaderLength(
const char *dev)
60 if ((!strcmp(
"eth", dev)) || (!strcmp(
"br", dev)) || (!strcmp(
"bond", dev)) ||
61 (!strcmp(
"wlan", dev)) || (!strcmp(
"tun", dev)) || (!strcmp(
"tap", dev)) ||
62 (!strcmp(
"lo", dev))) {
67 if (!strcmp(
"ppp", dev))
83 #if defined SIOCGIFMTU
87 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
88 fd = socket(AF_INET, SOCK_DGRAM, 0);
93 if (ioctl(fd, SIOCGIFMTU, (
char *)&ifr) < 0) {
94 SCLogWarning(
"Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev,
95 strerror(errno), errno);
100 SCLogInfo(
"%s: MTU %d", dev, ifr.ifr_mtu);
102 #elif defined OS_WIN32
103 return GetIfaceMTUWin32(dev);
125 const char *dev = ld->
dev;
126 if ((dev == NULL) || strlen(dev) == 0)
136 int ll_header = GetIfaceMaxHWHeaderLength(dev);
137 return ll_header + mtu;
146 int GetIfaceFlags(
const char *ifname)
150 int fd = socket(AF_INET, SOCK_DGRAM, 0);
155 memset(&ifr, 0,
sizeof(ifr));
156 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
158 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
159 SCLogError(
"%s: failed to get device flags: %s", ifname, strerror(errno));
166 int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
169 return ifr.ifr_flags;
181 int SetIfaceFlags(
const char *ifname,
int flags)
185 int fd = socket(AF_INET, SOCK_DGRAM, 0);
190 memset(&ifr, 0,
sizeof(ifr));
191 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
193 ifr.ifr_flags =
flags & 0xffff;
194 ifr.ifr_flagshigh =
flags >> 16;
196 ifr.ifr_flags = (uint16_t)
flags;
199 if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
200 SCLogError(
"%s: unable to set device flags: %s", ifname, strerror(errno));
211 int GetIfaceCaps(
const char *ifname)
215 int fd = socket(AF_INET, SOCK_DGRAM, 0);
220 memset(&ifr, 0,
sizeof(ifr));
221 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
223 if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
224 SCLogError(
"%s: unable to get device caps: %s", ifname, strerror(errno));
230 return ifr.ifr_curcap;
234 int SetIfaceCaps(
const char *ifname,
int caps)
238 int fd = socket(AF_INET, SOCK_DGRAM, 0);
243 memset(&ifr, 0,
sizeof(ifr));
244 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
245 ifr.ifr_reqcap = caps;
247 if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) {
248 SCLogError(
"%s: unable to set caps: %s", ifname, strerror(errno));
259 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
260 static int GetEthtoolValue(
const char *dev,
int cmd, uint32_t *value)
264 struct ethtool_value ethv;
266 fd = socket(AF_INET, SOCK_DGRAM, 0);
270 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
273 ifr.ifr_data = (
void *) ðv;
274 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
275 SCLogWarning(
"%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno));
285 static int SetEthtoolValue(
const char *dev,
int cmd, uint32_t value)
289 struct ethtool_value ethv;
291 fd = socket(AF_INET, SOCK_DGRAM, 0);
295 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
299 ifr.ifr_data = (
void *) ðv;
300 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
301 SCLogWarning(
"%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno));
310 static int GetIfaceOffloadingLinux(
const char *dev,
int csum,
int other)
316 const char *rx =
"unset", *tx =
"unset";
318 #ifdef ETHTOOL_GRXCSUM
319 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
324 #ifdef ETHTOOL_GTXCSUM
325 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
331 SCLogPerf(
"%s: NIC offloading: RX %s TX %s", dev, rx, tx);
333 SCLogWarning(
"%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev,
340 const char *lro =
"unset", *gro =
"unset", *tso =
"unset", *gso =
"unset";
341 const char *sg =
"unset";
344 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
350 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
356 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
362 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
367 #ifdef ETHTOOL_GFLAGS
368 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
369 if (value & ETH_FLAG_LRO) {
375 if (other_ret == 0) {
376 SCLogPerf(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg,
379 SCLogWarning(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: "
380 "ethtool -K %s sg off gro off lro off tso off gso off",
381 dev, sg, gro, lro, tso, gso, dev);
388 static int DisableIfaceOffloadingLinux(
LiveDevice *ldev,
int csum,
int other)
396 const char *dev = ldev->
dev;
399 #ifdef ETHTOOL_GRXCSUM
400 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
401 SCLogPerf(
"%s: disabling rxcsum offloading", dev);
402 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0);
406 #ifdef ETHTOOL_GTXCSUM
407 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
408 SCLogPerf(
"%s: disabling txcsum offloading", dev);
409 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0);
416 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
417 SCLogPerf(
"%s: disabling gro offloading", dev);
418 SetEthtoolValue(dev, ETHTOOL_SGRO, 0);
423 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
424 SCLogPerf(
"%s: disabling tso offloading", dev);
425 SetEthtoolValue(dev, ETHTOOL_STSO, 0);
430 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
431 SCLogPerf(
"%s: disabling gso offloading", dev);
432 SetEthtoolValue(dev, ETHTOOL_SGSO, 0);
437 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
438 SCLogPerf(
"%s: disabling sg offloading", dev);
439 SetEthtoolValue(dev, ETHTOOL_SSG, 0);
443 #ifdef ETHTOOL_GFLAGS
444 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
445 if (value & ETH_FLAG_LRO) {
446 SCLogPerf(
"%s: disabling lro offloading", dev);
447 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO);
456 static int RestoreIfaceOffloadingLinux(
LiveDevice *ldev)
461 const char *dev = ldev->
dev;
463 #ifdef ETHTOOL_GRXCSUM
465 SCLogPerf(
"%s: restoring rxcsum offloading", dev);
466 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1);
469 #ifdef ETHTOOL_GTXCSUM
471 SCLogPerf(
"%s: restoring txcsum offloading", dev);
472 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1);
477 SCLogPerf(
"%s: restoring gro offloading", dev);
478 SetEthtoolValue(dev, ETHTOOL_SGRO, 1);
483 SCLogPerf(
"%s: restoring tso offloading", dev);
484 SetEthtoolValue(dev, ETHTOOL_STSO, 1);
489 SCLogPerf(
"%s: restoring gso offloading", dev);
490 SetEthtoolValue(dev, ETHTOOL_SGSO, 1);
495 SCLogPerf(
"%s: restoring sg offloading", dev);
496 SetEthtoolValue(dev, ETHTOOL_SSG, 1);
499 #ifdef ETHTOOL_GFLAGS
502 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
503 SCLogPerf(
"%s: restoring lro offloading", dev);
504 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
514 static int GetIfaceOffloadingBSD(
const char *ifname)
517 int if_caps = GetIfaceCaps(ifname);
523 if (if_caps & IFCAP_RXCSUM) {
524 SCLogWarning(
"%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum",
529 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
530 SCLogWarning(
"%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s "
536 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
538 "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro",
548 static int DisableIfaceOffloadingBSD(
LiveDevice *ldev)
555 const char *ifname = ldev->
dev;
556 int if_caps = GetIfaceCaps(ifname);
557 int set_caps = if_caps;
563 if (if_caps & IFCAP_RXCSUM) {
564 SCLogPerf(
"%s: disabling rxcsum offloading", ifname);
565 set_caps &= ~IFCAP_RXCSUM;
567 if (if_caps & IFCAP_TXCSUM) {
568 SCLogPerf(
"%s: disabling txcsum offloading", ifname);
569 set_caps &= ~IFCAP_TXCSUM;
571 #ifdef IFCAP_RXCSUM_IPV6
572 if (if_caps & IFCAP_RXCSUM_IPV6) {
573 SCLogPerf(
"%s: disabling rxcsum6 offloading", ifname);
574 set_caps &= ~IFCAP_RXCSUM_IPV6;
577 #ifdef IFCAP_TXCSUM_IPV6
578 if (if_caps & IFCAP_TXCSUM_IPV6) {
579 SCLogPerf(
"%s: disabling txcsum6 offloading", ifname);
580 set_caps &= ~IFCAP_TXCSUM_IPV6;
584 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
585 SCLogPerf(
"%s: disabling tso|toe|lro offloading", ifname);
586 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
589 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
590 SCLogPerf(
"%s: disabling tso|lro offloading", ifname);
591 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
594 if (set_caps != if_caps) {
595 if (if_caps & IFCAP_RXCSUM)
597 if (if_caps & IFCAP_TSO)
600 if (if_caps & IFCAP_TOE)
603 if (if_caps & IFCAP_LRO)
606 SetIfaceCaps(ifname, set_caps);
611 static int RestoreIfaceOffloadingBSD(
LiveDevice *ldev)
618 const char *ifname = ldev->
dev;
619 int if_caps = GetIfaceCaps(ifname);
620 int set_caps = if_caps;
627 SCLogPerf(
"%s: restoring rxcsum offloading", ifname);
628 set_caps |= IFCAP_RXCSUM;
631 SCLogPerf(
"%s: restoring tso offloading", ifname);
632 set_caps |= IFCAP_TSO;
636 SCLogPerf(
"%s: restoring toe offloading", ifname);
637 set_caps |= IFCAP_TOE;
641 SCLogPerf(
"%s: restoring lro offloading", ifname);
642 set_caps |= IFCAP_LRO;
645 if (set_caps != if_caps) {
646 SetIfaceCaps(ifname, set_caps);
668 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
669 return GetIfaceOffloadingLinux(dev, csum, other);
670 #elif defined SIOCGIFCAP
671 return GetIfaceOffloadingBSD(dev);
672 #elif defined OS_WIN32
673 return GetIfaceOffloadingWin32(dev, csum, other);
684 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
685 return DisableIfaceOffloadingLinux(dev, csum, other);
686 #elif defined SIOCSIFCAP
687 return DisableIfaceOffloadingBSD(dev);
688 #elif defined OS_WIN32
689 return DisableIfaceOffloadingWin32(dev, csum, other);
699 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
700 RestoreIfaceOffloadingLinux(dev);
701 #elif defined SIOCSIFCAP
702 RestoreIfaceOffloadingBSD(dev);
703 #elif defined OS_WIN32
704 RestoreIfaceOffloadingWin32(dev);
711 #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS
713 struct ethtool_rxnfc nfccmd;
716 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
717 fd = socket(AF_INET, SOCK_DGRAM, 0);
719 SCLogWarning(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
723 nfccmd.cmd = ETHTOOL_GRXRINGS;
724 ifr.ifr_data = (
void*) &nfccmd;
726 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
727 if (errno != ENOTSUP) {
728 SCLogWarning(
"%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno));
734 SCLogInfo(
"%s: RX RSS queues: %d", dev, (
int)nfccmd.data);
735 return (
int)nfccmd.data;