|
|
6d3351 |
From e97ab8d35d2582029353dc322c229bf5a6a931ba Mon Sep 17 00:00:00 2001
|
|
|
6d3351 |
Message-Id: <e97ab8d35d2582029353dc322c229bf5a6a931ba@dist-git>
|
|
|
6d3351 |
From: Laine Stump <laine@laine.org>
|
|
|
6d3351 |
Date: Mon, 14 Aug 2017 21:28:21 -0400
|
|
|
6d3351 |
Subject: [PATCH] util: restructure virNetDevReadNetConfig() to eliminate false
|
|
|
6d3351 |
error logs
|
|
|
6d3351 |
|
|
|
6d3351 |
virHostdevRestoreNetConfig() calls virNetDevReadNetConfig() to try and
|
|
|
6d3351 |
read the "original config" of a netdev, and if that fails, it tries
|
|
|
6d3351 |
again with a different directory/netdev name. This achieves the
|
|
|
6d3351 |
desired effect (we end up finding the config wherever it may be), but
|
|
|
6d3351 |
for each failure, virNetDevReadNetConfig() places a nice error message
|
|
|
6d3351 |
in the system logs. Experience has shown that false-positive error
|
|
|
6d3351 |
logs like this lead to erroneous bug reports, and can often mislead
|
|
|
6d3351 |
those searching for *real* bugs.
|
|
|
6d3351 |
|
|
|
6d3351 |
This patch changes virNetDevReadNetConfig() to explicitly check if the
|
|
|
6d3351 |
file exists before calling virFileReadAll(); if it doesn't exist,
|
|
|
6d3351 |
virNetDevReadNetConfig() returns a success, but leaves all the
|
|
|
6d3351 |
variables holding the results as NULL. (This makes sense if you define
|
|
|
6d3351 |
the purpose of the function as "read a netdev's config from its config
|
|
|
6d3351 |
file *if that file exists*).
|
|
|
6d3351 |
|
|
|
6d3351 |
To take advantage of that change, the caller,
|
|
|
6d3351 |
virHostdevRestoreNetConfig() is modified to fail immediately if
|
|
|
6d3351 |
virNetDevReadNetConfig() returns an error, and otherwise to try the
|
|
|
6d3351 |
different directory/netdev name if adminMAC & vlan & MAC are all NULL
|
|
|
6d3351 |
after the preceding attempt.
|
|
|
6d3351 |
|
|
|
6d3351 |
Resolves: https://bugzilla.redhat.com/1460082
|
|
|
6d3351 |
|
|
|
6d3351 |
(cherry picked from commit 9a08168301466dde301adedb9b567590b5968e32)
|
|
|
6d3351 |
|
|
|
6d3351 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
6d3351 |
---
|
|
|
6d3351 |
src/util/virhostdev.c | 122 ++++++++++++++++++++++++++++----------------
|
|
|
6d3351 |
src/util/virnetdev.c | 16 ++++--
|
|
|
6d3351 |
src/util/virnetdevmacvlan.c | 5 +-
|
|
|
6d3351 |
3 files changed, 94 insertions(+), 49 deletions(-)
|
|
|
6d3351 |
|
|
|
6d3351 |
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
|
|
|
6d3351 |
index 102fd85c16..cca9d81a4c 100644
|
|
|
6d3351 |
--- a/src/util/virhostdev.c
|
|
|
6d3351 |
+++ b/src/util/virhostdev.c
|
|
|
6d3351 |
@@ -534,6 +534,10 @@ virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev,
|
|
|
6d3351 |
int ret = -1;
|
|
|
6d3351 |
int vf = -1;
|
|
|
6d3351 |
bool port_profile_associate = false;
|
|
|
6d3351 |
+ virMacAddrPtr MAC = NULL;
|
|
|
6d3351 |
+ virMacAddrPtr adminMAC = NULL;
|
|
|
6d3351 |
+ virNetDevVlanPtr vlan = NULL;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
|
|
|
6d3351 |
/* This is only needed for PCI devices that have been defined
|
|
|
6d3351 |
* using <interface type='hostdev'>. For all others, it is a NOP.
|
|
|
6d3351 |
@@ -559,62 +563,92 @@ virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev,
|
|
|
6d3351 |
NULL,
|
|
|
6d3351 |
port_profile_associate);
|
|
|
6d3351 |
} else {
|
|
|
6d3351 |
- virMacAddrPtr MAC = NULL;
|
|
|
6d3351 |
- virMacAddrPtr adminMAC = NULL;
|
|
|
6d3351 |
- virNetDevVlanPtr vlan = NULL;
|
|
|
6d3351 |
+ /* we need to try 3 different places for the config file:
|
|
|
6d3351 |
+ * 1) ${stateDir}/${PF}_vf${vf}
|
|
|
6d3351 |
+ * This is almost always where the saved config is
|
|
|
6d3351 |
+ *
|
|
|
6d3351 |
+ * 2) ${oldStateDir/${PF}_vf${vf}
|
|
|
6d3351 |
+ * saved config is only here if this machine was running a
|
|
|
6d3351 |
+ * (by now *very*) old version of libvirt that saved the
|
|
|
6d3351 |
+ * file in a different directory
|
|
|
6d3351 |
+ *
|
|
|
6d3351 |
+ * 3) ${stateDir}${PF[1]}_vf${VF}
|
|
|
6d3351 |
+ * PF[1] means "the netdev for port 2 of the PF device", and
|
|
|
6d3351 |
+ * is only valid when the PF is a Mellanox dual port NIC with
|
|
|
6d3351 |
+ * a VF that was created in "single port" mode.
|
|
|
6d3351 |
+ *
|
|
|
6d3351 |
+ * NB: if virNetDevReadNetConfig() returns < 0, then it found
|
|
|
6d3351 |
+ * the file, but there was a problem, so we should
|
|
|
6d3351 |
+ * immediately return an error to our caller. If it returns
|
|
|
6d3351 |
+ * 0, but all of the interesting stuff is NULL, that means
|
|
|
6d3351 |
+ * the file wasn't found, so we can/should check other
|
|
|
6d3351 |
+ * locations for it.
|
|
|
6d3351 |
+ */
|
|
|
6d3351 |
|
|
|
6d3351 |
- ret = virNetDevReadNetConfig(linkdev, vf, stateDir, &adminMAC, &vlan, &MAC);
|
|
|
6d3351 |
- if (ret < 0 && oldStateDir)
|
|
|
6d3351 |
- ret = virNetDevReadNetConfig(linkdev, vf, oldStateDir,
|
|
|
6d3351 |
- &adminMAC, &vlan, &MAC);
|
|
|
6d3351 |
+ /* 1) standard location */
|
|
|
6d3351 |
+ if (virNetDevReadNetConfig(linkdev, vf, stateDir,
|
|
|
6d3351 |
+ &adminMAC, &vlan, &MAC) < 0) {
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
+ }
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (ret < 0) {
|
|
|
6d3351 |
- /* see if the config was saved using the PF's "port 2"
|
|
|
6d3351 |
- * netdev for the file name.
|
|
|
6d3351 |
- */
|
|
|
6d3351 |
+ /* 2) "old" (pre-1.2.3 circa 2014) location - whenever we get
|
|
|
6d3351 |
+ * to the point that nobody will ever upgrade directly from
|
|
|
6d3351 |
+ * 1.2.3 (or older) directly to current libvirt, we can
|
|
|
6d3351 |
+ * eliminate this clause
|
|
|
6d3351 |
+ **/
|
|
|
6d3351 |
+ if (!(adminMAC || vlan || MAC) && oldStateDir &&
|
|
|
6d3351 |
+ virNetDevReadNetConfig(linkdev, vf, oldStateDir,
|
|
|
6d3351 |
+ &adminMAC, &vlan, &MAC) < 0) {
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
+ }
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ /* 3) try using the PF's "port 2" netdev as the name of the
|
|
|
6d3351 |
+ * config file
|
|
|
6d3351 |
+ */
|
|
|
6d3351 |
+ if (!(adminMAC || vlan || MAC)) {
|
|
|
6d3351 |
VIR_FREE(linkdev);
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (virHostdevNetDevice(hostdev, 1, &linkdev, &vf) >= 0) {
|
|
|
6d3351 |
- ret = virNetDevReadNetConfig(linkdev, vf, stateDir,
|
|
|
6d3351 |
- &adminMAC, &vlan, &MAC);
|
|
|
6d3351 |
+ if (virHostdevNetDevice(hostdev, 1, &linkdev, &vf) < 0 ||
|
|
|
6d3351 |
+ virNetDevReadNetConfig(linkdev, vf, stateDir,
|
|
|
6d3351 |
+ &adminMAC, &vlan, &MAC) < 0) {
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (ret == 0) {
|
|
|
6d3351 |
- /* if a MAC was stored for the VF, we should now restore
|
|
|
6d3351 |
- * that as the adminMAC. We have to do it this way because
|
|
|
6d3351 |
- * the VF is still not bound to the host's net driver, so
|
|
|
6d3351 |
- * we can't directly set its MAC (and even after it is
|
|
|
6d3351 |
- * re-bound to the host net driver, it will still have its
|
|
|
6d3351 |
- * "administratively set" flag on, and that prohibits the
|
|
|
6d3351 |
- * VF's net driver from directly setting the MAC
|
|
|
6d3351 |
- * anyway). But it we set the desired VF MAC as the "admin
|
|
|
6d3351 |
- * MAC" *now*, then when the VF is re-bound to the host
|
|
|
6d3351 |
- * net driver (which will happen soon after returning from
|
|
|
6d3351 |
- * this function), that adminMAC will be set (by the PF)
|
|
|
6d3351 |
- * as the VF's new initial MAC.
|
|
|
6d3351 |
- *
|
|
|
6d3351 |
- * If no MAC was stored for the VF, that means it wasn't
|
|
|
6d3351 |
- * bound to a net driver before we used it anyway, so the
|
|
|
6d3351 |
- * adminMAC is all we have, and we can just restore it
|
|
|
6d3351 |
- * directly.
|
|
|
6d3351 |
- */
|
|
|
6d3351 |
- if (MAC) {
|
|
|
6d3351 |
- VIR_FREE(adminMAC);
|
|
|
6d3351 |
- adminMAC = MAC;
|
|
|
6d3351 |
- MAC = NULL;
|
|
|
6d3351 |
- }
|
|
|
6d3351 |
-
|
|
|
6d3351 |
- ignore_value(virNetDevSetNetConfig(linkdev, vf,
|
|
|
6d3351 |
- adminMAC, vlan, MAC, true));
|
|
|
6d3351 |
+ /* if a MAC was stored for the VF, we should now restore
|
|
|
6d3351 |
+ * that as the adminMAC. We have to do it this way because
|
|
|
6d3351 |
+ * the VF is still not bound to the host's net driver, so
|
|
|
6d3351 |
+ * we can't directly set its MAC (and even after it is
|
|
|
6d3351 |
+ * re-bound to the host net driver, it will still have its
|
|
|
6d3351 |
+ * "administratively set" flag on, and that prohibits the
|
|
|
6d3351 |
+ * VF's net driver from directly setting the MAC
|
|
|
6d3351 |
+ * anyway). But it we set the desired VF MAC as the "admin
|
|
|
6d3351 |
+ * MAC" *now*, then when the VF is re-bound to the host
|
|
|
6d3351 |
+ * net driver (which will happen soon after returning from
|
|
|
6d3351 |
+ * this function), that adminMAC will be set (by the PF)
|
|
|
6d3351 |
+ * as the VF's new initial MAC.
|
|
|
6d3351 |
+ *
|
|
|
6d3351 |
+ * If no MAC was stored for the VF, that means it wasn't
|
|
|
6d3351 |
+ * bound to a net driver before we used it anyway, so the
|
|
|
6d3351 |
+ * adminMAC is all we have, and we can just restore it
|
|
|
6d3351 |
+ * directly.
|
|
|
6d3351 |
+ */
|
|
|
6d3351 |
+ if (MAC) {
|
|
|
6d3351 |
+ VIR_FREE(adminMAC);
|
|
|
6d3351 |
+ adminMAC = MAC;
|
|
|
6d3351 |
+ MAC = NULL;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
- VIR_FREE(MAC);
|
|
|
6d3351 |
- VIR_FREE(adminMAC);
|
|
|
6d3351 |
- virNetDevVlanFree(vlan);
|
|
|
6d3351 |
+ ignore_value(virNetDevSetNetConfig(linkdev, vf,
|
|
|
6d3351 |
+ adminMAC, vlan, MAC, true));
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
+ ret = 0;
|
|
|
6d3351 |
+ cleanup:
|
|
|
6d3351 |
VIR_FREE(linkdev);
|
|
|
6d3351 |
+ VIR_FREE(MAC);
|
|
|
6d3351 |
+ VIR_FREE(adminMAC);
|
|
|
6d3351 |
+ virNetDevVlanFree(vlan);
|
|
|
6d3351 |
|
|
|
6d3351 |
return ret;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
|
|
|
6d3351 |
index 05112d9772..476f5334d1 100644
|
|
|
6d3351 |
--- a/src/util/virnetdev.c
|
|
|
6d3351 |
+++ b/src/util/virnetdev.c
|
|
|
6d3351 |
@@ -1971,7 +1971,9 @@ virNetDevSaveNetConfig(const char *linkdev, int vf,
|
|
|
6d3351 |
* @linkdev:@vf from a file in @stateDir. (see virNetDevSaveNetConfig
|
|
|
6d3351 |
* for details of file name and format).
|
|
|
6d3351 |
*
|
|
|
6d3351 |
- * Returns 0 on success, -1 on failure.
|
|
|
6d3351 |
+ * Returns 0 on success, -1 on failure. It is *NOT* considered failure
|
|
|
6d3351 |
+ * if no file is found to read. In that case, adminMAC, vlan, and MAC
|
|
|
6d3351 |
+ * are set to NULL, and success is returned.
|
|
|
6d3351 |
*
|
|
|
6d3351 |
* The caller MUST free adminMAC, vlan, and MAC when it is finished
|
|
|
6d3351 |
* with them (they will be NULL if they weren't found in the file)
|
|
|
6d3351 |
@@ -2036,8 +2038,8 @@ virNetDevReadNetConfig(const char *linkdev, int vf,
|
|
|
6d3351 |
if (linkdev && !virFileExists(filePath)) {
|
|
|
6d3351 |
/* the device may have been stored in a file named for the
|
|
|
6d3351 |
* VF due to saveVlan == false (or an older version of
|
|
|
6d3351 |
- * libvirt), so reset filePath so we'll try the other
|
|
|
6d3351 |
- * filename before failing.
|
|
|
6d3351 |
+ * libvirt), so reset filePath and pfDevName so we'll try
|
|
|
6d3351 |
+ * the other filename.
|
|
|
6d3351 |
*/
|
|
|
6d3351 |
VIR_FREE(filePath);
|
|
|
6d3351 |
pfDevName = NULL;
|
|
|
6d3351 |
@@ -2049,6 +2051,14 @@ virNetDevReadNetConfig(const char *linkdev, int vf,
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
+ if (!virFileExists(filePath)) {
|
|
|
6d3351 |
+ /* having no file to read is not necessarily an error, so we
|
|
|
6d3351 |
+ * just return success, but with MAC, adminMAC, and vlan set to NULL
|
|
|
6d3351 |
+ */
|
|
|
6d3351 |
+ ret = 0;
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
+ }
|
|
|
6d3351 |
+
|
|
|
6d3351 |
if (virFileReadAll(filePath, 128, &fileStr) < 0)
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
|
|
|
6d3351 |
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
|
|
|
6d3351 |
index 97c87701cf..fb41bf934c 100644
|
|
|
6d3351 |
--- a/src/util/virnetdevmacvlan.c
|
|
|
6d3351 |
+++ b/src/util/virnetdevmacvlan.c
|
|
|
6d3351 |
@@ -1187,8 +1187,9 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
|
|
|
6d3351 |
virMacAddrPtr adminMAC = NULL;
|
|
|
6d3351 |
virNetDevVlanPtr vlan = NULL;
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (virNetDevReadNetConfig(linkdev, -1, stateDir,
|
|
|
6d3351 |
- &adminMAC, &vlan, &MAC) == 0) {
|
|
|
6d3351 |
+ if ((virNetDevReadNetConfig(linkdev, -1, stateDir,
|
|
|
6d3351 |
+ &adminMAC, &vlan, &MAC) == 0) &&
|
|
|
6d3351 |
+ (adminMAC || vlan || MAC)) {
|
|
|
6d3351 |
|
|
|
6d3351 |
ignore_value(virNetDevSetNetConfig(linkdev, -1,
|
|
|
6d3351 |
adminMAC, vlan, MAC, !!vlan));
|
|
|
6d3351 |
--
|
|
|
6d3351 |
2.14.1
|
|
|
6d3351 |
|