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 *pcap_dev)
60 if ((!strcmp(
"eth", pcap_dev))
62 (!strcmp(
"br", pcap_dev))
64 (!strcmp(
"bond", pcap_dev))
66 (!strcmp(
"wlan", pcap_dev))
68 (!strcmp(
"tun", pcap_dev))
70 (!strcmp(
"tap", pcap_dev))
72 (!strcmp(
"lo", pcap_dev))) {
77 if (!strcmp(
"ppp", pcap_dev))
93 #if defined SIOCGIFMTU
97 (void)
strlcpy(ifr.ifr_name, pcap_dev,
sizeof(ifr.ifr_name));
98 fd = socket(AF_INET, SOCK_DGRAM, 0);
103 if (ioctl(fd, SIOCGIFMTU, (
char *)&ifr) < 0) {
104 SCLogWarning(
"Failure when trying to get MTU via ioctl for '%s': %s (%d)", pcap_dev,
105 strerror(errno), errno);
110 SCLogInfo(
"%s: MTU %d", pcap_dev, ifr.ifr_mtu);
112 #elif defined OS_WIN32
113 return GetIfaceMTUWin32(pcap_dev);
132 if ((pcap_dev == NULL) || strlen(pcap_dev) == 0)
141 int ll_header = GetIfaceMaxHWHeaderLength(pcap_dev);
142 if (ll_header == -1) {
146 return ll_header + mtu;
155 int GetIfaceFlags(
const char *ifname)
159 int fd = socket(AF_INET, SOCK_DGRAM, 0);
164 memset(&ifr, 0,
sizeof(ifr));
165 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
167 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
168 SCLogError(
"%s: failed to get device flags: %s", ifname, strerror(errno));
175 int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
178 return ifr.ifr_flags;
190 int SetIfaceFlags(
const char *ifname,
int flags)
194 int fd = socket(AF_INET, SOCK_DGRAM, 0);
199 memset(&ifr, 0,
sizeof(ifr));
200 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
202 ifr.ifr_flags =
flags & 0xffff;
203 ifr.ifr_flagshigh =
flags >> 16;
205 ifr.ifr_flags = (uint16_t)
flags;
208 if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
209 SCLogError(
"%s: unable to set device flags: %s", ifname, strerror(errno));
220 int GetIfaceCaps(
const char *ifname)
224 int fd = socket(AF_INET, SOCK_DGRAM, 0);
229 memset(&ifr, 0,
sizeof(ifr));
230 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
232 if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
233 SCLogError(
"%s: unable to get device caps: %s", ifname, strerror(errno));
239 return ifr.ifr_curcap;
243 int SetIfaceCaps(
const char *ifname,
int caps)
247 int fd = socket(AF_INET, SOCK_DGRAM, 0);
252 memset(&ifr, 0,
sizeof(ifr));
253 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
254 ifr.ifr_reqcap = caps;
256 if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) {
257 SCLogError(
"%s: unable to set caps: %s", ifname, strerror(errno));
268 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
269 static int GetEthtoolValue(
const char *dev,
int cmd, uint32_t *value)
273 struct ethtool_value ethv;
275 fd = socket(AF_INET, SOCK_DGRAM, 0);
279 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
282 ifr.ifr_data = (
void *) ðv;
283 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
284 SCLogWarning(
"%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno));
294 static int SetEthtoolValue(
const char *dev,
int cmd, uint32_t value)
298 struct ethtool_value ethv;
300 fd = socket(AF_INET, SOCK_DGRAM, 0);
304 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
308 ifr.ifr_data = (
void *) ðv;
309 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
310 SCLogWarning(
"%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno));
319 static int GetIfaceOffloadingLinux(
const char *dev,
int csum,
int other)
325 const char *rx =
"unset", *tx =
"unset";
327 #ifdef ETHTOOL_GRXCSUM
328 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
333 #ifdef ETHTOOL_GTXCSUM
334 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
340 SCLogPerf(
"%s: NIC offloading: RX %s TX %s", dev, rx, tx);
342 SCLogWarning(
"%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev,
349 const char *lro =
"unset", *gro =
"unset", *tso =
"unset", *gso =
"unset";
350 const char *sg =
"unset";
353 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
359 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
365 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
371 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
376 #ifdef ETHTOOL_GFLAGS
377 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
378 if (value & ETH_FLAG_LRO) {
384 if (other_ret == 0) {
385 SCLogPerf(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg,
388 SCLogWarning(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: "
389 "ethtool -K %s sg off gro off lro off tso off gso off",
390 dev, sg, gro, lro, tso, gso, dev);
397 static int DisableIfaceOffloadingLinux(
LiveDevice *ldev,
int csum,
int other)
405 const char *dev = ldev->
dev;
408 #ifdef ETHTOOL_GRXCSUM
409 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
410 SCLogPerf(
"%s: disabling rxcsum offloading", dev);
411 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0);
415 #ifdef ETHTOOL_GTXCSUM
416 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
417 SCLogPerf(
"%s: disabling txcsum offloading", dev);
418 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0);
425 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
426 SCLogPerf(
"%s: disabling gro offloading", dev);
427 SetEthtoolValue(dev, ETHTOOL_SGRO, 0);
432 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
433 SCLogPerf(
"%s: disabling tso offloading", dev);
434 SetEthtoolValue(dev, ETHTOOL_STSO, 0);
439 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
440 SCLogPerf(
"%s: disabling gso offloading", dev);
441 SetEthtoolValue(dev, ETHTOOL_SGSO, 0);
446 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
447 SCLogPerf(
"%s: disabling sg offloading", dev);
448 SetEthtoolValue(dev, ETHTOOL_SSG, 0);
452 #ifdef ETHTOOL_GFLAGS
453 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
454 if (value & ETH_FLAG_LRO) {
455 SCLogPerf(
"%s: disabling lro offloading", dev);
456 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO);
465 static int RestoreIfaceOffloadingLinux(
LiveDevice *ldev)
470 const char *dev = ldev->
dev;
472 #ifdef ETHTOOL_GRXCSUM
474 SCLogPerf(
"%s: restoring rxcsum offloading", dev);
475 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1);
478 #ifdef ETHTOOL_GTXCSUM
480 SCLogPerf(
"%s: restoring txcsum offloading", dev);
481 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1);
486 SCLogPerf(
"%s: restoring gro offloading", dev);
487 SetEthtoolValue(dev, ETHTOOL_SGRO, 1);
492 SCLogPerf(
"%s: restoring tso offloading", dev);
493 SetEthtoolValue(dev, ETHTOOL_STSO, 1);
498 SCLogPerf(
"%s: restoring gso offloading", dev);
499 SetEthtoolValue(dev, ETHTOOL_SGSO, 1);
504 SCLogPerf(
"%s: restoring sg offloading", dev);
505 SetEthtoolValue(dev, ETHTOOL_SSG, 1);
508 #ifdef ETHTOOL_GFLAGS
511 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
512 SCLogPerf(
"%s: restoring lro offloading", dev);
513 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
523 static int GetIfaceOffloadingBSD(
const char *ifname)
526 int if_caps = GetIfaceCaps(ifname);
532 if (if_caps & IFCAP_RXCSUM) {
533 SCLogWarning(
"%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum",
538 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
539 SCLogWarning(
"%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s "
545 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
547 "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro",
557 static int DisableIfaceOffloadingBSD(
LiveDevice *ldev)
564 const char *ifname = ldev->
dev;
565 int if_caps = GetIfaceCaps(ifname);
566 int set_caps = if_caps;
572 if (if_caps & IFCAP_RXCSUM) {
573 SCLogPerf(
"%s: disabling rxcsum offloading", ifname);
574 set_caps &= ~IFCAP_RXCSUM;
576 if (if_caps & IFCAP_TXCSUM) {
577 SCLogPerf(
"%s: disabling txcsum offloading", ifname);
578 set_caps &= ~IFCAP_TXCSUM;
580 #ifdef IFCAP_RXCSUM_IPV6
581 if (if_caps & IFCAP_RXCSUM_IPV6) {
582 SCLogPerf(
"%s: disabling rxcsum6 offloading", ifname);
583 set_caps &= ~IFCAP_RXCSUM_IPV6;
586 #ifdef IFCAP_TXCSUM_IPV6
587 if (if_caps & IFCAP_TXCSUM_IPV6) {
588 SCLogPerf(
"%s: disabling txcsum6 offloading", ifname);
589 set_caps &= ~IFCAP_TXCSUM_IPV6;
593 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
594 SCLogPerf(
"%s: disabling tso|toe|lro offloading", ifname);
595 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
598 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
599 SCLogPerf(
"%s: disabling tso|lro offloading", ifname);
600 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
603 if (set_caps != if_caps) {
604 if (if_caps & IFCAP_RXCSUM)
606 if (if_caps & IFCAP_TSO)
609 if (if_caps & IFCAP_TOE)
612 if (if_caps & IFCAP_LRO)
615 SetIfaceCaps(ifname, set_caps);
620 static int RestoreIfaceOffloadingBSD(
LiveDevice *ldev)
627 const char *ifname = ldev->
dev;
628 int if_caps = GetIfaceCaps(ifname);
629 int set_caps = if_caps;
636 SCLogPerf(
"%s: restoring rxcsum offloading", ifname);
637 set_caps |= IFCAP_RXCSUM;
640 SCLogPerf(
"%s: restoring tso offloading", ifname);
641 set_caps |= IFCAP_TSO;
645 SCLogPerf(
"%s: restoring toe offloading", ifname);
646 set_caps |= IFCAP_TOE;
650 SCLogPerf(
"%s: restoring lro offloading", ifname);
651 set_caps |= IFCAP_LRO;
654 if (set_caps != if_caps) {
655 SetIfaceCaps(ifname, set_caps);
677 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
678 return GetIfaceOffloadingLinux(dev, csum, other);
679 #elif defined SIOCGIFCAP
680 return GetIfaceOffloadingBSD(dev);
681 #elif defined OS_WIN32
682 return GetIfaceOffloadingWin32(dev, csum, other);
693 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
694 return DisableIfaceOffloadingLinux(dev, csum, other);
695 #elif defined SIOCSIFCAP
696 return DisableIfaceOffloadingBSD(dev);
697 #elif defined OS_WIN32
698 return DisableIfaceOffloadingWin32(dev, csum, other);
708 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
709 RestoreIfaceOffloadingLinux(dev);
710 #elif defined SIOCSIFCAP
711 RestoreIfaceOffloadingBSD(dev);
712 #elif defined OS_WIN32
713 RestoreIfaceOffloadingWin32(dev);
720 #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS
722 struct ethtool_rxnfc nfccmd;
725 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
726 fd = socket(AF_INET, SOCK_DGRAM, 0);
728 SCLogWarning(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
732 nfccmd.cmd = ETHTOOL_GRXRINGS;
733 ifr.ifr_data = (
void*) &nfccmd;
735 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
736 if (errno != ENOTSUP) {
737 SCLogWarning(
"%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno));
743 SCLogInfo(
"%s: RX RSS queues: %d", dev, (
int)nfccmd.data);
744 return (
int)nfccmd.data;