From 2a1cdf01b58f42bfdf20cccdf7db209493897356 Mon Sep 17 00:00:00 2001 From: LIU Yulong Date: Thu, 20 Sep 2018 21:30:09 +0800 Subject: [PATCH] Install centralized floating IP nat rules to all ha nodes For L3 DVR HA router, the centralized floating IP nat rules are not installed in every HA node snat namespace. So, install the rules to all the router snat-namespace on every scheduled HA router host. Conflicts: neutron/tests/common/l3_test_common.py neutron/tests/functional/agent/l3/test_dvr_router.py Closes-Bug: #1793527 Change-Id: I08132510b3ed374a3f85146498f3624a103873d7 (cherry picked from commit ee7660f593f0f997fff457021b3d5feb5c71906d) --- neutron/agent/l3/dvr_edge_router.py | 8 ++ neutron/agent/l3/dvr_local_router.py | 35 ++++++ neutron/tests/common/l3_test_common.py | 21 +++- .../tests/functional/agent/l3/framework.py | 6 +- .../functional/agent/l3/test_dvr_router.py | 118 ++++++++++++------ neutron/tests/unit/agent/l3/test_agent.py | 45 +++++-- .../unit/agent/l3/test_dvr_local_router.py | 3 + 7 files changed, 188 insertions(+), 48 deletions(-) diff --git a/neutron/agent/l3/dvr_edge_router.py b/neutron/agent/l3/dvr_edge_router.py index 3ad41922132..36ba61065d1 100644 --- a/neutron/agent/l3/dvr_edge_router.py +++ b/neutron/agent/l3/dvr_edge_router.py @@ -352,3 +352,11 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter): for fip in floating_ips: self._set_floating_ip_nat_rules_for_centralized_floatingip(fip) self.snat_iptables_manager.apply() + + def process_floating_ip_nat_rules(self): + if self._is_this_snat_host(): + self.process_floating_ip_nat_rules_for_centralized_floatingip() + + # Cover mixed dvr_snat and compute node, aka a dvr_snat node has both + # centralized and distributed floating IPs. + super(DvrEdgeRouter, self).process_floating_ip_nat_rules() diff --git a/neutron/agent/l3/dvr_local_router.py b/neutron/agent/l3/dvr_local_router.py index 3125ef8945c..5b0f5edb4d4 100644 --- a/neutron/agent/l3/dvr_local_router.py +++ b/neutron/agent/l3/dvr_local_router.py @@ -67,6 +67,12 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase): if fip.get(lib_constants.DVR_SNAT_BOUND): return [] + # For dvr_no_external node should not process any floating IP + # iptables rules. + if (self.agent_conf.agent_mode == + lib_constants.L3_AGENT_MODE_DVR_NO_EXTERNAL): + return [] + fixed_ip = fip['fixed_ip_address'] floating_ip = fip['floating_ip_address'] rtr_2_fip_name = self.fip_ns.get_rtr_ext_device_name(self.router_id) @@ -120,6 +126,12 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase): # the floating IP is intended for this host should # be done. return + + # dvr_no_external host should not process any floating IP route rules. + if (self.agent_conf.agent_mode == + lib_constants.L3_AGENT_MODE_DVR_NO_EXTERNAL): + return + floating_ip = fip['floating_ip_address'] fixed_ip = fip['fixed_ip_address'] self._add_floating_ip_rule(floating_ip, fixed_ip) @@ -525,6 +537,29 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase): def external_gateway_updated(self, ex_gw_port, interface_name): pass + def process_floating_ip_nat_rules(self): + """Configure NAT rules for the router's floating IPs. + + Configures iptables rules for the floating ips of the given router + """ + # Clear out all iptables rules for floating ips + self.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip') + + floating_ips = self.get_floating_ips() + # Loop once to ensure that floating ips are configured. + for fip in floating_ips: + # If floating IP is snat_bound, then the iptables rule should + # not be installed to qrouter namespace, since the mixed snat + # namespace may already install it. + if fip.get(lib_constants.DVR_SNAT_BOUND): + continue + # Rebuild iptables rules for the floating ip. + for chain, rule in self.floating_forward_rules(fip): + self.iptables_manager.ipv4['nat'].add_rule( + chain, rule, tag='floating_ip') + + self.iptables_manager.apply() + def external_gateway_removed(self, ex_gw_port, interface_name): # TODO(Carl) Should this be calling process_snat_dnat_for_fip? self.process_floating_ip_nat_rules() diff --git a/neutron/tests/common/l3_test_common.py b/neutron/tests/common/l3_test_common.py index b70eb9ecf1c..ffa59ed0622 100644 --- a/neutron/tests/common/l3_test_common.py +++ b/neutron/tests/common/l3_test_common.py @@ -55,8 +55,10 @@ def get_ha_interface(ip='169.254.192.1', mac='12:34:56:78:2b:5d'): def prepare_router_data(ip_version=4, enable_snat=None, num_internal_ports=1, enable_floating_ip=False, enable_ha=False, - extra_routes=False, dual_stack=False, - enable_gw=True, v6_ext_gw_with_sub=True, **kwargs): + extra_routes=False, dual_stack=False, enable_gw=True, + v6_ext_gw_with_sub=True, + snat_bound_fip=False, + **kwargs): fixed_ips = [] subnets = [] gateway_mac = kwargs.get('gateway_mac', 'ca:fe:de:ad:be:ee') @@ -110,6 +112,7 @@ def prepare_router_data(ip_version=4, enable_snat=None, num_internal_ports=1, 'routes': routes, 'gw_port': ex_gw_port} + router_fips = router.get(lib_constants.FLOATINGIP_KEY, []) if enable_floating_ip: fip = {'id': _uuid(), 'port_id': _uuid(), @@ -119,7 +122,19 @@ def prepare_router_data(ip_version=4, enable_snat=None, num_internal_ports=1, qos_policy_id = kwargs.get(qos_consts.QOS_POLICY_ID) if qos_policy_id: fip[qos_consts.QOS_POLICY_ID] = qos_policy_id - router[lib_constants.FLOATINGIP_KEY] = [fip] + router_fips.append(fip) + + if snat_bound_fip: + fip = {'id': _uuid(), + 'port_id': _uuid(), + 'status': 'DOWN', + 'floating_ip_address': '19.4.4.3', + 'fixed_ip_address': '10.0.0.2'} + qos_policy_id = kwargs.get(qos_consts.QOS_POLICY_ID) + if qos_policy_id: + fip[qos_consts.QOS_POLICY_ID] = qos_policy_id + router_fips.append(fip) + router[lib_constants.FLOATINGIP_KEY] = router_fips router_append_interface(router, count=num_internal_ports, ip_version=ip_version, dual_stack=dual_stack) diff --git a/neutron/tests/functional/agent/l3/framework.py b/neutron/tests/functional/agent/l3/framework.py index 6b8c82e3cc4..e01074f15be 100644 --- a/neutron/tests/functional/agent/l3/framework.py +++ b/neutron/tests/functional/agent/l3/framework.py @@ -473,7 +473,11 @@ class L3AgentTestFramework(base.BaseSudoTestCase): self.assertFalse(router.iptables_manager.is_chain_empty( 'nat', 'POSTROUTING')) - def _assert_floating_ip_chains(self, router): + def _assert_floating_ip_chains(self, router, snat_bound_fip=False): + if snat_bound_fip: + self.assertFalse(router.snat_iptables_manager.is_chain_empty( + 'nat', 'float-snat')) + self.assertFalse(router.iptables_manager.is_chain_empty( 'nat', 'float-snat')) diff --git a/neutron/tests/functional/agent/l3/test_dvr_router.py b/neutron/tests/functional/agent/l3/test_dvr_router.py index 0aa0e90a0e3..dcf3201fdbd 100644 --- a/neutron/tests/functional/agent/l3/test_dvr_router.py +++ b/neutron/tests/functional/agent/l3/test_dvr_router.py @@ -71,6 +71,14 @@ class TestDvrRouter(framework.L3AgentTestFramework): def test_dvr_router_lifecycle_ha_with_snat_with_fips(self): self._dvr_router_lifecycle(enable_ha=True, enable_snat=True) + def test_dvr_lifecycle_no_ha_with_snat_with_fips_with_cent_fips(self): + self._dvr_router_lifecycle(enable_ha=False, enable_snat=True, + snat_bound_fip=True) + + def test_dvr_lifecycle_ha_with_snat_with_fips_with_cent_fips(self): + self._dvr_router_lifecycle(enable_ha=True, enable_snat=True, + snat_bound_fip=True) + def _helper_create_dvr_router_fips_for_ext_network( self, agent_mode, **dvr_router_kwargs): self.agent.conf.agent_mode = agent_mode @@ -406,7 +414,10 @@ class TestDvrRouter(framework.L3AgentTestFramework): self._validate_fips_for_external_network(router2, fip2_ns) def _dvr_router_lifecycle(self, enable_ha=False, enable_snat=False, - custom_mtu=2000, ip_version=4, dual_stack=False): + custom_mtu=2000, + ip_version=lib_constants.IP_VERSION_4, + dual_stack=False, + snat_bound_fip=False): '''Test dvr router lifecycle :param enable_ha: sets the ha value for the router. @@ -421,7 +432,8 @@ class TestDvrRouter(framework.L3AgentTestFramework): # We get the router info particular to a dvr router router_info = self.generate_dvr_router_info( - enable_ha, enable_snat, extra_routes=True) + enable_ha, enable_snat, extra_routes=True, + snat_bound_fip=snat_bound_fip) for key in ('_interfaces', '_snat_router_interfaces', '_floatingip_agent_interfaces'): for port in router_info[key]: @@ -478,9 +490,9 @@ class TestDvrRouter(framework.L3AgentTestFramework): self._assert_internal_devices(router) self._assert_dvr_external_device(router) self._assert_dvr_gateway(router) - self._assert_dvr_floating_ips(router) + self._assert_dvr_floating_ips(router, snat_bound_fip=snat_bound_fip) self._assert_snat_chains(router) - self._assert_floating_ip_chains(router) + self._assert_floating_ip_chains(router, snat_bound_fip=snat_bound_fip) self._assert_metadata_chains(router) self._assert_rfp_fpr_mtu(router, custom_mtu) if enable_snat: @@ -521,21 +533,33 @@ class TestDvrRouter(framework.L3AgentTestFramework): extra_routes=extra_routes, num_internal_ports=2, enable_gw=enable_gw, + snat_bound_fip=snat_bound_fip, **kwargs) internal_ports = router.get(lib_constants.INTERFACE_KEY, []) router['distributed'] = True router['gw_port_host'] = agent.conf.host if enable_floating_ip: - floating_ip = router['_floatingips'][0] + for floating_ip in router[lib_constants.FLOATINGIP_KEY]: floating_ip['host'] = agent.conf.host - if snat_bound_fip: - floating_ip[lib_constants.DVR_SNAT_BOUND] = True if enable_floating_ip and enable_centralized_fip: # For centralizing the fip, we are emulating the legacy # router behavior were the fip dict does not contain any # host information. - floating_ip['host'] = None + router[lib_constants.FLOATINGIP_KEY][0]['host'] = None + + # In order to test the mixed dvr_snat and compute scenario, we create + # two floating IPs, one is distributed, another is centralized. + # The distributed floating IP should have the host, which was + # just set to None above, then we set it back. The centralized + # floating IP has host None, and this IP will be used to test + # migration from centralized to distributed. + if snat_bound_fip: + router[lib_constants.FLOATINGIP_KEY][0]['host'] = agent.conf.host + router[lib_constants.FLOATINGIP_KEY][1][ + lib_constants.DVR_SNAT_BOUND] = True + router[lib_constants.FLOATINGIP_KEY][1]['host'] = None + if enable_gw: external_gw_port = router['gw_port'] router['gw_port'][portbindings.HOST_ID] = agent.conf.host @@ -545,11 +569,11 @@ class TestDvrRouter(framework.L3AgentTestFramework): # the agent type the dvr supports. The namespace creation is # dependent on the agent_type. if enable_floating_ip: - floating_ip = router['_floatingips'][0] - floating_ip['floating_network_id'] = ( - external_gw_port['network_id']) - floating_ip['port_id'] = internal_ports[0]['id'] - floating_ip['status'] = 'ACTIVE' + for index, floating_ip in enumerate(router['_floatingips']): + floating_ip['floating_network_id'] = ( + external_gw_port['network_id']) + floating_ip['port_id'] = internal_ports[index]['id'] + floating_ip['status'] = 'ACTIVE' self._add_fip_agent_gw_port_info_to_router(router, external_gw_port) @@ -717,7 +741,7 @@ class TestDvrRouter(framework.L3AgentTestFramework): router.router_id) self.assertFalse(self._namespace_exists(namespace)) - def _assert_dvr_floating_ips(self, router): + def _assert_dvr_floating_ips(self, router, snat_bound_fip=False): # in the fip namespace: # Check that the fg- (floatingip_agent_gateway) # is created with the ip address of the external gateway port @@ -755,8 +779,12 @@ class TestDvrRouter(framework.L3AgentTestFramework): # correctly for fip in floating_ips: expected_rules = router.floating_forward_rules(fip) + if fip.get(lib_constants.DVR_SNAT_BOUND): + iptables_mgr = router.snat_iptables_manager + else: + iptables_mgr = router.iptables_manager self._assert_iptables_rules_exist( - router.iptables_manager, 'nat', expected_rules) + iptables_mgr, 'nat', expected_rules) def test_dvr_router_with_ha_for_fip_disassociation(self): """Test to validate the fip rules are deleted in dvr_snat_ha router. @@ -884,6 +912,7 @@ class TestDvrRouter(framework.L3AgentTestFramework): for rule in expected_rules: self.assertIn( str(iptables_manager.IptablesRule(rule[0], rule[1])), rules) + return True def test_prevent_snat_rule_exist_on_restarted_agent(self): self.agent.conf.agent_mode = 'dvr_snat' @@ -928,8 +957,7 @@ class TestDvrRouter(framework.L3AgentTestFramework): # existing ports on the uplinked subnet, the ARP # cache is properly populated. self.agent.conf.agent_mode = 'dvr_snat' - router_info = l3_test_common.prepare_router_data() - router_info['distributed'] = True + router_info = self.generate_dvr_router_info(enable_snat=True) expected_neighbor = '35.4.1.10' port_data = { 'fixed_ips': [{'ip_address': expected_neighbor}], @@ -1076,8 +1104,9 @@ class TestDvrRouter(framework.L3AgentTestFramework): # In the snat namespace, check the iptables rules are set correctly for fip in snat_bound_floatingips: expected_rules = router1.floating_forward_rules(fip) - self._assert_iptables_rules_exist( - router1.snat_iptables_manager, 'nat', expected_rules) + if fip.get(lib_constants.DVR_SNAT_BOUND): + self._assert_iptables_rules_exist( + router1.snat_iptables_manager, 'nat', expected_rules) def test_floating_ip_migration_from_unbound_to_bound(self): """Test to check floating ips migrate from unboun to bound host.""" @@ -1086,33 +1115,51 @@ class TestDvrRouter(framework.L3AgentTestFramework): enable_floating_ip=True, enable_centralized_fip=True, enable_snat=True, snat_bound_fip=True) router1 = self.manage_router(self.agent, router_info) - centralized_floatingips = router_info[lib_constants.FLOATINGIP_KEY] + floatingips = router_info[lib_constants.FLOATINGIP_KEY] + distributed_fip = floatingips[0] + centralized_floatingip = floatingips[1] # For private ports hosted in dvr_no_fip agent, the floatingip # dict will contain the fip['host'] key, but the value will always # be None to emulate the legacy router. - self.assertIsNone(centralized_floatingips[0]['host']) + self.assertIsNone(centralized_floatingip['host']) self.assertTrue(self._namespace_exists(router1.ns_name)) fip_ns = router1.fip_ns.get_name() self.assertTrue(self._namespace_exists(fip_ns)) self._assert_snat_namespace_exists(router1) # If fips are centralized then, the DNAT rules are only # configured in the SNAT Namespace and not in the router-ns. - router_ns = router1.ns_name - fixed_ip = centralized_floatingips[0]['fixed_ip_address'] - for fip in centralized_floatingips: - expected_rules = router1.floating_forward_rules(fip) - self.assertFalse(self._assert_iptables_rules_exist( - router1.snat_iptables_manager, 'nat', expected_rules)) - self.assertFalse(self._fixed_ip_rule_exists(router_ns, fixed_ip)) - # Now let us edit the floatingIP info with 'host' and remove - # the 'dvr_snat_bound' - router1.router[lib_constants.FLOATINGIP_KEY][0]['host'] = ( + expected_rules = router1.floating_forward_rules(distributed_fip) + self.assertTrue(self._assert_iptables_rules_exist( + router1.iptables_manager, 'nat', expected_rules)) + expected_rules = router1._centralized_floating_forward_rules( + centralized_floatingip['floating_ip_address'], + centralized_floatingip['fixed_ip_address']) + self.assertTrue(self._assert_iptables_rules_exist( + router1.snat_iptables_manager, 'nat', expected_rules)) + qrouter_ns = router1.ns_name + fixed_ip_dist = distributed_fip['fixed_ip_address'] + snat_ns = router1.snat_namespace.name + fixed_ip_cent = centralized_floatingip['fixed_ip_address'] + self.assertFalse(self._fixed_ip_rule_exists(qrouter_ns, fixed_ip_cent)) + self.assertTrue(self._fixed_ip_rule_exists(qrouter_ns, fixed_ip_dist)) + self.assertFalse(self._fixed_ip_rule_exists(snat_ns, fixed_ip_dist)) + self.assertFalse(self._fixed_ip_rule_exists(snat_ns, fixed_ip_cent)) + # Now let us edit the centralized floatingIP info with 'host' + # and remove the 'dvr_snat_bound' + router1.router[lib_constants.FLOATINGIP_KEY][1]['host'] = ( self.agent.conf.host) - del router1.router[lib_constants.FLOATINGIP_KEY][0]['dvr_snat_bound'] + del router1.router[lib_constants.FLOATINGIP_KEY][1]['dvr_snat_bound'] self.agent._process_updated_router(router1.router) router_updated = self.agent.router_info[router_info['id']] - router_ns = router_updated.ns_name - self.assertTrue(self._fixed_ip_rule_exists(router_ns, fixed_ip)) + + qrouter_ns = router_updated.ns_name + fixed_ip_dist = distributed_fip['fixed_ip_address'] + snat_ns = router_updated.snat_namespace.name + fixed_ip_cent = centralized_floatingip['fixed_ip_address'] + self.assertTrue(self._fixed_ip_rule_exists(qrouter_ns, fixed_ip_dist)) + self.assertFalse(self._fixed_ip_rule_exists(snat_ns, fixed_ip_dist)) + self.assertTrue(self._fixed_ip_rule_exists(qrouter_ns, fixed_ip_cent)) + self.assertFalse(self._fixed_ip_rule_exists(snat_ns, fixed_ip_cent)) self.assertTrue(self._namespace_exists(fip_ns)) def test_floating_ip_not_deployed_on_dvr_no_external_agent(self): @@ -1134,8 +1181,7 @@ class TestDvrRouter(framework.L3AgentTestFramework): # configured in the SNAT Namespace and not in the router-ns. for fip in centralized_floatingips: expected_rules = router1.floating_forward_rules(fip) - self.assertFalse(self._assert_iptables_rules_exist( - router1.iptables_manager, 'nat', expected_rules)) + self.assertEqual(0, len(expected_rules)) def test_floating_ip_create_does_not_raise_keyerror_on_missing_host(self): """Test to check floating ips configure does not raise Keyerror.""" diff --git a/neutron/tests/unit/agent/l3/test_agent.py b/neutron/tests/unit/agent/l3/test_agent.py index 33f24b97150..c0ceceb0658 100644 --- a/neutron/tests/unit/agent/l3/test_agent.py +++ b/neutron/tests/unit/agent/l3/test_agent.py @@ -702,6 +702,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): return_value=sn_port) ri._snat_redirect_remove = mock.Mock() if router.get('distributed'): + ri.snat_iptables_manager = iptables_manager.IptablesManager( + namespace=ri.snat_namespace.name, use_ipv6=ri.use_ipv6) ri.fip_ns.delete_rtr_2_fip_link = mock.Mock() ri.router['gw_port'] = "" ri.external_gateway_removed(ex_gw_port, interface_name) @@ -1034,6 +1036,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) self._set_ri_kwargs(agent, router['id'], router) ri = dvr_router.DvrEdgeRouter(HOSTNAME, **self.ri_kwargs) + ri.snat_iptables_manager = iptables_manager.IptablesManager( + namespace=ri.snat_namespace.name, use_ipv6=ri.use_ipv6) subnet_id = l3_test_common.get_subnet_id( router[lib_constants.INTERFACE_KEY][0]) ri.router['distributed'] = True @@ -1041,15 +1045,17 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): 'fixed_ips': [{'subnet_id': subnet_id, 'ip_address': '1.2.3.4'}]}] ri.router['gw_port_host'] = None - self._test_process_router(ri, agent) + self._test_process_router(ri, agent, is_dvr_edge=True) - def _test_process_router(self, ri, agent): + def _test_process_router(self, ri, agent, is_dvr_edge=False): router = ri.router agent.host = HOSTNAME fake_fip_id = 'fake_fip_id' ri.create_dvr_external_gateway_on_agent = mock.Mock() ri.process_floating_ip_addresses = mock.Mock() ri.process_floating_ip_nat_rules = mock.Mock() + ri.process_floating_ip_nat_rules_for_centralized_floatingip = ( + mock.Mock()) ri.process_floating_ip_addresses.return_value = { fake_fip_id: 'ACTIVE'} ri.external_gateway_added = mock.Mock() @@ -1064,8 +1070,14 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): ri.process() ri.process_floating_ip_addresses.assert_called_with(mock.ANY) ri.process_floating_ip_addresses.reset_mock() - ri.process_floating_ip_nat_rules.assert_called_with() - ri.process_floating_ip_nat_rules.reset_mock() + if not is_dvr_edge: + ri.process_floating_ip_nat_rules.assert_called_with() + ri.process_floating_ip_nat_rules.reset_mock() + elif ri.router.get('gw_port_host') == agent.host: + ri.process_floating_ip_nat_rules_for_centralized_floatingip. \ + assert_called_with() + ri.process_floating_ip_nat_rules_for_centralized_floatingip. \ + reset_mock() ri.external_gateway_added.reset_mock() # remap floating IP to a new fixed ip @@ -1076,8 +1088,14 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): ri.process() ri.process_floating_ip_addresses.assert_called_with(mock.ANY) ri.process_floating_ip_addresses.reset_mock() - ri.process_floating_ip_nat_rules.assert_called_with() - ri.process_floating_ip_nat_rules.reset_mock() + if not is_dvr_edge: + ri.process_floating_ip_nat_rules.assert_called_with() + ri.process_floating_ip_nat_rules.reset_mock() + elif ri.router.get('gw_port_host') == agent.host: + ri.process_floating_ip_nat_rules_for_centralized_floatingip. \ + assert_called_with() + ri.process_floating_ip_nat_rules_for_centralized_floatingip. \ + reset_mock() self.assertEqual(0, ri.external_gateway_added.call_count) self.assertEqual(0, ri.external_gateway_updated.call_count) ri.external_gateway_added.reset_mock() @@ -1101,8 +1119,14 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): ri.process() ri.process_floating_ip_addresses.assert_called_with(mock.ANY) ri.process_floating_ip_addresses.reset_mock() - ri.process_floating_ip_nat_rules.assert_called_with() - ri.process_floating_ip_nat_rules.reset_mock() + if not is_dvr_edge: + ri.process_floating_ip_nat_rules.assert_called_with() + ri.process_floating_ip_nat_rules.reset_mock() + elif ri.router.get('gw_port_host') == agent.host: + ri.process_floating_ip_nat_rules_for_centralized_floatingip. \ + assert_called_with() + ri.process_floating_ip_nat_rules_for_centralized_floatingip. \ + reset_mock() # now no ports so state is torn down del router[lib_constants.INTERFACE_KEY] @@ -2264,6 +2288,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): num_internal_ports=1) self._set_ri_kwargs(agent, router['id'], router) ri = dvr_router.DvrEdgeRouter(HOSTNAME, **self.ri_kwargs) + ri.snat_iptables_manager = iptables_manager.IptablesManager( + namespace=ri.snat_namespace.name, use_ipv6=ri.use_ipv6) self.mock_ip.get_devices.return_value = stale_devlist ri.process() @@ -2780,6 +2806,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): agent._fetch_external_net_id = mock.Mock(return_value=external_net_id) ri.ex_gw_port = ri.router['gw_port'] del ri.router['gw_port'] + ri.external_gateway_added( + ri.ex_gw_port, + ri.get_external_device_name(ri.ex_gw_port['id'])) ri.fip_ns = None nat = ri.iptables_manager.ipv4['nat'] nat.clear_rules_by_tag = mock.Mock() 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 233327a855c..b2300fa9bea 100644 --- a/neutron/tests/unit/agent/l3/test_dvr_local_router.py +++ b/neutron/tests/unit/agent/l3/test_dvr_local_router.py @@ -736,6 +736,9 @@ class TestDvrRouterOperations(base.BaseTestCase): agent._fetch_external_net_id = mock.Mock(return_value=external_net_id) ri.ex_gw_port = ri.router['gw_port'] del ri.router['gw_port'] + ri.external_gateway_added( + ri.ex_gw_port, + ri.get_external_device_name(ri.ex_gw_port['id'])) ri.fip_ns = None nat = ri.iptables_manager.ipv4['nat'] nat.clear_rules_by_tag = mock.Mock()