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
|
||||
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
|
||||
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 */
|
||||
#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
|
||||
*/
|
||||
static struct {
|
||||
/** determined HW offload support */
|
||||
bool supported;
|
||||
/** bit in feature set */
|
||||
u_int bit;
|
||||
/** total number of device feature blocks */
|
||||
u_int total_blocks;
|
||||
/** determined HW offload state */
|
||||
nl_offload_state_t state;
|
||||
} 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_gstrings *cmd = NULL;
|
||||
struct ifreq ifr;
|
||||
uint32_t sset_len, i;
|
||||
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 */
|
||||
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))
|
||||
{
|
||||
netlink_hw_offload.supported = TRUE;
|
||||
netlink_hw_offload.bit = i;
|
||||
netlink_hw_offload.total_blocks = (sset_len + 31) / 32;
|
||||
netlink_hw_offload.state = NL_OFFLOAD_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
str += ETH_GSTRING_LEN;
|
||||
|
@ -1429,6 +1424,7 @@ static void netlink_find_offload_feature(const char *ifname, int query_socket)
|
|||
out:
|
||||
free(sset_info);
|
||||
free(cmd);
|
||||
close(query_socket);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1443,25 +1439,18 @@ static bool netlink_detect_offload(const char *ifname)
|
|||
int block;
|
||||
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);
|
||||
if (query_socket < 0)
|
||||
{
|
||||
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 */
|
||||
INIT_EXTRA(cmd, sizeof(cmd->features[0]) * netlink_hw_offload.total_blocks,
|
||||
.cmd = ETHTOOL_GFEATURES,
|
||||
|
@ -1471,31 +1460,31 @@ static bool netlink_detect_offload(const char *ifname)
|
|||
ifr.ifr_name[IFNAMSIZ-1] = '\0';
|
||||
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;
|
||||
feature_bit = 1U << (netlink_hw_offload.bit % 32);
|
||||
if (cmd->features[block].active & feature_bit)
|
||||
{
|
||||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
block = netlink_hw_offload.bit / 32;
|
||||
feature_bit = 1U << (netlink_hw_offload.bit % 32);
|
||||
if (cmd->features[block].active & feature_bit)
|
||||
{
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
out_free:
|
||||
free(cmd);
|
||||
if (!ret)
|
||||
{
|
||||
DBG1(DBG_KNL, "HW offload is not supported by device");
|
||||
}
|
||||
out:
|
||||
free(cmd);
|
||||
close(query_socket);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void netlink_find_offload_feature(const char *ifname)
|
||||
{
|
||||
}
|
||||
|
||||
static bool netlink_detect_offload(const char *ifname)
|
||||
{
|
||||
return FALSE;
|
||||
|
@ -3698,5 +3687,9 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
|||
(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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue