Blame SOURCES/libvirt-util-if-setting-admin-MAC-to-00-00-00-00-00-00-fails-try-02-00-00-00-00-00.patch

5c27b6
From 458aa8587e750e7b368e1a86208841a082242ce5 Mon Sep 17 00:00:00 2001
5c27b6
Message-Id: <458aa8587e750e7b368e1a86208841a082242ce5@dist-git>
5c27b6
From: Laine Stump <laine@laine.org>
5c27b6
Date: Thu, 13 Apr 2017 14:29:36 -0400
5c27b6
Subject: [PATCH] util: if setting admin MAC to 00:00:00:00:00:00 fails, try
5c27b6
 02:00:00:00:00:00
5c27b6
5c27b6
Some PF drivers allow setting the admin MAC (that is the MAC address
5c27b6
that the VF will be initialized to the next time the VF's driver is
5c27b6
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
5c27b6
initialize the admin MACs to all 0, but don't allow setting it to that
5c27b6
very same value. It has been an uphill battle convincing the driver
5c27b6
people that it's reasonable to expect The argument that's used is
5c27b6
that an all 0 device MAC address on a device is invalid; however, from
5c27b6
an outsider's point of view, when the admin MAC is set to 0 at the
5c27b6
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
5c27b6
random non-0 value. But that's beside the point - even if I could
5c27b6
convince one or two SRIOV driver maintainers to permit setting the
5c27b6
admin MAC to 0, there are still several other drivers.
5c27b6
5c27b6
So rather than fighting that losing battle, this patch checks for a
5c27b6
failure to set the admin MAC due to an all 0 value, and retries it
5c27b6
with 02:00:00:00:00:00. That won't result in a random value being set
5c27b6
in the VF MAC at next VF driver init, but that's okay, because we
5c27b6
always want to set a specific value anyway. Rather, the "almost 0"
5c27b6
setting makes it easy to visually detect from the output of "ip link
5c27b6
show" which VFs are currently in use and which are free.
5c27b6
5c27b6
Resolves: https://bugzilla.redhat.com/1442040 (RHEL 7.3.z)
5c27b6
Resolves: https://bugzilla.redhat.com/1415609 (RHEL 7.4)
5c27b6
5c27b6
(cherry picked from commit d5f4abefc231a71e21e33e0d2eb4da8f22552c70)
5c27b6
---
5c27b6
 src/util/virnetdev.c | 42 ++++++++++++++++++++++++++++++++++++++----
5c27b6
 1 file changed, 38 insertions(+), 4 deletions(-)
5c27b6
5c27b6
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
5c27b6
index 4739f573a..0223877ff 100644
5c27b6
--- a/src/util/virnetdev.c
5c27b6
+++ b/src/util/virnetdev.c
5c27b6
@@ -1391,6 +1391,14 @@ virNetDevSysfsFile(char **pf_sysfs_device_link ATTRIBUTE_UNUSED,
5c27b6
 #if defined(__linux__) && defined(HAVE_LIBNL) && defined(IFLA_VF_MAX)
5c27b6
 
5c27b6
 
5c27b6
+static virMacAddr zeroMAC = { .addr = { 0, 0, 0, 0, 0, 0 } };
5c27b6
+
5c27b6
+/* if a net driver doesn't allow setting MAC to all 0, try setting
5c27b6
+ * to this (the only bit that is set is the "locally administered" bit")
5c27b6
+ */
5c27b6
+static virMacAddr altZeroMAC = { .addr = { 2, 0, 0, 0, 0, 0 } };
5c27b6
+
5c27b6
+
5c27b6
 static struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
5c27b6
     [IFLA_VF_MAC]       = { .type = NLA_UNSPEC,
5c27b6
                             .maxlen = sizeof(struct ifla_vf_mac) },
5c27b6
@@ -1401,7 +1409,8 @@ static struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
5c27b6
 
5c27b6
 static int
5c27b6
 virNetDevSetVfConfig(const char *ifname, int vf,
5c27b6
-                     const virMacAddr *macaddr, int vlanid)
5c27b6
+                     const virMacAddr *macaddr, int vlanid,
5c27b6
+                     bool *allowRetry)
5c27b6
 {
5c27b6
     int rc = -1;
5c27b6
     struct nlmsghdr *resp = NULL;
5c27b6
@@ -1478,7 +1487,15 @@ virNetDevSetVfConfig(const char *ifname, int vf,
5c27b6
         if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
5c27b6
             goto malformed_resp;
5c27b6
 
5c27b6
-        if (err->error) {
5c27b6
+        /* if allowRetry is true and the error was EINVAL, then
5c27b6
+         * silently return a failure so the caller can retry with a
5c27b6
+         * different MAC address
5c27b6
+         */
5c27b6
+        if (err->error == -EINVAL && *allowRetry &&
5c27b6
+            macaddr && !virMacAddrCmp(macaddr, &zeroMAC)) {
5c27b6
+            goto cleanup;
5c27b6
+        } else if (err->error) {
5c27b6
+            /* other errors are permanent */
5c27b6
             char macstr[VIR_MAC_STRING_BUFLEN];
5c27b6
 
5c27b6
             virReportSystemError(-err->error,
5c27b6
@@ -1490,6 +1507,7 @@ virNetDevSetVfConfig(const char *ifname, int vf,
5c27b6
                                  vlanid,
5c27b6
                                  ifname ? ifname : "(unspecified)",
5c27b6
                                  vf);
5c27b6
+            *allowRetry = false; /* no use retrying */
5c27b6
             goto cleanup;
5c27b6
         }
5c27b6
         break;
5c27b6
@@ -2126,8 +2144,24 @@ virNetDevSetNetConfig(const char *linkdev, int vf,
5c27b6
          * guest or host). if there is a vlanTag to set, it will take
5c27b6
          * effect immediately though.
5c27b6
          */
5c27b6
-        if (virNetDevSetVfConfig(pfDevName, vf, adminMAC, vlanTag) < 0)
5c27b6
-            goto cleanup;
5c27b6
+        bool allowRetry = true;
5c27b6
+
5c27b6
+        if (virNetDevSetVfConfig(pfDevName, vf,
5c27b6
+                                 adminMAC, vlanTag, &allowRetry) < 0) {
5c27b6
+            /* allowRetry will still be true if the failure was due to
5c27b6
+             * trying to set the MAC address to all 0. In that case,
5c27b6
+             * we can retry with "altZeroMAC", which is just an all-0 MAC
5c27b6
+             * with the "locally administered" bit set.
5c27b6
+             */
5c27b6
+            if (!allowRetry)
5c27b6
+                goto cleanup;
5c27b6
+
5c27b6
+            allowRetry = false;
5c27b6
+            if (virNetDevSetVfConfig(pfDevName, vf,
5c27b6
+                                     &altZeroMAC, vlanTag, &allowRetry) < 0) {
5c27b6
+                goto cleanup;
5c27b6
+            }
5c27b6
+        }
5c27b6
     }
5c27b6
 
5c27b6
     ret = 0;
5c27b6
-- 
5c27b6
2.12.2
5c27b6