Merge "Test neutron-dynamic-routing on OVN"
diff --git a/neutron_tempest_plugin/api/admin/test_dhcp_agent_scheduler.py b/neutron_tempest_plugin/api/admin/test_dhcp_agent_scheduler.py
deleted file mode 100644
index 9dc4438..0000000
--- a/neutron_tempest_plugin/api/admin/test_dhcp_agent_scheduler.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright 2013 IBM Corp.
-#
-#    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 neutron_lib import constants
-from neutron_lib.utils import test
-from tempest.lib import decorators
-
-from neutron_tempest_plugin.api import base
-from neutron_tempest_plugin.common import utils
-
-
-class DHCPAgentSchedulersTestJSON(base.BaseAdminNetworkTest):
-
-    required_extensions = ['dhcp_agent_scheduler']
-
-    @classmethod
-    def resource_setup(cls):
-        super(DHCPAgentSchedulersTestJSON, cls).resource_setup()
-        # Create a network and make sure it will be hosted by a
-        # dhcp agent: this is done by creating a regular port
-        cls.network = cls.create_network()
-        cls.subnet = cls.create_subnet(cls.network)
-        cls.cidr = cls.subnet['cidr']
-        cls.port = cls.create_port(cls.network)
-
-    @test.unstable_test("bug 1906654")
-    @decorators.idempotent_id('f164801e-1dd8-4b8b-b5d3-cc3ac77cfaa5')
-    def test_dhcp_port_status_active(self):
-
-        def dhcp_port_active():
-            for p in self.client.list_ports(
-                    network_id=self.network['id'])['ports']:
-                if (p['device_owner'] == constants.DEVICE_OWNER_DHCP and
-                        p['status'] == constants.PORT_STATUS_ACTIVE):
-                    return True
-            return False
-        utils.wait_until_true(dhcp_port_active)
-
-    @decorators.idempotent_id('5032b1fe-eb42-4a64-8f3b-6e189d8b5c7d')
-    def test_list_dhcp_agent_hosting_network(self):
-        self.admin_client.list_dhcp_agent_hosting_network(
-            self.network['id'])
-
-    @decorators.idempotent_id('30c48f98-e45d-4ffb-841c-b8aad57c7587')
-    def test_list_networks_hosted_by_one_dhcp(self):
-        body = self.admin_client.list_dhcp_agent_hosting_network(
-            self.network['id'])
-        agents = body['agents']
-        self.assertIsNotNone(agents)
-        agent = agents[0]
-        self.assertTrue(self._check_network_in_dhcp_agent(
-            self.network['id'], agent))
-
-    def _check_network_in_dhcp_agent(self, network_id, agent):
-        network_ids = []
-        body = self.admin_client.list_networks_hosted_by_one_dhcp_agent(
-            agent['id'])
-        networks = body['networks']
-        for network in networks:
-            network_ids.append(network['id'])
-        return network_id in network_ids
-
-    @decorators.idempotent_id('a0856713-6549-470c-a656-e97c8df9a14d')
-    def test_add_remove_network_from_dhcp_agent(self):
-        # The agent is now bound to the network, we can free the port
-        self.client.delete_port(self.port['id'])
-        self.ports.remove(self.port)
-        agent = dict()
-        agent['agent_type'] = None
-        body = self.admin_client.list_agents()
-        agents = body['agents']
-        for a in agents:
-            if a['agent_type'] == 'DHCP agent':
-                agent = a
-                break
-        self.assertEqual(agent['agent_type'], 'DHCP agent', 'Could not find '
-                         'DHCP agent in agent list though dhcp_agent_scheduler'
-                         ' is enabled.')
-        network = self.create_network()
-        network_id = network['id']
-        if self._check_network_in_dhcp_agent(network_id, agent):
-            self._remove_network_from_dhcp_agent(network_id, agent)
-            self._add_dhcp_agent_to_network(network_id, agent)
-        else:
-            self._add_dhcp_agent_to_network(network_id, agent)
-            self._remove_network_from_dhcp_agent(network_id, agent)
-
-    def _remove_network_from_dhcp_agent(self, network_id, agent):
-        self.admin_client.remove_network_from_dhcp_agent(
-            agent_id=agent['id'],
-            network_id=network_id)
-        self.assertFalse(self._check_network_in_dhcp_agent(
-            network_id, agent))
-
-    def _add_dhcp_agent_to_network(self, network_id, agent):
-        self.admin_client.add_dhcp_agent_to_network(agent['id'],
-                                                    network_id)
-        self.assertTrue(self._check_network_in_dhcp_agent(
-            network_id, agent))
diff --git a/neutron_tempest_plugin/api/admin/test_ports.py b/neutron_tempest_plugin/api/admin/test_ports.py
index e9a1bdb..e26e122 100644
--- a/neutron_tempest_plugin/api/admin/test_ports.py
+++ b/neutron_tempest_plugin/api/admin/test_ports.py
@@ -230,6 +230,9 @@
 
     @decorators.idempotent_id('7261391f-64cc-45a6-a1e3-435694c54bf5')
     def test_port_resource_request_no_provider_net_conflict(self):
+        self.skipTest('This test is skipped until LP#1991965 is implemented. '
+                      'Once implemented, it will be removed and new tests '
+                      'added. For now it is temporarily kept as a reminder')
         conflict = self.assertRaises(
             tlib_exceptions.Conflict,
             self._create_qos_policy_and_port,
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index e080d42..10821c1 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -994,8 +994,9 @@
         ip_version = ip_version or cls._ip_version
         default_params = (
             constants.DEFAULT_SECURITY_GROUP_RULE_PARAMS[ip_version])
-        if ('remote_address_group_id' in kwargs and 'remote_ip_prefix' in
-                default_params):
+        if (('remote_address_group_id' in kwargs or
+             'remote_group_id' in kwargs) and
+                'remote_ip_prefix' in default_params):
             default_params.pop('remote_ip_prefix')
         for key, value in default_params.items():
             kwargs.setdefault(key, value)
diff --git a/neutron_tempest_plugin/api/test_ports.py b/neutron_tempest_plugin/api/test_ports.py
index f1dfe5c..8d5772b 100644
--- a/neutron_tempest_plugin/api/test_ports.py
+++ b/neutron_tempest_plugin/api/test_ports.py
@@ -80,7 +80,7 @@
                        service="network")
     def test_create_update_port_with_dns_name(self):
         # NOTE(manjeets) dns_domain is set to openstackgate.local
-        # so dns_name for port can be set
+        # (or any other configured value) so dns_name for port can be set
         self.create_subnet(self.network)
         body = self.create_port(self.network, dns_name='d1')
         self.assertEqual('d1', body['dns_name'])
diff --git a/neutron_tempest_plugin/api/test_security_groups.py b/neutron_tempest_plugin/api/test_security_groups.py
index d251f8c..e7a9eae 100644
--- a/neutron_tempest_plugin/api/test_security_groups.py
+++ b/neutron_tempest_plugin/api/test_security_groups.py
@@ -29,13 +29,15 @@
 LOG = log.getLogger(__name__)
 
 
-class SecGroupTest(base.BaseAdminNetworkTest):
+class BaseSecGroupTest(base.BaseAdminNetworkTest):
 
     required_extensions = ['security-group']
 
-    @decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
-    def test_create_list_update_show_delete_security_group(self):
-        security_group = self.create_security_group()
+    def _test_create_list_update_show_delete_security_group(self):
+        sg_kwargs = {}
+        if self.stateless_sg:
+            sg_kwargs['stateful'] = False
+        security_group = self.create_security_group(**sg_kwargs)
 
         # List security groups and verify if created group is there in response
         security_groups = self.client.list_security_groups()['security_groups']
@@ -61,9 +63,11 @@
         self.assertEqual(observed_security_group['description'],
                          new_description)
 
-    @decorators.idempotent_id('1fff0d57-bb6c-4528-9c1d-2326dce1c087')
-    def test_show_security_group_contains_all_rules(self):
-        security_group = self.create_security_group()
+    def _test_show_security_group_contains_all_rules(self):
+        sg_kwargs = {}
+        if self.stateless_sg:
+            sg_kwargs['stateful'] = False
+        security_group = self.create_security_group(**sg_kwargs)
         protocol = random.choice(list(base_security_groups.V4_PROTOCOL_NAMES))
         security_group_rule = self.create_security_group_rule(
             security_group=security_group,
@@ -80,14 +84,16 @@
         self.assertIn(
             security_group_rule['id'], observerd_security_group_rules_ids)
 
-    @decorators.idempotent_id('b5923b1a-4d33-44e1-af25-088dcb55b02b')
-    def test_list_security_group_rules_contains_all_rules(self):
+    def _test_list_security_group_rules_contains_all_rules(self):
         """Test list security group rules.
 
         This test checks if all SG rules which belongs to the tenant OR
         which belongs to the tenant's security group are listed.
         """
-        security_group = self.create_security_group()
+        sg_kwargs = {}
+        if self.stateless_sg:
+            sg_kwargs['stateful'] = False
+        security_group = self.create_security_group(**sg_kwargs)
         protocol = random.choice(list(base_security_groups.V4_PROTOCOL_NAMES))
         security_group_rule = self.create_security_group_rule(
             security_group=security_group,
@@ -98,9 +104,13 @@
 
         # Create also other SG with some custom rule to check that regular user
         # can't see this rule
-        admin_security_group = self.create_security_group(
-            project={'id': self.admin_client.tenant_id},
-            client=self.admin_client)
+        sg_kwargs = {
+            'project': {'id': self.admin_client.tenant_id},
+            'client': self.admin_client
+        }
+        if self.stateless_sg:
+            sg_kwargs['stateful'] = False
+        admin_security_group = self.create_security_group(**sg_kwargs)
         admin_security_group_rule = self.create_security_group_rule(
             security_group=admin_security_group,
             project={'id': self.admin_client.tenant_id},
@@ -113,12 +123,12 @@
         self.assertIn(security_group_rule['id'], rules_ids)
         self.assertNotIn(admin_security_group_rule['id'], rules_ids)
 
-    @decorators.idempotent_id('7c0ecb10-b2db-11e6-9b14-000c29248b0d')
-    def test_create_bulk_sec_groups(self):
+    def _test_create_bulk_sec_groups(self):
         # Creates 2 sec-groups in one request
         sec_nm = [data_utils.rand_name('secgroup'),
                   data_utils.rand_name('secgroup')]
-        body = self.client.create_bulk_security_groups(sec_nm)
+        body = self.client.create_bulk_security_groups(
+            sec_nm, stateless=self.stateless_sg)
         created_sec_grps = body['security_groups']
         self.assertEqual(2, len(created_sec_grps))
         for secgrp in created_sec_grps:
@@ -127,13 +137,16 @@
             self.assertIn(secgrp['name'], sec_nm)
             self.assertIsNotNone(secgrp['id'])
 
-    @decorators.idempotent_id('e93f33d8-57ea-11eb-b69b-74e5f9e2a801')
-    def test_create_sec_groups_with_the_same_name(self):
+    def _test_create_sec_groups_with_the_same_name(self):
         same_name_sg_number = 5
         sg_name = 'sg_zahlabut'
         sg_names = [sg_name] * same_name_sg_number
+        sg_kwargs = {}
+        if self.stateless_sg:
+            sg_kwargs['stateful'] = False
         for name in sg_names:
-            self.create_security_group(name=name)
+            sg_kwargs['name'] = name
+            self.create_security_group(**sg_kwargs)
         sec_groups = [item['id'] for item in
                       self.client.list_security_groups(
                           name=sg_name)['security_groups']]
@@ -143,9 +156,55 @@
             ' is: {}'.format(same_name_sg_number))
 
 
-class StatelessSecGroupTest(base.BaseAdminNetworkTest):
+class StatefulSecGroupTest(BaseSecGroupTest):
+
+    stateless_sg = False
+
+    @decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
+    def test_create_list_update_show_delete_security_group(self):
+        self._test_create_list_update_show_delete_security_group()
+
+    @decorators.idempotent_id('1fff0d57-bb6c-4528-9c1d-2326dce1c087')
+    def test_show_security_group_contains_all_rules(self):
+        self._test_show_security_group_contains_all_rules()
+
+    @decorators.idempotent_id('b5923b1a-4d33-44e1-af25-088dcb55b02b')
+    def test_list_security_group_rules_contains_all_rules(self):
+        self._test_list_security_group_rules_contains_all_rules()
+
+    @decorators.idempotent_id('7c0ecb10-b2db-11e6-9b14-000c29248b0d')
+    def test_create_bulk_sec_groups(self):
+        self._test_create_bulk_sec_groups()
+
+    @decorators.idempotent_id('e93f33d8-57ea-11eb-b69b-74e5f9e2a801')
+    def test_create_sec_groups_with_the_same_name(self):
+        self._test_create_sec_groups_with_the_same_name()
+
+
+class StatelessSecGroupTest(BaseSecGroupTest):
 
     required_extensions = ['security-group', 'stateful-security-group']
+    stateless_sg = True
+
+    @decorators.idempotent_id('0214d58a-2177-47e1-af83-dcd45c024829')
+    def test_create_list_update_show_delete_security_group(self):
+        self._test_create_list_update_show_delete_security_group()
+
+    @decorators.idempotent_id('ddbc0e4c-840f-44ab-8718-0b95b7c7b575')
+    def test_show_security_group_contains_all_rules(self):
+        self._test_show_security_group_contains_all_rules()
+
+    @decorators.idempotent_id('cdf3a63a-08fe-4091-bab4-62180847990f')
+    def test_list_security_group_rules_contains_all_rules(self):
+        self._test_list_security_group_rules_contains_all_rules()
+
+    @decorators.idempotent_id('b33e612e-65f0-467b-9bf2-b5b2ce67f72f')
+    def test_create_bulk_sec_groups(self):
+        self._test_create_bulk_sec_groups()
+
+    @decorators.idempotent_id('a6896935-db18-413d-95f5-4f465e0e2209')
+    def test_create_sec_groups_with_the_same_name(self):
+        self._test_create_sec_groups_with_the_same_name()
 
     @decorators.idempotent_id('0a6c1476-3d1a-11ec-b0ec-0800277ac3d9')
     def test_stateless_security_group_update(self):
@@ -380,21 +439,16 @@
         self.assertEqual(self._get_sg_rules_quota(), new_quota)
 
 
-class SecGroupProtocolTest(base.BaseNetworkTest):
+class BaseSecGroupProtocolTest(base.BaseNetworkTest):
 
     protocol_names = base_security_groups.V4_PROTOCOL_NAMES
     protocol_ints = base_security_groups.V4_PROTOCOL_INTS
 
-    @decorators.idempotent_id('282e3681-aa6e-42a7-b05c-c341aa1e3cdf')
-    def test_security_group_rule_protocol_names(self):
-        self._test_security_group_rule_protocols(protocols=self.protocol_names)
-
-    @decorators.idempotent_id('66e47f1f-20b6-4417-8839-3cc671c7afa3')
-    def test_security_group_rule_protocol_ints(self):
-        self._test_security_group_rule_protocols(protocols=self.protocol_ints)
-
     def _test_security_group_rule_protocols(self, protocols):
-        security_group = self.create_security_group()
+        sg_kwargs = {}
+        if self.stateless_sg:
+            sg_kwargs['stateful'] = False
+        security_group = self.create_security_group(**sg_kwargs)
         for protocol in protocols:
             self._test_security_group_rule(
                 security_group=security_group,
@@ -414,14 +468,38 @@
                              "{!r} does not match.".format(key))
 
 
-class SecGroupProtocolIPv6Test(SecGroupProtocolTest):
+class StatefulSecGroupProtocolTest(BaseSecGroupProtocolTest):
+    stateless_sg = False
+
+    @decorators.idempotent_id('282e3681-aa6e-42a7-b05c-c341aa1e3cdf')
+    def test_security_group_rule_protocol_names(self):
+        self._test_security_group_rule_protocols(protocols=self.protocol_names)
+
+    @decorators.idempotent_id('66e47f1f-20b6-4417-8839-3cc671c7afa3')
+    def test_security_group_rule_protocol_ints(self):
+        self._test_security_group_rule_protocols(protocols=self.protocol_ints)
+
+
+class StatelessSecGroupProtocolTest(BaseSecGroupProtocolTest):
+    required_extensions = ['security-group', 'stateful-security-group']
+    stateless_sg = True
+
+    @decorators.idempotent_id('3a065cdd-99bd-409f-a08e-385c6674bec2')
+    def test_security_group_rule_protocol_names(self):
+        self._test_security_group_rule_protocols(protocols=self.protocol_names)
+
+    @decorators.idempotent_id('b0332b5d-6fac-49d5-a79d-ae4fe62600f7')
+    def test_security_group_rule_protocol_ints(self):
+        self._test_security_group_rule_protocols(protocols=self.protocol_ints)
+
+
+class BaseSecGroupProtocolIPv6Test(BaseSecGroupProtocolTest):
 
     _ip_version = constants.IP_VERSION_6
     protocol_names = base_security_groups.V6_PROTOCOL_NAMES
     protocol_ints = base_security_groups.V6_PROTOCOL_INTS
 
-    @decorators.idempotent_id('c7d17b41-3b4e-4add-bb3b-6af59baaaffa')
-    def test_security_group_rule_protocol_legacy_icmpv6(self):
+    def _test_security_group_rule_protocol_legacy_icmpv6(self):
         # These legacy protocols can be used to create security groups,
         # but they could be shown either with their passed protocol name,
         # or a canonical-ized version, depending on the neutron version.
@@ -439,7 +517,10 @@
                 ethertype=self.ethertype)
 
     def _test_security_group_rule_legacy(self, protocol_list, **kwargs):
-        security_group = self.create_security_group()
+        sg_kwargs = {}
+        if self.stateless_sg:
+            sg_kwargs['stateful'] = False
+        security_group = self.create_security_group(**sg_kwargs)
         security_group_rule = self.create_security_group_rule(
             security_group=security_group, **kwargs)
         observed_security_group_rule = self.client.show_security_group_rule(
@@ -457,6 +538,23 @@
                                  "{!r} does not match.".format(key))
 
 
+class StatefulSecGroupProtocolIPv6Test(BaseSecGroupProtocolIPv6Test):
+    stateless_sg = False
+
+    @decorators.idempotent_id('c7d17b41-3b4e-4add-bb3b-6af59baaaffa')
+    def test_security_group_rule_protocol_legacy_icmpv6(self):
+        self._test_security_group_rule_protocol_legacy_icmpv6()
+
+
+class StatelessSecGroupProtocolIPv6Test(BaseSecGroupProtocolIPv6Test):
+    required_extensions = ['security-group', 'stateful-security-group']
+    stateless_sg = True
+
+    @decorators.idempotent_id('a034814e-0fa5-4437-8e6f-0d2eebd668b3')
+    def test_security_group_rule_protocol_legacy_icmpv6(self):
+        self._test_security_group_rule_protocol_legacy_icmpv6()
+
+
 class RbacSharedSecurityGroupTest(base.BaseAdminNetworkTest):
 
     force_tenant_isolation = True
diff --git a/neutron_tempest_plugin/api/test_security_groups_negative.py b/neutron_tempest_plugin/api/test_security_groups_negative.py
index 7efa70e..224558c 100644
--- a/neutron_tempest_plugin/api/test_security_groups_negative.py
+++ b/neutron_tempest_plugin/api/test_security_groups_negative.py
@@ -189,3 +189,66 @@
     def test_sg_creation_with_insufficient_sg_rules_quota(self):
         self._set_sg_rules_quota(0)
         self.assertRaises(lib_exc.Conflict, self.create_security_group)
+
+
+class NegativeStatelessSecGroupTest(base.BaseNetworkTest):
+
+    required_extensions = ['security-group', 'stateful-security-group']
+
+    @classmethod
+    def resource_setup(cls):
+        super().resource_setup()
+        cls.network = cls.create_network()
+        cls.stateless_sg = cls.create_security_group(stateful=False)
+        cls.stateful_sg = cls.create_security_group(stateful=True)
+
+    @decorators.idempotent_id('9e85ce0d-37b2-4044-88a8-09ae965069ba')
+    def test_create_port_with_stateful_and_stateless_sg(self):
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.create_port,
+            network=self.network,
+            security_groups=[self.stateful_sg['id'], self.stateless_sg['id']])
+
+    def _test_adding_sg_to_port_with_different_type_of_sg(
+            self, initial_sg, updated_sg):
+        port = self.create_port(
+            network=self.network,
+            security_groups=[initial_sg['id']]
+        )
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.update_port,
+            port,
+            security_groups=[initial_sg['id'], updated_sg['id']]
+        )
+
+    @decorators.idempotent_id('63374580-3154-410b-ab31-e98a136094f8')
+    def test_adding_stateful_sg_to_port_with_stateless_sg(self):
+        self._test_adding_sg_to_port_with_different_type_of_sg(
+            self.stateless_sg, self.stateful_sg)
+
+    @decorators.idempotent_id('3854a4c6-4ace-4133-be83-4a2820ede06f')
+    def test_adding_stateless_sg_to_port_with_stateful_sg(self):
+        self._test_adding_sg_to_port_with_different_type_of_sg(
+            self.stateful_sg, self.stateless_sg)
+
+    def _test_update_used_sg(self, security_group):
+        self.create_port(
+            network=self.network,
+            security_groups=[security_group['id']]
+        )
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.client.update_security_group,
+            security_group['id'],
+            stateful=not security_group['stateful']
+        )
+
+    @decorators.idempotent_id('5e1e3053-16dc-4f0b-a327-ff953f527248')
+    def test_update_used_stateless_sg_to_stateful(self):
+        self._test_update_used_sg(self.stateless_sg)
+
+    @decorators.idempotent_id('afe4d777-7a98-44ed-a1dc-588861f6daba')
+    def test_update_used_stateful_sg_to_stateless(self):
+        self._test_update_used_sg(self.stateful_sg)
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index aea79ad..4fad1fa 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -73,6 +73,10 @@
                choices=['None', 'openvswitch', 'ovn',
                         'iptables_hybrid', 'iptables'],
                help='Driver for security groups firewall in the L2 agent'),
+    cfg.StrOpt('dns_domain',
+               default='openstackgate.local',
+               help='dns_domain value configured at neutron.conf, which will '
+                    'be used for the DNS configuration of the instances'),
 
     # Multicast tests settings
     cfg.StrOpt('multicast_group_range',
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index b9bf36f..c8eddd1 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -190,6 +190,26 @@
             port_range_max=22)
 
     @classmethod
+    def create_ingress_metadata_secgroup_rule(cls, secgroup_id=None):
+        """This rule is intended to permit inbound metadata traffic
+
+        Allowing ingress traffic from metadata server, required only for
+        stateless security groups.
+        """
+        # NOTE(slaweq): in case of stateless security groups, there is no
+        # "related" or "established" traffic matching at all so even if
+        # egress traffic to 169.254.169.254 is allowed by default SG, we
+        # need to explicitly allow ingress traffic from the metadata server
+        # to be able to receive responses in the guest vm
+        cls.create_security_group_rule(
+            security_group_id=secgroup_id,
+            direction=neutron_lib_constants.INGRESS_DIRECTION,
+            protocol=neutron_lib_constants.PROTO_NAME_TCP,
+            remote_ip_prefix='169.254.169.254/32',
+            description='metadata out'
+        )
+
+    @classmethod
     def create_pingable_secgroup_rule(cls, secgroup_id=None,
                                       client=None):
         """This rule is intended to permit inbound ping
@@ -610,13 +630,14 @@
             self._log_local_network_status()
             raise
 
-    def nc_client(self, ip_address, port, protocol):
+    def nc_client(self, ip_address, port, protocol, ssh_client=None):
         """Check connectivity to TCP/UDP port at host via nc.
 
-        Client is always executed locally on host where tests are executed.
+        If ssh_client is not given, it is executed locally on host where tests
+        are executed. Otherwise ssh_client object is used to execute it.
         """
         cmd = get_ncat_client_cmd(ip_address, port, protocol)
-        result = shell.execute_local_command(cmd)
+        result = shell.execute(cmd, ssh_client=ssh_client)
         self.assertEqual(0, result.exit_status)
         return result.stdout
 
@@ -654,3 +675,15 @@
         router = self.client.update_router(
             router['id'], **kwargs)['router']
         self.assertEqual(admin_state_up, router['admin_state_up'])
+
+    def _check_cmd_installed_on_server(self, ssh_client, server, cmd):
+        try:
+            ssh_client.execute_script('which %s' % cmd)
+        except SSH_EXC_TUPLE as ssh_e:
+            LOG.debug(ssh_e)
+            self._log_console_output([server])
+            self._log_local_network_status()
+            raise
+        except exceptions.SSHScriptFailed:
+            raise self.skipException(
+                "%s is not available on server %s" % (cmd, server['id']))
diff --git a/neutron_tempest_plugin/scenario/test_internal_dns.py b/neutron_tempest_plugin/scenario/test_internal_dns.py
index 692bb70..e705241 100644
--- a/neutron_tempest_plugin/scenario/test_internal_dns.py
+++ b/neutron_tempest_plugin/scenario/test_internal_dns.py
@@ -129,12 +129,13 @@
             servers=[self.server, leia])
 
         resolv_conf = ssh_client.exec_command('cat /etc/resolv.conf')
-        self.assertIn('openstackgate.local', resolv_conf)
+        dns_domain = CONF.neutron_plugin_options.dns_domain
+        self.assertIn(dns_domain, resolv_conf)
         self.assertNotIn('starwars', resolv_conf)
 
         self.check_remote_connectivity(ssh_client, 'leia',
                                        servers=[self.server, leia])
-        self.check_remote_connectivity(ssh_client, 'leia.openstackgate.local',
+        self.check_remote_connectivity(ssh_client, 'leia.' + dns_domain,
                                        servers=[self.server, leia])
 
     @utils.requires_ext(extension="dns-integration", service="network")
diff --git a/neutron_tempest_plugin/scenario/test_mac_learning.py b/neutron_tempest_plugin/scenario/test_mac_learning.py
index 409a6d8..db340ed 100644
--- a/neutron_tempest_plugin/scenario/test_mac_learning.py
+++ b/neutron_tempest_plugin/scenario/test_mac_learning.py
@@ -116,18 +116,6 @@
                                           pkey=self.keypair['private_key'])
         return server
 
-    def _check_cmd_installed_on_server(self, ssh_client, server, cmd):
-        try:
-            ssh_client.execute_script('which %s' % cmd)
-        except base.SSH_EXC_TUPLE as ssh_e:
-            LOG.debug(ssh_e)
-            self._log_console_output([server])
-            self._log_local_network_status()
-            raise
-        except exceptions.SSHScriptFailed:
-            raise self.skipException(
-                "%s is not available on server %s" % (cmd, server['id']))
-
     def _prepare_sender(self, server, address):
         check_script = get_sender_script(self.sender_output_file, address,
                                          self.completed_message)
diff --git a/neutron_tempest_plugin/scenario/test_multicast.py b/neutron_tempest_plugin/scenario/test_multicast.py
index 4fd41cf..390e0f0 100644
--- a/neutron_tempest_plugin/scenario/test_multicast.py
+++ b/neutron_tempest_plugin/scenario/test_multicast.py
@@ -213,18 +213,6 @@
                                             server, PYTHON3_BIN)
         return server
 
-    def _check_cmd_installed_on_server(self, ssh_client, server, cmd):
-        try:
-            ssh_client.execute_script('which %s' % cmd)
-        except base.SSH_EXC_TUPLE as ssh_e:
-            LOG.debug(ssh_e)
-            self._log_console_output([server])
-            self._log_local_network_status()
-            raise
-        except exceptions.SSHScriptFailed:
-            raise self.skipException(
-                "%s is not available on server %s" % (cmd, server['id']))
-
     def _prepare_sender(self, server, mcast_address):
         check_script = get_sender_script(
             group=mcast_address, port=self.multicast_port,
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 5af84db..d5f9b77 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -23,16 +23,30 @@
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
+from neutron_tempest_plugin.common import ip
 from neutron_tempest_plugin.common import ssh
 from neutron_tempest_plugin.common import utils
 from neutron_tempest_plugin import config
+from neutron_tempest_plugin import exceptions
 from neutron_tempest_plugin.scenario import base
 from neutron_tempest_plugin.scenario import constants as const
 
 CONF = config.CONF
 
+EPHEMERAL_PORT_RANGE = {'min': 32768, 'max': 65535}
 
-class NetworkSecGroupTest(base.BaseTempestTestCase):
+
+def get_capture_script(interface, tcp_port, packet_types, result_file):
+    return """#!/bin/bash
+tcpdump -i %(interface)s -vvneA -s0 -l -c1 \
+"dst port %(port)s and tcp[tcpflags] == %(packet_types)s" &> %(result)s &
+    """ % {'interface': interface,
+           'port': tcp_port,
+           'packet_types': packet_types,
+           'result': result_file}
+
+
+class BaseNetworkSecGroupTest(base.BaseTempestTestCase):
     credentials = ['primary', 'admin']
     required_extensions = ['router', 'security-group']
 
@@ -70,46 +84,61 @@
 
     @classmethod
     def setup_credentials(cls):
-        super(NetworkSecGroupTest, cls).setup_credentials()
+        super(BaseNetworkSecGroupTest, cls).setup_credentials()
         cls.network_client = cls.os_admin.network_client
 
     @classmethod
     def setup_clients(cls):
-        super(NetworkSecGroupTest, cls).setup_clients()
+        super(BaseNetworkSecGroupTest, cls).setup_clients()
         cls.project_id = cls.os_primary.credentials.tenant_id
 
     @classmethod
     def resource_setup(cls):
-        super(NetworkSecGroupTest, cls).resource_setup()
+        super(BaseNetworkSecGroupTest, cls).resource_setup()
         # setup basic topology for servers we can log into it
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
-        router = cls.create_router_by_client()
-        cls.create_router_interface(router['id'], cls.subnet['id'])
+        cls.router = cls.create_router_by_client()
+        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.keypair = cls.create_keypair()
 
     def setUp(self):
-        super(NetworkSecGroupTest, self).setUp()
+        super(BaseNetworkSecGroupTest, self).setUp()
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.network_client.reset_quotas, self.project_id)
         self.network_client.update_quotas(self.project_id, security_group=-1)
+        self.network_client.update_quotas(self.project_id,
+                                          security_group_rule=-1)
 
     def create_vm_testing_sec_grp(self, num_servers=2, security_groups=None,
-                                  ports=None):
+                                  ports=None, network_id=None,
+                                  use_advanced_image=False):
         """Create instance for security group testing
 
         :param num_servers (int): number of servers to spawn
         :param security_groups (list): list of security groups
         :param ports* (list): list of ports
+        :param: use_advanced_image (bool): use Cirros (False) or
+                advanced guest image
         *Needs to be the same length as num_servers
         """
+        if (not use_advanced_image or
+                CONF.neutron_plugin_options.default_image_is_advanced):
+            flavor_ref = CONF.compute.flavor_ref
+            image_ref = CONF.compute.image_ref
+            username = CONF.validation.image_ssh_user
+        else:
+            flavor_ref = CONF.neutron_plugin_options.advanced_image_flavor_ref
+            image_ref = CONF.neutron_plugin_options.advanced_image_ref
+            username = CONF.neutron_plugin_options.advanced_image_ssh_user
+        network_id = network_id or self.network['id']
         servers, fips, server_ssh_clients = ([], [], [])
         for i in range(num_servers):
             server_args = {
-                'flavor_ref': CONF.compute.flavor_ref,
-                'image_ref': CONF.compute.image_ref,
+                'flavor_ref': flavor_ref,
+                'image_ref': image_ref,
                 'key_name': self.keypair['name'],
-                'networks': [{'uuid': self.network['id']}],
+                'networks': [{'uuid': network_id}],
                 'security_groups': security_groups
             }
             if ports is not None:
@@ -120,30 +149,135 @@
                 self.os_primary.servers_client, server['server']['id'],
                 const.SERVER_STATUS_ACTIVE)
             port = self.client.list_ports(
-                network_id=self.network['id'], device_id=server['server'][
+                network_id=network_id, device_id=server['server'][
                     'id'])['ports'][0]
             fips.append(self.create_floatingip(port=port))
             server_ssh_clients.append(ssh.Client(
-                fips[i]['floating_ip_address'], CONF.validation.image_ssh_user,
+                fips[i]['floating_ip_address'], username,
                 pkey=self.keypair['private_key']))
         return server_ssh_clients, fips, servers
 
+    def _get_default_security_group(self):
+        sgs = self.os_primary.network_client.list_security_groups(
+            project_id=self.project_id)['security_groups']
+        for sg in sgs:
+            if sg['name'] == 'default':
+                return sg
+
+    def _create_security_group(self, name_prefix, **kwargs):
+        if self.stateless_sg:
+            kwargs['stateful'] = False
+        return super(BaseNetworkSecGroupTest, self).create_security_group(
+            name=data_utils.rand_name(name_prefix), **kwargs)
+
+    def _create_client_and_server_vms(
+            self, allowed_tcp_port=None, use_advanced_image=False):
+        networks = {
+            'server': self.network,
+            'client': self.create_network()}
+        subnet = self.create_subnet(networks['client'])
+        self.create_router_interface(self.router['id'], subnet['id'])
+
+        security_groups = {}
+        for sg_name in ["server", "client"]:
+            sg = self._create_security_group('vm_%s_secgrp' % sg_name)
+            self.create_loginable_secgroup_rule(
+                secgroup_id=sg['id'])
+            if allowed_tcp_port:
+                self.create_security_group_rule(
+                    security_group_id=sg['id'],
+                    protocol=constants.PROTO_NAME_TCP,
+                    direction=constants.INGRESS_DIRECTION,
+                    port_range_min=allowed_tcp_port,
+                    port_range_max=allowed_tcp_port)
+            else:
+                self.create_pingable_secgroup_rule(sg['id'])
+            if self.stateless_sg:
+                self.create_ingress_metadata_secgroup_rule(
+                    secgroup_id=sg['id'])
+            security_groups[sg_name] = sg
+        # NOTE(slaweq): we need to iterate over create_vm_testing_sec_grp as
+        # this method plugs all SGs to all VMs and we need each vm to use other
+        # SGs
+        ssh_clients = {}
+        fips = {}
+        servers = {}
+        for server_name, sg in security_groups.items():
+            _ssh_clients, _fips, _servers = self.create_vm_testing_sec_grp(
+                num_servers=1,
+                security_groups=[{'name': sg['name']}],
+                network_id=networks[server_name]['id'],
+                use_advanced_image=use_advanced_image)
+            ssh_clients[server_name] = _ssh_clients[0]
+            fips[server_name] = _fips[0]
+            servers[server_name] = _servers[0]
+        return ssh_clients, fips, servers, security_groups
+
+    def _test_connectivity_between_vms_using_different_sec_groups(self):
+        TEST_TCP_PORT = 1022
+        ssh_clients, fips, servers, security_groups = (
+            self._create_client_and_server_vms(TEST_TCP_PORT))
+
+        # make sure tcp connectivity between vms works fine
+        for fip in fips.values():
+            self.check_connectivity(fip['floating_ip_address'],
+                                    CONF.validation.image_ssh_user,
+                                    self.keypair['private_key'])
+        # Check connectivity between servers
+        def _message_received(server_ssh_client, client_ssh_client,
+                              dest_fip, servers):
+            expected_msg = "Test_msg"
+            utils.kill_nc_process(server_ssh_client)
+            self.nc_listen(server_ssh_client,
+                           TEST_TCP_PORT,
+                           constants.PROTO_NAME_TCP,
+                           expected_msg,
+                           list(servers.values()))
+            try:
+                received_msg = self.nc_client(
+                    dest_fip,
+                    TEST_TCP_PORT,
+                    constants.PROTO_NAME_TCP,
+                    ssh_client=client_ssh_client)
+                return received_msg and expected_msg in received_msg
+            except exceptions.ShellCommandFailed:
+                return False
+
+        if self.stateless_sg:
+            # In case of stateless SG connectivity will not work without
+            # explicit allow ingress response from server to client
+            utils.wait_until_true(
+                lambda: not _message_received(
+                    ssh_clients['server'], ssh_clients['client'],
+                    fips['server']['fixed_ip_address'], servers))
+            self.create_security_group_rule(
+                security_group_id=security_groups['client']['id'],
+                protocol=constants.PROTO_NAME_TCP,
+                direction=constants.INGRESS_DIRECTION,
+                port_range_min=EPHEMERAL_PORT_RANGE['min'],
+                port_range_max=EPHEMERAL_PORT_RANGE['max'])
+
+        utils.wait_until_true(
+            lambda: _message_received(
+                ssh_clients['server'], ssh_clients['client'],
+                fips['server']['fixed_ip_address'], servers))
+
     def _test_ip_prefix(self, rule_list, should_succeed):
         # Add specific remote prefix to VMs and check connectivity
-        ssh_secgrp_name = data_utils.rand_name('ssh_secgrp')
-        icmp_secgrp_name = data_utils.rand_name('icmp_secgrp_with_cidr')
-        ssh_secgrp = self.os_primary.network_client.create_security_group(
-            name=ssh_secgrp_name)
+        ssh_secgrp = self._create_security_group('ssh_secgrp')
         self.create_loginable_secgroup_rule(
-            secgroup_id=ssh_secgrp['security_group']['id'])
-        icmp_secgrp = self.os_primary.network_client.create_security_group(
-            name=icmp_secgrp_name)
+            secgroup_id=ssh_secgrp['id'])
+        if self.stateless_sg:
+            self.create_ingress_metadata_secgroup_rule(
+                secgroup_id=ssh_secgrp['id'])
+        icmp_secgrp = self._create_security_group('icmp_secgrp')
         self.create_secgroup_rules(
-            rule_list, secgroup_id=icmp_secgrp['security_group']['id'])
+            rule_list, secgroup_id=icmp_secgrp['id'])
         for sec_grp in (ssh_secgrp, icmp_secgrp):
-            self.security_groups.append(sec_grp['security_group'])
-        security_groups_list = [{'name': ssh_secgrp_name},
-                                {'name': icmp_secgrp_name}]
+            self.security_groups.append(sec_grp)
+        security_groups_list = [
+            {'name': ssh_secgrp['name']},
+            {'name': icmp_secgrp['name']}]
         server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
             security_groups=security_groups_list)
 
@@ -157,14 +291,18 @@
             'fixed_ip_address'], should_succeed=should_succeed,
             servers=servers)
 
-    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d764')
-    def test_default_sec_grp_scenarios(self):
+    def _test_default_sec_grp_scenarios(self):
+        # Ensure that SG used in tests is stateful or stateless as required
+        default_sg_id = self._get_default_security_group()['id']
+        self.os_primary.network_client.update_security_group(
+            default_sg_id, stateful=not self.stateless_sg)
+        if self.stateless_sg:
+            self.create_ingress_metadata_secgroup_rule(
+                secgroup_id=default_sg_id)
         server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp()
+
         # Check ssh connectivity when you add sec group rule, enabling ssh
-        self.create_loginable_secgroup_rule(
-            self.os_primary.network_client.list_security_groups()[
-                'security_groups'][0]['id']
-        )
+        self.create_loginable_secgroup_rule(default_sg_id)
         self.check_connectivity(fips[0]['floating_ip_address'],
                                 CONF.validation.image_ssh_user,
                                 self.keypair['private_key'])
@@ -180,6 +318,10 @@
             servers=servers)
 
         # Check ICMP connectivity from VM to external network
+        if self.stateless_sg:
+            # NOTE(slaweq): in case of stateless SG explicit ingress rule for
+            # the ICMP replies needs to be added too
+            self.create_pingable_secgroup_rule(default_sg_id)
         subnets = self.os_admin.network_client.list_subnets(
             network_id=CONF.network.public_network_id)['subnets']
         ext_net_ip = None
@@ -191,11 +333,10 @@
         self.check_remote_connectivity(server_ssh_clients[0], ext_net_ip,
                                        servers=servers)
 
-    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d864')
-    def test_protocol_number_rule(self):
+    def _test_protocol_number_rule(self):
         # protocol number is added instead of str in security rule creation
         name = data_utils.rand_name("test_protocol_number_rule")
-        security_group = self.create_security_group(name=name)
+        security_group = self._create_security_group(name)
         port = self.create_port(network=self.network, name=name,
                                 security_groups=[security_group['id']])
         _, fips, _ = self.create_vm_testing_sec_grp(num_servers=1,
@@ -208,23 +349,22 @@
         self.create_secgroup_rules(rule_list, secgroup_id=security_group['id'])
         self.ping_ip_address(fips[0]['floating_ip_address'])
 
-    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d964')
-    def test_two_sec_groups(self):
+    def _test_two_sec_groups(self):
         # add 2 sec groups to VM and test rules of both are working
-        ssh_secgrp_name = data_utils.rand_name('ssh_secgrp')
-        icmp_secgrp_name = data_utils.rand_name('icmp_secgrp')
-        ssh_secgrp = self.os_primary.network_client.create_security_group(
-            name=ssh_secgrp_name)
+        ssh_secgrp = self._create_security_group('ssh_secgrp')
         self.create_loginable_secgroup_rule(
-            secgroup_id=ssh_secgrp['security_group']['id'])
-        icmp_secgrp = self.os_primary.network_client.create_security_group(
-            name=icmp_secgrp_name)
+            secgroup_id=ssh_secgrp['id'])
+        icmp_secgrp = self._create_security_group('icmp_secgrp')
         self.create_pingable_secgroup_rule(
-            secgroup_id=icmp_secgrp['security_group']['id'])
+            secgroup_id=icmp_secgrp['id'])
+        if self.stateless_sg:
+            self.create_ingress_metadata_secgroup_rule(
+                secgroup_id=ssh_secgrp['id'])
         for sec_grp in (ssh_secgrp, icmp_secgrp):
-            self.security_groups.append(sec_grp['security_group'])
-        security_groups_list = [{'name': ssh_secgrp_name},
-                                {'name': icmp_secgrp_name}]
+            self.security_groups.append(sec_grp)
+        security_groups_list = [
+            {'name': ssh_secgrp['name']},
+            {'name': icmp_secgrp['name']}]
         server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
             num_servers=1, security_groups=security_groups_list)
         # make sure ssh connectivity works
@@ -239,7 +379,7 @@
 
         # update port with ssh security group only
         self.os_primary.network_client.update_port(
-            port_id, security_groups=[ssh_secgrp['security_group']['id']])
+            port_id, security_groups=[ssh_secgrp['id']])
 
         # make sure ssh connectivity works
         self.check_connectivity(fips[0]['floating_ip_address'],
@@ -252,9 +392,7 @@
 
         # update port with ssh and ICMP security groups
         self.os_primary.network_client.update_port(
-            port_id, security_groups=[
-                icmp_secgrp['security_group']['id'],
-                ssh_secgrp['security_group']['id']])
+            port_id, security_groups=[icmp_secgrp['id'], ssh_secgrp['id']])
 
         # make sure ssh connectivity  works after update
         self.check_connectivity(fips[0]['floating_ip_address'],
@@ -264,82 +402,18 @@
         # make sure ICMP connectivity works after update
         self.ping_ip_address(fips[0]['floating_ip_address'])
 
-    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d664')
-    def test_ip_prefix(self):
-        cidr = self.subnet['cidr']
-        rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
-                      'direction': constants.INGRESS_DIRECTION,
-                      'remote_ip_prefix': cidr}]
-        self._test_ip_prefix(rule_list, should_succeed=True)
-
-    @decorators.attr(type='negative')
-    @decorators.idempotent_id('a01cd2ef-3cfc-4614-8aac-9d1333ea21dd')
-    def test_ip_prefix_negative(self):
-        # define bad CIDR
-        cidr = '10.100.0.254/32'
-        rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
-                      'direction': constants.INGRESS_DIRECTION,
-                      '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):
+    def _test_remote_group(self):
         # create a new sec group
-        ssh_secgrp_name = data_utils.rand_name('ssh_secgrp')
-        ssh_secgrp = self.os_primary.network_client.create_security_group(
-            name=ssh_secgrp_name)
-        # add cleanup
-        self.security_groups.append(ssh_secgrp['security_group'])
+        ssh_secgrp = self._create_security_group('ssh_secgrp')
         # configure sec group to support SSH connectivity
         self.create_loginable_secgroup_rule(
-            secgroup_id=ssh_secgrp['security_group']['id'])
+            secgroup_id=ssh_secgrp['id'])
+        if self.stateless_sg:
+            self.create_ingress_metadata_secgroup_rule(
+                secgroup_id=ssh_secgrp['id'])
         # spawn two instances with the sec group created
         server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
-            security_groups=[{'name': ssh_secgrp_name}])
+            security_groups=[{'name': ssh_secgrp['name']}])
         # verify SSH functionality
         for i in range(2):
             self.check_connectivity(fips[i]['floating_ip_address'],
@@ -352,9 +426,9 @@
         # add ICMP support to the remote group
         rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
                       'direction': constants.INGRESS_DIRECTION,
-                      'remote_group_id': ssh_secgrp['security_group']['id']}]
+                      'remote_group_id': ssh_secgrp['id']}]
         self.create_secgroup_rules(
-            rule_list, secgroup_id=ssh_secgrp['security_group']['id'])
+            rule_list, secgroup_id=ssh_secgrp['id'])
         # verify ICMP connectivity between instances works
         self.check_remote_connectivity(
             server_ssh_clients[0], fips[1]['fixed_ip_address'],
@@ -363,14 +437,7 @@
         self.ping_ip_address(fips[0]['floating_ip_address'],
                              should_succeed=False)
 
-    @testtools.skipUnless(
-        CONF.neutron_plugin_options.firewall_driver == 'openvswitch',
-        "Openvswitch agent is required to run this test")
-    @decorators.idempotent_id('678dd4c0-2953-4626-b89c-8e7e4110ec4b')
-    @tempest_utils.requires_ext(extension="address-group", service="network")
-    @tempest_utils.requires_ext(
-        extension="security-groups-remote-address-group", service="network")
-    def test_remote_group_and_remote_address_group(self):
+    def _test_remote_group_and_remote_address_group(self):
         """Test SG rules with remote group and remote address group
 
         This test checks the ICMP connection among two servers using a security
@@ -380,17 +447,13 @@
         them should not disable the connection.
         """
         # create a new sec group
-        ssh_secgrp_name = data_utils.rand_name('ssh_secgrp')
-        ssh_secgrp = self.os_primary.network_client.create_security_group(
-            name=ssh_secgrp_name)
-        # add cleanup
-        self.security_groups.append(ssh_secgrp['security_group'])
+        ssh_secgrp = self._create_security_group('ssh_secgrp')
         # configure sec group to support SSH connectivity
         self.create_loginable_secgroup_rule(
-            secgroup_id=ssh_secgrp['security_group']['id'])
+            secgroup_id=ssh_secgrp['id'])
         # spawn two instances with the sec group created
         server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
-            security_groups=[{'name': ssh_secgrp_name}])
+            security_groups=[{'name': ssh_secgrp['name']}])
         # verify SSH functionality
         for i in range(2):
             self.check_connectivity(fips[i]['floating_ip_address'],
@@ -403,9 +466,9 @@
         # add ICMP support to the remote group
         rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
                       'direction': constants.INGRESS_DIRECTION,
-                      'remote_group_id': ssh_secgrp['security_group']['id']}]
+                      'remote_group_id': ssh_secgrp['id']}]
         remote_sg_rid = self.create_secgroup_rules(
-            rule_list, secgroup_id=ssh_secgrp['security_group']['id'])[0]['id']
+            rule_list, secgroup_id=ssh_secgrp['id'])[0]['id']
         # verify ICMP connectivity between instances works
         self.check_remote_connectivity(
             server_ssh_clients[0], fips[1]['fixed_ip_address'],
@@ -422,7 +485,7 @@
                       'direction': constants.INGRESS_DIRECTION,
                       'remote_address_group_id': test_ag['id']}]
         remote_ag_rid = self.create_secgroup_rules(
-            rule_list, secgroup_id=ssh_secgrp['security_group']['id'])[0]['id']
+            rule_list, secgroup_id=ssh_secgrp['id'])[0]['id']
         # verify ICMP connectivity between instances still works
         self.check_remote_connectivity(
             server_ssh_clients[0], fips[1]['fixed_ip_address'],
@@ -452,8 +515,7 @@
         self.ping_ip_address(fips[0]['floating_ip_address'],
                              should_succeed=False)
 
-    @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad488')
-    def test_multiple_ports_secgroup_inheritance(self):
+    def _test_multiple_ports_secgroup_inheritance(self):
         """Test multiple port security group inheritance
 
         This test creates two ports with security groups, then
@@ -461,20 +523,20 @@
         inherited properly and enforced in these instances.
         """
         # create a security group and make it loginable and pingable
-        secgrp = self.os_primary.network_client.create_security_group(
-            name=data_utils.rand_name('secgrp'))
+        secgrp = self._create_security_group('secgrp')
         self.create_loginable_secgroup_rule(
-            secgroup_id=secgrp['security_group']['id'])
+            secgroup_id=secgrp['id'])
         self.create_pingable_secgroup_rule(
-            secgroup_id=secgrp['security_group']['id'])
-        # add security group to cleanup
-        self.security_groups.append(secgrp['security_group'])
+            secgroup_id=secgrp['id'])
+        if self.stateless_sg:
+            self.create_ingress_metadata_secgroup_rule(
+                secgroup_id=secgrp['id'])
         # create two ports with fixed IPs and the security group created
         ports = []
         for i in range(2):
             ports.append(self.create_port(
                 self.network, fixed_ips=[{'subnet_id': self.subnets[0]['id']}],
-                security_groups=[secgrp['security_group']['id']]))
+                security_groups=[secgrp['id']]))
         # spawn instances with the ports created
         server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
             ports=ports)
@@ -485,17 +547,24 @@
                                     CONF.validation.image_ssh_user,
                                     self.keypair['private_key'])
 
-    @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad489')
-    def test_multiple_ports_portrange_remote(self):
+    def _test_multiple_ports_portrange_remote(self):
+        initial_security_groups = []
+        if self.stateless_sg:
+            md_secgrp = self._create_security_group('metadata_secgrp')
+            self.create_ingress_metadata_secgroup_rule(
+                secgroup_id=md_secgrp['id'])
+            initial_security_groups.append(
+                {'name': md_secgrp['name']})
+
         ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
-            num_servers=3)
+            num_servers=3, security_groups=initial_security_groups)
         secgroups = []
         ports = []
 
         # Create remote and test security groups
         for i in range(0, 2):
             secgroups.append(
-                self.create_security_group(name='secgrp-%d' % i))
+                self._create_security_group('secgrp-%d' % i))
             # configure sec groups to support SSH connectivity
             self.create_loginable_secgroup_rule(
                 secgroup_id=secgroups[-1]['id'])
@@ -535,6 +604,21 @@
                       'port_range_min': '82',
                       'port_range_max': '83',
                       'remote_group_id': secgroups[0]['id']}]
+        if self.stateless_sg:
+            rule_list.append({
+                'protocol': constants.PROTO_NUM_TCP,
+                'direction': constants.EGRESS_DIRECTION,
+                'remote_group_id': secgroups[0]['id']})
+            # NOTE(slaweq): in case of stateless SG, client needs to have also
+            # rule which will explicitly accept ingress connections from
+            # secgroup[1]
+
+            self.create_security_group_rule(
+                security_group_id=secgroups[0]['id'],
+                protocol=constants.PROTO_NAME_TCP,
+                direction=constants.INGRESS_DIRECTION,
+                remote_group_id=secgroups[1]['id'])
+
         self.create_secgroup_rules(
             rule_list, secgroup_id=secgroups[1]['id'])
 
@@ -558,84 +642,19 @@
                     ssh_clients[0], ssh_clients[2], test_ip, port) as con:
                 con.test_connection(should_pass=False)
 
-    @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad490')
-    def test_intra_sg_isolation(self):
-        """Test intra security group isolation
-
-        This test creates a security group that does not allow ingress
-        packets from vms of the same security group. The purpose of this
-        test is to verify that intra SG traffic is properly blocked, while
-        traffic like metadata and DHCP remains working due to the
-        allow-related behavior of the egress rules (added via default).
-        """
-        # create a security group and make it loginable
-        secgrp_name = data_utils.rand_name('secgrp')
-        secgrp = self.os_primary.network_client.create_security_group(
-            name=secgrp_name)
-        secgrp_id = secgrp['security_group']['id']
-        # add security group to cleanup
-        self.security_groups.append(secgrp['security_group'])
-
-        # remove all rules and add ICMP, DHCP and metadata as egress,
-        # and ssh as ingress.
-        for sgr in secgrp['security_group']['security_group_rules']:
-            self.client.delete_security_group_rule(sgr['id'])
-
-        self.create_loginable_secgroup_rule(secgroup_id=secgrp_id)
-        rule_list = [{'direction': constants.EGRESS_DIRECTION,
-                      'protocol': constants.PROTO_NAME_TCP,
-                      'remote_ip_prefix': '169.254.169.254/32',
-                      'description': 'metadata out',
-                      },
-                     {'direction': constants.EGRESS_DIRECTION,
-                      'protocol': constants.PROTO_NAME_UDP,
-                      'port_range_min': '67',
-                      'port_range_max': '67',
-                      'description': 'dhcpv4 out',
-                      },
-                     {'direction': constants.EGRESS_DIRECTION,
-                      'protocol': constants.PROTO_NAME_ICMP,
-                      'description': 'ping out',
-                      },
-                     ]
-        self.create_secgroup_rules(rule_list, secgroup_id=secgrp_id)
-
-        # go vms, go!
-        ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
-            num_servers=2, security_groups=[{'name': secgrp_name}])
-
-        # verify SSH functionality. This will ensure that servers were
-        # able to reach dhcp + metadata servers
-        for fip in fips:
-            self.check_connectivity(fip['floating_ip_address'],
-                                    CONF.validation.image_ssh_user,
-                                    self.keypair['private_key'])
-
-        # try to ping instances without intra SG permission (should fail)
-        self.check_remote_connectivity(
-            ssh_clients[0], fips[1]['fixed_ip_address'],
-            should_succeed=False)
-        self.check_remote_connectivity(
-            ssh_clients[1], fips[0]['fixed_ip_address'],
-            should_succeed=False)
-
-        # add intra sg rule. This will allow packets from servers that
-        # are in the same sg
-        rule_list = [{'direction': constants.INGRESS_DIRECTION,
-                      'remote_group_id': secgrp_id}]
-        self.create_secgroup_rules(rule_list, secgroup_id=secgrp_id)
-
-        # try to ping instances with intra SG permission
-        self.check_remote_connectivity(
-            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):
+    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)
+        initial_security_groups = []
+        if self.stateless_sg:
+            md_secgrp = self._create_security_group('metadata_secgrp')
+            self.create_ingress_metadata_secgroup_rule(
+                secgroup_id=md_secgrp['id'])
+            initial_security_groups.append(
+                {'name': md_secgrp['name']})
+        client_ssh, _, vms = self.create_vm_testing_sec_grp(
+            num_servers=2, security_groups=initial_security_groups)
+        tmp_ssh, _, tmp_vm = self.create_vm_testing_sec_grp(
+            num_servers=1, security_groups=initial_security_groups)
         srv_ssh = tmp_ssh[0]
         srv_vm = tmp_vm[0]
         srv_port = self.client.list_ports(network_id=self.network['id'],
@@ -643,7 +662,7 @@
         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)
+            sg = self._create_security_group('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]
@@ -663,6 +682,22 @@
         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'])
+
+        if self.stateless_sg:
+            # NOTE(slaweq): in case of stateless SG, client needs to have also
+            # rule which will explicitly accept ingress TCP connections which
+            # will be replies from the TCP server so it will use random
+            # destination port (depends on the src port choosen by client while
+            # establishing connection)
+            self.create_security_group_rule(
+                security_group_id=secgrps[0]['id'],
+                protocol=constants.PROTO_NAME_TCP,
+                direction=constants.INGRESS_DIRECTION)
+            self.create_security_group_rule(
+                security_group_id=secgrps[1]['id'],
+                protocol=constants.PROTO_NAME_TCP,
+                direction=constants.INGRESS_DIRECTION)
+
         # The conntrack entries are ruled by the OF definitions but conntrack
         # status can change the datapath. Let's check the rules in two
         # attempts
@@ -675,8 +710,7 @@
                         client_ssh[1], srv_ssh, srv_ip, port) as con:
                     con.test_connection()
 
-    @decorators.idempotent_id('96dcd5ff-9d45-4e0d-bea0-0b438cbd388f')
-    def test_remove_sec_grp_from_active_vm(self):
+    def _test_remove_sec_grp_from_active_vm(self):
         """Tests the following:
 
         1. Create SG associated with ICMP rule
@@ -685,18 +719,15 @@
         4. Remove the security group from VM by Port update
         5. Ping the VM, expected should be FAIL
         """
-        sec_grp_name = data_utils.rand_name('test_sg')
-        secgrp = self.os_primary.network_client.create_security_group(
-            name=sec_grp_name)
-        self.security_groups.append(secgrp['security_group'])
-        sec_grp_id = secgrp['security_group']['id']
-        self.create_pingable_secgroup_rule(sec_grp_id)
+        secgrp = self._create_security_group('test_sg')
+        self.security_groups.append(secgrp)
+        self.create_pingable_secgroup_rule(secgrp['id'])
 
         ex_port = self.create_port(
             self.network, fixed_ips=[{'subnet_id': self.subnet['id']}],
-            security_groups=[sec_grp_id])
+            security_groups=[secgrp['id']])
         fip = self.create_vm_testing_sec_grp(
-            num_servers=1, security_groups=[{'name': sec_grp_name}],
+            num_servers=1, security_groups=[{'name': secgrp['name']}],
             ports=[ex_port])[1][0]
 
         self.ping_ip_address(fip['floating_ip_address'])
@@ -704,3 +735,391 @@
                                 security_groups=[])
         self.ping_ip_address(fip['floating_ip_address'],
                              should_succeed=False)
+
+
+class StatefulNetworkSecGroupTest(BaseNetworkSecGroupTest):
+    stateless_sg = False
+
+    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d764')
+    def test_default_sec_grp_scenarios(self):
+        self._test_default_sec_grp_scenarios()
+
+    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d864')
+    def test_protocol_number_rule(self):
+        self._test_protocol_number_rule()
+
+    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d964')
+    def test_two_sec_groups(self):
+        self._test_two_sec_groups()
+
+    @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d664')
+    def test_ip_prefix(self):
+        cidr = self.subnet['cidr']
+        rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'remote_ip_prefix': cidr}]
+        self._test_ip_prefix(rule_list, should_succeed=True)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('a01cd2ef-3cfc-4614-8aac-9d1333ea21dd')
+    def test_ip_prefix_negative(self):
+        # define bad CIDR
+        cidr = '10.100.0.254/32'
+        rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'remote_ip_prefix': cidr}]
+        self._test_ip_prefix(rule_list, should_succeed=False)
+
+    @decorators.idempotent_id('7ed39b86-006d-40fb-887a-ae46693dabc9')
+    def test_remote_group(self):
+        self._test_remote_group()
+
+    @testtools.skipUnless(
+        CONF.neutron_plugin_options.firewall_driver == 'openvswitch',
+        "Openvswitch agent is required to run this test")
+    @decorators.idempotent_id('678dd4c0-2953-4626-b89c-8e7e4110ec4b')
+    @tempest_utils.requires_ext(extension="address-group", service="network")
+    @tempest_utils.requires_ext(
+        extension="security-groups-remote-address-group", service="network")
+    def test_remote_group_and_remote_address_group(self):
+        self._test_remote_group_and_remote_address_group()
+
+    @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad488')
+    def test_multiple_ports_secgroup_inheritance(self):
+        self._test_multiple_ports_secgroup_inheritance()
+
+    @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad489')
+    def test_multiple_ports_portrange_remote(self):
+        self._test_multiple_ports_portrange_remote()
+
+    @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad490')
+    def test_intra_sg_isolation(self):
+        """Test intra security group isolation
+
+        This test creates a security group that does not allow ingress
+        packets from vms of the same security group. The purpose of this
+        test is to verify that intra SG traffic is properly blocked, while
+        traffic like metadata and DHCP remains working due to the
+        allow-related behavior of the egress rules (added via default).
+        """
+        # create a security group and make it loginable
+        secgrp = self._create_security_group('secgrp')
+
+        # remove all rules and add ICMP, DHCP and metadata as egress,
+        # and ssh as ingress.
+        for sgr in secgrp['security_group_rules']:
+            self.client.delete_security_group_rule(sgr['id'])
+
+        self.create_loginable_secgroup_rule(secgroup_id=secgrp['id'])
+        rule_list = [{'direction': constants.EGRESS_DIRECTION,
+                      'protocol': constants.PROTO_NAME_TCP,
+                      'remote_ip_prefix': '169.254.169.254/32',
+                      'description': 'metadata out',
+                      },
+                     {'direction': constants.EGRESS_DIRECTION,
+                      'protocol': constants.PROTO_NAME_UDP,
+                      'port_range_min': '67',
+                      'port_range_max': '67',
+                      'description': 'dhcpv4 out',
+                      },
+                     {'direction': constants.EGRESS_DIRECTION,
+                      'protocol': constants.PROTO_NAME_ICMP,
+                      'description': 'ping out',
+                      },
+                     ]
+        self.create_secgroup_rules(rule_list, secgroup_id=secgrp['id'])
+
+        # go vms, go!
+        ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
+            num_servers=2,
+            security_groups=[{'name': secgrp['name']}])
+
+        # verify SSH functionality. This will ensure that servers were
+        # able to reach dhcp + metadata servers
+        for fip in fips:
+            self.check_connectivity(fip['floating_ip_address'],
+                                    CONF.validation.image_ssh_user,
+                                    self.keypair['private_key'])
+
+        # try to ping instances without intra SG permission (should fail)
+        self.check_remote_connectivity(
+            ssh_clients[0], fips[1]['fixed_ip_address'],
+            should_succeed=False)
+        self.check_remote_connectivity(
+            ssh_clients[1], fips[0]['fixed_ip_address'],
+            should_succeed=False)
+
+        # add intra sg rule. This will allow packets from servers that
+        # are in the same sg
+        rule_list = [{'direction': constants.INGRESS_DIRECTION,
+                      'remote_group_id': secgrp['id']}]
+        self.create_secgroup_rules(rule_list, secgroup_id=secgrp['id'])
+
+        # try to ping instances with intra SG permission
+        self.check_remote_connectivity(
+            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):
+        self._test_overlapping_sec_grp_rules()
+
+    @decorators.idempotent_id('96dcd5ff-9d45-4e0d-bea0-0b438cbd388f')
+    def test_remove_sec_grp_from_active_vm(self):
+        self._test_remove_sec_grp_from_active_vm()
+
+    @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('ssh_sg')
+        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('sg')
+        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('4a724164-bbc0-4029-a844-644ece66c026')
+    def test_connectivity_between_vms_using_different_sec_groups(self):
+        self._test_connectivity_between_vms_using_different_sec_groups()
+
+
+@testtools.skipIf(
+    CONF.neutron_plugin_options.firewall_driver in ['openvswitch', 'None'],
+    "Firewall driver other than 'openvswitch' is required to use "
+    "stateless security groups.")
+class StatelessNetworkSecGroupTest(BaseNetworkSecGroupTest):
+    required_extensions = ['security-group', 'stateful-security-group']
+    stateless_sg = True
+
+    @decorators.idempotent_id('9e193e3f-56f2-4f4e-886c-988a147958ef')
+    def test_default_sec_grp_scenarios(self):
+        self._test_default_sec_grp_scenarios()
+
+    @decorators.idempotent_id('afae8654-a389-4887-b21d-7f07ec350177')
+    def test_protocol_number_rule(self):
+        self._test_protocol_number_rule()
+
+    @decorators.idempotent_id('b51cc0eb-8f9a-49e7-96ab-61cd31243b67')
+    def test_two_sec_groups(self):
+        self._test_two_sec_groups()
+
+    @decorators.idempotent_id('07985496-58da-4c1f-a6ef-2fdd88128a81')
+    def test_ip_prefix(self):
+        cidr = self.subnet['cidr']
+        rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'remote_ip_prefix': cidr}]
+        self._test_ip_prefix(rule_list, should_succeed=True)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('1ad469c4-0d8f-42ae-8ec3-46cc424565c4')
+    def test_ip_prefix_negative(self):
+        # define bad CIDR
+        cidr = '10.100.0.254/32'
+        rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'remote_ip_prefix': cidr}]
+        self._test_ip_prefix(rule_list, should_succeed=False)
+
+    @decorators.idempotent_id('fa1e93bf-67c5-4590-9962-38ee1f43a46a')
+    def test_remote_group(self):
+        self._test_remote_group()
+
+    @testtools.skipUnless(
+        CONF.neutron_plugin_options.firewall_driver == 'openvswitch',
+        "Openvswitch agent is required to run this test")
+    @decorators.idempotent_id('9fae530d-2711-4c61-a4a5-8efe6e58ab14')
+    @tempest_utils.requires_ext(extension="address-group", service="network")
+    @tempest_utils.requires_ext(
+        extension="security-groups-remote-address-group", service="network")
+    def test_remote_group_and_remote_address_group(self):
+        self._test_remote_group_and_remote_address_group()
+
+    @decorators.idempotent_id('4f1eb6db-ae7f-4f26-b371-cbd8363f9b0b')
+    def test_multiple_ports_secgroup_inheritance(self):
+        self._test_multiple_ports_secgroup_inheritance()
+
+    @decorators.idempotent_id('4043ca0a-eabb-4198-be53-3d3051cc0804')
+    def test_multiple_ports_portrange_remote(self):
+        self._test_multiple_ports_portrange_remote()
+
+    @decorators.idempotent_id('bfe25138-ceac-4944-849a-b9b90aff100f')
+    def test_overlapping_sec_grp_rules(self):
+        self._test_overlapping_sec_grp_rules()
+
+    @decorators.idempotent_id('e4340e47-39cd-49ed-967c-fc2c40b47c5a')
+    def test_remove_sec_grp_from_active_vm(self):
+        self._test_remove_sec_grp_from_active_vm()
+
+    @decorators.idempotent_id('8d4753cc-cd7a-48a0-8ece-e11efce2af10')
+    def test_reattach_sg_with_changed_mode(self):
+        sg_kwargs = {'stateful': True}
+        secgrp = self.os_primary.network_client.create_security_group(
+            name=data_utils.rand_name('secgrp'), **sg_kwargs)['security_group']
+        # add cleanup
+        self.security_groups.append(secgrp)
+
+        # now configure sec group to support required connectivity
+        self.create_pingable_secgroup_rule(secgroup_id=secgrp['id'])
+        # and create server
+        ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
+            num_servers=1, security_groups=[{'name': secgrp['name']}])
+        server_ports = self.network_client.list_ports(
+            device_id=servers[0]['server']['id'])['ports']
+
+        # make sure connectivity works
+        self.ping_ip_address(fips[0]['floating_ip_address'],
+                             should_succeed=True)
+        # remove SG from ports
+        for port in server_ports:
+            self.network_client.update_port(port['id'], security_groups=[])
+        # make sure there is now no connectivity as there's no SG attached
+        # to the port
+        self.ping_ip_address(fips[0]['floating_ip_address'],
+                             should_succeed=False)
+
+        # Update SG to be stateless
+        self.os_primary.network_client.update_security_group(
+            secgrp['id'], stateful=False)
+        # Add SG back to the ports
+        for port in server_ports:
+            self.network_client.update_port(
+                port['id'], security_groups=[secgrp['id']])
+        # Make sure connectivity works fine again
+        self.ping_ip_address(fips[0]['floating_ip_address'],
+                             should_succeed=True)
+
+    @decorators.idempotent_id('7ede9ab5-a615-46c5-9dea-cf2aa1ea43cb')
+    def test_connectivity_between_vms_using_different_sec_groups(self):
+        self._test_connectivity_between_vms_using_different_sec_groups()
+
+    @testtools.skipUnless(
+        (CONF.neutron_plugin_options.advanced_image_ref or
+         CONF.neutron_plugin_options.default_image_is_advanced),
+        "Advanced image is required to run this test.")
+    @decorators.idempotent_id('c3bb8073-97a2-4bea-a6fb-0a9d2e4df13f')
+    def test_packets_of_any_connection_state_can_reach_dest(self):
+        TEST_TCP_PORT = 1022
+        PKT_TYPES = [
+            {'nping': 'syn', 'tcpdump': 'tcp-syn'},
+            {'nping': 'ack', 'tcpdump': 'tcp-ack'},
+            {'nping': 'syn,ack', 'tcpdump': 'tcp-syn|tcp-ack'},
+            {'nping': 'rst', 'tcpdump': 'tcp-rst'},
+            {'nping': 'fin', 'tcpdump': 'tcp-fin'},
+            {'nping': 'psh', 'tcpdump': 'tcp-push'}]
+        ssh_clients, fips, servers, _ = self._create_client_and_server_vms(
+            TEST_TCP_PORT, use_advanced_image=True)
+
+        self._check_cmd_installed_on_server(
+            ssh_clients['server'], servers['server']['server'], 'nping')
+        self._check_cmd_installed_on_server(
+            ssh_clients['client'], servers['client']['server'], 'tcpdump')
+        server_port = self.network_client.show_port(
+            fips['server']['port_id'])['port']
+        server_ip_command = ip.IPCommand(ssh_client=ssh_clients['server'])
+        addresses = server_ip_command.list_addresses(port=server_port)
+        port_iface = ip.get_port_device_name(addresses, server_port)
+
+        def _get_file_suffix(pkt_type):
+            return pkt_type['tcpdump'].replace(
+                'tcp-', '').replace('|', '')
+
+        for pkt_type in PKT_TYPES:
+            file_suffix = _get_file_suffix(pkt_type)
+            capture_script_path = "/tmp/capture_%s.sh" % file_suffix
+            capture_out = "/tmp/capture_%s.out" % file_suffix
+            capture_script = get_capture_script(
+                port_iface, TEST_TCP_PORT, pkt_type['tcpdump'], capture_out)
+            ssh_clients['server'].execute_script(
+                'echo \'%s\' > %s' % (capture_script, capture_script_path))
+            ssh_clients['server'].execute_script(
+                "bash %s" % capture_script_path, become_root=True)
+
+        for pkt_type in PKT_TYPES:
+            ssh_clients['client'].execute_script(
+                "nping --tcp -p %(tcp_port)s --flags %(tcp_flag)s --ttl 10 "
+                "%(ip_address)s -c 3" % {
+                    'tcp_port': TEST_TCP_PORT,
+                    'tcp_flag': pkt_type['nping'],
+                    'ip_address': fips['server']['fixed_ip_address']},
+                become_root=True)
+
+        def _packtet_received(pkt_type):
+            file_suffix = _get_file_suffix(pkt_type)
+            expected_msg = "1 packet captured"
+            result = ssh_clients['server'].execute_script(
+                "cat {path} || echo '{path} not exists yet'".format(
+                    path="/tmp/capture_%s.out" % file_suffix))
+            return expected_msg in result
+
+        for pkt_type in PKT_TYPES:
+            utils.wait_until_true(
+                lambda: _packtet_received(pkt_type),
+                timeout=10,
+                exception=RuntimeError(
+                    'No TCP packet of type %s received by server %s' % (
+                        pkt_type['nping'],
+                        fips['server']['fixed_ip_address'])))
+
+    @testtools.skipUnless(
+        (CONF.neutron_plugin_options.advanced_image_ref or
+         CONF.neutron_plugin_options.default_image_is_advanced),
+        "Advanced image is required to run this test.")
+    @decorators.idempotent_id('14c4af2c-8077-4756-a6e3-6bebd642ed92')
+    def test_fragmented_traffic_is_accepted(self):
+        ssh_clients, fips, servers, security_groups = (
+            self._create_client_and_server_vms(use_advanced_image=True))
+
+        # make sure tcp connectivity to vms works fine
+        for fip in fips.values():
+            self.check_connectivity(
+                fip['floating_ip_address'],
+                CONF.neutron_plugin_options.advanced_image_ssh_user,
+                self.keypair['private_key'])
+
+        # Check that ICMP packets bigger than MTU aren't working without
+        # fragmentation allowed
+        self.check_remote_connectivity(
+            ssh_clients['client'], fips['server']['fixed_ip_address'],
+            mtu=self.network['mtu'] + 1, fragmentation=False,
+            should_succeed=False)
+        # and are working fine with fragmentation enabled:
+        self.check_remote_connectivity(
+            ssh_clients['client'], fips['server']['fixed_ip_address'],
+            mtu=self.network['mtu'] + 1, fragmentation=True,
+            should_succeed=True)
diff --git a/neutron_tempest_plugin/services/network/json/network_client.py b/neutron_tempest_plugin/services/network/json/network_client.py
index a917b4f..0666297 100644
--- a/neutron_tempest_plugin/services/network/json/network_client.py
+++ b/neutron_tempest_plugin/services/network/json/network_client.py
@@ -273,9 +273,13 @@
         self.expected_success(201, resp.status)
         return service_client.ResponseBody(resp, body)
 
-    def create_bulk_security_groups(self, security_group_list):
+    def create_bulk_security_groups(self, security_group_list,
+                                    stateless=False):
         group_list = [{'security_group': {'name': name}}
                       for name in security_group_list]
+        if stateless:
+            for group in group_list:
+                group['security_group']['stateful'] = False
         post_data = {'security_groups': group_list}
         body = self.serialize_list(post_data, 'security_groups',
                                    'security_group')
diff --git a/tools/customize_ubuntu_image b/tools/customize_ubuntu_image
index fdd2d12..cb96b17 100755
--- a/tools/customize_ubuntu_image
+++ b/tools/customize_ubuntu_image
@@ -19,6 +19,7 @@
    iperf3
    iputils-ping
    ncat
+   nmap
    psmisc  # provides killall command
    python3
    tcpdump
diff --git a/tox.ini b/tox.ini
index ff50b9d..c2fc078 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,11 +1,10 @@
 [tox]
 minversion = 3.18.0
 envlist = pep8
-skipsdist = True
 ignore_basepython_conflict = True
 
 [testenv]
-basepython = python3
+basepython = {env:TOX_PYTHON:python3}
 usedevelop = True
 setenv =
    VIRTUAL_ENV={envdir}
@@ -15,15 +14,16 @@
    OS_STDERR_CAPTURE={env:OS_STDERR_CAPTURE:true}
 deps =
   -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+  -r{toxinidir}/requirements.txt
   -r{toxinidir}/test-requirements.txt
 commands = stestr run --slowest {posargs}
 
 [testenv:pep8]
 commands =
-  sh ./tools/misc-sanity-checks.sh
+  bash ./tools/misc-sanity-checks.sh
   flake8
 allowlist_externals =
-  sh
+  bash
 
 [testenv:venv]
 commands = {posargs}
diff --git a/zuul.d/2023_1_jobs.yaml b/zuul.d/2023_1_jobs.yaml
new file mode 100644
index 0000000..d6ba077
--- /dev/null
+++ b/zuul.d/2023_1_jobs.yaml
@@ -0,0 +1,270 @@
+- job:
+    name: neutron-tempest-plugin-openvswitch-2023-1
+    parent: neutron-tempest-plugin-openvswitch
+    override-checkout: stable/2023.1
+    vars:
+      network_api_extensions_openvswitch:
+        - dhcp_agent_scheduler
+        - local_ip
+        - qos-bw-minimum-ingress
+      tempest_test_regex: "\
+          (^neutron_tempest_plugin.api)|\
+          (^neutron_tempest_plugin.scenario)|\
+          (^tempest.api.compute.servers.test_attach_interfaces)|\
+          (^tempest.api.compute.servers.test_multiple_create)"
+      network_available_features: &available_features
+        - ipv6_metadata
+      network_api_extensions_common: &api_extensions
+        - address-group
+        - address-scope
+        - agent
+        - allowed-address-pairs
+        - auto-allocated-topology
+        - availability_zone
+        - binding
+        - default-subnetpools
+        - dns-domain-ports
+        - dns-integration
+        - dns-integration-domain-keywords
+        - empty-string-filtering
+        - expose-port-forwarding-in-fip
+        - expose-l3-conntrack-helper
+        - ext-gw-mode
+        - external-net
+        - extra_dhcp_opt
+        - extraroute
+        - extraroute-atomic
+        - filter-validation
+        - fip-port-details
+        - flavors
+        - floating-ip-port-forwarding
+        - floating-ip-port-forwarding-detail
+        - floatingip-pools
+        - ip-substring-filtering
+        - l3-conntrack-helper
+        - l3-ext-ndp-proxy
+        - l3-flavors
+        - l3-ha
+        - l3-ndp-proxy
+        - l3_agent_scheduler
+        - metering
+        - multi-provider
+        - net-mtu
+        - net-mtu-writable
+        - network-ip-availability
+        - network_availability_zone
+        - network-segment-range
+        - pagination
+        - port-device-profile
+        - port-resource-request
+        - port-resource-request-groups
+        - port-mac-address-regenerate
+        - port-security
+        - port-security-groups-filtering
+        - project-id
+        - provider
+        - qos
+        - qos-fip
+        - quotas
+        - quota_details
+        - rbac-address-group
+        - rbac-address-scope
+        - rbac-policies
+        - rbac-security-groups
+        - rbac-subnetpool
+        - router
+        - router_availability_zone
+        - security-group
+        - security-groups-remote-address-group
+        - segment
+        - service-type
+        - sorting
+        - standard-attr-description
+        - standard-attr-revisions
+        - standard-attr-segment
+        - standard-attr-tag
+        - standard-attr-timestamp
+        - stateful-security-group
+        - subnet_allocation
+        - subnet-dns-publish-fixed-ip
+        - subnet-service-types
+        - subnetpool-prefix-ops
+        - tag-ports-during-bulk-creation
+        - trunk
+        - trunk-details
+        - uplink-status-propagation
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
+
+- job:
+    name: neutron-tempest-plugin-openvswitch-iptables_hybrid-2023-1
+    parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
+    override-checkout: stable/2023.1
+    vars:
+      network_api_extensions_openvswitch:
+        - dhcp_agent_scheduler
+        - local_ip
+        - logging
+      network_available_features: *available_features
+      tempest_test_regex: "\
+          (^neutron_tempest_plugin.api)|\
+          (^neutron_tempest_plugin.scenario)|\
+          (^tempest.api.compute.servers.test_attach_interfaces)|\
+          (^tempest.api.compute.servers.test_multiple_create)"
+      # TODO(slaweq): remove trunks subport_connectivity test from blacklist
+      # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
+      # 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.StatefulNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
+      devstack_local_conf:
+        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
+
+- job:
+    name: neutron-tempest-plugin-openvswitch-enforce-scope-new-defaults-2023-1
+    parent: neutron-tempest-plugin-openvswitch-2023-1
+    override-checkout: stable/2023.1
+    vars:
+      devstack_localrc:
+        # Enabeling the scope and new defaults for services.
+        # NOTE: (gmann) We need to keep keystone scope check disable as
+        # services (except ironic) does not support the system scope and
+        # they need keystone to continue working with project scope. Until
+        # Keystone policies are changed to work for both system as well as
+        # for project scoped, we need to keep scope check disable for
+        # keystone.
+        NOVA_ENFORCE_SCOPE: true
+        GLANCE_ENFORCE_SCOPE: true
+        NEUTRON_ENFORCE_SCOPE: true
+
+- job:
+    name: neutron-tempest-plugin-linuxbridge-2023-1
+    parent: neutron-tempest-plugin-linuxbridge
+    override-checkout: stable/2023.1
+    vars:
+      network_api_extensions_linuxbridge:
+        - dhcp_agent_scheduler
+        - vlan-transparent
+      network_available_features: *available_features
+      tempest_test_regex: "\
+          (^neutron_tempest_plugin.api)|\
+          (^neutron_tempest_plugin.scenario)|\
+          (^tempest.api.compute.servers.test_attach_interfaces)|\
+          (^tempest.api.compute.servers.test_multiple_create)"
+      # TODO(eolivare): remove VLAN Transparency tests from blacklist
+      # when bug https://bugs.launchpad.net/neutron/+bug/1907548 will be fixed
+      # TODO(slaweq): remove
+      # test_established_tcp_session_after_re_attachinging_sg from the
+      # exclude regex when bug https://bugs.launchpad.net/neutron/+bug/1936911
+      # will be fixed
+      # TODO(slaweq) remove test_floatingip_port_details from the exclude
+      # regex when bug https://bugs.launchpad.net/neutron/+bug/1799790 will be
+      # fixed
+      tempest_exclude_regex: "\
+          (^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatefulNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_floatingip.FloatingIPPortDetailsTest.test_floatingip_port_details)"
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_linuxbridge) | join(',') }}"
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
+            neutron_plugin_options:
+              available_type_drivers: flat,vlan,local,vxlan
+              q_agent: linuxbridge
+              firewall_driver: iptables
+
+- job:
+    name: neutron-tempest-plugin-ovn-2023-1
+    parent: neutron-tempest-plugin-ovn
+    override-checkout: stable/2023.1
+    vars:
+      network_api_extensions_ovn:
+        - vlan-transparent
+      tempest_test_regex: "\
+          (^neutron_tempest_plugin.api)|\
+          (^neutron_tempest_plugin.scenario)|\
+          (^tempest.api.compute.servers.test_attach_interfaces)|\
+          (^tempest.api.compute.servers.test_multiple_create)"
+      # TODO(jlibosva): Remove the NetworkWritableMtuTest test from the list
+      # once east/west fragmentation is supported in core OVN
+      tempest_exclude_regex: "\
+          (^neutron_tempest_plugin.scenario.test_mtu.NetworkWritableMtuTest)"
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_ovn) | join(',') }}"
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
+            neutron_plugin_options:
+              available_type_drivers: local,flat,vlan,geneve
+              is_igmp_snooping_enabled: True
+              firewall_driver: ovn
+
+- job:
+    name: neutron-tempest-plugin-dvr-multinode-scenario-2023-1
+    parent: neutron-tempest-plugin-dvr-multinode-scenario
+    override-checkout: stable/2023.1
+    vars:
+      network_api_extensions_common: *api_extensions
+      network_api_extensions_dvr:
+        - dhcp_agent_scheduler
+        - dvr
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_dvr) | join(',') }}"
+
+- job:
+    name: neutron-tempest-plugin-designate-scenario-2023-1
+    parent: neutron-tempest-plugin-designate-scenario
+    override-checkout: stable/2023.1
+    vars:
+      network_api_extensions_common: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-sfc-2023-1
+    parent: neutron-tempest-plugin-sfc
+    override-checkout: stable/2023.1
+
+- job:
+    name: neutron-tempest-plugin-bgpvpn-bagpipe-2023-1
+    parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    override-checkout: stable/2023.1
+
+- job:
+    name: neutron-tempest-plugin-dynamic-routing-2023-1
+    parent: neutron-tempest-plugin-dynamic-routing
+    override-checkout: stable/2023.1
+
+- job:
+    name: neutron-tempest-plugin-fwaas-2023-1
+    parent: neutron-tempest-plugin-fwaas
+    override-checkout: stable/2023.1
+
+- job:
+    name: neutron-tempest-plugin-vpnaas-2023-1
+    parent: neutron-tempest-plugin-vpnaas
+    override-checkout: stable/2023.1
+
+- job:
+    name: neutron-tempest-plugin-tap-as-a-service-2023-1
+    parent: neutron-tempest-plugin-tap-as-a-service
+    override-checkout: stable/2023.1
diff --git a/zuul.d/base-nested-switch.yaml b/zuul.d/base-nested-switch.yaml
index dcc0175..a9f5750 100644
--- a/zuul.d/base-nested-switch.yaml
+++ b/zuul.d/base-nested-switch.yaml
@@ -13,20 +13,21 @@
     name: neutron-tempest-plugin-base-nested-switch
     parent: neutron-tempest-plugin-base
     abstract: true
-    branches: ^(?!stable/(queens|rocky|stein|train|ussuri)).*$
+    branches: ^(?!stable/(train|ussuri|victoria|wallaby)).*$
     # Comment nodeset and vars to switch back to non nested nodes
     nodeset: neutron-nested-virt-ubuntu-focal
     vars:
       devstack_localrc:
         LIBVIRT_TYPE: kvm
-        LIBVIRT_CPU_MODE: host-passthrough
-        CIRROS_VERSION: 0.5.1
-        DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-disk
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.5.1-x86_64-disk.img
+        # cirros 0.6.1 not booting when host-passthrough is used
+        # LIBVIRT_CPU_MODE: host-passthrough
+        CIRROS_VERSION: 0.6.1
+        DEFAULT_IMAGE_NAME: cirros-0.6.1-x86_64-disk
+        DEFAULT_IMAGE_FILE_NAME: cirros-0.6.1-x86_64-disk.img
 
 # Base nested switch job for EM releases
 - job:
-    name: neutron-tempest-plugin-scenario-nested-switch
+    name: neutron-tempest-plugin-base-nested-switch
     parent: neutron-tempest-plugin-base
     abstract: true
-    branches: ^(stable/(queens|rocky|stein|train|ussuri)).*$
+    branches: ^(stable/(train|ussuri|victoria|wallaby)).*$
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index 2534f14..6ff76be 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -27,9 +27,9 @@
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
         PHYSICAL_NETWORK: public
         IMAGE_URLS: https://cloud-images.ubuntu.com/minimal/releases/focal/release/ubuntu-20.04-minimal-cloudimg-amd64.img
-        CIRROS_VERSION: 0.5.1
-        DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.5.1-x86_64-uec.tar.gz
+        CIRROS_VERSION: 0.6.1
+        DEFAULT_IMAGE_NAME: cirros-0.6.1-x86_64-uec
+        DEFAULT_IMAGE_FILE_NAME: cirros-0.6.1-x86_64-uec.tar.gz
         ADVANCED_IMAGE_NAME: ubuntu-20.04-minimal-cloudimg-amd64
         ADVANCED_INSTANCE_TYPE: ntp_image_256M
         ADVANCED_INSTANCE_USER: ubuntu
@@ -164,9 +164,6 @@
               quota_floatingip: 500
               quota_security_group: 150
               quota_security_group_rule: 1000
-          # 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
@@ -207,6 +204,7 @@
       - ^neutron/tests/functional/.*
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^neutron/agent/.*$
       - ^neutron/privileged/.*$
       - ^neutron_lib/tests/unit/.*$
@@ -256,9 +254,6 @@
             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
@@ -288,6 +283,7 @@
       - ^neutron/tests/functional/.*
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^neutron/agent/ovn/.*$
       - ^neutron/agent/windows/.*$
       - ^neutron/plugins/ml2/drivers/linuxbridge/.*$
@@ -344,7 +340,8 @@
       # 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)"
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatefulNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
       devstack_localrc:
         Q_AGENT: openvswitch
         Q_ML2_TENANT_NETWORK_TYPE: vxlan
@@ -356,9 +353,6 @@
             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
@@ -389,6 +383,7 @@
       - ^neutron/tests/functional/.*
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^neutron/agent/linux/openvswitch_firewall/.*$
       - ^neutron/agent/ovn/.*$
       - ^neutron/agent/windows/.*$
@@ -413,6 +408,23 @@
       - ^vagrant/.*$
       - ^zuul.d/(?!(project)).*\.yaml
 
+- job:
+    name: neutron-tempest-plugin-openvswitch-enforce-scope-new-defaults
+    parent: neutron-tempest-plugin-openvswitch
+    vars:
+      devstack_localrc:
+        # Enabeling the scope and new defaults for services.
+        # NOTE: (gmann) We need to keep keystone scope check disable as
+        # services (except ironic) does not support the system scope and
+        # they need keystone to continue working with project scope. Until
+        # Keystone policies are changed to work for both system as well as
+        # for project scoped, we need to keep scope check disable for
+        # keystone.
+        NOVA_ENFORCE_SCOPE: true
+        GLANCE_ENFORCE_SCOPE: true
+        NEUTRON_ENFORCE_SCOPE: true
+
+
 # TODO(slaweq): remove that job's definition as soon as new job
 # "neutron-tempest-plugin-openvswitch-iptables_hybrid" will be used in the
 # neutron repo as a parent for a
@@ -496,7 +508,8 @@
       # fixed
       tempest_exclude_regex: "\
           (^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)|\
-          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatefulNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
           (^neutron_tempest_plugin.scenario.test_floatingip.FloatingIPPortDetailsTest.test_floatingip_port_details)"
       devstack_localrc:
         Q_AGENT: linuxbridge
@@ -514,9 +527,6 @@
               debug_iptables_rules: true
             EXPERIMENTAL:
               linuxbridge: 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
@@ -544,6 +554,7 @@
       - ^neutron/tests/functional/.*
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^neutron/agent/linux/openvswitch_firewall/.*$
       - ^neutron/agent/ovn/.*$
       - ^neutron/agent/windows/.*$
@@ -594,14 +605,6 @@
         Q_ML2_PLUGIN_TYPE_DRIVERS: local,flat,vlan,geneve
         Q_ML2_TENANT_NETWORK_TYPE: geneve
         Q_USE_PROVIDERNET_FOR_PUBLIC: true
-        # NOTE(slaweq): In the job with OVN backend we can't use Ubuntu minimal
-        # image because kernel in that image don't supports MULTICAST traffic
-        # thus multicast scenario test with IGMP snooping enabled would fail
-        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: ntp_image_384M
-        ADVANCED_INSTANCE_USER: ubuntu
-        CUSTOMIZE_IMAGE: false
         ENABLE_CHASSIS_AS_GW: true
         OVN_L3_CREATE_PUBLIC_NETWORK: true
         OVN_DBS_LOG_LEVEL: dbg
@@ -678,6 +681,7 @@
       - ^neutron/tests/functional/.*
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^neutron/agent/dhcp/.*$
       - ^neutron/agent/l2/.*$
       - ^neutron/agent/l3/.*$
@@ -742,9 +746,9 @@
         USE_PYTHON3: true
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_dvr) | join(',') }}"
         PHYSICAL_NETWORK: default
-        CIRROS_VERSION: 0.5.1
-        DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.5.1-x86_64-uec.tar.gz
+        CIRROS_VERSION: 0.6.1
+        DEFAULT_IMAGE_NAME: cirros-0.6.1-x86_64-uec
+        DEFAULT_IMAGE_FILE_NAME: cirros-0.6.1-x86_64-uec.tar.gz
         IMAGE_URLS: https://cloud-images.ubuntu.com/minimal/releases/focal/release/ubuntu-20.04-minimal-cloudimg-amd64.img
         ADVANCED_IMAGE_NAME: ubuntu-20.04-minimal-cloudimg-amd64
         ADVANCED_INSTANCE_TYPE: ntp_image_256M
@@ -803,9 +807,6 @@
               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
@@ -885,9 +886,6 @@
             $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
@@ -944,6 +942,7 @@
       - ^neutron/tests/functional/.*
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^neutron/agent/.*$
       - ^neutron/cmd/.*$
       - ^neutron/privileged/.*$
@@ -992,6 +991,11 @@
         - flow_classifier
         - sfc
       devstack_localrc:
+        # TODO(slaweq): check why traceroute output is different in Cirros >
+        # 0.6.1 which is causing failures of the networking-sfc jobs
+        CIRROS_VERSION: 0.5.1
+        DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec
+        DEFAULT_IMAGE_FILE_NAME: cirros-0.5.1-x86_64-uec.tar.gz
         Q_AGENT: openvswitch
         Q_ML2_TENANT_NETWORK_TYPE: vxlan
         Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
@@ -1014,10 +1018,13 @@
       - ^neutron/tests/fullstack/.*
       - ^neutron/tests/functional/.*
       - ^neutron_tempest_plugin/api/test_.*$
+      - ^neutron_tempest_plugin/scenario/admin/.*$
+      - ^neutron_tempest_plugin/scenario/test_.*$
       - ^neutron_tempest_plugin/(bgpvpn|fwaas|neutron_dynamic_routing|tap_as_a_service|vpnaas).*$
       - ^neutron_tempest_plugin/services/bgp/.*$
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^rally-jobs/.*$
       - ^roles/.*functional.*$
       - ^playbooks/.*functional.*$
@@ -1076,10 +1083,13 @@
       - ^neutron/tests/fullstack/.*
       - ^neutron/tests/functional/.*
       - ^neutron_tempest_plugin/api/test_.*$
+      - ^neutron_tempest_plugin/scenario/admin/.*$
+      - ^neutron_tempest_plugin/scenario/test_.*$
       - ^neutron_tempest_plugin/(fwaas|neutron_dynamic_routing|sfc|tap_as_a_service|vpnaas).*$
       - ^neutron_tempest_plugin/services/bgp/.*$
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^rally-jobs/.*$
       - ^roles/.*functional.*$
       - ^playbooks/.*functional.*$
@@ -1126,9 +1136,12 @@
       - ^neutron/tests/fullstack/.*
       - ^neutron/tests/functional/.*
       - ^neutron_tempest_plugin/api/test_.*$
+      - ^neutron_tempest_plugin/scenario/admin/.*$
+      - ^neutron_tempest_plugin/scenario/test_.*$
       - ^neutron_tempest_plugin/(bgpvpn|fwaas|sfc|tap_as_a_service|vpnaas).*$
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^rally-jobs/.*$
       - ^roles/.*functional.*$
       - ^playbooks/.*functional.*$
@@ -1185,10 +1198,13 @@
       - ^neutron/tests/fullstack/.*
       - ^neutron/tests/functional/.*
       - ^neutron_tempest_plugin/api/test_.*$
+      - ^neutron_tempest_plugin/scenario/admin/.*$
+      - ^neutron_tempest_plugin/scenario/test_.*$
       - ^neutron_tempest_plugin/(bgpvpn|neutron_dynamic_routing|sfc|tap_as_a_service|vpnaas).*$
       - ^neutron_tempest_plugin/services/bgp/.*$
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^rally-jobs/.*$
       - ^roles/.*functional.*$
       - ^playbooks/.*functional.*$
@@ -1248,10 +1264,13 @@
       - ^neutron/tests/fullstack/.*
       - ^neutron/tests/functional/.*
       - ^neutron_tempest_plugin/api/test_.*$
+      - ^neutron_tempest_plugin/scenario/admin/.*$
+      - ^neutron_tempest_plugin/scenario/test_.*$
       - ^neutron_tempest_plugin/(bgpvpn|fwaas|neutron_dynamic_routing|sfc|tap_as_a_service).*$
       - ^neutron_tempest_plugin/services/bgp/.*$
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^rally-jobs/.*$
       - ^roles/.*functional.*$
       - ^playbooks/.*functional.*$
@@ -1280,11 +1299,6 @@
         - taas-vlan-filter
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
-        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: ntp_image_384M
-        ADVANCED_INSTANCE_USER: ubuntu
-        CUSTOMIZE_IMAGE: false
         BUILD_TIMEOUT: 784
         Q_AGENT: openvswitch
         Q_ML2_TENANT_NETWORK_TYPE: vxlan,vlan
@@ -1358,10 +1372,13 @@
       - ^neutron/tests/fullstack/.*
       - ^neutron/tests/functional/.*
       - ^neutron_tempest_plugin/api/test_.*$
+      - ^neutron_tempest_plugin/scenario/admin/.*$
+      - ^neutron_tempest_plugin/scenario/test_.*$
       - ^neutron_tempest_plugin/(bgpvpn|fwaas|neutron_dynamic_routing|sfc|vpnaas).*$
       - ^neutron_tempest_plugin/services/bgp/.*$
       - ^tools/.*$
       - ^tox.ini$
+      - ^plugin.spec$
       - ^rally-jobs/.*$
       - ^roles/.*functional.*$
       - ^playbooks/.*functional.*$
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 6adf860..2347c1b 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -5,6 +5,7 @@
         - neutron-tempest-plugin-linuxbridge
         - neutron-tempest-plugin-openvswitch
         - neutron-tempest-plugin-openvswitch-iptables_hybrid
+        - neutron-tempest-plugin-openvswitch-enforce-scope-new-defaults
         - neutron-tempest-plugin-ovn
         - neutron-tempest-plugin-designate-scenario
     gate:
@@ -13,6 +14,7 @@
         - neutron-tempest-plugin-openvswitch
         - neutron-tempest-plugin-ovn
         - neutron-tempest-plugin-openvswitch-iptables_hybrid
+        - neutron-tempest-plugin-openvswitch-enforce-scope-new-defaults
     #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
     #              the experimental queue when it will be more stable
     experimental:
@@ -23,61 +25,6 @@
 
 
 - project-template:
-    name: neutron-tempest-plugin-jobs-queens
-    check:
-      jobs:
-        - neutron-tempest-plugin-api-queens
-        - neutron-tempest-plugin-scenario-linuxbridge-queens
-        - neutron-tempest-plugin-scenario-openvswitch-queens
-    gate:
-      jobs:
-        - neutron-tempest-plugin-api-queens
-    #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
-    #              the experimental queue when it will be more stable
-    experimental:
-      jobs:
-        - neutron-tempest-plugin-dvr-multinode-scenario-queens
-
-
-- project-template:
-    name: neutron-tempest-plugin-jobs-rocky
-    check:
-      jobs:
-        - neutron-tempest-plugin-api-rocky
-        - 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
-    #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
-    #              the experimental queue when it will be more stable
-    experimental:
-      jobs:
-        - neutron-tempest-plugin-dvr-multinode-scenario-rocky
-
-
-- project-template:
-    name: neutron-tempest-plugin-jobs-stein
-    check:
-      jobs:
-        - neutron-tempest-plugin-api-stein
-        - 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
-    #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
-    #              the experimental queue when it will be more stable
-    experimental:
-      jobs:
-        - neutron-tempest-plugin-dvr-multinode-scenario-stein
-
-
-- project-template:
     name: neutron-tempest-plugin-jobs-train
     check:
       jobs:
@@ -85,7 +32,6 @@
         - 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
@@ -212,45 +158,65 @@
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-zed
 
+- project-template:
+    name: neutron-tempest-plugin-jobs-2023-1
+    check:
+      jobs:
+        - neutron-tempest-plugin-linuxbridge-2023-1
+        - neutron-tempest-plugin-openvswitch-2023-1
+        - neutron-tempest-plugin-openvswitch-iptables_hybrid-2023-1
+        - neutron-tempest-plugin-ovn-2023-1
+        - neutron-tempest-plugin-designate-scenario-2023-1
+    gate:
+      jobs:
+        - neutron-tempest-plugin-ovn-2023-1
+    #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
+    #              the experimental queue when it will be more stable
+    experimental:
+      jobs:
+        - neutron-tempest-plugin-dvr-multinode-scenario-2023-1
+
 - project:
     templates:
       - build-openstack-docs-pti
       - neutron-tempest-plugin-jobs
-      - neutron-tempest-plugin-jobs-wallaby
       - neutron-tempest-plugin-jobs-xena
       - neutron-tempest-plugin-jobs-yoga
       - neutron-tempest-plugin-jobs-zed
+      - neutron-tempest-plugin-jobs-2023-1
       - check-requirements
       - tempest-plugin-jobs
       - release-notes-jobs-python3
     check:
       jobs:
         - neutron-tempest-plugin-sfc
-        - neutron-tempest-plugin-sfc-wallaby
         - neutron-tempest-plugin-sfc-xena
         - neutron-tempest-plugin-sfc-yoga
         - neutron-tempest-plugin-sfc-zed
+        - neutron-tempest-plugin-sfc-2023-1
         - neutron-tempest-plugin-bgpvpn-bagpipe
-        - neutron-tempest-plugin-bgpvpn-bagpipe-wallaby
         - neutron-tempest-plugin-bgpvpn-bagpipe-xena
         - neutron-tempest-plugin-bgpvpn-bagpipe-yoga
         - neutron-tempest-plugin-bgpvpn-bagpipe-zed
+        - neutron-tempest-plugin-bgpvpn-bagpipe-2023-1
         - neutron-tempest-plugin-dynamic-routing
-        - neutron-tempest-plugin-dynamic-routing-wallaby
         - neutron-tempest-plugin-dynamic-routing-xena
         - neutron-tempest-plugin-dynamic-routing-yoga
         - neutron-tempest-plugin-dynamic-routing-zed
+        - neutron-tempest-plugin-dynamic-routing-2023-1
         - neutron-tempest-plugin-fwaas
         - neutron-tempest-plugin-fwaas-zed
+        - neutron-tempest-plugin-fwaas-2023-1
         - neutron-tempest-plugin-vpnaas
-        - neutron-tempest-plugin-vpnaas-wallaby
         - neutron-tempest-plugin-vpnaas-xena
         - neutron-tempest-plugin-vpnaas-yoga
         - neutron-tempest-plugin-vpnaas-zed
+        - neutron-tempest-plugin-vpnaas-2023-1
         - neutron-tempest-plugin-tap-as-a-service
         - neutron-tempest-plugin-tap-as-a-service-xena
         - neutron-tempest-plugin-tap-as-a-service-yoga
         - neutron-tempest-plugin-tap-as-a-service-zed
+        - neutron-tempest-plugin-tap-as-a-service-2023-1
 
     gate:
       jobs:
diff --git a/zuul.d/queens_jobs.yaml b/zuul.d/queens_jobs.yaml
deleted file mode 100644
index 3a1c37f..0000000
--- a/zuul.d/queens_jobs.yaml
+++ /dev/null
@@ -1,280 +0,0 @@
-- job:
-    name: neutron-tempest-plugin-api-queens
-    nodeset: openstack-single-node-xenial
-    parent: neutron-tempest-plugin-base
-    override-checkout: stable/queens
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.3.0
-      - 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
-        # Neutron services
-        q-agt: true
-        q-dhcp: true
-        q-l3: true
-        q-meta: true
-        q-metering: true
-      branch_override: stable/queens
-      tempest_concurrency: 4
-      tempest_test_regex: ^neutron_tempest_plugin\.api
-      # TODO(slaweq): find a way to put this list of extensions in
-      # neutron repository and keep it different per branch,
-      # then it could be removed from here
-      network_api_extensions_common: &api_extensions
-        - address-scope
-        - agent
-        - allowed-address-pairs
-        - auto-allocated-topology
-        - availability_zone
-        - binding
-        - default-subnetpools
-        - dhcp_agent_scheduler
-        - dns-domain-ports
-        - dns-integration
-        - ext-gw-mode
-        - external-net
-        - extra_dhcp_opt
-        - extraroute
-        - flavors
-        - ip-substring-filtering
-        - l3-flavors
-        - l3-ha
-        - l3_agent_scheduler
-        - logging
-        - metering
-        - multi-provider
-        - net-mtu
-        - net-mtu-writable
-        - network-ip-availability
-        - network_availability_zone
-        - pagination
-        - port-security
-        - project-id
-        - provider
-        - qos
-        - qos-fip
-        - quotas
-        - quota_details
-        - rbac-policies
-        - router
-        - router_availability_zone
-        - security-group
-        - segment
-        - service-type
-        - sorting
-        - standard-attr-description
-        - standard-attr-revisions
-        - standard-attr-timestamp
-        - standard-attr-tag
-        - subnet_allocation
-        - subnet-service-types
-        - trunk
-        - trunk-details
-      network_api_extensions_tempest:
-        - dvr
-      network_available_features: &available_features
-        -
-      devstack_localrc:
-        NEUTRON_DEPLOY_MOD_WSGI: false
-        USE_PYTHON3: false
-        CIRROS_VERSION: 0.3.5
-        DEFAULT_IMAGE_NAME: cirros-0.3.5-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.3.5-x86_64-uec.tar.gz
-        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
-        TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        Q_AGENT: openvswitch
-        Q_ML2_TENANT_NETWORK_TYPE: vxlan
-        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
-        ML2_L3_PLUGIN: router
-      devstack_local_conf:
-        post-config:
-          # 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: gre,vxlan
-            ml2:
-              type_drivers: flat,geneve,vlan,gre,local,vxlan
-        test-config:
-          $TEMPEST_CONFIG:
-            neutron_plugin_options:
-              available_type_drivers: flat,geneve,vlan,gre,local,vxlan
-
-
-
-- job:
-    name: neutron-tempest-plugin-scenario-openvswitch-queens
-    parent: neutron-tempest-plugin-openvswitch
-    nodeset: openstack-single-node-xenial
-    override-checkout: stable/queens
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.3.0
-      - openstack/tempest
-    vars:
-      branch_override: stable/queens
-      tempest_test_regex: "\
-          (^neutron_tempest_plugin.scenario)|\
-          (^tempest.api.compute.servers.test_attach_interfaces)|\
-          (^tempest.api.compute.servers.test_multiple_create)"
-      network_api_extensions: *api_extensions
-      network_available_features: *available_features
-      devstack_local_conf:
-        post-config:
-          $NEUTRON_L3_CONF:
-            DEFAULT:
-              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
-              keepalived_use_no_track: False
-      # TODO(slaweq): remove trunks subport_connectivity test from blacklist
-      # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
-      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
-      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
-      tempest_black_regex: "\
-          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
-          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
-      devstack_localrc:
-        USE_PYTHON3: false
-        CIRROS_VERSION: 0.3.5
-        DEFAULT_IMAGE_NAME: cirros-0.3.5-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.3.5-x86_64-uec.tar.gz
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
-        TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        # NOTE(slaweq) some tests are not running fine with ubuntu minimal on
-        # Queens
-        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
-        CUSTOMIZE_IMAGE: false
-
-- job:
-    name: neutron-tempest-plugin-scenario-linuxbridge-queens
-    parent: neutron-tempest-plugin-base
-    nodeset: openstack-single-node-xenial
-    timeout: 10000
-    roles:
-      - zuul: openstack/neutron
-    override-checkout: stable/queens
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.3.0
-      - openstack/tempest
-    vars:
-      branch_override: stable/queens
-      tempest_test_regex: "\
-          (^neutron_tempest_plugin.scenario)|\
-          (^tempest.api.compute.servers.test_attach_interfaces)|\
-          (^tempest.api.compute.servers.test_multiple_create)"
-      network_api_extensions: *api_extensions
-      network_available_features: *available_features
-      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
-      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
-      tempest_black_regex: "\
-          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
-      devstack_localrc:
-        USE_PYTHON3: false
-        CIRROS_VERSION: 0.3.5
-        DEFAULT_IMAGE_NAME: cirros-0.3.5-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.3.5-x86_64-uec.tar.gz
-        Q_AGENT: linuxbridge
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
-        TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        # NOTE(slaweq) some tests are not running fine with ubuntu minimal on
-        # Queens
-        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
-        CUSTOMIZE_IMAGE: false
-      devstack_local_conf:
-        post-config:
-          $NEUTRON_CONF:
-            DEFAULT:
-              enable_dvr: false
-            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
-          $NEUTRON_L3_CONF:
-            DEFAULT:
-              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
-              keepalived_use_no_track: False
-        test-config:
-          # NOTE: ignores linux bridge's trunk delete on bound port test
-          # for rocky branch (as https://review.opendev.org/#/c/605589/
-          # fix will not apply for rocky branch)
-          $TEMPEST_CONFIG:
-            neutron_plugin_options:
-              available_type_drivers: flat,vlan,local,vxlan
-              q_agent: None
-
-- job:
-    name: neutron-tempest-plugin-dvr-multinode-scenario-queens
-    parent: neutron-tempest-plugin-dvr-multinode-scenario
-    nodeset: openstack-two-node-xenial
-    override-checkout: stable/queens
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.3.0
-      - openstack/tempest
-    vars:
-      branch_override: stable/queens
-      network_api_extensions_common: *api_extensions
-      # TODO(slaweq): remove trunks subport_connectivity test from blacklist
-      # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
-      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
-      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
-      tempest_black_regex: "\
-          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
-          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
-      devstack_localrc:
-        USE_PYTHON3: false
-        CIRROS_VERSION: 0.3.5
-        DEFAULT_IMAGE_NAME: cirros-0.3.5-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.3.5-x86_64-uec.tar.gz
-        TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-
-- job:
-    name: neutron-tempest-plugin-designate-scenario-queens
-    parent: neutron-tempest-plugin-designate-scenario
-    nodeset: openstack-single-node-xenial
-    override-checkout: stable/queens
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.3.0
-      - name: openstack/designate-tempest-plugin
-        override-checkout: 0.7.0
-      - openstack/tempest
-    vars:
-      branch_override: stable/queens
-      network_api_extensions_common: *api_extensions
-      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
-      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
-      tempest_black_regex: "\
-          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
-      devstack_localrc:
-        USE_PYTHON3: false
-        CIRROS_VERSION: 0.3.5
-        DEFAULT_IMAGE_NAME: cirros-0.3.5-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.3.5-x86_64-uec.tar.gz
-        TEMPEST_PLUGINS: '"/opt/stack/designate-tempest-plugin /opt/stack/neutron-tempest-plugin"'
-        ADVANCED_INSTANCE_TYPE: ds512M
diff --git a/zuul.d/rocky_jobs.yaml b/zuul.d/rocky_jobs.yaml
deleted file mode 100644
index 75d7098..0000000
--- a/zuul.d/rocky_jobs.yaml
+++ /dev/null
@@ -1,672 +0,0 @@
-- job:
-    name: neutron-tempest-plugin-api-rocky
-    nodeset: openstack-single-node-xenial
-    parent: neutron-tempest-plugin-base
-    description: |
-      This job run on py2 for stable/rocky gate.
-    override-checkout: stable/rocky
-    required-projects: &required-projects-rocky
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.9.0
-      - openstack/tempest
-    vars: &api_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
-      tempest_concurrency: 4
-      tempest_test_regex: ^neutron_tempest_plugin\.api
-      # TODO(slaweq): find a way to put this list of extensions in
-      # neutron repository and keep it different per branch,
-      # then it could be removed from here
-      network_api_extensions_common: &api_extensions
-        - address-scope
-        - agent
-        - allowed-address-pairs
-        - auto-allocated-topology
-        - availability_zone
-        - binding
-        - default-subnetpools
-        - dhcp_agent_scheduler
-        - dns-domain-ports
-        - dns-integration
-        - empty-string-filtering
-        - expose-port-forwarding-in-fip
-        - ext-gw-mode
-        - external-net
-        - extra_dhcp_opt
-        - extraroute
-        - fip-port-details
-        - flavors
-        - floating-ip-port-forwarding
-        - ip-substring-filtering
-        - l3-flavors
-        - l3-ha
-        - l3_agent_scheduler
-        - logging
-        - metering
-        - multi-provider
-        - net-mtu
-        - net-mtu-writable
-        - network-ip-availability
-        - network_availability_zone
-        - pagination
-        - port-mac-address-regenerate
-        - port-security
-        - port-security-groups-filtering
-        - project-id
-        - provider
-        - qos
-        - qos-fip
-        - quotas
-        - quota_details
-        - rbac-policies
-        - router
-        - router_availability_zone
-        - security-group
-        - segment
-        - service-type
-        - sorting
-        - standard-attr-description
-        - standard-attr-revisions
-        - standard-attr-segment
-        - standard-attr-timestamp
-        - standard-attr-tag
-        - subnet_allocation
-        - subnet-service-types
-        - trunk
-        - trunk-details
-      network_api_extensions_tempest:
-        - dvr
-      devstack_localrc:
-        NEUTRON_DEPLOY_MOD_WSGI: false
-        USE_PYTHON3: false
-        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
-        TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        Q_AGENT: openvswitch
-        Q_ML2_TENANT_NETWORK_TYPE: vxlan
-        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
-        ML2_L3_PLUGIN: router
-      devstack_local_conf:
-        post-config:
-          # 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: gre,vxlan
-            ml2:
-              type_drivers: flat,geneve,vlan,gre,local,vxlan
-        test-config:
-          $TEMPEST_CONFIG:
-            neutron_plugin_options:
-              available_type_drivers: flat,geneve,vlan,gre,local,vxlan
-    # NOTE(gmann): This job run on py2 for stable/rocky gate.
-    branches:
-      - stable/rocky
-
-- job:
-    name: neutron-tempest-plugin-api-rocky
-    nodeset: openstack-single-node-xenial
-    parent: neutron-tempest-plugin-base
-    description: |
-      This job run on py3 for other than stable/rocky gate
-      which is nothing but neutron-tempest-pluign master gate.
-    override-checkout: stable/rocky
-    required-projects: *required-projects-rocky
-    vars:
-      <<: *api_vars_rocky
-      devstack_localrc:
-        USE_PYTHON3: True
-    branches: ^(?!stable/rocky).*$
-
-- job:
-    name: neutron-tempest-plugin-scenario-openvswitch-rocky
-    parent: neutron-tempest-plugin-base
-    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
-      tempest_test_regex: "\
-          (^neutron_tempest_plugin.scenario)|\
-          (^tempest.api.compute.servers.test_attach_interfaces)|\
-          (^tempest.api.compute.servers.test_multiple_create)"
-      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
-        # NOTE(slaweq) some tests are not running fine with ubuntu minimal on
-        # Rocky
-        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
-        CUSTOMIZE_IMAGE: false
-      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
-        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
-      # NOTE(bcafarel): filtering out unstable tests or tests with known
-      # issues in the used pinned version for this EM branch
-      tempest_black_regex: &rocky_tempest_exclude "\
-          (^neutron_tempest_plugin.scenario.admin.test_floatingip.FloatingIpTestCasesAdmin.test_two_vms_fips)|\
-          (^neutron_tempest_plugin.scenario.test_floatingip.FloatingIPQosTest.test_qos)|\
-          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)|\
-          (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
-          (^neutron_tempest_plugin.scenario.test_ports.PortsTest.test_previously_used_port)|\
-          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_ip_prefix)|\
-          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)|\
-          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_secgroup_inheritance)|\
-          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_remote_group)|\
-          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
-          (^tempest.api.compute.servers.test_attach_interfaces.AttachInterfacesTestJSON.test_reassign_port_between_servers)|\
-          (^tempest.api.compute.servers.test_attach_interfaces.AttachInterfacesUnderV243Test.test_add_remove_fixed_ip)"
-    branches:
-      - stable/rocky
-    irrelevant-files: &openvswitch-scenario-irrelevant-files
-      - ^(test-|)requirements.txt$
-      - ^releasenotes/.*$
-      - ^doc/.*$
-      - ^setup.cfg$
-      - ^.*\.rst$
-      - ^neutron/locale/.*$
-      - ^neutron/tests/unit/.*$
-      - ^neutron/tests/fullstack/.*
-      - ^neutron/tests/functional/.*
-      - ^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
-    parent: neutron-tempest-plugin-openvswitch
-    nodeset: openstack-single-node-xenial
-    description: |
-      This job run on py3 for other than stable/rocky gate
-      which is nothing but neutron-tempest-pluign master gate.
-    override-checkout: stable/rocky
-    required-projects: *required-projects-rocky
-    vars:
-      <<: *scenario_vars_rocky
-      devstack_localrc:
-        USE_PYTHON3: True
-        ADVANCED_INSTANCE_TYPE: ds512M
-    branches: ^(?!stable/rocky).*$
-    irrelevant-files: *openvswitch-scenario-irrelevant-files
-
-- job:
-    name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-rocky
-    parent: neutron-tempest-plugin-base
-    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
-      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
-        # NOTE(slaweq) some tests are not running fine with ubuntu minimal on
-        # Rocky
-        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
-        CUSTOMIZE_IMAGE: false
-      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
-      tempest_black_regex: *rocky_tempest_exclude
-    branches:
-      - stable/rocky
-    irrelevant-files: &iptables_hybrid_irrelevant_files
-      - ^(test-|)requirements.txt$
-      - ^releasenotes/.*$
-      - ^doc/.*$
-      - ^setup.cfg$
-      - ^.*\.rst$
-      - ^neutron/locale/.*$
-      - ^neutron/tests/unit/.*$
-      - ^neutron/tests/fullstack/.*
-      - ^neutron/tests/functional/.*
-      - ^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-base
-    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.
-    override-checkout: stable/rocky
-    required-projects: *required-projects-rocky
-    vars:
-      <<: *openvswitch_vars_rocky
-      devstack_localrc:
-        USE_PYTHON3: True
-        ADVANCED_INSTANCE_TYPE: ds512M
-    branches: ^(?!stable/rocky).*$
-    irrelevant-files: *iptables_hybrid_irrelevant_files
-
-- job:
-    name: neutron-tempest-plugin-scenario-linuxbridge-rocky
-    parent: neutron-tempest-plugin-base
-    timeout: 10000
-    description: |
-      This job run on py2 for stable/rocky gate.
-    nodeset: openstack-single-node-xenial
-    roles:
-      - zuul: openstack/neutron
-    override-checkout: stable/rocky
-    required-projects: *required-projects-rocky
-    vars: &linuxbridge_vars_rocky
-      branch_override: stable/rocky
-      tempest_test_regex: "\
-          (^neutron_tempest_plugin.scenario)|\
-          (^tempest.api.compute.servers.test_attach_interfaces)|\
-          (^tempest.api.compute.servers.test_multiple_create)"
-      network_api_extensions: *api_extensions
-      devstack_localrc:
-        USE_PYTHON3: false
-        Q_AGENT: linuxbridge
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
-        TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        # NOTE(slaweq) some tests are not running fine with ubuntu minimal on
-        # Rocky
-        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
-        CUSTOMIZE_IMAGE: false
-      devstack_local_conf:
-        post-config:
-          $NEUTRON_CONF:
-            DEFAULT:
-              enable_dvr: false
-            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
-          $NEUTRON_L3_CONF:
-            DEFAULT:
-              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
-              keepalived_use_no_track: False
-        test-config:
-          # NOTE: ignores linux bridge's trunk delete on bound port test
-          # for rocky branch (as https://review.opendev.org/#/c/605589/
-          # fix will not apply for rocky branch)
-          $TEMPEST_CONFIG:
-            neutron_plugin_options:
-              available_type_drivers: flat,vlan,local,vxlan
-              q_agent: None
-      tempest_black_regex: *rocky_tempest_exclude
-    branches:
-      - stable/rocky
-
-- job:
-    name: neutron-tempest-plugin-scenario-linuxbridge-rocky
-    parent: neutron-tempest-plugin-base
-    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.
-    roles:
-      - zuul: openstack/neutron
-    override-checkout: stable/rocky
-    required-projects: *required-projects-rocky
-    vars:
-      <<: *linuxbridge_vars_rocky
-      devstack_localrc:
-        USE_PYTHON3: True
-        Q_AGENT: linuxbridge
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
-        TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        ADVANCED_INSTANCE_TYPE: ds512M
-    branches: ^(?!stable/rocky).*$
-
-- job:
-    name: neutron-tempest-plugin-dvr-multinode-scenario-rocky
-    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
-      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
-        DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec
-        DEFAULT_IMAGE_FILE_NAME: cirros-0.5.1-x86_64-uec.tar.gz
-        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
-      tempest_black_regex: *rocky_tempest_exclude
-    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: tempest-multinode-full
-    nodeset: openstack-two-node-xenial
-    description: |
-      This job run on py3 for other than stable/rocky gate
-      which is nothing but neutron-tempest-pluign master gate.
-    override-checkout: stable/rocky
-    vars:
-      <<: *multinode_scenario_vars_rocky
-      devstack_localrc:
-        USE_PYTHON3: True
-    required-projects: *required-projects-rocky
-    group-vars:
-      <<: *multinode_scenario_group_vars_rocky
-      subnode:
-        devstack_localrc:
-          USE_PYTHON3: True
-    branches: ^(?!stable/rocky).*$
-
-- job:
-    name: neutron-tempest-plugin-designate-scenario-rocky
-    parent: neutron-tempest-plugin-designate-scenario
-    description: |
-      This job run on py2 for stable/rocky gate.
-    nodeset: openstack-single-node-xenial
-    override-checkout: stable/rocky
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.9.0
-      - name: openstack/designate-tempest-plugin
-        override-checkout: 0.7.0
-      - openstack/tempest
-    vars: &designate_scenario_vars_rocky
-      branch_override: stable/rocky
-      network_api_extensions_common: *api_extensions
-      devstack_localrc:
-        USE_PYTHON3: false
-        TEMPEST_PLUGINS: '"/opt/stack/designate-tempest-plugin /opt/stack/neutron-tempest-plugin"'
-        ADVANCED_INSTANCE_TYPE: ds512M
-      # NOTE(bcafarel): filtering out unstable tests or tests with known
-      # issues in the used pinned version for this EM branch
-      tempest_black_regex: "(^neutron_tempest_plugin.scenario.test_dns_integration.DNSIntegrationAdminTests.test_port_on_special_network)"
-    branches:
-      - stable/rocky
-
-- job:
-    name: neutron-tempest-plugin-designate-scenario-rocky
-    parent: neutron-tempest-plugin-designate-scenario
-    nodeset: openstack-single-node-xenial
-    description: |
-      This job run on py3 for other than stable/rocky gate
-      which is nothing but neutron-tempest-plugin master gate.
-    override-checkout: stable/rocky
-    required-projects: *required-projects-rocky
-    vars:
-      <<: *designate_scenario_vars_rocky
-      devstack_localrc:
-        USE_PYTHON3: True
-    branches: ^(?!stable/rocky).*$
diff --git a/zuul.d/stein_jobs.yaml b/zuul.d/stein_jobs.yaml
deleted file mode 100644
index 0f18a8a..0000000
--- a/zuul.d/stein_jobs.yaml
+++ /dev/null
@@ -1,389 +0,0 @@
-- job:
-    name: neutron-tempest-plugin-api-stein
-    parent: neutron-tempest-plugin-base
-    nodeset: openstack-single-node-bionic
-    override-checkout: stable/stein
-    required-projects: &required-projects-stein
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 1.1.0
-      - 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
-        # Neutron services
-        q-agt: true
-        q-dhcp: true
-        q-l3: true
-        q-meta: true
-        q-metering: true
-      branch_override: stable/stein
-      tempest_concurrency: 4
-      tempest_test_regex: ^neutron_tempest_plugin\.api
-      # TODO(slaweq): find a way to put this list of extensions in
-      # neutron repository and keep it different per branch,
-      # then it could be removed from here
-      network_api_extensions_common: &api_extensions
-        - address-scope
-        - agent
-        - allowed-address-pairs
-        - auto-allocated-topology
-        - availability_zone
-        - binding
-        - default-subnetpools
-        - dhcp_agent_scheduler
-        - dns-domain-ports
-        - dns-integration
-        - empty-string-filtering
-        - expose-port-forwarding-in-fip
-        - ext-gw-mode
-        - external-net
-        - extra_dhcp_opt
-        - extraroute
-        - filter-validation
-        - fip-port-details
-        - flavors
-        - floatingip-pools
-        - floating-ip-port-forwarding
-        - ip-substring-filtering
-        - l3-flavors
-        - l3-ha
-        - l3_agent_scheduler
-        - logging
-        - metering
-        - multi-provider
-        - net-mtu
-        - net-mtu-writable
-        - network-ip-availability
-        - network_availability_zone
-        - network-segment-range
-        - pagination
-        - port-resource-request
-        - port-mac-address-regenerate
-        - port-security
-        - port-security-groups-filtering
-        - project-id
-        - provider
-        - qos
-        - qos-bw-minimum-ingress
-        - qos-fip
-        - quotas
-        - quota_details
-        - rbac-policies
-        - rbac-security-groups
-        - router
-        - router_availability_zone
-        - security-group
-        - segment
-        - service-type
-        - sorting
-        - standard-attr-description
-        - standard-attr-revisions
-        - standard-attr-segment
-        - standard-attr-tag
-        - standard-attr-timestamp
-        - subnet_allocation
-        - subnet-service-types
-        - trunk
-        - trunk-details
-        - uplink-status-propagation
-      network_api_extensions_tempest:
-        - dvr
-      network_available_features: &available_features
-        -
-      # NOTE(bcafarel): filtering out unstable tests or tests with known
-      # issues in the used pinned version for this EM branch
-      tempest_black_regex: &stein_tempest_exclude "\
-          (^neutron_tempest_plugin.scenario.test_mtu.NetworkWritableMtuTest.test_connectivity_min_max_mtu)|\
-          (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
-          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_parent_port_connectivity_after_trunk_deleted_lb)|\
-          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
-          (^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)"
-      devstack_localrc:
-        NEUTRON_DEPLOY_MOD_WSGI: false
-        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
-        Q_AGENT: openvswitch
-        Q_ML2_TENANT_NETWORK_TYPE: vxlan
-        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
-        ML2_L3_PLUGIN: router
-        ADVANCED_INSTANCE_TYPE: ds512M
-        ADVANCED_INSTANCE_USER: ubuntu
-      devstack_local_conf:
-        post-config:
-          # 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: gre,vxlan
-            ml2:
-              type_drivers: flat,geneve,vlan,gre,local,vxlan
-        test-config:
-          $TEMPEST_CONFIG:
-            neutron_plugin_options:
-              available_type_drivers: flat,geneve,vlan,gre,local,vxlan
-
-- job:
-    name: neutron-tempest-plugin-scenario-openvswitch-stein
-    parent: neutron-tempest-plugin-openvswitch
-    nodeset: openstack-single-node-bionic
-    override-checkout: stable/stein
-    required-projects: *required-projects-stein
-    vars:
-      branch_override: stable/stein
-      tempest_test_regex: "\
-          (^neutron_tempest_plugin.scenario)|\
-          (^tempest.api.compute.servers.test_attach_interfaces)|\
-          (^tempest.api.compute.servers.test_multiple_create)"
-      network_api_extensions: *api_extensions
-      network_available_features: *available_features
-      tempest_black_regex: *stein_tempest_exclude
-      devstack_localrc:
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
-        # NOTE(bcafarel) guestmount binary not available on host OS
-        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
-        CUSTOMIZE_IMAGE: false
-      devstack_local_conf:
-        post-config:
-          $NEUTRON_L3_CONF:
-            DEFAULT:
-              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
-              keepalived_use_no_track: False
-        test-config:
-          $TEMPEST_CONFIG:
-            network-feature-enabled:
-              available_features: ""
-            neutron_plugin_options:
-              ipv6_metadata: False
-
-- job:
-    name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-stein
-    parent: neutron-tempest-plugin-base
-    nodeset: openstack-single-node-bionic
-    timeout: 10000
-    override-checkout: stable/stein
-    required-projects: *required-projects-stein
-    vars:
-      branch_override: stable/stein
-      tempest_test_regex: "\
-          (^neutron_tempest_plugin.scenario)|\
-          (^tempest.api.compute.servers.test_attach_interfaces)|\
-          (^tempest.api.compute.servers.test_multiple_create)"
-      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
-      tempest_black_regex: *stein_tempest_exclude
-      devstack_localrc:
-        Q_AGENT: openvswitch
-        Q_ML2_TENANT_NETWORK_TYPE: vxlan
-        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
-        # NOTE(bcafarel) guestmount binary not available on host OS
-        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
-        CUSTOMIZE_IMAGE: false
-      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
-              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
-              ipv6_metadata: False
-    irrelevant-files:
-      - ^(test-|)requirements.txt$
-      - ^releasenotes/.*$
-      - ^doc/.*$
-      - ^setup.cfg$
-      - ^.*\.rst$
-      - ^neutron/locale/.*$
-      - ^neutron/tests/unit/.*$
-      - ^neutron/tests/fullstack/.*
-      - ^neutron/tests/functional/.*
-      - ^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-base
-    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
-      tempest_test_regex: "\
-          (^neutron_tempest_plugin.scenario)|\
-          (^tempest.api.compute.servers.test_attach_interfaces)|\
-          (^tempest.api.compute.servers.test_multiple_create)"
-      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
-        # SG logging isn't supported by linuxbridge backend
-        neutron-log: false
-      network_api_extensions: *api_extensions
-      network_api_extensions_linuxbridge:
-        - vlan-transparent
-      network_available_features: *available_features
-      tempest_black_regex: *stein_tempest_exclude
-      devstack_localrc:
-        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
-        # NOTE(bcafarel) guestmount binary not available on host OS
-        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
-        CUSTOMIZE_IMAGE: false
-      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
-              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
-              q_agent: linuxbridge
-              firewall_driver: iptables
-              ipv6_metadata: False
-    irrelevant-files:
-      - ^(test-|)requirements.txt$
-      - ^releasenotes/.*$
-      - ^doc/.*$
-      - ^setup.cfg$
-      - ^.*\.rst$
-      - ^neutron/locale/.*$
-      - ^neutron/tests/unit/.*$
-      - ^neutron/tests/fullstack/.*
-      - ^neutron/tests/functional/.*
-      - ^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
-    parent: neutron-tempest-plugin-dvr-multinode-scenario
-    nodeset: openstack-two-node-bionic
-    override-checkout: stable/stein
-    required-projects: *required-projects-stein
-    vars:
-      network_api_extensions_common: *api_extensions
-      branch_override: stable/stein
-
-- job:
-    name: neutron-tempest-plugin-designate-scenario-stein
-    parent: neutron-tempest-plugin-designate-scenario
-    nodeset: openstack-single-node-bionic
-    override-checkout: stable/stein
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 1.3.0
-      - name: openstack/designate-tempest-plugin
-        override-checkout: 0.7.0
-      - openstack/tempest
-    vars:
-      branch_override: stable/stein
-      network_api_extensions_common: *api_extensions
-      devstack_localrc:
-        # NOTE(bcafarel) guestmount binary not available on host OS
-        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
-        CUSTOMIZE_IMAGE: false
diff --git a/zuul.d/train_jobs.yaml b/zuul.d/train_jobs.yaml
index c8c2efe..159feb2 100644
--- a/zuul.d/train_jobs.yaml
+++ b/zuul.d/train_jobs.yaml
@@ -24,7 +24,6 @@
         q-l3: true
         q-meta: true
         q-metering: true
-      branch_override: stable/train
       tempest_concurrency: 4
       tempest_test_regex: ^neutron_tempest_plugin\.api
       # TODO(slaweq): find a way to put this list of extensions in
@@ -118,9 +117,6 @@
         ML2_L3_PLUGIN: router
       devstack_local_conf:
         post-config:
-          # 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: gre,vxlan
@@ -138,7 +134,6 @@
     override-checkout: stable/train
     required-projects: *required-projects-train
     vars:
-      branch_override: stable/train
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -173,7 +168,6 @@
     override-checkout: stable/train
     required-projects: *required-projects-train
     vars:
-      branch_override: stable/train
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -208,7 +202,6 @@
     override-checkout: stable/train
     required-projects: *required-projects-train
     vars:
-      branch_override: stable/train
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -244,30 +237,6 @@
     required-projects: *required-projects-train
     vars:
       network_api_extensions_common: *api_extensions
-      branch_override: stable/train
-
-- job:
-    name: neutron-tempest-plugin-designate-scenario-train
-    parent: neutron-tempest-plugin-designate-scenario
-    nodeset: openstack-single-node-bionic
-    override-checkout: stable/train
-    required-projects:
-      - openstack/neutron
-      - name: openstack/neutron-tempest-plugin
-        override-checkout: 1.5.0
-      - openstack/tempest
-      - name: openstack/designate-tempest-plugin
-        override-checkout: 0.7.0
-    vars:
-      branch_override: stable/train
-      network_api_extensions_common: *api_extensions
-      devstack_localrc:
-        # NOTE(bcafarel) guestmount binary not available on host OS
-        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
-        CUSTOMIZE_IMAGE: false
 
 - job:
     name: neutron-tempest-plugin-sfc-train
@@ -276,7 +245,6 @@
     override-checkout: stable/train
     required-projects: *required-projects-train
     vars:
-      branch_override: stable/train
       network_api_extensions_common: *api_extensions
 
 - job:
@@ -286,7 +254,6 @@
     override-checkout: stable/train
     required-projects: *required-projects-train
     vars:
-      branch_override: stable/train
       network_api_extensions: *api_extensions
 
 - job:
@@ -296,5 +263,4 @@
     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 56da160..5abc741 100644
--- a/zuul.d/ussuri_jobs.yaml
+++ b/zuul.d/ussuri_jobs.yaml
@@ -24,7 +24,6 @@
         q-l3: true
         q-meta: true
         q-metering: true
-      branch_override: stable/ussuri
       tempest_concurrency: 4
       tempest_test_regex: ^neutron_tempest_plugin\.api
       # TODO(slaweq): find a way to put this list of extensions in
@@ -122,9 +121,6 @@
         CUSTOMIZE_IMAGE: false
       devstack_local_conf:
         post-config:
-          # 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: gre,vxlan
@@ -143,15 +139,20 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
           (^tempest.api.compute.servers.test_multiple_create)"
       network_api_extensions: *api_extensions
       network_available_features: *available_features
-      devstack_localrc:
+      devstack_localrc: &localrc_scenarios_common
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+        # NOTE(bcafarel) guestmount binary not available on host OS
+        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
+        CUSTOMIZE_IMAGE: false
       devstack_local_conf:
         post-config:
           $NEUTRON_L3_CONF:
@@ -173,15 +174,17 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
           (^tempest.api.compute.servers.test_multiple_create)"
       network_api_extensions: *api_extensions
       network_available_features: *available_features
-      devstack_localrc:
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+      # 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_security_groups.NetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
+      devstack_localrc: *localrc_scenarios_common
       devstack_local_conf:
         post-config:
           $NEUTRON_L3_CONF:
@@ -202,15 +205,13 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
           (^tempest.api.compute.servers.test_multiple_create)"
       network_api_extensions: *api_extensions
       network_available_features: *available_features
-      devstack_localrc:
-        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+      devstack_localrc: *localrc_scenarios_common
       devstack_local_conf:
         post-config:
           $NEUTRON_L3_CONF:
@@ -231,7 +232,6 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -259,6 +259,12 @@
         OVN_BRANCH: "v20.03.0"
         # NOTE(slaweq): IGMP Snooping requires OVN 20.12
         OVN_IGMP_SNOOPING_ENABLE: False
+        # NOTE(bcafarel) guestmount binary not available on host OS
+        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
+        CUSTOMIZE_IMAGE: false
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
@@ -273,7 +279,6 @@
     required-projects: *required-projects-ussuri
     vars:
       network_api_extensions_common: *api_extensions
-      branch_override: stable/ussuri
 
 - job:
     name: neutron-tempest-plugin-designate-scenario-ussuri
@@ -285,10 +290,11 @@
       - name: openstack/neutron-tempest-plugin
         override-checkout: 1.6.0
       - openstack/tempest
-      - openstack/designate-tempest-plugin
+      - name: openstack/designate-tempest-plugin
+        override-checkout: 0.7.0
     vars:
-      branch_override: stable/ussuri
-      network_api_extensions_common: *api_extensions
+      network_api_extensions: *api_extensions
+      devstack_localrc: *localrc_scenarios_common
 
 - job:
     name: neutron-tempest-plugin-sfc-ussuri
@@ -297,7 +303,6 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       network_api_extensions_common: *api_extensions
 
 - job:
@@ -307,7 +312,6 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       network_api_extensions: *api_extensions
 
 - job:
@@ -323,7 +327,6 @@
         override-checkout: 1.6.0
       - openstack/tempest
     vars:
-      branch_override: stable/ussuri
       tempest_test_regex: ^neutron_tempest_plugin\.fwaas
       devstack_plugins:
         neutron-fwaas: https://opendev.org/openstack/neutron-fwaas.git
@@ -341,7 +344,6 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       network_api_extensions_common: *api_extensions
 
 - job:
@@ -351,5 +353,4 @@
     override-checkout: stable/ussuri
     required-projects: *required-projects-ussuri
     vars:
-      branch_override: stable/ussuri
       network_api_extensions_common: *api_extensions
diff --git a/zuul.d/victoria_jobs.yaml b/zuul.d/victoria_jobs.yaml
index 7a92403..cfca0ea 100644
--- a/zuul.d/victoria_jobs.yaml
+++ b/zuul.d/victoria_jobs.yaml
@@ -1,6 +1,7 @@
 - job:
     name: neutron-tempest-plugin-api-victoria
     parent: neutron-tempest-plugin-base
+    nodeset: openstack-single-node-focal
     override-checkout: stable/victoria
     required-projects: &required-projects-victoria
       - openstack/neutron
@@ -23,7 +24,6 @@
         q-l3: true
         q-meta: true
         q-metering: true
-      branch_override: stable/victoria
       tempest_concurrency: 4
       tempest_test_regex: ^neutron_tempest_plugin\.api
       # TODO(slaweq): find a way to put this list of extensions in
@@ -121,9 +121,6 @@
         CUSTOMIZE_IMAGE: false
       devstack_local_conf:
         post-config:
-          # 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: gre,vxlan
@@ -140,7 +137,6 @@
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -169,13 +165,16 @@
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
           (^tempest.api.compute.servers.test_multiple_create)"
       network_api_extensions: *api_extensions
       network_available_features: *available_features
+      # 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_security_groups.NetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         # NOTE(bcafarel) guestmount binary not available on host OS
@@ -198,7 +197,6 @@
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -227,7 +225,6 @@
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -250,11 +247,11 @@
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-victoria
     parent: neutron-tempest-plugin-dvr-multinode-scenario
+    nodeset: openstack-two-node-focal
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
       network_api_extensions_common: *api_extensions
-      branch_override: stable/victoria
 
 - job:
     name: neutron-tempest-plugin-designate-scenario-victoria
@@ -268,7 +265,6 @@
       - name: openstack/designate-tempest-plugin
         override-checkout: 0.12.0
     vars:
-      branch_override: stable/victoria
       network_api_extensions_common: *api_extensions
       devstack_localrc:
         # NOTE(bcafarel) guestmount binary not available on host OS
@@ -281,35 +277,35 @@
 - job:
     name: neutron-tempest-plugin-sfc-victoria
     parent: neutron-tempest-plugin-sfc
+    nodeset: openstack-single-node-focal
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-bgpvpn-bagpipe-victoria
     parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    nodeset: openstack-single-node-focal
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       network_api_extensions: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-dynamic-routing-victoria
     parent: neutron-tempest-plugin-dynamic-routing
+    nodeset: openstack-single-node-focal
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-vpnaas-victoria
     parent: neutron-tempest-plugin-vpnaas
+    nodeset: openstack-single-node-focal
     override-checkout: stable/victoria
     required-projects: *required-projects-victoria
     vars:
-      branch_override: stable/victoria
       network_api_extensions_common: *api_extensions
diff --git a/zuul.d/wallaby_jobs.yaml b/zuul.d/wallaby_jobs.yaml
index a3c07c0..9fce55b 100644
--- a/zuul.d/wallaby_jobs.yaml
+++ b/zuul.d/wallaby_jobs.yaml
@@ -1,7 +1,13 @@
 - job:
     name: neutron-tempest-plugin-api-wallaby
     parent: neutron-tempest-plugin-base
+    nodeset: openstack-single-node-focal
     override-checkout: stable/wallaby
+    required-projects: &required-projects-wallaby
+      - openstack/neutron
+      - name: openstack/neutron-tempest-plugin
+        override-checkout: 1.8.0
+      - openstack/tempest
     vars:
       tempest_concurrency: 4
       tempest_test_regex: ^neutron_tempest_plugin\.api
@@ -93,8 +99,8 @@
     name: neutron-tempest-plugin-scenario-openvswitch-wallaby
     parent: neutron-tempest-plugin-openvswitch
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -113,14 +119,21 @@
     name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-wallaby
     parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
           (^tempest.api.compute.servers.test_multiple_create)"
       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
+      # 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:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
@@ -133,8 +146,8 @@
     name: neutron-tempest-plugin-scenario-linuxbridge-wallaby
     parent: neutron-tempest-plugin-linuxbridge
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -153,8 +166,8 @@
     name: neutron-tempest-plugin-scenario-ovn-wallaby
     parent: neutron-tempest-plugin-ovn
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -171,47 +184,58 @@
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-wallaby
     parent: neutron-tempest-plugin-dvr-multinode-scenario
+    nodeset: openstack-two-node-focal
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
       network_api_extensions_common: *api_extensions
-      branch_override: stable/wallaby
 
 - job:
     name: neutron-tempest-plugin-designate-scenario-wallaby
     parent: neutron-tempest-plugin-designate-scenario
     override-checkout: stable/wallaby
+    required-projects:
+      - openstack/neutron
+      - name: openstack/neutron-tempest-plugin
+        override-checkout: 1.8.0
+      - openstack/tempest
+      - name: openstack/designate-tempest-plugin
+        override-checkout: 0.16.0
     vars:
-      branch_override: stable/wallaby
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-sfc-wallaby
     parent: neutron-tempest-plugin-sfc
+    nodeset: openstack-single-node-focal
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-bgpvpn-bagpipe-wallaby
     parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    nodeset: openstack-single-node-focal
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       network_api_extensions: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-dynamic-routing-wallaby
     parent: neutron-tempest-plugin-dynamic-routing
+    nodeset: openstack-single-node-focal
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-vpnaas-wallaby
     parent: neutron-tempest-plugin-vpnaas
+    nodeset: openstack-single-node-focal
     override-checkout: stable/wallaby
+    required-projects: *required-projects-wallaby
     vars:
-      branch_override: stable/wallaby
       network_api_extensions_common: *api_extensions
diff --git a/zuul.d/xena_jobs.yaml b/zuul.d/xena_jobs.yaml
index 91aa023..5d0f617 100644
--- a/zuul.d/xena_jobs.yaml
+++ b/zuul.d/xena_jobs.yaml
@@ -1,6 +1,7 @@
 - job:
     name: neutron-tempest-plugin-api-xena
     parent: neutron-tempest-plugin-base
+    nodeset: openstack-single-node-focal
     override-checkout: stable/xena
     vars:
       tempest_concurrency: 4
@@ -96,7 +97,6 @@
     parent: neutron-tempest-plugin-openvswitch
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -116,7 +116,6 @@
     parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -136,7 +135,6 @@
     parent: neutron-tempest-plugin-linuxbridge
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -156,7 +154,6 @@
     parent: neutron-tempest-plugin-ovn
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -173,41 +170,40 @@
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-xena
     parent: neutron-tempest-plugin-dvr-multinode-scenario
+    nodeset: openstack-two-node-focal
     override-checkout: stable/xena
     vars:
       network_api_extensions_common: *api_extensions
-      branch_override: stable/xena
 
 - job:
     name: neutron-tempest-plugin-designate-scenario-xena
     parent: neutron-tempest-plugin-designate-scenario
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-sfc-xena
     parent: neutron-tempest-plugin-sfc
+    nodeset: openstack-single-node-focal
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-bgpvpn-bagpipe-xena
     parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    nodeset: openstack-single-node-focal
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       network_api_extensions: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-dynamic-routing-xena
     parent: neutron-tempest-plugin-dynamic-routing
+    nodeset: openstack-single-node-focal
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       network_api_extensions_common: *api_extensions
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_bgp) | join(',') }}"
@@ -235,15 +231,15 @@
 - job:
     name: neutron-tempest-plugin-vpnaas-xena
     parent: neutron-tempest-plugin-vpnaas
+    nodeset: openstack-single-node-focal
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-tap-as-a-service-xena
     parent: neutron-tempest-plugin-tap-as-a-service
+    nodeset: openstack-single-node-focal
     override-checkout: stable/xena
     vars:
-      branch_override: stable/xena
       network_api_extensions_common: *api_extensions
diff --git a/zuul.d/yoga_jobs.yaml b/zuul.d/yoga_jobs.yaml
index 2e99ef2..2dacd4b 100644
--- a/zuul.d/yoga_jobs.yaml
+++ b/zuul.d/yoga_jobs.yaml
@@ -1,6 +1,7 @@
 - job:
     name: neutron-tempest-plugin-api-yoga
     parent: neutron-tempest-plugin-base
+    nodeset: openstack-single-node-focal
     override-checkout: stable/yoga
     vars:
       tempest_concurrency: 4
@@ -98,7 +99,6 @@
     parent: neutron-tempest-plugin-openvswitch
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -118,7 +118,6 @@
     parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -138,7 +137,6 @@
     parent: neutron-tempest-plugin-linuxbridge
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -158,7 +156,6 @@
     parent: neutron-tempest-plugin-ovn
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       tempest_test_regex: "\
           (^neutron_tempest_plugin.scenario)|\
           (^tempest.api.compute.servers.test_attach_interfaces)|\
@@ -177,41 +174,40 @@
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-yoga
     parent: neutron-tempest-plugin-dvr-multinode-scenario
+    nodeset: openstack-two-node-focal
     override-checkout: stable/yoga
     vars:
       network_api_extensions_common: *api_extensions
-      branch_override: stable/yoga
 
 - job:
     name: neutron-tempest-plugin-designate-scenario-yoga
     parent: neutron-tempest-plugin-designate-scenario
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-sfc-yoga
     parent: neutron-tempest-plugin-sfc
+    nodeset: openstack-single-node-focal
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-bgpvpn-bagpipe-yoga
     parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    nodeset: openstack-single-node-focal
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       network_api_extensions: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-dynamic-routing-yoga
     parent: neutron-tempest-plugin-dynamic-routing
+    nodeset: openstack-single-node-focal
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       network_api_extensions_common: *api_extensions
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_bgp) | join(',') }}"
@@ -239,15 +235,15 @@
 - job:
     name: neutron-tempest-plugin-vpnaas-yoga
     parent: neutron-tempest-plugin-vpnaas
+    nodeset: openstack-single-node-focal
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-tap-as-a-service-yoga
     parent: neutron-tempest-plugin-tap-as-a-service
+    nodeset: openstack-single-node-focal
     override-checkout: stable/yoga
     vars:
-      branch_override: stable/yoga
       network_api_extensions_common: *api_extensions
diff --git a/zuul.d/zed_jobs.yaml b/zuul.d/zed_jobs.yaml
index 9bf11ba..0d846f7 100644
--- a/zuul.d/zed_jobs.yaml
+++ b/zuul.d/zed_jobs.yaml
@@ -3,7 +3,6 @@
     parent: neutron-tempest-plugin-openvswitch
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_openvswitch:
         - local_ip
         - qos-bw-minimum-ingress
@@ -109,7 +108,6 @@
     parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_openvswitch:
         - local_ip
         - logging
@@ -124,7 +122,8 @@
       # 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)"
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatefulNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
       network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
@@ -139,7 +138,6 @@
     parent: neutron-tempest-plugin-linuxbridge
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_linuxbridge:
         - vlan-transparent
       tempest_test_regex: "\
@@ -149,7 +147,8 @@
           (^tempest.api.compute.servers.test_multiple_create)"
       tempest_exclude_regex: "\
           (^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)|\
-          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatefulNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)|\
           (^neutron_tempest_plugin.scenario.test_floatingip.FloatingIPPortDetailsTest.test_floatingip_port_details)"
       network_available_features: *available_features
       devstack_localrc:
@@ -165,7 +164,6 @@
     parent: neutron-tempest-plugin-ovn
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       tempest_test_regex: "\
           (^neutron_tempest_plugin.api)|\
           (^neutron_tempest_plugin.scenario)|\
@@ -187,41 +185,40 @@
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-zed
     parent: neutron-tempest-plugin-dvr-multinode-scenario
+    nodeset: openstack-two-node-focal
     override-checkout: stable/zed
     vars:
       network_api_extensions_common: *api_extensions
-      branch_override: stable/zed
 
 - job:
     name: neutron-tempest-plugin-designate-scenario-zed
     parent: neutron-tempest-plugin-designate-scenario
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-sfc-zed
     parent: neutron-tempest-plugin-sfc
+    nodeset: openstack-single-node-focal
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-bgpvpn-bagpipe-zed
     parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    nodeset: openstack-single-node-focal
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-dynamic-routing-zed
     parent: neutron-tempest-plugin-dynamic-routing
+    nodeset: openstack-single-node-focal
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_common: *api_extensions
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_bgp) | join(',') }}"
@@ -249,23 +246,23 @@
 - job:
     name: neutron-tempest-plugin-fwaas-zed
     parent: neutron-tempest-plugin-fwaas
+    nodeset: openstack-single-node-focal
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-vpnaas-zed
     parent: neutron-tempest-plugin-vpnaas
+    nodeset: openstack-single-node-focal
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_common: *api_extensions
 
 - job:
     name: neutron-tempest-plugin-tap-as-a-service-zed
     parent: neutron-tempest-plugin-tap-as-a-service
+    nodeset: openstack-single-node-focal
     override-checkout: stable/zed
     vars:
-      branch_override: stable/zed
       network_api_extensions_common: *api_extensions