]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Extend vxlan_group option to allow a range of group addresses
authorJohn Nielsen <john@jnielsen.net>
Wed, 22 Jul 2015 18:43:04 +0000 (12:43 -0600)
committerJohn Nielsen <john@jnielsen.net>
Wed, 29 Jul 2015 00:28:14 +0000 (18:28 -0600)
If vxlan_group is specified in CIDR notation, it is interpreted as a
range of group addresses. VXLAN VNIs are mapped to group addresses in
a many-to-one round robin fashion, or one-to-one if a large enough
range is provided. Since VNIs are 24 bits, a /8 such as 239.0.0.0/8
allows each VNI to use a unique multicast group. (239.0.0.0/8 also
happens to be the "site-local" multicast range.)

With multiple VNIs on a single multicast group, it is likely that
VTEPs will unnecessarily receive broadcast/unknown/multicast
datagrams for VNIs in which they do not participate. Using a range of
groups mitigates or eliminates this issue. It is thus an alternative
to the l2_population extension and driver for environments where both
multicast and linuxbridge are used.

The default setting is unchanged, but the comments in the ini file
suggest 239.0.0.0/8 as an alternative. Administrators are free to use
any valid multicast range that can be expressed in CIDR notation, and
should choose a size and starting address that make sense for their
environment.

DocImpact
Closes-Bug: #1477331
Change-Id: If9a3487a28ba2b02a6ef934c5421cec5d505b53c

etc/neutron/plugins/ml2/linuxbridge_agent.ini
neutron/plugins/ml2/drivers/linuxbridge/agent/common/config.py
neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py
neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py

index d1a01ba72ee14232b8d5d5cc17995c6fdd2bdda4..2ea019ed62013cf1895f14ea2d58bcaeb5ef5a2c 100644 (file)
 # (IntOpt) use specific TOS for vxlan interface protocol packets
 # tos =
 #
-# (StrOpt) multicast group to use for broadcast emulation.
-# This group must be the same on all the agents.
+# (StrOpt) multicast group or group range to use for broadcast emulation.
+# Specifying a range allows different VNIs to use different group addresses,
+# reducing or eliminating spurious broadcast traffic to the tunnel endpoints.
+# Ranges are specified by using CIDR notation. To reserve a unique group for
+# each possible (24-bit) VNI, use a /8 such as 239.0.0.0/8.
+# This setting must be the same on all the agents.
 # vxlan_group = 224.0.0.1
 #
 # (StrOpt) Local IP address to use for VXLAN endpoints (required)
index 6f15236ba8fdea40baf3fcaab3a1120857becb6b..daac80000492b049c9e9025150ee3410c0d15459 100644 (file)
@@ -30,7 +30,11 @@ vxlan_opts = [
     cfg.IntOpt('tos',
                help=_("TOS for vxlan interface protocol packets.")),
     cfg.StrOpt('vxlan_group', default=DEFAULT_VXLAN_GROUP,
-               help=_("Multicast group for vxlan interface.")),
+               help=_("Multicast group(s) for vxlan interface. A range of "
+                      "group addresses may be specified by using CIDR "
+                      "notation. To reserve a unique group for each possible "
+                      "(24-bit) VNI, use a /8 such as 239.0.0.0/8. This "
+                      "setting must be the same on all the agents.")),
     cfg.IPOpt('local_ip', version=4,
               help=_("Local IP address of the VXLAN endpoints.")),
     cfg.BoolOpt('l2_population', default=False,
index b9747a4ec04073945d4667c9f86bc91f806a26ab..fddace246d2c1393ad2a0365b5338ce85a18e17e 100644 (file)
@@ -26,6 +26,7 @@ import time
 import eventlet
 eventlet.monkey_patch()
 
+import netaddr
 from oslo_config import cfg
 from oslo_log import log as logging
 import oslo_messaging
@@ -128,6 +129,22 @@ class LinuxBridgeManager(object):
             LOG.warning(_LW("Invalid Segmentation ID: %s, will lead to "
                             "incorrect vxlan device name"), segmentation_id)
 
+    def get_vxlan_group(self, segmentation_id):
+        try:
+            # Ensure the configured group address/range is valid and multicast
+            net = netaddr.IPNetwork(cfg.CONF.VXLAN.vxlan_group)
+            if not (net.network.is_multicast() and
+                    net.broadcast.is_multicast()):
+                raise ValueError()
+            # Map the segmentation ID to (one of) the group address(es)
+            return str(net.network +
+                       (int(segmentation_id) & int(net.hostmask)))
+        except (netaddr.core.AddrFormatError, ValueError):
+            LOG.warning(_LW("Invalid VXLAN Group: %s, must be an address "
+                            "or network (in CIDR notation) in a multicast "
+                            "range"),
+                        cfg.CONF.VXLAN.vxlan_group)
+
     def get_all_neutron_bridges(self):
         neutron_bridge_list = []
         bridge_list = os.listdir(BRIDGE_FS)
@@ -241,7 +258,7 @@ class LinuxBridgeManager(object):
                        'segmentation_id': segmentation_id})
             args = {'dev': self.local_int}
             if self.vxlan_mode == lconst.VXLAN_MCAST:
-                args['group'] = cfg.CONF.VXLAN.vxlan_group
+                args['group'] = self.get_vxlan_group(segmentation_id)
             if cfg.CONF.VXLAN.ttl:
                 args['ttl'] = cfg.CONF.VXLAN.ttl
             if cfg.CONF.VXLAN.tos:
@@ -547,7 +564,7 @@ class LinuxBridgeManager(object):
 
     def vxlan_mcast_supported(self):
         if not cfg.CONF.VXLAN.vxlan_group:
-            LOG.warning(_LW('VXLAN muticast group must be provided in '
+            LOG.warning(_LW('VXLAN muticast group(s) must be provided in '
                             'vxlan_group option to enable VXLAN MCAST mode'))
             return False
         if not ip_lib.iproute_arg_supported(
index 55b9bd821b4ce6f0ddb41c6652a5733a8e23cb0d..5ba7796ccfafc75c05cd4c446904ba77ab462844 100644 (file)
@@ -397,6 +397,19 @@ class TestLinuxBridgeManager(base.BaseTestCase):
                          "vxlan-" + str(vn_id))
         self.assertIsNone(self.lbm.get_vxlan_device_name(vn_id + 1))
 
+    def test_get_vxlan_group(self):
+        cfg.CONF.set_override('vxlan_group', '239.1.2.3/24', 'VXLAN')
+        vn_id = p_const.MAX_VXLAN_VNI
+        self.assertEqual('239.1.2.255', self.lbm.get_vxlan_group(vn_id))
+        vn_id = 256
+        self.assertEqual('239.1.2.0', self.lbm.get_vxlan_group(vn_id))
+        vn_id = 257
+        self.assertEqual('239.1.2.1', self.lbm.get_vxlan_group(vn_id))
+        cfg.CONF.set_override('vxlan_group', '240.0.0.0', 'VXLAN')
+        self.assertIsNone(self.lbm.get_vxlan_group(vn_id))
+        cfg.CONF.set_override('vxlan_group', '224.0.0.1/', 'VXLAN')
+        self.assertIsNone(self.lbm.get_vxlan_group(vn_id))
+
     def test_get_all_neutron_bridges(self):
         br_list = ["br-int", "brq1", "brq2", "br-ex"]
         with mock.patch.object(os, 'listdir') as listdir_fn: