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

John Ferlan jferlan at redhat.com
Tue Dec 2 19:39:27 UTC 2014



On 12/02/2014 12:08 PM, Laine Stump wrote:
> 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

s/floowing/flooding

unless of course it was COW's involved in the flood, then perhaps
floowing is more apropos ;-)

> 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
> 

ACK - although there's a grammar nit for the html page and a couple of
naming comments (go with your gut on resolution - the names seem fine
just thinking consistency between *_AUTO and learningWithFlood and using
"none"/NONE instead of "absent"/ABSENT).

John

> 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

s/The /The optional /

> +          to tell libvirt how the bridge's forwarding database (fdb)
> +          will be updated. In the default

s/In the default/If not provided or if using the/

(or something like that to indicate the default action)

> +          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>

I actually like your other name "auto", but this is fine, too.

> +                  <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")

"none" is more common than "absent"...

> +
>  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,

again NONE is more common...

> +   VIR_NETWORK_BRIDGE_FDB_AUTO,

Since it's really never used otherwise - LEARNING_WITH_FLOOD keeps names
in synch rather than 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;
>  }
> 




More information about the libvir-list mailing list