6d3351
From 282c1d8582c7b3a30c87f3ad50859ad139cdce7c Mon Sep 17 00:00:00 2001
6d3351
Message-Id: <282c1d8582c7b3a30c87f3ad50859ad139cdce7c@dist-git>
6d3351
From: Laine Stump <laine@laine.org>
6d3351
Date: Mon, 14 Aug 2017 21:28:18 -0400
6d3351
Subject: [PATCH] util: make virPCIGetNetName() more versatile
6d3351
6d3351
A single PCI device may have multiple netdevs associated with it. Each
6d3351
of those netdevs will have a different phys_port_id entry in
6d3351
sysfs. This patch modifies virPCIGetNetName() to allow selecting one
6d3351
of the potential many netdevs in two different ways:
6d3351
6d3351
1) by setting the "idx" argument, the caller can select the 1st (0),
6d3351
2nd (1), etc. netdev from the PCI device's net subdirectory.
6d3351
6d3351
2) If the physPortID arg is set (to a null-terminated string) then
6d3351
virPCIGetNetName() returns the netdev that has that phys_port_id in
6d3351
the sysfs file of the same name in the netdev's directory.
6d3351
6d3351
Resolves: https://bugzilla.redhat.com/1460082
6d3351
6d3351
(cherry picked from commit b3b5aa75ed40d14bb96d3e7d2cff7356ccaab442)
6d3351
6d3351
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
6d3351
---
6d3351
 src/util/virhostdev.c |  2 +-
6d3351
 src/util/virnetdev.c  |  9 ++++---
6d3351
 src/util/virpci.c     | 66 ++++++++++++++++++++++++++++++++++++++++++---------
6d3351
 src/util/virpci.h     |  5 +++-
6d3351
 4 files changed, 66 insertions(+), 16 deletions(-)
6d3351
6d3351
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
6d3351
index 579563c3f3..580f0fac06 100644
6d3351
--- a/src/util/virhostdev.c
6d3351
+++ b/src/util/virhostdev.c
6d3351
@@ -326,7 +326,7 @@ virHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
6d3351
          * type='hostdev'>, and it is only those devices that should
6d3351
          * end up calling this function.
6d3351
          */
6d3351
-        if (virPCIGetNetName(sysfs_path, linkdev) < 0)
6d3351
+        if (virPCIGetNetName(sysfs_path, 0, NULL, linkdev) < 0)
6d3351
             goto cleanup;
6d3351
 
6d3351
         if (!linkdev) {
6d3351
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
6d3351
index 2fced369b3..b6d31ef938 100644
6d3351
--- a/src/util/virnetdev.c
6d3351
+++ b/src/util/virnetdev.c
6d3351
@@ -1262,8 +1262,10 @@ virNetDevGetVirtualFunctions(const char *pfname,
6d3351
             goto cleanup;
6d3351
         }
6d3351
 
6d3351
-        if (virPCIGetNetName(pci_sysfs_device_link, &((*vfname)[i])) < 0)
6d3351
+        if (virPCIGetNetName(pci_sysfs_device_link, 0,
6d3351
+                             NULL, &((*vfname)[i])) < 0) {
6d3351
             goto cleanup;
6d3351
+        }
6d3351
 
6d3351
         if (!(*vfname)[i])
6d3351
             VIR_INFO("VF does not have an interface name");
6d3351
@@ -1362,7 +1364,8 @@ virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
6d3351
     if (virNetDevSysfsDeviceFile(&physfn_sysfs_path, ifname, "physfn") < 0)
6d3351
         return ret;
6d3351
 
6d3351
-    if (virPCIGetNetName(physfn_sysfs_path, pfname) < 0)
6d3351
+    if (virPCIGetNetName(physfn_sysfs_path, 0,
6d3351
+                         NULL, pfname) < 0)
6d3351
         goto cleanup;
6d3351
 
6d3351
     if (!*pfname) {
6d3351
@@ -1422,7 +1425,7 @@ virNetDevPFGetVF(const char *pfname, int vf, char **vfname)
6d3351
      * isn't bound to a netdev driver, it won't have a netdev name,
6d3351
      * and vfname will be NULL).
6d3351
      */
6d3351
-    ret = virPCIGetNetName(virtfnSysfsPath, vfname);
6d3351
+    ret = virPCIGetNetName(virtfnSysfsPath, 0, NULL, vfname);
6d3351
 
6d3351
  cleanup:
6d3351
     VIR_FREE(virtfnName);
6d3351
diff --git a/src/util/virpci.c b/src/util/virpci.c
6d3351
index b2b50c2d3a..e7bb588da1 100644
6d3351
--- a/src/util/virpci.c
6d3351
+++ b/src/util/virpci.c
6d3351
@@ -24,6 +24,7 @@
6d3351
 #include <config.h>
6d3351
 
6d3351
 #include "virpci.h"
6d3351
+#include "virnetdev.h"
6d3351
 
6d3351
 #include <dirent.h>
6d3351
 #include <fcntl.h>
6d3351
@@ -2855,16 +2856,30 @@ virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
6d3351
     return 0;
6d3351
 }
6d3351
 
6d3351
-/*
6d3351
- * Returns the network device name of a pci device
6d3351
+/**
6d3351
+ * virPCIGetNetName:
6d3351
+ * @device_link_sysfs_path: sysfs path to the PCI device
6d3351
+ * @idx: used to choose which netdev when there are several
6d3351
+ *       (ignored if physPortID is set)
6d3351
+ * @physPortID: match this string in the netdev's phys_port_id
6d3351
+ *       (or NULL to ignore and use idx instead)
6d3351
+ * @netname: used to return the name of the netdev
6d3351
+ *       (set to NULL (but returns success) if there is no netdev)
6d3351
+ *
6d3351
+ * Returns 0 on success, -1 on error (error has been logged)
6d3351
  */
6d3351
 int
6d3351
-virPCIGetNetName(const char *device_link_sysfs_path, char **netname)
6d3351
+virPCIGetNetName(const char *device_link_sysfs_path,
6d3351
+                 size_t idx,
6d3351
+                 char *physPortID,
6d3351
+                 char **netname)
6d3351
 {
6d3351
     char *pcidev_sysfs_net_path = NULL;
6d3351
     int ret = -1;
6d3351
     DIR *dir = NULL;
6d3351
     struct dirent *entry = NULL;
6d3351
+    char *thisPhysPortID = NULL;
6d3351
+    size_t i = 0;
6d3351
 
6d3351
     if (virBuildPath(&pcidev_sysfs_net_path, device_link_sysfs_path,
6d3351
                      "net") == -1) {
6d3351
@@ -2875,21 +2890,48 @@ virPCIGetNetName(const char *device_link_sysfs_path, char **netname)
6d3351
     if (virDirOpenQuiet(&dir, pcidev_sysfs_net_path) < 0) {
6d3351
         /* this *isn't* an error - caller needs to check for netname == NULL */
6d3351
         ret = 0;
6d3351
-        goto out;
6d3351
+        goto cleanup;
6d3351
     }
6d3351
 
6d3351
     while (virDirRead(dir, &entry, pcidev_sysfs_net_path) > 0) {
6d3351
-        /* Assume a single directory entry */
6d3351
-        if (VIR_STRDUP(*netname, entry->d_name) > 0)
6d3351
-            ret = 0;
6d3351
+        /* if the caller sent a physPortID, compare it to the
6d3351
+         * physportID of this netdev. If not, look for entry[idx].
6d3351
+         */
6d3351
+        if (physPortID) {
6d3351
+            if (virNetDevGetPhysPortID(entry->d_name, &thisPhysPortID) < 0)
6d3351
+                goto cleanup;
6d3351
+
6d3351
+            /* if this one doesn't match, keep looking */
6d3351
+            if (STRNEQ_NULLABLE(physPortID, thisPhysPortID)) {
6d3351
+                VIR_FREE(thisPhysPortID);
6d3351
+                continue;
6d3351
+            }
6d3351
+        } else {
6d3351
+            if (i++ < idx)
6d3351
+                continue;
6d3351
+        }
6d3351
+
6d3351
+        if (VIR_STRDUP(*netname, entry->d_name) < 0)
6d3351
+            goto cleanup;
6d3351
+
6d3351
+        ret = 0;
6d3351
         break;
6d3351
     }
6d3351
 
6d3351
+    if (ret < 0) {
6d3351
+        if (physPortID) {
6d3351
+            virReportError(VIR_ERR_INTERNAL_ERROR,
6d3351
+                           _("Could not find network device with "
6d3351
+                             "phys_port_id '%s' under PCI device at %s"),
6d3351
+                           physPortID, device_link_sysfs_path);
6d3351
+        } else {
6d3351
+            ret = 0; /* no netdev at the given index is *not* an error */
6d3351
+        }
6d3351
+    }
6d3351
+ cleanup:
6d3351
     VIR_DIR_CLOSE(dir);
6d3351
-
6d3351
- out:
6d3351
     VIR_FREE(pcidev_sysfs_net_path);
6d3351
-
6d3351
+    VIR_FREE(thisPhysPortID);
6d3351
     return ret;
6d3351
 }
6d3351
 
6d3351
@@ -2917,7 +2959,7 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path,
6d3351
         goto cleanup;
6d3351
     }
6d3351
 
6d3351
-    if (virPCIGetNetName(pf_sysfs_device_path, pfname) < 0)
6d3351
+    if (virPCIGetNetName(pf_sysfs_device_path, 0, NULL, pfname) < 0)
6d3351
         goto cleanup;
6d3351
 
6d3351
     if (!*pfname) {
6d3351
@@ -2994,6 +3036,8 @@ virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr dev ATTRIBUTE_UNUSED,
6d3351
 
6d3351
 int
6d3351
 virPCIGetNetName(const char *device_link_sysfs_path ATTRIBUTE_UNUSED,
6d3351
+                 size_t idx ATTRIBUTE_UNUSED,
6d3351
+                 char *physPortID ATTRIBUTE_UNUSED,
6d3351
                  char **netname ATTRIBUTE_UNUSED)
6d3351
 {
6d3351
     virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
6d3351
diff --git a/src/util/virpci.h b/src/util/virpci.h
6d3351
index 82d4ddc61b..adf336706b 100644
6d3351
--- a/src/util/virpci.h
6d3351
+++ b/src/util/virpci.h
6d3351
@@ -207,7 +207,10 @@ int virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link,
6d3351
 int virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
6d3351
                                     char **pci_sysfs_device_link);
6d3351
 
6d3351
-int virPCIGetNetName(const char *device_link_sysfs_path, char **netname);
6d3351
+int virPCIGetNetName(const char *device_link_sysfs_path,
6d3351
+                     size_t idx,
6d3351
+                     char *physPortID,
6d3351
+                     char **netname);
6d3351
 
6d3351
 int virPCIGetSysfsFile(char *virPCIDeviceName,
6d3351
                              char **pci_sysfs_device_link)
6d3351
-- 
6d3351
2.14.1
6d3351