Merge "Improve VLAN allocations synchronization" into stable/queens

This commit is contained in:
Zuul 2020-04-29 02:28:43 +00:00 committed by Gerrit Code Review
commit d25457e049
3 changed files with 61 additions and 30 deletions

View File

@ -33,3 +33,24 @@ class VlanAllocation(base.NeutronDbObject):
}
primary_keys = ['physical_network', 'vlan_id']
@staticmethod
def get_physical_networks(context):
query = context.session.query(VlanAllocation.db_model.physical_network)
query = query.group_by(VlanAllocation.db_model.physical_network)
physnets = query.all()
return {physnet.physical_network for physnet in physnets}
@staticmethod
def delete_physical_networks(context, physical_networks):
column = VlanAllocation.db_model.physical_network
context.session.query(VlanAllocation.db_model).filter(
column.in_(physical_networks)).delete(synchronize_session=False)
@staticmethod
def bulk_create(ctx, physical_network, vlan_ids):
ctx.session.bulk_insert_mappings(
vlan_alloc_model.VlanAllocation,
[{'physical_network': physical_network,
'allocated': False,
'vlan_id': vlan_id} for vlan_id in vlan_ids])

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import sys
from neutron_lib import constants as p_const
@ -21,7 +22,6 @@ from neutron_lib import exceptions as exc
from neutron_lib.plugins.ml2 import api
from oslo_config import cfg
from oslo_log import log
from six import moves
from neutron._i18n import _
from neutron.conf.plugins.ml2.drivers import driver_type
@ -64,22 +64,30 @@ class VlanTypeDriver(helpers.SegmentTypeDriver):
def _sync_vlan_allocations(self):
ctx = context.get_admin_context()
with db_api.context_manager.writer.using(ctx):
# get existing allocations for all physical networks
allocations = dict()
allocs = vlanalloc.VlanAllocation.get_objects(ctx)
for alloc in allocs:
if alloc.physical_network not in allocations:
allocations[alloc.physical_network] = list()
# VLAN ranges per physical network:
# {phy1: [(1, 10), (30, 50)], ...}
ranges = self.network_vlan_ranges
# Delete those VLAN registers from unconfigured physical networks
physnets = vlanalloc.VlanAllocation.get_physical_networks(ctx)
physnets_unconfigured = physnets - set(ranges)
if physnets_unconfigured:
LOG.debug('Removing any VLAN register on physical networks %s',
physnets_unconfigured)
vlanalloc.VlanAllocation.delete_physical_networks(
ctx, physnets_unconfigured)
# Get existing allocations for all configured physical networks
allocations = collections.defaultdict(list)
for alloc in vlanalloc.VlanAllocation.get_objects(ctx):
allocations[alloc.physical_network].append(alloc)
# process vlan ranges for each configured physical network
for (physical_network,
vlan_ranges) in self.network_vlan_ranges.items():
for physical_network, vlan_ranges in ranges.items():
# determine current configured allocatable vlans for
# this physical network
vlan_ids = set()
for vlan_min, vlan_max in vlan_ranges:
vlan_ids |= set(moves.range(vlan_min, vlan_max + 1))
vlan_ids |= set(range(vlan_min, vlan_max + 1))
# remove from table unallocated vlans not currently
# allocatable
@ -112,25 +120,9 @@ class VlanTypeDriver(helpers.SegmentTypeDriver):
alloc.delete()
del allocations[physical_network]
# add missing allocatable vlans to table
for vlan_id in sorted(vlan_ids):
alloc = vlanalloc.VlanAllocation(
ctx,
physical_network=physical_network,
vlan_id=vlan_id, allocated=False)
alloc.create()
# remove from table unallocated vlans for any unconfigured
# physical networks
for allocs in allocations.values():
for alloc in allocs:
if not alloc.allocated:
LOG.debug("Removing vlan %(vlan_id)s on physical "
"network %(physical_network)s from pool",
{'vlan_id': alloc.vlan_id,
'physical_network':
alloc.physical_network})
alloc.delete()
# Add missing allocatable VLAN registers for "physical_network"
vlanalloc.VlanAllocation.bulk_create(ctx, physical_network,
vlan_ids)
def get_type(self):
return p_const.TYPE_VLAN

View File

@ -29,6 +29,7 @@ from neutron.tests.unit import testlib_api
PROVIDER_NET = 'phys_net1'
TENANT_NET = 'phys_net2'
UNCONFIGURED_NET = 'no_net'
VLAN_MIN = 200
VLAN_MAX = 209
NETWORK_VLAN_RANGES = [PROVIDER_NET, "%s:%s:%s" %
@ -40,6 +41,12 @@ UPDATED_VLAN_RANGES = {
EMPTY_VLAN_RANGES = {
PROVIDER_NET: []
}
NETWORK_VLAN_RANGES_WITH_UNCONFIG = {
PROVIDER_NET: [],
TENANT_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)],
UNCONFIGURED_NET: [(VLAN_MIN, VLAN_MAX)]
}
CORE_PLUGIN = 'ml2'
@ -168,10 +175,21 @@ class VlanTypeTest(testlib_api.SqlTestCase):
self._get_allocation(self.context, segment).allocated)
check_in_ranges(self.network_vlan_ranges)
self.driver.network_vlan_ranges = UPDATED_VLAN_RANGES
self.driver._sync_vlan_allocations()
check_in_ranges(UPDATED_VLAN_RANGES)
self.driver.network_vlan_ranges = NETWORK_VLAN_RANGES_WITH_UNCONFIG
self.driver._sync_vlan_allocations()
self.driver.network_vlan_ranges = UPDATED_VLAN_RANGES
with mock.patch.object(type_vlan.LOG, 'debug') as mock_debug:
self.driver._sync_vlan_allocations()
mock_debug.assert_called_once_with(
'Removing any VLAN register on physical networks %s',
{UNCONFIGURED_NET})
check_in_ranges(UPDATED_VLAN_RANGES)
self.driver.network_vlan_ranges = EMPTY_VLAN_RANGES
self.driver._sync_vlan_allocations()