From: Swaminathan Vasudevan Date: Wed, 15 Apr 2015 04:34:33 +0000 (-0700) Subject: Fixes race condition and boosts the scheduling performance X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=c65d3ab6ad4589e6e4a6b488d2eb5d1e4cfee138;p=openstack-build%2Fneutron-build.git Fixes race condition and boosts the scheduling performance This patch fixes a race-condition that occurs when the scheduler tries to check for dvr serviceable ports before it schedules a router when a subnet is associated with a router. Sometimes the dhcp port creation is delayed and so the router is not scheduled to the l3-agent. Also it boosts the scheduling performance on dvr-snat node for scheduling a router. This patch will provide a work around to fix this race condition and to boost the scheduling performance by scheduling a router on a dvr-snat when dhcp is enabled on the provided subnet, instead of checking all the available ports on the subnet. Closes-Bug: #1442494 Change-Id: I089fefdd8535bdc9ed90b3230438ab0bfb6aab4f --- diff --git a/neutron/db/l3_agentschedulers_db.py b/neutron/db/l3_agentschedulers_db.py index 931436bdd..f661dcc62 100644 --- a/neutron/db/l3_agentschedulers_db.py +++ b/neutron/db/l3_agentschedulers_db.py @@ -379,6 +379,25 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase, return False core_plugin = manager.NeutronManager.get_plugin() + # NOTE(swami):Before checking for existence of dvr + # serviceable ports on the host managed by the l3 + # agent, let's verify if at least one subnet has + # dhcp enabled. If so, then the host will have a + # dvr serviceable port, which is in fact the DHCP + # port. + # This optimization is valid assuming that the L3 + # DVR_SNAT node will be the one hosting the DHCP + # Agent. + agent_conf = self.get_configuration_dict(l3_agent) + agent_mode = agent_conf.get(constants.L3_AGENT_MODE, + constants.L3_AGENT_MODE_LEGACY) + + for subnet_id in subnet_ids: + subnet_dict = core_plugin.get_subnet(context, subnet_id) + if (subnet_dict['enable_dhcp'] and ( + agent_mode == constants.L3_AGENT_MODE_DVR_SNAT)): + return True + filter = {'fixed_ips': {'subnet_id': subnet_ids}} ports = core_plugin.get_ports(context, filters=filter) for port in ports: diff --git a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py index c08991aaf..09e3f7080 100644 --- a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py +++ b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py @@ -722,6 +722,29 @@ class L3SchedulerTestBaseMixin(object): l3_agent, router['id']) self.assertFalse(val) + def test_check_ports_exist_on_l3agent_with_dhcp_enabled_subnets(self): + self._register_l3_dvr_agents() + router = self._make_router(self.fmt, + tenant_id=str(uuid.uuid4()), + name='r2') + router['external_gateway_info'] = None + router['id'] = str(uuid.uuid4()) + router['distributed'] = True + + agent_list = [self.l3_dvr_snat_agent] + subnet = {'id': str(uuid.uuid4()), + '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_ports = mock.Mock() + val = self.check_ports_exist_on_l3agent( + self.adminContext, agent_list[0], router['id']) + self.assertTrue(val) + 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, @@ -749,9 +772,12 @@ class L3SchedulerTestBaseMixin(object): 'binding:host_id': 'host_1', 'device_owner': 'compute:', 'id': 1234} + subnet = {'id': str(uuid.uuid4()), + 'enable_dhcp': False} 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) val = self.check_ports_exist_on_l3agent(self.adminContext, l3_agent, router['id']) self.assertTrue(val)