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
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:
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
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
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
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)
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),\