From e585c822e38919451beeb95406c521b09b18e9fc Mon Sep 17 00:00:00 2001 From: Swaminathan Vasudevan Date: Thu, 2 Apr 2015 17:25:39 -0700 Subject: Fix dynamic arp populate error for dvr routers Recent refactor to the L3 Agent have introduced this problem. When we create a VM after we attach an interface to a router or when we add an interface with an existing VM to a router, in both cases the arp entries for the dvr serviced ports are not getting populated in the Router Namespace. Closes-Bug: #1438969 Change-Id: I4a82e2435d176f3d9336d7f0dab9726c063840b9 Co-authored-by: Armando Migliaccio --- neutron/agent/l3/dvr_router.py | 11 ++++++++--- neutron/agent/linux/ip_lib.py | 5 +++++ neutron/tests/functional/agent/test_l3_agent.py | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/neutron/agent/l3/dvr_router.py b/neutron/agent/l3/dvr_router.py index b18cb9aee4..4d2539ff44 100644 --- a/neutron/agent/l3/dvr_router.py +++ b/neutron/agent/l3/dvr_router.py @@ -307,6 +307,14 @@ class DvrRouter(router.RouterInfo): def internal_network_added(self, port): super(DvrRouter, self).internal_network_added(port) + # NOTE: The following function _set_subnet_arp_info + # should be called to dynamically populate the arp + # entries for the dvr services ports into the router + # namespace. This does not have dependency on the + # external_gateway port or the agent_mode. + for subnet in port['subnets']: + self._set_subnet_arp_info(subnet['id']) + ex_gw_port = self.get_ex_gw_port() if not ex_gw_port: return @@ -333,9 +341,6 @@ class DvrRouter(router.RouterInfo): interface_name, dvr_snat_ns.SNAT_INT_DEV_PREFIX) - for subnet in port['subnets']: - self._set_subnet_arp_info(subnet['id']) - def _dvr_internal_network_removed(self, port): if not self.ex_gw_port: return diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py index 330ea3dd65..119dc9341d 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py @@ -544,6 +544,11 @@ class IpNeighCommand(IpDeviceCommandBase): 'lladdr', mac_address, 'dev', self.name)) + def show(self): + return self._as_root([], + ('show', + 'dev', self.name)) + class IpNetnsCommand(IpCommandBase): COMMAND = 'netns' diff --git a/neutron/tests/functional/agent/test_l3_agent.py b/neutron/tests/functional/agent/test_l3_agent.py index 719ab605af..ec5deb025a 100755 --- a/neutron/tests/functional/agent/test_l3_agent.py +++ b/neutron/tests/functional/agent/test_l3_agent.py @@ -1051,6 +1051,26 @@ class TestDvrRouter(L3AgentTestFramework): self._assert_dvr_snat_gateway(router1) self.assertFalse(self._namespace_exists(fip_ns)) + def test_dvr_router_add_internal_network_set_arp_cache(self): + # Check that, when the router is set up and there are + # existing ports on the the uplinked subnet, the ARP + # cache is properly populated. + self.agent.conf.agent_mode = 'dvr_snat' + router_info = test_l3_agent.prepare_router_data() + router_info['distributed'] = True + expected_neighbor = '35.4.1.10' + port_data = { + 'fixed_ips': [{'ip_address': expected_neighbor}], + 'mac_address': 'fa:3e:aa:bb:cc:dd', + 'device_owner': 'compute:None' + } + self.agent.plugin_rpc.get_ports_by_subnet.return_value = [port_data] + router1 = self._create_router(self.agent, router_info) + internal_device = router1.get_internal_device_name( + router_info['_interfaces'][0]['id']) + neighbors = ip_lib.IPDevice(internal_device, router1.ns_name).neigh + self.assertEqual(expected_neighbor, neighbors.show().split()[0]) + def _assert_rfp_fpr_mtu(self, router, expected_mtu=1500): dev_mtu = self.get_device_mtu( router.router_id, router.fip_ns.get_rtr_ext_device_name, -- cgit v1.2.1