render / rpms / libvirt

Forked from rpms/libvirt 9 months ago
Clone
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