diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index 738f2f9c801..cf47e6e7a05 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -716,27 +716,46 @@ class _DVRAgentInterfaceMixin(object): # All unbound ports with floatingip irrespective of # the device owner should be included as valid ports # and updated. - port_host = port[portbindings.HOST_ID] - if (port_host == host or port_in_migration or + if (port_in_migration or self._is_unbound_port(port)): port_dict.update({port['id']: port}) - if port_host and port_host != host: - # Consider the ports where the portbinding host and - # request host does not match. + continue + port_host = port[portbindings.HOST_ID] + if port_host: l3_agent_on_host = self.get_l3_agents( context, filters={'host': [port_host]}) + l3_agent_mode = '' if len(l3_agent_on_host): l3_agent_mode = self._get_agent_mode( l3_agent_on_host[0]) - # If the agent requesting is dvr_snat but - # the portbinding host resides in dvr_no_external - # agent then include the port. - requesting_agent_mode = self._get_agent_mode(agent) + requesting_agent_mode = self._get_agent_mode(agent) + # Consider the ports where the portbinding host and + # request host match. + if port_host == host: + # Check for agent type before adding the port_dict. + # For VMs that are hosted on the dvr_no_external + # agent and if the request is coming from the same + # agent on re-syncs then we need to add the appropriate + # port['agent'] before updating the dict. if (l3_agent_mode == ( l3_const.L3_AGENT_MODE_DVR_NO_EXTERNAL) and requesting_agent_mode == ( - const.L3_AGENT_MODE_DVR_SNAT)): + l3_const.L3_AGENT_MODE_DVR_NO_EXTERNAL)): + port['agent'] = ( + l3_const.L3_AGENT_MODE_DVR_NO_EXTERNAL) + + port_dict.update({port['id']: port}) + # Consider the ports where the portbinding host and + # request host does not match. + else: + # If the agent requesting is dvr_snat but + # the portbinding host resides in dvr_no_external + # agent then include the port. + if (l3_agent_mode == ( + l3_const.L3_AGENT_MODE_DVR_NO_EXTERNAL) and + requesting_agent_mode == ( + const.L3_AGENT_MODE_DVR_SNAT)): port['agent'] = ( l3_const.L3_AGENT_MODE_DVR_NO_EXTERNAL) port_dict.update({port['id']: port}) diff --git a/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py b/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py index 194c3a43ea2..936c352b8a0 100644 --- a/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py +++ b/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py @@ -969,6 +969,16 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.context, self.l3_agent['host'], [router['id']])) floatingips = router_info[0][constants.FLOATINGIP_KEY] self.assertTrue(floatingips[0][n_const.DVR_SNAT_BOUND]) + # Test case to make sure when an agent in this case + # dvr_no_external restarts and does a full sync, we need + # to make sure that the returned router_info has + # DVR_SNAT_BOUND flag enabled, otherwise the floating IP + # state would error out. + router_sync_info = ( + self.l3_plugin.list_active_sync_routers_on_active_l3_agent( + self.context, HOST1, [router['id']])) + floatingips = router_sync_info[0][constants.FLOATINGIP_KEY] + self.assertTrue(floatingips[0][n_const.DVR_SNAT_BOUND]) def test_allowed_addr_pairs_delayed_fip_and_update_arp_entry(self): HOST1 = 'host1'