VXLAN multicast groups in linuxbridge
Enable creation of VXLANs with different multicast addresses allocated by VNI-address mappings. Dictionary of multicast addresses and corresponding VXLAN VNI IDs should be loaded from settings. Usable to not flood whole network when managing routers between more datacenters and can not use L2population because VXLAN points to external device. Co-Authored-By: Kevin Benton <kevin@benton.pub> DocImpact: VXLAN addresses used by linux bridge can be specified per VNI Closes-Bug: #1579068 Change-Id: I24f272ccd6d61d9fa7ea3b6f256fabd381f5434a
This commit is contained in:
parent
d20c0edfc6
commit
8a596f35bb
@ -58,6 +58,12 @@ vxlan_opts = [
|
||||
"fully compatible with the allowed-address-pairs "
|
||||
"extension.")
|
||||
),
|
||||
cfg.ListOpt('multicast_ranges',
|
||||
default=[],
|
||||
help=_("Optional comma-separated list of "
|
||||
"<multicast address>:<vni_min>:<vni_max> triples "
|
||||
"describing how to assign a multicast address to "
|
||||
"VXLAN according to its VNI ID.")),
|
||||
]
|
||||
|
||||
bridge_opts = [
|
||||
|
@ -98,7 +98,30 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
|
||||
{'brq': bridge, 'net': physnet})
|
||||
sys.exit(1)
|
||||
|
||||
def _is_valid_multicast_range(self, mrange):
|
||||
try:
|
||||
addr, vxlan_min, vxlan_max = mrange.split(':')
|
||||
if int(vxlan_min) > int(vxlan_max):
|
||||
raise ValueError()
|
||||
try:
|
||||
local_ver = netaddr.IPAddress(self.local_ip).version
|
||||
n_addr = netaddr.IPAddress(addr)
|
||||
if not n_addr.is_multicast() or n_addr.version != local_ver:
|
||||
raise ValueError()
|
||||
except netaddr.core.AddrFormatError:
|
||||
raise ValueError()
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def validate_vxlan_group_with_local_ip(self):
|
||||
for r in cfg.CONF.VXLAN.multicast_ranges:
|
||||
if not self._is_valid_multicast_range(r):
|
||||
LOG.error("Invalid multicast_range %(r)s. Must be in "
|
||||
"<multicast address>:<vni_min>:<vni_max> format and "
|
||||
"addresses must be in the same family as local IP "
|
||||
"%(loc)s.", {'r': r, 'loc': self.local_ip})
|
||||
sys.exit(1)
|
||||
if not cfg.CONF.VXLAN.vxlan_group:
|
||||
return
|
||||
try:
|
||||
@ -186,8 +209,19 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
|
||||
LOG.warning(_LW("Invalid Segmentation ID: %s, will lead to "
|
||||
"incorrect vxlan device name"), segmentation_id)
|
||||
|
||||
@staticmethod
|
||||
def _match_multicast_range(segmentation_id):
|
||||
for mrange in cfg.CONF.VXLAN.multicast_ranges:
|
||||
addr, vxlan_min, vxlan_max = mrange.split(':')
|
||||
if int(vxlan_min) <= segmentation_id <= int(vxlan_max):
|
||||
return addr
|
||||
|
||||
def get_vxlan_group(self, segmentation_id):
|
||||
net = netaddr.IPNetwork(cfg.CONF.VXLAN.vxlan_group)
|
||||
mcast_addr = self._match_multicast_range(segmentation_id)
|
||||
if mcast_addr:
|
||||
net = netaddr.IPNetwork(mcast_addr)
|
||||
else:
|
||||
net = netaddr.IPNetwork(cfg.CONF.VXLAN.vxlan_group)
|
||||
# Map the segmentation ID to (one of) the group address(es)
|
||||
return str(net.network +
|
||||
(int(segmentation_id) & int(net.hostmask)))
|
||||
|
@ -222,6 +222,45 @@ class TestLinuxBridgeManager(base.BaseTestCase):
|
||||
vn_id = 257
|
||||
self.assertEqual('239.1.2.1', self.lbm.get_vxlan_group(vn_id))
|
||||
|
||||
def test_get_vxlan_group_with_multicast_address(self):
|
||||
cfg.CONF.set_override('vxlan_group', '239.1.2.3/32', 'VXLAN')
|
||||
cfg.CONF.set_override('multicast_ranges',
|
||||
('224.0.0.10:300:315',
|
||||
'225.0.0.15:400:600'), 'VXLAN')
|
||||
vn_id = 300
|
||||
self.assertEqual('224.0.0.10', self.lbm.get_vxlan_group(vn_id))
|
||||
vn_id = 500
|
||||
self.assertEqual('225.0.0.15', self.lbm.get_vxlan_group(vn_id))
|
||||
vn_id = 315
|
||||
self.assertEqual('224.0.0.10', self.lbm.get_vxlan_group(vn_id))
|
||||
vn_id = 4000
|
||||
# outside of range should fallback to group
|
||||
self.assertEqual('239.1.2.3', self.lbm.get_vxlan_group(vn_id))
|
||||
|
||||
def test__is_valid_multicast_range(self):
|
||||
bad_ranges = ['224.0.0.10:330:315', 'x:100:200', '10.0.0.1:100:200',
|
||||
'224.0.0.10:100', '224.0.0.10:100:200:300']
|
||||
for r in bad_ranges:
|
||||
self.assertFalse(self.lbm._is_valid_multicast_range(r),
|
||||
'range %s should have been invalid' % r)
|
||||
good_ranges = ['224.0.0.10:315:330', '224.0.0.0:315:315']
|
||||
for r in good_ranges:
|
||||
self.assertTrue(self.lbm._is_valid_multicast_range(r),
|
||||
'range %s should have been valid' % r)
|
||||
# v4 ranges are bad when a v6 local_ip is present
|
||||
self.lbm.local_ip = '2000::1'
|
||||
for r in good_ranges:
|
||||
self.assertFalse(self.lbm._is_valid_multicast_range(r),
|
||||
'range %s should have been invalid' % r)
|
||||
|
||||
def test__match_multicast_range(self):
|
||||
cfg.CONF.set_override('multicast_ranges',
|
||||
('224.0.0.10:300:315',
|
||||
'225.0.0.15:400:600'), 'VXLAN')
|
||||
self.assertEqual('224.0.0.10', self.lbm._match_multicast_range(307))
|
||||
self.assertEqual('225.0.0.15', self.lbm._match_multicast_range(407))
|
||||
self.assertIsNone(self.lbm._match_multicast_range(399))
|
||||
|
||||
def test_get_vxlan_group_with_ipv6(self):
|
||||
cfg.CONF.set_override('local_ip', LOCAL_IPV6, 'VXLAN')
|
||||
self.lbm.local_ip = LOCAL_IPV6
|
||||
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
prelude: >
|
||||
Enable creation of VXLANs with different multicast
|
||||
addresses allocated by VNI-address mappings.
|
||||
features:
|
||||
- The ability to control vni-multicast address
|
||||
distribution in linuxbridge agent via new config
|
||||
option - multicast_ranges.
|
||||
other:
|
||||
- Example configuration of `multicast_ranges` in
|
||||
ml2_conf.ini under the `[vxlan]` config. section
|
||||
multicast_ranges = 224.0.0.10:10:90,225.0.0.15:100:900
|
||||
For VNI between 10 and 90, the multicast address
|
||||
224.0.0.0.10 will be used, and for 100 through 900
|
||||
225.0.0.15 will be used. Other VNI values will get
|
||||
standard `vxlan_group` address. For more info see RFE
|
||||
`<https://bugs.launchpad.net/neutron/+bug/1579068>`
|
Loading…
Reference in New Issue
Block a user