Change check_ports_exist_on_l3agent to pass the subnet_ids

The get_subnet_ids_on_router is called for every
available l3agent in check_ports_exist_on_l3agent.
This introduces un-necessary call to the same
function multiple times which is expensive since it
calls get_ports internally.

In large scale the time taken to schedule a VM
on a given N-Node increases.

By passing the subnet_ids to check_ports_exist_on_l3agent
we would be only calling once get_subnet_ids_on_router in
the get_l3_agent_candidates.

This patch addresses the above problem by calling
get_subnet_ids_on_router just once.

Change-Id: I9d130f98e07bfe571eee32b827ff9af4010ff0fb
Related-Bug: #1513678
This commit is contained in:
Swaminathan Vasudevan 2015-11-04 18:02:09 -08:00
parent 21ca26e50a
commit 062ad0a0a6
5 changed files with 44 additions and 43 deletions

View File

@ -439,15 +439,12 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
if agentschedulers_db.AgentSchedulerDbMixin.is_eligible_agent( if agentschedulers_db.AgentSchedulerDbMixin.is_eligible_agent(
active, l3_agent)] active, l3_agent)]
def check_ports_exist_on_l3agent(self, context, l3_agent, router_id): def check_ports_exist_on_l3agent(
self, context, l3_agent, subnet_ids):
""" """
This function checks for existence of dvr serviceable This function checks for existence of dvr serviceable
ports on the host, running the input l3agent. ports on the host, running the input l3agent.
""" """
subnet_ids = self.get_subnet_ids_on_router(context, router_id)
if not subnet_ids:
return False
core_plugin = manager.NeutronManager.get_plugin() core_plugin = manager.NeutronManager.get_plugin()
# NOTE(swami):Before checking for existence of dvr # NOTE(swami):Before checking for existence of dvr
# serviceable ports on the host managed by the l3 # serviceable ports on the host managed by the l3
@ -479,6 +476,10 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
ignore_admin_state=False): ignore_admin_state=False):
"""Get the valid l3 agents for the router from a list of l3_agents.""" """Get the valid l3 agents for the router from a list of l3_agents."""
candidates = [] candidates = []
is_router_distributed = sync_router.get('distributed', False)
if is_router_distributed:
subnet_ids = self.get_subnet_ids_on_router(
context, sync_router['id'])
for l3_agent in l3_agents: for l3_agent in l3_agents:
if not ignore_admin_state and not l3_agent.admin_state_up: if not ignore_admin_state and not l3_agent.admin_state_up:
# ignore_admin_state True comes from manual scheduling # ignore_admin_state True comes from manual scheduling
@ -500,16 +501,15 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
(ex_net_id and gateway_external_network_id and (ex_net_id and gateway_external_network_id and
ex_net_id != gateway_external_network_id)): ex_net_id != gateway_external_network_id)):
continue continue
is_router_distributed = sync_router.get('distributed', False)
if agent_mode in ( if agent_mode in (
constants.L3_AGENT_MODE_LEGACY, constants.L3_AGENT_MODE_LEGACY,
constants.L3_AGENT_MODE_DVR_SNAT) and ( constants.L3_AGENT_MODE_DVR_SNAT) and (
not is_router_distributed): not is_router_distributed):
candidates.append(l3_agent) candidates.append(l3_agent)
elif is_router_distributed and agent_mode.startswith( elif (is_router_distributed and subnet_ids and
constants.L3_AGENT_MODE_DVR) and ( agent_mode.startswith(constants.L3_AGENT_MODE_DVR) and (
self.check_ports_exist_on_l3agent( self.check_ports_exist_on_l3agent(
context, l3_agent, sync_router['id'])): context, l3_agent, subnet_ids))):
candidates.append(l3_agent) candidates.append(l3_agent)
return candidates return candidates

View File

@ -375,11 +375,14 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
constants.L3_ROUTER_NAT) constants.L3_ROUTER_NAT)
l3_agents = plugin.get_l3_agents_hosting_routers(context, l3_agents = plugin.get_l3_agents_hosting_routers(context,
[router['id']]) [router['id']])
for l3_agent in l3_agents: subnet_ids = plugin.get_subnet_ids_on_router(
if not plugin.check_ports_exist_on_l3agent(context, l3_agent, context, router['id'])
router['id']): if subnet_ids:
plugin.remove_router_from_l3_agent( for l3_agent in l3_agents:
context, l3_agent['id'], router['id']) if not plugin.check_ports_exist_on_l3agent(
context, l3_agent, subnet_ids):
plugin.remove_router_from_l3_agent(
context, l3_agent['id'], router['id'])
router_interface_info = self._make_router_interface_info( router_interface_info = self._make_router_interface_info(
router['id'], port['tenant_id'], port['id'], subnet['id'], router['id'], port['tenant_id'], port['id'], subnet['id'],
[subnet['id']]) [subnet['id']])

View File

@ -758,13 +758,18 @@ class OvsAgentSchedulerTestCase(OvsAgentSchedulerTestCaseBase):
router = {'name': 'router1', router = {'name': 'router1',
'admin_state_up': True, 'admin_state_up': True,
'distributed': True} 'distributed': True}
subnet_ids = {'id': '1234'}
r = self.l3plugin.create_router( r = self.l3plugin.create_router(
self.adminContext, {'router': router}) self.adminContext, {'router': router})
dvr_agent = self._register_dvr_agents()[1] dvr_agent = self._register_dvr_agents()[1]
with mock.patch.object( with mock.patch.object(
self.l3plugin, self.l3plugin,
'check_ports_exist_on_l3agent') as port_exists: 'check_ports_exist_on_l3agent') as port_exists,\
mock.patch.object(
self.l3plugin,
'get_subnet_ids_on_router') as rtr_subnets:
rtr_subnets.return_value = [subnet_ids]
port_exists.return_value = True port_exists.return_value = True
self.l3plugin.schedule_router( self.l3plugin.schedule_router(
self.adminContext, r['id']) self.adminContext, r['id'])

View File

@ -483,6 +483,8 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
plugin = mock.MagicMock() plugin = mock.MagicMock()
plugin.get_l3_agents_hosting_routers = mock.Mock( plugin.get_l3_agents_hosting_routers = mock.Mock(
return_value=[mock.MagicMock()]) return_value=[mock.MagicMock()])
plugin.get_subnet_ids_on_router = mock.Mock(
return_value=interface_info)
plugin.check_ports_exist_on_l3agent = mock.Mock( plugin.check_ports_exist_on_l3agent = mock.Mock(
return_value=False) return_value=False)
plugin.remove_router_from_l3_agent = mock.Mock( plugin.remove_router_from_l3_agent = mock.Mock(
@ -519,6 +521,8 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
router_dict = {'name': 'test_router', 'admin_state_up': True, router_dict = {'name': 'test_router', 'admin_state_up': True,
'distributed': True} 'distributed': True}
router = self._create_router(router_dict) router = self._create_router(router_dict)
plugin = mock.MagicMock()
plugin.get_subnet_ids_on_router = mock.Mock()
with self.network() as net_ext,\ with self.network() as net_ext,\
self.subnet() as subnet1,\ self.subnet() as subnet1,\
self.subnet(cidr='20.0.0.0/24') as subnet2: self.subnet(cidr='20.0.0.0/24') as subnet2:
@ -550,7 +554,8 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
with mock.patch.object(manager.NeutronManager, with mock.patch.object(manager.NeutronManager,
'get_service_plugins') as get_svc_plugin: 'get_service_plugins') as get_svc_plugin:
get_svc_plugin.return_value = { get_svc_plugin.return_value = {
plugin_const.L3_ROUTER_NAT: self.mixin} plugin_const.L3_ROUTER_NAT: plugin}
self.mixin.manager = manager
self.mixin.remove_router_interface( self.mixin.remove_router_interface(
self.ctx, router['id'], {'port_id': dvr_ports[0]['id']}) self.ctx, router['id'], {'port_id': dvr_ports[0]['id']})
@ -563,6 +568,7 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
dvr_ports = self.core_plugin.get_ports( dvr_ports = self.core_plugin.get_ports(
self.ctx, filters=dvr_filters) self.ctx, filters=dvr_filters)
self.assertEqual(1, len(dvr_ports)) self.assertEqual(1, len(dvr_ports))
self.assertEqual(1, plugin.get_subnet_ids_on_router.call_count)
def test__validate_router_migration_notify_advanced_services(self): def test__validate_router_migration_notify_advanced_services(self):
router = {'name': 'foo_router', 'admin_state_up': False} router = {'name': 'foo_router', 'admin_state_up': False}

View File

@ -616,6 +616,7 @@ class L3SchedulerTestBaseMixin(object):
agent_list = [self.agent1, self.l3_dvr_agent] agent_list = [self.agent1, self.l3_dvr_agent]
# test dvr agent_mode case only dvr agent should be candidate # test dvr agent_mode case only dvr agent should be candidate
router['distributed'] = True router['distributed'] = True
self.get_subnet_ids_on_router = mock.Mock()
self.check_ports_exist_on_l3agent = mock.Mock(return_value=True) self.check_ports_exist_on_l3agent = mock.Mock(return_value=True)
self._check_get_l3_agent_candidates(router, agent_list, HOST_DVR) self._check_get_l3_agent_candidates(router, agent_list, HOST_DVR)
@ -629,6 +630,7 @@ class L3SchedulerTestBaseMixin(object):
agent_list = [self.agent1, self.l3_dvr_agent] agent_list = [self.agent1, self.l3_dvr_agent]
router['distributed'] = True router['distributed'] = True
# Test no VMs present case # Test no VMs present case
self.get_subnet_ids_on_router = mock.Mock()
self.check_ports_exist_on_l3agent = mock.Mock(return_value=False) self.check_ports_exist_on_l3agent = mock.Mock(return_value=False)
self._check_get_l3_agent_candidates( self._check_get_l3_agent_candidates(
router, agent_list, HOST_DVR, count=0) router, agent_list, HOST_DVR, count=0)
@ -643,6 +645,7 @@ class L3SchedulerTestBaseMixin(object):
router['distributed'] = True router['distributed'] = True
agent_list = [self.l3_dvr_snat_agent] agent_list = [self.l3_dvr_snat_agent]
self.get_subnet_ids_on_router = mock.Mock()
self.check_ports_exist_on_l3agent = mock.Mock(return_value=True) self.check_ports_exist_on_l3agent = mock.Mock(return_value=True)
self._check_get_l3_agent_candidates(router, agent_list, HOST_DVR_SNAT) self._check_get_l3_agent_candidates(router, agent_list, HOST_DVR_SNAT)
@ -658,6 +661,7 @@ class L3SchedulerTestBaseMixin(object):
agent_list = [self.l3_dvr_snat_agent] agent_list = [self.l3_dvr_snat_agent]
self.check_ports_exist_on_l3agent = mock.Mock(return_value=False) self.check_ports_exist_on_l3agent = mock.Mock(return_value=False)
# Test no VMs present case # Test no VMs present case
self.get_subnet_ids_on_router = mock.Mock()
self.check_ports_exist_on_l3agent.return_value = False self.check_ports_exist_on_l3agent.return_value = False
self._check_get_l3_agent_candidates( self._check_get_l3_agent_candidates(
router, agent_list, HOST_DVR_SNAT, count=0) router, agent_list, HOST_DVR_SNAT, count=0)
@ -684,14 +688,13 @@ class L3SchedulerTestBaseMixin(object):
router['external_gateway_info'] = None router['external_gateway_info'] = None
router['id'] = str(uuid.uuid4()) router['id'] = str(uuid.uuid4())
self.plugin.get_ports = mock.Mock(return_value=[]) self.plugin.get_ports = mock.Mock(return_value=[])
self.get_subnet_ids_on_router = mock.Mock(return_value=[]) return l3_agent
return l3_agent, router
def test_check_ports_exist_on_l3agent_no_subnets(self): def test_check_ports_exist_on_l3agent_no_subnets(self):
l3_agent, router = self._prepare_check_ports_exist_tests() l3_agent = self._prepare_check_ports_exist_tests()
# no subnets # no subnets
val = self.check_ports_exist_on_l3agent(self.adminContext, val = self.check_ports_exist_on_l3agent(
l3_agent, router['id']) self.adminContext, l3_agent, [])
self.assertFalse(val) self.assertFalse(val)
def test_check_ports_exist_on_l3agent_with_dhcp_enabled_subnets(self): def test_check_ports_exist_on_l3agent_with_dhcp_enabled_subnets(self):
@ -707,38 +710,24 @@ class L3SchedulerTestBaseMixin(object):
subnet = {'id': str(uuid.uuid4()), subnet = {'id': str(uuid.uuid4()),
'enable_dhcp': True} 'enable_dhcp': True}
self.get_subnet_ids_on_router = mock.Mock(
return_value=[subnet['id']])
self.plugin.get_subnet = mock.Mock(return_value=subnet) self.plugin.get_subnet = mock.Mock(return_value=subnet)
self.plugin.get_ports = mock.Mock() self.plugin.get_ports = mock.Mock()
val = self.check_ports_exist_on_l3agent( val = self.check_ports_exist_on_l3agent(
self.adminContext, agent_list[0], router['id']) self.adminContext, agent_list[0], [subnet['id']])
self.assertTrue(val) self.assertTrue(val)
self.assertFalse(self.plugin.get_ports.called) self.assertFalse(self.plugin.get_ports.called)
def test_check_ports_exist_on_l3agent_if_no_subnets_then_return(self):
l3_agent, router = self._prepare_check_ports_exist_tests()
with mock.patch.object(manager.NeutronManager,
'get_plugin') as getp:
getp.return_value = self.plugin
# no subnets and operation is remove_router_interface,
# so return immediately without calling get_ports
self.check_ports_exist_on_l3agent(self.adminContext,
l3_agent, router['id'])
self.assertFalse(self.plugin.get_ports.called)
def test_check_ports_exist_on_l3agent_no_subnet_match(self): def test_check_ports_exist_on_l3agent_no_subnet_match(self):
l3_agent, router = self._prepare_check_ports_exist_tests() l3_agent = self._prepare_check_ports_exist_tests()
# no matching subnet # no matching subnet
self.plugin.get_subnet_ids_on_router = mock.Mock( self.plugin.get_subnet_ids_on_router = mock.Mock(
return_value=[str(uuid.uuid4())]) return_value=[str(uuid.uuid4())])
val = self.check_ports_exist_on_l3agent(self.adminContext, val = self.check_ports_exist_on_l3agent(self.adminContext,
l3_agent, router['id']) l3_agent, [])
self.assertFalse(val) self.assertFalse(val)
def test_check_ports_exist_on_l3agent_subnet_match(self): def test_check_ports_exist_on_l3agent_subnet_match(self):
l3_agent, router = self._prepare_check_ports_exist_tests() l3_agent = self._prepare_check_ports_exist_tests()
# matching subnet # matching subnet
port = {'subnet_id': str(uuid.uuid4()), port = {'subnet_id': str(uuid.uuid4()),
'binding:host_id': 'host_1', 'binding:host_id': 'host_1',
@ -747,11 +736,9 @@ class L3SchedulerTestBaseMixin(object):
subnet = {'id': str(uuid.uuid4()), subnet = {'id': str(uuid.uuid4()),
'enable_dhcp': False} 'enable_dhcp': False}
self.plugin.get_ports.return_value = [port] self.plugin.get_ports.return_value = [port]
self.get_subnet_ids_on_router = mock.Mock(
return_value=[port['subnet_id']])
self.plugin.get_subnet = mock.Mock(return_value=subnet) self.plugin.get_subnet = mock.Mock(return_value=subnet)
val = self.check_ports_exist_on_l3agent(self.adminContext, val = self.check_ports_exist_on_l3agent(self.adminContext,
l3_agent, router['id']) l3_agent, [port['subnet_id']])
self.assertTrue(val) self.assertTrue(val)
def test_get_l3_agents_hosting_routers(self): def test_get_l3_agents_hosting_routers(self):