When libvirt is managing a bridge's forwarding database (FDB)
(macTableManager='libvirt'), if we add FDB entries for a new guest
interface even before the qemu process is created, then in the case of
a migration any other guest attached to the "destination" bridge will
have its traffic immediately sent to the destination of the migration
even while the source domain is still running (and the destination, of
course, isn't). To make sure that traffic from other guests on the new
host continues flowing to the old guest until the new one is ready, we
have to wait until the new guest CPUs are started to add the FDB
entries.
Conversely, we need to remove the FDB entries from the bridge any time
the guest CPUs are stopped; among other things, this will assure
proper operation during a post-copy migration (which is just the
opposite of the problem described in the previous paragraph).
---
src/qemu/qemu_command.c | 10 +++-------
src/qemu/qemu_interface.c | 26 ++++++++++++++++++++++++++
2 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 48bdf4e..f4d2f85 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -335,18 +335,14 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
/* libvirt is managing the FDB of the bridge this device
* is attaching to, so we need to turn off learning and
* unicast_flood on the device to prevent the kernel from
- * adding any FDB entries for it, then add an fdb entry
- * outselves, using the MAC address from the interface
- * config.
+ * adding any FDB entries for it. We will add add an fdb
+ * entry ourselves (during qemuInterfaceStartDevices(),
+ * using the MAC address from the interface config.
*/
if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
goto cleanup;
if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) <
0)
goto cleanup;
- if (virNetDevBridgeFDBAdd(&net->mac, net->ifname,
- VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
- VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
- goto cleanup;
}
} else {
if (qemuCreateInBridgePortWithHelper(cfg, brname,
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index b9694c8..4e16521 100644
--- a/src/qemu/qemu_interface.c
+++ b/src/qemu/qemu_interface.c
@@ -23,10 +23,12 @@
#include <config.h>
+#include "network_conf.h"
#include "qemu_interface.h"
#include "virnetdev.h"
#include "virnetdevtap.h"
#include "virnetdevmacvlan.h"
+#include "virnetdevbridge.h"
#include "virnetdevvportprofile.h"
/**
@@ -45,6 +47,20 @@ qemuInterfaceStartDevice(virDomainNetDefPtr net)
switch (virDomainNetGetActualType(net)) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
+ if (virDomainNetGetActualBridgeMACTableManager(net)
+ == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
+ /* libvirt is managing the FDB of the bridge this device
+ * is attaching to, so we have turned off learning and
+ * unicast_flood on the device to prevent the kernel from
+ * adding any FDB entries for it. This means we need to
+ * add an fdb entry ourselves, using the MAC address from
+ * the interface config.
+ */
+ if (virNetDevBridgeFDBAdd(&net->mac, net->ifname,
+ VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
+ VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
+ goto cleanup;
+ }
break;
case VIR_DOMAIN_NET_TYPE_DIRECT:
/* macvtap devices share their MAC address with the guest
@@ -116,6 +132,16 @@ qemuInterfaceStopDevice(virDomainNetDefPtr net)
switch (virDomainNetGetActualType(net)) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
+ if (virDomainNetGetActualBridgeMACTableManager(net)
+ == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
+ /* remove the FDB entries that were added during
+ * qemuInterfaceStartDevices()
+ */
+ if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
+ VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
+ VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
+ goto cleanup;
+ }
break;
case VIR_DOMAIN_NET_TYPE_DIRECT:
--
1.9.3