Merge "Add API tests for basic address_groups CRUD operations"
diff --git a/devstack/functions.sh b/devstack/functions.sh
index 8d8a4bf..f758ff6 100644
--- a/devstack/functions.sh
+++ b/devstack/functions.sh
@@ -85,3 +85,15 @@
     fi
     iniset $TEMPEST_CONFIG neutron_plugin_options advanced_image_flavor_ref $flavor_ref
 }
+
+
+function create_flavor_for_advance_image {
+    local name=$1
+    local ram=$2
+    local disk=$3
+    local vcpus=$4
+
+    if [[ -z $(openstack flavor list | grep $name) ]]; then
+        openstack flavor create --ram $ram --disk $disk --vcpus $vcpus $name
+    fi
+}
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
index 7a46014..2e3ac20 100644
--- a/devstack/plugin.sh
+++ b/devstack/plugin.sh
@@ -20,6 +20,7 @@
         test-config)
             echo_summary "Configuring neutron-tempest-plugin tempest options"
             configure_advanced_image
+            create_flavor_for_advance_image ntp_image_384M 384 4 1
             configure_flavor_for_advanced_image
     esac
 fi
diff --git a/neutron_tempest_plugin/api/test_allowed_address_pair.py b/neutron_tempest_plugin/api/test_allowed_address_pair.py
deleted file mode 100644
index 7b11638..0000000
--- a/neutron_tempest_plugin/api/test_allowed_address_pair.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.lib import decorators
-
-from neutron_tempest_plugin.api import base
-
-
-class AllowedAddressPairTestJSON(base.BaseNetworkTest):
-
-    """AllowedAddressPairTestJSON class
-
-    Tests the Neutron Allowed Address Pair API extension using the Tempest
-    REST client. The following API operations are tested with this extension:
-
-        create port
-        list ports
-        update port
-        show port
-
-    v2.0 of the Neutron API is assumed. It is also assumed that the following
-    options are defined in the [network-feature-enabled] section of
-    etc/tempest.conf
-
-        api_extensions
-    """
-
-    required_extensions = ['allowed-address-pairs']
-
-    @classmethod
-    def resource_setup(cls):
-        super(AllowedAddressPairTestJSON, cls).resource_setup()
-        cls.network = cls.create_network()
-        cls.create_subnet(cls.network)
-        port = cls.create_port(cls.network)
-        cls.ip_address = port['fixed_ips'][0]['ip_address']
-        cls.mac_address = port['mac_address']
-
-    @decorators.idempotent_id('86c3529b-1231-40de-803c-00e40882f043')
-    def test_create_list_port_with_address_pair(self):
-        # Create port with allowed address pair attribute
-        allowed_address_pairs = [{'ip_address': self.ip_address,
-                                  'mac_address': self.mac_address}]
-        body = self.create_port(
-            self.network,
-            allowed_address_pairs=allowed_address_pairs)
-        port_id = body['id']
-
-        # Confirm port was created with allowed address pair attribute
-        body = self.client.list_ports()
-        ports = body['ports']
-        port = [p for p in ports if p['id'] == port_id]
-        msg = 'Created port not found in list of ports returned by Neutron'
-        self.assertTrue(port, msg)
-        self._confirm_allowed_address_pair(port[0], self.ip_address)
-
-    def _update_port_with_address(self, address, mac_address=None, **kwargs):
-        # Create a port without allowed address pair
-        body = self.create_port(self.network)
-        port_id = body['id']
-        if mac_address is None:
-            mac_address = self.mac_address
-
-        # Update allowed address pair attribute of port
-        allowed_address_pairs = [{'ip_address': address,
-                                  'mac_address': mac_address}]
-        if kwargs:
-            allowed_address_pairs.append(kwargs['allowed_address_pairs'])
-        body = self.client.update_port(
-            port_id, allowed_address_pairs=allowed_address_pairs)
-        allowed_address_pair = body['port']['allowed_address_pairs']
-        self.assertCountEqual(allowed_address_pair, allowed_address_pairs)
-
-    @decorators.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4')
-    def test_update_port_with_address_pair(self):
-        # Update port with allowed address pair
-        self._update_port_with_address(self.ip_address)
-
-    @decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4')
-    def test_update_port_with_cidr_address_pair(self):
-        # Update allowed address pair with cidr
-        cidr = str(next(self.get_subnet_cidrs()))
-        self._update_port_with_address(cidr)
-
-    @decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
-    def test_update_port_with_multiple_ip_mac_address_pair(self):
-        # Create an ip _address and mac_address through port create
-        resp = self.create_port(self.network)
-        ipaddress = resp['fixed_ips'][0]['ip_address']
-        macaddress = resp['mac_address']
-
-        # Update allowed address pair port with multiple ip and  mac
-        allowed_address_pairs = {'ip_address': ipaddress,
-                                 'mac_address': macaddress}
-        self._update_port_with_address(
-            self.ip_address, self.mac_address,
-            allowed_address_pairs=allowed_address_pairs)
-
-    def _confirm_allowed_address_pair(self, port, ip):
-        msg = 'Port allowed address pairs should not be empty'
-        self.assertTrue(port['allowed_address_pairs'], msg)
-        ip_address = port['allowed_address_pairs'][0]['ip_address']
-        mac_address = port['allowed_address_pairs'][0]['mac_address']
-        self.assertEqual(ip_address, ip)
-        self.assertEqual(mac_address, self.mac_address)
-
-
-class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON):
-    _ip_version = 6
diff --git a/neutron_tempest_plugin/api/test_security_groups.py b/neutron_tempest_plugin/api/test_security_groups.py
index 94b6dbf..0970d83 100644
--- a/neutron_tempest_plugin/api/test_security_groups.py
+++ b/neutron_tempest_plugin/api/test_security_groups.py
@@ -240,12 +240,14 @@
 
     def _create_security_group_rules(self, amount, port_index=1):
         for i in range(amount):
-            self.create_security_group_rule(**{
+            ingress_rule = self.create_security_group_rule(**{
                 'project_id': self.client.tenant_id,
                 'direction': 'ingress',
                 'port_range_max': port_index + i,
                 'port_range_min': port_index + i,
                 'protocol': 'tcp'})
+            self.addCleanup(
+                self.client.delete_security_group_rule, ingress_rule['id'])
 
     def _increase_sg_rules_quota(self):
         sg_rules_quota = self._get_sg_rules_quota()
diff --git a/neutron_tempest_plugin/api/test_subnets.py b/neutron_tempest_plugin/api/test_subnets.py
index b8842ab..3b075d5 100644
--- a/neutron_tempest_plugin/api/test_subnets.py
+++ b/neutron_tempest_plugin/api/test_subnets.py
@@ -10,6 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import netaddr
 from tempest.lib import decorators
 
 from neutron_tempest_plugin.api import base
@@ -69,3 +70,44 @@
         self._test_list_validation_filters(self.list_kwargs)
         self._test_list_validation_filters({
             'unknown_filter': 'value'}, filter_is_valid=False)
+
+
+class SubnetServiceTypeTestJSON(base.BaseNetworkTest):
+
+    required_extensions = ['subnet-service-types']
+
+    @classmethod
+    def resource_setup(cls):
+        super(SubnetServiceTypeTestJSON, cls).resource_setup()
+        cls.network = cls.create_network()
+
+    @decorators.idempotent_id('7e0edb66-1bb2-4473-ab83-d039cddced0d')
+    def test_allocate_ips_are_from_correct_subnet(self):
+        cidr_1 = netaddr.IPNetwork('192.168.1.0/24')
+        cidr_2 = netaddr.IPNetwork('192.168.2.0/24')
+
+        # NOTE(slaweq): service_type "network:distributed" is needed for
+        # ML2/OVN backend. It's needed because OVN driver creates additional
+        # port for metadata service in each subnet with enabled dhcp and such
+        # port needs to have allocated IP address from the subnet also.
+        self.create_subnet(
+            self.network,
+            service_types=['test:type_1', 'network:distributed'],
+            cidr=str(cidr_1))
+        self.create_subnet(
+            self.network,
+            service_types=['test:type_2', 'network:distributed'],
+            cidr=str(cidr_2))
+        port_type_1 = self.create_port(self.network,
+                                       device_owner="test:type_1")
+        port_type_2 = self.create_port(self.network,
+                                       device_owner="test:type_2")
+
+        self.assertEqual(1, len(port_type_1['fixed_ips']))
+        self.assertEqual(1, len(port_type_2['fixed_ips']))
+        self.assertIn(
+            netaddr.IPAddress(port_type_1['fixed_ips'][0]['ip_address']),
+            cidr_1)
+        self.assertIn(
+            netaddr.IPAddress(port_type_2['fixed_ips'][0]['ip_address']),
+            cidr_2)
diff --git a/neutron_tempest_plugin/api/test_trunk.py b/neutron_tempest_plugin/api/test_trunk.py
index 1f83bd8..26f8de8 100644
--- a/neutron_tempest_plugin/api/test_trunk.py
+++ b/neutron_tempest_plugin/api/test_trunk.py
@@ -247,21 +247,23 @@
     @classmethod
     def skip_checks(cls):
         super(TrunkTestMtusJSONBase, cls).skip_checks()
-        if not all(cls.is_type_driver_enabled(t) for t in ['gre', 'vxlan']):
-            msg = "Either vxlan or gre type driver not enabled."
+        if not all(cls.is_type_driver_enabled(t) for t in ['vlan', 'vxlan']):
+            msg = "Either vxlan or vlan type driver not enabled."
             raise cls.skipException(msg)
 
     def setUp(self):
         super(TrunkTestMtusJSONBase, self).setUp()
+        physnet_name = CONF.neutron_plugin_options.provider_vlans[0]
 
-        # VXLAN autocomputed MTU (1450) is smaller than that of GRE (1458)
+        # VXLAN autocomputed MTU (1450) is smaller than that of VLAN (1480)
         self.smaller_mtu_net = self.create_network(
             name=data_utils.rand_name('vxlan-net'),
             provider_network_type='vxlan')
 
         self.larger_mtu_net = self.create_network(
-            name=data_utils.rand_name('gre-net'),
-            provider_network_type='gre')
+            name=data_utils.rand_name('vlan-net'),
+            provider_network_type='vlan',
+            provider_physical_network=physnet_name)
 
         self.smaller_mtu_port = self.create_port(self.smaller_mtu_net)
         self.smaller_mtu_port_2 = self.create_port(self.smaller_mtu_net)
diff --git a/neutron_tempest_plugin/common/utils.py b/neutron_tempest_plugin/common/utils.py
index f03762c..898e4b9 100644
--- a/neutron_tempest_plugin/common/utils.py
+++ b/neutron_tempest_plugin/common/utils.py
@@ -136,3 +136,76 @@
 def call_url_remote(ssh_client, url):
     cmd = "curl %s --retry 3 --connect-timeout 2" % url
     return ssh_client.exec_command(cmd)
+
+
+class StatefulConnection:
+    """Class to test connection that should remain opened
+
+    Can be used to perform some actions while the initiated connection
+    remain opened
+    """
+
+    def __init__(self, client_ssh, server_ssh, target_ip, target_port):
+        self.client_ssh = client_ssh
+        self.server_ssh = server_ssh
+        self.ip = target_ip
+        self.port = target_port
+        self.connection_started = False
+        self.test_attempt = 0
+
+    def __enter__(self):
+        return self
+
+    @property
+    def test_str(self):
+        return 'attempt_{}'.format(str(self.test_attempt).zfill(3))
+
+    def _start_connection(self):
+        self.server_ssh.exec_command(
+                'echo "{}" > input.txt'.format(self.test_str))
+        self.server_ssh.exec_command('tail -f input.txt | nc -lp '
+                '{} &> output.txt &'.format(self.port))
+        self.client_ssh.exec_command(
+                'echo "{}" > input.txt'.format(self.test_str))
+        self.client_ssh.exec_command('tail -f input.txt | nc {} {} &>'
+                'output.txt &'.format(self.ip, self.port))
+
+    def _test_connection(self):
+        if not self.connection_started:
+            self._start_connection()
+        else:
+            self.server_ssh.exec_command(
+                    'echo "{}" >> input.txt'.format(self.test_str))
+            self.client_ssh.exec_command(
+                    'echo "{}" >> input.txt & sleep 1'.format(self.test_str))
+        try:
+            self.server_ssh.exec_command(
+                    'grep {} output.txt'.format(self.test_str))
+            self.client_ssh.exec_command(
+                    'grep {} output.txt'.format(self.test_str))
+            if not self.should_pass:
+                return False
+            else:
+                if not self.connection_started:
+                    self.connection_started = True
+                return True
+        except exceptions.SSHExecCommandFailed:
+            if self.should_pass:
+                return False
+            else:
+                return True
+        finally:
+            self.test_attempt += 1
+
+    def test_connection(self, should_pass=True, timeout=10, sleep_timer=1):
+        self.should_pass = should_pass
+        wait_until_true(
+                self._test_connection, timeout=timeout, sleep=sleep_timer)
+
+    def __exit__(self, type, value, traceback):
+        self.server_ssh.exec_command('sudo killall nc || killall nc')
+        self.server_ssh.exec_command(
+                'sudo killall tail || killall tail || echo "True"')
+        self.client_ssh.exec_command('sudo killall nc || killall nc')
+        self.client_ssh.exec_command(
+                'sudo killall tail || killall tail || echo "True"')
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index fad85ad..8591c89 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -222,18 +222,12 @@
 
         error_msg = (
             "Router %s is not active on any of the L3 agents" % router_id)
-        # NOTE(slaweq): Due to bug
-        # the bug https://launchpad.net/bugs/1923633 let's temporary skip test
-        # if router will not become active on any of the L3 agents in 600
-        # seconds. When that bug will be fixed, we should get rid of that skip
-        # and lower timeout to e.g. 300 seconds, or even less
-        try:
-            utils.wait_until_true(
-                _router_active_on_l3_agent,
-                timeout=600, sleep=5,
-                exception=lib_exc.TimeoutException(error_msg))
-        except lib_exc.TimeoutException:
-            raise cls.skipException("Bug 1923633. %s" % error_msg)
+        # NOTE(slaweq): timeout here should be lower for sure, but due to
+        # the bug https://launchpad.net/bugs/1923633 let's wait even 10
+        # minutes until router will be active on some of the L3 agents
+        utils.wait_until_true(_router_active_on_l3_agent,
+                              timeout=600, sleep=5,
+                              exception=lib_exc.TimeoutException(error_msg))
 
     @classmethod
     def skip_if_no_extension_enabled_in_l3_agents(cls, extension):
diff --git a/neutron_tempest_plugin/scenario/test_dns_integration.py b/neutron_tempest_plugin/scenario/test_dns_integration.py
index 5c590eb..79c0993 100644
--- a/neutron_tempest_plugin/scenario/test_dns_integration.py
+++ b/neutron_tempest_plugin/scenario/test_dns_integration.py
@@ -199,3 +199,56 @@
         self.client.delete_port(port['id'])
         self._verify_dns_records(addr_v6, name, record_type='AAAA',
                                  found=False)
+
+
+class DNSIntegrationDomainPerProjectTests(BaseDNSIntegrationTests):
+
+    credentials = ['primary', 'admin']
+
+    required_extensions = ['subnet-dns-publish-fixed-ip',
+                           'dns-integration-domain-keywords']
+
+    @classmethod
+    def resource_setup(cls):
+        super(BaseDNSIntegrationTests, cls).resource_setup()
+
+        name = data_utils.rand_name('test-domain')
+        zone_name = "%s.%s.%s.zone." % (cls.client.user_id,
+                                        cls.client.tenant_id,
+                                        name)
+        dns_domain_template = "<user_id>.<project_id>.%s.zone." % name
+
+        _, cls.zone = cls.dns_client.create_zone(name=zone_name)
+        cls.addClassResourceCleanup(cls.dns_client.delete_zone,
+            cls.zone['id'], ignore_errors=lib_exc.NotFound)
+        dns_waiters.wait_for_zone_status(
+            cls.dns_client, cls.zone['id'], 'ACTIVE')
+
+        cls.network = cls.create_network(dns_domain=dns_domain_template)
+        cls.subnet = cls.create_subnet(cls.network,
+                                       dns_publish_fixed_ip=True)
+        cls.subnet_v6 = cls.create_subnet(cls.network,
+                                          ip_version=6,
+                                          dns_publish_fixed_ip=True)
+        cls.router = cls.create_router_by_client()
+        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+        cls.keypair = cls.create_keypair()
+
+    @decorators.idempotent_id('43a67509-3161-4125-8f2c-0d4a67599721')
+    def test_port_with_dns_name(self):
+        name = data_utils.rand_name('port-test')
+        port = self.create_port(self.network,
+                                dns_name=name)
+        addr = port['fixed_ips'][0]['ip_address']
+        self._verify_dns_records(addr, name)
+        self.client.delete_port(port['id'])
+        self._verify_dns_records(addr, name, found=False)
+
+    @decorators.idempotent_id('ac89db9b-5ca4-43bd-85ba-40fbeb47e208')
+    def test_fip_admin_delete(self):
+        name = data_utils.rand_name('fip-test')
+        fip = self._create_floatingip_with_dns(name)
+        addr = fip['floating_ip_address']
+        self._verify_dns_records(addr, name)
+        self.delete_floatingip(fip, client=self.admin_client)
+        self._verify_dns_records(addr, name, found=False)
diff --git a/neutron_tempest_plugin/scenario/test_ipv6.py b/neutron_tempest_plugin/scenario/test_ipv6.py
index 4237d4f..32fb581 100644
--- a/neutron_tempest_plugin/scenario/test_ipv6.py
+++ b/neutron_tempest_plugin/scenario/test_ipv6.py
@@ -43,35 +43,41 @@
     """
     ip_command = ip.IPCommand(ssh)
     nic = ip_command.get_nic_name_by_mac(ipv6_port['mac_address'])
+    ip_command.set_link(nic, "up")
 
-    # NOTE(slaweq): on RHEL based OS ifcfg file for new interface is
-    # needed to make IPv6 working on it, so if
-    # /etc/sysconfig/network-scripts directory exists ifcfg-%(nic)s file
-    # should be added in it
-    if sysconfig_network_scripts_dir_exists(ssh):
+
+def configure_eth_connection_profile_NM(ssh):
+    """Prepare a Network manager profile for ipv6 port
+
+    By default the NetworkManager uses IPv6 privacy
+    format it isn't supported by neutron then we create
+    a ether profile with eui64 supported format
+
+    @param ssh: RemoteClient ssh instance to server
+    """
+    # NOTE(ccamposr): on RHEL based OS we need a ether profile with
+    # eui64 format
+    if nmcli_command_exists(ssh):
         try:
-            ssh.execute_script(
-                'echo -e "DEVICE=%(nic)s\\nNAME=%(nic)s\\nIPV6INIT=yes" | '
-                'tee /etc/sysconfig/network-scripts/ifcfg-%(nic)s; '
-                'nmcli connection reload' % {'nic': nic},
-                become_root=True)
-            ssh.execute_script('nmcli connection up %s' % nic,
+            ssh.execute_script('nmcli connection add type ethernet con-name '
+                               'ether ifname "*"', become_root=True)
+            ssh.execute_script('nmcli con mod ether ipv6.addr-gen-mode eui64',
                                become_root=True)
+
         except lib_exc.SSHExecCommandFailed as e:
             # NOTE(slaweq): Sometimes it can happen that this SSH command
             # will fail because of some error from network manager in
             # guest os.
             # But even then doing ip link set up below is fine and
             # IP address should be configured properly.
-            LOG.debug("Error during restarting %(nic)s interface on "
-                      "instance. Error message: %(error)s",
-                      {'nic': nic, 'error': e})
-    ip_command.set_link(nic, "up")
+            LOG.debug("Error creating NetworkManager profile. "
+                      "Error message: %(error)s",
+                      {'error': e})
 
 
-def sysconfig_network_scripts_dir_exists(ssh):
+def nmcli_command_exists(ssh):
     return "False" not in ssh.execute_script(
-        'test -d /etc/sysconfig/network-scripts/ || echo "False"')
+        'if ! type nmcli > /dev/null ; then echo "False"; fi')
 
 
 class IPv6Test(base.BaseTempestTestCase):
@@ -165,6 +171,8 @@
 
         # And plug VM to the second IPv6 network
         ipv6_port = self.create_port(ipv6_networks[1])
+        # Add NetworkManager profile with ipv6 eui64 format to guest OS
+        configure_eth_connection_profile_NM(ssh_client)
         self.create_interface(vm['id'], ipv6_port['id'])
         ip.wait_for_interface_status(
             self.os_primary.interfaces_client, vm['id'],
diff --git a/neutron_tempest_plugin/scenario/test_mac_learning.py b/neutron_tempest_plugin/scenario/test_mac_learning.py
new file mode 100644
index 0000000..736d46c
--- /dev/null
+++ b/neutron_tempest_plugin/scenario/test_mac_learning.py
@@ -0,0 +1,210 @@
+# Copyright 2021 Red Hat, Inc
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from oslo_log import log
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+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
+
+
+CONF = config.CONF
+LOG = log.getLogger(__name__)
+
+
+# -s0 -l -c5 &> /tmp/tcpdump_out &
+def get_receiver_script(result_file, packets_expected):
+    """Script that listen icmp echos and write the output on result_file."""
+    return """#!/bin/bash
+export LC_ALL=en_US.UTF-8
+tcpdump -i any -n -v 'icmp[icmptype] = icmp-echoreply or icmp[icmptype] = \
+icmp-echo' -s0 -l -c%(packets_expected)d &> %(result_file)s &
+    """ % {'result_file': result_file,
+           'packets_expected': packets_expected}
+
+
+def get_sender_script(result_file, receiver_address, completed_message):
+    """Script that sends packets to the receiver server."""
+    return """#!/bin/bash
+export LC_ALL=en_US.UTF-8
+ping -c 5 %(address)s
+echo '%(completed_message)s' > %(result_file)s &
+    """ % {'result_file': result_file,
+           'address': receiver_address,
+           'completed_message': completed_message}
+
+
+class MacLearningTest(base.BaseTempestTestCase):
+
+    credentials = ['primary', 'admin']
+    force_tenant_isolation = False
+
+    # Import configuration options
+    available_type_drivers = (
+        CONF.neutron_plugin_options.available_type_drivers)
+
+    completed_message = "Done!"
+    output_file = "/tmp/tcpdump_out"
+    sender_output_file = "/tmp/sender_out"
+    sender_script_file = "/tmp/ping.sh"
+    receiver_script_file = "/tmp/traffic.sh"
+
+    @classmethod
+    def skip_checks(cls):
+        super(MacLearningTest, cls).skip_checks()
+        advanced_image_available = (
+            CONF.neutron_plugin_options.advanced_image_ref or
+            CONF.neutron_plugin_options.default_image_is_advanced)
+        if not advanced_image_available:
+            skip_reason = "This test requires advanced tools to be executed"
+            raise cls.skipException(skip_reason)
+
+    @classmethod
+    def resource_setup(cls):
+        super(MacLearningTest, cls).resource_setup()
+
+        if CONF.neutron_plugin_options.default_image_is_advanced:
+            cls.flavor_ref = CONF.compute.flavor_ref
+            cls.image_ref = CONF.compute.image_ref
+            cls.username = CONF.validation.image_ssh_user
+        else:
+            cls.flavor_ref = (
+                CONF.neutron_plugin_options.advanced_image_flavor_ref)
+            cls.image_ref = CONF.neutron_plugin_options.advanced_image_ref
+            cls.username = CONF.neutron_plugin_options.advanced_image_ssh_user
+
+        # Setup basic topology for servers so that we can log into them
+        # It's important to keep port security and DHCP disabled for this test
+        cls.network = cls.create_network(port_security_enabled=False)
+        cls.subnet = cls.create_subnet(cls.network, enable_dhcp=False)
+        cls.router = cls.create_router_by_client()
+        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+
+        cls.keypair = cls.create_keypair()
+
+    def _create_server(self):
+        name = data_utils.rand_name("maclearning-server")
+        server = self.create_server(
+            flavor_ref=self.flavor_ref,
+            image_ref=self.image_ref,
+            key_name=self.keypair['name'], name=name,
+            networks=[{'uuid': self.network['id']}],
+            config_drive='True')['server']
+        self.wait_for_server_active(server)
+        self.wait_for_guest_os_ready(server)
+        server['port'] = self.client.list_ports(
+            network_id=self.network['id'], device_id=server['id'])['ports'][0]
+        server['fip'] = self.create_floatingip(port=server['port'])
+        server['ssh_client'] = ssh.Client(server['fip']['floating_ip_address'],
+                                          self.username,
+                                          pkey=self.keypair['private_key'])
+        return server
+
+    def _check_cmd_installed_on_server(self, ssh_client, server_id, cmd):
+        try:
+            ssh_client.execute_script('which %s' % cmd)
+        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)
+        self._check_cmd_installed_on_server(server['ssh_client'], server['id'],
+                                            'tcpdump')
+        server['ssh_client'].execute_script(
+            'echo "%s" > %s' % (check_script, self.sender_script_file))
+
+    def _prepare_listener(self, server, n_packets):
+        check_script = get_receiver_script(
+            result_file=self.output_file,
+            packets_expected=n_packets)
+        self._check_cmd_installed_on_server(server['ssh_client'], server['id'],
+                                            'tcpdump')
+        server['ssh_client'].execute_script(
+            'echo "%s" > %s' % (check_script, self.receiver_script_file))
+
+    @decorators.idempotent_id('013686ac-23b1-23e4-8361-10b1c98a2861')
+    def test_mac_learning_vms_on_same_network(self):
+        """Test mac learning works in a network.
+
+        The receiver server will receive all the sent packets.
+        The non receiver should not receive any.
+
+        """
+        sender = self._create_server()
+        receiver = self._create_server()
+        non_receiver = self._create_server()
+
+        def check_server_result(server, expected_result, output_file):
+            result = server['ssh_client'].execute_script(
+                "cat {path} || echo '{path} not exists yet'".format(
+                    path=output_file))
+            LOG.debug("VM result: %s", result)
+            return expected_result in result
+
+        # Prepare the server that is intended to receive the packets
+        self._prepare_listener(receiver, 5)
+
+        # Prepare the server that is not intended receive of the packets.
+        self._prepare_listener(non_receiver, 2)
+
+        # Run the scripts
+        for server in [receiver, non_receiver]:
+            server['ssh_client'].execute_script(
+                "bash %s" % self.receiver_script_file, become_root=True)
+
+        # Prepare the server that will make the ping.
+        target_ip = receiver['port']['fixed_ips'][0]['ip_address']
+        self._prepare_sender(sender, address=target_ip)
+
+        LOG.debug("The receiver IP is: %s", target_ip)
+        # Run the sender node script
+        sender['ssh_client'].execute_script(
+                "bash %s" % self.sender_script_file, become_root=True)
+
+        # Check if the message was sent.
+        utils.wait_until_true(
+            lambda: check_server_result(
+                sender, self.completed_message,
+                self.sender_output_file),
+            exception=RuntimeError(
+                "Sender script wasn't executed properly"))
+
+        # Check receiver server
+        receiver_expected_result = '5 packets captured'
+        utils.wait_until_true(
+            lambda: check_server_result(receiver,
+                receiver_expected_result, self.output_file),
+            exception=RuntimeError(
+                'Receiver server did not receive expected packet'))
+
+        # Check the non_receiver server
+        non_receiver_expected_result = '0 packets captured'
+        try:
+            LOG.debug("Try killing non-receiver tcpdump")
+            non_receiver['ssh_client'].execute_script(
+                "killall tcpdump && sleep 2", become_root=True)
+        except exceptions.SSHScriptFailed:
+            LOG.debug("Killing tcpdump failed")
+            self.assertTrue(check_server_result(non_receiver,
+                            non_receiver_expected_result,
+                            self.output_file),
+                            'Non targeted server received unexpected packets')
+            return
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 8b7098e..40aa66a 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -54,6 +54,7 @@
         utils.kill_nc_process(ssh_server)
         url = 'http://%s:%d' % (test_ip, test_port)
         utils.spawn_http_server(ssh_server, port=test_port, message='foo_ok')
+        utils.process_is_running(ssh_server, 'nc')
         try:
             ret = utils.call_url_remote(ssh_client, url)
             if should_pass:
@@ -277,6 +278,50 @@
                       'remote_ip_prefix': cidr}]
         self._test_ip_prefix(rule_list, should_succeed=False)
 
+    @decorators.idempotent_id('01f0ddca-b049-47eb-befd-82acb502c9ec')
+    def test_established_tcp_session_after_re_attachinging_sg(self):
+        """Test existing connection remain open after sg has been re-attached
+
+        Verifies that new packets can pass over the existing connection when
+        the security group has been removed from the server and then added
+        back
+        """
+
+        ssh_sg = self.create_security_group()
+        self.create_loginable_secgroup_rule(secgroup_id=ssh_sg['id'])
+        vm_ssh, fips, vms = self.create_vm_testing_sec_grp(
+                security_groups=[{'name': ssh_sg['name']}])
+        sg = self.create_security_group()
+        nc_rule = [{'protocol': constants.PROTO_NUM_TCP,
+                    'direction': constants.INGRESS_DIRECTION,
+                    'port_range_min': 6666,
+                    'port_range_max': 6666}]
+        self.create_secgroup_rules(nc_rule, secgroup_id=sg['id'])
+        srv_port = self.client.list_ports(network_id=self.network['id'],
+                device_id=vms[1]['server']['id'])['ports'][0]
+        srv_ip = srv_port['fixed_ips'][0]['ip_address']
+        with utils.StatefulConnection(
+                vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id'], sg['id']])
+            con.test_connection()
+        with utils.StatefulConnection(
+                vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
+            self.client.update_port(
+                    srv_port['id'], security_groups=[ssh_sg['id']])
+            con.test_connection(should_pass=False)
+        with utils.StatefulConnection(
+                vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id'], sg['id']])
+            con.test_connection()
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id']])
+            con.test_connection(should_pass=False)
+            self.client.update_port(srv_port['id'],
+                    security_groups=[ssh_sg['id'], sg['id']])
+            con.test_connection()
+
     @decorators.idempotent_id('7ed39b86-006d-40fb-887a-ae46693dabc9')
     def test_remote_group(self):
         # create a new sec group
@@ -572,3 +617,45 @@
             ssh_clients[0], fips[1]['fixed_ip_address'])
         self.check_remote_connectivity(
             ssh_clients[1], fips[0]['fixed_ip_address'])
+
+    @decorators.idempotent_id('cd66b826-d86c-4fb4-ab37-17c8391753cb')
+    def test_overlapping_sec_grp_rules(self):
+        """Test security group rules with overlapping port ranges"""
+        client_ssh, _, vms = self.create_vm_testing_sec_grp(num_servers=2)
+        tmp_ssh, _, tmp_vm = self.create_vm_testing_sec_grp(num_servers=1)
+        srv_ssh = tmp_ssh[0]
+        srv_vm = tmp_vm[0]
+        srv_port = self.client.list_ports(network_id=self.network['id'],
+                device_id=srv_vm['server']['id'])['ports'][0]
+        srv_ip = srv_port['fixed_ips'][0]['ip_address']
+        secgrps = []
+        for i, vm in enumerate(vms):
+            sg = self.create_security_group(name='secgrp-%d' % i)
+            self.create_loginable_secgroup_rule(secgroup_id=sg['id'])
+            port = self.client.list_ports(network_id=self.network['id'],
+                    device_id=vm['server']['id'])['ports'][0]
+            self.client.update_port(port['id'], security_groups=[sg['id']])
+            secgrps.append(sg)
+        tcp_port = 3000
+        rule_list = [{'protocol': constants.PROTO_NUM_TCP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'port_range_min': tcp_port,
+                      'port_range_max': tcp_port,
+                      'remote_group_id': secgrps[0]['id']},
+                     {'protocol': constants.PROTO_NUM_TCP,
+                      'direction': constants.INGRESS_DIRECTION,
+                      'port_range_min': tcp_port,
+                      'port_range_max': tcp_port + 2,
+                      'remote_group_id': secgrps[1]['id']}]
+        self.client.update_port(srv_port['id'],
+                security_groups=[secgrps[0]['id'], secgrps[1]['id']])
+        self.create_secgroup_rules(rule_list, secgroup_id=secgrps[0]['id'])
+        # The conntrack entries are ruled by the OF definitions but conntrack
+        # status can change the datapath. Let's check the rules in two
+        # attempts
+        for _ in range(2):
+            self._verify_http_connection(client_ssh[0], srv_ssh, srv_ip,
+                                         tcp_port, [])
+            for port in range(tcp_port, tcp_port + 3):
+                self._verify_http_connection(client_ssh[1], srv_ssh, srv_ip,
+                                             port, [])
diff --git a/setup.cfg b/setup.cfg
index 144569f..136aa0f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,12 +1,12 @@
 [metadata]
 name = neutron-tempest-plugin
 summary = Tempest plugin for Neutron Project
-description-file =
+description_file =
     README.rst
 author = OpenStack
-author-email = openstack-discuss@lists.openstack.org
-home-page = https://opendev.org/openstack/neutron-tempest-plugin
-python-requires = >=3.6
+author_email = openstack-discuss@lists.openstack.org
+home_page = https://opendev.org/openstack/neutron-tempest-plugin
+python_requires = >=3.6
 classifier =
     Environment :: OpenStack
     Intended Audience :: Information Technology
diff --git a/tox.ini b/tox.ini
index d3e722a..ff50b9d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-minversion = 3.1
+minversion = 3.18.0
 envlist = pep8
 skipsdist = True
 ignore_basepython_conflict = True
@@ -22,7 +22,7 @@
 commands =
   sh ./tools/misc-sanity-checks.sh
   flake8
-whitelist_externals =
+allowlist_externals =
   sh
 
 [testenv:venv]
diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml
index 04fe323..880e64f 100644
--- a/zuul.d/base.yaml
+++ b/zuul.d/base.yaml
@@ -112,7 +112,7 @@
         CIRROS_VERSION: 0.5.1
         IMAGE_URLS: https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img
         ADVANCED_IMAGE_NAME: ubuntu-18.04-server-cloudimg-amd64
-        ADVANCED_INSTANCE_TYPE: ds512M
+        ADVANCED_INSTANCE_TYPE: ntp_image_384M
         ADVANCED_INSTANCE_USER: ubuntu
         BUILD_TIMEOUT: 784
       tempest_concurrency: 3  # out of 4
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index fd256e1..58a1d37 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -17,6 +17,7 @@
         - dhcp_agent_scheduler
         - dns-domain-ports
         - dns-integration
+        - dns-integration-domain-keywords
         - empty-string-filtering
         - expose-port-forwarding-in-fip
         - expose-l3-conntrack-helper
@@ -75,6 +76,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk
@@ -86,25 +88,16 @@
         - ipv6_metadata
       tempest_test_regex: ^neutron_tempest_plugin\.api
       devstack_services:
-        # Disable OVN services
-        br-ex-tcpdump: false
-        br-int-flows: false
-        ovn-controller: false
-        ovn-northd: false
-        ovs-vswitchd: false
-        ovsdb-server: false
-        q-ovn-metadata-agent: false
-        # Neutron services
-        q-agt: true
-        q-dhcp: true
-        q-l3: true
-        q-meta: true
-        q-metering: true
         neutron-log: true
       devstack_localrc:
-        Q_AGENT: openvswitch
-        Q_ML2_TENANT_NETWORK_TYPE: vxlan
-        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
+        # TODO(lucasagomes): Re-enable MOD_WSGI after
+        # https://bugs.launchpad.net/neutron/+bug/1912359 is implemented
+        NEUTRON_DEPLOY_MOD_WSGI: false
+        # TODO(ralonsoh): remove OVN_BUILD_FROM_SOURCE once the OS packages
+        # include at least OVN v20.12.0.
+        OVN_BUILD_FROM_SOURCE: True
+        OVN_BRANCH: "v21.03.0"
+        OVS_BRANCH: "8dc1733eaea866dce033b3c44853e1b09bf59fc7"
       devstack_local_conf:
         post-config:
           # NOTE(slaweq): We can get rid of this hardcoded absolute path when
@@ -220,7 +213,11 @@
       network_available_features: *available_features
       # TODO(slaweq): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
-      tempest_exclude_regex: "(^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)"
+      # TODO(akatz): remove established tcp session verification test when the
+      # bug https://bugzilla.redhat.com/show_bug.cgi?id=1965036 will be fixed
+      tempest_exclude_regex: "\
+          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_established_tcp_session_after_re_attachinging_sg)"
       devstack_localrc:
         Q_AGENT: openvswitch
         Q_ML2_TENANT_NETWORK_TYPE: vxlan
@@ -297,7 +294,13 @@
       network_available_features: *available_features
       # TODO(eolivare): remove VLAN Transparency tests from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1907548 will be fixed
-      tempest_exclude_regex: "(^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)"
+      # 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
+      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)"
       devstack_localrc:
         Q_AGENT: linuxbridge
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions + network_api_extensions_linuxbridge) | join(',') }}"
@@ -397,7 +400,6 @@
         q-meta: false
         q-metering: false
         q-qos: true
-        tls-proxy: true
         # Cinder services
         c-api: false
         c-bak: false
@@ -489,17 +491,34 @@
         CIRROS_VERSION: 0.5.1
         IMAGE_URLS: https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img
         ADVANCED_IMAGE_NAME: ubuntu-18.04-server-cloudimg-amd64
-        ADVANCED_INSTANCE_TYPE: ds512M
+        ADVANCED_INSTANCE_TYPE: ntp_image_384M
         ADVANCED_INSTANCE_USER: ubuntu
         BUILD_TIMEOUT: 784
+        Q_AGENT: openvswitch
+        Q_ML2_TENANT_NETWORK_TYPE: vxlan
+        Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
       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
+        tls-proxy: true
         tempest: true
+        # Disable OVN services
+        br-ex-tcpdump: false
+        br-int-flows: false
+        ovn-controller: false
+        ovn-northd: false
+        ovs-vswitchd: false
+        ovsdb-server: false
+        q-ovn-metadata-agent: false
+        # Neutron services
+        q-agt: true
+        q-dhcp: true
+        q-l3: true
+        q-meta: true
+        q-metering: true
         neutron-dns: true
         neutron-qos: true
         neutron-segments: true
@@ -574,7 +593,16 @@
     group-vars:
       subnode:
         devstack_services:
-          tls-proxy: false
+          tls-proxy: true
+          br-ex-tcpdump: false
+          br-int-flows: false
+          # Disable OVN services
+          ovn-controller: false
+          ovn-northd: false
+          ovs-vswitchd: false
+          ovsdb-server: false
+          q-ovn-metadata-agent: false
+          # Neutron services
           q-agt: true
           q-l3: true
           q-meta: true
@@ -592,6 +620,9 @@
           s-proxy: false
         devstack_localrc:
           USE_PYTHON3: true
+          Q_AGENT: openvswitch
+          Q_ML2_TENANT_NETWORK_TYPE: vxlan
+          Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
         devstack_local_conf:
           post-config:
             $NEUTRON_CONF:
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 936bd11..969f80a 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -7,6 +7,7 @@
         - neutron-tempest-plugin-scenario-openvswitch
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
         - neutron-tempest-plugin-scenario-ovn
+        - neutron-tempest-plugin-designate-scenario
     gate:
       jobs:
         - neutron-tempest-plugin-api
@@ -19,10 +20,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario
 
 
 - project-template:
@@ -50,6 +47,7 @@
         - neutron-tempest-plugin-scenario-linuxbridge-rocky
         - neutron-tempest-plugin-scenario-openvswitch-rocky
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-rocky
+        - neutron-tempest-plugin-designate-scenario-rocky
     gate:
       jobs:
         - neutron-tempest-plugin-api-rocky
@@ -58,10 +56,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-rocky
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-rocky
 
 
 - project-template:
@@ -72,6 +66,7 @@
         - neutron-tempest-plugin-scenario-linuxbridge-stein
         - neutron-tempest-plugin-scenario-openvswitch-stein
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-stein
+        - neutron-tempest-plugin-designate-scenario-stein
     gate:
       jobs:
         - neutron-tempest-plugin-api-stein
@@ -80,10 +75,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-stein
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-stein
 
 
 - project-template:
@@ -94,6 +85,7 @@
         - neutron-tempest-plugin-scenario-linuxbridge-train
         - neutron-tempest-plugin-scenario-openvswitch-train
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-train
+        - neutron-tempest-plugin-designate-scenario-train
     gate:
       jobs:
         - neutron-tempest-plugin-api-train
@@ -102,10 +94,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-train
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-train
 
 
 - project-template:
@@ -117,6 +105,7 @@
         - neutron-tempest-plugin-scenario-openvswitch-ussuri
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-ussuri
         - neutron-tempest-plugin-scenario-ovn-ussuri
+        - neutron-tempest-plugin-designate-scenario-ussuri
     gate:
       jobs:
         - neutron-tempest-plugin-api-ussuri
@@ -125,10 +114,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-ussuri
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-ussuri
 
 
 - project-template:
@@ -140,6 +125,7 @@
         - neutron-tempest-plugin-scenario-openvswitch-victoria
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-victoria
         - neutron-tempest-plugin-scenario-ovn-victoria
+        - neutron-tempest-plugin-designate-scenario-victoria
     gate:
       jobs:
         - neutron-tempest-plugin-api-victoria
@@ -148,10 +134,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-victoria
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-victoria
 
 
 - project-template:
@@ -163,6 +145,7 @@
         - neutron-tempest-plugin-scenario-openvswitch-wallaby
         - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-wallaby
         - neutron-tempest-plugin-scenario-ovn-wallaby
+        - neutron-tempest-plugin-designate-scenario-wallaby
     gate:
       jobs:
         - neutron-tempest-plugin-api-wallaby
@@ -171,10 +154,6 @@
     experimental:
       jobs:
         - neutron-tempest-plugin-dvr-multinode-scenario-wallaby
-        # TODO(slaweq): move it back to the check queue when bug
-        # https://bugs.launchpad.net/neutron/+bug/1891309
-        # will be fixed
-        - neutron-tempest-plugin-designate-scenario-wallaby
 
 
 - project:
diff --git a/zuul.d/queens_jobs.yaml b/zuul.d/queens_jobs.yaml
index 33430c8..9701548 100644
--- a/zuul.d/queens_jobs.yaml
+++ b/zuul.d/queens_jobs.yaml
@@ -75,6 +75,7 @@
         - standard-attr-timestamp
         - standard-attr-tag
         - subnet_allocation
+        - subnet-service-types
         - trunk
         - trunk-details
       network_api_extensions_tempest:
diff --git a/zuul.d/rocky_jobs.yaml b/zuul.d/rocky_jobs.yaml
index c5ccbc0..47f88f2 100644
--- a/zuul.d/rocky_jobs.yaml
+++ b/zuul.d/rocky_jobs.yaml
@@ -84,6 +84,7 @@
         - standard-attr-timestamp
         - standard-attr-tag
         - subnet_allocation
+        - subnet-service-types
         - trunk
         - trunk-details
       network_api_extensions_tempest:
@@ -434,7 +435,7 @@
         CIRROS_VERSION: 0.5.1
         IMAGE_URLS: https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img
         ADVANCED_IMAGE_NAME: ubuntu-18.04-server-cloudimg-amd64
-        ADVANCED_INSTANCE_TYPE: ds512M
+        ADVANCED_INSTANCE_TYPE: ntp_image_384M
         ADVANCED_INSTANCE_USER: ubuntu
         BUILD_TIMEOUT: 784
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
diff --git a/zuul.d/stein_jobs.yaml b/zuul.d/stein_jobs.yaml
index 7a8ea25..40bca7c 100644
--- a/zuul.d/stein_jobs.yaml
+++ b/zuul.d/stein_jobs.yaml
@@ -88,6 +88,7 @@
         - standard-attr-tag
         - standard-attr-timestamp
         - subnet_allocation
+        - subnet-service-types
         - trunk
         - trunk-details
         - uplink-status-propagation
diff --git a/zuul.d/train_jobs.yaml b/zuul.d/train_jobs.yaml
index b87dc8c..a623251 100644
--- a/zuul.d/train_jobs.yaml
+++ b/zuul.d/train_jobs.yaml
@@ -92,6 +92,7 @@
         - standard-attr-tag
         - standard-attr-timestamp
         - subnet_allocation
+        - subnet-service-types
         - subnetpool-prefix-ops
         - trunk
         - trunk-details
diff --git a/zuul.d/ussuri_jobs.yaml b/zuul.d/ussuri_jobs.yaml
index 945ec25..5c5881e 100644
--- a/zuul.d/ussuri_jobs.yaml
+++ b/zuul.d/ussuri_jobs.yaml
@@ -90,6 +90,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk
diff --git a/zuul.d/victoria_jobs.yaml b/zuul.d/victoria_jobs.yaml
index e0e29ed..832d242 100644
--- a/zuul.d/victoria_jobs.yaml
+++ b/zuul.d/victoria_jobs.yaml
@@ -89,6 +89,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk
diff --git a/zuul.d/wallaby_jobs.yaml b/zuul.d/wallaby_jobs.yaml
index fa2ddb6..13a192e 100644
--- a/zuul.d/wallaby_jobs.yaml
+++ b/zuul.d/wallaby_jobs.yaml
@@ -76,6 +76,7 @@
         - standard-attr-timestamp
         - subnet_allocation
         - subnet-dns-publish-fixed-ip
+        - subnet-service-types
         - subnetpool-prefix-ops
         - tag-ports-during-bulk-creation
         - trunk