|
|
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 |
|