[Swan-dev] [PATCH libreswan] pluto: Rework nic offload detection code

avivh at mellanox.com avivh at mellanox.com
Tue Oct 31 14:36:12 UTC 2017


From: Aviv Heller <avivh at mellanox.com>

Signed-off-by: Aviv Heller <avivh at mellanox.com>
---
 programs/pluto/kernel_netlink.c | 141 +++++++++++++++++++++++-----------------
 1 file changed, 81 insertions(+), 60 deletions(-)

diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
index 199dc47..fd98d40 100644
--- a/programs/pluto/kernel_netlink.c
+++ b/programs/pluto/kernel_netlink.c
@@ -97,9 +97,17 @@ static int netlinkfd = NULL_FD;
 static int netlink_bcast_fd = NULL_FD;
 
 #ifdef USE_NIC_OFFLOAD
-#define NIC_OFFLOAD_UNKNOWN (-2)
-#define NIC_OFFLOAD_UNSUPPORTED (-1)
-static int netlink_esp_hw_offload = NIC_OFFLOAD_UNKNOWN;
+enum nic_offload_state {
+	NIC_OFFLOAD_UNKNOWN = 0,
+	NIC_OFFLOAD_UNSUPPORTED,
+	NIC_OFFLOAD_SUPPORTED,
+};
+
+static struct {
+	unsigned int bit;
+	unsigned int total_blocks;
+	enum nic_offload_state state;
+} netlink_esp_hw_offload;
 #endif
 
 #define NE(x) { x, #x }	/* Name Entry -- shorthand for sparse_names */
@@ -856,85 +864,98 @@ static bool netlink_raw_eroute(const ip_address *this_host,
 #ifdef USE_NIC_OFFLOAD
 static void netlink_find_offload_feature(const char *ifname)
 {
-	netlink_esp_hw_offload = NIC_OFFLOAD_UNSUPPORTED;
-
-	/*
-	 * Determine number of device-features.
-	 * Only one set queried so .data needs only one element
-	 * See <linux/ethtool.h>
-	 */
-	struct ethtool_sset_info *sset_info = 
-		alloc_bytes(sizeof(*sset_info) + 1 * sizeof(sset_info->data[0]),
-			"ethtool_sset_info");
-	sset_info->cmd = ETHTOOL_GSSET_INFO;
-	sset_info->sset_mask = ((__u64)1) << ETH_SS_FEATURES;
-
+	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 = alloc_bytes(sizeof(*sset_info) + sizeof(sset_info->data[0]), "ethtool_sset_info");
+	sset_info->cmd = ETHTOOL_GSSET_INFO;
+	sset_info->sset_mask = 1ULL << ETH_SS_FEATURES;
 	jam_str(ifr.ifr_name, sizeof(ifr.ifr_name), ifname);
 	ifr.ifr_data = (void *)sset_info;
-	if (ioctl(netlinkfd, SIOCETHTOOL, &ifr) == 0 &&
-	    sset_info->sset_mask == ((__u64)1) << ETH_SS_FEATURES)
-	{
-		/* Retrieve names of device-features */
-		uint32_t sset_len = sset_info->data[0];
-
-		struct ethtool_gstrings *cmd =
-			alloc_bytes(sizeof(*cmd) + ETH_GSTRING_LEN * sset_len,
-				"ethtool_gstrings");
-		cmd->cmd = ETHTOOL_GSTRINGS;
-		cmd->string_set = ETH_SS_FEATURES;
-		jam_str(ifr.ifr_name, sizeof(ifr.ifr_name), ifname);
-		ifr.ifr_data = (void *)cmd;
-		if (ioctl(netlinkfd, SIOCETHTOOL, &ifr) == 0) {
-			/* Look for the ESP_HW feature bit */
-			char *str = (char *)cmd->data;
-			for (uint32_t i = 0; i < cmd->len; i++) {
-				if (strneq(str, "esp-hw-offload", ETH_GSTRING_LEN)) {
-					netlink_esp_hw_offload = i;
-					break;
-				}
-				str += ETH_GSTRING_LEN;
-			}
-		}
-		pfree(cmd);
+	err = ioctl(netlinkfd, 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 = alloc_bytes(sizeof(*cmd) + ETH_GSTRING_LEN * sset_len, "ethtool_gstrings");
+	cmd->cmd = ETHTOOL_GSTRINGS;
+	cmd->string_set = ETH_SS_FEATURES;
+	jam_str(ifr.ifr_name, sizeof(ifr.ifr_name), ifname);
+	ifr.ifr_data = (void *)cmd;
+	err = ioctl(netlinkfd, 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:
 	pfree(sset_info);
+
+	if (cmd != NULL)
+		pfree(cmd);
 }
 
 static bool netlink_detect_offload(const char *ifname)
 {
+	struct ethtool_gfeatures *cmd;
+	uint32_t feature_bit;
+	struct ifreq ifr;
+	bool ret = false;
+	int block;
+
 	/*
 	 * Kernel requires a real interface in order to query the kernel-wide
-	 * capability, so we delay until our first invocation.
+	 * capability, so we do it here on first invocation
 	 */
-	if (netlink_esp_hw_offload == NIC_OFFLOAD_UNKNOWN)
+	if (netlink_esp_hw_offload.state == NIC_OFFLOAD_UNKNOWN)
 		netlink_find_offload_feature(ifname);
 
-	if (netlink_esp_hw_offload == NIC_OFFLOAD_UNSUPPORTED)
-		return FALSE;
-
-	/* Feature is supported by kernel. Query device feature. */
-	passert(netlink_esp_hw_offload >= 0);	/* it's a bit number */
-
-	unsigned block = netlink_esp_hw_offload / 32;
-	uint32_t feature_bit = ((uint32_t) 1) << (netlink_esp_hw_offload % 32);
+	if (netlink_esp_hw_offload.state == NIC_OFFLOAD_UNSUPPORTED)
+		return false;
 
-	struct ethtool_gfeatures *cmd =
-		alloc_bytes(sizeof(*cmd) + sizeof(cmd->features[0]) * (block+1),
-			"ethtool_gfeatures");
-	struct ifreq ifr;
+	/* Feature is supported by kernel. Query device features */
+	cmd = alloc_bytes(sizeof(*cmd) + sizeof(cmd->features[0]) *
+			  netlink_esp_hw_offload.total_blocks,
+			  "ethtool_gfeatures");
 	jam_str(ifr.ifr_name, sizeof(ifr.ifr_name), ifname);
 	ifr.ifr_data = (void *)cmd;
 	cmd->cmd = ETHTOOL_GFEATURES;
-	cmd->size = block + 1;
+	cmd->size = netlink_esp_hw_offload.total_blocks;
+	if (ioctl(netlinkfd, SIOCETHTOOL, &ifr))
+		goto out;
 
-	/* ??? something is very wrong if this ioctl fails */
-	bool ret = ioctl(netlinkfd, SIOCETHTOOL, &ifr) == 0 &&
-		(cmd->features[block].active & feature_bit) != 0;
+	block = netlink_esp_hw_offload.bit / 32;
+	feature_bit = 1U << (netlink_esp_hw_offload.bit % 32);
+	if (!(cmd->features[block].active & feature_bit))
+		goto out;
 
-	pfree(cmd);
+	ret = true;
 
+out:
+	pfree(cmd);
 	return ret;
 }
 #endif /* USE_NIC_OFFLOAD */
-- 
1.8.3.1



More information about the Swan-dev mailing list