diff --git a/neutron/agent/l3/dvr_edge_router.py b/neutron/agent/l3/dvr_edge_router.py index efdf1609e18..c4416d7d873 100644 --- a/neutron/agent/l3/dvr_edge_router.py +++ b/neutron/agent/l3/dvr_edge_router.py @@ -33,6 +33,9 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter): self.router_id, self.agent_conf, self.driver, self.use_ipv6) self.snat_iptables_manager = None + def get_gw_ns_name(self): + return self.snat_namespace.name + def external_gateway_added(self, ex_gw_port, interface_name): super(DvrEdgeRouter, self).external_gateway_added( ex_gw_port, interface_name) diff --git a/neutron/agent/l3/router_info.py b/neutron/agent/l3/router_info.py index a7fe32de66d..f673cfed637 100644 --- a/neutron/agent/l3/router_info.py +++ b/neutron/agent/l3/router_info.py @@ -122,6 +122,9 @@ class RouterInfo(object): def get_external_device_interface_name(self, ex_gw_port): return self.get_external_device_name(ex_gw_port['id']) + def get_gw_ns_name(self): + return self.ns_name + def _update_routing_table(self, operation, route, namespace): cmd = ['ip', 'route', operation, 'to', route['destination'], 'via', route['nexthop']] diff --git a/neutron/agent/linux/pd.py b/neutron/agent/linux/pd.py index 4c8f4b4aaaa..7ec9c4244f7 100644 --- a/neutron/agent/linux/pd.py +++ b/neutron/agent/linux/pd.py @@ -24,7 +24,7 @@ from oslo_utils import netutils import six from stevedore import driver -from neutron._i18n import _ +from neutron._i18n import _, _LE from neutron.callbacks import events from neutron.callbacks import registry from neutron.callbacks import resources @@ -57,6 +57,9 @@ class PrefixDelegation(object): registry.subscribe(add_router, resources.ROUTER, events.BEFORE_CREATE) + registry.subscribe(update_router, + resources.ROUTER, + events.AFTER_UPDATE) registry.subscribe(remove_router, resources.ROUTER, events.AFTER_DELETE) @@ -329,12 +332,24 @@ def get_router_entry(ns_name): def add_router(resource, event, l3_agent, **kwargs): added_router = kwargs['router'] router = l3_agent.pd.routers.get(added_router.router_id) + gw_ns_name = added_router.get_gw_ns_name() if not router: l3_agent.pd.routers[added_router.router_id] = ( - get_router_entry(added_router.ns_name)) + get_router_entry(gw_ns_name)) else: # This will happen during l3 agent restart - router['ns_name'] = added_router.ns_name + router['ns_name'] = gw_ns_name + + +@utils.synchronized("l3-agent-pd") +def update_router(resource, event, l3_agent, **kwargs): + updated_router = kwargs['router'] + router = l3_agent.pd.routers.get(updated_router.router_id) + if not router: + LOG.exception(_LE("Router to be updated is not in internal routers " + "list: %s"), updated_router.router_id) + else: + router['ns_name'] = updated_router.get_gw_ns_name() class PDInfo(object): diff --git a/neutron/tests/unit/agent/l3/test_agent.py b/neutron/tests/unit/agent/l3/test_agent.py index bc8ab15d45d..c541030a1f7 100644 --- a/neutron/tests/unit/agent/l3/test_agent.py +++ b/neutron/tests/unit/agent/l3/test_agent.py @@ -670,8 +670,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): self._set_ri_kwargs(mock.Mock(), router['id'], router) ri = dvr_router.DvrEdgeRouter(HOSTNAME, **self.ri_kwargs) # Make sure that ri.snat_namespace object is created when the - # router is initialized + # router is initialized, and that it's name matches the gw + # namespace name self.assertIsNotNone(ri.snat_namespace) + self.assertEqual(ri.snat_namespace.name, ri.get_gw_ns_name()) def test_ext_gw_updated_calling_snat_ns_delete_if_gw_port_host_none( self): diff --git a/neutron/tests/unit/agent/l3/test_dvr_local_router.py b/neutron/tests/unit/agent/l3/test_dvr_local_router.py index bf484996893..dbf5c64c34d 100644 --- a/neutron/tests/unit/agent/l3/test_dvr_local_router.py +++ b/neutron/tests/unit/agent/l3/test_dvr_local_router.py @@ -164,6 +164,10 @@ class TestDvrRouterOperations(base.BaseTestCase): self.ri_kwargs['router_id'] = router_id self.ri_kwargs['router'] = router + def test_gw_ns_name(self): + ri = self._create_router() + self.assertEqual(ri.ns_name, ri.get_gw_ns_name()) + def test_create_dvr_fip_interfaces_update(self): ri = self._create_router() fip_agent_port = {'subnets': []} diff --git a/neutron/tests/unit/agent/linux/test_pd.py b/neutron/tests/unit/agent/linux/test_pd.py index e12106727dd..2b4a5d444c0 100644 --- a/neutron/tests/unit/agent/linux/test_pd.py +++ b/neutron/tests/unit/agent/linux/test_pd.py @@ -12,6 +12,9 @@ import mock +from neutron.agent.l3 import dvr_edge_router +from neutron.agent.l3 import dvr_local_router +from neutron.agent.l3 import legacy_router from neutron.agent.linux import pd from neutron.tests import base as tests_base @@ -24,8 +27,68 @@ class FakeRouter(object): class TestPrefixDelegation(tests_base.DietTestCase): def test_remove_router(self): l3_agent = mock.Mock() - router_id = 1 + router_id = '1' l3_agent.pd.routers = {router_id: pd.get_router_entry(None)} pd.remove_router(None, None, l3_agent, router=FakeRouter(router_id)) self.assertTrue(l3_agent.pd.delete_router_pd.called) self.assertEqual({}, l3_agent.pd.routers) + + def _test_add_update_pd(self, l3_agent, router, ns_name): + # add entry + pd.add_router(None, None, l3_agent, router=router) + pd_router = l3_agent.pd.routers.get(router.router_id) + self.assertEqual(ns_name, pd_router.get('ns_name')) + + # clear namespace name, update entry + pd_router['ns_name'] = None + pd.update_router(None, None, l3_agent, router=router) + pd_router = l3_agent.pd.routers.get(router.router_id) + self.assertEqual(ns_name, pd_router.get('ns_name')) + + def test_add_update_dvr_edge_router(self): + l3_agent = mock.Mock() + l3_agent.pd.routers = {} + router_id = '1' + ri = dvr_edge_router.DvrEdgeRouter(l3_agent, + 'host', + router_id, + mock.Mock(), + mock.Mock(), + mock.Mock()) + ns_name = ri.snat_namespace.name + self._test_add_update_pd(l3_agent, ri, ns_name) + + def test_add_update_dvr_local_router(self): + l3_agent = mock.Mock() + l3_agent.pd.routers = {} + router_id = '1' + ri = dvr_local_router.DvrLocalRouter(l3_agent, + 'host', + router_id, + mock.Mock(), + mock.Mock(), + mock.Mock()) + ns_name = ri.ns_name + self._test_add_update_pd(l3_agent, ri, ns_name) + + def test_add_update_legacy_router(self): + l3_agent = mock.Mock() + l3_agent.pd.routers = {} + router_id = '1' + ri = legacy_router.LegacyRouter(l3_agent, + router_id, + mock.Mock(), + mock.Mock(), + mock.Mock()) + ns_name = ri.ns_name + self._test_add_update_pd(l3_agent, ri, ns_name) + + def test_update_no_router_exception(self): + l3_agent = mock.Mock() + l3_agent.pd.routers = {} + router = mock.Mock() + router.router_id = '1' + + with mock.patch.object(pd.LOG, 'exception') as log: + pd.update_router(None, None, l3_agent, router=router) + self.assertTrue(log.called)