From: Thomas Egerer Date: Wed, 9 Oct 2019 15:16:29 +0000 (+0200) Subject: kernel-netlink: Check for offloading support in constructor X-Git-Tag: 5.8.2dr2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a605452c038e506a203ca567ffbe8205f5cee786;p=thirdparty%2Fstrongswan.git 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 --- diff --git a/conf/plugins/kernel-netlink.opt b/conf/plugins/kernel-netlink.opt index 0e368ca1ed..1ca5a42ddd 100644 --- a/conf/plugins/kernel-netlink.opt +++ b/conf/plugins/kernel-netlink.opt @@ -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. diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 27bb3792dd..4465d41f3b 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -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,23 +1439,16 @@ static bool netlink_detect_offload(const char *ifname) int block; bool ret = FALSE; - query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); - if (query_socket < 0) + if (!netlink_hw_offload.supported) { + DBG1(DBG_KNL, "HW offload is not supported by kernel"); 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) + query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); + if (query_socket < 0) { - DBG1(DBG_KNL, "HW offload is not supported by kernel"); - goto out; + return FALSE; } /* feature is supported by kernel, query device features */ @@ -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; }