Separate the command for replace_port to delete and add
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
This commit is contained in:
parent
b8d281a303
commit
8b7e5997da
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue