From f6845986446601b92082c811f4181016ef0fefc8 Mon Sep 17 00:00:00 2001 From: Gal Sagie Date: Mon, 30 Mar 2015 10:40:36 +0300 Subject: [PATCH] Suppress exception when trying to remove non existing device in SNAT redirect L3 service plugin first calls to remove_router_interface from the L2 OVS agent which delete this port from OVS and then the service plugin calls to remove the router interface from L3 agent. Catch the exception thrown on the delete gateway, if its due to device doesn't exists ignore the exception Closes-Bug: #1435012 Change-Id: Ieeaa01e7c0393f5200d1a8d2bbbc16befe7699a2 --- neutron/agent/l3/dvr_router.py | 15 +++++++++++++-- neutron/agent/linux/ip_lib.py | 10 +++++++++- neutron/common/exceptions.py | 4 ++++ neutron/tests/functional/agent/test_l3_agent.py | 11 +++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/neutron/agent/l3/dvr_router.py b/neutron/agent/l3/dvr_router.py index 4d2539ff4..d26770590 100644 --- a/neutron/agent/l3/dvr_router.py +++ b/neutron/agent/l3/dvr_router.py @@ -24,6 +24,7 @@ from neutron.agent.l3 import router_info as router from neutron.agent.linux import ip_lib from neutron.agent.linux import iptables_manager from neutron.common import constants as l3_constants +from neutron.common import exceptions from neutron.common import utils as common_utils from neutron.i18n import _LE @@ -246,6 +247,15 @@ class DvrRouter(router.RouterInfo): snat_idx = net.value return snat_idx + def _snat_delete_device_gateway(self, ns_ip_device, gw_ip_addr, + snat_idx): + try: + ns_ip_device.route.delete_gateway(gw_ip_addr, + table=snat_idx) + except exceptions.DeviceNotFoundError: + # Suppress device not exist exception + pass + def _snat_redirect_modify(self, gateway, sn_port, sn_int, is_add): """Adds or removes rules and routes for SNAT redirection.""" try: @@ -271,8 +281,9 @@ class DvrRouter(router.RouterInfo): ['sysctl', '-w', 'net.ipv4.conf.%s.send_redirects=0' % sn_int]) else: - ns_ipd.route.delete_gateway(gw_ip_addr, - table=snat_idx) + self._snat_delete_device_gateway(ns_ipd, + gw_ip_addr, + snat_idx) ns_ipr.rule.delete(sn_port_cidr, snat_idx, snat_idx) break diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py index f2f0f9b09..baf61b90e 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py @@ -18,6 +18,7 @@ import netaddr import os from oslo_config import cfg from oslo_log import log as logging +from oslo_utils import excutils from neutron.agent.common import utils from neutron.common import exceptions @@ -406,7 +407,14 @@ class IpRouteCommand(IpDeviceCommandBase): 'dev', self.name] if table: args += ['table', table] - self._as_root([ip_version], tuple(args)) + try: + self._as_root([ip_version], tuple(args)) + except RuntimeError as rte: + with (excutils.save_and_reraise_exception()) as ctx: + if "Cannot find device" in rte.message: + ctx.reraise = False + raise exceptions.DeviceNotFoundError( + device_name=self.name) def list_onlink_routes(self, ip_version): def iterate_routes(): diff --git a/neutron/common/exceptions.py b/neutron/common/exceptions.py index d5b64c52e..e5212ab4e 100644 --- a/neutron/common/exceptions.py +++ b/neutron/common/exceptions.py @@ -453,3 +453,7 @@ class SubnetPoolDeleteError(BadRequest): class SubnetPoolQuotaExceeded(OverQuota): message = _("Per-tenant subnet pool prefix quota exceeded") + + +class DeviceNotFoundError(NeutronException): + message = _("IP Device '%(device_name)s' does not exist") diff --git a/neutron/tests/functional/agent/test_l3_agent.py b/neutron/tests/functional/agent/test_l3_agent.py index d21ee536f..30f29d4e3 100755 --- a/neutron/tests/functional/agent/test_l3_agent.py +++ b/neutron/tests/functional/agent/test_l3_agent.py @@ -1091,6 +1091,7 @@ class TestDvrRouter(L3AgentTestFramework): ) if gateway_expected_in_snat_namespace: self._assert_dvr_snat_gateway(router) + self._assert_removal_of_already_deleted_gateway_device(router) snat_namespace_should_not_exist = ( self.agent.conf.agent_mode == 'dvr' @@ -1111,6 +1112,16 @@ class TestDvrRouter(L3AgentTestFramework): expected_gateway = external_port['subnets'][0]['gateway_ip'] self.assertEqual(expected_gateway, existing_gateway) + def _assert_removal_of_already_deleted_gateway_device(self, router): + namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name( + router.router_id) + device = ip_lib.IPDevice("fakedevice", + namespace=namespace) + + # Assert that no exception is thrown for this case + self.assertIsNone(router._snat_delete_device_gateway( + device, "192.168.0.1", 0)) + def _assert_snat_namespace_does_not_exist(self, router): namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name( router.router_id) -- 2.45.2