diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/agent/common/ovs_lib.py neutron-9.4.2.dev21/neutron/agent/common/ovs_lib.py
*** neutron-9.4.2.dev21-backup/neutron/agent/common/ovs_lib.py	2018-12-17 16:03:21.761022853 -0800
--- neutron-9.4.2.dev21/neutron/agent/common/ovs_lib.py	2018-12-18 14:47:48.361661601 -0800
***************
*** 260,265 ****
--- 260,278 ----
          with self.ovsdb.transaction() as txn:
              txn.add(self.ovsdb.add_port(self.br_name, port_name,
                                          may_exist=False))
+             # NOTE(mangelajo): Port is added to dead vlan (4095) by default
+             # until it's handled by the neutron-openvswitch-agent. Otherwise it
+             # becomes a trunk port on br-int (receiving traffic for all vlans),
+             # and also triggers issues on ovs-vswitchd related to the
+             # datapath flow revalidator thread, see lp#1767422
+             txn.add(self.ovsdb.db_set(
+                     'Port', port_name, ('tag', constants.DEAD_VLAN_TAG)))
+ 
+             # TODO(mangelajo): We could accept attr tuples for the Port too
+             # but, that could potentially break usage of this function in
+             # stable branches (where we need to backport).
+             # https://review.openstack.org/#/c/564825/4/neutron/agent/common/
+             # ovs_lib.py@289
              if interface_attr_tuples:
                  txn.add(self.ovsdb.db_set('Interface', port_name,
                                            *interface_attr_tuples))
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/agent/l3/router_info.py neutron-9.4.2.dev21/neutron/agent/l3/router_info.py
*** neutron-9.4.2.dev21-backup/neutron/agent/l3/router_info.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/agent/l3/router_info.py	2018-12-18 14:56:02.934852397 -0800
***************
*** 614,619 ****
--- 614,629 ----
                           prefix=EXTERNAL_DEV_PREFIX,
                           mtu=ex_gw_port.get('mtu'))
  
+         if self.agent_conf.external_network_bridge:
+             # NOTE(slaweq): for OVS implementations remove the DEAD VLAN tag
+             # on ports. DEAD VLAN tag is added to each newly created port
+             # and should be removed by L2 agent but if
+             # external_network_bridge is set than external gateway port is
+             # created in this bridge and will not be touched by L2 agent.
+             # This is related to lp#1767422
+             self.driver.remove_vlan_tag(
+                 self.agent_conf.external_network_bridge, interface_name)
+ 
      def _get_external_gw_ips(self, ex_gw_port):
          gateway_ips = []
          if 'subnets' in ex_gw_port:
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/agent/linux/interface.py neutron-9.4.2.dev21/neutron/agent/linux/interface.py
*** neutron-9.4.2.dev21-backup/neutron/agent/linux/interface.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/agent/linux/interface.py	2018-12-18 14:58:23.282430711 -0800
***************
*** 238,243 ****
--- 238,254 ----
      def get_device_name(self, port):
          return (self.DEV_NAME_PREFIX + port.id)[:self.DEV_NAME_LEN]
  
+     def remove_vlan_tag(self, bridge, interface_name):
+         """Remove vlan tag from given interface.
+ 
+         This method is necessary only for the case when deprecated
+         option 'external_network_bridge' is used in L3 agent as
+         external gateway port is then created in this external bridge
+         directly and it will have DEAD_VLAN_TAG added by default.
+         """
+         # TODO(slaweq): remove it when external_network_bridge option will be
+         # removed
+ 
      @staticmethod
      def configure_ipv6_ra(namespace, dev_name, value):
          """Configure handling of IPv6 Router Advertisements on an
***************
*** 347,352 ****
--- 358,367 ----
          ovs = ovs_lib.OVSBridge(bridge)
          ovs.replace_port(device_name, *attrs)
  
+     def remove_vlan_tag(self, bridge, interface):
+         ovs = ovs_lib.OVSBridge(bridge)
+         ovs.clear_db_attribute("Port", interface, "tag")
+ 
      def plug_new(self, network_id, port_id, device_name, mac_address,
                   bridge=None, namespace=None, prefix=None, mtu=None):
          """Plug in the interface."""
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/common/net_helpers.py neutron-9.4.2.dev21/neutron/tests/common/net_helpers.py
*** neutron-9.4.2.dev21-backup/neutron/tests/common/net_helpers.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/tests/common/net_helpers.py	2018-12-18 15:01:42.826132346 -0800
***************
*** 741,746 ****
--- 741,750 ----
              self.mac,
              bridge=self.bridge.br_name,
              namespace=self.namespace)
+         # NOTE(mangelajo): for OVS implementations remove the DEAD VLAN tag
+         # on ports that we intend to use as fake vm interfaces, they
+         # need to be flat. This is related to lp#1767422
+         self.bridge.clear_db_attribute("Port", port_name, "tag")
          self.addCleanup(self.bridge.delete_port, port_name)
          self.port = ip_lib.IPDevice(port_name, self.namespace)
  
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/functional/agent/l2/base.py neutron-9.4.2.dev21/neutron/tests/functional/agent/l2/base.py
*** neutron-9.4.2.dev21-backup/neutron/tests/functional/agent/l2/base.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/tests/functional/agent/l2/base.py	2018-12-18 15:03:34.937795498 -0800
***************
*** 394,401 ****
  
          self._plug_ports(network, ports, self.agent, bridge=phys_br,
                           namespace=namespace)
! 
!         if phys_segmentation_id and network_type == 'vlan':
              for port in ports:
                  phys_br.set_db_attribute(
                      "Port", port['vif_name'], "tag", phys_segmentation_id)
--- 394,406 ----
  
          self._plug_ports(network, ports, self.agent, bridge=phys_br,
                           namespace=namespace)
!         if network_type == 'flat':
!             # NOTE(slaweq): for OVS implementations remove the DEAD VLAN tag
!             # on ports that belongs to flat network. DEAD VLAN tag is added
!             # to each newly created port. This is related to lp#1767422
!             for port in ports:
!                 phys_br.clear_db_attribute("Port", port['vif_name'], "tag")
!         elif phys_segmentation_id and network_type == 'vlan':
              for port in ports:
                  phys_br.set_db_attribute(
                      "Port", port['vif_name'], "tag", phys_segmentation_id)
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/functional/agent/l3/framework.py neutron-9.4.2.dev21/neutron/tests/functional/agent/l3/framework.py
*** neutron-9.4.2.dev21-backup/neutron/tests/functional/agent/l3/framework.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/tests/functional/agent/l3/framework.py	2018-12-18 15:07:31.894883761 -0800
***************
*** 32,37 ****
--- 32,38 ----
  from neutron.agent.l3 import router_info as l3_router_info
  from neutron.agent import l3_agent as l3_agent_main
  from neutron.agent.linux import external_process
+ from neutron.agent.linux import interface
  from neutron.agent.linux import ip_lib
  from neutron.agent.linux import keepalived
  from neutron.common import constants as n_const
***************
*** 44,56 ****
  
  _uuid = uuidutils.generate_uuid
  
  
  def get_ovs_bridge(br_name):
      return ovs_lib.OVSBridge(br_name)
  
  
  class L3AgentTestFramework(base.BaseSudoTestCase):
!     INTERFACE_DRIVER = 'neutron.agent.linux.interface.OVSInterfaceDriver'
      NESTED_NAMESPACE_SEPARATOR = '@'
  
      def setUp(self):
--- 45,59 ----
  
  _uuid = uuidutils.generate_uuid
  
+ OVS_INTERFACE_DRIVER = 'neutron.agent.linux.interface.OVSInterfaceDriver'
+ 
  
  def get_ovs_bridge(br_name):
      return ovs_lib.OVSBridge(br_name)
  
  
  class L3AgentTestFramework(base.BaseSudoTestCase):
!     INTERFACE_DRIVER = OVS_INTERFACE_DRIVER
      NESTED_NAMESPACE_SEPARATOR = '@'
  
      def setUp(self):
***************
*** 318,324 ****
  
      def manage_router(self, agent, router):
          self.addCleanup(agent._safe_router_removed, router['id'])
!         agent._process_added_router(router)
          return agent.router_info[router['id']]
  
      def _delete_router(self, agent, router_id):
--- 321,347 ----
  
      def manage_router(self, agent, router):
          self.addCleanup(agent._safe_router_removed, router['id'])
! 
!         # NOTE(mangelajo): Neutron functional for l3 don't rely on openvswitch
!         #                  agent tagging ports, and all ports remain untagged
!         #                  during test execution.
!         #                  Workaround related to lp#1767422 plugs new ports as
!         #                  dead vlan (4095) to avoid issues, we need to remove
!         #                  such tag during functional l3 testing.
!         original_plug_new = interface.OVSInterfaceDriver.plug_new
! 
!         def new_ovs_plug(self, *args, **kwargs):
!             original_plug_new(self, *args, **kwargs)
!             bridge = (kwargs.get('bridge') or args[4] or
!                       self.conf.ovs_integration_bridge)
!             device_name = kwargs.get('device_name') or args[2]
!             ovsbr = ovs_lib.OVSBridge(bridge)
!             ovsbr.clear_db_attribute('Port', device_name, 'tag')
! 
!         with mock.patch(OVS_INTERFACE_DRIVER + '.plug_new', autospec=True) as (
!                 ovs_plug):
!             ovs_plug.side_effect = new_ovs_plug
!             agent._process_added_router(router)
          return agent.router_info[router['id']]
  
      def _delete_router(self, agent, router_id):
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/functional/agent/test_ovs_lib.py neutron-9.4.2.dev21/neutron/tests/functional/agent/test_ovs_lib.py
*** neutron-9.4.2.dev21-backup/neutron/tests/functional/agent/test_ovs_lib.py	2018-12-17 16:03:21.765022894 -0800
--- neutron-9.4.2.dev21/neutron/tests/functional/agent/test_ovs_lib.py	2018-12-18 15:13:06.210277942 -0800
***************
*** 25,30 ****
--- 25,32 ----
  from neutron.agent.linux import ip_lib
  from neutron.agent.ovsdb.native import idlutils
  from neutron.common import utils
+ from neutron.plugins.ml2.drivers.openvswitch.agent.common import (
+     constants as agent_const)
  from neutron.tests.common.exclusive_resources import port
  from neutron.tests.common import net_helpers
  from neutron.tests.functional.agent.linux import base
***************
*** 90,95 ****
--- 92,99 ----
          self.assertTrue(self.br.port_exists(port_name))
          self.assertEqual('test', self.br.db_get_val('Interface', port_name,
                                                      'external_ids')['test'])
+         self.assertEqual(agent_const.DEAD_VLAN_TAG,
+                          self.br.db_get_val('Port', port_name, 'tag'))
  
      def test_attribute_lifecycle(self):
          (port_name, ofport) = self.create_ovs_port()
