offloading: improve checks on FreeBSD

Move FreeBSD specific (but not netmap specific) checks from the netmap
code to the general ioctl wrapper code.

Warn from the check functions now, so callers no longer need to.
pull/2160/head
Victor Julien 9 years ago
parent 33f8769001
commit 45fa25eb0c

@ -80,6 +80,8 @@
#endif /* HAVE_NETMAP */
#include "util-ioctl.h"
extern intmax_t max_pending_packets;
#ifndef HAVE_NETMAP
@ -224,113 +226,6 @@ typedef TAILQ_HEAD(NetmapDeviceList_, NetmapDevice_) NetmapDeviceList;
static NetmapDeviceList netmap_devlist = TAILQ_HEAD_INITIALIZER(netmap_devlist);
static SCMutex netmap_devlist_lock = SCMUTEX_INITIALIZER;
/**
* \brief Get interface flags.
* \param fd Network susbystem file descritor.
* \param ifname Inteface name.
* \return Interface flags or -1 on error
*/
static int NetmapGetIfaceFlags(int fd, const char *ifname)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
SCLogError(SC_ERR_NETMAP_CREATE,
"Unable to get flags for iface \"%s\": %s",
ifname, strerror(errno));
return -1;
}
#ifdef OS_FREEBSD
int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
return flags;
#else
return ifr.ifr_flags;
#endif
}
#ifdef SIOCGIFCAP
static int NetmapGetIfaceCaps(int fd, const char *ifname)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
SCLogError(SC_ERR_NETMAP_CREATE,
"Unable to get caps for iface \"%s\": %s",
ifname, strerror(errno));
return -1;
}
return ifr.ifr_curcap;
}
#endif
static void NetmapCheckOffloading(int fd, const char *ifname)
{
#ifdef SIOCGIFCAP
int if_caps = NetmapGetIfaceCaps(fd, ifname);
if (if_caps == -1) {
return;
}
SCLogDebug("if_caps %X", if_caps);
if (if_caps & IFCAP_RXCSUM) {
SCLogWarning(SC_ERR_NETMAP_CREATE,
"Using NETMAP with RXCSUM activated can lead to capture "
"problems: ifconfig %s -rxcsum", ifname);
}
if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
SCLogWarning(SC_ERR_NETMAP_CREATE,
"Using NETMAP with TSO, TOE or LRO activated can lead to "
"capture problems: ifconfig %s -tso -toe -lro", ifname);
}
#else
if (GetIfaceOffloading(ifname) == 1) {
SCLogWarning(SC_ERR_NETMAP_CREATE,
"Using NETMAP with GRO or LRO activated can lead to "
"capture problems: "
"ethtool -K %s rx off sg off gro off gso off tso off",
ifname);
}
#endif
}
/**
* \brief Set interface flags.
* \param fd Network susbystem file descritor.
* \param ifname Inteface name.
* \param flags Flags to set.
* \return Zero on success.
*/
static int NetmapSetIfaceFlags(int fd, const char *ifname, int flags)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
#ifdef OS_FREEBSD
ifr.ifr_flags = flags & 0xffff;
ifr.ifr_flagshigh = flags >> 16;
#else
ifr.ifr_flags = flags;
#endif
if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
SCLogError(SC_ERR_NETMAP_CREATE,
"Unable to set flags for iface \"%s\": %s",
ifname, strerror(errno));
return -1;
}
return 0;
}
/** \brief get RSS RX-queue count
* \retval rx_rings RSS RX queue count or 1 on error
*/
@ -398,6 +293,8 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver
}
}
(void)GetIfaceOffloading(ifname);
/* not found, create new record */
pdev = SCMalloc(sizeof(*pdev));
if (unlikely(pdev == NULL)) {
@ -419,39 +316,25 @@ static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int ver
}
/* check interface is up */
int if_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (if_fd < 0) {
SCLogError(SC_ERR_NETMAP_CREATE,
"Couldn't create control socket for '%s' interface",
ifname);
goto error_fd;
}
int if_flags = NetmapGetIfaceFlags(if_fd, ifname);
int if_flags = GetIfaceFlags(ifname);
if (if_flags == -1) {
if (verbose) {
SCLogError(SC_ERR_NETMAP_CREATE,
"Can not access to interface '%s'",
ifname);
}
close(if_fd);
goto error_fd;
}
if ((if_flags & IFF_UP) == 0) {
if (verbose) {
SCLogError(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname);
}
close(if_fd);
SCLogWarning(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname);
goto error_fd;
}
/* if needed, try to set iface in promisc mode */
if (promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) {
if_flags |= IFF_PPROMISC;
NetmapSetIfaceFlags(if_fd, ifname, if_flags);
SetIfaceFlags(ifname, if_flags);
}
NetmapCheckOffloading(if_fd, ifname);
close(if_fd);
/* query netmap info */
memset(&nm_req, 0, sizeof(nm_req));
strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name));

@ -510,15 +510,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data)
SCMutexUnlock(&pcap_bpf_compile_lock);
}
/* Making it conditional to Linux even if GetIfaceOffloading return 0
* for non Linux. */
#ifdef HAVE_LINUX_ETHTOOL_H
if (GetIfaceOffloading(pcapconfig->iface) == 1) {
SCLogWarning(SC_ERR_PCAP_CREATE,
"Using Pcap capture with GRO or LRO activated can lead to "
"capture problems.");
}
#endif /* HAVE_LINUX_ETHTOOL_H */
(void)GetIfaceOffloading(pcapconfig->iface);
ptv->datalink = pcap_datalink(ptv->pcap_handle);

@ -324,6 +324,7 @@ const char * SCErrorToString(SCError err)
CASE_CODE (SC_ERR_NETFLOW_LOG_GENERIC);
CASE_CODE (SC_ERR_SMTP_LOG_GENERIC);
CASE_CODE (SC_ERR_SSH_LOG_GENERIC);
CASE_CODE (SC_ERR_NIC_OFFLOADING);
}
return "UNKNOWN_ERROR";

@ -314,6 +314,7 @@ typedef enum {
SC_ERR_NETFLOW_LOG_GENERIC,
SC_ERR_SMTP_LOG_GENERIC,
SC_ERR_SSH_LOG_GENERIC,
SC_ERR_NIC_OFFLOADING,
} SCError;
const char *SCErrorToString(SCError);

@ -137,6 +137,106 @@ int GetIfaceMaxPacketSize(const char *pcap_dev)
return ll_header + mtu;
}
#ifdef SIOCGIFFLAGS
/**
* \brief Get interface flags.
* \param ifname Inteface name.
* \return Interface flags or -1 on error
*/
int GetIfaceFlags(const char *ifname)
{
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
SCLogError(SC_ERR_SYSCALL,
"Unable to get flags for iface \"%s\": %s",
ifname, strerror(errno));
close(fd);
return -1;
}
close(fd);
#ifdef OS_FREEBSD
int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
return flags;
#else
return ifr.ifr_flags;
#endif
}
#endif
#ifdef SIOCSIFFLAGS
/**
* \brief Set interface flags.
* \param ifname Inteface name.
* \param flags Flags to set.
* \return Zero on success.
*/
int SetIfaceFlags(const char *ifname, int flags)
{
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
#ifdef OS_FREEBSD
ifr.ifr_flags = flags & 0xffff;
ifr.ifr_flagshigh = flags >> 16;
#else
ifr.ifr_flags = flags;
#endif
if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
SCLogError(SC_ERR_SYSCALL,
"Unable to set flags for iface \"%s\": %s",
ifname, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
#endif /* SIOCGIFFLAGS */
#ifdef SIOCGIFCAP
int GetIfaceCaps(const char *ifname)
{
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
SCLogError(SC_ERR_SYSCALL,
"Unable to get caps for iface \"%s\": %s",
ifname, strerror(errno));
close(fd);
return -1;
}
close(fd);
return ifr.ifr_curcap;
}
#endif
#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value)
{
@ -204,13 +304,47 @@ static int GetIfaceOffloadingLinux(const char *dev)
}
}
#endif
SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, "
"TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso);
if (ret == 0) {
SCLogInfo("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, "
"TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso);
} else {
SCLogWarning(SC_ERR_NIC_OFFLOADING, "NIC offloading on %s: SG: %s, "
" GRO: %s, LRO: %s, TSO: %s, GSO: %s: "
"ethtool -K %s sg off gro off lro off tso off gso off",
dev, sg, gro, lro, tso, gso, dev);
}
return ret;
}
#endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */
#ifdef SIOCGIFCAP
static int GetIfaceOffloadingBSD(const char *ifname)
{
int ret = 0;
int if_caps = GetIfaceCaps(ifname);
if (if_caps == -1) {
return -1;
}
SCLogDebug("if_caps %X", if_caps);
if (if_caps & IFCAP_RXCSUM) {
SCLogWarning(SC_ERR_NIC_OFFLOADING,
"Using %s with RXCSUM activated can lead to capture "
"problems: ifconfig %s -rxcsum", ifname, ifname);
ret = 1;
}
if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
SCLogWarning(SC_ERR_NIC_OFFLOADING,
"Using %s with TSO, TOE or LRO activated can lead to "
"capture problems: ifconfig %s -tso -toe -lro",
ifname, ifname);
ret = 1;
}
return ret;
}
#endif
/**
* \brief output offloading status of the link
*
@ -227,8 +361,11 @@ int GetIfaceOffloading(const char *dev)
{
#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
return GetIfaceOffloadingLinux(dev);
#endif
#elif defined SIOCGIFCAP
return GetIfaceOffloadingBSD(dev);
#else
return 0;
#endif
}
int GetIfaceRSSQueuesNum(const char *pcap_dev)

@ -25,3 +25,12 @@ int GetIfaceMTU(const char *pcap_dev);
int GetIfaceMaxPacketSize(const char *pcap_dev);
int GetIfaceOffloading(const char *pcap_dev);
int GetIfaceRSSQueuesNum(const char *pcap_dev);
#ifdef SIOCGIFFLAGS
int GetIfaceFlags(const char *ifname);
#endif
#ifdef SIOCSIFFLAGS
int SetIfaceFlags(const char *ifname, int flags);
#endif
#ifdef SIOCGIFCAP
int GetIfaceCaps(const char *ifname);
#endif

Loading…
Cancel
Save