Blame SOURCES/libvirt-util-virPCIGetNetName-use-first-netdev-name-when-phys_port_id-isn-t-matched.patch

6d3351
From 3d1121ecc9a2fa0e6be2df92f04990ec6d44be56 Mon Sep 17 00:00:00 2001
6d3351
Message-Id: <3d1121ecc9a2fa0e6be2df92f04990ec6d44be56@dist-git>
6d3351
From: Laine Stump <laine@laine.org>
6d3351
Date: Wed, 20 Sep 2017 07:35:18 -0400
6d3351
Subject: [PATCH] util: virPCIGetNetName(): use first netdev name when
6d3351
 phys_port_id isn't matched
6d3351
6d3351
The mlx4 (Mellanox) netdev driver implements the sysfs phys_port_id
6d3351
file for both VFs and PFs, so you can find the VF netdev plugged into
6d3351
the same physical port as any given PF netdev by comparing the
6d3351
contents of phys_port_id of the respective netdevs. That's what
6d3351
libvirt does when attempting to find the PF netdev for a given VF
6d3351
netdev (or vice versa).
6d3351
6d3351
Most other netdev's drivers don't implement phys_port_id, so the file
6d3351
is visible in sysfs directory listing, but attempts to read it result
6d3351
in ENOTSUPP. In these cases, libvirt is unable to read phys_port_id of
6d3351
either the PF or the VF, so it just returns the first entry in the
6d3351
PF/VF's list of netdevs.
6d3351
6d3351
But we've found that the i40e driver is in between those two
6d3351
situations - it implements phys_port_id for PF netdevs, but doesn't
6d3351
implement it for VF netdevs. So libvirt would successfully read the
6d3351
phys_port_id of the PF netdev, then try to find a VF netdev with
6d3351
matching phys_port_id, but would fail because phys_port_id is NULL for
6d3351
all VFs. This would result in a message like the following:
6d3351
6d3351
   Could not find network device with phys_port_id '3cfdfe9edc39'
6d3351
   under PCI device at /sys/class/net/ens4f1/device/virtfn0
6d3351
6d3351
To solve this problem in a way that won't break functionality for
6d3351
anyone else, this patch saves the first netdev name we find for the
6d3351
device, and returns that if we fail to find a netdev with the desired
6d3351
phys_port_id.
6d3351
6d3351
Resolves: https://bugzilla.redhat.com/1489263
6d3351
6d3351
(cherry picked from commit 747116e0b904a4bc3c438c1fe6badd9961504814)
6d3351
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
6d3351
---
6d3351
 src/util/virpci.c | 31 +++++++++++++++++++++++++++----
6d3351
 1 file changed, 27 insertions(+), 4 deletions(-)
6d3351
6d3351
diff --git a/src/util/virpci.c b/src/util/virpci.c
6d3351
index ea8fc228fc..54e65feab0 100644
6d3351
--- a/src/util/virpci.c
6d3351
+++ b/src/util/virpci.c
6d3351
@@ -2878,6 +2878,7 @@ virPCIGetNetName(const char *device_link_sysfs_path,
6d3351
     int ret = -1;
6d3351
     DIR *dir = NULL;
6d3351
     struct dirent *entry = NULL;
6d3351
+    char *firstEntryName = NULL;
6d3351
     char *thisPhysPortID = NULL;
6d3351
     size_t i = 0;
6d3351
 
6d3351
@@ -2904,6 +2905,16 @@ virPCIGetNetName(const char *device_link_sysfs_path,
6d3351
             /* if this one doesn't match, keep looking */
6d3351
             if (STRNEQ_NULLABLE(physPortID, thisPhysPortID)) {
6d3351
                 VIR_FREE(thisPhysPortID);
6d3351
+                /* save the first entry we find to use as a failsafe
6d3351
+                 * in case we don't match the phys_port_id. This is
6d3351
+                 * needed because some NIC drivers (e.g. i40e)
6d3351
+                 * implement phys_port_id for PFs, but not for VFs
6d3351
+                 */
6d3351
+                if (!firstEntryName &&
6d3351
+                    VIR_STRDUP(firstEntryName, entry->d_name) < 0) {
6d3351
+                    goto cleanup;
6d3351
+                }
6d3351
+
6d3351
                 continue;
6d3351
             }
6d3351
         } else {
6d3351
@@ -2920,10 +2931,21 @@ virPCIGetNetName(const char *device_link_sysfs_path,
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
+            if (firstEntryName) {
6d3351
+                /* we didn't match the provided phys_port_id, but this
6d3351
+                 * is probably because phys_port_id isn't implemented
6d3351
+                 * for this NIC driver, so just return the first
6d3351
+                 * (probably only) netname we found.
6d3351
+                 */
6d3351
+                *netname = firstEntryName;
6d3351
+                firstEntryName = NULL;
6d3351
+                ret = 0;
6d3351
+            } else {
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
+            }
6d3351
         } else {
6d3351
             ret = 0; /* no netdev at the given index is *not* an error */
6d3351
         }
6d3351
@@ -2932,6 +2954,7 @@ virPCIGetNetName(const char *device_link_sysfs_path,
6d3351
     VIR_DIR_CLOSE(dir);
6d3351
     VIR_FREE(pcidev_sysfs_net_path);
6d3351
     VIR_FREE(thisPhysPortID);
6d3351
+    VIR_FREE(firstEntryName);
6d3351
     return ret;
6d3351
 }
6d3351
 
6d3351
-- 
6d3351
2.14.2
6d3351