]> xenbits.xensource.com Git - libvirt.git/commitdiff
conf: new network bridge device attribute macTableManager
authorLaine Stump <laine@laine.org>
Thu, 20 Nov 2014 17:40:33 +0000 (12:40 -0500)
committerLaine Stump <laine@laine.org>
Mon, 8 Dec 2014 19:41:37 +0000 (14:41 -0500)
The macTableManager attribute of a network's bridge subelement tells
libvirt how the bridge's MAC address table (used to determine the
egress port for packets) is managed. In the default mode, "kernel",
management is left to the kernel, which usually 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 "libvirt" mode, libvirt turns off
learning and flooding on all the bridge ports connected to guest
domain interfaces, and adds/removes 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 on 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 slightly better security (a guest
can still send out packets with a spoofed source MAC address, but 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' macTableManager='libvirt'/>
    ...

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

docs/formatnetwork.html.in
docs/schemas/network.rng
src/conf/network_conf.c
src/conf/network_conf.h
src/libvirt_private.syms
tests/networkxml2xmlin/host-bridge-no-flood.xml [new file with mode: 0644]
tests/networkxml2xmlin/nat-network-explicit-flood.xml [new file with mode: 0644]
tests/networkxml2xmlout/host-bridge-no-flood.xml [new file with mode: 0644]
tests/networkxml2xmlout/nat-network-explicit-flood.xml [new file with mode: 0644]
tests/networkxml2xmltest.c

index 7bcf316a6fe2919c7919028e16f9d0d2c6c7ea77..ca0e20709c902657534fff01369cb1f44c0cc940 100644 (file)
@@ -81,7 +81,7 @@
 
     <pre>
         ...
-        &lt;bridge name="virbr0" stp="on" delay="5"/&gt;
+        &lt;bridge name="virbr0" stp="on" delay="5" macTableManager="libvirt"/&gt;
         &lt;domain name="example.com"/&gt;
         &lt;forward mode="nat" dev="eth0"/&gt;
         ...</pre>
         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>&lt;forward&gt;</code> mode of
+
         "nat" or "route" (or an isolated network with
-        no <code>&lt;forward&gt;</code> element).
+        no <code>&lt;forward&gt;</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>macTableManager</code> attribute of the bridge
+          element is used to tell libvirt how the bridge's MAC address
+          table (used to determine the correct egress port for packets
+          based on destination MAC address) will be managed. In the
+          default <code>kernel</code> setting, the kernel
+          automatically adds and removes entries, typically using
+          learning, flooding, and promiscuous mode on the bridge's
+          ports in order to determine the proper egress port for
+          packets.  When <code>macTableManager</code> is set
+          to <code>libvirt</code>, libvirt disables kernel management
+          of the MAC table (in the case of the Linux host bridge, this
+          means enabling vlan_filtering on the bridge, and disabling
+          learning and unicast_filter for all bridge ports), and
+          explicitly adds/removes entries to the table according to
+          the MAC addresses in the domain interface configurations.
+          Allowing libvirt to manage the MAC table can improve
+          performance - with a Linux host bridge, for example, turning
+          off learning and unicast_flood on ports has its own
+          performance advantage, and can also lead to an additional
+          boost by permitting the kernel to automatically turn off
+          promiscuous mode on some ports of the bridge (in particular,
+          the port attaching the bridge to the physical
+          network). However, it can also cause some networking setups
+          to stop working (e.g. vlan tagging, multicast,
+          guest-initiated changes to MAC address) 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>
index 4546f80375800c7924ce0c84419dcb8b86f5dcf5..9a7d156303eaacdae7b47a6356d7fd350e524652 100644 (file)
               </attribute>
             </optional>
 
+            <optional>
+              <attribute name="macTableManager">
+                <choice>
+                  <value>kernel</value>
+                  <value>libvirt</value>
+                </choice>
+              </attribute>
+            </optional>
+
           </element>
         </optional>
 
index 97719ed536de9b116066e5dc4990ca1d08620385..0d09deff7ff95a97af889ce778c7c7ddc1fccb26 100644 (file)
@@ -55,6 +55,10 @@ VIR_ENUM_IMPL(virNetworkForward,
               VIR_NETWORK_FORWARD_LAST,
               "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev")
 
+VIR_ENUM_IMPL(virNetworkBridgeMACTableManager,
+              VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LAST,
+              "default", "kernel", "libvirt")
+
 VIR_ENUM_DECL(virNetworkForwardHostdevDevice)
 VIR_ENUM_IMPL(virNetworkForwardHostdevDevice,
               VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST,
@@ -2108,6 +2112,18 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
     }
     VIR_FREE(tmp);
 
+    tmp = virXPathString("string(./bridge[1]/@macTableManager)", ctxt);
+    if (tmp) {
+        if ((def->macTableManager
+             = virNetworkBridgeMACTableManagerTypeFromString(tmp)) <= 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid macTableManager 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 +2306,14 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
                            def->name);
             goto error;
         }
+        if (def->macTableManager) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("bridge macTableManager 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 +2807,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->macTableManager) {
 
         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->macTableManager) {
+            virBufferAsprintf(buf, " macTableManager='%s'",
+                             virNetworkBridgeMACTableManagerTypeToString(def->macTableManager));
+        }
+        virBufferAddLit(buf, "/>\n");
     }
 
-
     if (def->mac_specified) {
         char macaddr[VIR_MAC_STRING_BUFLEN];
         virMacAddrFormat(&def->mac, macaddr);
index 660cd2d10cd1096ffb6b9f26d58adcb9c5ad1c28..811002818a8c1a633e72c5f3ffce38c12d47a66c 100644 (file)
@@ -53,6 +53,16 @@ typedef enum {
     VIR_NETWORK_FORWARD_LAST,
 } virNetworkForwardType;
 
+typedef enum {
+   VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_DEFAULT = 0,
+   VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_KERNEL,
+   VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT,
+
+   VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LAST,
+} virNetworkBridgeMACTableManagerType;
+
+VIR_ENUM_DECL(virNetworkBridgeMACTableManager)
+
 typedef enum {
     VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE = 0,
     VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI,
@@ -231,6 +241,7 @@ struct _virNetworkDef {
     int   connections; /* # of guest interfaces connected to this network */
 
     char *bridge;       /* Name of bridge device */
+    int  macTableManager; /* enum virNetworkBridgeMACTableManager */
     char *domain;
     unsigned long delay;   /* Bridge forward delay (ms) */
     bool stp; /* Spanning tree protocol */
index 3e445fc46abdc6014a72ec85932a1f4e62b4edb2..645d516e1e3c7ee9e58449d4230ad927ccc41ea9 100644 (file)
@@ -529,6 +529,8 @@ virNetDevVPortTypeToString;
 
 # conf/network_conf.h
 virNetworkAssignDef;
+virNetworkBridgeMACTableManagerTypeFromString;
+virNetworkBridgeMACTableManagerTypeToString;
 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 (file)
index 0000000..562e697
--- /dev/null
@@ -0,0 +1,6 @@
+<network>
+  <name>host-bridge-net</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+  <forward mode="bridge"/>
+  <bridge name="br0" macTableManager="libvirt"/>
+</network>
diff --git a/tests/networkxml2xmlin/nat-network-explicit-flood.xml b/tests/networkxml2xmlin/nat-network-explicit-flood.xml
new file mode 100644 (file)
index 0000000..9738b81
--- /dev/null
@@ -0,0 +1,21 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <bridge name="virbr0" macTableManager="kernel"/>
+  <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 (file)
index 0000000..bdbbf3b
--- /dev/null
@@ -0,0 +1,6 @@
+<network>
+  <name>host-bridge-net</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+  <forward mode='bridge'/>
+  <bridge name='br0' macTableManager='libvirt'/>
+</network>
diff --git a/tests/networkxml2xmlout/nat-network-explicit-flood.xml b/tests/networkxml2xmlout/nat-network-explicit-flood.xml
new file mode 100644 (file)
index 0000000..305c3b7
--- /dev/null
@@ -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' macTableManager='kernel'/>
+  <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>
index 65ac591fb191d6ecdc2983d84b03898cc276d6c7..34a52112815354abae597fccca79d6badd110f4f 100644 (file)
@@ -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;
 }