Blob Blame History Raw
From b470923607cb80c282b2484de081b15781faeb7c Mon Sep 17 00:00:00 2001
Message-Id: <b470923607cb80c282b2484de081b15781faeb7c@dist-git>
From: Tony Krowiak <akrowiak@linux.vnet.ibm.com>
Date: Mon, 3 Nov 2014 10:00:23 -0500
Subject: [PATCH] qemu: change macvtap multicast list in response to
 NIC_RX_FILTER_CHANGED

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

This patch adds functionality to processNicRxFilterChangedEvent().
The old and new multicast lists are compared and the filters in
the macvtap are programmed to match the guest's filters.

Signed-off-by: Tony Krowiak <akrowiak@linux.vnet.ibm.com>
(cherry picked from commit d70cc1fa7219b347a301e132bb927f41958b372d)
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/qemu/qemu_driver.c | 138 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 114 insertions(+), 24 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 229836f..3812615 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4148,6 +4148,106 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver,
 
 
 static void
+syncNicRxFilterMacAddr(char *ifname, virNetDevRxFilterPtr guestFilter,
+                       virNetDevRxFilterPtr hostFilter)
+{
+    char newMacStr[VIR_MAC_STRING_BUFLEN];
+
+    if (virMacAddrCmp(&hostFilter->mac, &guestFilter->mac)) {
+        virMacAddrFormat(&guestFilter->mac, newMacStr);
+
+        /* set new MAC address from guest to associated macvtap device */
+        if (virNetDevSetMAC(ifname, &guestFilter->mac) < 0) {
+            VIR_WARN("Couldn't set new MAC address %s to device %s "
+                     "while responding to NIC_RX_FILTER_CHANGED",
+                     newMacStr, ifname);
+        } else {
+            VIR_DEBUG("device %s MAC address set to %s", ifname, newMacStr);
+        }
+    }
+}
+
+
+static void
+syncNicRxFilterGuestMulticast(char *ifname, virNetDevRxFilterPtr guestFilter,
+                              virNetDevRxFilterPtr hostFilter)
+{
+    size_t i, j;
+    bool found;
+    char macstr[VIR_MAC_STRING_BUFLEN];
+
+    for (i = 0; i < guestFilter->multicast.nTable; i++) {
+        found = false;
+
+        for (j = 0; j < hostFilter->multicast.nTable; j++) {
+            if (virMacAddrCmp(&guestFilter->multicast.table[i],
+                              &hostFilter->multicast.table[j]) == 0) {
+                found = true;
+                break;
+            }
+        }
+
+        if (!found) {
+            virMacAddrFormat(&guestFilter->multicast.table[i], macstr);
+
+            if (virNetDevAddMulti(ifname, &guestFilter->multicast.table[i]) < 0) {
+                VIR_WARN("Couldn't add new multicast MAC address %s to "
+                         "device %s while responding to NIC_RX_FILTER_CHANGED",
+                         macstr, ifname);
+            } else {
+                VIR_DEBUG("Added multicast MAC %s to %s interface",
+                          macstr, ifname);
+            }
+        }
+    }
+}
+
+
+static void
+syncNicRxFilterHostMulticast(char *ifname, virNetDevRxFilterPtr guestFilter,
+                             virNetDevRxFilterPtr hostFilter)
+{
+    size_t i, j;
+    bool found;
+    char macstr[VIR_MAC_STRING_BUFLEN];
+
+    for (i = 0; i < hostFilter->multicast.nTable; i++) {
+        found = false;
+
+        for (j = 0; j < guestFilter->multicast.nTable; j++) {
+            if (virMacAddrCmp(&hostFilter->multicast.table[i],
+                              &guestFilter->multicast.table[j]) == 0) {
+                found = true;
+                break;
+            }
+        }
+
+        if (!found) {
+            virMacAddrFormat(&hostFilter->multicast.table[i], macstr);
+
+            if (virNetDevDelMulti(ifname, &hostFilter->multicast.table[i]) < 0) {
+                VIR_WARN("Couldn't delete multicast MAC address %s from "
+                         "device %s while responding to NIC_RX_FILTER_CHANGED",
+                         macstr, ifname);
+            } else {
+                VIR_DEBUG("Deleted multicast MAC %s from %s interface",
+                          macstr, ifname);
+            }
+        }
+    }
+}
+
+
+static void
+syncNicRxFilterMulticast(char *ifname,
+                         virNetDevRxFilterPtr guestFilter,
+                         virNetDevRxFilterPtr hostFilter)
+{
+    syncNicRxFilterGuestMulticast(ifname, guestFilter, hostFilter);
+    syncNicRxFilterHostMulticast(ifname, guestFilter, hostFilter);
+}
+
+static void
 processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                char *devAlias)
@@ -4156,9 +4256,8 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
     qemuDomainObjPrivatePtr priv = vm->privateData;
     virDomainDeviceDef dev;
     virDomainNetDefPtr def;
-    virNetDevRxFilterPtr filter = NULL;
-    virMacAddr oldMAC;
-    char newMacStr[VIR_MAC_STRING_BUFLEN];
+    virNetDevRxFilterPtr guestFilter = NULL;
+    virNetDevRxFilterPtr hostFilter = NULL;
     int ret;
 
     VIR_DEBUG("Received NIC_RX_FILTER_CHANGED event for device %s "
@@ -4203,37 +4302,27 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
               "device %s in domain %s", def->info.alias, vm->def->name);
 
     qemuDomainObjEnterMonitor(driver, vm);
-    ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &filter);
+    ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &guestFilter);
     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 "
+        if (virNetDevGetRxFilter(def->ifname, &hostFilter)) {
+            VIR_WARN("Couldn't get current RX filter for 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);
-            }
-        }
+        /* For macvtap connections, set the following macvtap network device
+         * attributes to match those of the guest network device:
+         * - MAC address
+         * - Multicast MAC address table
+         */
+        syncNicRxFilterMacAddr(def->ifname, guestFilter, hostFilter);
+        syncNicRxFilterMulticast(def->ifname, guestFilter, hostFilter);
     }
 
  endjob:
@@ -4243,7 +4332,8 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
     ignore_value(qemuDomainObjEndJob(driver, vm));
 
  cleanup:
-    virNetDevRxFilterFree(filter);
+    virNetDevRxFilterFree(hostFilter);
+    virNetDevRxFilterFree(guestFilter);
     VIR_FREE(devAlias);
     virObjectUnref(cfg);
 }
-- 
2.1.3