Blob Blame History Raw
From 68e16ab92310206b28471434ff80f90b4fcf987b Mon Sep 17 00:00:00 2001
Message-Id: <68e16ab92310206b28471434ff80f90b4fcf987b@dist-git>
From: Laine Stump <laine@laine.org>
Date: Mon, 3 Nov 2014 10:00:21 -0500
Subject: [PATCH] qemu: change macvtap device MAC address in response to
 NIC_RX_FILTER_CHANGED

https://bugzilla.redhat.com/show_bug.cgi?id=848199

This patch fills in the functionality of
processNicRxFilterChangedEvent().  It now checks if it is appropriate
to respond to the NIC_RX_FILTER_CHANGED event (based on device type
and configuration) and takes appropriate action. Currently it checks
if the guest interface has been configured with
trustGuestRxFilters='yes', and if the host side device is macvtap. If
so, and the MAC address on the guest has changed, the MAC address of
the macvtap device is changed to match.

The result of this is that networking from the guest will continue to
work if the mac address of a macvtap-connected network device is
changed from within the guest, as long as trustGuestRxFilters='yes'
(previously changing the MAC address in the guest would break
networking).

(cherry picked from commit db6b738dde047c9b38ed41add5d00bbbdb7c5daa)

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/qemu/qemu_driver.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 29deb76..229836f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4153,8 +4153,13 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
                                char *devAlias)
 {
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    qemuDomainObjPrivatePtr priv = vm->privateData;
     virDomainDeviceDef dev;
     virDomainNetDefPtr def;
+    virNetDevRxFilterPtr filter = NULL;
+    virMacAddr oldMAC;
+    char newMacStr[VIR_MAC_STRING_BUFLEN];
+    int ret;
 
     VIR_DEBUG("Received NIC_RX_FILTER_CHANGED event for device %s "
               "from domain %p %s",
@@ -4182,11 +4187,55 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
     }
     def = dev.data.net;
 
+    if (!virDomainNetGetActualTrustGuestRxFilters(def)) {
+        VIR_WARN("ignore NIC_RX_FILTER_CHANGED event for network "
+                  "device %s in domain %s",
+                  def->info.alias, vm->def->name);
+        /* not sending "query-rx-filter" will also suppress any
+         * further NIC_RX_FILTER_CHANGED events for this device
+         */
+        goto endjob;
+    }
+
     /* handle the event - send query-rx-filter and respond to it. */
 
     VIR_DEBUG("process NIC_RX_FILTER_CHANGED event for network "
               "device %s in domain %s", def->info.alias, vm->def->name);
 
+    qemuDomainObjEnterMonitor(driver, vm);
+    ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &filter);
+    qemuDomainObjExitMonitor(driver, vm);
+    if (ret < 0)
+        goto endjob;
+
+    virMacAddrFormat(&filter->mac, newMacStr);
+
+    if (virDomainNetGetActualType(def) == VIR_DOMAIN_NET_TYPE_DIRECT) {
+
+        /* For macvtap connections, set the macvtap device's MAC
+         * address to match that of the guest device.
+         */
+
+        if (virNetDevGetMAC(def->ifname, &oldMAC) < 0) {
+            VIR_WARN("Couldn't get current MAC address of device %s "
+                     "while responding to NIC_RX_FILTER_CHANGED",
+                     def->ifname);
+            goto endjob;
+        }
+
+        if (virMacAddrCmp(&oldMAC, &filter->mac)) {
+            /* set new MAC address from guest to associated macvtap device */
+            if (virNetDevSetMAC(def->ifname, &filter->mac) < 0) {
+                VIR_WARN("Couldn't set new MAC address %s to device %s "
+                         "while responding to NIC_RX_FILTER_CHANGED",
+                         newMacStr, def->ifname);
+            } else {
+                VIR_DEBUG("device %s MAC address set to %s",
+                          def->ifname, newMacStr);
+            }
+        }
+    }
+
  endjob:
     /* We had an extra reference to vm before starting a new job so ending the
      * job is guaranteed not to remove the last reference.
@@ -4194,6 +4243,7 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
     ignore_value(qemuDomainObjEndJob(driver, vm));
 
  cleanup:
+    virNetDevRxFilterFree(filter);
     VIR_FREE(devAlias);
     virObjectUnref(cfg);
 }
-- 
2.1.3