Merge "Revert "Skip scenario tests if HA router will not be active""
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index 216ccfc..024fe43 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -784,6 +784,15 @@
         return qos_rule
 
     @classmethod
+    def create_qos_dscp_marking_rule(cls, policy_id, dscp_mark):
+        """Wrapper utility that creates and returns a QoS dscp rule."""
+        body = cls.admin_client.create_dscp_marking_rule(
+            policy_id, dscp_mark)
+        qos_rule = body['dscp_marking_rule']
+        cls.qos_rules.append(qos_rule)
+        return qos_rule
+
+    @classmethod
     def delete_router(cls, router, client=None):
         client = client or cls.client
         if 'routes' in router:
diff --git a/neutron_tempest_plugin/api/test_allowed_address_pair.py b/neutron_tempest_plugin/api/test_allowed_address_pair.py
deleted file mode 100644
index 7b11638..0000000
--- a/neutron_tempest_plugin/api/test_allowed_address_pair.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.lib import decorators
-
-from neutron_tempest_plugin.api import base
-
-
-class AllowedAddressPairTestJSON(base.BaseNetworkTest):
-
-    """AllowedAddressPairTestJSON class
-
-    Tests the Neutron Allowed Address Pair API extension using the Tempest
-    REST client. The following API operations are tested with this extension:
-
-        create port
-        list ports
-        update port
-        show port
-
-    v2.0 of the Neutron API is assumed. It is also assumed that the following
-    options are defined in the [network-feature-enabled] section of
-    etc/tempest.conf
-
-        api_extensions
-    """
-
-    required_extensions = ['allowed-address-pairs']
-
-    @classmethod
-    def resource_setup(cls):
-        super(AllowedAddressPairTestJSON, cls).resource_setup()
-        cls.network = cls.create_network()
-        cls.create_subnet(cls.network)
-        port = cls.create_port(cls.network)
-        cls.ip_address = port['fixed_ips'][0]['ip_address']
-        cls.mac_address = port['mac_address']
-
-    @decorators.idempotent_id('86c3529b-1231-40de-803c-00e40882f043')
-    def test_create_list_port_with_address_pair(self):
-        # Create port with allowed address pair attribute
-        allowed_address_pairs = [{'ip_address': self.ip_address,
-                                  'mac_address': self.mac_address}]
-        body = self.create_port(
-            self.network,
-            allowed_address_pairs=allowed_address_pairs)
-        port_id = body['id']
-
-        # Confirm port was created with allowed address pair attribute
-        body = self.client.list_ports()
-        ports = body['ports']
-        port = [p for p in ports if p['id'] == port_id]
-        msg = 'Created port not found in list of ports returned by Neutron'
-        self.assertTrue(port, msg)
-        self._confirm_allowed_address_pair(port[0], self.ip_address)
-
-    def _update_port_with_address(self, address, mac_address=None, **kwargs):
-        # Create a port without allowed address pair
-        body = self.create_port(self.network)
-        port_id = body['id']
-        if mac_address is None:
-            mac_address = self.mac_address
-
-        # Update allowed address pair attribute of port
-        allowed_address_pairs = [{'ip_address': address,
-                                  'mac_address': mac_address}]
-        if kwargs:
-            allowed_address_pairs.append(kwargs['allowed_address_pairs'])
-        body = self.client.update_port(
-            port_id, allowed_address_pairs=allowed_address_pairs)
-        allowed_address_pair = body['port']['allowed_address_pairs']
-        self.assertCountEqual(allowed_address_pair, allowed_address_pairs)
-
-    @decorators.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4')
-    def test_update_port_with_address_pair(self):
-        # Update port with allowed address pair
-        self._update_port_with_address(self.ip_address)
-
-    @decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4')
-    def test_update_port_with_cidr_address_pair(self):
-        # Update allowed address pair with cidr
-        cidr = str(next(self.get_subnet_cidrs()))
-        self._update_port_with_address(cidr)
-
-    @decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
-    def test_update_port_with_multiple_ip_mac_address_pair(self):
-        # Create an ip _address and mac_address through port create
-        resp = self.create_port(self.network)
-        ipaddress = resp['fixed_ips'][0]['ip_address']
-        macaddress = resp['mac_address']
-
-        # Update allowed address pair port with multiple ip and  mac
-        allowed_address_pairs = {'ip_address': ipaddress,
-                                 'mac_address': macaddress}
-        self._update_port_with_address(
-            self.ip_address, self.mac_address,
-            allowed_address_pairs=allowed_address_pairs)
-
-    def _confirm_allowed_address_pair(self, port, ip):
-        msg = 'Port allowed address pairs should not be empty'
-        self.assertTrue(port['allowed_address_pairs'], msg)
-        ip_address = port['allowed_address_pairs'][0]['ip_address']
-        mac_address = port['allowed_address_pairs'][0]['mac_address']
-        self.assertEqual(ip_address, ip)
-        self.assertEqual(mac_address, self.mac_address)
-
-
-class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON):
-    _ip_version = 6
diff --git a/neutron_tempest_plugin/api/test_ports_negative.py b/neutron_tempest_plugin/api/test_ports_negative.py
index e327c25..004feb9 100644
--- a/neutron_tempest_plugin/api/test_ports_negative.py
+++ b/neutron_tempest_plugin/api/test_ports_negative.py
@@ -54,10 +54,13 @@
     @decorators.idempotent_id('7cf473ae-7ec8-4834-ae17-9ef6ec6b8a32')
     def test_add_port_with_nonexist_network_id(self):
         network = self.network
+        # Copy and restore net ID so the cleanup will delete correct net
+        original_network_id = network['id']
         network['id'] = uuidutils.generate_uuid()
         self.assertRaises(lib_exc.NotFound,
                           self.create_port,
                           network)
+        network['id'] = original_network_id
 
     @decorators.attr(type='negative')
     @decorators.idempotent_id('cad2d349-25fa-490e-9675-cd2ea24164bc')
diff --git a/neutron_tempest_plugin/api/test_qos_negative.py b/neutron_tempest_plugin/api/test_qos_negative.py
index f6c4afc..2d06d11 100644
--- a/neutron_tempest_plugin/api/test_qos_negative.py
+++ b/neutron_tempest_plugin/api/test_qos_negative.py
@@ -90,33 +90,122 @@
                           self.admin_client.delete_qos_policy, non_exist_id)
 
 
-class QosBandwidthLimitRuleNegativeTestJSON(base.BaseAdminNetworkTest):
+class QosRuleNegativeBaseTestJSON(base.BaseAdminNetworkTest):
 
     required_extensions = [qos_apidef.ALIAS]
 
-    @decorators.attr(type='negative')
-    @decorators.idempotent_id('e9ce8042-c828-4cb9-b1f1-85bd35e6553a')
-    def test_rule_update_rule_nonexistent_policy(self):
+    def _test_rule_update_rule_nonexistent_policy(self, create_params,
+                                                  update_params):
         non_exist_id = data_utils.rand_name('qos_policy')
         policy = self.create_qos_policy(name='test-policy',
                                         description='test policy',
                                         shared=False)
-        rule = self.create_qos_bandwidth_limit_rule(policy_id=policy['id'],
-                                                    max_kbps=1,
-                                                    max_burst_kbps=1)
+        rule = self.rule_create_m(policy_id=policy['id'], **create_params)
         self.assertRaises(
             lib_exc.NotFound,
-            self.admin_client.update_bandwidth_limit_rule,
-            non_exist_id, rule['id'], max_kbps=200, max_burst_kbps=1337)
+            self.rule_update_m,
+            non_exist_id, rule['id'], **update_params)
 
-    @decorators.attr(type='negative')
-    @decorators.idempotent_id('a2c72066-0c32-4f28-be7f-78fa721588b6')
-    def test_rule_update_rule_nonexistent_rule(self):
+    def _test_rule_create_rule_non_existent_policy(self, create_params):
+        non_exist_id = data_utils.rand_name('qos_policy')
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.rule_create_m,
+            non_exist_id, **create_params)
+
+    def _test_rule_update_rule_nonexistent_rule(self, update_params):
         non_exist_id = data_utils.rand_name('qos_rule')
         policy = self.create_qos_policy(name='test-policy',
                                         description='test policy',
                                         shared=False)
         self.assertRaises(
             lib_exc.NotFound,
-            self.admin_client.update_bandwidth_limit_rule,
-            policy['id'], non_exist_id, max_kbps=200, max_burst_kbps=1337)
+            self.rule_update_m,
+            policy['id'], non_exist_id, **update_params)
+
+
+class QosBandwidthLimitRuleNegativeTestJSON(QosRuleNegativeBaseTestJSON):
+
+    @classmethod
+    def resource_setup(cls):
+        cls.rule_create_m = cls.create_qos_bandwidth_limit_rule
+        cls.rule_update_m = cls.admin_client.update_bandwidth_limit_rule
+        super(QosBandwidthLimitRuleNegativeTestJSON, cls).resource_setup()
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('e9ce8042-c828-4cb9-b1f1-85bd35e6553a')
+    def test_rule_update_rule_nonexistent_policy(self):
+        create_params = {'max_kbps': 1, 'max_burst_kbps': 1}
+        update_params = {'max_kbps': 200, 'max_burst_kbps': 1337}
+        self._test_rule_update_rule_nonexistent_policy(
+            create_params, update_params)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('1b592566-745f-4e15-a439-073afe341244')
+    def test_rule_create_rule_non_existent_policy(self):
+        create_params = {'max_kbps': 200, 'max_burst_kbps': 300}
+        self._test_rule_create_rule_non_existent_policy(create_params)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('a2c72066-0c32-4f28-be7f-78fa721588b6')
+    def test_rule_update_rule_nonexistent_rule(self):
+        update_params = {'max_kbps': 200, 'max_burst_kbps': 1337}
+        self._test_rule_update_rule_nonexistent_rule(update_params)
+
+
+class QosMinimumBandwidthRuleNegativeTestJSON(QosRuleNegativeBaseTestJSON):
+
+    @classmethod
+    def resource_setup(cls):
+        cls.rule_create_m = cls.create_qos_minimum_bandwidth_rule
+        cls.rule_update_m = cls.admin_client.update_minimum_bandwidth_rule
+        super(QosMinimumBandwidthRuleNegativeTestJSON, cls).resource_setup()
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('08b8455b-4d4f-4119-bad3-9357085c3a80')
+    def test_rule_update_rule_nonexistent_policy(self):
+        create_params = {'min_kbps': 1}
+        update_params = {'min_kbps': 200}
+        self._test_rule_update_rule_nonexistent_policy(
+            create_params, update_params)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('5a714a4a-bfbc-4cf9-b0c0-13fd185204f7')
+    def test_rule_create_rule_non_existent_policy(self):
+        create_params = {'min_kbps': 200}
+        self._test_rule_create_rule_non_existent_policy(create_params)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('8470cbe0-8ca5-46ab-9c66-7cf69301b121')
+    def test_rule_update_rule_nonexistent_rule(self):
+        update_params = {'min_kbps': 200}
+        self._test_rule_update_rule_nonexistent_rule(update_params)
+
+
+class QosDscpRuleNegativeTestJSON(QosRuleNegativeBaseTestJSON):
+
+    @classmethod
+    def resource_setup(cls):
+        cls.rule_create_m = cls.create_qos_dscp_marking_rule
+        cls.rule_update_m = cls.admin_client.update_dscp_marking_rule
+        super(QosDscpRuleNegativeTestJSON, cls).resource_setup()
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('d47d5fbe-3e98-476f-b2fd-97818175dea5')
+    def test_rule_update_rule_nonexistent_policy(self):
+        create_params = {'dscp_mark': 26}
+        update_params = {'dscp_mark': 16}
+        self._test_rule_update_rule_nonexistent_policy(
+            create_params, update_params)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('07d17f09-3dc4-4c24-9bb1-49081a153c5a')
+    def test_rule_create_rule_non_existent_policy(self):
+        create_params = {'dscp_mark': 16}
+        self._test_rule_create_rule_non_existent_policy(create_params)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('9c0bd085-5a7a-496f-a984-50dc631a64f2')
+    def test_rule_update_rule_nonexistent_rule(self):
+        update_params = {'dscp_mark': 16}
+        self._test_rule_update_rule_nonexistent_rule(update_params)
diff --git a/neutron_tempest_plugin/api/test_subnets.py b/neutron_tempest_plugin/api/test_subnets.py
index b8842ab..d4992d3 100644
--- a/neutron_tempest_plugin/api/test_subnets.py
+++ b/neutron_tempest_plugin/api/test_subnets.py
@@ -10,6 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import netaddr
 from tempest.lib import decorators
 
 from neutron_tempest_plugin.api import base
@@ -69,3 +70,38 @@
         self._test_list_validation_filters(self.list_kwargs)
         self._test_list_validation_filters({
             'unknown_filter': 'value'}, filter_is_valid=False)
+
+
+class SubnetServiceTypeTestJSON(base.BaseNetworkTest):
+
+    required_extensions = ['subnet-service-types']
+
+    @classmethod
+    def resource_setup(cls):
+        super(SubnetServiceTypeTestJSON, cls).resource_setup()
+        cls.network = cls.create_network()
+
+    @decorators.idempotent_id('7e0edb66-1bb2-4473-ab83-d039cddced0d')
+    def test_allocate_ips_are_from_correct_subnet(self):
+        cidr_1 = netaddr.IPNetwork('192.168.1.0/24')
+        cidr_2 = netaddr.IPNetwork('192.168.2.0/24')
+
+        self.create_subnet(self.network,
+                           service_types=['test:type_1'],
+                           cidr=str(cidr_1))
+        self.create_subnet(self.network,
+                           service_types=['test:type_2'],
+                           cidr=str(cidr_2))
+        port_type_1 = self.create_port(self.network,
+                                       device_owner="test:type_1")
+        port_type_2 = self.create_port(self.network,
+                                       device_owner="test:type_2")
+
+        self.assertEqual(1, len(port_type_1['fixed_ips']))
+        self.assertEqual(1, len(port_type_2['fixed_ips']))
+        self.assertIn(
+            netaddr.IPAddress(port_type_1['fixed_ips'][0]['ip_address']),
+            cidr_1)
+        self.assertIn(
+            netaddr.IPAddress(port_type_2['fixed_ips'][0]['ip_address']),
+            cidr_2)
diff --git a/neutron_tempest_plugin/common/ip.py b/neutron_tempest_plugin/common/ip.py
index 7b172b0..9fe49db 100644
--- a/neutron_tempest_plugin/common/ip.py
+++ b/neutron_tempest_plugin/common/ip.py
@@ -383,6 +383,23 @@
     return arp_table
 
 
+def list_iptables(version=constants.IP_VERSION_4, namespace=None):
+    cmd = ''
+    if namespace:
+        cmd = 'sudo ip netns exec %s ' % namespace
+    cmd += ('iptables-save' if version == constants.IP_VERSION_4 else
+            'ip6tables-save')
+    return shell.execute(cmd).stdout
+
+
+def list_listening_sockets(namespace=None):
+    cmd = ''
+    if namespace:
+        cmd = 'sudo ip netns exec %s ' % namespace
+    cmd += 'netstat -nlp'
+    return shell.execute(cmd).stdout
+
+
 class Route(HasProperties,
             collections.namedtuple('Route',
                                    ['dest', 'properties'])):
diff --git a/neutron_tempest_plugin/common/utils.py b/neutron_tempest_plugin/common/utils.py
index f03762c..1526ecf 100644
--- a/neutron_tempest_plugin/common/utils.py
+++ b/neutron_tempest_plugin/common/utils.py
@@ -136,3 +136,74 @@
 def call_url_remote(ssh_client, url):
     cmd = "curl %s --retry 3 --connect-timeout 2" % url
     return ssh_client.exec_command(cmd)
+
+
+class StatefulConnection:
+    """Class to test connection that should remain opened
+
+    Can be used to perform some actions while the initiated connection
+    remain opened
+    """
+
+    def __init__(self, client_ssh, server_ssh, target_ip, target_port):
+        self.client_ssh = client_ssh
+        self.server_ssh = server_ssh
+        self.ip = target_ip
+        self.port = target_port
+        self.connection_started = False
+        self.test_attempt = 0
+
+    def __enter__(self):
+        return self
+
+    @property
+    def test_str(self):
+        return 'attempt_{}'.format(str(self.test_attempt).zfill(3))
+
+    def _start_connection(self):
+        self.server_ssh.exec_command(
+                'echo "{}" > input.txt'.format(self.test_str))
+        self.server_ssh.exec_command('tail -f input.txt | nc -lp '
+                '{} &> output.txt &'.format(self.port))
+        self.client_ssh.exec_command(
+                'echo "{}" > input.txt'.format(self.test_str))
+        self.client_ssh.exec_command('tail -f input.txt | nc {} {} &>'
+                'output.txt &'.format(self.ip, self.port))
+
+    def _test_connection(self):
+        if not self.connection_started:
+            self._start_connection()
+        else:
+            self.server_ssh.exec_command(
+                    'echo "{}" >> input.txt'.format(self.test_str))
+            self.client_ssh.exec_command(
+                    'echo "{}" >> input.txt & sleep 1'.format(self.test_str))
+        try:
+            self.server_ssh.exec_command(
+                    'grep {} output.txt'.format(self.test_str))
+            self.client_ssh.exec_command(
+                    'grep {} output.txt'.format(self.test_str))
+            if not self.should_pass:
+                return False
+            else:
+                if not self.connection_started:
+                    self.connection_started = True
+                return True
+        except exceptions.SSHExecCommandFailed:
+            if self.should_pass:
+                return False
+            else:
+                return True
+        finally:
+            self.test_attempt += 1
+
+    def test_connection(self, should_pass=True, timeout=10, sleep_timer=1):
+        self.should_pass = should_pass
+        wait_until_true(
+                self._test_connection, timeout=timeout, sleep=sleep_timer)
+
+    def __exit__(self, type, value, traceback):
+        self.server_ssh.exec_command('sudo killall nc || killall nc')
+        self.server_ssh.exec_command('sudo killall tail || killall tail')
+        self.client_ssh.exec_command('sudo killall nc || killall nc')
+        self.client_ssh.exec_command('sudo killall tail || killall tail')
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index c29585f..8591c89 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -346,7 +346,9 @@
         try:
             local_ips = ip_utils.IPCommand(namespace=ns_name).list_addresses()
             local_routes = ip_utils.IPCommand(namespace=ns_name).list_routes()
-            arp_table = ip_utils.arp_table()
+            arp_table = ip_utils.arp_table(namespace=ns_name)
+            iptables = ip_utils.list_iptables(namespace=ns_name)
+            lsockets = ip_utils.list_listening_sockets(namespace=ns_name)
         except exceptions.ShellCommandFailed:
             LOG.debug('Namespace %s has been deleted synchronously during the '
                       'host network collection process', ns_name)
@@ -358,6 +360,8 @@
                   ns_name, '\n'.join(str(r) for r in local_routes))
         LOG.debug('Namespace %s; Local ARP table:\n%s',
                   ns_name, '\n'.join(str(r) for r in arp_table))
+        LOG.debug('Namespace %s; Local iptables:\n%s', ns_name, iptables)
+        LOG.debug('Namespace %s; Listening sockets:\n%s', ns_name, lsockets)
 
     def _check_remote_connectivity(self, source, dest, count,
                                    should_succeed=True,
diff --git a/neutron_tempest_plugin/scenario/test_dns_integration.py b/neutron_tempest_plugin/scenario/test_dns_integration.py
index e5995c0..79c0993 100644
--- a/neutron_tempest_plugin/scenario/test_dns_integration.py
+++ b/neutron_tempest_plugin/scenario/test_dns_integration.py
@@ -42,7 +42,7 @@
 
 
 class BaseDNSIntegrationTests(base.BaseTempestTestCase, DNSMixin):
-    credentials = ['primary']
+    credentials = ['primary', 'admin']
 
     @classmethod
     def setup_clients(cls):
@@ -199,3 +199,56 @@
         self.client.delete_port(port['id'])
         self._verify_dns_records(addr_v6, name, record_type='AAAA',
                                  found=False)
+
+
+class DNSIntegrationDomainPerProjectTests(BaseDNSIntegrationTests):
+
+    credentials = ['primary', 'admin']
+
+    required_extensions = ['subnet-dns-publish-fixed-ip',
+                           'dns-integration-domain-keywords']
+
+    @classmethod
+    def resource_setup(cls):
+        super(BaseDNSIntegrationTests, cls).resource_setup()
+
+        name = data_utils.rand_name('test-domain')
+        zone_name = "%s.%s.%s.zone." % (cls.client.user_id,
+                                        cls.client.tenant_id,
+                                        name)
+        dns_domain_template = "<user_id>.<project_id>.%s.zone." % name
+
+        _, cls.zone = cls.dns_client.create_zone(name=zone_name)
+        cls.addClassResourceCleanup(cls.dns_client.delete_zone,
+            cls.zone['id'], ignore_errors=lib_exc.NotFound)
+        dns_waiters.wait_for_zone_status(
+            cls.dns_client, cls.zone['id'], 'ACTIVE')
+
+        cls.network = cls.create_network(dns_domain=dns_domain_template)
+        cls.subnet = cls.create_subnet(cls.network,
+                                       dns_publish_fixed_ip=True)
+        cls.subnet_v6 = cls.create_subnet(cls.network,
+                                          ip_version=6,
+                                          dns_publish_fixed_ip=True)
+        cls.router = cls.create_router_by_client()
+        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+        cls.keypair = cls.create_keypair()
+
+    @decorators.idempotent_id('43a67509-3161-4125-8f2c-0d4a67599721')
+    def test_port_with_dns_name(self):
+        name = data_utils.rand_name('port-test')
+        port = self.create_port(self.network,
+                                dns_name=name)
+        addr = port['fixed_ips'][0]['ip_address']
+        self._verify_dns_records(addr, name)
+        self.client.delete_port(port['id'])
+        self._verify_dns_records(addr, name, found=False)
+
+    @decorators.idempotent_id('ac89db9b-5ca4-43bd-85ba-40fbeb47e208')
+    def test_fip_admin_delete(self):
+        name = data_utils.rand_name('fip-test')
+        fip = self._create_floatingip_with_dns(name)
+        addr = fip['floating_ip_address']
+        self._verify_dns_records(addr, name)
+        self.delete_floatingip(fip, client=self.admin_client)
+        self._verify_dns_records(addr, name, found=False)
diff --git a/neutron_tempest_plugin/scenario/test_multicast.py b/neutron_tempest_plugin/scenario/test_multicast.py
index 7c1fd2d..726d1e0 100644
--- a/neutron_tempest_plugin/scenario/test_multicast.py
+++ b/neutron_tempest_plugin/scenario/test_multicast.py
@@ -364,8 +364,7 @@
             # We don't expect any packets to be captured really in this case
             # so let's kill tcpdump so it flushes its output to the output
             # file.
-            expected_result = (
-                '0 packets captured\n0 packets received by filter')
+            expected_result = ('0 packets captured')
             unregistered_error_message = (
                 'Unregistered server received unexpected packet(s).')
             try:
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 8b7098e..40aa66a 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -54,6 +54,7 @@
         utils.kill_nc_process(ssh_server)
         url = 'http://%s:%d' % (test_ip, test_port)
         utils.spawn_http_server(ssh_server, port=test_port, message='foo_ok')
+        utils.process_is_running(ssh_server, 'nc')
         try:
             ret = utils.call_url_remote(ssh_client, url)
             if should_pass:
@@ -277,6 +278,50 @@
                       'remote_ip_prefix': cidr}]
         self._test_ip_prefix(rule_list, should_succeed=False)
 
+    @decorators.idempotent_id('01f0ddca-b049-47eb-befd-82acb502c9ec')
+    def test_established_tcp_session_after_re_attachinging_sg(self):
+        """Test existing connection remain open after sg has been re-attached
+
+        Verifies that new packets can pass over the existing connection when
+        the security group has been removed from the server and then added
+        back
+        """
+
+        ssh_sg = self.create_security_group()
+        self.create_loginable_secgroup_rule(secgroup_id=ssh_sg['id'])
+        vm_ssh, fips, vms = self.create_vm_testing_sec_grp(
+                security_groups=[{'name': ssh_sg['name']}])
+        sg = self.create_security_group()
+        nc_rule = [{'protocol': constants.PROTO_NUM_TCP,
+                    'direction': constants.INGRESS_DIRECTION,
+                    'port_range_min': 6666,
+                    'port_range_max': 6666}]
+        self.create_secgroup_rules(nc_rule, secgroup_id=sg['id'])
+        srv_port = self.client.list_ports(network_id=self.network['id'],
+                device_id=vms[1]['server']['id'])['ports'][0]
+        srv_ip = srv_port['fixed_ips'][0]['ip_address']
+        with utils.StatefulConnection(
+                vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id'], sg['id']])
+            con.test_connection()
+        with utils.StatefulConnection(
+                vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
+            self.client.update_port(
+                    srv_port['id'], security_groups=[ssh_sg['id']])
+            con.test_connection(should_pass=False)
+        with utils.StatefulConnection(
+                vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id'], sg['id']])
+            con.test_connection()
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id']])
+            con.test_connection(should_pass=False)
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id'], sg['id']])
+            con.test_connection()
+
     @decorators.idempotent_id('7ed39b86-006d-40fb-887a-ae46693dabc9')
     def test_remote_group(self):
         # create a new sec group
@@ -572,3 +617,45 @@
             ssh_clients[0], fips[1]['fixed_ip_address'])
         self.check_remote_connectivity(
             ssh_clients[1], fips[0]['fixed_ip_address'])
+
+    @decorators.idempotent_id('cd66b826-d86c-4fb4-ab37-17c8391753cb')
+    def test_overlapping_sec_grp_rules(self):
+        """Test security group rules with overlapping port ranges"""
+        client_ssh, _, vms = self.create_vm_testing_sec_grp(num_servers=2)
+        tmp_ssh, _, tmp_vm = self.create_vm_testing_sec_grp(num_servers=1)
+        srv_ssh = tmp_ssh[0]
+        srv_vm = tmp_vm[0]
+        srv_port = self.client.list_ports(network_id=self.network['id'],
+                device_id=srv_vm['server']['id'])['ports'][0]
+        srv_ip = srv_port['fixed_ips'][0]['ip_address']
+        secgrps = []
+        for i, vm in enumerate(vms):
+            sg = self.create_security_group(name='secgrp-%d' % i)
+            self.create_loginable_secgroup_rule(secgroup_id=sg['id'])
+            port = self.client.list_ports(network_id=self.network['id'],
+                    device_id=vm['server']['id'])['ports'][0]
+            self.client.update_port(port['id'], security_groups=[sg['id']])
+            secgrps.append(sg)
+        tcp_port = 3000
+        rule_list = [{'protocol': constants.PROTO_NUM_TCP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'port_range_min': tcp_port,
+                      'port_range_max': tcp_port,
+                      'remote_group_id': secgrps[0]['id']},
+                     {'protocol': constants.PROTO_NUM_TCP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'port_range_min': tcp_port,
+                      'port_range_max': tcp_port + 2,
+                      'remote_group_id': secgrps[1]['id']}]
+        self.client.update_port(srv_port['id'],
+                security_groups=[secgrps[0]['id'], secgrps[1]['id']])
+        self.create_secgroup_rules(rule_list, secgroup_id=secgrps[0]['id'])
+        # The conntrack entries are ruled by the OF definitions but conntrack
+        # status can change the datapath. Let's check the rules in two
+        # attempts
+        for _ in range(2):
+            self._verify_http_connection(client_ssh[0], srv_ssh, srv_ip,
+                                         tcp_port, [])
+            for port in range(tcp_port, tcp_port + 3):
+                self._verify_http_connection(client_ssh[1], srv_ssh, srv_ip,
+                                             port, [])
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index db37fad..063eb02 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -17,6 +17,7 @@
         - dhcp_agent_scheduler
         - dns-domain-ports
         - dns-integration
+        - dns-integration-domain-keywords
         - empty-string-filtering
         - expose-port-forwarding-in-fip
         - expose-l3-conntrack-helper
@@ -75,6 +76,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk
@@ -86,11 +88,25 @@
         - ipv6_metadata
       tempest_test_regex: ^neutron_tempest_plugin\.api
       devstack_services:
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Neutron services
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
         neutron-log: true
       devstack_localrc:
-        # TODO(lucasagomes): Re-enable MOD_WSGI after
-        # https://bugs.launchpad.net/neutron/+bug/1912359 is implemented
-        NEUTRON_DEPLOY_MOD_WSGI: false
+        Q_AGENT: openvswitch
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
       devstack_local_conf:
         post-config:
           # NOTE(slaweq): We can get rid of this hardcoded absolute path when
@@ -206,7 +222,11 @@
       network_available_features: *available_features
       # TODO(slaweq): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
-      tempest_exclude_regex: "(^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)"
+      # TODO(akatz): remove established tcp session verification test when the
+      # bug https://bugzilla.redhat.com/show_bug.cgi?id=1965036 will be fixed
+      tempest_exclude_regex: "\
+          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
       devstack_localrc:
         Q_AGENT: openvswitch
         Q_ML2_TENANT_NETWORK_TYPE: vxlan
@@ -685,6 +705,21 @@
       - openstack/neutron-tempest-plugin
       - openstack/tempest
     vars:
+      devstack_services:
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Enable Neutron services that are not used by OVN
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
       network_api_extensions_common: *api_extensions
       tempest_test_regex: ^neutron_tempest_plugin\.sfc
       devstack_plugins:
@@ -694,6 +729,9 @@
         - flow_classifier
         - sfc
       devstack_localrc:
+        Q_AGENT: openvswitch
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_sfc) | join(',') }}"
       # TODO(bcafarel): tests still fail from time to time in parallel
       # https://bugs.launchpad.net/neutron/+bug/1851500
@@ -707,12 +745,30 @@
       - openstack/networking-bagpipe
       - openstack/networking-bgpvpn
     vars:
+      devstack_services:
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Enable Neutron services that are not used by OVN
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
       tempest_test_regex: ^neutron_tempest_plugin\.bgpvpn
       network_api_extensions: *api_extensions
       network_api_extensions_bgpvpn:
         - bgpvpn
         - bgpvpn-routes-control
       devstack_localrc:
+        Q_AGENT: openvswitch
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
         NETWORKING_BGPVPN_DRIVER: "BGPVPN:BaGPipe:networking_bgpvpn.neutron.services.service_drivers.bagpipe.bagpipe_v2.BaGPipeBGPVPNDriver:default"
         BAGPIPE_DATAPLANE_DRIVER_IPVPN: "ovs"
         BAGPIPE_BGP_PEERS: "-"
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 055fdfc..969f80a 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -7,6 +7,7 @@
         - neutron-tempest-plugin-scenario-openvswitch
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
         - neutron-tempest-plugin-scenario-ovn
+        - neutron-tempest-plugin-designate-scenario
     gate:
       jobs:
         - neutron-tempest-plugin-api
@@ -19,10 +20,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario
 
 
 - project-template:
@@ -50,6 +47,7 @@
         - neutron-tempest-plugin-scenario-linuxbridge-rocky
         - neutron-tempest-plugin-scenario-openvswitch-rocky
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-rocky
+        - neutron-tempest-plugin-designate-scenario-rocky
     gate:
       jobs:
         - neutron-tempest-plugin-api-rocky
@@ -58,10 +56,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-rocky
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-rocky
 
 
 - project-template:
@@ -72,6 +66,7 @@
         - neutron-tempest-plugin-scenario-linuxbridge-stein
         - neutron-tempest-plugin-scenario-openvswitch-stein
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-stein
+        - neutron-tempest-plugin-designate-scenario-stein
     gate:
       jobs:
         - neutron-tempest-plugin-api-stein
@@ -80,10 +75,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-stein
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-stein
 
 
 - project-template:
@@ -94,6 +85,7 @@
         - neutron-tempest-plugin-scenario-linuxbridge-train
         - neutron-tempest-plugin-scenario-openvswitch-train
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-train
+        - neutron-tempest-plugin-designate-scenario-train
     gate:
       jobs:
         - neutron-tempest-plugin-api-train
@@ -102,10 +94,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-train
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-train
 
 
 - project-template:
@@ -117,6 +105,7 @@
         - neutron-tempest-plugin-scenario-openvswitch-ussuri
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-ussuri
         - neutron-tempest-plugin-scenario-ovn-ussuri
+        - neutron-tempest-plugin-designate-scenario-ussuri
     gate:
       jobs:
         - neutron-tempest-plugin-api-ussuri
@@ -125,10 +114,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-ussuri
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-ussuri
 
 
 - project-template:
@@ -140,6 +125,7 @@
         - neutron-tempest-plugin-scenario-openvswitch-victoria
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-victoria
         - neutron-tempest-plugin-scenario-ovn-victoria
+        - neutron-tempest-plugin-designate-scenario-victoria
     gate:
       jobs:
         - neutron-tempest-plugin-api-victoria
@@ -148,10 +134,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-victoria
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-victoria
 
 
 - project-template:
@@ -163,6 +145,7 @@
         - neutron-tempest-plugin-scenario-openvswitch-wallaby
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-wallaby
         - neutron-tempest-plugin-scenario-ovn-wallaby
+        - neutron-tempest-plugin-designate-scenario-wallaby
     gate:
       jobs:
         - neutron-tempest-plugin-api-wallaby
@@ -171,17 +154,12 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-wallaby
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-wallaby
 
 
 - project:
     templates:
       - build-openstack-docs-pti
       - neutron-tempest-plugin-jobs
-      - neutron-tempest-plugin-jobs-train
       - neutron-tempest-plugin-jobs-ussuri
       - neutron-tempest-plugin-jobs-victoria
       - neutron-tempest-plugin-jobs-wallaby
@@ -191,12 +169,10 @@
     check:
       jobs:
         - neutron-tempest-plugin-sfc
-        - neutron-tempest-plugin-sfc-train
         - neutron-tempest-plugin-sfc-ussuri
         - neutron-tempest-plugin-sfc-victoria
         - neutron-tempest-plugin-sfc-wallaby
         - neutron-tempest-plugin-bgpvpn-bagpipe
-        - neutron-tempest-plugin-bgpvpn-bagpipe-train
         - neutron-tempest-plugin-bgpvpn-bagpipe-ussuri
         - neutron-tempest-plugin-bgpvpn-bagpipe-victoria
         - neutron-tempest-plugin-bgpvpn-bagpipe-wallaby
@@ -217,10 +193,6 @@
 
     experimental:
       jobs:
-        - neutron-tempest-plugin-fwaas-train:
-            # TODO(slaweq): switch it to be voting when bug
-            # https://bugs.launchpad.net/neutron/+bug/1858645 will be fixed
-            voting: false
         - neutron-tempest-plugin-fwaas-ussuri:
             # TODO(slaweq): switch it to be voting when bug
             # https://bugs.launchpad.net/neutron/+bug/1858645 will be fixed
diff --git a/zuul.d/queens_jobs.yaml b/zuul.d/queens_jobs.yaml
index 33430c8..9701548 100644
--- a/zuul.d/queens_jobs.yaml
+++ b/zuul.d/queens_jobs.yaml
@@ -75,6 +75,7 @@
         - standard-attr-timestamp
         - standard-attr-tag
         - subnet_allocation
+        - subnet-service-types
         - trunk
         - trunk-details
       network_api_extensions_tempest:
diff --git a/zuul.d/rocky_jobs.yaml b/zuul.d/rocky_jobs.yaml
index 0cc84a7..11e4c9a 100644
--- a/zuul.d/rocky_jobs.yaml
+++ b/zuul.d/rocky_jobs.yaml
@@ -84,6 +84,7 @@
         - standard-attr-timestamp
         - standard-attr-tag
         - subnet_allocation
+        - subnet-service-types
         - trunk
         - trunk-details
       network_api_extensions_tempest:
@@ -132,33 +133,85 @@
 
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-rocky
-    parent: neutron-tempest-plugin-scenario-openvswitch
+    parent: neutron-tempest-plugin-scenario
     description: |
       This job run on py2 for stable/rocky gate.
     nodeset: openstack-single-node-xenial
+    timeout: 10000
     override-checkout: stable/rocky
     required-projects: *required-projects-rocky
     vars: &scenario_vars_rocky
+      devstack_services:
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Neutron services
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
       branch_override: stable/rocky
       network_api_extensions: *api_extensions
       network_available_features: &available_features
         -
       devstack_localrc:
         USE_PYTHON3: false
+        Q_AGENT: openvswitch
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
       devstack_local_conf:
         post-config:
+          $NEUTRON_CONF:
+            DEFAULT:
+              enable_dvr: false
+              l3_ha: true
+          # NOTE(slaweq): We can get rid of this hardcoded absolute path when
+          # devstack-tempest job will be switched to use lib/neutron instead of
+          # lib/neutron-legacy
+          /$NEUTRON_CORE_PLUGIN_CONF:
+            agent:
+              tunnel_types: vxlan,gre
+            ovs:
+              tunnel_bridge: br-tun
+              bridge_mappings: public:br-ex
           $NEUTRON_L3_CONF:
             DEFAULT:
               # NOTE(slaweq): on Xenial keepalived don't knows this option yet
               keepalived_use_no_track: False
-      # NOTE(bcafarel): newer tests, unstable on rocky branch
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
+            neutron_plugin_options:
+              available_type_drivers: flat,vlan,local,vxlan
+              firewall_driver: openvswitch
       tempest_black_regex: "\
           (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
           (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)"
     branches:
       - stable/rocky
+    irrelevant-files: &openvswitch-scenario-irrelevant-files
+      - ^(test-|)requirements.txt$
+      - ^releasenotes/.*$
+      - ^doc/.*$
+      - ^setup.cfg$
+      - ^.*\.rst$
+      - ^neutron/locale/.*$
+      - ^neutron/tests/unit/.*$
+      - ^tools/.*$
+      - ^tox.ini$
+      - ^neutron/agent/windows/.*$
+      - ^neutron/plugins/ml2/drivers/linuxbridge/.*$
+      - ^neutron/plugins/ml2/drivers/macvtap/.*$
+      - ^neutron/plugins/ml2/drivers/mech_sriov/.*$
 
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-rocky
@@ -174,28 +227,70 @@
       devstack_localrc:
         USE_PYTHON3: True
     branches: ^(?!stable/rocky).*$
+    irrelevant-files: *openvswitch-scenario-irrelevant-files
 
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-rocky
-    parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
+    parent: neutron-tempest-plugin-scenario
     nodeset: openstack-single-node-xenial
+    timeout: 10000
     description: |
       This job run on py2 for stable/rocky gate.
     override-checkout: stable/rocky
     required-projects: *required-projects-rocky
     vars: &openvswitch_vars_rocky
-      branch_override: stable/rocky
+      devstack_services:
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Neutron services
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+        Q_AGENT: openvswitch
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
       devstack_local_conf:
         post-config:
+          $NEUTRON_CONF:
+            DEFAULT:
+              enable_dvr: false
+              l3_ha: true
+          # NOTE(slaweq): We can get rid of this hardcoded absolute path when
+          # devstack-tempest job will be switched to use lib/neutron instead of
+          # lib/neutron-legacy
+          /$NEUTRON_CORE_PLUGIN_CONF:
+            agent:
+              tunnel_types: vxlan,gre
+            ovs:
+              tunnel_bridge: br-tun
+              bridge_mappings: public:br-ex
+            securitygroup:
+              firewall_driver: iptables_hybrid
           $NEUTRON_L3_CONF:
             DEFAULT:
               # NOTE(slaweq): on Xenial keepalived don't knows this option yet
               keepalived_use_no_track: False
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
+            neutron_plugin_options:
+              available_type_drivers: flat,vlan,local,vxlan
+              firewall_driver: iptables_hybrid
       # TODO(bcafarel): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
       # NOTE(bcafarel): other are newer tests, unstable on rocky branch
@@ -205,11 +300,27 @@
           (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)"
     branches:
       - stable/rocky
+    irrelevant-files: &iptables_hybrid_irrelevant_files
+      - ^(test-|)requirements.txt$
+      - ^releasenotes/.*$
+      - ^doc/.*$
+      - ^setup.cfg$
+      - ^.*\.rst$
+      - ^neutron/locale/.*$
+      - ^neutron/tests/unit/.*$
+      - ^tools/.*$
+      - ^tox.ini$
+      - ^neutron/agent/linux/openvswitch_firewall/.*$
+      - ^neutron/agent/windows/.*$
+      - ^neutron/plugins/ml2/drivers/linuxbridge/.*$
+      - ^neutron/plugins/ml2/drivers/macvtap/.*$
+      - ^neutron/plugins/ml2/drivers/mech_sriov/.*$
 
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-rocky
-    parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
+    parent: neutron-tempest-plugin-scenario
     nodeset: openstack-single-node-xenial
+    timeout: 10000
     description: |
       This job run on py3 for other than stable/rocky gate
       which is nothing but neutron-tempest-pluign master gate.
@@ -220,6 +331,7 @@
       devstack_localrc:
         USE_PYTHON3: True
     branches: ^(?!stable/rocky).*$
+    irrelevant-files: *iptables_hybrid_irrelevant_files
 
 - job:
     name: neutron-tempest-plugin-scenario-linuxbridge-rocky
@@ -295,28 +407,171 @@
 
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-rocky
-    parent: neutron-tempest-plugin-dvr-multinode-scenario
+    parent: tempest-multinode-full
     description: |
       This job run on py2 for stable/rocky gate.
     nodeset: openstack-two-node-xenial
     override-checkout: stable/rocky
+    roles:
+      - zuul: openstack/devstack
     required-projects: *required-projects-rocky
+    pre-run: playbooks/dvr-multinode-scenario-pre-run.yaml
+    voting: false
     vars: &multinode_scenario_vars_rocky
-      branch_override: stable/rocky
+      tempest_concurrency: 4
+      tox_envlist: all
+      tempest_test_regex: ^neutron_tempest_plugin\.scenario
+      # NOTE(slaweq): in case of some tests, which requires advanced image,
+      # default test timeout set to 1200 seconds may be not enough if job is
+      # run on slow node
+      tempest_test_timeout: 2400
       network_api_extensions_common: *api_extensions
+      network_api_extensions_dvr:
+        - dvr
       devstack_localrc:
         USE_PYTHON3: false
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_dvr) | join(',') }}"
+        PHYSICAL_NETWORK: default
+        CIRROS_VERSION: 0.5.1
+        IMAGE_URLS: https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img
+        ADVANCED_IMAGE_NAME: ubuntu-18.04-server-cloudimg-amd64
+        ADVANCED_INSTANCE_TYPE: ds512M
+        ADVANCED_INSTANCE_USER: ubuntu
+        BUILD_TIMEOUT: 784
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+      devstack_plugins:
+        neutron: https://opendev.org/openstack/neutron.git
+        neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin.git
+      tempest_plugins:
+        - neutron-tempest-plugin
+      devstack_services:
+        tls-proxy: false
+        tempest: true
+        neutron-dns: true
+        neutron-qos: true
+        neutron-segments: true
+        neutron-trunk: true
+        neutron-log: true
+        neutron-port-forwarding: true
+        # Cinder services
+        c-api: false
+        c-bak: false
+        c-sch: false
+        c-vol: false
+        cinder: false
+        # We don't need Swift to be run in the Neutron jobs
+        s-account: false
+        s-container: false
+        s-object: false
+        s-proxy: false
+      devstack_local_conf:
+        post-config:
+          $NEUTRON_CONF:
+            quotas:
+              quota_router: 100
+              quota_floatingip: 500
+              quota_security_group: 100
+              quota_security_group_rule: 1000
+            DEFAULT:
+              router_distributed: True
+          # NOTE(slaweq): We can get rid of this hardcoded absolute path when
+          # devstack-tempest job will be switched to use lib/neutron instead of
+          # lib/neutron-legacy
+          "/$NEUTRON_CORE_PLUGIN_CONF":
+            ml2:
+              type_drivers: flat,geneve,vlan,gre,local,vxlan
+              mechanism_drivers: openvswitch,l2population
+            ml2_type_vlan:
+              network_vlan_ranges: foo:1:10
+            ml2_type_vxlan:
+              vni_ranges: 1:2000
+            ml2_type_gre:
+              tunnel_id_ranges: 1:1000
+            agent:
+              enable_distributed_routing: True
+              l2_population: True
+              tunnel_types: vxlan,gre
+            ovs:
+              tunnel_bridge: br-tun
+              bridge_mappings: public:br-ex
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              agent_mode: dvr_snat
+            agent:
+              availability_zone: nova
+          $NEUTRON_DHCP_CONF:
+            agent:
+              availability_zone: nova
+          "/etc/neutron/api-paste.ini":
+            "composite:neutronapi_v2_0":
+              use: "call:neutron.auth:pipeline_factory"
+              noauth: "cors request_id catch_errors osprofiler extensions neutronapiapp_v2_0"
+              keystone: "cors request_id catch_errors osprofiler authtoken keystonecontext extensions neutronapiapp_v2_0"
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: *available_features
+            neutron_plugin_options:
+              provider_vlans: foo,
+              agent_availability_zone: nova
+              image_is_advanced: true
+              available_type_drivers: flat,geneve,vlan,gre,local,vxlan
+              l3_agent_mode: dvr_snat
+              firewall_driver: openvswitch
+      branch_override: stable/rocky
       # NOTE(bcafarel): newer tests, unstable on rocky branch
       tempest_black_regex: "\
           (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
           (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)"
     branches:
       - stable/rocky
+    group-vars: &multinode_scenario_group_vars_rocky
+      subnode:
+        devstack_services:
+          tls-proxy: false
+          q-agt: true
+          q-l3: true
+          q-meta: true
+          neutron-qos: true
+          neutron-trunk: true
+          neutron-log: true
+          neutron-port-forwarding: true
+          # Cinder services
+          c-bak: false
+          c-vol: false
+          # We don't need Swift to be run in the Neutron jobs
+          s-account: false
+          s-container: false
+          s-object: false
+          s-proxy: false
+        devstack_localrc:
+          USE_PYTHON3: true
+        devstack_local_conf:
+          post-config:
+            $NEUTRON_CONF:
+              DEFAULT:
+                router_distributed: True
+            # NOTE(slaweq): We can get rid of this hardcoded absolute path when
+            # devstack-tempest job will be switched to use lib/neutron instead of
+            # lib/neutron-legacy
+            "/$NEUTRON_CORE_PLUGIN_CONF":
+              agent:
+                enable_distributed_routing: True
+                l2_population: True
+                tunnel_types: vxlan,gre
+              ovs:
+                tunnel_bridge: br-tun
+                bridge_mappings: public:br-ex
+            $NEUTRON_L3_CONF:
+              DEFAULT:
+                agent_mode: dvr_snat
+              agent:
+                availability_zone: nova
+    irrelevant-files: *openvswitch-scenario-irrelevant-files
 
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-rocky
-    parent: neutron-tempest-plugin-dvr-multinode-scenario
+    parent: tempest-multinode-full
     nodeset: openstack-two-node-xenial
     description: |
       This job run on py3 for other than stable/rocky gate
@@ -328,6 +583,7 @@
         USE_PYTHON3: True
     required-projects: *required-projects-rocky
     group-vars:
+      <<: *multinode_scenario_group_vars_rocky
       subnode:
         devstack_localrc:
           USE_PYTHON3: True
diff --git a/zuul.d/stein_jobs.yaml b/zuul.d/stein_jobs.yaml
index 28729a4..40bca7c 100644
--- a/zuul.d/stein_jobs.yaml
+++ b/zuul.d/stein_jobs.yaml
@@ -88,6 +88,7 @@
         - standard-attr-tag
         - standard-attr-timestamp
         - subnet_allocation
+        - subnet-service-types
         - trunk
         - trunk-details
         - uplink-status-propagation
@@ -144,18 +145,55 @@
 
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-stein
-    parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
+    parent: neutron-tempest-plugin-scenario
     nodeset: openstack-single-node-bionic
+    timeout: 10000
     override-checkout: stable/stein
     required-projects: *required-projects-stein
     vars:
       branch_override: stable/stein
+      devstack_services:
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Neutron services
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
       network_api_extensions: *api_extensions
       network_available_features: *available_features
+      # TODO(slaweq): remove trunks subport_connectivity test from blacklist
+      # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
+      tempest_black_regex: "(^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)"
       devstack_localrc:
+        Q_AGENT: openvswitch
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         post-config:
+          $NEUTRON_CONF:
+            DEFAULT:
+              enable_dvr: false
+              l3_ha: true
+          # NOTE(slaweq): We can get rid of this hardcoded absolute path when
+          # devstack-tempest job will be switched to use lib/neutron instead of
+          # lib/neutron-legacy
+          /$NEUTRON_CORE_PLUGIN_CONF:
+            agent:
+              tunnel_types: vxlan,gre
+            ovs:
+              tunnel_bridge: br-tun
+              bridge_mappings: public:br-ex
+            securitygroup:
+              firewall_driver: iptables_hybrid
           $NEUTRON_L3_CONF:
             DEFAULT:
               # NOTE(slaweq): on Bionic keepalived don't knows this option yet
@@ -163,24 +201,84 @@
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
-              available_features: ""
+              available_features: "{{ network_available_features | join(',') }}"
             neutron_plugin_options:
+              available_type_drivers: flat,vlan,local,vxlan
+              firewall_driver: iptables_hybrid
               ipv6_metadata: False
+    irrelevant-files:
+      - ^(test-|)requirements.txt$
+      - ^releasenotes/.*$
+      - ^doc/.*$
+      - ^setup.cfg$
+      - ^.*\.rst$
+      - ^neutron/locale/.*$
+      - ^neutron/tests/unit/.*$
+      - ^tools/.*$
+      - ^tox.ini$
+      - ^neutron/agent/linux/openvswitch_firewall/.*$
+      - ^neutron/agent/ovn/.*$
+      - ^neutron/agent/windows/.*$
+      - ^neutron/plugins/ml2/drivers/linuxbridge/.*$
+      - ^neutron/plugins/ml2/drivers/macvtap/.*$
+      - ^neutron/plugins/ml2/drivers/mech_sriov/.*$
+      - ^neutron/plugins/ml2/drivers/ovn/.*$
 
 - job:
     name: neutron-tempest-plugin-scenario-linuxbridge-stein
-    parent: neutron-tempest-plugin-scenario-linuxbridge
+    parent: neutron-tempest-plugin-scenario
     nodeset: openstack-single-node-bionic
+    timeout: 10000
+    roles:
+      - zuul: openstack/neutron
+    pre-run: playbooks/linuxbridge-scenario-pre-run.yaml
     override-checkout: stable/stein
     required-projects: *required-projects-stein
     vars:
       branch_override: stable/stein
+      devstack_services:
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Neutron services
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
       network_api_extensions: *api_extensions
+      network_api_extensions_linuxbridge:
+        - vlan-transparent
       network_available_features: *available_features
+      # TODO(eolivare): remove VLAN Transparency tests from blacklist
+      # when bug https://bugs.launchpad.net/neutron/+bug/1907548 will be fixed
+      tempest_black_regex: "(^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)"
       devstack_localrc:
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+        Q_AGENT: linuxbridge
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions + network_api_extensions_linuxbridge) | join(',') }}"
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch,linuxbridge
       devstack_local_conf:
         post-config:
+          $NEUTRON_CONF:
+            DEFAULT:
+              enable_dvr: false
+              vlan_transparent: true
+              l3_ha: true
+            AGENT:
+              debug_iptables_rules: true
+          # NOTE(slaweq): We can get rid of this hardcoded absolute path when
+          # devstack-tempest job will be switched to use lib/neutron instead of
+          # lib/neutron-legacy
+          /$NEUTRON_CORE_PLUGIN_CONF:
+            ml2:
+              type_drivers: flat,vlan,local,vxlan
+              mechanism_drivers: linuxbridge
           $NEUTRON_L3_CONF:
             DEFAULT:
               # NOTE(slaweq): on Bionic keepalived don't knows this option yet
@@ -188,9 +286,29 @@
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
-              available_features: ""
+              available_features: "{{ network_available_features | join(',') }}"
             neutron_plugin_options:
+              available_type_drivers: flat,vlan,local,vxlan
+              q_agent: linuxbridge
+              firewall_driver: iptables
               ipv6_metadata: False
+    irrelevant-files:
+      - ^(test-|)requirements.txt$
+      - ^releasenotes/.*$
+      - ^doc/.*$
+      - ^setup.cfg$
+      - ^.*\.rst$
+      - ^neutron/locale/.*$
+      - ^neutron/tests/unit/.*$
+      - ^tools/.*$
+      - ^tox.ini$
+      - ^neutron/agent/linux/openvswitch_firewall/.*$
+      - ^neutron/agent/ovn/.*$
+      - ^neutron/agent/windows/.*$
+      - ^neutron/plugins/ml2/drivers/openvswitch/.*$
+      - ^neutron/plugins/ml2/drivers/macvtap/.*$
+      - ^neutron/plugins/ml2/drivers/mech_sriov/.*$
+      - ^neutron/plugins/ml2/drivers/ovn/.*$
 
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-stein
diff --git a/zuul.d/train_jobs.yaml b/zuul.d/train_jobs.yaml
index 75c8ebe..a623251 100644
--- a/zuul.d/train_jobs.yaml
+++ b/zuul.d/train_jobs.yaml
@@ -3,6 +3,11 @@
     parent: neutron-tempest-plugin-api
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: &required-projects-train
+      - openstack/neutron
+      - name: openstack/neutron-tempest-plugin
+        override-checkout: 1.5.0
+      - openstack/tempest
     vars:
       devstack_services:
         # Disable OVN services
@@ -87,6 +92,7 @@
         - standard-attr-tag
         - standard-attr-timestamp
         - subnet_allocation
+        - subnet-service-types
         - subnetpool-prefix-ops
         - trunk
         - trunk-details
@@ -122,6 +128,7 @@
     parent: neutron-tempest-plugin-scenario-openvswitch
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       branch_override: stable/train
       network_api_extensions: *api_extensions
@@ -146,6 +153,7 @@
     parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       branch_override: stable/train
       network_api_extensions: *api_extensions
@@ -170,6 +178,7 @@
     parent: neutron-tempest-plugin-scenario-linuxbridge
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       branch_override: stable/train
       network_api_extensions: *api_extensions
@@ -194,6 +203,7 @@
     parent: neutron-tempest-plugin-dvr-multinode-scenario
     nodeset: openstack-two-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       network_api_extensions_common: *api_extensions
       branch_override: stable/train
@@ -203,6 +213,7 @@
     parent: neutron-tempest-plugin-designate-scenario
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       branch_override: stable/train
       network_api_extensions_common: *api_extensions
@@ -212,6 +223,7 @@
     parent: neutron-tempest-plugin-sfc
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       branch_override: stable/train
       network_api_extensions_common: *api_extensions
@@ -221,6 +233,7 @@
     parent: neutron-tempest-plugin-bgpvpn-bagpipe
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       branch_override: stable/train
       network_api_extensions: *api_extensions
@@ -230,6 +243,7 @@
     parent: neutron-tempest-plugin-fwaas-ussuri
     nodeset: openstack-single-node-bionic
     override-checkout: stable/train
+    required-projects: *required-projects-train
     vars:
       branch_override: stable/train
       network_api_extensions_common: *api_extensions
diff --git a/zuul.d/ussuri_jobs.yaml b/zuul.d/ussuri_jobs.yaml
index 945ec25..5c5881e 100644
--- a/zuul.d/ussuri_jobs.yaml
+++ b/zuul.d/ussuri_jobs.yaml
@@ -90,6 +90,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk
diff --git a/zuul.d/victoria_jobs.yaml b/zuul.d/victoria_jobs.yaml
index e0e29ed..832d242 100644
--- a/zuul.d/victoria_jobs.yaml
+++ b/zuul.d/victoria_jobs.yaml
@@ -89,6 +89,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk
diff --git a/zuul.d/wallaby_jobs.yaml b/zuul.d/wallaby_jobs.yaml
index fa2ddb6..13a192e 100644
--- a/zuul.d/wallaby_jobs.yaml
+++ b/zuul.d/wallaby_jobs.yaml
@@ -76,6 +76,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk