Adding functionality to libvirt that will allow
it query the interface for the availability of RDMA and
tx-udp_tnl-segmentation Offloading NIC capabilities
Here is an example of the feature XML definition:
<device>
<name>net_eth4_90_e2_ba_5e_a5_45</name>
<path>/sys/devices/pci0000:00/0000:00:03.0/0000:08:00.1/net/eth4</path>
<parent>pci_0000_08_00_1</parent>
<capability type='net'>
<interface>eth4</interface>
<address>90:e2:ba:5e:a5:45</address>
<link speed='10000' state='up'/>
<feature name='rx'/>
<feature name='tx'/>
<feature name='sg'/>
<feature name='tso'/>
<feature name='gso'/>
<feature name='gro'/>
<feature name='rxvlan'/>
<feature name='txvlan'/>
<feature name='rxhash'/>
<feature name='rdma'/>
<feature name='tx-udp_tnl-segmentation'/>
<capability type='80203'/>
</capability>
</device>
---
docs/formatnode.html.in | 2 +
src/conf/device_conf.c | 4 +-
src/conf/device_conf.h | 2 +
src/util/virnetdev.c | 97 ++++++++++++++++++++++++++++++++++++++--------
src/util/virnetdev.h | 1 +
5 files changed, 88 insertions(+), 18 deletions(-)
diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index 3ff1bef..9b32dd1 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -199,6 +199,8 @@
<dt><code>txvlan</code></dt><dd>tx-vlan-offload</dd>
<dt><code>ntuple</code></dt><dd>ntuple-filters</dd>
<dt><code>rxhash</code></dt><dd>receive-hashing</dd>
+
<dt><code>rdma</code></dt><dd>remote-direct-memory-access</dd>
+
<dt><code>tx-udp_tnl-segmentation</code></dt><dd>tx-udp-tunnel-segmentation</dd>
</dl>
</dd>
<dt><code>capability</code></dt>
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c
index 98808e2..8e8d557 100644
--- a/src/conf/device_conf.c
+++ b/src/conf/device_conf.c
@@ -51,7 +51,9 @@ VIR_ENUM_IMPL(virNetDevFeature,
"rxvlan",
"txvlan",
"ntuple",
- "rxhash")
+ "rxhash",
+ "rdma",
+ "tx-udp_tnl-segmentation")
int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr)
{
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index 7ea90f6..07298c9 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -74,6 +74,8 @@ typedef enum {
VIR_NET_DEV_FEAT_TXVLAN,
VIR_NET_DEV_FEAT_NTUPLE,
VIR_NET_DEV_FEAT_RXHASH,
+ VIR_NET_DEV_FEAT_RDMA,
+ VIR_NET_DEV_FEAT_TX_UDP_TNL_SEGMENTATION,
VIR_NET_DEV_FEAT_LAST
} virNetDevFeature;
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index e4fcd81..3086616 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -87,6 +87,14 @@ VIR_LOG_INIT("util.netdev");
# define VIR_IFF_ALLMULTI 0
#endif
+#define RESOURCE_FILE_LEN 4096
+#define TX_UDP_TNL 25
+#define GFEATURES_SIZE 2
+#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) \
+ (FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
+
typedef enum {
VIR_MCAST_TYPE_INDEX_TOKEN,
VIR_MCAST_TYPE_NAME_TOKEN,
@@ -2943,6 +2951,58 @@ int virNetDevGetRxFilter(const char *ifname,
return ret;
}
+
+/**
+ * virNetDevRDMAFeature
+ * This function checks for the availability of RDMA feature
+ * and add it to bitmap
+ *
+ * @ifname: name of the interface
+ * @out: add RDMA feature if exist to bitmap
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+virNetDevRDMAFeature(const char *ifname,
+ virBitmapPtr *out)
+{
+ char *eth_devpath = NULL;
+ char *ib_devpath = NULL;
+ char *eth_res_buf = NULL;
+ char *ib_res_buf = NULL;
+ struct dirent *dp;
+
+ DIR *dirp = opendir(SYSFS_INFINIBAND_DIR);
+ if (dirp == NULL) {
+ virReportSystemError(errno,
+ _("Failed to opendir path '%s'"),
+ SYSFS_INFINIBAND_DIR);
+ return -1;
+ }
+
+ if (virAsprintf(ð_devpath, SYSFS_NET_DIR "%s/device/resource",
ifname) < 0)
+ return -1;
+ if (!virFileExists(eth_devpath))
+ return 0;
+ if (virFileReadAll(eth_devpath, RESOURCE_FILE_LEN, ð_res_buf) < 0)
+ return -1;
+ while (virDirRead(dirp, &dp, SYSFS_INFINIBAND_DIR) > 0) {
+ if (STREQ(dp->d_name, ".") ||
+ STREQ(dp->d_name, ".."))
+ continue;
+
+ if (virAsprintf(&ib_devpath, SYSFS_INFINIBAND_DIR
"%s/device/resource", dp->d_name) < 0)
+ continue;
+ if (virFileReadAll(ib_devpath, RESOURCE_FILE_LEN, &ib_res_buf) < 0)
+ continue;
+ if (STREQ(eth_res_buf, ib_res_buf)) {
+ ignore_value(virBitmapSetBit(*out, VIR_NET_DEV_FEAT_RDMA));
+ break;
+ }
+ }
+ return 0;
+}
+
#if defined(SIOCETHTOOL) && defined(HAVE_STRUCT_IFREQ)
/**
@@ -2952,12 +3012,10 @@ int virNetDevGetRxFilter(const char *ifname,
* @ifname: name of the interface
* @cmd: reference to an ethtool command structure
*
- * Returns 0 on success, -1 on failure.
*/
-static int
-virNetDevFeatureAvailable(const char *ifname, struct ethtool_value *cmd)
+static void
+virNetDevFeatureAvailable(const char *ifname, void *cmd)
{
- int ret = -1;
int sock = -1;
virIfreq ifr;
@@ -2969,8 +3027,7 @@ virNetDevFeatureAvailable(const char *ifname, struct ethtool_value
*cmd)
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ifname);
- ifr.ifr_data = (void*) cmd;
-
+ ifr.ifr_data = cmd;
if (ioctl(sock, SIOCETHTOOL, &ifr) != 0) {
switch (errno) {
case EPERM:
@@ -2988,12 +3045,9 @@ virNetDevFeatureAvailable(const char *ifname, struct ethtool_value
*cmd)
}
}
- ret = cmd->data > 0 ? 1: 0;
cleanup:
if (sock)
VIR_FORCE_CLOSE(sock);
-
- return ret;
}
@@ -3013,7 +3067,7 @@ virNetDevGetFeatures(const char *ifname,
{
size_t i = -1;
struct ethtool_value cmd = { 0 };
-
+ struct ethtool_gfeatures g_cmd = { 0 };
struct elem{
const int cmd;
const virNetDevFeature feat;
@@ -3037,7 +3091,8 @@ virNetDevGetFeatures(const char *ifname,
for (i = 0; i < ARRAY_CARDINALITY(cmds); i++) {
cmd.cmd = cmds[i].cmd;
- if (virNetDevFeatureAvailable(ifname, &cmd))
+ virNetDevFeatureAvailable(ifname, &cmd);
+ if (cmd.data > 0)
ignore_value(virBitmapSetBit(*out, cmds[i].feat));
}
@@ -3061,14 +3116,22 @@ virNetDevGetFeatures(const char *ifname,
};
cmd.cmd = ETHTOOL_GFLAGS;
- if (virNetDevFeatureAvailable(ifname, &cmd)) {
- for (j = 0; j < ARRAY_CARDINALITY(flags); j++) {
- if (cmd.data & flags[j].cmd)
- ignore_value(virBitmapSetBit(*out, flags[j].feat));
+ virNetDevFeatureAvailable(ifname, &cmd);
+ if (cmd.data > 0) {
+ for (j = 0; j < ARRAY_CARDINALITY(flags); j++) {
+ if (cmd.data & flags[j].cmd)
+ ignore_value(virBitmapSetBit(*out, flags[j].feat));
+ }
}
- }
-# endif
+ g_cmd.cmd = ETHTOOL_GFEATURES;
+ g_cmd.size = GFEATURES_SIZE;
+ virNetDevFeatureAvailable(ifname, &g_cmd);
+ if FEATURE_BIT_IS_SET(g_cmd.features, TX_UDP_TNL, active)
+ ignore_value(virBitmapSetBit(*out, VIR_NET_DEV_FEAT_TX_UDP_TNL_SEGMENTATION));
+# endif
+ if (virNetDevRDMAFeature(ifname, out))
+ return -1;
return 0;
}
#else
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index 190b70e..fff881c 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -210,6 +210,7 @@ int virNetDevGetRcvAllMulti(const char *ifname, bool *receive)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
# define SYSFS_NET_DIR "/sys/class/net/"
+# define SYSFS_INFINIBAND_DIR "/sys/class/infiniband/"
int virNetDevSysfsFile(char **pf_sysfs_device_link,
const char *ifname,
const char *file)
--
1.7.1