kernel-netlink: Check for offloading support in constructor
This avoids races that could potentially occur when doing the check during SA installation. Signed-off-by: Thomas Egerer <thomas.egerer@secunet.com>
This commit is contained in:
parent
29b4b2e8e2
commit
a605452c03
|
@ -18,6 +18,16 @@ charon.plugins.kernel-netlink.fwmark =
|
||||||
inverts the meaning (i.e. the rule only applies to packets that don't match
|
inverts the meaning (i.e. the rule only applies to packets that don't match
|
||||||
the mark).
|
the mark).
|
||||||
|
|
||||||
|
charon.plugins.kernel-netlink.hw_offload_feature_interface = lo
|
||||||
|
Interface to be used to find hardware offload feature flag on.
|
||||||
|
|
||||||
|
If the kernel supports hardware offloading, the plugin needs to find the
|
||||||
|
feature flag which represents hardware offloading support for network
|
||||||
|
devices. Using the loopback device for this purpose is usually fine, since
|
||||||
|
it should always be present. For rare cases in which the loopback device
|
||||||
|
cannot be used to obtain the appropriate feature flag, this option can
|
||||||
|
be used to specify an alternative interface for offload feature detection.
|
||||||
|
|
||||||
charon.plugins.kernel-netlink.mss = 0
|
charon.plugins.kernel-netlink.mss = 0
|
||||||
MSS to set on installed routes, 0 to disable.
|
MSS to set on installed routes, 0 to disable.
|
||||||
|
|
||||||
|
|
|
@ -1346,40 +1346,35 @@ static bool add_uint32(struct nlmsghdr *hdr, int buflen,
|
||||||
* ETHTOOL_GFEATURES since 2.6.39, so check for the latter */
|
* ETHTOOL_GFEATURES since 2.6.39, so check for the latter */
|
||||||
#ifdef ETHTOOL_GFEATURES
|
#ifdef ETHTOOL_GFEATURES
|
||||||
|
|
||||||
/**
|
|
||||||
* IPsec HW offload state in kernel
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
NL_OFFLOAD_UNKNOWN,
|
|
||||||
NL_OFFLOAD_UNSUPPORTED,
|
|
||||||
NL_OFFLOAD_SUPPORTED
|
|
||||||
} nl_offload_state_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global metadata used for IPsec HW offload
|
* Global metadata used for IPsec HW offload
|
||||||
*/
|
*/
|
||||||
static struct {
|
static struct {
|
||||||
|
/** determined HW offload support */
|
||||||
|
bool supported;
|
||||||
/** bit in feature set */
|
/** bit in feature set */
|
||||||
u_int bit;
|
u_int bit;
|
||||||
/** total number of device feature blocks */
|
/** total number of device feature blocks */
|
||||||
u_int total_blocks;
|
u_int total_blocks;
|
||||||
/** determined HW offload state */
|
|
||||||
nl_offload_state_t state;
|
|
||||||
} netlink_hw_offload;
|
} netlink_hw_offload;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if kernel supports HW offload
|
* Check if kernel supports HW offload and determine feature flag
|
||||||
*/
|
*/
|
||||||
static void netlink_find_offload_feature(const char *ifname, int query_socket)
|
static void netlink_find_offload_feature(const char *ifname)
|
||||||
{
|
{
|
||||||
struct ethtool_sset_info *sset_info;
|
struct ethtool_sset_info *sset_info;
|
||||||
struct ethtool_gstrings *cmd = NULL;
|
struct ethtool_gstrings *cmd = NULL;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
uint32_t sset_len, i;
|
uint32_t sset_len, i;
|
||||||
char *str;
|
char *str;
|
||||||
int err;
|
int err, query_socket;
|
||||||
|
|
||||||
netlink_hw_offload.state = NL_OFFLOAD_UNSUPPORTED;
|
query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
|
||||||
|
if (query_socket < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* determine number of device features */
|
/* determine number of device features */
|
||||||
INIT_EXTRA(sset_info, sizeof(uint32_t),
|
INIT_EXTRA(sset_info, sizeof(uint32_t),
|
||||||
|
@ -1418,9 +1413,9 @@ static void netlink_find_offload_feature(const char *ifname, int query_socket)
|
||||||
{
|
{
|
||||||
if (strneq(str, "esp-hw-offload", ETH_GSTRING_LEN))
|
if (strneq(str, "esp-hw-offload", ETH_GSTRING_LEN))
|
||||||
{
|
{
|
||||||
|
netlink_hw_offload.supported = TRUE;
|
||||||
netlink_hw_offload.bit = i;
|
netlink_hw_offload.bit = i;
|
||||||
netlink_hw_offload.total_blocks = (sset_len + 31) / 32;
|
netlink_hw_offload.total_blocks = (sset_len + 31) / 32;
|
||||||
netlink_hw_offload.state = NL_OFFLOAD_SUPPORTED;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
str += ETH_GSTRING_LEN;
|
str += ETH_GSTRING_LEN;
|
||||||
|
@ -1429,6 +1424,7 @@ static void netlink_find_offload_feature(const char *ifname, int query_socket)
|
||||||
out:
|
out:
|
||||||
free(sset_info);
|
free(sset_info);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
|
close(query_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1443,25 +1439,18 @@ static bool netlink_detect_offload(const char *ifname)
|
||||||
int block;
|
int block;
|
||||||
bool ret = FALSE;
|
bool ret = FALSE;
|
||||||
|
|
||||||
|
if (!netlink_hw_offload.supported)
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "HW offload is not supported by kernel");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
|
query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
|
||||||
if (query_socket < 0)
|
if (query_socket < 0)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* kernel requires a real interface in order to query the kernel-wide
|
|
||||||
* capability, so we do it here on first invocation.
|
|
||||||
*/
|
|
||||||
if (netlink_hw_offload.state == NL_OFFLOAD_UNKNOWN)
|
|
||||||
{
|
|
||||||
netlink_find_offload_feature(ifname, query_socket);
|
|
||||||
}
|
|
||||||
if (netlink_hw_offload.state == NL_OFFLOAD_UNSUPPORTED)
|
|
||||||
{
|
|
||||||
DBG1(DBG_KNL, "HW offload is not supported by kernel");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* feature is supported by kernel, query device features */
|
/* feature is supported by kernel, query device features */
|
||||||
INIT_EXTRA(cmd, sizeof(cmd->features[0]) * netlink_hw_offload.total_blocks,
|
INIT_EXTRA(cmd, sizeof(cmd->features[0]) * netlink_hw_offload.total_blocks,
|
||||||
.cmd = ETHTOOL_GFEATURES,
|
.cmd = ETHTOOL_GFEATURES,
|
||||||
|
@ -1471,31 +1460,31 @@ static bool netlink_detect_offload(const char *ifname)
|
||||||
ifr.ifr_name[IFNAMSIZ-1] = '\0';
|
ifr.ifr_name[IFNAMSIZ-1] = '\0';
|
||||||
ifr.ifr_data = (void*)cmd;
|
ifr.ifr_data = (void*)cmd;
|
||||||
|
|
||||||
if (ioctl(query_socket, SIOCETHTOOL, &ifr))
|
if (!ioctl(query_socket, SIOCETHTOOL, &ifr))
|
||||||
{
|
{
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
block = netlink_hw_offload.bit / 32;
|
block = netlink_hw_offload.bit / 32;
|
||||||
feature_bit = 1U << (netlink_hw_offload.bit % 32);
|
feature_bit = 1U << (netlink_hw_offload.bit % 32);
|
||||||
if (cmd->features[block].active & feature_bit)
|
if (cmd->features[block].active & feature_bit)
|
||||||
{
|
{
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out_free:
|
|
||||||
free(cmd);
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "HW offload is not supported by device");
|
DBG1(DBG_KNL, "HW offload is not supported by device");
|
||||||
}
|
}
|
||||||
out:
|
free(cmd);
|
||||||
close(query_socket);
|
close(query_socket);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
static void netlink_find_offload_feature(const char *ifname)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static bool netlink_detect_offload(const char *ifname)
|
static bool netlink_detect_offload(const char *ifname)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -3698,5 +3687,9 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
||||||
(watcher_cb_t)receive_events, this);
|
(watcher_cb_t)receive_events, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netlink_find_offload_feature(lib->settings->get_str(lib->settings,
|
||||||
|
"%s.hw_offload_feature_interface", "lo",
|
||||||
|
lib->ns));
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue