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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list