From 1cd4b8ed5af8c5ce734f2bba68dd644b8039cf1f Mon Sep 17 00:00:00 2001 From: LIU Yulong Date: Wed, 26 Sep 2018 15:58:11 +0800 Subject: [PATCH] Do not install centralized FIP if HA port is down The issue scenario happens when we disassociate a floating IP while the 'master' router host is restarted or powered-off. When the L3 agent is powered-on again, the HA router state config still remains 'master', but the ha port is down. And the message queue still has one 'router_update' message (floating IP disassociate message), so the L3 agent will sync this router info at least twice during the restart, one is the router_update, the other is the L3 agent full-sync. The first one will add the centralized FIP to the qg-device, because the router state is 'master'. So for DVR HA routers, only add the centralized floating IP to the qg-device in the snat-namespace when the HA port is up. For the restart procedure, if the HA port is up, but the router is set to 'backup', do not add the floating IP. Closes-Bug: #1794305 Change-Id: Ib39fe7dcd437a867c69852885c461a594167f6a1 (cherry picked from commit 656a8f872970013ff4c0bc577266cbe7f0343037) --- neutron/agent/l3/dvr_edge_ha_router.py | 5 ++- .../unit/agent/l3/test_dvr_local_router.py | 35 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/neutron/agent/l3/dvr_edge_ha_router.py b/neutron/agent/l3/dvr_edge_ha_router.py index 15d7a8dbaef..9c9035f4ab7 100644 --- a/neutron/agent/l3/dvr_edge_ha_router.py +++ b/neutron/agent/l3/dvr_edge_ha_router.py @@ -61,7 +61,10 @@ class DvrEdgeHaRouter(dvr_edge_router.DvrEdgeRouter, interface_name = self.get_snat_external_device_interface_name( self.get_ex_gw_port()) self._add_vip(fip_cidr, interface_name) - if self.is_router_master(): + + self.ha_port = self.router.get(constants.HA_INTERFACE_KEY) + if (self.is_router_master() and self.ha_port and + self.ha_port['status'] == constants.PORT_STATUS_ACTIVE): return super(DvrEdgeHaRouter, self).add_centralized_floatingip( fip, fip_cidr) else: 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 2e0e83ddb18..233327a855c 100644 --- a/neutron/tests/unit/agent/l3/test_dvr_local_router.py +++ b/neutron/tests/unit/agent/l3/test_dvr_local_router.py @@ -814,11 +814,13 @@ class TestDvrRouterOperations(base.BaseTestCase): @mock.patch.object(dvr_edge_rtr.DvrEdgeRouter, 'add_centralized_floatingip') - def test_add_centralized_floatingip(self, - super_add_centralized_floatingip): + def test_add_centralized_floatingip_dvr_ha( + self, + super_add_centralized_floatingip): agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) agent.conf.agent_mode = lib_constants.L3_AGENT_MODE_DVR_SNAT - router = l3_test_common.prepare_router_data(num_internal_ports=2) + router = l3_test_common.prepare_router_data( + num_internal_ports=2, enable_ha=True) router['gw_port_host'] = HOSTNAME self.mock_driver.unplug.reset_mock() self._set_ri_kwargs(agent, router['id'], router) @@ -834,13 +836,26 @@ class TestDvrRouterOperations(base.BaseTestCase): ri._add_vip.assert_called_once_with(fip_cidr, interface_name) super_add_centralized_floatingip.assert_not_called() - ri1 = dvr_edge_ha_rtr.DvrEdgeHaRouter(HOSTNAME, [], **self.ri_kwargs) - ri1.is_router_master = mock.Mock(return_value=True) - ri1._add_vip = mock.Mock() - interface_name = ri1.get_snat_external_device_interface_name( - ri1.get_ex_gw_port()) - ri1.add_centralized_floatingip(fip, fip_cidr) - ri1._add_vip.assert_called_once_with(fip_cidr, interface_name) + router[lib_constants.HA_INTERFACE_KEY]['status'] = 'DOWN' + self._set_ri_kwargs(agent, router['id'], router) + ri_1 = dvr_edge_ha_rtr.DvrEdgeHaRouter(HOSTNAME, [], **self.ri_kwargs) + ri_1.is_router_master = mock.Mock(return_value=True) + ri_1._add_vip = mock.Mock() + interface_name = ri_1.get_snat_external_device_interface_name( + ri_1.get_ex_gw_port()) + ri_1.add_centralized_floatingip(fip, fip_cidr) + ri_1._add_vip.assert_called_once_with(fip_cidr, interface_name) + super_add_centralized_floatingip.assert_not_called() + + router[lib_constants.HA_INTERFACE_KEY]['status'] = 'ACTIVE' + self._set_ri_kwargs(agent, router['id'], router) + ri_2 = dvr_edge_ha_rtr.DvrEdgeHaRouter(HOSTNAME, [], **self.ri_kwargs) + ri_2.is_router_master = mock.Mock(return_value=True) + ri_2._add_vip = mock.Mock() + interface_name = ri_2.get_snat_external_device_interface_name( + ri_2.get_ex_gw_port()) + ri_2.add_centralized_floatingip(fip, fip_cidr) + ri_2._add_vip.assert_called_once_with(fip_cidr, interface_name) super_add_centralized_floatingip.assert_called_once_with(fip, fip_cidr)