[libvirt] [PATCH 1/2] util: Add helper APIs to get/verify VF Representor name

Jai Singh Rana jai.rana at gmail.com
Fri Feb 9 14:00:44 UTC 2018


Switchdev VF Representor interface name on host is derived based on BDF
of pci SR-IOV device in 'hostdev' and querying required net sysfs
entries on host.
---
 po/POTFILES.in              |   1 +
 src/Makefile.am             |   1 +
 src/libvirt_private.syms    |   5 +
 src/util/virhostdev.c       |  10 ++
 src/util/virhostdev.h       |   6 +
 src/util/virnetdevhostdev.c | 284 ++++++++++++++++++++++++++++++++++++++++++++
 src/util/virnetdevhostdev.h |  33 +++++
 7 files changed, 340 insertions(+)
 create mode 100644 src/util/virnetdevhostdev.c
 create mode 100644 src/util/virnetdevhostdev.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 285955469..73ce73397 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -237,6 +237,7 @@ src/util/virnetdevmacvlan.c
 src/util/virnetdevmidonet.c
 src/util/virnetdevopenvswitch.c
 src/util/virnetdevtap.c
+src/util/virnetdevhostdev.c
 src/util/virnetdevveth.c
 src/util/virnetdevvportprofile.c
 src/util/virnetlink.c
diff --git a/src/Makefile.am b/src/Makefile.am
index db68e01db..0f3c3f1bc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -148,6 +148,7 @@ UTIL_SOURCES = \
 		util/virnetdev.h util/virnetdev.c \
 		util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
 		util/virnetdevbridge.h util/virnetdevbridge.c \
+		util/virnetdevhostdev.h util/virnetdevhostdev.c	\
 		util/virnetdevip.h util/virnetdevip.c \
 		util/virnetdevmacvlan.c util/virnetdevmacvlan.h \
 		util/virnetdevmidonet.h util/virnetdevmidonet.c \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3b14d7d15..d9bc8ad72 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2288,6 +2288,11 @@ virNetDevBridgeSetSTPDelay;
 virNetDevBridgeSetVlanFiltering;
 
 
+# util/virnetdevhostdev.h
+virNetdevHostdevCheckVFRepIFName;
+virNetdevHostdevGetVFRepIFName;
+
+
 # util/virnetdevip.h
 virNetDevIPAddrAdd;
 virNetDevIPAddrDel;
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index a12224c58..7a90779f0 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -350,6 +350,16 @@ virHostdevNetDevice(virDomainHostdevDefPtr hostdev,
     return ret;
 }
 
+/* Non static wrapper for virHostdevNetDevice to use outside filescope */
+int
+virHostdevNetDeviceWrapper(virDomainHostdevDefPtr hostdev,
+                    int pfNetDevIdx,
+                    char **linkdev,
+                    int *vf)
+{
+    return virHostdevNetDevice(hostdev, pfNetDevIdx, linkdev, vf);
+}
+
 
 static bool
 virHostdevIsPCINetDevice(virDomainHostdevDefPtr hostdev)
diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h
index 54e1c66be..7dc860a85 100644
--- a/src/util/virhostdev.h
+++ b/src/util/virhostdev.h
@@ -202,5 +202,11 @@ int virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr mgr,
 int virHostdevPCINodeDeviceReset(virHostdevManagerPtr mgr,
                                  virPCIDevicePtr pci)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int
+virHostdevNetDeviceWrapper(virDomainHostdevDefPtr hostdev,
+                    int pfNetDevIdx,
+                    char **linkdev,
+                    int *vf)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4);
 
 #endif /* __VIR_HOSTDEV_H__ */
diff --git a/src/util/virnetdevhostdev.c b/src/util/virnetdevhostdev.c
new file mode 100644
index 000000000..ecf4b7d8f
--- /dev/null
+++ b/src/util/virnetdevhostdev.c
@@ -0,0 +1,284 @@
+/* 
+ * virnetdevhostdev.c: utilities to get/verify Switchdev VF Representor
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <dirent.h>
+
+#include "virhostdev.h"
+#include "virnetdevhostdev.h"
+#include "viralloc.h"
+#include "virstring.h"
+#include "virfile.h"
+#include "virerror.h"
+#include "virlog.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_LOG_INIT("util.netdevhostdev");
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+#define IFSWITCHIDSIZ 20
+
+#ifndef SYSFS_NET_DIR
+#define SYSFS_NET_DIR "/sys/class/net/"
+#endif
+
+#if 0
+static int
+virNetdevHostdevPCISysfsPath(virDomainHostdevDefPtr hostdev,
+                             char **sysfs_path)
+{
+    virPCIDeviceAddress config_address;
+
+    config_address.domain = hostdev->source.subsys.u.pci.addr.domain;
+    config_address.bus = hostdev->source.subsys.u.pci.addr.bus;
+    config_address.slot = hostdev->source.subsys.u.pci.addr.slot;
+    config_address.function = hostdev->source.subsys.u.pci.addr.function;
+
+    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
+}
+
+
+static int
+virNetdevHostdevNetDevice(virDomainHostdevDefPtr hostdev,
+                          int pfNetDevIdx,
+                          char **linkdev,
+                          int *vf)
+{
+    int ret = -1;
+    char *sysfs_path = NULL;
+
+    if (virNetdevHostdevPCISysfsPath(hostdev, &sysfs_path) < 0)
+        return ret;
+
+    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
+        if (virPCIGetVirtualFunctionInfo(sysfs_path, pfNetDevIdx,
+                                         linkdev, vf) < 0)
+            goto cleanup;
+    } else {
+        /* In practice this should never happen, since we currently
+         * only support assigning SRIOV VFs via <interface
+         * type='hostdev'>, and it is only those devices that should
+         * end up calling this function.
+         */
+        if (virPCIGetNetName(sysfs_path, 0, NULL, linkdev) < 0)
+            goto cleanup;
+
+        if (!linkdev) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("The device at %s has no network device name"),
+                           sysfs_path);
+            goto cleanup;
+        }
+
+        *vf = -1;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(sysfs_path);
+
+    return ret;
+}
+#endif
+
+
+/**
+ * virNetdevHostdevNetSysfsPath
+ *
+ * @pf_name: netdev name of the physical function (PF)
+ * @vf: virtual function (VF) number for the device of interest
+ * @vf_representor: name of the VF representor interface
+ *
+ * Finds the VF representor name of VF# @vf of SRIOV PF @pfname, and
+ * puts it in @vf_representor. The caller must free @vf_representor
+ * when it's finished with it
+ *
+ * Returns 0 on success, -1 on failure
+ */
+static int
+virNetdevHostdevNetSysfsPath(char *pf_name, int vf, char **vf_representor)
+{
+    char *pf_switch_id = NULL;
+    char *pf_switch_id_file = NULL;
+    char *pf_subsystem_device_file = NULL;
+    char *pf_subsystem_device_switch_id = NULL;
+    char *pf_subsystem_device_port_name_file = NULL;
+    char *pf_subsystem_dir = NULL;
+    char *vf_representor_name = NULL;
+    char *vf_num_str = NULL;
+    char *vf_suffix = NULL;
+    DIR *dirp = NULL;
+    struct dirent *dp;
+    int ret = -1;
+
+
+    if (virAsprintf(&pf_switch_id_file, SYSFS_NET_DIR "%s/phys_switch_id",
+                    pf_name) < 0)
+        goto cleanup;
+
+    if (virAsprintf(&pf_subsystem_dir, SYSFS_NET_DIR "%s/subsystem",
+                    pf_name) < 0)
+        goto cleanup;
+
+    if (virFileReadAllQuiet(pf_switch_id_file, IFSWITCHIDSIZ,
+                            &pf_switch_id) <= 0) {
+        goto cleanup;
+    }
+
+    if (virDirOpen(&dirp, pf_subsystem_dir) < 0)
+        goto cleanup;
+
+    /* Iterate over the PFs subsystem devices to find entry with matching
+     * switch_id with that of PF.
+     */
+    while (virDirRead(dirp, &dp, pf_subsystem_dir) > 0) {
+        if (STREQ(dp->d_name, pf_name))
+            continue;
+
+        if (virAsprintf(&pf_subsystem_device_file, "%s/%s/phys_switch_id",
+                        pf_subsystem_dir, dp->d_name) < 0)
+            goto cleanup;
+
+        if (virFileReadAllQuiet(pf_subsystem_device_file, IFSWITCHIDSIZ,
+                                &pf_subsystem_device_switch_id) > 0) {
+            if (!STREQ(pf_switch_id, pf_subsystem_device_switch_id)) {
+                VIR_FREE(pf_subsystem_device_file);
+                VIR_FREE(pf_subsystem_device_switch_id);
+                continue;
+            }
+        }
+
+        if (virAsprintf(&pf_subsystem_device_port_name_file,
+                        "%s/%s/phys_port_name", pf_subsystem_dir,
+                        dp->d_name) < 0)
+            goto cleanup;
+
+        if (virFileReadAllQuiet
+            (pf_subsystem_device_port_name_file, IFNAMSIZ,
+             &vf_representor_name) <= 0) {
+            VIR_FREE(pf_subsystem_device_file);
+            VIR_FREE(pf_subsystem_device_switch_id);
+            VIR_FREE(pf_subsystem_device_port_name_file);
+            continue;
+        }
+
+        if (virAsprintf(&vf_num_str, "%d", vf) < 0)
+            goto cleanup;
+
+        /* phys_port_name may contain just VF number or string with
+         * 'vf' or 'VF' followed by VF number at the end.
+         */
+        if (!(vf_suffix = strcasestr(vf_representor_name, "vf")))
+            vf_suffix = vf_representor_name;
+
+        if (strstr(vf_suffix, vf_num_str)) {
+            if (virAsprintf(vf_representor, "%s", dp->d_name) < 0)
+                goto cleanup;
+
+            ret = 0;
+            break;
+        }
+    }
+
+  cleanup:
+    VIR_DIR_CLOSE(dirp);
+    VIR_FREE(pf_switch_id);
+    VIR_FREE(pf_switch_id_file);
+    VIR_FREE(pf_subsystem_dir);
+    VIR_FREE(pf_subsystem_device_file);
+    VIR_FREE(pf_subsystem_device_switch_id);
+    VIR_FREE(pf_subsystem_device_port_name_file);
+    VIR_FREE(vf_num_str);
+    VIR_FREE(vf_representor_name);
+    return ret;
+}
+
+
+/**
+ * virNetdevHostdevGetVFRepIFName
+ *
+ * @hostdev: host device to check
+ * @ifname : Contains VF representor name upon successful return.
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int
+virNetdevHostdevGetVFRepIFName(virDomainHostdevDefPtr hostdev,
+                               char **ifname)
+{
+    char *linkdev = NULL;
+    char *vf_representor = NULL;
+    int vf = -1;
+    int ret = -1;
+
+    if (virHostdevNetDeviceWrapper(hostdev, -1, &linkdev, &vf) < 0)
+        goto cleanup;
+
+    if (virNetdevHostdevNetSysfsPath(linkdev, vf, &vf_representor))
+        goto cleanup;
+
+    if (VIR_STRDUP(*ifname, vf_representor) > 0)
+        ret = 0;
+
+  cleanup:
+    VIR_FREE(linkdev);
+    VIR_FREE(vf_representor);
+    return ret;
+}
+
+
+/**
+ * virNetdevHostdevCheckVFRepIFName
+ *
+ * @hostdev: host device to check
+ * @ifname : VF representor name to verify
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int
+virNetdevHostdevCheckVFRepIFName(virDomainHostdevDefPtr hostdev,
+                                 const char *ifname)
+{
+    char *linkdev = NULL;
+    char *vf_representor = NULL;
+    int vf = -1;
+    int ret = -1;
+
+    if (virHostdevNetDeviceWrapper(hostdev, -1, &linkdev, &vf) < 0)
+        goto cleanup;
+
+    if (virNetdevHostdevNetSysfsPath(linkdev, vf, &vf_representor))
+        goto cleanup;
+
+    if (STREQ(ifname, vf_representor))
+        ret = 0;
+
+  cleanup:
+    VIR_FREE(linkdev);
+    VIR_FREE(vf_representor);
+    return ret;
+}
diff --git a/src/util/virnetdevhostdev.h b/src/util/virnetdevhostdev.h
new file mode 100644
index 000000000..9fb5c5069
--- /dev/null
+++ b/src/util/virnetdevhostdev.h
@@ -0,0 +1,33 @@
+/* 
+ * virnetdevhostdev.h: utilities to get/verify Switchdev VF Representor
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VIR_NETDEV_HOSTDEV_H__
+#define __VIR_NETDEV_HOSTDEV_H__
+#include "virnetdevtap.h"
+
+int
+virNetdevHostdevGetVFRepIFName(virDomainHostdevDefPtr hostdev,
+                               char **ifname)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+int
+virNetdevHostdevCheckVFRepIFName(virDomainHostdevDefPtr hostdev,
+                                 const char *ifname)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+#define virNetdevHostdevVFRepInterfaceStats virNetDevTapInterfaceStats
+#endif /* __VIR_NETDEV_HOSTDEV_H__ */
-- 
2.13.6




More information about the libvir-list mailing list