From ab2e93ffd426cd3f31a1fdd0eb3222e1082d5f57 Mon Sep 17 00:00:00 2001 From: Hemanth Nakkina Date: Fri, 12 Feb 2021 17:44:38 +0530 Subject: [PATCH] Fix deletion of rfp interfaces when router is re-enabled 1. When dvr router is disabled and enabled back, the rfp interfaces are deleted on the nodes without snat-* namespace. This is due to creation of snat namespace during router initialization stage on all the nodes. At later stages, since the gw_port_host is not bounded on this node, external gateway is removed which triggers removal of rfp interfaces and snat namespace. Create snat namespace only on the nodes where gw_port_host is bounded. 2. In case of DVR SNAT, when the l3 agent is rescheduled to another node, the rfp interfaces on qrouter-* namespace are removed. Instead of calling external_gateway_removed() which further deletes the rfp interfaces, the qg-, sg- interfaces need to be unplugged and snat namespace need to be deleted. To resolve unit test errors after clean cherrypick, the bridge is added to the unplug function call in external_gateway_updated. Closes-Bug: #1894843 Change-Id: Ic35c2f9bceacec8eeba67a2b1ea0cd0b0ffc72fe (cherry picked from commit 393d484e07e53496ff068d14047c97d28febd03a) --- neutron/agent/l3/dvr_edge_router.py | 12 +++-- .../functional/agent/l3/test_dvr_router.py | 48 +++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/neutron/agent/l3/dvr_edge_router.py b/neutron/agent/l3/dvr_edge_router.py index c5af8c2ffe9..4abe151ae70 100644 --- a/neutron/agent/l3/dvr_edge_router.py +++ b/neutron/agent/l3/dvr_edge_router.py @@ -71,8 +71,12 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter): if self.snat_namespace.exists(): LOG.debug("SNAT was rescheduled to host %s. Clearing snat " "namespace.", self.router.get('gw_port_host')) - return self.external_gateway_removed( - ex_gw_port, interface_name) + self.driver.unplug( + interface_name, + bridge=self.agent_conf.external_network_bridge, + namespace=self.snat_namespace.name, + prefix=router.EXTERNAL_DEV_PREFIX) + self.snat_namespace.delete() return if not self.snat_namespace.exists(): @@ -179,8 +183,8 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter): # TODO(mlavalle): in the near future, this method should contain the # code in the L3 agent that creates a gateway for a dvr. The first step # is to move the creation of the snat namespace here - self.snat_namespace.create() - return self.snat_namespace + if self._is_this_snat_host(): + self.snat_namespace.create() def _get_snat_int_device_name(self, port_id): long_name = lib_constants.SNAT_INT_DEV_PREFIX + port_id diff --git a/neutron/tests/functional/agent/l3/test_dvr_router.py b/neutron/tests/functional/agent/l3/test_dvr_router.py index 760d49a3e42..d9f7eba4d7d 100644 --- a/neutron/tests/functional/agent/l3/test_dvr_router.py +++ b/neutron/tests/functional/agent/l3/test_dvr_router.py @@ -790,6 +790,54 @@ class TestDvrRouter(framework.L3AgentTestFramework): self._assert_iptables_rules_exist( iptables_mgr, 'nat', expected_rules) + def test_dvr_router_fip_associations_exist_when_router_reenabled(self): + """Test to validate the fip associations when router is re-enabled. + + This test validates the fip associations when the router is disabled + and enabled back again. This test is specifically for the host where + snat namespace is not created or gateway port is binded on other host. + """ + self.agent.conf.agent_mode = 'dvr_snat' + router_info = self.generate_dvr_router_info(enable_snat=True) + # Ensure agent does not create snat namespace by changing gw_port_host + router_info['gw_port_host'] = 'agent2' + router_info_copy = copy.deepcopy(router_info) + router1 = self.manage_router(self.agent, router_info) + + fip_ns_name = router1.fip_ns.name + self.assertTrue(self._namespace_exists(router1.fip_ns.name)) + + # Simulate disable router + self.agent._safe_router_removed(router1.router['id']) + self.assertFalse(self._namespace_exists(router1.ns_name)) + self.assertTrue(self._namespace_exists(fip_ns_name)) + + # Simulated enable router + router_updated = self.manage_router(self.agent, router_info_copy) + self._assert_dvr_floating_ips(router_updated) + + def test_dvr_router_fip_associations_exist_when_snat_removed(self): + """Test to validate the fip associations when snat is removed. + + This test validates the fip associations when the snat is removed from + the agent. The fip associations should exist when the snat is moved to + another l3 agent. + """ + self.agent.conf.agent_mode = 'dvr_snat' + router_info = self.generate_dvr_router_info(enable_snat=True) + router_info_copy = copy.deepcopy(router_info) + router1 = self.manage_router(self.agent, router_info) + + # Remove gateway port host and the binding host_id to simulate + # removal of snat from l3 agent + router_info_copy['gw_port_host'] = '' + router_info_copy['gw_port']['binding:host_id'] = '' + router_info_copy['gw_port']['binding:vif_type'] = 'unbound' + router_info_copy['gw_port']['binding:vif_details'] = {} + self.agent._process_updated_router(router_info_copy) + router_updated = self.agent.router_info[router1.router['id']] + self._assert_dvr_floating_ips(router_updated) + def test_dvr_router_with_ha_for_fip_disassociation(self): """Test to validate the fip rules are deleted in dvr_snat_ha router.