From be7d0bb6abc893e53dfc864c52506928b1d38fa3 Mon Sep 17 00:00:00 2001 From: Hemanth Nakkina Date: Fri, 2 Jul 2021 17:01:55 +0530 Subject: [PATCH] Update arp entry of snat port on qrouter ns In some cases, the arp entry of snat port is not updated in qrouter namespace. l3-agent calls get_ports_by_subnet() while setting arps for the subnet. And the snat port is not returned if it is still unbound. One of the scenario this is observed is when router is created, external gateway set and internal subnet attached to router in quick succession. This patch retrieves snat port details from router info as well and updates arp entry for snat port. Closes-Bug: #1933092 Change-Id: I7ee797b4b930306cf6360922d855f8b24f1b813d --- neutron/agent/l3/dvr_local_router.py | 13 +++++++++++++ neutron/tests/unit/agent/l3/test_agent.py | 1 + .../tests/unit/agent/l3/test_dvr_local_router.py | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/neutron/agent/l3/dvr_local_router.py b/neutron/agent/l3/dvr_local_router.py index af5ce59f792..4f753685cdb 100644 --- a/neutron/agent/l3/dvr_local_router.py +++ b/neutron/agent/l3/dvr_local_router.py @@ -336,6 +336,19 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase): 'add', device=device, device_exists=device_exists) + + # subnet_ports does not have snat port if the port is still unbound + # by the time this function is called. So ensure to add arp entry + # for snat port if port details are updated in router info. + for p in self.get_snat_interfaces(): + for fixed_ip in p['fixed_ips']: + if fixed_ip['subnet_id'] == subnet_id: + self._update_arp_entry(fixed_ip['ip_address'], + p['mac_address'], + subnet_id, + 'add', + device=device, + device_exists=device_exists) self._process_arp_cache_for_internal_port(subnet_id) @staticmethod diff --git a/neutron/tests/unit/agent/l3/test_agent.py b/neutron/tests/unit/agent/l3/test_agent.py index 30e3caa8a35..8154dd3dbe0 100644 --- a/neutron/tests/unit/agent/l3/test_agent.py +++ b/neutron/tests/unit/agent/l3/test_agent.py @@ -1271,6 +1271,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): router[lib_constants.INTERFACE_KEY][0]) ri.router['distributed'] = True ri.router['_snat_router_interfaces'] = [{ + 'mac_address': 'fa:16:3e:80:8d:80', 'fixed_ips': [{'subnet_id': subnet_id, 'ip_address': '1.2.3.4'}]}] ri.router['gw_port_host'] = None 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 4c913815bbe..d30e5ced38f 100644 --- a/neutron/tests/unit/agent/l3/test_dvr_local_router.py +++ b/neutron/tests/unit/agent/l3/test_dvr_local_router.py @@ -545,6 +545,11 @@ class TestDvrRouterOperations(base.BaseTestCase): ri = dvr_router.DvrLocalRouter(HOSTNAME, **self.ri_kwargs) ports = ri.router.get(lib_constants.INTERFACE_KEY, []) subnet_id = l3_test_common.get_subnet_id(ports[0]) + ri.router['_snat_router_interfaces'] = [{ + 'mac_address': 'fa:16:3e:80:8d:80', + 'fixed_ips': [{'subnet_id': subnet_id, + 'ip_address': '1.2.3.10'}]}] + test_ports = [{'mac_address': '00:11:22:33:44:55', 'device_owner': lib_constants.DEVICE_OWNER_DHCP, 'fixed_ips': [{'ip_address': '1.2.3.4', @@ -576,7 +581,8 @@ class TestDvrRouterOperations(base.BaseTestCase): self.assertEqual(1, parp.call_count) self.mock_ip_dev.neigh.add.assert_has_calls([ mock.call('1.2.3.4', '00:11:22:33:44:55'), - mock.call('10.20.30.40', '00:11:22:33:44:55')]) + mock.call('10.20.30.40', '00:11:22:33:44:55'), + mock.call('1.2.3.10', 'fa:16:3e:80:8d:80')]) # Test negative case router['distributed'] = False