Skip to content

Commit

Permalink
Fix OVS and LB plugins' VLAN allocation table synchronization
Browse files Browse the repository at this point in the history
In both the openvswitch and linuxbridge plugins, if previous entries
for a physical network have been completely removed from the
network_vlan_ranges configuration variable, allocation table records
for unallocated VLANs on that physical network are now removed from
the DB at startup. The test_ovs_db and test_lb_db unit tests have also
been extended to cover this case. Fixes bug 1052289.

Test assertions that were added to the test_ovs_db unit test in
https://review.openstack.org/#/c/11388 have been added to the
test_lb_db unit test. Fixes bug 1045596.

Change-Id: I04e924603eaf0df717414c2aaa83fd203b791308
  • Loading branch information
Bob Kukura authored and ttx committed Sep 21, 2012
1 parent 34396fa commit a2fb340
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 44 deletions.
48 changes: 31 additions & 17 deletions quantum/plugins/linuxbridge/db/l2network_db_v2.py
Expand Up @@ -40,23 +40,28 @@ def initialize():
def sync_network_states(network_vlan_ranges):
"""Synchronize network_states table with current configured VLAN ranges."""

# process vlan ranges for each physical network separately
for physical_network, vlan_ranges in network_vlan_ranges.iteritems():

# determine current configured allocatable vlans for this
# physical network
vlan_ids = set()
for vlan_range in vlan_ranges:
vlan_ids |= set(xrange(vlan_range[0], vlan_range[1] + 1))
session = db.get_session()
with session.begin():
# get existing allocations for all physical networks
allocations = dict()
states = (session.query(l2network_models_v2.NetworkState).
all())
for state in states:
if state.physical_network not in allocations:
allocations[state.physical_network] = set()
allocations[state.physical_network].add(state)

# process vlan ranges for each configured physical network
for physical_network, vlan_ranges in network_vlan_ranges.iteritems():
# determine current configured allocatable vlans for this
# physical network
vlan_ids = set()
for vlan_range in vlan_ranges:
vlan_ids |= set(xrange(vlan_range[0], vlan_range[1] + 1))

session = db.get_session()
with session.begin():
# remove from table unallocated vlans not currently allocatable
try:
states = (session.query(l2network_models_v2.NetworkState).
filter_by(physical_network=physical_network).
all())
for state in states:
if physical_network in allocations:
for state in allocations[physical_network]:
try:
# see if vlan is allocatable
vlan_ids.remove(state.vlan_id)
Expand All @@ -68,15 +73,24 @@ def sync_network_states(network_vlan_ranges):
"%s from pool" %
(state.vlan_id, physical_network))
session.delete(state)
except exc.NoResultFound:
pass
del allocations[physical_network]

# add missing allocatable vlans to table
for vlan_id in sorted(vlan_ids):
state = l2network_models_v2.NetworkState(physical_network,
vlan_id)
session.add(state)

# remove from table unallocated vlans for any unconfigured physical
# networks
for states in allocations.itervalues():
for state in states:
if not state.allocated:
LOG.debug("removing vlan %s on physical network %s"
" from pool" %
(state.vlan_id, physical_network))
session.delete(state)


def get_network_state(physical_network, vlan_id):
"""Get state of specified network"""
Expand Down
61 changes: 36 additions & 25 deletions quantum/plugins/openvswitch/ovs_db_v2.py
Expand Up @@ -64,21 +64,26 @@ def sync_vlan_allocations(network_vlan_ranges):

session = db.get_session()
with session.begin():
# process vlan ranges for each physical network separately
# get existing allocations for all physical networks
allocations = dict()
allocs = (session.query(ovs_models_v2.VlanAllocation).
all())
for alloc in allocs:
if alloc.physical_network not in allocations:
allocations[alloc.physical_network] = set()
allocations[alloc.physical_network].add(alloc)

# process vlan ranges for each configured physical network
for physical_network, vlan_ranges in network_vlan_ranges.iteritems():

# determine current configured allocatable vlans for this
# physical network
vlan_ids = set()
for vlan_range in vlan_ranges:
vlan_ids |= set(xrange(vlan_range[0], vlan_range[1] + 1))

# remove from table unallocated vlans not currently allocatable
try:
allocs = (session.query(ovs_models_v2.VlanAllocation).
filter_by(physical_network=physical_network).
all())
for alloc in allocs:
if physical_network in allocations:
for alloc in allocations[physical_network]:
try:
# see if vlan is allocatable
vlan_ids.remove(alloc.vlan_id)
Expand All @@ -90,14 +95,23 @@ def sync_vlan_allocations(network_vlan_ranges):
"%s from pool" %
(alloc.vlan_id, physical_network))
session.delete(alloc)
except exc.NoResultFound:
pass
del allocations[physical_network]

# add missing allocatable vlans to table
for vlan_id in sorted(vlan_ids):
alloc = ovs_models_v2.VlanAllocation(physical_network, vlan_id)
session.add(alloc)

# remove from table unallocated vlans for any unconfigured physical
# networks
for allocs in allocations.itervalues():
for alloc in allocs:
if not alloc.allocated:
LOG.debug("removing vlan %s on physical network %s"
" from pool" %
(alloc.vlan_id, physical_network))
session.delete(alloc)


def get_vlan_allocation(physical_network, vlan_id):
session = db.get_session()
Expand Down Expand Up @@ -188,22 +202,19 @@ def sync_tunnel_allocations(tunnel_id_ranges):
session = db.get_session()
with session.begin():
# remove from table unallocated tunnels not currently allocatable
try:
allocs = (session.query(ovs_models_v2.TunnelAllocation).
all())
for alloc in allocs:
try:
# see if tunnel is allocatable
tunnel_ids.remove(alloc.tunnel_id)
except KeyError:
# it's not allocatable, so check if its allocated
if not alloc.allocated:
# it's not, so remove it from table
LOG.debug("removing tunnel %s from pool" %
alloc.tunnel_id)
session.delete(alloc)
except exc.NoResultFound:
pass
allocs = (session.query(ovs_models_v2.TunnelAllocation).
all())
for alloc in allocs:
try:
# see if tunnel is allocatable
tunnel_ids.remove(alloc.tunnel_id)
except KeyError:
# it's not allocatable, so check if its allocated
if not alloc.allocated:
# it's not, so remove it from table
LOG.debug("removing tunnel %s from pool" %
alloc.tunnel_id)
session.delete(alloc)

# add missing allocatable tunnels to table
for tunnel_id in sorted(tunnel_ids):
Expand Down
41 changes: 40 additions & 1 deletion quantum/tests/unit/linuxbridge/test_lb_db.py
Expand Up @@ -20,10 +20,12 @@
from quantum.plugins.linuxbridge.db import l2network_db_v2 as lb_db

PHYS_NET = 'physnet1'
PHYS_NET_2 = 'physnet2'
VLAN_MIN = 10
VLAN_MAX = 19
VLAN_RANGES = {PHYS_NET: [(VLAN_MIN, VLAN_MAX)]}
UPDATED_VLAN_RANGES = {PHYS_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)]}
UPDATED_VLAN_RANGES = {PHYS_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)],
PHYS_NET_2: [(VLAN_MIN + 20, VLAN_MAX + 20)]}
TEST_NETWORK_ID = 'abcdefghijklmnopqrstuvwxyz'


Expand All @@ -43,6 +45,8 @@ def test_sync_network_states(self):
VLAN_MIN).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MIN + 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MAX - 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MAX).allocated)
self.assertIsNone(lb_db.get_network_state(PHYS_NET,
Expand All @@ -56,11 +60,46 @@ def test_sync_network_states(self):
VLAN_MIN + 5).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MIN + 5 + 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MAX + 5 - 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MAX + 5).allocated)
self.assertIsNone(lb_db.get_network_state(PHYS_NET,
VLAN_MAX + 5 + 1))

self.assertIsNone(lb_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20 - 1))
self.assertFalse(lb_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20 + 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20 - 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20).allocated)
self.assertIsNone(lb_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20 + 1))

lb_db.sync_network_states(VLAN_RANGES)

self.assertIsNone(lb_db.get_network_state(PHYS_NET,
VLAN_MIN - 1))
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MIN).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MIN + 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MAX - 1).allocated)
self.assertFalse(lb_db.get_network_state(PHYS_NET,
VLAN_MAX).allocated)
self.assertIsNone(lb_db.get_network_state(PHYS_NET,
VLAN_MAX + 1))

self.assertIsNone(lb_db.get_network_state(PHYS_NET_2,
VLAN_MIN + 20))
self.assertIsNone(lb_db.get_network_state(PHYS_NET_2,
VLAN_MAX + 20))

def test_network_pool(self):
vlan_ids = set()
for x in xrange(VLAN_MIN, VLAN_MAX + 1):
Expand Down
45 changes: 44 additions & 1 deletion quantum/tests/unit/openvswitch/test_ovs_db.py
Expand Up @@ -20,10 +20,12 @@
from quantum.plugins.openvswitch import ovs_db_v2

PHYS_NET = 'physnet1'
PHYS_NET_2 = 'physnet2'
VLAN_MIN = 10
VLAN_MAX = 19
VLAN_RANGES = {PHYS_NET: [(VLAN_MIN, VLAN_MAX)]}
UPDATED_VLAN_RANGES = {PHYS_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)]}
UPDATED_VLAN_RANGES = {PHYS_NET: [(VLAN_MIN + 5, VLAN_MAX + 5)],
PHYS_NET_2: [(VLAN_MIN + 20, VLAN_MAX + 20)]}
TUN_MIN = 100
TUN_MAX = 109
TUNNEL_RANGES = [(TUN_MIN, TUN_MAX)]
Expand All @@ -47,6 +49,8 @@ def test_sync_vlan_allocations(self):
VLAN_MIN).allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MIN + 1).allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MAX - 1).allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MAX).allocated)
self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET,
Expand All @@ -71,6 +75,43 @@ def test_sync_vlan_allocations(self):
self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MAX + 5 + 1))

self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MIN + 20 - 1))
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MIN + 20).
allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MIN + 20 + 1).
allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MAX + 20 - 1).
allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MAX + 20).
allocated)
self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MAX + 20 + 1))

ovs_db_v2.sync_vlan_allocations(VLAN_RANGES)

self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MIN - 1))
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MIN).allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MIN + 1).allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MAX - 1).allocated)
self.assertFalse(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MAX).allocated)
self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET,
VLAN_MAX + 1))

self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MIN + 20))
self.assertIsNone(ovs_db_v2.get_vlan_allocation(PHYS_NET_2,
VLAN_MAX + 20))

def test_vlan_pool(self):
vlan_ids = set()
for x in xrange(VLAN_MIN, VLAN_MAX + 1):
Expand Down Expand Up @@ -138,6 +179,8 @@ def test_sync_tunnel_allocations(self):
self.assertFalse(ovs_db_v2.get_tunnel_allocation(TUN_MIN).allocated)
self.assertFalse(ovs_db_v2.get_tunnel_allocation(TUN_MIN + 1).
allocated)
self.assertFalse(ovs_db_v2.get_tunnel_allocation(TUN_MAX - 1).
allocated)
self.assertFalse(ovs_db_v2.get_tunnel_allocation(TUN_MAX).allocated)
self.assertIsNone(ovs_db_v2.get_tunnel_allocation(TUN_MAX + 1))

Expand Down

0 comments on commit a2fb340

Please sign in to comment.