From 226c999de3e342bf7ce667e21f4ab685b7fd5622 Mon Sep 17 00:00:00 2001 From: Oleg Bondarev Date: Wed, 2 Dec 2015 14:52:30 +0300 Subject: [PATCH] DVR: optimize check_ports_exist_on_l3_agent() Currently the function gets all ports on the subnet and iterates through them to find dvr serviceable ports on a particular host. This patch makes it a single DB query to see if any port exists matching criterias. Partial-Bug: #1513678 Change-Id: Ie17885497aacb8fda4a2c4a05f19d08991038557 Co-Authored-By: Oleg Bondarev --- neutron/common/utils.py | 17 +++++++++++++---- neutron/db/l3_agentschedulers_db.py | 27 +++++++++++++++++---------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/neutron/common/utils.py b/neutron/common/utils.py index 7237fd9d8..63af63599 100644 --- a/neutron/common/utils.py +++ b/neutron/common/utils.py @@ -367,6 +367,18 @@ class exception_logger(object): return call +def get_other_dvr_serviced_device_owners(): + """Return device_owner names for ports that should be serviced by DVR + + This doesn't return DEVICE_OWNER_COMPUTE_PREFIX since it is a + prefix, not a complete device_owner name, so should be handled + separately (see is_dvr_serviced() below) + """ + return [n_const.DEVICE_OWNER_LOADBALANCER, + n_const.DEVICE_OWNER_LOADBALANCERV2, + n_const.DEVICE_OWNER_DHCP] + + def is_dvr_serviced(device_owner): """Check if the port need to be serviced by DVR @@ -375,11 +387,8 @@ def is_dvr_serviced(device_owner): if they are required for DVR or any service directly or indirectly associated with DVR. """ - dvr_serviced_device_owners = (n_const.DEVICE_OWNER_LOADBALANCER, - n_const.DEVICE_OWNER_LOADBALANCERV2, - n_const.DEVICE_OWNER_DHCP) return (device_owner.startswith(n_const.DEVICE_OWNER_COMPUTE_PREFIX) or - device_owner in dvr_serviced_device_owners) + device_owner in get_other_dvr_serviced_device_owners()) @debtcollector.removals.remove(message="This will removed in the N cycle.") diff --git a/neutron/db/l3_agentschedulers_db.py b/neutron/db/l3_agentschedulers_db.py index 996dcdaca..d6ab00ead 100644 --- a/neutron/db/l3_agentschedulers_db.py +++ b/neutron/db/l3_agentschedulers_db.py @@ -33,6 +33,7 @@ from neutron.db import agents_db from neutron.db import agentschedulers_db from neutron.db import l3_attrs_db from neutron.db import model_base +from neutron.db import models_v2 from neutron.extensions import l3agentscheduler from neutron.extensions import portbindings from neutron.extensions import router_availability_zone as router_az @@ -455,21 +456,27 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase, if agentschedulers_db.AgentSchedulerDbMixin.is_eligible_agent( active, l3_agent)] - def check_ports_exist_on_l3agent( - self, context, l3_agent, subnet_ids): + def check_ports_exist_on_l3agent(self, context, l3_agent, subnet_ids): """ This function checks for existence of dvr serviceable ports on the host, running the input l3agent. """ + # db query will return ports for all subnets if subnet_ids is empty, + # so need to check first + if not subnet_ids: + return False + core_plugin = manager.NeutronManager.get_plugin() - filter = {'fixed_ips': {'subnet_id': subnet_ids}} - ports = core_plugin.get_ports(context, filters=filter) - for port in ports: - if (n_utils.is_dvr_serviced(port['device_owner']) and - l3_agent['host'] == port[portbindings.HOST_ID]): - return True - - return False + filters = {'fixed_ips': {'subnet_id': subnet_ids}, + portbindings.HOST_ID: [l3_agent['host']]} + ports_query = core_plugin._get_ports_query(context, filters=filters) + owner_filter = or_( + models_v2.Port.device_owner.startswith( + constants.DEVICE_OWNER_COMPUTE_PREFIX), + models_v2.Port.device_owner.in_( + n_utils.get_other_dvr_serviced_device_owners())) + ports_query = ports_query.filter(owner_filter) + return ports_query.first() is not None def get_l3_agent_candidates(self, context, sync_router, l3_agents, ignore_admin_state=False): -- 2.45.2