From eb7ee4d8eb19901f95e56cded1033b7d33cbc221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C5=82awek=20Kap=C5=82o=C5=84ski?= Date: Wed, 21 Mar 2018 15:28:51 +0100 Subject: [PATCH] Don't set administratively disabled ports as ACTIVE There was a race condition during port update to disable it. In case when neutron-server receives port update call to set admin_state_down on port, it sends PORT_UPDATE notification to agents. Then both L2 and DHCP agents start doing their job with port. L2 agent asks neutron-server about device details and during processing this call server sets port's status to DOWN if its admin_state_up = False. Problem is that sometimes just after that, DHCP agent will send to neutron server notification that provisioning for this port is finished. As there is no any other provisioning block in db (because it is just port update) neutron-server is setting port's status to ACTIVE. This patch fixes this issue by allowing to transition to ACTIVE only ports which are administratively enabled. Change-Id: If506e0ff68fc49748f19618470c85901339a419b Closes-Bug: #1757089 (cherry picked from commit 2a1319ab7a21c2492627c38c5549d20eada899ff) --- neutron/plugins/ml2/plugin.py | 4 ++++ neutron/tests/unit/plugins/ml2/test_plugin.py | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 3b78d05864e..848e8a39435 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -253,6 +253,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, LOG.debug("Port %s had new provisioning blocks added so it " "will not transition to active.", port_id) return + if not port.admin_state_up: + LOG.debug("Port %s is administratively disabled so it will " + "not transition to active.", port_id) + return self.update_port_status(context, port_id, const.PORT_STATUS_ACTIVE) @log_helpers.log_method_call diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py index 5c85515af69..cf360570966 100644 --- a/neutron/tests/unit/plugins/ml2/test_plugin.py +++ b/neutron/tests/unit/plugins/ml2/test_plugin.py @@ -720,6 +720,19 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase): self.assertIsNone(plugin._port_provisioned('port', 'evt', 'trigger', self.context, port_id)) + def test__port_provisioned_port_admin_state_down(self): + plugin = directory.get_plugin() + ups = mock.patch.object(plugin, 'update_port_status').start() + port_id = 'fake_port_id' + binding = mock.Mock(vif_type=portbindings.VIF_TYPE_OVS) + port = mock.Mock( + id=port_id, admin_state_up=False, port_binding=binding) + with mock.patch('neutron.plugins.ml2.plugin.db.get_port', + return_value=port): + plugin._port_provisioned('port', 'evt', 'trigger', + self.context, port_id) + self.assertFalse(ups.called) + def test_port_after_create_outside_transaction(self): self.tx_open = True receive = lambda *a, **k: setattr(self, 'tx_open',