|
|
5c27b6 |
From 61e603b025083ece8ebf12dc3664c0a5f613f400 Mon Sep 17 00:00:00 2001
|
|
|
5c27b6 |
Message-Id: <61e603b025083ece8ebf12dc3664c0a5f613f400@dist-git>
|
|
|
5c27b6 |
From: Laine Stump <laine@laine.org>
|
|
|
5c27b6 |
Date: Thu, 13 Apr 2017 14:29:37 -0400
|
|
|
5c27b6 |
Subject: [PATCH] util: try *really* hard to set the MAC address of an SRIOV VF
|
|
|
5c27b6 |
|
|
|
5c27b6 |
If an SRIOV VF has previously been used for VFIO device assignment,
|
|
|
5c27b6 |
the "admin MAC" that is stored in the PF driver's table of VF info
|
|
|
5c27b6 |
will have been set to the MAC address that the virtual machine wanted
|
|
|
5c27b6 |
the device to have. Setting the admin MAC for a VF also sets a flag in
|
|
|
5c27b6 |
the PF that is loosely called the "administratively set" flag. Once
|
|
|
5c27b6 |
that flag is set, it is no longer possible for the net driver of the
|
|
|
5c27b6 |
VF (either on the host or in a virtual machine) to directly set the
|
|
|
5c27b6 |
VF's MAC again; this flag isn't reset until the *PF* driver is
|
|
|
5c27b6 |
restarted, and that requires taking *all* VFs offline, so it's not
|
|
|
5c27b6 |
really feasible to do.
|
|
|
5c27b6 |
|
|
|
5c27b6 |
If the same SRIOV VF is later used for macvtap passthrough mode, the
|
|
|
5c27b6 |
VF's MAC address must be set, but normally we don't unbind the VF from
|
|
|
5c27b6 |
its host net driver (since we actually need the host net driver in
|
|
|
5c27b6 |
this case). Since setting the VF MAC directly will fail, in the past
|
|
|
5c27b6 |
"we" ("I") had tried to fix the problem by simply setting the admin MAC
|
|
|
5c27b6 |
(via the PF) instead. This *appeared* to work (and might have at one
|
|
|
5c27b6 |
time, due to promiscuous mode being turned on somewhere or something),
|
|
|
5c27b6 |
but it currently creates a non-working interface because only the
|
|
|
5c27b6 |
value for admin MAC is set to the desired value, *not* the actual MAC
|
|
|
5c27b6 |
that the VF is using.
|
|
|
5c27b6 |
|
|
|
5c27b6 |
Earlier patches in this series reverted that behavior, so that we once
|
|
|
5c27b6 |
again set the MAC of the VF itself for macvtap passthrough operation,
|
|
|
5c27b6 |
not the admin MAC. But that brings back the original bug - if the
|
|
|
5c27b6 |
interface has been used for VFIO device assignment, you can no longer
|
|
|
5c27b6 |
use it for macvtap passthrough.
|
|
|
5c27b6 |
|
|
|
5c27b6 |
This patch solves that problem by noticing when virNetDevSetMAC()
|
|
|
5c27b6 |
fails for a VF, and in that case it sets the desired MAC to the admin
|
|
|
5c27b6 |
MAC via the PF, then "bounces" the VF driver (by unbinding and the
|
|
|
5c27b6 |
immediately rebinding it to the VF). This causes the VF's MAC to be
|
|
|
5c27b6 |
reinitialized from the admin MAC, and everybody is happy (until the
|
|
|
5c27b6 |
*next* time someone wants to set the VF's MAC address, since the
|
|
|
5c27b6 |
"administratively set" bit is still turned on).
|
|
|
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 86556e167a634599ac9975bd5dad98e3ef9f7017)
|
|
|
5c27b6 |
---
|
|
|
5c27b6 |
src/util/virnetdev.c | 102 +++++++++++++++++++++++++++++++++++++++++----------
|
|
|
5c27b6 |
1 file changed, 83 insertions(+), 19 deletions(-)
|
|
|
5c27b6 |
|
|
|
5c27b6 |
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
|
|
|
5c27b6 |
index 0223877ff..a510ebc2e 100644
|
|
|
5c27b6 |
--- a/src/util/virnetdev.c
|
|
|
5c27b6 |
+++ b/src/util/virnetdev.c
|
|
|
5c27b6 |
@@ -1054,6 +1054,32 @@ virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname,
|
|
|
5c27b6 |
return 0;
|
|
|
5c27b6 |
}
|
|
|
5c27b6 |
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+static virPCIDevicePtr
|
|
|
5c27b6 |
+virNetDevGetPCIDevice(const char *devName)
|
|
|
5c27b6 |
+{
|
|
|
5c27b6 |
+ char *vfSysfsDevicePath = NULL;
|
|
|
5c27b6 |
+ virPCIDeviceAddressPtr vfPCIAddr = NULL;
|
|
|
5c27b6 |
+ virPCIDevicePtr vfPCIDevice = NULL;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevSysfsFile(&vfSysfsDevicePath, devName, "device") < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ vfPCIAddr = virPCIGetDeviceAddressFromSysfsLink(vfSysfsDevicePath);
|
|
|
5c27b6 |
+ if (!vfPCIAddr)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ vfPCIDevice = virPCIDeviceNew(vfPCIAddr->domain, vfPCIAddr->bus,
|
|
|
5c27b6 |
+ vfPCIAddr->slot, vfPCIAddr->function);
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ cleanup:
|
|
|
5c27b6 |
+ VIR_FREE(vfSysfsDevicePath);
|
|
|
5c27b6 |
+ VIR_FREE(vfPCIAddr);
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ return vfPCIDevice;
|
|
|
5c27b6 |
+}
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
/**
|
|
|
5c27b6 |
* virNetDevGetVirtualFunctions:
|
|
|
5c27b6 |
*
|
|
|
5c27b6 |
@@ -2001,6 +2027,7 @@ virNetDevSetNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
char *pfDevOrig = NULL;
|
|
|
5c27b6 |
char *vfDevOrig = NULL;
|
|
|
5c27b6 |
int vlanTag = -1;
|
|
|
5c27b6 |
+ virPCIDevicePtr vfPCIDevice = NULL;
|
|
|
5c27b6 |
|
|
|
5c27b6 |
if (vf >= 0) {
|
|
|
5c27b6 |
/* linkdev is the PF */
|
|
|
5c27b6 |
@@ -2096,6 +2123,8 @@ virNetDevSetNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
}
|
|
|
5c27b6 |
|
|
|
5c27b6 |
if (MAC) {
|
|
|
5c27b6 |
+ int setMACrc;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
if (!linkdev) {
|
|
|
5c27b6 |
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
5c27b6 |
_("VF %d of PF '%s' is not bound to a net driver, "
|
|
|
5c27b6 |
@@ -2104,27 +2133,61 @@ virNetDevSetNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
goto cleanup;
|
|
|
5c27b6 |
}
|
|
|
5c27b6 |
|
|
|
5c27b6 |
- if (virNetDevSetMAC(linkdev, MAC) < 0) {
|
|
|
5c27b6 |
- /* This may have failed due to the "administratively
|
|
|
5c27b6 |
- * set" flag being set in the PF for this VF. For now
|
|
|
5c27b6 |
- * we will just fail, but in the future we should
|
|
|
5c27b6 |
- * attempt to set the VF MAC via the PF.
|
|
|
5c27b6 |
+ setMACrc = virNetDevSetMACInternal(linkdev, MAC, !!pfDevOrig);
|
|
|
5c27b6 |
+ if (setMACrc < 0) {
|
|
|
5c27b6 |
+ bool allowRetry = false;
|
|
|
5c27b6 |
+ int retries = 100;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* if pfDevOrig == NULL, this isn't a VF, so we've failed */
|
|
|
5c27b6 |
+ if (!pfDevOrig || errno != EADDRNOTAVAIL)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* Otherwise this is a VF, and virNetDevSetMAC failed with
|
|
|
5c27b6 |
+ * EADDRNOTAVAIL, which could be due to the
|
|
|
5c27b6 |
+ * "administratively set" flag being set in the PF for
|
|
|
5c27b6 |
+ * this VF. When this happens, we can attempt to use an
|
|
|
5c27b6 |
+ * alternate method to set the VF MAC: first set it into
|
|
|
5c27b6 |
+ * the admin MAC for this VF in the PF, then unbind/rebind
|
|
|
5c27b6 |
+ * the VF from its net driver. This causes the VF's MAC to
|
|
|
5c27b6 |
+ * be initialized to whatever was stored in the admin MAC.
|
|
|
5c27b6 |
*/
|
|
|
5c27b6 |
- goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (virNetDevSetVfConfig(pfDevName, vf,
|
|
|
5c27b6 |
+ MAC, vlanTag, &allowRetry) < 0) {
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+ }
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* admin MAC is set, now we need to construct a virPCIDevice
|
|
|
5c27b6 |
+ * object so we can call virPCIDeviceRebind()
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ if (!(vfPCIDevice = virNetDevGetPCIDevice(linkdev)))
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* Rebind the device. This should set the proper MAC address */
|
|
|
5c27b6 |
+ if (virPCIDeviceRebind(vfPCIDevice) < 0)
|
|
|
5c27b6 |
+ goto cleanup;
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ /* Wait until virNetDevGetIndex for the VF netdev returns success.
|
|
|
5c27b6 |
+ * This indicates that the device is ready to be used. If we don't
|
|
|
5c27b6 |
+ * wait, then upcoming operations on the VF may fail.
|
|
|
5c27b6 |
+ */
|
|
|
5c27b6 |
+ while (retries-- > 0 && !virNetDevExists(linkdev))
|
|
|
5c27b6 |
+ usleep(1000);
|
|
|
5c27b6 |
}
|
|
|
5c27b6 |
- if (pfDevOrig) {
|
|
|
5c27b6 |
- /* if pfDevOrig is set, it means that the caller was
|
|
|
5c27b6 |
- * *really* only interested in setting the MAC of the VF
|
|
|
5c27b6 |
- * itself, *not* the admin MAC via the PF. In those cases,
|
|
|
5c27b6 |
- * the adminMAC was only provided in case we need to set
|
|
|
5c27b6 |
- * the VF's MAC by temporarily unbinding/rebinding the
|
|
|
5c27b6 |
- * VF's net driver with the admin MAC set to the desired
|
|
|
5c27b6 |
- * MAC, and then want to restore the admin MAC to its
|
|
|
5c27b6 |
- * original setting when we're finished. We would only
|
|
|
5c27b6 |
- * need to do that if the virNetDevSetMAC() above had
|
|
|
5c27b6 |
- * failed; since it didn't, we don't need to set the
|
|
|
5c27b6 |
- * adminMAC, so we are NULLing it out here to avoid that
|
|
|
5c27b6 |
- * below.
|
|
|
5c27b6 |
+
|
|
|
5c27b6 |
+ if (pfDevOrig && setMACrc == 0) {
|
|
|
5c27b6 |
+ /* if pfDevOrig is set, it that the caller was *really*
|
|
|
5c27b6 |
+ * only interested in setting the MAC of the VF itself,
|
|
|
5c27b6 |
+ * *not* the admin MAC via the PF. In those cases, the
|
|
|
5c27b6 |
+ * adminMAC was only provided in case we need to set the
|
|
|
5c27b6 |
+ * VF's MAC by temporarily unbinding/rebinding the VF's
|
|
|
5c27b6 |
+ * net driver with the admin MAC set to the desired MAC,
|
|
|
5c27b6 |
+ * and then want to restore the admin MAC to its original
|
|
|
5c27b6 |
+ * setting when we're finished. We would only need to do
|
|
|
5c27b6 |
+ * that if the virNetDevSetMAC() above had failed; since
|
|
|
5c27b6 |
+ * setMACrc == 0, we know it didn't fail and we don't need
|
|
|
5c27b6 |
+ * to set the adminMAC, so we are NULLing it out here to
|
|
|
5c27b6 |
+ * avoid that below.
|
|
|
5c27b6 |
|
|
|
5c27b6 |
* (NB: since setting the admin MAC sets the
|
|
|
5c27b6 |
* "administratively set" flag for the VF in the PF's
|
|
|
5c27b6 |
@@ -2168,6 +2231,7 @@ virNetDevSetNetConfig(const char *linkdev, int vf,
|
|
|
5c27b6 |
cleanup:
|
|
|
5c27b6 |
VIR_FREE(pfDevOrig);
|
|
|
5c27b6 |
VIR_FREE(vfDevOrig);
|
|
|
5c27b6 |
+ virPCIDeviceFree(vfPCIDevice);
|
|
|
5c27b6 |
return ret;
|
|
|
5c27b6 |
}
|
|
|
5c27b6 |
|
|
|
5c27b6 |
--
|
|
|
5c27b6 |
2.12.2
|
|
|
5c27b6 |
|