From bce58c6410dd1f464746e81c71e045f4548bd437 Mon Sep 17 00:00:00 2001 From: Swaminathan Vasudevan Date: Tue, 5 Jul 2016 13:22:04 -0700 Subject: [PATCH] DVR: Cleanup the stale snat redirect rules in router namespace After the stale snat namespace is deleted the snat redirect rules in router namespace should be cleaned. Here we are basically reading the ip rule from the router namespace and just cleaning up all the snat redirect rules leaving the default ones untouched. Closes-Bug: #1599287 (cherry picked from commit 34e51cad42960bdb08a92d1a60a33594bdf057ba) Conflicts: neutron/tests/functional/agent/l3/test_dvr_router.py Change-Id: Ic505a46e56d9e950bd36a1596d3f1adfb5ef5577 --- neutron/agent/l3/dvr_local_router.py | 26 ++++++++++++++++++ neutron/agent/l3/router_info.py | 7 +++++ .../tests/functional/agent/test_l3_agent.py | 27 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/neutron/agent/l3/dvr_local_router.py b/neutron/agent/l3/dvr_local_router.py index a067bb436a4..f6e52c40122 100644 --- a/neutron/agent/l3/dvr_local_router.py +++ b/neutron/agent/l3/dvr_local_router.py @@ -292,6 +292,32 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase): except exceptions.DeviceNotFoundError: pass + def _stale_ip_rule_cleanup(self, ns_ipr, ns_ipd, ip_version): + ip_rules_list = ns_ipr.rule.list_rules(ip_version) + snat_table_list = [] + for ip_rule in ip_rules_list: + snat_table = ip_rule['table'] + priority = ip_rule['priority'] + if snat_table in ['local', 'default', 'main']: + continue + if (ip_version == l3_constants.IP_VERSION_4 and + snat_table in range(dvr_fip_ns.FIP_PR_START, + dvr_fip_ns.FIP_PR_END)): + continue + gateway_cidr = ip_rule['from'] + ns_ipr.rule.delete(ip=gateway_cidr, + table=snat_table, + priority=priority) + snat_table_list.append(snat_table) + for tb in snat_table_list: + ns_ipd.route.flush(ip_version, table=tb) + + def gateway_redirect_cleanup(self, rtr_interface): + ns_ipr = ip_lib.IPRule(namespace=self.ns_name) + ns_ipd = ip_lib.IPDevice(rtr_interface, namespace=self.ns_name) + self._stale_ip_rule_cleanup(ns_ipr, ns_ipd, l3_constants.IP_VERSION_4) + self._stale_ip_rule_cleanup(ns_ipr, ns_ipd, l3_constants.IP_VERSION_6) + def _snat_redirect_modify(self, gateway, sn_port, sn_int, is_add): """Adds or removes rules and routes for SNAT redirection.""" try: diff --git a/neutron/agent/l3/router_info.py b/neutron/agent/l3/router_info.py index e22bc93d74a..60ae7a32b66 100644 --- a/neutron/agent/l3/router_info.py +++ b/neutron/agent/l3/router_info.py @@ -197,6 +197,9 @@ class RouterInfo(object): def add_floating_ip(self, fip, interface_name, device): raise NotImplementedError() + def gateway_redirect_cleanup(self, rtr_interface): + pass + def remove_floating_ip(self, device, ip_cidr): device.delete_addr_and_conntrack_state(ip_cidr) @@ -599,6 +602,10 @@ class RouterInfo(object): elif not ex_gw_port and self.ex_gw_port: self.external_gateway_removed(self.ex_gw_port, interface_name) pd.remove_gw_interface(self.router['id']) + elif not ex_gw_port and not self.ex_gw_port: + for p in self.internal_ports: + interface_name = self.get_internal_device_name(p['id']) + self.gateway_redirect_cleanup(interface_name) existing_devices = self._get_existing_devices() stale_devs = [dev for dev in existing_devices diff --git a/neutron/tests/functional/agent/test_l3_agent.py b/neutron/tests/functional/agent/test_l3_agent.py index 879645fe38e..e82591a4250 100644 --- a/neutron/tests/functional/agent/test_l3_agent.py +++ b/neutron/tests/functional/agent/test_l3_agent.py @@ -1700,6 +1700,33 @@ class TestDvrRouter(L3AgentTestFramework): self.assertFalse(sg_device) self.assertTrue(qg_device) + def test_dvr_router_gateway_redirect_cleanup_on_agent_restart(self): + """Test to validate the router namespace gateway redirect rule cleanup. + + This test checks for the non existence of the gateway redirect + rules in the router namespace after the agent restarts while the + gateway is removed for the router. + """ + self.agent.conf.agent_mode = 'dvr_snat' + router_info = self.generate_dvr_router_info() + router1 = self.manage_router(self.agent, router_info) + self._assert_snat_namespace_exists(router1) + self.assertTrue(self._namespace_exists(router1.ns_name)) + restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport( + self.agent.host, self.agent.conf) + router1.router['gw_port'] = "" + router1.router['gw_port_host'] = "" + router1.router['external_gateway_info'] = "" + restarted_router = self.manage_router(restarted_agent, router1.router) + self.assertTrue(self._namespace_exists(restarted_router.ns_name)) + ns_ipr = ip_lib.IPRule(namespace=router1.ns_name) + ip4_rules_list = ns_ipr.rule.list_rules(l3_constants.IP_VERSION_4) + ip6_rules_list = ns_ipr.rule.list_rules(l3_constants.IP_VERSION_6) + # Just make sure the basic set of rules are there in the router + # namespace + self.assertEqual(3, len(ip4_rules_list)) + self.assertEqual(2, len(ip6_rules_list)) + def _assert_fip_namespace_deleted(self, ext_gateway_port): ext_net_id = ext_gateway_port['network_id'] self.agent.fipnamespace_delete_on_ext_net(