]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Check that VXLAN is not in use in LB VXLAN check
authorKevin Benton <blak111@gmail.com>
Wed, 29 Jul 2015 23:32:43 +0000 (16:32 -0700)
committerKevin Benton <blak111@gmail.com>
Fri, 31 Jul 2015 10:04:24 +0000 (04:04 -0600)
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

neutron/agent/linux/ip_lib.py
neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py
neutron/tests/functional/agent/linux/test_ip_lib.py
neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py

index e3268b7aad30b7a6e72d8879a1938c142b3cbf30..cadbd019fb1d4c989168493685050f627b99f86a 100644 (file)
@@ -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:
index b9747a4ec04073945d4667c9f86bc91f806a26ab..861736ef7c2d66f6a720cc0f6d6ca1f2192c0300 100644 (file)
@@ -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
index 8804599ec5bad97dfca6ff649eef32a01c2337aa..4695a964e3ebcf3ad4c1d9bf89d51bd2464cdbea 100644 (file)
@@ -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)
index 55b9bd821b4ce6f0ddb41c6652a5733a8e23cb0d..3f227a9ffa4a5b34bf1b95a01c337c1d7d8ce7ed 100644 (file)
@@ -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),\