diff --git a/neutron/db/l3_dvrscheduler_db.py b/neutron/db/l3_dvrscheduler_db.py index b8e3e234aaa..b79d57b8cd0 100644 --- a/neutron/db/l3_dvrscheduler_db.py +++ b/neutron/db/l3_dvrscheduler_db.py @@ -440,20 +440,24 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): for router_id in (router_ids - result_set): subnet_ids = self.get_subnet_ids_on_router( context, router_id, keep_gateway_port=False) - if (subnet_ids and + if (subnet_ids and ( self._check_dvr_serviceable_ports_on_host( context, agent_db['host'], - list(subnet_ids))): + list(subnet_ids)) or + self._is_router_related_to_dvr_routers( + context, router_id, dvr_routers))): result_set.add(router_id) LOG.debug("Routers %(router_ids)s are scheduled or have " "serviceable ports in host %(host)s", {'router_ids': result_set, 'host': agent_db['host']}) - for router_id in router_ids: - result_set |= set( + related_routers = set() + for router_id in result_set: + related_routers |= set( self._get_other_dvr_router_ids_connected_router( context, router_id)) + result_set |= related_routers LOG.debug("Router IDs %(router_ids)s for agent in host %(host)s", {'router_ids': result_set, @@ -506,6 +510,13 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): query = query.filter(host_filter) return query.first() is not None + @log_helpers.log_method_call + def _is_router_related_to_dvr_routers(self, context, router_id, + dvr_routers): + related_routers = self._get_other_dvr_router_ids_connected_router( + context, router_id) + return any([r in dvr_routers for r in related_routers]) + def _notify_l3_agent_new_port(resource, event, trigger, **kwargs): LOG.debug('Received %(resource)s %(event)s', { 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 96d144b910f..38348fbcc9e 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 @@ -1618,6 +1618,56 @@ class L3DvrTestCase(L3DvrTestCaseBase): self.context, self.l3_agent, [router1['id'], router3['id']]) self.assertEqual({router1['id'], router3['id']}, set(ids)) + def test__get_router_ids_for_agent_related_router(self): + router1 = self._create_router() + router2 = self._create_router() + router3 = self._create_router() + arg_list = (portbindings.HOST_ID,) + dvr_l3_agent = helpers.register_l3_agent( + host="host1", agent_mode=constants.L3_AGENT_MODE_DVR) + host = dvr_l3_agent['host'] + with self.subnet() as wan_subnet,\ + self.subnet(cidr='20.0.0.0/24') as subnet1,\ + self.subnet(cidr='30.0.0.0/24') as subnet2,\ + self.subnet(cidr='40.0.0.0/24') as subnet3,\ + self.port(subnet=wan_subnet) as wan_port1,\ + self.port(subnet=wan_subnet) as wan_port2,\ + self.port(subnet=subnet1, + device_owner=constants.DEVICE_OWNER_DHCP, + arg_list=arg_list, + **{portbindings.HOST_ID: host}): + + self.l3_plugin.add_router_interface( + self.context, router1['id'], + {'subnet_id': subnet1['subnet']['id']}) + self.l3_plugin.add_router_interface( + self.context, router2['id'], + {'subnet_id': subnet2['subnet']['id']}) + # Router3 is here just to be sure that it will not be returned as + # is not related to the router1 and router2 in any way + self.l3_plugin.add_router_interface( + self.context, router3['id'], + {'subnet_id': subnet3['subnet']['id']}) + + self.l3_plugin.add_router_interface( + self.context, router1['id'], + {'port_id': wan_port1['port']['id']}) + self.l3_plugin.add_router_interface( + self.context, router2['id'], + {'port_id': wan_port2['port']['id']}) + + ids = self.l3_plugin._get_router_ids_for_agent( + self.context, dvr_l3_agent, []) + self.assertEqual({router1['id'], router2['id']}, set(ids)) + + ids = self.l3_plugin._get_router_ids_for_agent( + self.context, dvr_l3_agent, [router2['id']]) + self.assertEqual({router1['id'], router2['id']}, set(ids)) + + ids = self.l3_plugin._get_router_ids_for_agent( + self.context, dvr_l3_agent, [router1['id']]) + self.assertEqual({router1['id'], router2['id']}, set(ids)) + def test_remove_router_interface(self): HOST1 = 'host1' helpers.register_l3_agent(