[libvirt] [PATCHv2 3/9] conf: new network bridge device attribute fdb

Laine Stump laine at laine.org
Tue Dec 2 17:08:33 UTC 2014


The fdb attribute of a network's bridge subelement tells libvirt how
the bridge's forwarding database (fdb) is managed. In the default
mode, "learningWithFlood", management of fdb entries is left to the
kernel, which determines entries in part by turning on promiscuous
mode on all ports of the bridge, flooding packets to all ports when
the correct destination is unknown, and adding/removing entries to the
fdb as it sees incoming traffic from particular MAC addresses.  In
"managed" mode, libvirt turns off learning and floowing on all the
bridge ports connected to guest domain interfaces, and adds/removes
fdb entries according to the MAC addresses in the domain interface
configurations. A side effect of turning off learning and
unicast_flood on the ports of a bridge is that (with Linux kernel 3.17
and newer), the kernel can automatically turn off promiscuous mode one
or more of the bridge's ports (usually only the one interface that is
used to connect the bridge to the physical network). The result is
better performance (because packets aren't being flooded to all ports,
and can be dropped earlier when they are of no interest) and better
security (since a guest will only receive traffic intended for the
guest interface's configured MAC address).

The attribute looks like this in the configuration:

  <network>
    <name>test</name>
    <bridge name='br0' fdb='managed'/>
    ...

This patch only adds the config knob, documentation, and test
cases. The functionality behind this knob is added in later patches.
---

Changes from V1: Changed name and values of attribute, as outlined in
the patchset cover letter.

 docs/formatnetwork.html.in                         | 42 +++++++++++++++---
 docs/schemas/network.rng                           |  9 ++++
 src/conf/network_conf.c                            | 50 +++++++++++++++++-----
 src/conf/network_conf.h                            | 11 +++++
 src/libvirt_private.syms                           |  2 +
 tests/networkxml2xmlin/host-bridge-no-flood.xml    |  6 +++
 .../nat-network-explicit-flood.xml                 | 21 +++++++++
 tests/networkxml2xmlout/host-bridge-no-flood.xml   |  6 +++
 .../nat-network-explicit-flood.xml                 | 23 ++++++++++
 tests/networkxml2xmltest.c                         |  2 +
 10 files changed, 155 insertions(+), 17 deletions(-)
 create mode 100644 tests/networkxml2xmlin/host-bridge-no-flood.xml
 create mode 100644 tests/networkxml2xmlin/nat-network-explicit-flood.xml
 create mode 100644 tests/networkxml2xmlout/host-bridge-no-flood.xml
 create mode 100644 tests/networkxml2xmlout/nat-network-explicit-flood.xml

diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index dc438ae..e624e1d 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -81,7 +81,7 @@
 
     <pre>
         ...
-        <bridge name="virbr0" stp="on" delay="5"/>
+        <bridge name="virbr0" stp="on" delay="5" fdb="managed"/>
         <domain name="example.com"/>
         <forward mode="nat" dev="eth0"/>
         ...</pre>
@@ -92,18 +92,48 @@
         defines the name of a bridge device which will be used to construct
         the virtual network. The virtual machines will be connected to this
         bridge device allowing them to talk to each other. The bridge device
-        may also be connected to the LAN. It is recommended that bridge
-        device names started with the prefix <code>vir</code>, but the name
-        <code>virbr0</code> is reserved for the "default" virtual
-        network.  This element should always be provided when defining
+        may also be connected to the LAN. When defining
         a new network with a <code><forward></code> mode of
+
         "nat" or "route" (or an isolated network with
-        no <code><forward></code> element).
+        no <code><forward></code> element), libvirt will
+        automatically generate a unique name for the bridge device if
+        none is given, and this name will be permanently stored in the
+        network configuration so that that the same name will be used
+        every time the network is started. For these types of networks
+        (nat, routed, and isolated), a bridge name beginning with the
+        prefix "virbr" is recommended (and that is what is
+        auto-generated), but not enforced.
         Attribute <code>stp</code> specifies if Spanning Tree Protocol
         is 'on' or 'off' (default is
         'on'). Attribute <code>delay</code> sets the bridge's forward
         delay value in seconds (default is 0).
         <span class="since">Since 0.3.0</span>
+
+        <p>
+          The <code>fdb</code> attribute of the bridge element is used
+          to tell libvirt how the bridge's forwarding database (fdb)
+          will be updated. In the default
+          mode <code>learningWithFlood</code>, the kernel
+          automatically adds and removes entries, using bridge
+          learning, flooding, and promiscuous mode on the bridge's
+          ports in order to determine the proper destination for
+          packets.  In <code>managed</code> mode, libvirt disables
+          learning and unicast_flooding on all bridge ports connected
+          to guest domain interfaces, and explicitly adds entries to
+          the fdb based on the MAC addresses in the domain interface
+          configurations. Turning off learning and unicast_flood can
+          also permit the kernel to turn off promiscuous mode on some
+          ports of the bridge, and the combination of turning off
+          these three settings can improve performance and provide
+          better security, but can also cause some networking setups
+          to stop working (e.g. vlan tagging, multicast) and is not
+          supported by older kernels.
+          <span class="since">Since 1.2.11, requires kernel 3.17 or
+          newer</span>
+        </p>
+
+
       </dd>
       <dt><code>domain</code></dt>
       <dd>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 4546f80..cc0095b 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -65,6 +65,15 @@
               </attribute>
             </optional>
 
+            <optional>
+              <attribute name="fdb">
+                <choice>
+                  <value>learningWithFlood</value>
+                  <value>managed</value>
+                </choice>
+              </attribute>
+            </optional>
+
           </element>
         </optional>
 
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index a249e32..4c5809d 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -55,6 +55,10 @@ VIR_ENUM_IMPL(virNetworkForward,
               VIR_NETWORK_FORWARD_LAST,
               "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev")
 
+VIR_ENUM_IMPL(virNetworkBridgeFDB,
+              VIR_NETWORK_BRIDGE_FDB_LAST,
+              "absent", "learningWithFlood", "managed")
+
 VIR_ENUM_DECL(virNetworkForwardHostdevDevice)
 VIR_ENUM_IMPL(virNetworkForwardHostdevDevice,
               VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST,
@@ -2108,6 +2112,17 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
     }
     VIR_FREE(tmp);
 
+    tmp = virXPathString("string(./bridge[1]/@fdb)", ctxt);
+    if (tmp) {
+        if ((def->fdb = virNetworkBridgeFDBTypeFromString(tmp)) <= 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid fdb setting '%s' "
+                             "in network '%s'"), tmp, def->name);
+            goto error;
+        }
+        VIR_FREE(tmp);
+    }
+
     tmp = virXPathString("string(./mac[1]/@address)", ctxt);
     if (tmp) {
         if (virMacAddrParse(tmp, &def->mac) < 0) {
@@ -2290,6 +2305,14 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
                            def->name);
             goto error;
         }
+        if (def->fdb) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("bridge fdb setting not allowed "
+                             "in %s mode (network '%s')"),
+                           virNetworkForwardTypeToString(def->forward.type),
+                           def->name);
+            goto error;
+        }
         /* fall through to next case */
     case VIR_NETWORK_FORWARD_BRIDGE:
         if (def->delay || stp) {
@@ -2783,22 +2806,27 @@ virNetworkDefFormatBuf(virBufferPtr buf,
             virBufferAddLit(buf, "</forward>\n");
     }
 
+
     if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
-         def->forward.type == VIR_NETWORK_FORWARD_NAT ||
-         def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
+        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
+        def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
+        def->bridge || def->fdb) {
 
         virBufferAddLit(buf, "<bridge");
-        if (def->bridge)
-            virBufferEscapeString(buf, " name='%s'", def->bridge);
-        virBufferAsprintf(buf, " stp='%s' delay='%ld'/>\n",
-                          def->stp ? "on" : "off",
-                          def->delay);
-    } else if (def->forward.type == VIR_NETWORK_FORWARD_BRIDGE &&
-               def->bridge) {
-        virBufferEscapeString(buf, "<bridge name='%s'/>\n", def->bridge);
+        virBufferEscapeString(buf, " name='%s'", def->bridge);
+        if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
+            def->forward.type == VIR_NETWORK_FORWARD_NAT ||
+            def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
+            virBufferAsprintf(buf, " stp='%s' delay='%ld'",
+                              def->stp ? "on" : "off", def->delay);
+        }
+        if (def->fdb) {
+            virBufferAsprintf(buf, " fdb='%s'",
+                             virNetworkBridgeFDBTypeToString(def->fdb));
+        }
+        virBufferAddLit(buf, "/>\n");
     }
 
-
     if (def->mac_specified) {
         char macaddr[VIR_MAC_STRING_BUFLEN];
         virMacAddrFormat(&def->mac, macaddr);
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 660cd2d..cf9b743 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -54,6 +54,16 @@ typedef enum {
 } virNetworkForwardType;
 
 typedef enum {
+   VIR_NETWORK_BRIDGE_FDB_ABSENT = 0,
+   VIR_NETWORK_BRIDGE_FDB_AUTO,
+   VIR_NETWORK_BRIDGE_FDB_MANAGED,
+
+   VIR_NETWORK_BRIDGE_FDB_LAST,
+} virNetworkBridgeFDBType;
+
+VIR_ENUM_DECL(virNetworkBridgeFDB)
+
+typedef enum {
     VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE = 0,
     VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI,
     VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV,
@@ -231,6 +241,7 @@ struct _virNetworkDef {
     int   connections; /* # of guest interfaces connected to this network */
 
     char *bridge;       /* Name of bridge device */
+    int  fdb; /* enum virNetworkBridgeFDBType - default is learningWithFlood */
     char *domain;
     unsigned long delay;   /* Bridge forward delay (ms) */
     bool stp; /* Spanning tree protocol */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 6b6c51b..703cba8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -529,6 +529,8 @@ virNetDevVPortTypeToString;
 
 # conf/network_conf.h
 virNetworkAssignDef;
+virNetworkBridgeFDBTypeFromString;
+virNetworkBridgeFDBTypeToString;
 virNetworkConfigChangeSetup;
 virNetworkConfigFile;
 virNetworkDefCopy;
diff --git a/tests/networkxml2xmlin/host-bridge-no-flood.xml b/tests/networkxml2xmlin/host-bridge-no-flood.xml
new file mode 100644
index 0000000..d5fced0
--- /dev/null
+++ b/tests/networkxml2xmlin/host-bridge-no-flood.xml
@@ -0,0 +1,6 @@
+<network>
+  <name>host-bridge-net</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+  <forward mode="bridge"/>
+  <bridge name="br0" fdb='managed'/>
+</network>
diff --git a/tests/networkxml2xmlin/nat-network-explicit-flood.xml b/tests/networkxml2xmlin/nat-network-explicit-flood.xml
new file mode 100644
index 0000000..d6fa1b7
--- /dev/null
+++ b/tests/networkxml2xmlin/nat-network-explicit-flood.xml
@@ -0,0 +1,21 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <bridge name="virbr0" fdb="learningWithFlood"/>
+  <forward mode="nat" dev="eth1"/>
+  <ip address="192.168.122.1" netmask="255.255.255.0">
+    <dhcp>
+      <range start="192.168.122.2" end="192.168.122.254"/>
+      <host mac="00:16:3e:77:e2:ed" name="a.example.com" ip="192.168.122.10"/>
+      <host mac="00:16:3e:3e:a9:1a" name="b.example.com" ip="192.168.122.11"/>
+    </dhcp>
+  </ip>
+  <ip family="ipv4" address="192.168.123.1" netmask="255.255.255.0">
+  </ip>
+  <ip family="ipv6" address="2001:db8:ac10:fe01::1" prefix="64">
+  </ip>
+  <ip family="ipv6" address="2001:db8:ac10:fd01::1" prefix="64">
+  </ip>
+  <ip family="ipv4" address="10.24.10.1">
+  </ip>
+</network>
diff --git a/tests/networkxml2xmlout/host-bridge-no-flood.xml b/tests/networkxml2xmlout/host-bridge-no-flood.xml
new file mode 100644
index 0000000..ff07943
--- /dev/null
+++ b/tests/networkxml2xmlout/host-bridge-no-flood.xml
@@ -0,0 +1,6 @@
+<network>
+  <name>host-bridge-net</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+  <forward mode='bridge'/>
+  <bridge name='br0' fdb='managed'/>
+</network>
diff --git a/tests/networkxml2xmlout/nat-network-explicit-flood.xml b/tests/networkxml2xmlout/nat-network-explicit-flood.xml
new file mode 100644
index 0000000..340f6bb
--- /dev/null
+++ b/tests/networkxml2xmlout/nat-network-explicit-flood.xml
@@ -0,0 +1,23 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward dev='eth1' mode='nat'>
+    <interface dev='eth1'/>
+  </forward>
+  <bridge name='virbr0' stp='on' delay='0' fdb='learningWithFlood'/>
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
+    <dhcp>
+      <range start='192.168.122.2' end='192.168.122.254'/>
+      <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10'/>
+      <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11'/>
+    </dhcp>
+  </ip>
+  <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+  </ip>
+  <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+  </ip>
+  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+  </ip>
+  <ip family='ipv4' address='10.24.10.1'>
+  </ip>
+</network>
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index 65ac591..34a5211 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -120,6 +120,8 @@ mymain(void)
     DO_TEST("hostdev");
     DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE);
     DO_TEST("passthrough-address-crash");
+    DO_TEST("nat-network-explicit-flood");
+    DO_TEST("host-bridge-no-flood");
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
1.9.3




More information about the libvir-list mailing list