Improve VLAN allocations synchronization
In order to reduce the number of elements retrieved from the DB, this patch, before processing the VLAN allocations per physical network, deleted those registers belonging to any unconfigured physical network. The VLAN registers per physical network are deleted using a bulk delete operation, to speed up the process. Those missing VLAN registers per network are now created using a bulk insert operation, available in the ORM. This bulk operation speeds up the sync process. Conflicts: neutron/plugins/ml2/drivers/type_vlan.py Change-Id: I8568e2277e157754aaff87a059a40e34e6a43e2b Partial-Bug: #1862178 (cherry picked from commit016e7826f1
) (cherry picked from commit651eb12bec
) (cherry picked from commit4fff732b76
) (cherry picked from commit8a6521e445
)
This commit is contained in:
parent
14b9029df4
commit
89c56d738d
|
@ -33,3 +33,24 @@ class VlanAllocation(base.NeutronDbObject):
|
||||||
}
|
}
|
||||||
|
|
||||||
primary_keys = ['physical_network', 'vlan_id']
|
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])
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import collections
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from neutron_lib import constants as p_const
|
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 neutron_lib.plugins.ml2 import api
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from six import moves
|
|
||||||
|
|
||||||
from neutron._i18n import _
|
from neutron._i18n import _
|
||||||
from neutron.conf.plugins.ml2.drivers import driver_type
|
from neutron.conf.plugins.ml2.drivers import driver_type
|
||||||
|
@ -64,22 +64,30 @@ class VlanTypeDriver(helpers.SegmentTypeDriver):
|
||||||
def _sync_vlan_allocations(self):
|
def _sync_vlan_allocations(self):
|
||||||
ctx = context.get_admin_context()
|
ctx = context.get_admin_context()
|
||||||
with db_api.context_manager.writer.using(ctx):
|
with db_api.context_manager.writer.using(ctx):
|
||||||
# get existing allocations for all physical networks
|
# VLAN ranges per physical network:
|
||||||
allocations = dict()
|
# {phy1: [(1, 10), (30, 50)], ...}
|
||||||
allocs = vlanalloc.VlanAllocation.get_objects(ctx)
|
ranges = self.network_vlan_ranges
|
||||||
for alloc in allocs:
|
|
||||||
if alloc.physical_network not in allocations:
|
# Delete those VLAN registers from unconfigured physical networks
|
||||||
allocations[alloc.physical_network] = list()
|
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)
|
allocations[alloc.physical_network].append(alloc)
|
||||||
|
|
||||||
# process vlan ranges for each configured physical network
|
for physical_network, vlan_ranges in ranges.items():
|
||||||
for (physical_network,
|
|
||||||
vlan_ranges) in self.network_vlan_ranges.items():
|
|
||||||
# determine current configured allocatable vlans for
|
# determine current configured allocatable vlans for
|
||||||
# this physical network
|
# this physical network
|
||||||
vlan_ids = set()
|
vlan_ids = set()
|
||||||
for vlan_min, vlan_max in vlan_ranges:
|
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
|
# remove from table unallocated vlans not currently
|
||||||
# allocatable
|
# allocatable
|
||||||
|
@ -112,25 +120,9 @@ class VlanTypeDriver(helpers.SegmentTypeDriver):
|
||||||
alloc.delete()
|
alloc.delete()
|
||||||
del allocations[physical_network]
|
del allocations[physical_network]
|
||||||
|
|
||||||
# add missing allocatable vlans to table
|
# Add missing allocatable VLAN registers for "physical_network"
|
||||||
for vlan_id in sorted(vlan_ids):
|
vlanalloc.VlanAllocation.bulk_create(ctx, physical_network,
|
||||||
alloc = vlanalloc.VlanAllocation(
|
vlan_ids)
|
||||||
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()
|
|
||||||
|
|
||||||
def get_type(self):
|
def get_type(self):
|
||||||
return p_const.TYPE_VLAN
|
return p_const.TYPE_VLAN
|
||||||
|
|
|
@ -29,6 +29,7 @@ from neutron.tests.unit import testlib_api
|
||||||
|
|
||||||
PROVIDER_NET = 'phys_net1'
|
PROVIDER_NET = 'phys_net1'
|
||||||
TENANT_NET = 'phys_net2'
|
TENANT_NET = 'phys_net2'
|
||||||
|
UNCONFIGURED_NET = 'no_net'
|
||||||
VLAN_MIN = 200
|
VLAN_MIN = 200
|
||||||
VLAN_MAX = 209
|
VLAN_MAX = 209
|
||||||
NETWORK_VLAN_RANGES = [PROVIDER_NET, "%s:%s:%s" %
|
NETWORK_VLAN_RANGES = [PROVIDER_NET, "%s:%s:%s" %
|
||||||
|
@ -40,6 +41,12 @@ UPDATED_VLAN_RANGES = {
|
||||||
EMPTY_VLAN_RANGES = {
|
EMPTY_VLAN_RANGES = {
|
||||||
PROVIDER_NET: []
|
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'
|
CORE_PLUGIN = 'ml2'
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,10 +175,21 @@ class VlanTypeTest(testlib_api.SqlTestCase):
|
||||||
self._get_allocation(self.context, segment).allocated)
|
self._get_allocation(self.context, segment).allocated)
|
||||||
|
|
||||||
check_in_ranges(self.network_vlan_ranges)
|
check_in_ranges(self.network_vlan_ranges)
|
||||||
|
|
||||||
self.driver.network_vlan_ranges = UPDATED_VLAN_RANGES
|
self.driver.network_vlan_ranges = UPDATED_VLAN_RANGES
|
||||||
self.driver._sync_vlan_allocations()
|
self.driver._sync_vlan_allocations()
|
||||||
check_in_ranges(UPDATED_VLAN_RANGES)
|
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.network_vlan_ranges = EMPTY_VLAN_RANGES
|
||||||
self.driver._sync_vlan_allocations()
|
self.driver._sync_vlan_allocations()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue