qemu: add/remove bridge fdb entries as guest CPUs are started/stopped

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).
This commit is contained in:
Laine Stump 2014-12-10 12:41:16 -05:00
parent 9603bce7b1
commit 44292e48a0
2 changed files with 29 additions and 7 deletions

View File

@ -335,18 +335,14 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
/* libvirt is managing the FDB of the bridge this device /* libvirt is managing the FDB of the bridge this device
* is attaching to, so we need to turn off learning and * is attaching to, so we need to turn off learning and
* unicast_flood on the device to prevent the kernel from * unicast_flood on the device to prevent the kernel from
* adding any FDB entries for it, then add an fdb entry * adding any FDB entries for it. We will add add an fdb
* outselves, using the MAC address from the interface * entry ourselves (during qemuInterfaceStartDevices(),
* config. * using the MAC address from the interface config.
*/ */
if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0) if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
goto cleanup; goto cleanup;
if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0) if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)
goto cleanup; goto cleanup;
if (virNetDevBridgeFDBAdd(&net->mac, net->ifname,
VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
goto cleanup;
} }
} else { } else {
if (qemuCreateInBridgePortWithHelper(cfg, brname, if (qemuCreateInBridgePortWithHelper(cfg, brname,

View File

@ -23,10 +23,12 @@
#include <config.h> #include <config.h>
#include "network_conf.h"
#include "qemu_interface.h" #include "qemu_interface.h"
#include "virnetdev.h" #include "virnetdev.h"
#include "virnetdevtap.h" #include "virnetdevtap.h"
#include "virnetdevmacvlan.h" #include "virnetdevmacvlan.h"
#include "virnetdevbridge.h"
#include "virnetdevvportprofile.h" #include "virnetdevvportprofile.h"
/** /**
@ -46,6 +48,20 @@ qemuInterfaceStartDevice(virDomainNetDefPtr net)
switch (actualType) { switch (actualType) {
case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK: 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; break;
case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_DIRECT:
/* macvtap devices share their MAC address with the guest /* macvtap devices share their MAC address with the guest
@ -118,6 +134,16 @@ qemuInterfaceStopDevice(virDomainNetDefPtr net)
switch (actualType) { switch (actualType) {
case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK: 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; break;
case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_DIRECT: