Check that VXLAN is not in use in LB VXLAN check
The Linux bridge VXLAN supported check was only checking that the test interface didn't exist instead of checking that both the interface and the VXLAN didn't exist. This caused it to fail on startup if a VXLAN interface existed under a different name using one of the VXLANs that the agent tried to test support with. This patch adds a check to ensure that the VXLAN ID isn't in use as well. Closes-Bug: #1470579 Change-Id: I3a91ce54da86e319b7a4485dfae3fc99885383d4
This commit is contained in:
parent
50d662d95a
commit
a8d1b72180
|
@ -723,6 +723,14 @@ class IpNetnsCommand(IpCommandBase):
|
|||
return False
|
||||
|
||||
|
||||
def vxlan_in_use(segmentation_id, namespace=None):
|
||||
"""Return True if VXLAN VNID is in use by an interface, else False."""
|
||||
ip_wrapper = IPWrapper(namespace=namespace)
|
||||
interfaces = ip_wrapper.netns.execute(["ip", "-d", "link", "list"],
|
||||
check_exit_code=True)
|
||||
return 'vxlan id %s ' % segmentation_id in interfaces
|
||||
|
||||
|
||||
def device_exists(device_name, namespace=None):
|
||||
"""Return True if the device exists in the namespace."""
|
||||
try:
|
||||
|
|
|
@ -31,6 +31,7 @@ from oslo_log import log as logging
|
|||
import oslo_messaging
|
||||
from oslo_service import loopingcall
|
||||
from oslo_service import service
|
||||
from oslo_utils import excutils
|
||||
from six import moves
|
||||
|
||||
from neutron.agent.linux import bridge_lib
|
||||
|
@ -248,7 +249,19 @@ class LinuxBridgeManager(object):
|
|||
args['tos'] = cfg.CONF.VXLAN.tos
|
||||
if cfg.CONF.VXLAN.l2_population:
|
||||
args['proxy'] = True
|
||||
int_vxlan = self.ip.add_vxlan(interface, segmentation_id, **args)
|
||||
try:
|
||||
int_vxlan = self.ip.add_vxlan(interface, segmentation_id,
|
||||
**args)
|
||||
except RuntimeError:
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
# perform this check after an attempt rather than before
|
||||
# to avoid excessive lookups and a possible race condition.
|
||||
if ip_lib.vxlan_in_use(segmentation_id):
|
||||
ctxt.reraise = False
|
||||
LOG.error(_LE("Unable to create VXLAN interface for "
|
||||
"VNI %s because it is in use by another "
|
||||
"interface."), segmentation_id)
|
||||
return None
|
||||
int_vxlan.link.set_up()
|
||||
LOG.debug("Done creating vxlan interface %s", interface)
|
||||
return interface
|
||||
|
@ -526,10 +539,11 @@ class LinuxBridgeManager(object):
|
|||
|
||||
test_iface = None
|
||||
for seg_id in moves.range(1, p_const.MAX_VXLAN_VNI + 1):
|
||||
if not ip_lib.device_exists(
|
||||
self.get_vxlan_device_name(seg_id)):
|
||||
test_iface = self.ensure_vxlan(seg_id)
|
||||
break
|
||||
if (ip_lib.device_exists(self.get_vxlan_device_name(seg_id))
|
||||
or ip_lib.vxlan_in_use(seg_id)):
|
||||
continue
|
||||
test_iface = self.ensure_vxlan(seg_id)
|
||||
break
|
||||
else:
|
||||
LOG.error(_LE('No valid Segmentation ID to perform UCAST test.'))
|
||||
return False
|
||||
|
|
|
@ -101,6 +101,18 @@ class IpLibTestCase(IpLibTestFramework):
|
|||
self.assertFalse(
|
||||
ip_lib.device_exists(attr.name, namespace=attr.namespace))
|
||||
|
||||
def test_vxlan_exists(self):
|
||||
attr = self.generate_device_details()
|
||||
ip = ip_lib.IPWrapper(namespace=attr.namespace)
|
||||
ip.netns.add(attr.namespace)
|
||||
self.addCleanup(ip.netns.delete, attr.namespace)
|
||||
self.assertFalse(ip_lib.vxlan_in_use(9999, namespace=attr.namespace))
|
||||
device = ip.add_vxlan(attr.name, 9999)
|
||||
self.addCleanup(self._safe_delete_device, device)
|
||||
self.assertTrue(ip_lib.vxlan_in_use(9999, namespace=attr.namespace))
|
||||
device.link.delete()
|
||||
self.assertFalse(ip_lib.vxlan_in_use(9999, namespace=attr.namespace))
|
||||
|
||||
def test_ipwrapper_get_device_by_ip(self):
|
||||
attr = self.generate_device_details()
|
||||
self.manage_device(attr)
|
||||
|
|
|
@ -873,6 +873,7 @@ class TestLinuxBridgeManager(base.BaseTestCase):
|
|||
self, expected, l2_population, iproute_arg_supported, fdb_append):
|
||||
cfg.CONF.set_override('l2_population', l2_population, 'VXLAN')
|
||||
with mock.patch.object(ip_lib, 'device_exists', return_value=False),\
|
||||
mock.patch.object(ip_lib, 'vxlan_in_use', return_value=False),\
|
||||
mock.patch.object(self.lbm,
|
||||
'delete_vxlan',
|
||||
return_value=None),\
|
||||
|
|
Loading…
Reference in New Issue