Extend vxlan_group option to allow a range of group addresses

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
This commit is contained in:
John Nielsen 2015-07-22 12:43:04 -06:00
parent 8584987e51
commit e34e67b8e6
4 changed files with 43 additions and 5 deletions

View File

@ -21,8 +21,12 @@
# (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)

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

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

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