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)
137 int ll_header = GetIfaceMaxHWHeaderLength(dev);
138 return ll_header + mtu;
147 int GetIfaceFlags(
const char *ifname)
151 int fd = socket(AF_INET, SOCK_DGRAM, 0);
156 memset(&ifr, 0,
sizeof(ifr));
157 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
159 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
160 SCLogError(
"%s: failed to get device flags: %s", ifname, strerror(errno));
167 int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
170 return ifr.ifr_flags;
182 int SetIfaceFlags(
const char *ifname,
int flags)
186 int fd = socket(AF_INET, SOCK_DGRAM, 0);
191 memset(&ifr, 0,
sizeof(ifr));
192 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
194 ifr.ifr_flags =
flags & 0xffff;
195 ifr.ifr_flagshigh =
flags >> 16;
197 ifr.ifr_flags = (uint16_t)
flags;
200 if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
201 SCLogError(
"%s: unable to set device flags: %s", ifname, strerror(errno));
212 int GetIfaceCaps(
const char *ifname)
216 int fd = socket(AF_INET, SOCK_DGRAM, 0);
221 memset(&ifr, 0,
sizeof(ifr));
222 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
224 if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
225 SCLogError(
"%s: unable to get device caps: %s", ifname, strerror(errno));
231 return ifr.ifr_curcap;
235 int SetIfaceCaps(
const char *ifname,
int caps)
239 int fd = socket(AF_INET, SOCK_DGRAM, 0);
244 memset(&ifr, 0,
sizeof(ifr));
245 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
246 ifr.ifr_reqcap = caps;
248 if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) {
249 SCLogError(
"%s: unable to set caps: %s", ifname, strerror(errno));
260 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
261 static int GetEthtoolValue(
const char *dev,
int cmd, uint32_t *value)
265 struct ethtool_value ethv;
267 fd = socket(AF_INET, SOCK_DGRAM, 0);
271 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
274 ifr.ifr_data = (
void *) ðv;
275 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
276 SCLogWarning(
"%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno));
286 static int SetEthtoolValue(
const char *dev,
int cmd, uint32_t value)
290 struct ethtool_value ethv;
292 fd = socket(AF_INET, SOCK_DGRAM, 0);
296 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
300 ifr.ifr_data = (
void *) ðv;
301 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
302 SCLogWarning(
"%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno));
311 static int GetIfaceOffloadingLinux(
const char *dev,
int csum,
int other)
317 const char *rx =
"unset", *tx =
"unset";
319 #ifdef ETHTOOL_GRXCSUM
320 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
325 #ifdef ETHTOOL_GTXCSUM
326 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
332 SCLogPerf(
"%s: NIC offloading: RX %s TX %s", dev, rx, tx);
334 SCLogWarning(
"%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev,
341 const char *lro =
"unset", *gro =
"unset", *tso =
"unset", *gso =
"unset";
342 const char *sg =
"unset";
345 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
351 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
357 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
363 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
368 #ifdef ETHTOOL_GFLAGS
369 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
370 if (value & ETH_FLAG_LRO) {
376 if (other_ret == 0) {
377 SCLogPerf(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg,
380 SCLogWarning(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: "
381 "ethtool -K %s sg off gro off lro off tso off gso off",
382 dev, sg, gro, lro, tso, gso, dev);
389 static int DisableIfaceOffloadingLinux(
LiveDevice *ldev,
int csum,
int other)
397 const char *dev = ldev->
dev;
400 #ifdef ETHTOOL_GRXCSUM
401 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
402 SCLogPerf(
"%s: disabling rxcsum offloading", dev);
403 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0);
407 #ifdef ETHTOOL_GTXCSUM
408 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
409 SCLogPerf(
"%s: disabling txcsum offloading", dev);
410 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0);
417 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
418 SCLogPerf(
"%s: disabling gro offloading", dev);
419 SetEthtoolValue(dev, ETHTOOL_SGRO, 0);
424 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
425 SCLogPerf(
"%s: disabling tso offloading", dev);
426 SetEthtoolValue(dev, ETHTOOL_STSO, 0);
431 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
432 SCLogPerf(
"%s: disabling gso offloading", dev);
433 SetEthtoolValue(dev, ETHTOOL_SGSO, 0);
438 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
439 SCLogPerf(
"%s: disabling sg offloading", dev);
440 SetEthtoolValue(dev, ETHTOOL_SSG, 0);
444 #ifdef ETHTOOL_GFLAGS
445 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
446 if (value & ETH_FLAG_LRO) {
447 SCLogPerf(
"%s: disabling lro offloading", dev);
448 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO);
457 static int RestoreIfaceOffloadingLinux(
LiveDevice *ldev)
462 const char *dev = ldev->
dev;
464 #ifdef ETHTOOL_GRXCSUM
466 SCLogPerf(
"%s: restoring rxcsum offloading", dev);
467 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1);
470 #ifdef ETHTOOL_GTXCSUM
472 SCLogPerf(
"%s: restoring txcsum offloading", dev);
473 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1);
478 SCLogPerf(
"%s: restoring gro offloading", dev);
479 SetEthtoolValue(dev, ETHTOOL_SGRO, 1);
484 SCLogPerf(
"%s: restoring tso offloading", dev);
485 SetEthtoolValue(dev, ETHTOOL_STSO, 1);
490 SCLogPerf(
"%s: restoring gso offloading", dev);
491 SetEthtoolValue(dev, ETHTOOL_SGSO, 1);
496 SCLogPerf(
"%s: restoring sg offloading", dev);
497 SetEthtoolValue(dev, ETHTOOL_SSG, 1);
500 #ifdef ETHTOOL_GFLAGS
503 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
504 SCLogPerf(
"%s: restoring lro offloading", dev);
505 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
515 static int GetIfaceOffloadingBSD(
const char *ifname)
518 int if_caps = GetIfaceCaps(ifname);
524 if (if_caps & IFCAP_RXCSUM) {
525 SCLogWarning(
"%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum",
530 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
531 SCLogWarning(
"%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s "
537 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
539 "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro",
549 static int DisableIfaceOffloadingBSD(
LiveDevice *ldev)
556 const char *ifname = ldev->
dev;
557 int if_caps = GetIfaceCaps(ifname);
558 int set_caps = if_caps;
564 if (if_caps & IFCAP_RXCSUM) {
565 SCLogPerf(
"%s: disabling rxcsum offloading", ifname);
566 set_caps &= ~IFCAP_RXCSUM;
568 if (if_caps & IFCAP_TXCSUM) {
569 SCLogPerf(
"%s: disabling txcsum offloading", ifname);
570 set_caps &= ~IFCAP_TXCSUM;
572 #ifdef IFCAP_RXCSUM_IPV6
573 if (if_caps & IFCAP_RXCSUM_IPV6) {
574 SCLogPerf(
"%s: disabling rxcsum6 offloading", ifname);
575 set_caps &= ~IFCAP_RXCSUM_IPV6;
578 #ifdef IFCAP_TXCSUM_IPV6
579 if (if_caps & IFCAP_TXCSUM_IPV6) {
580 SCLogPerf(
"%s: disabling txcsum6 offloading", ifname);
581 set_caps &= ~IFCAP_TXCSUM_IPV6;
585 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
586 SCLogPerf(
"%s: disabling tso|toe|lro offloading", ifname);
587 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
590 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
591 SCLogPerf(
"%s: disabling tso|lro offloading", ifname);
592 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
595 if (set_caps != if_caps) {
596 if (if_caps & IFCAP_RXCSUM)
598 if (if_caps & IFCAP_TSO)
601 if (if_caps & IFCAP_TOE)
604 if (if_caps & IFCAP_LRO)
607 SetIfaceCaps(ifname, set_caps);
612 static int RestoreIfaceOffloadingBSD(
LiveDevice *ldev)
619 const char *ifname = ldev->
dev;
620 int if_caps = GetIfaceCaps(ifname);
621 int set_caps = if_caps;
628 SCLogPerf(
"%s: restoring rxcsum offloading", ifname);
629 set_caps |= IFCAP_RXCSUM;
632 SCLogPerf(
"%s: restoring tso offloading", ifname);
633 set_caps |= IFCAP_TSO;
637 SCLogPerf(
"%s: restoring toe offloading", ifname);
638 set_caps |= IFCAP_TOE;
642 SCLogPerf(
"%s: restoring lro offloading", ifname);
643 set_caps |= IFCAP_LRO;
646 if (set_caps != if_caps) {
647 SetIfaceCaps(ifname, set_caps);
669 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
670 return GetIfaceOffloadingLinux(dev, csum, other);
671 #elif defined SIOCGIFCAP
672 return GetIfaceOffloadingBSD(dev);
673 #elif defined OS_WIN32
674 return GetIfaceOffloadingWin32(dev, csum, other);
685 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
686 return DisableIfaceOffloadingLinux(dev, csum, other);
687 #elif defined SIOCSIFCAP
688 return DisableIfaceOffloadingBSD(dev);
689 #elif defined OS_WIN32
690 return DisableIfaceOffloadingWin32(dev, csum, other);
700 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
701 RestoreIfaceOffloadingLinux(dev);
702 #elif defined SIOCSIFCAP
703 RestoreIfaceOffloadingBSD(dev);
704 #elif defined OS_WIN32
705 RestoreIfaceOffloadingWin32(dev);
712 #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS
714 struct ethtool_rxnfc nfccmd;
717 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
718 fd = socket(AF_INET, SOCK_DGRAM, 0);
720 SCLogWarning(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
724 nfccmd.cmd = ETHTOOL_GRXRINGS;
725 ifr.ifr_data = (
void*) &nfccmd;
727 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
728 if (errno != ENOTSUP) {
729 SCLogWarning(
"%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno));
735 SCLogInfo(
"%s: RX RSS queues: %d", dev, (
int)nfccmd.data);
736 return (
int)nfccmd.data;