Exhaust VLAN allocations in physnet order
When an operator configured multiple network VLAN ranges, we had no guarantee that we would actually allocate in the order specified like we do with segmentation types. In *most* cases, the natural database order would be that the returned available segment IDs would come back in the order of the physnets because the sync_allocations code inserted them in that order. So it became something some deployments would rely on and operators would get a surprise when suddenly an allocation would happen from the later physnets while many VLANs were still available in the first one. This patch just strictly makes allocation attempts in the order of the network_vlan_ranges so operators are always guaranteed that the later physnets will not automatically be allocated from unless the earlier physnets are exhausted. Change-Id: I14ca9b7e1141199f3ec221184fbbe156f1f9e18b
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
Common utilities and helper functions for OpenStack Networking Plugins.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import contextlib
|
||||
import hashlib
|
||||
|
||||
@@ -131,7 +132,7 @@ def parse_network_vlan_range(network_vlan_range):
|
||||
|
||||
def parse_network_vlan_ranges(network_vlan_ranges_cfg_entries):
|
||||
"""Interpret a list of strings as network[:vlan_begin:vlan_end] entries."""
|
||||
networks = {}
|
||||
networks = collections.OrderedDict()
|
||||
for entry in network_vlan_ranges_cfg_entries:
|
||||
network, vlan_range = parse_network_vlan_range(entry)
|
||||
if vlan_range:
|
||||
|
||||
@@ -196,8 +196,12 @@ class VlanTypeDriver(helpers.SegmentTypeDriver):
|
||||
api.MTU: self.get_mtu(alloc.physical_network)}
|
||||
|
||||
def allocate_tenant_segment(self, context):
|
||||
alloc = self.allocate_partially_specified_segment(context)
|
||||
if not alloc:
|
||||
for physnet in self.network_vlan_ranges:
|
||||
alloc = self.allocate_partially_specified_segment(
|
||||
context, physical_network=physnet)
|
||||
if alloc:
|
||||
break
|
||||
else:
|
||||
return
|
||||
return {api.NETWORK_TYPE: p_const.TYPE_VLAN,
|
||||
api.PHYSICAL_NETWORK: alloc.physical_network,
|
||||
|
||||
@@ -259,3 +259,36 @@ class VlanTypeTest(testlib_api.SqlTestCase):
|
||||
"No vlan_id %(vlan_id)s found on physical network "
|
||||
"%(physical_network)s",
|
||||
{'vlan_id': 101, 'physical_network': PROVIDER_NET})
|
||||
|
||||
|
||||
class VlanTypeAllocationTest(testlib_api.SqlTestCase):
|
||||
|
||||
def test_allocate_tenant_segment_in_order_of_config(self):
|
||||
ranges = NETWORK_VLAN_RANGES + ['phys_net3:20:30']
|
||||
config.cfg.CONF.set_override('network_vlan_ranges',
|
||||
ranges,
|
||||
group='ml2_type_vlan')
|
||||
driver = type_vlan.VlanTypeDriver()
|
||||
driver.physnet_mtus = []
|
||||
driver._sync_vlan_allocations()
|
||||
# swap config order from DB order after sync has happened to
|
||||
# ensure config order is followed and not DB order
|
||||
config.cfg.CONF.set_override('network_vlan_ranges',
|
||||
list(reversed(ranges)),
|
||||
group='ml2_type_vlan')
|
||||
driver._parse_network_vlan_ranges()
|
||||
ctx = context.Context()
|
||||
for vlan in range(11):
|
||||
# all of physnet3 should be exhausted first
|
||||
self.assertEqual(
|
||||
{'network_type': 'vlan', 'physical_network': 'phys_net3',
|
||||
'segmentation_id': mock.ANY, 'mtu': 1500},
|
||||
driver.allocate_tenant_segment(ctx))
|
||||
for vlan in range(10):
|
||||
# then physnet2
|
||||
self.assertEqual(
|
||||
{'network_type': 'vlan', 'physical_network': 'phys_net2',
|
||||
'segmentation_id': mock.ANY, 'mtu': 1500},
|
||||
driver.allocate_tenant_segment(ctx))
|
||||
# then nothing
|
||||
self.assertFalse(driver.allocate_tenant_segment(ctx))
|
||||
|
||||
Reference in New Issue
Block a user