From aad9bd361315b4cad98d9a718903bfab0c4a6ac1 Mon Sep 17 00:00:00 2001 From: Adi Nissim Date: Mon, 12 Mar 2018 16:34:19 +0200 Subject: [PATCH 1/4] ipsec-types: Create new enum hw_offload_t Add the new enum in order to add HW offload auto mode. Signed-off-by: Adi Nissim Reviewed-by: Aviv Heller --- src/libstrongswan/ipsec/ipsec_types.c | 6 ++++++ src/libstrongswan/ipsec/ipsec_types.h | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/libstrongswan/ipsec/ipsec_types.c b/src/libstrongswan/ipsec/ipsec_types.c index c992eb5ad..0e9407108 100644 --- a/src/libstrongswan/ipsec/ipsec_types.c +++ b/src/libstrongswan/ipsec/ipsec_types.c @@ -37,6 +37,12 @@ ENUM(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_LZJH, "IPCOMP_LZJH" ); +ENUM(hw_offload_names, HW_OFFLOAD_NO, HW_OFFLOAD_AUTO, + "no", + "yes", + "auto", +); + /* * See header */ diff --git a/src/libstrongswan/ipsec/ipsec_types.h b/src/libstrongswan/ipsec/ipsec_types.h index 1db78ba6f..4324ea40a 100644 --- a/src/libstrongswan/ipsec/ipsec_types.h +++ b/src/libstrongswan/ipsec/ipsec_types.h @@ -26,6 +26,7 @@ typedef enum policy_dir_t policy_dir_t; typedef enum policy_type_t policy_type_t; typedef enum policy_priority_t policy_priority_t; typedef enum ipcomp_transform_t ipcomp_transform_t; +typedef enum hw_offload_t hw_offload_t; typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t; typedef struct lifetime_cfg_t lifetime_cfg_t; typedef struct mark_t mark_t; @@ -116,6 +117,20 @@ enum ipcomp_transform_t { */ extern enum_name_t *ipcomp_transform_names; +/** + * HW offload mode options + */ +enum hw_offload_t { + HW_OFFLOAD_NO = 0, + HW_OFFLOAD_YES = 1, + HW_OFFLOAD_AUTO = 2, +}; + +/** + * enum names for hw_offload_t. + */ +extern enum_name_t *hw_offload_names; + /** * This struct contains details about IPsec SA(s) tied to a policy. */ From 338cc5812eb7a9bb2550ea2420f6d9dbb017fb8b Mon Sep 17 00:00:00 2001 From: Adi Nissim Date: Mon, 12 Mar 2018 16:34:20 +0200 Subject: [PATCH 2/4] kernel-netlink: Add new automatic hw_offload mode Until now there were 2 hw_offload modes: no/yes * hw_offload = no : Configure the SA without HW offload. * hw_offload = yes : Configure the SA with HW offload. In this case, if the device does not support offloading, SA creation will fail. This commit introduces a new mode: hw_offload = auto ---------------------------------------------------- If the device and kernel support HW offload, configure the SA with HW offload, but do not fail SA creation otherwise. Signed-off-by: Adi Nissim Reviewed-by: Aviv Heller --- .../kernel_netlink/kernel_netlink_ipsec.c | 285 ++++++++++++++++-- 1 file changed, 262 insertions(+), 23 deletions(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 4e79dfced..eabf20840 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -17,16 +17,40 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ +/* + * Copyright (C) 2018 Mellanox Technologies. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #define _GNU_SOURCE #include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include @@ -236,6 +260,21 @@ static kernel_algorithm_t compression_algs[] = { {IPCOMP_LZJH, "lzjh" }, }; +/** + * IPsec offload + */ +enum nic_offload_state { + NIC_OFFLOAD_UNKNOWN, + NIC_OFFLOAD_UNSUPPORTED, + NIC_OFFLOAD_SUPPORTED +}; + +static struct { + unsigned int bit; + unsigned int total_blocks; + enum nic_offload_state state; +} netlink_esp_hw_offload; + /** * Look up a kernel algorithm name and its key size */ @@ -1290,6 +1329,224 @@ static bool add_mark(struct nlmsghdr *hdr, int buflen, mark_t mark) return TRUE; } +/** + * check if kernel supported HW offload + */ +static void netlink_find_offload_feature(const char *ifname, int fd_for_socket) +{ + struct ethtool_sset_info *sset_info = NULL; + struct ethtool_gstrings *cmd = NULL; + struct ifreq ifr; + uint32_t sset_len, i; + char *str; + int err; + + netlink_esp_hw_offload.state = NIC_OFFLOAD_UNSUPPORTED; + + /* Determine number of device-features */ + sset_info = malloc(sizeof(*sset_info)); + if (sset_info == NULL) + { + goto out; + } + memset(sset_info, 0, sizeof(*sset_info)); + + sset_info->cmd = ETHTOOL_GSSET_INFO; + sset_info->sset_mask = 1ULL << ETH_SS_FEATURES; + strcpy(ifr.ifr_name, ifname); + + ifr.ifr_data = (void *)sset_info; + + err = ioctl(fd_for_socket, SIOCETHTOOL, &ifr); + if (err != 0) + { + goto out; + } + + if (sset_info->sset_mask != 1ULL << ETH_SS_FEATURES) + { + goto out; + } + sset_len = sset_info->data[0]; + + /* Retrieve names of device-features */ + cmd = malloc(sizeof(*cmd) + ETH_GSTRING_LEN * sset_len); + if (cmd == NULL) + { + goto out; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->cmd = ETHTOOL_GSTRINGS; + cmd->string_set = ETH_SS_FEATURES; + strcpy(ifr.ifr_name, ifname); + ifr.ifr_data = (void *)cmd; + err = ioctl(fd_for_socket, SIOCETHTOOL, &ifr); + if (err) + { + goto out; + } + + /* Look for the ESP_HW feature bit */ + str = (char *)cmd->data; + for (i = 0; i < cmd->len; i++) + { + if (strneq(str, "esp-hw-offload", ETH_GSTRING_LEN) == 1) + break; + str += ETH_GSTRING_LEN; + } + if (i >= cmd->len) + { + goto out; + } + + netlink_esp_hw_offload.bit = i; + netlink_esp_hw_offload.total_blocks = (sset_len + 31) / 32; + netlink_esp_hw_offload.state = NIC_OFFLOAD_SUPPORTED; + +out: + if (sset_info != NULL) + { + free(sset_info); + } + if (cmd != NULL) + { + free(cmd); + } +} + +/** + * Check if interface supported HW offload + */ +static bool netlink_detect_offload(const char *ifname) +{ + struct ethtool_gfeatures *cmd; + uint32_t feature_bit; + struct ifreq ifr; + bool ret = FALSE; + int nl_send_fd; + int block; + + nl_send_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); + + if (nl_send_fd < 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_esp_hw_offload.state == NIC_OFFLOAD_UNKNOWN) + { + netlink_find_offload_feature(ifname, nl_send_fd); + } + + if (netlink_esp_hw_offload.state == NIC_OFFLOAD_UNSUPPORTED) + { + DBG1(DBG_KNL, "HW offload is not supported by kernel"); + goto out; + } + + /* Feature is supported by kernel. Query device features */ + cmd = malloc(sizeof(cmd->features[0]) * + netlink_esp_hw_offload.total_blocks); + if (cmd == NULL) + { + goto out; + } + + strcpy(ifr.ifr_name, ifname); + + ifr.ifr_data = (void *)cmd; + cmd->cmd = ETHTOOL_GFEATURES; + cmd->size = netlink_esp_hw_offload.total_blocks; + + if (ioctl(nl_send_fd, SIOCETHTOOL, &ifr)) + { + goto out_free; + } + + block = netlink_esp_hw_offload.bit / 32; + feature_bit = 1U << (netlink_esp_hw_offload.bit % 32); + if (cmd->features[block].active & feature_bit) + { + ret = TRUE; + } + +out_free: + free(cmd); + if (ret == FALSE) + { + DBG1(DBG_KNL, "HW offload is not supported by device"); + } +out: + close(nl_send_fd); + return ret; +} + +/** + * There are 3 configuration options: + * 1. HW_OFFLOAD_NO : Do not configure HW offload.. + * 2. HW_OFFLOAD_YES : Configure HW offload. + * Fail SA addition if offload is not supported. + * 3. HW_OFFLOAD_AUTO : Configure HW offload if supported by the kernel + * and device. + * Do not fail SA addition otherwise. + */ +static bool config_hw_offload(kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data, struct nlmsghdr *hdr, int buflen) +{ + bool cfg_hw_offload_is_yes = (data->hw_offload == HW_OFFLOAD_YES); + host_t *local = data->inbound ? id->dst : id->src; + struct xfrm_user_offload *offload; + bool hw_offload_support; + bool ret = FALSE; + char *ifname; + + /* Do Ipsec configuration without offload */ + if (data->hw_offload == HW_OFFLOAD_NO) + { + return TRUE; + } + + if (!charon->kernel->get_interface(charon->kernel, local, &ifname)) + { + return !cfg_hw_offload_is_yes; + } + + /* Check if interface supports hw_offload */ + hw_offload_support = netlink_detect_offload(ifname); + + if (!hw_offload_support) + { + ret = !cfg_hw_offload_is_yes; + goto out; + } + + /* Activate HW offload */ + offload = netlink_reserve(hdr, buflen, + XFRMA_OFFLOAD_DEV, sizeof(*offload)); + if (!offload) + { + ret = !cfg_hw_offload_is_yes; + goto out; + } + offload->ifindex = if_nametoindex(ifname); + if (local->get_family(local) == AF_INET6) + { + offload->flags |= XFRM_OFFLOAD_IPV6; + } + offload->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0; + + ret = TRUE; + +out: + free(ifname); + return ret; +} + METHOD(kernel_ipsec_t, add_sa, status_t, private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id, kernel_ipsec_add_sa_t *data) @@ -1650,30 +1907,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, data->replay_window); sa->replay_window = data->replay_window; } - if (data->hw_offload) + + DBG2(DBG_KNL, " HW offload mode = %N", hw_offload_names, data->hw_offload); + if (!config_hw_offload(id, data, hdr, sizeof(request))) { - host_t *local = data->inbound ? id->dst : id->src; - char *ifname; - - if (charon->kernel->get_interface(charon->kernel, local, &ifname)) - { - struct xfrm_user_offload *offload; - - offload = netlink_reserve(hdr, sizeof(request), - XFRMA_OFFLOAD_DEV, sizeof(*offload)); - if (!offload) - { - free(ifname); - goto failed; - } - offload->ifindex = if_nametoindex(ifname); - if (local->get_family(local) == AF_INET6) - { - offload->flags |= XFRM_OFFLOAD_IPV6; - } - offload->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0; - free(ifname); - } + DBG1(DBG_KNL, "failed to configure HW offload"); + goto failed; } } From ee26f7156fe1b54e79cf5b3bf9585edd397abd18 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 16 Mar 2018 19:34:43 +0100 Subject: [PATCH 3/4] kernel-netlink: Cleanup and fix some HW offload code issues Besides some style issues there were some incorrect allocations for ethtool requests. --- .../kernel_netlink/kernel_netlink_ipsec.c | 190 ++++++++---------- 1 file changed, 81 insertions(+), 109 deletions(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index eabf20840..69605d5f4 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2017 Tobias Brunner + * Copyright (C) 2006-2018 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2008-2016 Andreas Steffen * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser @@ -261,19 +261,25 @@ static kernel_algorithm_t compression_algs[] = { }; /** - * IPsec offload + * IPsec HW offload state in kernel */ -enum nic_offload_state { - NIC_OFFLOAD_UNKNOWN, - NIC_OFFLOAD_UNSUPPORTED, - NIC_OFFLOAD_SUPPORTED -}; +typedef enum { + NL_OFFLOAD_UNKNOWN, + NL_OFFLOAD_UNSUPPORTED, + NL_OFFLOAD_SUPPORTED +} nl_offload_state_t; +/** + * Global metadata used for IPsec HW offload + */ static struct { - unsigned int bit; - unsigned int total_blocks; - enum nic_offload_state state; -} netlink_esp_hw_offload; + /** 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; /** * Look up a kernel algorithm name and its key size @@ -1330,89 +1336,65 @@ static bool add_mark(struct nlmsghdr *hdr, int buflen, mark_t mark) } /** - * check if kernel supported HW offload + * Check if kernel supports HW offload */ -static void netlink_find_offload_feature(const char *ifname, int fd_for_socket) +static void netlink_find_offload_feature(const char *ifname, int query_socket) { - struct ethtool_sset_info *sset_info = NULL; + struct ethtool_sset_info *sset_info; struct ethtool_gstrings *cmd = NULL; struct ifreq ifr; uint32_t sset_len, i; char *str; int err; - netlink_esp_hw_offload.state = NIC_OFFLOAD_UNSUPPORTED; + netlink_hw_offload.state = NL_OFFLOAD_UNSUPPORTED; - /* Determine number of device-features */ - sset_info = malloc(sizeof(*sset_info)); - if (sset_info == NULL) - { - goto out; - } - memset(sset_info, 0, sizeof(*sset_info)); - - sset_info->cmd = ETHTOOL_GSSET_INFO; - sset_info->sset_mask = 1ULL << ETH_SS_FEATURES; + /* determine number of device features */ + INIT_EXTRA(sset_info, sizeof(uint32_t), + .cmd = ETHTOOL_GSSET_INFO, + .sset_mask = 1ULL << ETH_SS_FEATURES, + ); strcpy(ifr.ifr_name, ifname); + ifr.ifr_data = (void*)sset_info; - ifr.ifr_data = (void *)sset_info; - - err = ioctl(fd_for_socket, SIOCETHTOOL, &ifr); - if (err != 0) - { - goto out; - } - - if (sset_info->sset_mask != 1ULL << ETH_SS_FEATURES) + err = ioctl(query_socket, SIOCETHTOOL, &ifr); + if (err || sset_info->sset_mask != 1ULL << ETH_SS_FEATURES) { goto out; } sset_len = sset_info->data[0]; - /* Retrieve names of device-features */ - cmd = malloc(sizeof(*cmd) + ETH_GSTRING_LEN * sset_len); - if (cmd == NULL) - { - goto out; - } - - memset(cmd, 0, sizeof(*cmd)); - cmd->cmd = ETHTOOL_GSTRINGS; - cmd->string_set = ETH_SS_FEATURES; + /* retrieve names of device features */ + INIT_EXTRA(cmd, ETH_GSTRING_LEN * sset_len, + .cmd = ETHTOOL_GSTRINGS, + .string_set = ETH_SS_FEATURES, + ); strcpy(ifr.ifr_name, ifname); - ifr.ifr_data = (void *)cmd; - err = ioctl(fd_for_socket, SIOCETHTOOL, &ifr); + ifr.ifr_data = (void*)cmd; + + err = ioctl(query_socket, SIOCETHTOOL, &ifr); if (err) { goto out; } - /* Look for the ESP_HW feature bit */ - str = (char *)cmd->data; + /* look for the ESP_HW feature bit */ + str = (char*)cmd->data; for (i = 0; i < cmd->len; i++) { - if (strneq(str, "esp-hw-offload", ETH_GSTRING_LEN) == 1) + if (strneq(str, "esp-hw-offload", ETH_GSTRING_LEN)) + { + 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; } - if (i >= cmd->len) - { - goto out; - } - - netlink_esp_hw_offload.bit = i; - netlink_esp_hw_offload.total_blocks = (sset_len + 31) / 32; - netlink_esp_hw_offload.state = NIC_OFFLOAD_SUPPORTED; out: - if (sset_info != NULL) - { - free(sset_info); - } - if (cmd != NULL) - { - free(cmd); - } + free(sset_info); + free(cmd); } /** @@ -1423,53 +1405,44 @@ static bool netlink_detect_offload(const char *ifname) struct ethtool_gfeatures *cmd; uint32_t feature_bit; struct ifreq ifr; - bool ret = FALSE; - int nl_send_fd; + int query_socket; int block; + bool ret = FALSE; - nl_send_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); - - if (nl_send_fd < 0) + 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 + /* kernel requires a real interface in order to query the kernel-wide * capability, so we do it here on first invocation. */ - if (netlink_esp_hw_offload.state == NIC_OFFLOAD_UNKNOWN) + if (netlink_hw_offload.state == NL_OFFLOAD_UNKNOWN) { - netlink_find_offload_feature(ifname, nl_send_fd); + netlink_find_offload_feature(ifname, query_socket); } - - if (netlink_esp_hw_offload.state == NIC_OFFLOAD_UNSUPPORTED) + 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 */ - cmd = malloc(sizeof(cmd->features[0]) * - netlink_esp_hw_offload.total_blocks); - if (cmd == NULL) - { - 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, + .size = netlink_hw_offload.total_blocks, + ); strcpy(ifr.ifr_name, ifname); + ifr.ifr_data = (void*)cmd; - ifr.ifr_data = (void *)cmd; - cmd->cmd = ETHTOOL_GFEATURES; - cmd->size = netlink_esp_hw_offload.total_blocks; - - if (ioctl(nl_send_fd, SIOCETHTOOL, &ifr)) + if (ioctl(query_socket, SIOCETHTOOL, &ifr)) { goto out_free; } - block = netlink_esp_hw_offload.bit / 32; - feature_bit = 1U << (netlink_esp_hw_offload.bit % 32); + block = netlink_hw_offload.bit / 32; + feature_bit = 1U << (netlink_hw_offload.bit % 32); if (cmd->features[block].active & feature_bit) { ret = TRUE; @@ -1477,18 +1450,18 @@ static bool netlink_detect_offload(const char *ifname) out_free: free(cmd); - if (ret == FALSE) + if (!ret) { DBG1(DBG_KNL, "HW offload is not supported by device"); } out: - close(nl_send_fd); + close(query_socket); return ret; } /** - * There are 3 configuration options: - * 1. HW_OFFLOAD_NO : Do not configure HW offload.. + * There are 3 HW offload configuration values: + * 1. HW_OFFLOAD_NO : Do not configure HW offload. * 2. HW_OFFLOAD_YES : Configure HW offload. * Fail SA addition if offload is not supported. * 3. HW_OFFLOAD_AUTO : Configure HW offload if supported by the kernel @@ -1496,41 +1469,40 @@ out: * Do not fail SA addition otherwise. */ static bool config_hw_offload(kernel_ipsec_sa_id_t *id, - kernel_ipsec_add_sa_t *data, struct nlmsghdr *hdr, int buflen) + kernel_ipsec_add_sa_t *data, struct nlmsghdr *hdr, + int buflen) { - bool cfg_hw_offload_is_yes = (data->hw_offload == HW_OFFLOAD_YES); host_t *local = data->inbound ? id->dst : id->src; struct xfrm_user_offload *offload; - bool hw_offload_support; - bool ret = FALSE; + bool hw_offload_yes, ret = FALSE; char *ifname; - /* Do Ipsec configuration without offload */ + /* do Ipsec configuration without offload */ if (data->hw_offload == HW_OFFLOAD_NO) { return TRUE; } + hw_offload_yes = (data->hw_offload == HW_OFFLOAD_YES); + if (!charon->kernel->get_interface(charon->kernel, local, &ifname)) { - return !cfg_hw_offload_is_yes; + return !hw_offload_yes; } - /* Check if interface supports hw_offload */ - hw_offload_support = netlink_detect_offload(ifname); - - if (!hw_offload_support) + /* check if interface supports hw_offload */ + if (!netlink_detect_offload(ifname)) { - ret = !cfg_hw_offload_is_yes; + ret = !hw_offload_yes; goto out; } - /* Activate HW offload */ + /* activate HW offload */ offload = netlink_reserve(hdr, buflen, XFRMA_OFFLOAD_DEV, sizeof(*offload)); if (!offload) { - ret = !cfg_hw_offload_is_yes; + ret = !hw_offload_yes; goto out; } offload->ifindex = if_nametoindex(ifname); @@ -1908,7 +1880,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->replay_window = data->replay_window; } - DBG2(DBG_KNL, " HW offload mode = %N", hw_offload_names, data->hw_offload); + DBG2(DBG_KNL, " HW offload: %N", hw_offload_names, data->hw_offload); if (!config_hw_offload(id, data, hdr, sizeof(request))) { DBG1(DBG_KNL, "failed to configure HW offload"); From 8ced1570abe6dadd5b2b1ccbf0c4ca19c81f63df Mon Sep 17 00:00:00 2001 From: Adi Nissim Date: Mon, 12 Mar 2018 16:34:21 +0200 Subject: [PATCH 4/4] child-cfg: Make HW offload auto mode configurable Until now the configuration available to user for HW offload were: hw_offload = no hw_offload = yes With this commit users will be able to configure auto mode using: hw_offload = auto Signed-off-by: Adi Nissim Reviewed-by: Aviv Heller --- src/libcharon/config/child_cfg.c | 13 ++++++++++ src/libcharon/config/child_cfg.h | 16 ++++++++---- src/libcharon/kernel/kernel_ipsec.h | 4 +-- src/libcharon/plugins/vici/vici_config.c | 33 +++++++++++++++++------- src/libcharon/sa/child_sa.c | 2 +- 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 3d110e9a2..bc417f936 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -142,6 +142,11 @@ struct private_child_cfg_t { * anti-replay window size */ uint32_t replay_window; + + /** + * HW offload mode + */ + hw_offload_t hw_offload; }; METHOD(child_cfg_t, get_name, char*, @@ -467,6 +472,12 @@ METHOD(child_cfg_t, get_start_action, action_t, return this->start_action; } +METHOD(child_cfg_t, get_hw_offload, hw_offload_t, + private_child_cfg_t *this) +{ + return this->hw_offload; +} + METHOD(child_cfg_t, get_dpd_action, action_t, private_child_cfg_t *this) { @@ -652,6 +663,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .equals = _equals, .get_ref = _get_ref, .destroy = _destroy, + .get_hw_offload = _get_hw_offload, }, .name = strdup(name), .options = data->options, @@ -674,6 +686,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .other_ts = linked_list_create(), .replay_window = lib->settings->get_int(lib->settings, "%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns), + .hw_offload = data->hw_offload, ); return &this->public; diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index e2834fa8f..d566da3ec 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -182,6 +182,13 @@ struct child_cfg_t { */ action_t (*get_dpd_action) (child_cfg_t *this); + /** + * Get the HW offload mode to use for the CHILD_SA. + * + * @return hw offload mode + */ + hw_offload_t (*get_hw_offload) (child_cfg_t *this); + /** * Action to take if CHILD_SA gets closed. * @@ -305,14 +312,11 @@ enum child_cfg_option_t { /** Install outbound FWD IPsec policies to bypass drop policies */ OPT_FWD_OUT_POLICIES = (1<<4), - /** Enable hardware offload, if supported by the IPsec backend */ - OPT_HW_OFFLOAD = (1<<5), - /** Force 96-bit truncation for SHA-256 */ - OPT_SHA256_96 = (1<<6), + OPT_SHA256_96 = (1<<5), /** Set mark on inbound SAs */ - OPT_MARK_IN_SA = (1<<7), + OPT_MARK_IN_SA = (1<<6), }; /** @@ -347,6 +351,8 @@ struct child_cfg_create_t { action_t close_action; /** updown script to execute on up/down event (cloned) */ char *updown; + /** HW offload mode */ + hw_offload_t hw_offload; }; /** diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index b75304031..94b9c284b 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -91,8 +91,8 @@ struct kernel_ipsec_add_sa_t { uint16_t cpi; /** TRUE to enable UDP encapsulation for NAT traversal */ bool encap; - /** TRUE to enable hardware offloading if available */ - bool hw_offload; + /** no (disabled), yes (enabled), auto (enabled if supported) */ + hw_offload_t hw_offload; /** TRUE to use Extended Sequence Numbers */ bool esn; /** TRUE if initiator of the exchange creating the SA */ diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index c95d8c8be..5668b9209 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -533,7 +533,7 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " proposals = %#P", data->proposals); DBG2(DBG_CFG, " local_ts = %#R", data->local_ts); DBG2(DBG_CFG, " remote_ts = %#R", data->remote_ts); - DBG2(DBG_CFG, " hw_offload = %u", has_opt(OPT_HW_OFFLOAD)); + DBG2(DBG_CFG, " hw_offload = %N", hw_offload_names, cfg->hw_offload); DBG2(DBG_CFG, " sha256_96 = %u", has_opt(OPT_SHA256_96)); } @@ -892,14 +892,6 @@ CALLBACK(parse_opt_ipcomp, bool, return parse_option(out, OPT_IPCOMP, v); } -/** - * Parse OPT_HW_OFFLOAD option - */ -CALLBACK(parse_opt_hw_offl, bool, - child_cfg_option_t *out, chunk_t v) -{ - return parse_option(out, OPT_HW_OFFLOAD, v); -} /** * Parse OPT_SHA256_96 option @@ -943,6 +935,27 @@ CALLBACK(parse_action, bool, return FALSE; } +/** + * Parse an hw_offload_t + */ +CALLBACK(parse_hw_offload, bool, + action_t *out, chunk_t v) +{ + enum_map_t map[] = { + { "no", HW_OFFLOAD_NO }, + { "yes", HW_OFFLOAD_YES }, + { "auto", HW_OFFLOAD_AUTO }, + }; + int d; + + if (parse_map(map, countof(map), &d, v)) + { + *out = d; + return TRUE; + } + return FALSE; +} + /** * Parse a uint32_t with the given base */ @@ -1578,7 +1591,7 @@ CALLBACK(child_kv, bool, { "tfc_padding", parse_tfc, &child->cfg.tfc }, { "priority", parse_uint32, &child->cfg.priority }, { "interface", parse_string, &child->cfg.interface }, - { "hw_offload", parse_opt_hw_offl, &child->cfg.options }, + { "hw_offload", parse_hw_offload, &child->cfg.hw_offload }, { "sha256_96", parse_opt_sha256_96,&child->cfg.options }, }; diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index cca97ea80..52903563c 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -888,7 +888,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr, .ipcomp = this->ipcomp, .cpi = cpi, .encap = this->encap, - .hw_offload = this->config->has_option(this->config, OPT_HW_OFFLOAD), + .hw_offload = this->config->get_hw_offload(this->config), .esn = esn, .initiator = initiator, .inbound = inbound,