[libvirt] [PATCHv2] nodedev: Fix gfeature size to be according to running kernel

Moshe Levi moshele at mellanox.com
Thu Aug 13 10:23:32 UTC 2015


This patch add virNetDevGetGFeaturesSize to get the supported
gfeature size from the kernel
---
 src/util/virnetdev.c |   79 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 71 insertions(+), 8 deletions(-)

diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 2f3690e..582efda 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -90,7 +90,8 @@ VIR_LOG_INIT("util.netdev");
 #define RESOURCE_FILE_LEN 4096
 #if HAVE_DECL_ETHTOOL_GFEATURES
 # define TX_UDP_TNL 25
-# define GFEATURES_SIZE 2
+# define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+# define FEATURE_BITS_TO_BLOCKS(n_bits)      DIV_ROUND_UP(n_bits, 32U)
 # define FEATURE_WORD(blocks, index, field)  ((blocks)[(index) / 32U].field)
 # define FEATURE_FIELD_FLAG(index)      (1U << (index) % 32U)
 # define FEATURE_BIT_IS_SET(blocks, index, field)        \
@@ -3110,6 +3111,59 @@ virNetDevGFeatureAvailable(const char *ifname, struct ethtool_gfeatures *cmd)
         ret = FEATURE_BIT_IS_SET(cmd->features, TX_UDP_TNL, active);
     return ret;
 }
+
+
+/**
+ * virNetDevGetGFeaturesSize
+ * This function return the number of gfeatures supported in
+ * the kernel
+ *
+ * @ifname: name of the interface
+ *
+ * Returns gfeature size on success, 0 not supported and -1 on failure.
+ */
+static int
+ virNetDevGetGFeaturesSize(const char *ifname)
+{
+    struct {
+        struct ethtool_sset_info hdr;
+        uint32_t buf[1];
+    } sset_info;
+    struct ethtool_gstrings *strings;
+    uint32_t size = 0;
+    int ret = -1;
+
+    sset_info.hdr.cmd = ETHTOOL_GSSET_INFO;
+    sset_info.hdr.reserved = 0;
+    sset_info.hdr.sset_mask = 1ULL << ETH_SS_FEATURES;
+
+    if (virNetDevSendEthtoolIoctl(ifname, &sset_info) == -1)
+        return ret;
+    size = sset_info.hdr.sset_mask ? sset_info.hdr.data[0] : 0;
+    if (VIR_ALLOC_VAR(strings, struct ethtool_gstrings, sizeof(*strings) + size * ETH_GSTRING_LEN))
+        return ret;
+
+    strings->cmd = ETHTOOL_GSTRINGS;
+    strings->string_set = ETH_SS_FEATURES;
+    strings->len = size;
+    if (size != 0 && virNetDevSendEthtoolIoctl(ifname, strings) == -1) {
+        if (errno == EOPNOTSUPP || errno == EINVAL || errno == EPERM) {
+            ret = 0;
+            size = 0;
+        }
+        goto cleanup;
+    }
+
+    ret = 0;
+    size = FEATURE_BITS_TO_BLOCKS(size);
+
+ cleanup:
+    VIR_FREE(strings);
+    if (ret != -1)
+        ret = size;
+    return ret;
+}
+
 # endif
 
 
@@ -3131,6 +3185,7 @@ virNetDevGetFeatures(const char *ifname,
     struct ethtool_value cmd = { 0 };
 # if HAVE_DECL_ETHTOOL_GFEATURES
     struct ethtool_gfeatures *g_cmd;
+    uint32_t size = 0;
 # endif
     struct elem{
         const int cmd;
@@ -3188,14 +3243,22 @@ virNetDevGetFeatures(const char *ifname,
 # endif
 
 # if HAVE_DECL_ETHTOOL_GFEATURES
-    if (VIR_ALLOC_VAR(g_cmd,
-                      struct ethtool_get_features_block, GFEATURES_SIZE) < 0)
+    size = virNetDevGetGFeaturesSize(ifname);
+    if (size == -1) {
+        VIR_DEBUG("Failure to get GFeatures size on ifname %s", ifname);
         return -1;
-    g_cmd->cmd = ETHTOOL_GFEATURES;
-    g_cmd->size = GFEATURES_SIZE;
-    if (virNetDevGFeatureAvailable(ifname, g_cmd))
-        ignore_value(virBitmapSetBit(*out, VIR_NET_DEV_FEAT_TXUDPTNL));
-    VIR_FREE(g_cmd);
+    } else if (size == 0) {
+        VIR_DEBUG("GFeatures unsupported on ifname %s", ifname);
+    } else {
+        if (VIR_ALLOC_VAR(g_cmd,
+                          struct ethtool_get_features_block, size) < 0)
+            return -1;
+        g_cmd->cmd = ETHTOOL_GFEATURES;
+        g_cmd->size = size;
+        if (virNetDevGFeatureAvailable(ifname, g_cmd))
+            ignore_value(virBitmapSetBit(*out, VIR_NET_DEV_FEAT_TXUDPTNL));
+        VIR_FREE(g_cmd);
+    }
 # endif
 
     if (virNetDevRDMAFeature(ifname, out) < 0)
-- 
1.7.1




More information about the libvir-list mailing list