From 51c53ea40a30e0fcfbe9e4184f63fe4c1887ed6f Mon Sep 17 00:00:00 2001 From: lzklibj Date: Sat, 21 Mar 2015 09:58:15 -0700 Subject: [PATCH] fix l3-agent restart with last runtime fip for dvr In DVR enabled environment, after we associated a floating IP to a VM, when we restart L3-agent on the same compute node, the L3-agent will miss to create rtr_fip_subnet for router_info. The previous floating IP can still work, but new associated floating IPs to VMs related to the same router on this L3-agent will fail to configure and not work. This patch will fix this. The method create_dvr_fip_interfaces in dvr_router.py will invoke fip_ns.create_rtr_2_fip_link, and the later one will create rtr_fip_subnet, consider VMs related to the same router will share the same rtr_fip_subnet, so processing here should run only once for those VMs, once rtr_fip_subnet is created. Current code will check dist_fip_count then decide to invoke fip_ns.create_rtr_2_fip_link or not. dist_fip_count should be zero if a router related VMs never have been associated with any floating IPs before. But if a router has floating IPs associated to its related VMs, after it is restared, dist_fip_count will be non-zero, and this is the point this patch try to fix. And for case rtr_fip_subnet has been created, both dist_fip_count and is_fisrt will be false, and fip_ns.create_rtr_2_fip_link will be no more need to be invoked. Change-Id: I3786eab86755a403991728ccb72d03f159ff8b63 Closes-Bug: 1434824 --- neutron/agent/l3/dvr_router.py | 3 +- neutron/tests/unit/agent/l3/test_agent.py | 52 +++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/neutron/agent/l3/dvr_router.py b/neutron/agent/l3/dvr_router.py index 4d2539ff4..39a8d4b93 100644 --- a/neutron/agent/l3/dvr_router.py +++ b/neutron/agent/l3/dvr_router.py @@ -498,6 +498,7 @@ class DvrRouter(router.RouterInfo): ex_gw_port['network_id']) LOG.debug("FloatingIP agent gateway port received from the plugin: " "%s", fip_agent_port) + is_first = False if floating_ips: is_first = self.fip_ns.subscribe(self.router_id) if is_first and fip_agent_port: @@ -507,7 +508,7 @@ class DvrRouter(router.RouterInfo): self.fip_ns.create_gateway_port(fip_agent_port) if self.fip_ns.agent_gateway_port and floating_ips: - if self.dist_fip_count == 0: + if self.dist_fip_count == 0 or is_first: self.fip_ns.create_rtr_2_fip_link(self) # kicks the FW Agent to add rules for the IR namespace if diff --git a/neutron/tests/unit/agent/l3/test_agent.py b/neutron/tests/unit/agent/l3/test_agent.py index 0f0eb7f5f..1dca8ac12 100644 --- a/neutron/tests/unit/agent/l3/test_agent.py +++ b/neutron/tests/unit/agent/l3/test_agent.py @@ -1200,6 +1200,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): ri.fip_ns = agent.get_fip_ns(ext_gw_port['network_id']) ri.dist_fip_count = 0 ri.fip_ns.subscribe = mock.Mock() + ri.fip_ns.agent_router_gateway = mock.Mock() with contextlib.nested(mock.patch.object(ri, 'get_floating_ips'), @@ -1214,6 +1215,57 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): self.assertTrue(fips.called) self.assertEqual(ri.fip_ns.agent_gateway_port, agent_gateway_port[0]) + self.assertTrue(ri.rtr_fip_subnet) + + def test_create_dvr_fip_interfaces_for_restart_l3agent_case(self): + fake_floatingips = {'floatingips': [ + {'id': _uuid(), + 'floating_ip_address': '20.0.0.3', + 'fixed_ip_address': '192.168.0.1', + 'floating_network_id': _uuid(), + 'port_id': _uuid(), + 'host': HOSTNAME}]} + agent_gateway_port = ( + [{'fixed_ips': [ + {'ip_address': '20.0.0.30', + 'prefixlen': 24, + 'subnet_id': 'subnet_id'}], + 'subnets': [ + {'id': 'subnet_id', + 'gateway_ip': '20.0.0.1'}], + 'id': _uuid(), + 'network_id': 'fake_network_id', + 'mac_address': 'ca:fe:de:ad:be:ef'}] + ) + + router = prepare_router_data(enable_snat=True) + router[l3_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips'] + router[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = agent_gateway_port + router['distributed'] = True + agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) + ri = dvr_router.DvrRouter( + agent, HOSTNAME, router['id'], router, **self.ri_kwargs) + ext_gw_port = ri.router.get('gw_port') + ri.fip_ns = agent.get_fip_ns(ext_gw_port['network_id']) + ri.fip_ns.subscribe = mock.Mock(return_value=True) + ri.fip_ns.agent_router_gateway = mock.Mock() + ri.rtr_fip_subnet = None + ri.dist_fip_count = 1 + + with contextlib.nested(mock.patch.object( + ri, 'get_floating_ips'), + mock.patch.object( + ri, 'get_floating_agent_gw_interface') + ) as (fips, + fip_gw_port): + fips.return_value = fake_floatingips + fip_gw_port.return_value = agent_gateway_port[0] + ri.create_dvr_fip_interfaces(ext_gw_port) + self.assertTrue(fip_gw_port.called) + self.assertTrue(fips.called) + self.assertEqual(ri.fip_ns.agent_gateway_port, + agent_gateway_port[0]) + self.assertTrue(ri.rtr_fip_subnet) def test_process_router_cent_floating_ip_add(self): fake_floatingips = {'floatingips': [ -- 2.45.2