Merge "VXLAN multicast groups in linuxbridge"
This commit is contained in:
commit
3c2ce67efe
@ -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