From 2325e2aea86ddc28bc0e1573d4954518991cad19 Mon Sep 17 00:00:00 2001
From: Kevin Benton <kevin@benton.pub>
Date: Sat, 23 Jul 2016 00:07:17 -0700
Subject: [PATCH] Skip DHCP provisioning block for network ports

Network ports created via internal core plugin calls
(e.g. dhcp ports and router interfaces) don't generate
DHCP notifications to the DHCP agent so the agent never
clears the DHCP provisioning block. This patch just skips
adding DHCP provisioning blocks for network owned ports
since they don't depend on DHCP anyway.

Closes-Bug: #1590845
Closes-Bug: #1605955
Change-Id: I0111de79d9259ada3b1c06a087d0eaeb8f3cb158
---
 neutron/plugins/ml2/plugin.py                 | 5 +++++
 neutron/tests/unit/plugins/ml2/test_plugin.py | 7 +++++++
 2 files changed, 12 insertions(+)

diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py
index 17d47aae22d..5a69475a1f0 100644
--- a/neutron/plugins/ml2/plugin.py
+++ b/neutron/plugins/ml2/plugin.py
@@ -1097,6 +1097,11 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
             raise psec.PortSecurityAndIPRequiredForSecurityGroups()
 
     def _setup_dhcp_agent_provisioning_component(self, context, port):
+        # NOTE(kevinbenton): skipping network ports is a workaround for
+        # the fact that we don't issue dhcp notifications from internal
+        # port creation like router ports and dhcp ports via RPC
+        if utils.is_port_trusted(port):
+            return
         subnet_ids = [f['subnet_id'] for f in port['fixed_ips']]
         if (db.is_dhcp_active_on_any_subnet(context, subnet_ids) and
             any(self.get_configuration_dict(a).get('notifies_port_ready')
diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py
index e7141b64aaa..64eb386c2c1 100644
--- a/neutron/tests/unit/plugins/ml2/test_plugin.py
+++ b/neutron/tests/unit/plugins/ml2/test_plugin.py
@@ -595,6 +595,13 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
             with self.port():
                 self.assertTrue(ap.called)
 
+    def test_dhcp_provisioning_blocks_skipped_with_network_port(self):
+        self._add_fake_dhcp_agent()
+        with mock.patch.object(provisioning_blocks,
+                               'add_provisioning_component') as ap:
+            with self.port(device_owner=constants.DEVICE_OWNER_DHCP):
+                self.assertFalse(ap.called)
+
     def test_dhcp_provisioning_blocks_skipped_on_create_with_no_dhcp(self):
         self._add_fake_dhcp_agent()
         with self.subnet(enable_dhcp=False) as subnet: