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);
91 SCLogError(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
95 if (ioctl(fd, SIOCGIFMTU, (
char *)&ifr) < 0) {
96 SCLogWarning(
"Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev,
97 strerror(errno), errno);
102 SCLogInfo(
"%s: MTU %d", dev, ifr.ifr_mtu);
104 #elif defined OS_WIN32
105 return GetIfaceMTUWin32(dev);
127 const char *dev = ld->
dev;
128 if ((dev == NULL) || strlen(dev) == 0)
141 int ll_header = GetIfaceMaxHWHeaderLength(dev);
142 return ll_header + mtu;
151 int GetIfaceFlags(
const char *ifname)
155 int fd = socket(AF_INET, SOCK_DGRAM, 0);
157 SCLogError(
"%s: failed to open socket for ioctl: %s", ifname, strerror(errno));
161 memset(&ifr, 0,
sizeof(ifr));
162 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
164 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
165 SCLogError(
"%s: failed to get device flags: %s", ifname, strerror(errno));
172 int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
175 return ifr.ifr_flags;
187 int SetIfaceFlags(
const char *ifname,
int flags)
191 int fd = socket(AF_INET, SOCK_DGRAM, 0);
193 SCLogError(
"%s: failed to open socket for ioctl: %s", ifname, strerror(errno));
197 memset(&ifr, 0,
sizeof(ifr));
198 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
200 ifr.ifr_flags =
flags & 0xffff;
201 ifr.ifr_flagshigh =
flags >> 16;
203 ifr.ifr_flags = (uint16_t)
flags;
206 if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
207 SCLogError(
"%s: unable to set device flags: %s", ifname, strerror(errno));
218 int GetIfaceCaps(
const char *ifname)
222 int fd = socket(AF_INET, SOCK_DGRAM, 0);
224 SCLogError(
"%s: failed to open socket for ioctl: %s", ifname, strerror(errno));
228 memset(&ifr, 0,
sizeof(ifr));
229 strlcpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
231 if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
232 SCLogError(
"%s: unable to get device caps: %s", ifname, strerror(errno));
238 return ifr.ifr_curcap;
242 int SetIfaceCaps(
const char *ifname,
int caps)
246 int fd = socket(AF_INET, SOCK_DGRAM, 0);
248 SCLogError(
"%s: failed to open socket for ioctl: %s", ifname, strerror(errno));
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);
277 SCLogError(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
280 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
283 ifr.ifr_data = (
void *) ðv;
284 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
285 SCLogWarning(
"%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno));
295 static int SetEthtoolValue(
const char *dev,
int cmd, uint32_t value)
299 struct ethtool_value ethv;
301 fd = socket(AF_INET, SOCK_DGRAM, 0);
303 SCLogError(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
306 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
310 ifr.ifr_data = (
void *) ðv;
311 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
312 SCLogWarning(
"%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno));
321 static int GetIfaceOffloadingLinux(
const char *dev,
int csum,
int other)
327 const char *rx =
"unset", *tx =
"unset";
329 #ifdef ETHTOOL_GRXCSUM
330 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
335 #ifdef ETHTOOL_GTXCSUM
336 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
342 SCLogPerf(
"%s: NIC offloading: RX %s TX %s", dev, rx, tx);
344 SCLogWarning(
"%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev,
351 const char *lro =
"unset", *gro =
"unset", *tso =
"unset", *gso =
"unset";
352 const char *sg =
"unset";
355 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
361 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
367 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
373 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
378 #ifdef ETHTOOL_GFLAGS
379 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
380 if (value & ETH_FLAG_LRO) {
386 if (other_ret == 0) {
387 SCLogPerf(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg,
390 SCLogWarning(
"%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: "
391 "ethtool -K %s sg off gro off lro off tso off gso off",
392 dev, sg, gro, lro, tso, gso, dev);
399 static int DisableIfaceOffloadingLinux(
LiveDevice *ldev,
int csum,
int other)
407 const char *dev = ldev->
dev;
410 #ifdef ETHTOOL_GRXCSUM
411 if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
412 SCLogPerf(
"%s: disabling rxcsum offloading", dev);
413 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0);
417 #ifdef ETHTOOL_GTXCSUM
418 if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
419 SCLogPerf(
"%s: disabling txcsum offloading", dev);
420 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0);
427 if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
428 SCLogPerf(
"%s: disabling gro offloading", dev);
429 SetEthtoolValue(dev, ETHTOOL_SGRO, 0);
434 if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
435 SCLogPerf(
"%s: disabling tso offloading", dev);
436 SetEthtoolValue(dev, ETHTOOL_STSO, 0);
441 if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
442 SCLogPerf(
"%s: disabling gso offloading", dev);
443 SetEthtoolValue(dev, ETHTOOL_SGSO, 0);
448 if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
449 SCLogPerf(
"%s: disabling sg offloading", dev);
450 SetEthtoolValue(dev, ETHTOOL_SSG, 0);
454 #ifdef ETHTOOL_GFLAGS
455 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
456 if (value & ETH_FLAG_LRO) {
457 SCLogPerf(
"%s: disabling lro offloading", dev);
458 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO);
467 static int RestoreIfaceOffloadingLinux(
LiveDevice *ldev)
472 const char *dev = ldev->
dev;
474 #ifdef ETHTOOL_GRXCSUM
476 SCLogPerf(
"%s: restoring rxcsum offloading", dev);
477 SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1);
480 #ifdef ETHTOOL_GTXCSUM
482 SCLogPerf(
"%s: restoring txcsum offloading", dev);
483 SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1);
488 SCLogPerf(
"%s: restoring gro offloading", dev);
489 SetEthtoolValue(dev, ETHTOOL_SGRO, 1);
494 SCLogPerf(
"%s: restoring tso offloading", dev);
495 SetEthtoolValue(dev, ETHTOOL_STSO, 1);
500 SCLogPerf(
"%s: restoring gso offloading", dev);
501 SetEthtoolValue(dev, ETHTOOL_SGSO, 1);
506 SCLogPerf(
"%s: restoring sg offloading", dev);
507 SetEthtoolValue(dev, ETHTOOL_SSG, 1);
510 #ifdef ETHTOOL_GFLAGS
513 if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
514 SCLogPerf(
"%s: restoring lro offloading", dev);
515 SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
525 static int GetIfaceOffloadingBSD(
const char *ifname)
528 int if_caps = GetIfaceCaps(ifname);
534 if (if_caps & IFCAP_RXCSUM) {
535 SCLogWarning(
"%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum",
540 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
541 SCLogWarning(
"%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s "
547 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
549 "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro",
559 static int DisableIfaceOffloadingBSD(
LiveDevice *ldev)
566 const char *ifname = ldev->
dev;
567 int if_caps = GetIfaceCaps(ifname);
568 int set_caps = if_caps;
574 if (if_caps & IFCAP_RXCSUM) {
575 SCLogPerf(
"%s: disabling rxcsum offloading", ifname);
576 set_caps &= ~IFCAP_RXCSUM;
578 if (if_caps & IFCAP_TXCSUM) {
579 SCLogPerf(
"%s: disabling txcsum offloading", ifname);
580 set_caps &= ~IFCAP_TXCSUM;
582 #ifdef IFCAP_RXCSUM_IPV6
583 if (if_caps & IFCAP_RXCSUM_IPV6) {
584 SCLogPerf(
"%s: disabling rxcsum6 offloading", ifname);
585 set_caps &= ~IFCAP_RXCSUM_IPV6;
588 #ifdef IFCAP_TXCSUM_IPV6
589 if (if_caps & IFCAP_TXCSUM_IPV6) {
590 SCLogPerf(
"%s: disabling txcsum6 offloading", ifname);
591 set_caps &= ~IFCAP_TXCSUM_IPV6;
595 if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
596 SCLogPerf(
"%s: disabling tso|toe|lro offloading", ifname);
597 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
600 if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
601 SCLogPerf(
"%s: disabling tso|lro offloading", ifname);
602 set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
605 if (set_caps != if_caps) {
606 if (if_caps & IFCAP_RXCSUM)
608 if (if_caps & IFCAP_TSO)
611 if (if_caps & IFCAP_TOE)
614 if (if_caps & IFCAP_LRO)
617 SetIfaceCaps(ifname, set_caps);
622 static int RestoreIfaceOffloadingBSD(
LiveDevice *ldev)
629 const char *ifname = ldev->
dev;
630 int if_caps = GetIfaceCaps(ifname);
631 int set_caps = if_caps;
638 SCLogPerf(
"%s: restoring rxcsum offloading", ifname);
639 set_caps |= IFCAP_RXCSUM;
642 SCLogPerf(
"%s: restoring tso offloading", ifname);
643 set_caps |= IFCAP_TSO;
647 SCLogPerf(
"%s: restoring toe offloading", ifname);
648 set_caps |= IFCAP_TOE;
652 SCLogPerf(
"%s: restoring lro offloading", ifname);
653 set_caps |= IFCAP_LRO;
656 if (set_caps != if_caps) {
657 SetIfaceCaps(ifname, set_caps);
679 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
680 return GetIfaceOffloadingLinux(dev, csum, other);
681 #elif defined SIOCGIFCAP
682 return GetIfaceOffloadingBSD(dev);
683 #elif defined OS_WIN32
684 return GetIfaceOffloadingWin32(dev, csum, other);
695 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
696 return DisableIfaceOffloadingLinux(dev, csum, other);
697 #elif defined SIOCSIFCAP
698 return DisableIfaceOffloadingBSD(dev);
699 #elif defined OS_WIN32
700 return DisableIfaceOffloadingWin32(dev, csum, other);
710 #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
711 RestoreIfaceOffloadingLinux(dev);
712 #elif defined SIOCSIFCAP
713 RestoreIfaceOffloadingBSD(dev);
714 #elif defined OS_WIN32
715 RestoreIfaceOffloadingWin32(dev);
722 #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS
724 struct ethtool_rxnfc nfccmd;
727 (void)
strlcpy(ifr.ifr_name, dev,
sizeof(ifr.ifr_name));
728 fd = socket(AF_INET, SOCK_DGRAM, 0);
730 SCLogError(
"%s: failed to open socket for ioctl: %s", dev, strerror(errno));
734 nfccmd.cmd = ETHTOOL_GRXRINGS;
735 ifr.ifr_data = (
void*) &nfccmd;
737 if (ioctl(fd, SIOCETHTOOL, (
char *)&ifr) < 0) {
738 if (errno != ENOTSUP) {
739 SCLogWarning(
"%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno));
745 SCLogInfo(
"%s: RX RSS queues: %d", dev, (
int)nfccmd.data);
746 return (
int)nfccmd.data;