]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Separate the command for replace_port to delete and add
authorHong Hui Xiao <xiaohhui@cn.ibm.com>
Tue, 8 Dec 2015 06:17:54 +0000 (01:17 -0500)
committerHong Hui Xiao <xiaohhui@cn.ibm.com>
Thu, 17 Dec 2015 03:06:04 +0000 (22:06 -0500)
When a port has been added to router namespace, trying to replace the
port by adding del-port and add-port in one command, will not bring
the new port to kernel. Even if the port is updated in ovs db and can
be found on br-int, system can't see the new port. This will break
the following actions, which will manipulate the new port by ip
commands. A mail list has been filed to discuss this issue at [1].

The problem here will break the scenario that namespace is deleted
unexpectedly, and l3-agent tries to rebuild the namespace at restart.

Separating replace_port to two commands: del-port and add-port,
matches the original logic and has been verified that it can resolve
the problem here.

[1] http://openvswitch.org/pipermail/discuss/2015-December/019667.html

Change-Id: If36bcf5a0cccb667f3087aea1e9ea9f20eb3a563
Closes-Bug: #1519926

neutron/agent/common/ovs_lib.py
neutron/tests/functional/agent/l3/test_legacy_router.py

index dee22132d7efc942c58ec75524e0d9a5daa47087..a542bb1c09315406f75b88f1ebaefb50b2ad9097 100644 (file)
@@ -230,8 +230,12 @@ class OVSBridge(BaseOVS):
 
     def replace_port(self, port_name, *interface_attr_tuples):
         """Replace existing port or create it, and configure port interface."""
+
+        # NOTE(xiaohhui): If del_port is inside the transaction, there will
+        # only be one command for replace_port. This will cause the new port
+        # not be found by system, which will lead to Bug #1519926.
+        self.ovsdb.del_port(port_name).execute()
         with self.ovsdb.transaction() as txn:
-            txn.add(self.ovsdb.del_port(port_name))
             txn.add(self.ovsdb.add_port(self.br_name, port_name,
                                         may_exist=False))
             if interface_attr_tuples:
index 2f075970d4e76301af597a4aaeffee750393007c..389237fb865055a15e2640279626a9d278d1de4c 100644 (file)
@@ -18,6 +18,7 @@ import mock
 
 from neutron.agent.l3 import namespace_manager
 from neutron.agent.l3 import namespaces
+from neutron.agent.linux import ip_lib
 from neutron.callbacks import events
 from neutron.callbacks import registry
 from neutron.callbacks import resources
@@ -73,6 +74,27 @@ class L3AgentTestCase(framework.L3AgentTestFramework):
         self._router_lifecycle(enable_ha=False, dual_stack=True,
                                v6_ext_gw_with_sub=False)
 
+    def test_legacy_router_ns_rebuild(self):
+        router_info = self.generate_router_info(False)
+        router = self.manage_router(self.agent, router_info)
+        gw_port = router.router['gw_port']
+        gw_inf_name = router.get_external_device_name(gw_port['id'])
+        gw_device = ip_lib.IPDevice(gw_inf_name, namespace=router.ns_name)
+        router_ports = [gw_device]
+        for i_port in router_info.get(l3_constants.INTERFACE_KEY, []):
+            interface_name = router.get_internal_device_name(i_port['id'])
+            router_ports.append(
+                ip_lib.IPDevice(interface_name, namespace=router.ns_name))
+
+        namespaces.Namespace.delete(router.router_namespace)
+
+        # l3 agent should be able to rebuild the ns when it is deleted
+        self.manage_router(self.agent, router_info)
+        # Assert the router ports are there in namespace
+        self.assertTrue(all([port.exists() for port in router_ports]))
+
+        self._delete_router(self.agent, router.router_id)
+
     def test_conntrack_disassociate_fip_legacy_router(self):
         self._test_conntrack_disassociate_fip(ha=False)