Browse Source

[DVR] Related routers should be included if are requested

In case when related dvr router is configured by L3 agent, it is first
added to the tasks queue and then processed as any other router hosted
on the L3 agent.
But if L3 agent will ask neutron server about details of such router,
it wasn't returned back as this router wasn't really scheduled to the
compute node which was asking for it. It was "only" related to some
other router scheduled to this compute node. Because of that router's
info wasn't found in reply from the neutron-server and L3 agent was
removing it from the compute node.

Now _get_router_ids_for_agent method from the l3_dvrscheduler_db module
will check router serviceable ports for each dvr router hosted on the
compute node and will then find all routers related to it. Thanks to
that it will return routers which are on the compute node only because
of other related routers scheduled to this host and such router will not
be deleted anymore.

Change-Id: I689d5135b7194475c846731d846ccf6b25b80b4a
Closes-Bug: #1884527
(cherry picked from commit 38286dbd2e)
changes/62/740462/1
Slawek Kaplonski 3 months ago
parent
commit
afb359f371
2 changed files with 65 additions and 4 deletions
  1. +15
    -4
      neutron/db/l3_dvrscheduler_db.py
  2. +50
    -0
      neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py

+ 15
- 4
neutron/db/l3_dvrscheduler_db.py View File

@@ -431,20 +431,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,
@@ -497,6 +501,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 _dvr_handle_unbound_allowed_addr_pair_add(
plugin, context, port, allowed_address_pair):


+ 50
- 0
neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py View File

@@ -1847,6 +1847,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(


Loading…
Cancel
Save