Merge "New test case: "test_port_with_fixed_ip""
diff --git a/neutron_tempest_plugin/api/admin/test_dhcp_agent_scheduler.py b/neutron_tempest_plugin/api/admin/test_dhcp_agent_scheduler.py
index d0adcb8..9dc4438 100644
--- a/neutron_tempest_plugin/api/admin/test_dhcp_agent_scheduler.py
+++ b/neutron_tempest_plugin/api/admin/test_dhcp_agent_scheduler.py
@@ -13,6 +13,7 @@
 #    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
@@ -33,6 +34,7 @@
         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):
 
diff --git a/neutron_tempest_plugin/api/admin/test_ports.py b/neutron_tempest_plugin/api/admin/test_ports.py
index 9c94322..6f51b1c 100644
--- a/neutron_tempest_plugin/api/admin/test_ports.py
+++ b/neutron_tempest_plugin/api/admin/test_ports.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 import netaddr
-import six
 
 from neutron_lib import constants as const
 from tempest.common import utils
@@ -123,8 +122,8 @@
         self.assertIn('resource_request', port)
         vnic_trait = 'CUSTOM_VNIC_TYPE_%s' % vnic_type.upper()
         physnet_trait = 'CUSTOM_PHYSNET_%s' % self.physnet_name.upper()
-        six.assertCountEqual(self, [physnet_trait, vnic_trait],
-                             port['resource_request']['required'])
+        self.assertCountEqual([physnet_trait, vnic_trait],
+                              port['resource_request']['required'])
 
         self.assertEqual(
             {'NET_BW_EGR_KILOBIT_PER_SEC': self.EGRESS_KBPS,
diff --git a/neutron_tempest_plugin/api/admin/test_quotas.py b/neutron_tempest_plugin/api/admin/test_quotas.py
index ae773c8..0cf474e 100644
--- a/neutron_tempest_plugin/api/admin/test_quotas.py
+++ b/neutron_tempest_plugin/api/admin/test_quotas.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
 from tempest.common import utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
@@ -145,7 +144,7 @@
         # as requested for tenant
         quota_set = self.admin_client.show_details_quota(tenant_id)
         quota_set = quota_set['quota']
-        for key, value in six.iteritems(new_quotas):
+        for key, value in new_quotas.items():
             self.assertEqual(new_quotas[key]['limit'],
                              quota_set[key]['limit'])
             self.assertEqual(new_quotas[key]['reserved'],
@@ -155,5 +154,5 @@
 
         # validate 'default' action for old extension
         quota_limit = self.admin_client.show_quotas(tenant_id)['quota']
-        for key, value in six.iteritems(new_quotas):
+        for key, value in new_quotas.items():
             self.assertEqual(new_quotas[key]['limit'], quota_limit[key])
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index d63dec8..4833c71 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -140,6 +140,17 @@
         cls.conntrack_helpers = []
 
     @classmethod
+    def reserve_external_subnet_cidrs(cls):
+        client = cls.os_admin.network_client
+        ext_nets = client.list_networks(
+            **{"router:external": True})['networks']
+        for ext_net in ext_nets:
+            ext_subnets = client.list_subnets(
+                network_id=ext_net['id'])['subnets']
+            for ext_subnet in ext_subnets:
+                cls.reserve_subnet_cidr(ext_subnet['cidr'])
+
+    @classmethod
     def resource_cleanup(cls):
         if CONF.service_available.neutron:
             # Clean up trunks
diff --git a/neutron_tempest_plugin/api/test_ports.py b/neutron_tempest_plugin/api/test_ports.py
index c59ee83..f1dfe5c 100644
--- a/neutron_tempest_plugin/api/test_ports.py
+++ b/neutron_tempest_plugin/api/test_ports.py
@@ -15,6 +15,7 @@
 
 import copy
 
+from neutron_lib import constants as lib_constants
 from tempest.common import utils
 from tempest.lib import decorators
 
@@ -60,6 +61,20 @@
         body = self.client.list_ports(id=body['port']['id'])['ports'][0]
         self.assertEqual('d2', body['description'])
 
+    @decorators.idempotent_id('3ae162e8-ff00-490c-a423-6a88e48f1ed6')
+    def test_create_update_port_security(self):
+        body = self.create_port(self.network,
+                                port_security_enabled=True)
+        self.assertTrue(body['port_security_enabled'])
+        body = self.client.list_ports(id=body['id'])['ports'][0]
+        self.assertTrue(body['port_security_enabled'])
+        body = self.client.update_port(body['id'],
+                                       port_security_enabled=False,
+                                       security_groups=[])
+        self.assertFalse(body['port']['port_security_enabled'])
+        body = self.client.list_ports(id=body['port']['id'])['ports'][0]
+        self.assertFalse(body['port_security_enabled'])
+
     @decorators.idempotent_id('539fbefe-fb36-48aa-9a53-8c5fbd44e492')
     @utils.requires_ext(extension="dns-integration",
                        service="network")
@@ -137,6 +152,28 @@
         self.assertEqual(expected, subnets)
 
 
+class PortsIpv6TestJSON(base.BaseNetworkTest):
+
+    _ip_version = lib_constants.IP_VERSION_6
+
+    @classmethod
+    def resource_setup(cls):
+        super(PortsIpv6TestJSON, cls).resource_setup()
+        cls.network = cls.create_network()
+
+    @decorators.idempotent_id('b85879fb-4852-4b99-aa32-3f8a7a6a3f01')
+    def test_add_ipv6_ips_to_port(self):
+        s = self.create_subnet(self.network, ip_version=self._ip_version)
+        port = self.create_port(self.network)
+        # request another IP on the same subnet
+        port['fixed_ips'].append({'subnet_id': s['id']})
+        updated = self.client.update_port(port['id'],
+                                          fixed_ips=port['fixed_ips'])
+        subnets = [ip['subnet_id'] for ip in updated['port']['fixed_ips']]
+        expected = [s['id'], s['id']]
+        self.assertEqual(expected, subnets)
+
+
 class PortsSearchCriteriaTest(base.BaseSearchCriteriaTest):
 
     resource = 'port'
diff --git a/neutron_tempest_plugin/api/test_ports_negative.py b/neutron_tempest_plugin/api/test_ports_negative.py
new file mode 100644
index 0000000..e327c25
--- /dev/null
+++ b/neutron_tempest_plugin/api/test_ports_negative.py
@@ -0,0 +1,76 @@
+#    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.db import constants as db_const
+from oslo_utils import uuidutils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+from neutron_tempest_plugin.api import base
+
+LONG_NAME_NG = 'z' * (db_const.NAME_FIELD_SIZE + 1)
+LONG_DESCRIPTION_NG = 'z' * (db_const.LONG_DESCRIPTION_FIELD_SIZE + 1)
+
+
+class PortsNegativeTestJSON(base.BaseNetworkTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(PortsNegativeTestJSON, cls).resource_setup()
+        cls.network = cls.create_network()
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('0cbd256a-a6d4-4afa-a039-44cc13704bab')
+    def test_add_port_with_too_long_name(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_port,
+                          self.network, name=LONG_NAME_NG)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('e10da38c-1071-49c9-95c2-0c451e18ae31')
+    def test_add_port_with_too_long_description(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_port,
+                          self.network, description=LONG_DESCRIPTION_NG)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('5b69a905-3a84-43a4-807a-1a67ab85caeb')
+    def test_add_port_with_nonexist_tenant_id(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_port,
+                          self.network,
+                          project_id=uuidutils.generate_uuid())
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('7cf473ae-7ec8-4834-ae17-9ef6ec6b8a32')
+    def test_add_port_with_nonexist_network_id(self):
+        network = self.network
+        network['id'] = uuidutils.generate_uuid()
+        self.assertRaises(lib_exc.NotFound,
+                          self.create_port,
+                          network)
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('cad2d349-25fa-490e-9675-cd2ea24164bc')
+    def test_add_port_with_nonexist_security_groups_id(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.create_port,
+                          self.network,
+                          security_groups=[uuidutils.generate_uuid()])
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('9b0a4152-9aa4-4169-9b2c-579609e2fb4a')
+    def test_add_port_with_illegal_ip(self):
+        self.assertRaises(lib_exc.BadRequest,
+                          self.create_port,
+                          self.network,
+                          allowed_address_pairs=[{"ip_address: 12.12.12.a"}])
diff --git a/neutron_tempest_plugin/api/test_routers_negative.py b/neutron_tempest_plugin/api/test_routers_negative.py
index 8700761..86d58e2 100644
--- a/neutron_tempest_plugin/api/test_routers_negative.py
+++ b/neutron_tempest_plugin/api/test_routers_negative.py
@@ -19,6 +19,10 @@
 import testtools
 
 from neutron_tempest_plugin.api import base_routers as base
+from neutron_tempest_plugin import config
+
+
+CONF = config.CONF
 
 
 class RoutersNegativeTestBase(base.BaseRouterTest):
@@ -88,6 +92,23 @@
             self.client.add_router_interface_with_port_id,
             self.router['id'], invalid_id)
 
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('dad7a8ba-2726-11eb-82dd-74e5f9e2a801')
+    def test_remove_associated_ports(self):
+        self.client.update_router(
+            self.router['id'],
+            external_gateway_info={
+                'network_id': CONF.network.public_network_id})
+        network = self.create_network()
+        subnet = self.create_subnet(network)
+        self.create_router_interface(self.router['id'], subnet['id'])
+        port_ids = [
+            item['id'] for item in self.admin_client.list_ports(
+                device_id=self.router['id'])['ports']]
+        for port_id in port_ids:
+            with testtools.ExpectedException(lib_exc.Conflict):
+                self.admin_client.delete_port(port_id)
+
 
 class DvrRoutersNegativeTest(RoutersNegativeTestBase):
 
diff --git a/neutron_tempest_plugin/common/ssh.py b/neutron_tempest_plugin/common/ssh.py
index fa731d8..8334521 100644
--- a/neutron_tempest_plugin/common/ssh.py
+++ b/neutron_tempest_plugin/common/ssh.py
@@ -19,7 +19,6 @@
 
 from oslo_log import log
 import paramiko
-import six
 from tempest.lib.common import ssh
 from tempest.lib import exceptions
 import tenacity
@@ -33,13 +32,7 @@
 
 
 RETRY_EXCEPTIONS = (exceptions.TimeoutException, paramiko.SSHException,
-                    socket.error)
-if six.PY2:
-    # NOTE(ralonsoh): TimeoutError was added in 3.3 and corresponds to
-    # OSError(errno.ETIMEDOUT)
-    RETRY_EXCEPTIONS += (OSError, )
-else:
-    RETRY_EXCEPTIONS += (TimeoutError, )
+                    socket.error, TimeoutError)
 
 
 class Client(ssh.Client):
@@ -293,6 +286,13 @@
                 command=shell, host=self.host, script=script, stderr=stderr,
                 stdout=stdout, exit_status=exit_status)
 
+    def get_hostname(self):
+        """Retrieve the remote machine hostname"""
+        try:
+            return self.exec_command('hostname')
+        except exceptions.SSHExecCommandFailed:
+            return self.exec_command('cat /etc/hostname')
+
 
 def _buffer_to_string(data_buffer, encoding):
     return data_buffer.decode(encoding).replace("\r\n", "\n").replace(
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index c0e21c1..2290d0f 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -120,18 +120,6 @@
                     'This is required if advanced image has to be used in '
                     'tests.'),
 
-    # Enable/disable metadata over IPv6 tests. This feature naturally
-    # does not have an API extension, but at the time of first implementation
-    # it works only on victoria+ deployments with dhcp- and/or l3-agents
-    # (which in the gate is the same as non-ovn jobs).
-    cfg.BoolOpt('ipv6_metadata',
-                default=True,
-                help='Enable metadata over IPv6 tests where the feature is '
-                     'implemented, disable where it is not. Use this instead '
-                     'of network-feature-enabled.api_extensions, since API '
-                     'extensions do not make sense for a feature not '
-                     'exposed on the API.'),
-
     # Option for creating QoS policies configures as "shared".
     # The default is false in order to prevent undesired usage
     # while testing in parallel.
diff --git a/neutron_tempest_plugin/fwaas/api/test_fwaasv2_extensions.py b/neutron_tempest_plugin/fwaas/api/test_fwaasv2_extensions.py
index f085e6d..0dd18f1 100644
--- a/neutron_tempest_plugin/fwaas/api/test_fwaasv2_extensions.py
+++ b/neutron_tempest_plugin/fwaas/api/test_fwaasv2_extensions.py
@@ -13,7 +13,6 @@
 #    under the License.
 
 import netaddr
-import six
 
 from tempest.common import utils
 from tempest import config
@@ -212,7 +211,7 @@
         # show a created firewall rule
         fw_rule = self.firewall_rules_client.show_firewall_rule(
             self.fw_rule_1['id'])
-        for key, value in six.iteritems(fw_rule['firewall_rule']):
+        for key, value in fw_rule['firewall_rule'].items():
             if key != 'firewall_policy_id':
                 self.assertEqual(self.fw_rule_1[key], value)
             # This check is placed because we cannot modify policy during
@@ -258,7 +257,7 @@
         fw_policy = self.firewall_policies_client.show_firewall_policy(
             self.fw_policy_1['id'])
         fw_policy = fw_policy['firewall_policy']
-        for key, value in six.iteritems(fw_policy):
+        for key, value in fw_policy.items():
             self.assertEqual(self.fw_policy_1[key], value)
 
     @decorators.idempotent_id('48dfcd75-3924-479d-bb65-b3ed33397663')
@@ -283,7 +282,7 @@
             fwg_id)
         fwg = firewall_group['firewall_group']
 
-        for key, value in six.iteritems(fwg):
+        for key, value in fwg.items():
             if key == 'status':
                 continue
             self.assertEqual(created_firewall_group[key], value)
diff --git a/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base.py b/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base.py
index f752436..b4be57b 100644
--- a/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base.py
+++ b/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base.py
@@ -19,7 +19,6 @@
 import time
 
 import netaddr
-import six
 
 from os_ken.tests.integrated.common import docker_base as ctn_base
 from tempest.common import utils
@@ -125,10 +124,10 @@
         while True:
             with self.lock:
                 try:
-                    yield (i, str(six.next(subnet_gen)))
+                    yield (i, str(next(subnet_gen)))
                 except StopIteration:
                     subnet_gen = netaddr.iter_iprange(start, end, step=step)
-                    yield (i, str(six.next(subnet_gen)))
+                    yield (i, str(next(subnet_gen)))
                 i += 1
 
     def net_resource_cleanup(self):
diff --git a/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base_test_proto.py b/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base_test_proto.py
index 1bcf5b1..643620f 100644
--- a/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base_test_proto.py
+++ b/neutron_tempest_plugin/neutron_dynamic_routing/scenario/base_test_proto.py
@@ -14,7 +14,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import six
 from tempest import config
 
 from neutron_tempest_plugin.neutron_dynamic_routing.scenario import base
@@ -28,7 +27,7 @@
 
     def _test_check_neighbor_established(self, ip_version):
         self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
-        num, subnet = six.next(self.tnet_gen)
+        num, subnet = next(self.tnet_gen)
         mask = '/' + str(self.TPool.prefixlen)
         TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                         cidr=subnet + mask, router=None)
@@ -47,7 +46,7 @@
 
     def _test_check_advertised_tenant_network(self, ip_version):
         self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
-        num, subnet = six.next(self.tnet_gen)
+        num, subnet = next(self.tnet_gen)
         mask = '/' + str(self.TPool.prefixlen)
         TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                         cidr=subnet + mask, router=None)
@@ -73,7 +72,7 @@
         tnets = []
         tnets_cidr = []
         for i in range(0, 3):
-            num, subnet = six.next(self.tnet_gen)
+            num, subnet = next(self.tnet_gen)
             mask = '/' + str(self.TPool.prefixlen)
             TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                             cidr=subnet + mask, router=None)
@@ -102,7 +101,7 @@
         for (bgp_peer_args, r_as_ip) in zip(self.bgp_peer_args,
                                             self.r_as_ip):
             bgp_peer_args['peer_ip'] = r_as_ip.split('/')[0]
-        num, subnet = six.next(self.tnet_gen)
+        num, subnet = next(self.tnet_gen)
         mask = '/' + str(self.TPool.prefixlen)
         TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                         cidr=subnet + mask, router=None)
@@ -124,7 +123,7 @@
         for (bgp_peer_args, r_as_ip) in zip(self.bgp_peer_args,
                                             self.r_as_ip):
             bgp_peer_args['peer_ip'] = r_as_ip.split('/')[0]
-        num, subnet = six.next(self.tnet_gen)
+        num, subnet = next(self.tnet_gen)
         mask = '/' + str(self.TPool.prefixlen)
         TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                         cidr=subnet + mask, router=None)
diff --git a/neutron_tempest_plugin/neutron_dynamic_routing/scenario/basic/test_basic.py b/neutron_tempest_plugin/neutron_dynamic_routing/scenario/basic/test_basic.py
index 1c680f9..90a6815 100644
--- a/neutron_tempest_plugin/neutron_dynamic_routing/scenario/basic/test_basic.py
+++ b/neutron_tempest_plugin/neutron_dynamic_routing/scenario/basic/test_basic.py
@@ -15,7 +15,6 @@
 #    under the License.
 
 from os_ken.tests.integrated.common import docker_base as ctn_base
-import six
 from tempest import config
 from tempest.lib import decorators
 
@@ -31,7 +30,7 @@
     @decorators.idempotent_id('cc615252-c6cb-4d75-a70e-608fb2c3736a')
     def test_schedule_added_speaker(self):
         self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
-        num, subnet = six.next(self.tnet_gen)
+        num, subnet = next(self.tnet_gen)
         mask = '/' + str(self.TPool.prefixlen)
         TNet = s_base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                           cidr=subnet + mask, router=None)
@@ -51,7 +50,7 @@
     @decorators.idempotent_id('ce98c33c-0ffa-49ae-b365-da836406793b')
     def test_unschedule_deleted_speaker(self):
         self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
-        num, subnet = six.next(self.tnet_gen)
+        num, subnet = next(self.tnet_gen)
         mask = '/' + str(self.TPool.prefixlen)
         TNet = s_base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                           cidr=subnet + mask, router=None)
@@ -77,7 +76,7 @@
     @decorators.idempotent_id('aa6c565c-ded3-413b-8dc9-3928b3b0e38f')
     def test_remove_add_speaker_agent(self):
         self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
-        num, subnet = six.next(self.tnet_gen)
+        num, subnet = next(self.tnet_gen)
         mask = '/' + str(self.TPool.prefixlen)
         TNet = s_base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
                           cidr=subnet + mask, router=None)
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index b2f9af3..127701c 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -205,7 +205,6 @@
         else:
             router = cls.create_admin_router(**kwargs)
         LOG.debug("Created router %s", router['name'])
-        cls.routers.append(router)
         return router
 
     @removals.remove(version='Stein',
@@ -307,13 +306,19 @@
             self._log_ns_network_status(ns_name=ns_name)
 
     def _log_ns_network_status(self, ns_name=None):
-        local_ips = ip_utils.IPCommand(namespace=ns_name).list_addresses()
+        try:
+            local_ips = ip_utils.IPCommand(namespace=ns_name).list_addresses()
+            local_routes = ip_utils.IPCommand(namespace=ns_name).list_routes()
+            arp_table = ip_utils.arp_table()
+        except exceptions.ShellCommandFailed:
+            LOG.debug('Namespace %s has been deleted synchronously during the '
+                      'host network collection process', ns_name)
+            return
+
         LOG.debug('Namespace %s; IP Addresses:\n%s',
                   ns_name, '\n'.join(str(r) for r in local_ips))
-        local_routes = ip_utils.IPCommand(namespace=ns_name).list_routes()
         LOG.debug('Namespace %s; Local routes:\n%s',
                   ns_name, '\n'.join(str(r) for r in local_routes))
-        arp_table = ip_utils.arp_table()
         LOG.debug('Namespace %s; Local ARP table:\n%s',
                   ns_name, '\n'.join(str(r) for r in arp_table))
 
@@ -475,7 +480,7 @@
     def wait_for_guest_os_ready(self, server, client=None):
         if not CONF.compute_feature_enabled.console_output:
             LOG.debug('Console output not supported, cannot check if server '
-                      '%s is ready.', server['server']['id'])
+                      '%s is ready.', server['id'])
             return
 
         client = client or self.os_primary.servers_client
@@ -513,7 +518,7 @@
                     pkey=self.keypair['private_key'],
                     **kwargs)
                 self.assertIn(server['name'],
-                              ssh_client.exec_command('hostname'))
+                              ssh_client.get_hostname())
         except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
             LOG.debug(ssh_e)
             if log_errors:
diff --git a/neutron_tempest_plugin/scenario/test_dhcp.py b/neutron_tempest_plugin/scenario/test_dhcp.py
new file mode 100644
index 0000000..b95eaa2
--- /dev/null
+++ b/neutron_tempest_plugin/scenario/test_dhcp.py
@@ -0,0 +1,94 @@
+# 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 paramiko import ssh_exception as ssh_exc
+from tempest.common import utils
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+from neutron_tempest_plugin.common import ssh
+from neutron_tempest_plugin import config
+from neutron_tempest_plugin.scenario import base
+
+CONF = config.CONF
+LOG = log.getLogger(__name__)
+
+
+class DHCPTest(base.BaseTempestTestCase):
+
+    credentials = ['primary', 'admin']
+    force_tenant_isolation = False
+
+    @classmethod
+    def resource_setup(cls):
+        super(DHCPTest, cls).resource_setup()
+        cls.rand_name = data_utils.rand_name(
+            cls.__name__.rsplit('.', 1)[-1])
+        cls.network = cls.create_network(name=cls.rand_name)
+        cls.subnet = cls.create_subnet(
+            network=cls.network, name=cls.rand_name)
+        cls.router = cls.create_router_by_client()
+        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+        cls.keypair = cls.create_keypair(name=cls.rand_name)
+        cls.security_group = cls.create_security_group(name=cls.rand_name)
+        cls.create_loginable_secgroup_rule(cls.security_group['id'])
+
+    @utils.requires_ext(extension='extra_dhcp_opt', service='network')
+    @decorators.idempotent_id('58f7c094-1980-4e03-b0d3-6c4dd27217b1')
+    def test_extra_dhcp_opts(self):
+        """This test case tests DHCP extra options configured for Neutron port.
+
+        Test is checking just extra option "15" which is domain-name
+        according to the RFC 2132:
+        https://tools.ietf.org/html/rfc2132#section-5.3
+
+        To test that option, there is spawned VM connected to the port with
+        configured extra_dhcp_opts and test asserts that search domain name is
+        configured inside VM in /etc/resolv.conf file
+        """
+
+        test_domain = "test.domain"
+        extra_dhcp_opts = [
+            {'opt_name': 'domain-name',
+             'opt_value': '"%s"' % test_domain}]
+        port = self.create_port(
+            network=self.network, name=self.rand_name,
+            security_groups=[self.security_group['id']],
+            extra_dhcp_opts=extra_dhcp_opts)
+        floating_ip = self.create_floatingip(port=port)
+
+        server = self.create_server(
+            flavor_ref=CONF.compute.flavor_ref,
+            image_ref=CONF.compute.image_ref,
+            key_name=self.keypair['name'],
+            networks=[{'port': port['id']}])
+        self.wait_for_server_active(server['server'])
+        self.wait_for_guest_os_ready(server['server'])
+
+        try:
+            ssh_client = ssh.Client(
+                floating_ip['floating_ip_address'],
+                CONF.validation.image_ssh_user,
+                pkey=self.keypair['private_key'])
+            vm_resolv_conf = ssh_client.exec_command(
+                "cat /etc/resolv.conf")
+            self.assertIn(test_domain, vm_resolv_conf)
+        except (lib_exc.SSHTimeout,
+                ssh_exc.AuthenticationException,
+                AssertionError) as error:
+            LOG.debug(error)
+            self._log_console_output([server])
+            self._log_local_network_status()
+            raise
diff --git a/neutron_tempest_plugin/scenario/test_floatingip.py b/neutron_tempest_plugin/scenario/test_floatingip.py
index 8c8d163..262f429 100644
--- a/neutron_tempest_plugin/scenario/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/test_floatingip.py
@@ -341,6 +341,15 @@
     def resource_setup(cls):
         super(FloatingIPQosTest, cls).resource_setup()
 
+    def skip_if_no_extension_enabled_in_l3_agents(self, extension):
+        l3_agents = self.os_admin.network_client.list_agents(
+                binary='neutron-l3-agent')['agents']
+        for agent in l3_agents:
+            if extension in agent['configurations'].get('extensions', []):
+                return
+        raise self.skipTest("No L3 agent with '%s' extension enabled found." %
+                            extension)
+
     @decorators.idempotent_id('5eb48aea-eaba-4c20-8a6f-7740070a0aa3')
     def test_qos(self):
         """Test floating IP is binding to a QoS policy with
@@ -351,6 +360,8 @@
            received / elapsed time.
         """
 
+        self.skip_if_no_extension_enabled_in_l3_agents("fip_qos")
+
         self._test_basic_resources()
         policy_id = self._create_qos_policy()
         ssh_client = self._create_ssh_client()
diff --git a/neutron_tempest_plugin/scenario/test_internal_dns.py b/neutron_tempest_plugin/scenario/test_internal_dns.py
index c620233..406af3d 100644
--- a/neutron_tempest_plugin/scenario/test_internal_dns.py
+++ b/neutron_tempest_plugin/scenario/test_internal_dns.py
@@ -59,7 +59,7 @@
             CONF.validation.image_ssh_user,
             pkey=self.keypair['private_key'])
 
-        self.assertIn('luke', ssh_client.exec_command('hostname'))
+        self.assertIn('luke', ssh_client.get_hostname())
 
         leia_port = self.client.list_ports(
             network_id=self.network['id'],
diff --git a/neutron_tempest_plugin/scenario/test_ipv6.py b/neutron_tempest_plugin/scenario/test_ipv6.py
index 732c96d..4237d4f 100644
--- a/neutron_tempest_plugin/scenario/test_ipv6.py
+++ b/neutron_tempest_plugin/scenario/test_ipv6.py
@@ -84,6 +84,7 @@
     @tempest_utils.requires_ext(extension="router", service="network")
     def resource_setup(cls):
         super(IPv6Test, cls).resource_setup()
+        cls.reserve_external_subnet_cidrs()
         cls._setup_basic_resources()
 
     @classmethod
diff --git a/neutron_tempest_plugin/scenario/test_metadata.py b/neutron_tempest_plugin/scenario/test_metadata.py
index 3897183..91ecc97 100644
--- a/neutron_tempest_plugin/scenario/test_metadata.py
+++ b/neutron_tempest_plugin/scenario/test_metadata.py
@@ -16,6 +16,7 @@
 
 from neutron_lib import constants as nlib_const
 from oslo_log import log as logging
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 import testtools
@@ -45,10 +46,17 @@
     force_tenant_isolation = False
 
     @classmethod
+    def skip_checks(cls):
+        super(MetadataTest, cls).skip_checks()
+        if not utils.is_network_feature_enabled('ipv6_metadata'):
+            raise cls.skipException("Metadata over IPv6 is not enabled")
+
+    @classmethod
     def resource_setup(cls):
         super(MetadataTest, cls).resource_setup()
         cls.rand_name = data_utils.rand_name(
             cls.__name__.rsplit('.', 1)[-1])
+        cls.reserve_external_subnet_cidrs()
         cls.network = cls.create_network(name=cls.rand_name)
         cls.subnet_v4 = cls.create_subnet(
             network=cls.network, name=cls.rand_name)
@@ -113,11 +121,9 @@
         return interface
 
     @testtools.skipUnless(
-        (CONF.neutron_plugin_options.ipv6_metadata and
-         (CONF.neutron_plugin_options.advanced_image_ref or
-          CONF.neutron_plugin_options.default_image_is_advanced)),
-        'Advanced image and neutron_plugin_options.ipv6_metadata=True '
-        'is required to run this test.')
+        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('e680949a-f1cc-11ea-b49a-cba39bbbe5ad')
     def test_metadata_routed(self):
         use_advanced_image = (
diff --git a/neutron_tempest_plugin/scenario/test_port_forwardings.py b/neutron_tempest_plugin/scenario/test_port_forwardings.py
index fb6410c..a4711ae 100644
--- a/neutron_tempest_plugin/scenario/test_port_forwardings.py
+++ b/neutron_tempest_plugin/scenario/test_port_forwardings.py
@@ -120,7 +120,6 @@
                 lambda: _message_received(server, ssh_client, expected_msg),
                 **wait_params)
 
-    @test.unstable_test("bug 1896735")
     @decorators.idempotent_id('ab40fc48-ca8d-41a0-b2a3-f6679c847bfe')
     def test_port_forwarding_to_2_servers(self):
         servers = self._prepare_resources(num_servers=2,
@@ -130,7 +129,6 @@
         # And now test UDP port forwarding using nc
         self._test_udp_port_forwarding(servers)
 
-    @test.unstable_test("bug 1896735")
     @decorators.idempotent_id('aa19d46c-a4a6-11ea-bb37-0242ac130002')
     def test_port_forwarding_editing_and_deleting_tcp_rule(self):
         test_ext_port = 3333
diff --git a/neutron_tempest_plugin/scenario/test_qos.py b/neutron_tempest_plugin/scenario/test_qos.py
index 6cd6b25..77520a7 100644
--- a/neutron_tempest_plugin/scenario/test_qos.py
+++ b/neutron_tempest_plugin/scenario/test_qos.py
@@ -191,32 +191,26 @@
 
     @decorators.idempotent_id('00682a0c-b72e-11e8-b81e-8c16450ea513')
     def test_qos_basic_and_update(self):
-        """This test covers both:
+        """This test covers following scenarios:
 
-            1) Basic QoS functionality
-            This is a basic test that check that a QoS policy with
-            a bandwidth limit rule is applied correctly by sending
-            a file from the instance to the test node.
-            Then calculating the bandwidth every ~1 sec by the number of bits
-            received / elapsed time.
+            1) Create a QoS policy associated with the network.
+            Expected result: BW is limited according the values set in
+            QoS policy rule.
 
-            2) Update QoS policy
-            Administrator has the ability to update existing QoS policy,
-            this test is planned to verify that:
-            - actual BW is affected as expected after updating QoS policy.
-            Test scenario:
-            1) Associating QoS Policy with "Original_bandwidth"
-               to the test node
-            2) BW validation - by downloading file on test node.
-               ("Original_bandwidth" is expected)
-            3) Updating existing QoS Policy to a new BW value
-               "Updated_bandwidth"
-            4) BW validation - by downloading file on test node.
-               ("Updated_bandwidth" is expected)
-            Note:
-            There are two options to associate QoS policy to VM:
-            "Neutron Port" or "Network", in this test
-            both options are covered.
+            2) Update QoS policy associated with the network.
+            Expected result: BW is limited according the new values
+            set in QoS policy rule.
+
+            3) Create a new QoS policy associated with the VM port.
+            Expected result: BW is limited according the values set in
+            new QoS policy rule.
+            Note: Neutron port is prioritized higher than Network, means
+            that: "Neutron Port Priority" is also covered.
+
+            4) Update QoS policy associated with the VM port.
+            Expected result: BW is limited according the new values set
+            in QoS policy rule.
+
         """
 
         # Setup resources
@@ -244,7 +238,10 @@
             self.fip['floating_ip_address'],
             port=self.NC_PORT),
             timeout=self.CHECK_TIMEOUT,
-            sleep=1)
+            sleep=1,
+            exception=RuntimeError(
+                'Failed scenario: "Create a QoS policy associated with'
+                ' the network" Actual BW is not as expected!'))
 
         # As admin user update QoS rule
         self.os_admin.network_client.update_bandwidth_limit_rule(
@@ -261,7 +258,10 @@
             port=self.NC_PORT,
             expected_bw=QoSTest.LIMIT_BYTES_SEC * 2),
             timeout=self.CHECK_TIMEOUT,
-            sleep=1)
+            sleep=1,
+            exception=RuntimeError(
+                'Failed scenario: "Update QoS policy associated with'
+                ' the network" Actual BW is not as expected!'))
 
         # Create a new QoS policy
         bw_limit_policy_id_new = self._create_qos_policy()
@@ -284,7 +284,10 @@
             self.fip['floating_ip_address'],
             port=self.NC_PORT),
             timeout=self.CHECK_TIMEOUT,
-            sleep=1)
+            sleep=1,
+            exception=RuntimeError(
+                'Failed scenario: "Create a new QoS policy associated with'
+                ' the VM port" Actual BW is not as expected!'))
 
         # As admin user update QoS rule
         self.os_admin.network_client.update_bandwidth_limit_rule(
@@ -301,7 +304,10 @@
             port=self.NC_PORT,
             expected_bw=QoSTest.LIMIT_BYTES_SEC * 3),
             timeout=self.CHECK_TIMEOUT,
-            sleep=1)
+            sleep=1,
+            exception=RuntimeError(
+                'Failed scenario: "Update QoS policy associated with'
+                ' the VM port" Actual BW is not as expected!'))
 
     @decorators.idempotent_id('66e5673e-0522-11ea-8d71-362b9e155667')
     def test_attach_previously_used_port_to_new_instance(self):
diff --git a/neutron_tempest_plugin/scenario/test_trunk.py b/neutron_tempest_plugin/scenario/test_trunk.py
index 98fe6ae..8f260ea 100644
--- a/neutron_tempest_plugin/scenario/test_trunk.py
+++ b/neutron_tempest_plugin/scenario/test_trunk.py
@@ -15,6 +15,7 @@
 import collections
 
 from neutron_lib import constants
+from neutron_lib.utils import test
 from oslo_log import log as logging
 from tempest.common import utils as tutils
 from tempest.lib.common.utils import data_utils
@@ -246,6 +247,7 @@
             self._wait_for_trunk(vm.trunk)
             self._assert_has_ssh_connectivity(vm1.ssh_client)
 
+    @test.unstable_test("bug 1897796")
     @testtools.skipUnless(
         (CONF.neutron_plugin_options.advanced_image_ref or
          CONF.neutron_plugin_options.default_image_is_advanced),
diff --git a/neutron_tempest_plugin/services/network/json/network_client.py b/neutron_tempest_plugin/services/network/json/network_client.py
index 0b2544b..2678d73 100644
--- a/neutron_tempest_plugin/services/network/json/network_client.py
+++ b/neutron_tempest_plugin/services/network/json/network_client.py
@@ -11,9 +11,9 @@
 #    under the License.
 
 import time
+from urllib import parse as urlparse
 
 from oslo_serialization import jsonutils
-from six.moves.urllib import parse as urlparse
 from tempest.lib.common import rest_client as service_client
 from tempest.lib import exceptions as lib_exc
 
@@ -923,8 +923,6 @@
         return service_client.ResponseBody(resp, body)
 
     def list_security_groups(self, **kwargs):
-        post_body = {'security_groups': kwargs}
-        body = jsonutils.dumps(post_body)
         uri = '%s/security-groups' % self.uri_prefix
         if kwargs:
             uri += '?' + urlparse.urlencode(kwargs, doseq=1)
@@ -941,8 +939,6 @@
         return service_client.ResponseBody(resp, body)
 
     def list_ports(self, **kwargs):
-        post_body = {'ports': kwargs}
-        body = jsonutils.dumps(post_body)
         uri = '%s/ports' % self.uri_prefix
         if kwargs:
             uri += '?' + urlparse.urlencode(kwargs, doseq=1)
diff --git a/requirements.txt b/requirements.txt
index 3edf7dc..47dd923 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,7 +11,6 @@
 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
 oslo.utils>=3.33.0 # Apache-2.0
 paramiko>=2.0.0 # LGPLv2.1+
-six>=1.10.0 # MIT
 tempest>=17.1.0 # Apache-2.0
 tenacity>=3.2.1 # Apache-2.0
 ddt>=1.0.1 # MIT
diff --git a/tox.ini b/tox.ini
index eecd16e..3c18fbf 100644
--- a/tox.ini
+++ b/tox.ini
@@ -14,7 +14,7 @@
    OS_STDOUT_CAPTURE={env:OS_STDOUT_CAPTURE:true}
    OS_STDERR_CAPTURE={env:OS_STDERR_CAPTURE:true}
 deps =
-  -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+  -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
   -r{toxinidir}/test-requirements.txt
 commands = stestr run --slowest {posargs}
 
diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml
index 2bd6f5a..cc1479b 100644
--- a/zuul.d/base.yaml
+++ b/zuul.d/base.yaml
@@ -25,7 +25,6 @@
       tempest_plugins:
         - neutron-tempest-plugin
       devstack_services:
-        tls-proxy: false
         tempest: true
         neutron-dns: true
         neutron-qos: true
@@ -38,6 +37,12 @@
         neutron-tag-ports-during-bulk-creation: true
         br-ex-tcpdump: true
         br-int-flows: 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
@@ -69,11 +74,6 @@
           $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:
             neutron_plugin_options:
@@ -104,7 +104,10 @@
       # default test timeout set to 1200 seconds may be not enough if job is
       # run on slow node
       tempest_test_timeout: 2400
-      tempest_test_regex: ^neutron_tempest_plugin\.scenario
+      tempest_test_regex: "\
+          (^neutron_tempest_plugin.scenario)|\
+          (^tempest.api.compute.servers.test_attach_interfaces)|\
+          (^tempest.api.compute.servers.test_multiple_create)"
       devstack_localrc:
         PHYSICAL_NETWORK: default
         CIRROS_VERSION: 0.5.1
@@ -113,6 +116,4 @@
         ADVANCED_INSTANCE_TYPE: ds512M
         ADVANCED_INSTANCE_USER: ubuntu
         BUILD_TIMEOUT: 784
-      devstack_services:
-        cinder: true
-
+      tempest_concurrency: 3  # out of 4
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index 728eed8..5325f67 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -79,9 +79,13 @@
         - uplink-status-propagation
       network_api_extensions_tempest:
         - dvr
+      network_available_features: &available_features
+        - ipv6_metadata
       tempest_test_regex: ^neutron_tempest_plugin\.api
       devstack_services:
         neutron-log: true
+      devstack_localrc:
+        NEUTRON_DEPLOY_MOD_WSGI: true
       devstack_local_conf:
         post-config:
           # NOTE(slaweq): We can get rid of this hardcoded absolute path when
@@ -99,6 +103,7 @@
     timeout: 10000
     vars:
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         Q_AGENT: openvswitch
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
@@ -118,6 +123,8 @@
               bridge_mappings: public:br-ex
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
             neutron_plugin_options:
               available_type_drivers: flat,vlan,local,vxlan
 
@@ -127,6 +134,7 @@
     timeout: 10000
     vars:
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       # TODO(slaweq): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
       tempest_black_regex: "(^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)"
@@ -151,6 +159,8 @@
               firewall_driver: iptables_hybrid
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
             neutron_plugin_options:
               available_type_drivers: flat,vlan,local,vxlan
 
@@ -163,6 +173,7 @@
     pre-run: playbooks/linuxbridge-scenario-pre-run.yaml
     vars:
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         Q_AGENT: linuxbridge
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
@@ -181,6 +192,8 @@
               type_drivers: flat,vlan,local,vxlan
         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
@@ -196,9 +209,12 @@
       # TODO(slaweq): Remove test_trunk_subport_lifecycle test from the
       # blacklist when bug https://bugs.launchpad.net/neutron/+bug/1885900 will
       # be fixed
+      # TODO(jlibosva): Remove the NetworkWritableMtuTest test from the list
+      # once east/west fragmentation is supported in core OVN
       tempest_black_regex: "\
           (?:neutron_tempest_plugin.scenario.test_ipv6.IPv6Test)|\
-          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_trunk_subport_lifecycle)"
+          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_trunk_subport_lifecycle)|\
+          (^neutron_tempest_plugin.scenario.test_mtu.NetworkWritableMtuTest)"
       devstack_localrc:
         Q_AGENT: ovn
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
@@ -225,13 +241,19 @@
         q-l3: false
         q-meta: false
         q-metering: false
+        q-qos: true
+        tls-proxy: true
+        # Cinder services
+        c-api: false
+        c-bak: false
+        c-sch: false
+        c-vol: false
+        cinder: false
         s-account: false
         s-container-sync: false
         s-container: false
         s-object: false
         s-proxy: false
-        tls-proxy: true
-        q-qos: true
       devstack_local_conf:
         post-config:
           $NEUTRON_CONF:
@@ -242,9 +264,10 @@
               type_drivers: local,flat,vlan,geneve
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               available_type_drivers: local,flat,vlan,geneve
-              ipv6_metadata: False
               is_igmp_snooping_enabled: True
 
 - job:
@@ -296,7 +319,12 @@
         neutron-trunk: true
         neutron-log: true
         neutron-port-forwarding: true
-        cinder: 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
@@ -347,6 +375,8 @@
               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
@@ -364,6 +394,9 @@
           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
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 0355f69..dc6e56c 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -177,22 +177,10 @@
         - neutron-tempest-plugin-sfc-train
         - neutron-tempest-plugin-sfc-ussuri
         - neutron-tempest-plugin-sfc-victoria
-        - neutron-tempest-plugin-bgpvpn-bagpipe:
-            # TODO(slaweq): switch it to be voting when bug
-            # https://bugs.launchpad.net/networking-bagpipe/+bug/1897408
-            # will be fixed
-            voting: false
+        - neutron-tempest-plugin-bgpvpn-bagpipe
         - neutron-tempest-plugin-bgpvpn-bagpipe-train
-        - neutron-tempest-plugin-bgpvpn-bagpipe-ussuri:
-            # TODO(slaweq): switch it to be voting when bug
-            # https://bugs.launchpad.net/networking-bagpipe/+bug/1897408
-            # will be fixed
-            voting: false
-        - neutron-tempest-plugin-bgpvpn-bagpipe-victoria:
-            # TODO(slaweq): switch it to be voting when bug
-            # https://bugs.launchpad.net/networking-bagpipe/+bug/1897408
-            # will be fixed
-            voting: false
+        - neutron-tempest-plugin-bgpvpn-bagpipe-ussuri
+        - neutron-tempest-plugin-bgpvpn-bagpipe-victoria
         - neutron-tempest-plugin-fwaas-train:
             # TODO(slaweq): switch it to be voting when bug
             # https://bugs.launchpad.net/neutron/+bug/1858645 will be fixed
@@ -211,8 +199,5 @@
     gate:
       jobs:
         - neutron-tempest-plugin-sfc
-        # TODO(slaweq): make bgpvpn-bagpipe job gating again when
-        # https://bugs.launchpad.net/networking-bagpipe/+bug/1897408
-        # will be fixed
-        #- neutron-tempest-plugin-bgpvpn-bagpipe
+        - neutron-tempest-plugin-bgpvpn-bagpipe
         - neutron-tempest-plugin-dynamic-routing
diff --git a/zuul.d/queens_jobs.yaml b/zuul.d/queens_jobs.yaml
index b0ee336..e1ecc00 100644
--- a/zuul.d/queens_jobs.yaml
+++ b/zuul.d/queens_jobs.yaml
@@ -65,7 +65,10 @@
         - 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
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
@@ -87,6 +90,7 @@
     vars:
       branch_override: stable/queens
       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
       # NOTE(bcafarel): remove DNS test as queens pinned version does not have
@@ -117,6 +121,7 @@
     vars:
       branch_override: stable/queens
       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: "\
diff --git a/zuul.d/rocky_jobs.yaml b/zuul.d/rocky_jobs.yaml
index 6eb8c15..4b6145b 100644
--- a/zuul.d/rocky_jobs.yaml
+++ b/zuul.d/rocky_jobs.yaml
@@ -75,6 +75,7 @@
       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
@@ -108,6 +109,8 @@
     vars: &scenario_vars_rocky
       branch_override: stable/rocky
       network_api_extensions: *api_extensions
+      network_available_features: &available_features
+        -
       devstack_localrc:
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
diff --git a/zuul.d/stein_jobs.yaml b/zuul.d/stein_jobs.yaml
index ff6ed38..9de8384 100644
--- a/zuul.d/stein_jobs.yaml
+++ b/zuul.d/stein_jobs.yaml
@@ -73,7 +73,10 @@
         - uplink-status-propagation
       network_api_extensions_tempest:
         - dvr
+      network_available_features: &available_features
+        -
       devstack_localrc:
+        NEUTRON_DEPLOY_MOD_WSGI: false
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
 
 - job:
@@ -84,11 +87,14 @@
     vars:
       branch_override: stable/stein
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -100,11 +106,14 @@
     vars:
       branch_override: stable/stein
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -116,11 +125,14 @@
     vars:
       branch_override: stable/stein
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
diff --git a/zuul.d/train_jobs.yaml b/zuul.d/train_jobs.yaml
index a9cc5be..0785924 100644
--- a/zuul.d/train_jobs.yaml
+++ b/zuul.d/train_jobs.yaml
@@ -78,7 +78,10 @@
         - uplink-status-propagation
       network_api_extensions_tempest:
         - dvr
+      network_available_features: &available_features
+        -
       devstack_localrc:
+        NEUTRON_DEPLOY_MOD_WSGI: false
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
 
 - job:
@@ -89,11 +92,14 @@
     vars:
       branch_override: stable/train
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -105,11 +111,14 @@
     vars:
       branch_override: stable/train
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -121,11 +130,14 @@
     vars:
       branch_override: stable/train
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
diff --git a/zuul.d/ussuri_jobs.yaml b/zuul.d/ussuri_jobs.yaml
index 135d9f5..b71a460 100644
--- a/zuul.d/ussuri_jobs.yaml
+++ b/zuul.d/ussuri_jobs.yaml
@@ -82,9 +82,13 @@
         - uplink-status-propagation
       network_api_extensions_tempest:
         - dvr
+      network_available_features: &available_features
+        -
       devstack_localrc:
+        NEUTRON_DEPLOY_MOD_WSGI: false
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
 
+
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-ussuri
     parent: neutron-tempest-plugin-scenario-openvswitch
@@ -93,14 +97,18 @@
     vars:
       branch_override: stable/ussuri
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
+
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-ussuri
     parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
@@ -109,11 +117,14 @@
     vars:
       branch_override: stable/ussuri
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -125,11 +136,14 @@
     vars:
       branch_override: stable/ussuri
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
             neutron_plugin_options:
               ipv6_metadata: False
 
diff --git a/zuul.d/victoria_jobs.yaml b/zuul.d/victoria_jobs.yaml
index 0bc1e13..5543ea7 100644
--- a/zuul.d/victoria_jobs.yaml
+++ b/zuul.d/victoria_jobs.yaml
@@ -81,7 +81,10 @@
         - uplink-status-propagation
       network_api_extensions_tempest:
         - dvr
+      network_available_features: &available_features
+        - ipv6_metadata
       devstack_localrc:
+        NEUTRON_DEPLOY_MOD_WSGI: false
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
 
 - job:
@@ -91,11 +94,14 @@
     vars:
       branch_override: stable/victoria
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -106,11 +112,14 @@
     vars:
       branch_override: stable-victoria
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -121,11 +130,14 @@
     vars:
       branch_override: stable/victoria
       network_api_extensions: *api_extensions
+      network_available_features: *available_features
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
         test-config:
           $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: "{{ network_available_features | join(',') }}"
             neutron_plugin_options:
               ipv6_metadata: False
 
@@ -138,6 +150,11 @@
       network_api_extensions: *api_extensions
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            network-feature-enabled:
+              available_features: ""
 
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-victoria