At the time that the network driver allocates a connection to a
network, the tap device that will be used hasn't yet been created -
that will be done later by qemu (or lxc or whoever) - but if the
network has fdb='managed', then when we do get around to creating the
tap device, we will need to add an entry for it to the network
bridge's fdb (forwarding database) *and* turn off learning and
unicast_flood for that tap device in the bridge's sysfs settings. This
means that qemu needs to know both the bridge name as well as the
setting of fdb, so we either need to create a new API to retrieve that
info, or just pass it back in the ActualNetDef that is created during
networkAllocateActualDevice. We choose the latter method, since it's
already done for the bridge device, and it has the side effect of
making the information available in domain status.
(NB: in the future, I think that the tap device should actually be
created by networkAllocateActualDevice(), as that will solve several
other problems, but that is a battle for another day, and this
information will still be useful outside the network driver)
---
Changes from V1: Only names of attribute and its values
src/conf/domain_conf.c | 29 +++++++++++++++++++++++++++++
src/conf/domain_conf.h | 2 ++
src/libvirt_private.syms | 1 +
src/network/bridge_driver.c | 4 +++-
4 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index c4fb902..3a9f7a5 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -51,6 +51,7 @@
#include "netdev_bandwidth_conf.h"
#include "netdev_vlan_conf.h"
#include "device_conf.h"
+#include "network_conf.h"
#include "virtpm.h"
#include "virstring.h"
@@ -7003,6 +7004,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
char *mode = NULL;
char *addrtype = NULL;
char *trustGuestRxFilters = NULL;
+ char *fdb = NULL;
if (VIR_ALLOC(actual) < 0)
return -1;
@@ -7119,6 +7121,15 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
goto error;
}
actual->data.bridge.brname = brname;
+ fdb = virXPathString("string(./source/@fdb)", ctxt);
+ if (fdb &&
+ (actual->data.bridge.fdb
+ = virNetworkBridgeFDBTypeFromString(fdb)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid fdb setting '%s' "
+ "in domain interface's <actual>
element"), fdb);
+ goto error;
+ }
}
bandwidth_node = virXPathNode("./bandwidth", ctxt);
@@ -7139,6 +7150,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
VIR_FREE(mode);
VIR_FREE(addrtype);
VIR_FREE(trustGuestRxFilters);
+ VIR_FREE(fdb);
virDomainActualNetDefFree(actual);
ctxt->node = save_ctxt;
@@ -17156,12 +17168,18 @@ virDomainActualNetDefContentsFormat(virBufferPtr buf,
}
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
+ int fdb = virDomainNetGetActualFDB(def);
+
/* actualType == NETWORK includes the name of the bridge
* that is used by the network, whether we are
* "inSubElement" or not.
*/
virBufferEscapeString(buf, " bridge='%s'",
virDomainNetGetActualBridgeName(def));
+ if (fdb) {
+ virBufferAsprintf(buf, " fdb='%s'",
+ virNetworkBridgeFDBTypeToString(fdb));
+ }
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
const char *mode;
@@ -20760,6 +20778,17 @@ virDomainNetGetActualBridgeName(virDomainNetDefPtr iface)
return NULL;
}
+int
+virDomainNetGetActualFDB(virDomainNetDefPtr iface)
+{
+ if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
+ iface->data.network.actual &&
+ (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_NETWORK))
+ return iface->data.network.actual->data.bridge.fdb;
+ return 0;
+}
+
const char *
virDomainNetGetActualDirectDev(virDomainNetDefPtr iface)
{
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 439f3c0..1194f20 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -888,6 +888,7 @@ struct _virDomainActualNetDef {
union {
struct {
char *brname;
+ int fdb; /* enum virNetworkBridgeFDBType */
} bridge;
struct {
char *linkdev;
@@ -2540,6 +2541,7 @@ int virDomainGraphicsListenSetNetwork(virDomainGraphicsDefPtr def,
int virDomainNetGetActualType(virDomainNetDefPtr iface);
const char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface);
+int virDomainNetGetActualFDB(virDomainNetDefPtr iface);
const char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface);
int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface);
virDomainHostdevDefPtr virDomainNetGetActualHostdev(virDomainNetDefPtr iface);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 703cba8..9fc01f3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -331,6 +331,7 @@ virDomainNetGetActualBandwidth;
virDomainNetGetActualBridgeName;
virDomainNetGetActualDirectDev;
virDomainNetGetActualDirectMode;
+virDomainNetGetActualFDB;
virDomainNetGetActualHostdev;
virDomainNetGetActualTrustGuestRxFilters;
virDomainNetGetActualType;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 82b301a..3299cd6 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -3790,7 +3790,7 @@ networkAllocateActualDevice(virDomainDefPtr dom,
*/
iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
- /* we also store the bridge device
+ /* we also store the bridge device and fdb settings
* in iface->data.network.actual->data.bridge for later use
* after the domain's tap device is created (to attach to the
* bridge and set flood/learning mode on the tap device)
@@ -3798,6 +3798,7 @@ networkAllocateActualDevice(virDomainDefPtr dom,
if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
netdef->bridge) < 0)
goto error;
+ iface->data.network.actual->data.bridge.fdb = netdef->fdb;
if (networkPlugBandwidth(network, iface) < 0)
goto error;
@@ -3813,6 +3814,7 @@ networkAllocateActualDevice(virDomainDefPtr dom,
if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
netdef->bridge) < 0)
goto error;
+ iface->data.network.actual->data.bridge.fdb = netdef->fdb;
/* merge virtualports from interface, network, and portgroup to
* arrive at actual virtualport to use
--
1.9.3