Merge "Revert "Skip Floating IP QoS scenario test in DVR environment""
diff --git a/.zuul.yaml b/.zuul.yaml
index a002690..636327e 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -103,6 +103,13 @@
       - ^tox.ini$
 
 - job:
+    name: neutron-tempest-plugin-api-queens
+    parent: neutron-tempest-plugin-api
+    override-checkout: stable/queens
+    vars:
+      branch_override: stable/queens
+
+- job:
     name: neutron-tempest-plugin-scenario-linuxbridge
     parent: neutron-tempest-plugin-scenario
     timeout: 10000
@@ -119,6 +126,13 @@
               debug_iptables_rules: true
 
 - job:
+    name: neutron-tempest-plugin-scenario-linuxbridge-queens
+    parent: neutron-tempest-plugin-scenario-linuxbridge
+    override-checkout: stable/queens
+    vars:
+      branch_override: stable/queens
+
+- job:
     name: neutron-tempest-plugin-dvr-multinode-scenario
     parent: legacy-dsvm-base-multinode
     run: playbooks/neutron-tempest-plugin-dvr-multinode-scenario/run.yaml
@@ -143,6 +157,13 @@
     voting: false
 
 - job:
+    name: neutron-tempest-plugin-dvr-multinode-scenario-queens
+    parent: neutron-tempest-plugin-dvr-multinode-scenario
+    override-checkout: stable/queens
+    vars:
+      branch_override: stable/queens
+
+- job:
     name: neutron-tempest-plugin-designate-scenario
     parent: neutron-tempest-plugin-scenario
     description: Neutron designate integration scenario
@@ -168,6 +189,13 @@
       - ^setup.cfg$
     voting: false
 
+- job:
+    name: neutron-tempest-plugin-designate-scenario-queens
+    parent: neutron-tempest-plugin-designate-scenario
+    override-checkout: stable/queens
+    vars:
+      branch_override: stable/queens
+
 - project-template:
     name: neutron-tempest-plugin-jobs
     check:
@@ -182,6 +210,19 @@
         - neutron-tempest-plugin-api
         - build-openstack-sphinx-docs
 
+- project-template:
+    name: neutron-tempest-plugin-jobs-stable
+    check:
+      jobs:
+        - neutron-tempest-plugin-api-queens
+        - neutron-tempest-plugin-designate-scenario-queens
+        - neutron-tempest-plugin-dvr-multinode-scenario-queens
+        - neutron-tempest-plugin-scenario-linuxbridge-queens
+    gate:
+      jobs:
+        - neutron-tempest-plugin-api-queens
+
 - project:
     templates:
       - neutron-tempest-plugin-jobs
+      - neutron-tempest-plugin-jobs-stable
diff --git a/neutron_tempest_plugin/api/admin/test_quotas.py b/neutron_tempest_plugin/api/admin/test_quotas.py
index 1acfc18..ae773c8 100644
--- a/neutron_tempest_plugin/api/admin/test_quotas.py
+++ b/neutron_tempest_plugin/api/admin/test_quotas.py
@@ -121,17 +121,26 @@
         new_quotas = {'network': {'used': 1, 'limit': 2, 'reserved': 0},
                       'port': {'used': 1, 'limit': 2, 'reserved': 0}}
 
-        # update quota limit for tenant
-        new_quota = {'network': new_quotas['network']['limit'], 'port':
-                     new_quotas['port']['limit']}
-        quota_set = self._setup_quotas(tenant_id, **new_quota)
-
         # create test resources
         network = self._create_network(tenant_id)
         post_body = {"network_id": network['id'],
                      "tenant_id": tenant_id}
+
+        # NOTE(lucasagomes): Some backends such as OVN will create a port
+        # to be used by the metadata agent upon creating a network. In
+        # order to make this test more generic we need to calculate the
+        # number of expected used ports after the network is created and
+        # prior for the port being created
+        ports = self.admin_client.list_ports(tenant_id=tenant_id)
+        new_quotas['port']['used'] += len(ports['ports'])
+
         self._create_port(**post_body)
 
+        # update quota limit for tenant
+        new_quota = {'network': new_quotas['network']['limit'], 'port':
+                     new_quotas['port']['limit']}
+        quota_set = self._setup_quotas(tenant_id, **new_quota)
+
         # confirm from extended API quotas were changed
         # as requested for tenant
         quota_set = self.admin_client.show_details_quota(tenant_id)
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index 51a7d3e..fdd8ba9 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -58,7 +58,7 @@
     credentials = ['primary']
 
     # Default to ipv4.
-    _ip_version = 4
+    _ip_version = const.IP_VERSION_4
 
     @classmethod
     def get_client_manager(cls, credential_type=None, roles=None,
@@ -79,7 +79,8 @@
         super(BaseNetworkTest, cls).skip_checks()
         if not CONF.service_available.neutron:
             raise cls.skipException("Neutron support is required")
-        if cls._ip_version == 6 and not CONF.network_feature_enabled.ipv6:
+        if (cls._ip_version == const.IP_VERSION_6 and
+                not CONF.network_feature_enabled.ipv6):
             raise cls.skipException("IPv6 Tests are disabled.")
         for req_ext in getattr(cls, 'required_extensions', []):
             if not tutils.is_extension_enabled(req_ext, 'network'):
@@ -122,6 +123,7 @@
         cls.security_groups = []
         cls.projects = []
         cls.log_objects = []
+        cls.reserved_subnet_cidrs = set()
 
     @classmethod
     def resource_cleanup(cls):
@@ -282,50 +284,73 @@
         return network
 
     @classmethod
-    def create_subnet(cls, network, gateway='', cidr=None, mask_bits=None,
+    def create_subnet(cls, network, gateway=None, cidr=None, mask_bits=None,
                       ip_version=None, client=None, **kwargs):
-        """Wrapper utility that returns a test subnet."""
+        """Wrapper utility that returns a test subnet.
+
+        Convenient wrapper for client.create_subnet method. It reserves and
+        allocates CIDRs to avoid creating overlapping subnets.
+
+        :param network: network where to create the subnet
+        network['id'] must contain the ID of the network
+
+        :param gateway: gateway IP address
+        It can be a str or a netaddr.IPAddress
+        If gateway is not given, then it will use default address for
+        given subnet CIDR, like "192.168.0.1" for "192.168.0.0/24" CIDR
+
+        :param cidr: CIDR of the subnet to create
+        It can be either None, a str or a netaddr.IPNetwork instance
+
+        :param mask_bits: CIDR prefix length
+        It can be either None or a numeric value.
+        If cidr parameter is given then mask_bits is used to determinate a
+        sequence of valid CIDR to use as generated.
+        Please see netaddr.IPNetwork.subnet method documentation[1]
+
+        :param ip_version: ip version of generated subnet CIDRs
+        It can be None, IP_VERSION_4 or IP_VERSION_6
+        It has to match given either given CIDR and gateway
+
+        :param ip_version: numeric value (either IP_VERSION_4 or IP_VERSION_6)
+        this value must match CIDR and gateway IP versions if any of them is
+        given
+
+        :param client: client to be used to connect to network service
+
+        :param **kwargs: optional parameters to be forwarded to wrapped method
+
+        [1] http://netaddr.readthedocs.io/en/latest/tutorial_01.html#supernets-and-subnets  # noqa
+        """
 
         # allow tests to use admin client
         if not client:
             client = cls.client
 
-        # The cidr and mask_bits depend on the ip version.
-        ip_version = ip_version if ip_version is not None else cls._ip_version
-        gateway_not_set = gateway == ''
-        if ip_version == 4:
-            cidr = cidr or netaddr.IPNetwork(
-                config.safe_get_config_value(
-                    'network', 'project_network_cidr'))
-            mask_bits = (
-                mask_bits or config.safe_get_config_value(
-                    'network', 'project_network_mask_bits'))
-        elif ip_version == 6:
-            cidr = (
-                cidr or netaddr.IPNetwork(
-                    config.safe_get_config_value(
-                        'network', 'project_network_v6_cidr')))
-            mask_bits = (
-                mask_bits or config.safe_get_config_value(
-                    'network', 'project_network_v6_mask_bits'))
-        # Find a cidr that is not in use yet and create a subnet with it
-        for subnet_cidr in cidr.subnet(mask_bits):
-            if gateway_not_set:
-                gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1)
+        if gateway:
+            gateway_ip = netaddr.IPAddress(gateway)
+            if ip_version:
+                if ip_version != gateway_ip.version:
+                    raise ValueError(
+                        "Gateway IP version doesn't match IP version")
             else:
-                gateway_ip = gateway
-            try:
-                body = client.create_subnet(
-                    network_id=network['id'],
-                    cidr=str(subnet_cidr),
-                    ip_version=ip_version,
-                    gateway_ip=gateway_ip,
-                    **kwargs)
-                break
-            except lib_exc.BadRequest as e:
-                is_overlapping_cidr = 'overlaps with another subnet' in str(e)
-                if not is_overlapping_cidr:
-                    raise
+                ip_version = gateway_ip.version
+
+        for subnet_cidr in cls.get_subnet_cidrs(
+                ip_version=ip_version, cidr=cidr, mask_bits=mask_bits):
+            if cls.try_reserve_subnet_cidr(subnet_cidr):
+                gateway_ip = gateway or str(subnet_cidr.ip + 1)
+                try:
+                    body = client.create_subnet(
+                        network_id=network['id'],
+                        cidr=str(subnet_cidr),
+                        ip_version=subnet_cidr.version,
+                        gateway_ip=str(gateway_ip),
+                        **kwargs)
+                    break
+                except lib_exc.BadRequest as e:
+                    if 'overlaps with another subnet' not in str(e):
+                        raise
         else:
             message = 'Available CIDR for subnet creation could not be found'
             raise ValueError(message)
@@ -337,6 +362,93 @@
         return subnet
 
     @classmethod
+    def reserve_subnet_cidr(cls, addr, **ipnetwork_kwargs):
+        """Reserve given subnet CIDR making sure it is not used by create_subnet
+
+        :param addr: the CIDR address to be reserved
+        It can be a str or netaddr.IPNetwork instance
+
+        :param **ipnetwork_kwargs: optional netaddr.IPNetwork constructor
+        parameters
+        """
+
+        if not cls.try_reserve_subnet_cidr(addr, **ipnetwork_kwargs):
+            raise ValueError('Subnet CIDR already reserved: %r'.format(
+                addr))
+
+    @classmethod
+    def try_reserve_subnet_cidr(cls, addr, **ipnetwork_kwargs):
+        """Reserve given subnet CIDR if it hasn't been reserved before
+
+        :param addr: the CIDR address to be reserved
+        It can be a str or netaddr.IPNetwork instance
+
+        :param **ipnetwork_kwargs: optional netaddr.IPNetwork constructor
+        parameters
+
+        :return: True if it wasn't reserved before, False elsewhere.
+        """
+
+        subnet_cidr = netaddr.IPNetwork(addr, **ipnetwork_kwargs)
+        if subnet_cidr in cls.reserved_subnet_cidrs:
+            return False
+        else:
+            cls.reserved_subnet_cidrs.add(subnet_cidr)
+            return True
+
+    @classmethod
+    def get_subnet_cidrs(
+            cls, cidr=None, mask_bits=None, ip_version=None):
+        """Iterate over a sequence of unused subnet CIDR for IP version
+
+        :param cidr: CIDR of the subnet to create
+        It can be either None, a str or a netaddr.IPNetwork instance
+
+        :param mask_bits: CIDR prefix length
+        It can be either None or a numeric value.
+        If cidr parameter is given then mask_bits is used to determinate a
+        sequence of valid CIDR to use as generated.
+        Please see netaddr.IPNetwork.subnet method documentation[1]
+
+        :param ip_version: ip version of generated subnet CIDRs
+        It can be None, IP_VERSION_4 or IP_VERSION_6
+        It has to match given CIDR if given
+
+        :return: iterator over reserved CIDRs of type netaddr.IPNetwork
+
+        [1] http://netaddr.readthedocs.io/en/latest/tutorial_01.html#supernets-and-subnets  # noqa
+        """
+
+        if cidr:
+            # Generate subnet CIDRs starting from given CIDR
+            # checking it is of requested IP version
+            cidr = netaddr.IPNetwork(cidr, version=ip_version)
+        else:
+            # Generate subnet CIDRs starting from configured values
+            ip_version = ip_version or cls._ip_version
+            if ip_version == const.IP_VERSION_4:
+                mask_bits = mask_bits or config.safe_get_config_value(
+                    'network', 'project_network_mask_bits')
+                cidr = netaddr.IPNetwork(config.safe_get_config_value(
+                    'network', 'project_network_cidr'))
+            elif ip_version == const.IP_VERSION_6:
+                mask_bits = config.safe_get_config_value(
+                    'network', 'project_network_v6_mask_bits')
+                cidr = netaddr.IPNetwork(config.safe_get_config_value(
+                    'network', 'project_network_v6_cidr'))
+            else:
+                raise ValueError('Invalid IP version: {!r}'.format(ip_version))
+
+        if mask_bits:
+            subnet_cidrs = cidr.subnet(mask_bits)
+        else:
+            subnet_cidrs = iter([cidr])
+
+        for subnet_cidr in subnet_cidrs:
+            if subnet_cidr not in cls.reserved_subnet_cidrs:
+                yield subnet_cidr
+
+    @classmethod
     def create_port(cls, network, **kwargs):
         """Wrapper utility that returns a test port."""
         if CONF.network.port_vnic_type and 'binding:vnic_type' not in kwargs:
diff --git a/neutron_tempest_plugin/api/clients.py b/neutron_tempest_plugin/api/clients.py
index 875992e..14f6714 100644
--- a/neutron_tempest_plugin/api/clients.py
+++ b/neutron_tempest_plugin/api/clients.py
@@ -35,7 +35,8 @@
         'disable_ssl_certificate_validation':
             CONF.identity.disable_ssl_certificate_validation,
         'ca_certs': CONF.identity.ca_certificates_file,
-        'trace_requests': CONF.debug.trace_requests
+        'trace_requests': CONF.debug.trace_requests,
+        'proxy_url': CONF.service_clients.proxy_url
     }
 
     # NOTE: Tempest uses timeout values of compute API if project specific
diff --git a/neutron_tempest_plugin/api/test_allowed_address_pair.py b/neutron_tempest_plugin/api/test_allowed_address_pair.py
index 1c6abcc..f34cc5b 100644
--- a/neutron_tempest_plugin/api/test_allowed_address_pair.py
+++ b/neutron_tempest_plugin/api/test_allowed_address_pair.py
@@ -13,11 +13,9 @@
 #    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
-from neutron_tempest_plugin import config
 
 
 class AllowedAddressPairTestJSON(base.BaseNetworkTest):
@@ -94,9 +92,7 @@
     @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(
-            netaddr.IPNetwork(config.safe_get_config_value(
-                'network', 'project_network_cidr')))
+        cidr = str(next(self.get_subnet_cidrs()))
         self._update_port_with_address(cidr)
 
     @decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
diff --git a/neutron_tempest_plugin/api/test_dhcp_ipv6.py b/neutron_tempest_plugin/api/test_dhcp_ipv6.py
index 69b4ea0..0fab75c 100644
--- a/neutron_tempest_plugin/api/test_dhcp_ipv6.py
+++ b/neutron_tempest_plugin/api/test_dhcp_ipv6.py
@@ -58,8 +58,8 @@
         ports = body['ports']
         for port in ports:
             if (port['device_owner'].startswith(
-                    constants.DEVICE_OWNER_ROUTER_INTF)
-                and port['device_id'] in [r['id'] for r in self.routers]):
+                    constants.DEVICE_OWNER_ROUTER_INTF) and
+                port['device_id'] in [r['id'] for r in self.routers]):
                 self.client.remove_router_interface_with_port_id(
                     port['device_id'], port['id']
                 )
diff --git a/neutron_tempest_plugin/api/test_floating_ips.py b/neutron_tempest_plugin/api/test_floating_ips.py
index 19d8e2a..9f5778f 100644
--- a/neutron_tempest_plugin/api/test_floating_ips.py
+++ b/neutron_tempest_plugin/api/test_floating_ips.py
@@ -105,3 +105,38 @@
         body = self.client.update_floatingip(body['floatingip']['id'],
                                              port_id=None)
         self.assertIsNone(body['floatingip']['port_id'])
+
+    @decorators.idempotent_id('cecae820-ebaa-4f96-b386-6a9fbf25c552')
+    @utils.requires_ext(extension="standard-attr-description",
+                        service="network")
+    @utils.requires_ext(extension="fip-port-details", service="network")
+    def test_create_update_floatingip_port_details(self):
+
+        body = self.client.create_floatingip(
+            floating_network_id=self.ext_net_id,
+            port_id=self.ports[0]['id'],
+            description='d1'
+        )['floatingip']
+        self.floating_ips.append(body)
+        self._assert_port_details(self.ports[0], body)
+        body = self.client.show_floatingip(body['id'])['floatingip']
+        self._assert_port_details(self.ports[0], body)
+        body = self.client.update_floatingip(body['id'], description='d2')
+        self._assert_port_details(self.ports[0], body['floatingip'])
+        # disassociate
+        body = self.client.update_floatingip(body['floatingip']['id'],
+                                             port_id=None)
+        self.assertIn('port_details', body['floatingip'])
+        self.assertIsNone(body['floatingip']['port_details'])
+
+    def _assert_port_details(self, port, body):
+        self.assertIn('port_details', body)
+        port_details = body['port_details']
+        self.assertEqual(port['name'], port_details['name'])
+        self.assertEqual(port['network_id'], port_details['network_id'])
+        self.assertEqual(port['mac_address'], port_details['mac_address'])
+        self.assertEqual(port['admin_state_up'],
+                         port_details['admin_state_up'])
+        self.assertEqual(port['status'], port_details['status'])
+        self.assertEqual(port['device_id'], port_details['device_id'])
+        self.assertEqual(port['device_owner'], port_details['device_owner'])
diff --git a/neutron_tempest_plugin/api/test_network_ip_availability.py b/neutron_tempest_plugin/api/test_network_ip_availability.py
index 0b8ac23..10aee2e 100644
--- a/neutron_tempest_plugin/api/test_network_ip_availability.py
+++ b/neutron_tempest_plugin/api/test_network_ip_availability.py
@@ -22,7 +22,6 @@
 from tempest.lib import exceptions as lib_exc
 
 from neutron_tempest_plugin.api import base
-from neutron_tempest_plugin import config
 
 from neutron_lib import constants as lib_constants
 
@@ -76,34 +75,15 @@
                     self.assertEqual(expected_total, availability['total_ips'])
                     self.assertEqual(expected_used, availability['used_ips'])
 
-    def _create_subnet(self, network, ip_version):
-        if ip_version == lib_constants.IP_VERSION_4:
-            cidr = netaddr.IPNetwork('20.0.0.0/24')
-            mask_bits = config.safe_get_config_value(
-                'network', 'project_network_mask_bits')
-        elif ip_version == lib_constants.IP_VERSION_6:
-            cidr = netaddr.IPNetwork('20:db8::/64')
-            mask_bits = config.safe_get_config_value(
-                'network', 'project_network_v6_mask_bits')
-
-        subnet_cidr = next(cidr.subnet(mask_bits))
-        prefix_len = subnet_cidr.prefixlen
-        subnet = self.create_subnet(network,
-                                    cidr=subnet_cidr,
-                                    enable_dhcp=False,
-                                    mask_bits=mask_bits,
-                                    ip_version=ip_version)
-        return subnet, prefix_len
-
 
 def calc_total_ips(prefix, ip_version):
     # will calculate total ips after removing reserved.
     if ip_version == lib_constants.IP_VERSION_4:
-        total_ips = 2 ** (lib_constants.IPv4_BITS
-                          - prefix) - DEFAULT_IP4_RESERVED
+        total_ips = 2 ** (lib_constants.IPv4_BITS -
+                          prefix) - DEFAULT_IP4_RESERVED
     elif ip_version == lib_constants.IP_VERSION_6:
-        total_ips = 2 ** (lib_constants.IPv6_BITS
-                          - prefix) - DEFAULT_IP6_RESERVED
+        total_ips = 2 ** (lib_constants.IPv6_BITS -
+                          prefix) - DEFAULT_IP6_RESERVED
     return total_ips
 
 
@@ -122,7 +102,8 @@
         net_name = data_utils.rand_name('network')
         network = self.create_network(network_name=net_name)
         self.addCleanup(self.client.delete_network, network['id'])
-        subnet, prefix = self._create_subnet(network, self._ip_version)
+        subnet = self.create_subnet(network, enable_dhcp=False)
+        prefix = netaddr.IPNetwork(subnet['cidr']).prefixlen
         self.addCleanup(self.client.delete_subnet, subnet['id'])
         body = self.admin_client.list_network_ip_availabilities()
         used_ip = self._get_used_ips(network, body)
@@ -141,7 +122,7 @@
         net_name = data_utils.rand_name('network')
         network = self.create_network(network_name=net_name)
         self.addCleanup(self.client.delete_network, network['id'])
-        subnet, prefix = self._create_subnet(network, self._ip_version)
+        subnet = self.create_subnet(network, enable_dhcp=False)
         self.addCleanup(self.client.delete_subnet, subnet['id'])
         port = self.client.create_port(network_id=network['id'])
         self.addCleanup(self._cleanUp_port, port['port']['id'])
diff --git a/neutron_tempest_plugin/api/test_routers.py b/neutron_tempest_plugin/api/test_routers.py
index bc657e0..d5d2e04 100644
--- a/neutron_tempest_plugin/api/test_routers.py
+++ b/neutron_tempest_plugin/api/test_routers.py
@@ -159,9 +159,12 @@
         # Add router interface with subnet id
         router = self._create_router(data_utils.rand_name('router'), True)
         intf = self.create_router_interface(router['id'], subnet['id'])
-        status_active = lambda: self.client.show_port(
-            intf['port_id'])['port']['status'] == 'ACTIVE'
-        utils.wait_until_true(status_active, exception=AssertionError)
+
+        def _status_active():
+            return self.client.show_port(
+                intf['port_id'])['port']['status'] == 'ACTIVE'
+
+        utils.wait_until_true(_status_active, exception=AssertionError)
 
     @decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
     @tutils.requires_ext(extension='extraroute', service='network')
diff --git a/neutron_tempest_plugin/api/test_timestamp.py b/neutron_tempest_plugin/api/test_timestamp.py
index 0e49776..186d21f 100644
--- a/neutron_tempest_plugin/api/test_timestamp.py
+++ b/neutron_tempest_plugin/api/test_timestamp.py
@@ -12,6 +12,7 @@
 
 import copy
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
@@ -178,6 +179,7 @@
         self.assertEqual(sp['updated_at'], show_sp['updated_at'])
 
     @decorators.idempotent_id('396a97dc-b66c-4c46-9171-c39eefe6936c')
+    @utils.requires_ext(extension="standard-attr-segment", service="network")
     def test_segment_with_timestamp(self):
         network = self.create_network()
         segment = self.admin_client.list_segments(
diff --git a/neutron_tempest_plugin/common/utils.py b/neutron_tempest_plugin/common/utils.py
index d6d0aee..c42d984 100644
--- a/neutron_tempest_plugin/common/utils.py
+++ b/neutron_tempest_plugin/common/utils.py
@@ -18,11 +18,12 @@
 
 """Utilities and helper functions."""
 
-import eventlet
 import functools
 import threading
 import time
 
+import eventlet
+
 
 class classproperty(object):
     def __init__(self, f):
diff --git a/neutron_tempest_plugin/scenario/test_floatingip.py b/neutron_tempest_plugin/scenario/test_floatingip.py
index 3278c8c..bc40176 100644
--- a/neutron_tempest_plugin/scenario/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/test_floatingip.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import netaddr
 from neutron_lib import constants as lib_constants
 from neutron_lib.services.qos import constants as qos_consts
 from tempest.common import utils
@@ -69,15 +68,14 @@
                 network_id=CONF.network.public_network_id)
 
             for subnet in subnets['subnets']:
-                if (subnet['gateway_ip']
-                    and subnet['ip_version'] == lib_constants.IP_VERSION_4):
+                if (subnet['gateway_ip'] and
+                    subnet['ip_version'] == lib_constants.IP_VERSION_4):
                     return subnet['gateway_ip']
 
     @classmethod
     def _create_dest_network(cls):
         network = cls.create_network()
-        subnet = cls.create_subnet(network,
-            cidr=netaddr.IPNetwork('10.10.0.0/24'))
+        subnet = cls.create_subnet(network)
         cls.create_router_interface(cls.router['id'], subnet['id'])
         return network
 
diff --git a/neutron_tempest_plugin/scenario/test_mtu.py b/neutron_tempest_plugin/scenario/test_mtu.py
index 932c645..b38d770 100644
--- a/neutron_tempest_plugin/scenario/test_mtu.py
+++ b/neutron_tempest_plugin/scenario/test_mtu.py
@@ -12,7 +12,6 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-import netaddr
 
 from neutron_lib.api.definitions import provider_net
 from tempest.common import utils
@@ -70,8 +69,8 @@
     def skip_checks(cls):
         super(NetworkMtuTest, cls).skip_checks()
         if ("vxlan" not in
-                config.CONF.neutron_plugin_options.available_type_drivers
-            or "gre" not in
+                config.CONF.neutron_plugin_options.available_type_drivers or
+            "gre" not in
                 config.CONF.neutron_plugin_options.available_type_drivers):
             raise cls.skipException("GRE or VXLAN type_driver is not enabled")
 
@@ -83,16 +82,14 @@
     def _create_setup(self):
         self.admin_client = self.os_admin.network_client
         net_kwargs = {'tenant_id': self.client.tenant_id}
-        for sub, net_type in (
-                ('10.100.0.0/16', 'vxlan'), ('10.200.0.0/16', 'gre')):
+        for net_type in ['vxlan', 'gre']:
             net_kwargs['name'] = '-'.join([net_type, 'net'])
             net_kwargs['provider:network_type'] = net_type
             network = self.admin_client.create_network(**net_kwargs)[
                 'network']
             self.networks.append(network)
             self.addCleanup(self.admin_client.delete_network, network['id'])
-            cidr = netaddr.IPNetwork(sub)
-            subnet = self.create_subnet(network, cidr=cidr)
+            subnet = self.create_subnet(network)
             self.create_router_interface(self.router['id'], subnet['id'])
             self.addCleanup(self.client.remove_router_interface_with_subnet_id,
                             self.router['id'], subnet['id'])
@@ -165,14 +162,13 @@
         self.admin_client = self.os_admin.network_client
         net_kwargs = {'tenant_id': self.client.tenant_id,
                       'provider:network_type': 'vxlan'}
-        for sub in ('10.100.0.0/16', '10.200.0.0/16'):
+        for _ in range(2):
             net_kwargs['name'] = data_utils.rand_name('net')
             network = self.admin_client.create_network(**net_kwargs)[
                 'network']
             self.networks.append(network)
             self.addCleanup(self.admin_client.delete_network, network['id'])
-            cidr = netaddr.IPNetwork(sub)
-            subnet = self.create_subnet(network, cidr=cidr)
+            subnet = self.create_subnet(network)
             self.create_router_interface(self.router['id'], subnet['id'])
             self.addCleanup(self.client.remove_router_interface_with_subnet_id,
                             self.router['id'], subnet['id'])
diff --git a/neutron_tempest_plugin/scenario/test_qos.py b/neutron_tempest_plugin/scenario/test_qos.py
index 58accb0..0611160 100644
--- a/neutron_tempest_plugin/scenario/test_qos.py
+++ b/neutron_tempest_plugin/scenario/test_qos.py
@@ -75,8 +75,8 @@
     BS = 512
     COUNT = BUFFER_SIZE / BS
     FILE_SIZE = BS * COUNT
-    LIMIT_BYTES_SEC = (constants.LIMIT_KILO_BITS_PER_SECOND * 1024
-                       * TOLERANCE_FACTOR / 8.0)
+    LIMIT_BYTES_SEC = (constants.LIMIT_KILO_BITS_PER_SECOND * 1024 *
+                       TOLERANCE_FACTOR / 8.0)
     FILE_PATH = "/tmp/img"
 
     NC_PORT = 1234
diff --git a/neutron_tempest_plugin/scenario/test_trunk.py b/neutron_tempest_plugin/scenario/test_trunk.py
index 44f5ba7..6fdcd5b 100644
--- a/neutron_tempest_plugin/scenario/test_trunk.py
+++ b/neutron_tempest_plugin/scenario/test_trunk.py
@@ -12,7 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import netaddr
 from oslo_log import log as logging
 from tempest.common import utils as tutils
 from tempest.common import waiters
@@ -38,10 +37,6 @@
     'dhclient $IFACE.%(tag)d"')
 
 
-def get_next_subnet(cidr):
-    return netaddr.IPNetwork(cidr).next()
-
-
 class TrunkTest(base.BaseTempestTestCase):
     credentials = ['primary']
     force_tenant_isolation = False
@@ -145,6 +140,7 @@
                                 CONF.validation.image_ssh_user,
                                 self.keypair['private_key'])
 
+    @utils.unstable_test("bug 1766701")
     @decorators.idempotent_id('bb13fe28-f152-4000-8131-37890a40c79e')
     def test_trunk_subport_lifecycle(self):
         """Test trunk creation and subport transition to ACTIVE status.
@@ -225,6 +221,7 @@
                                 CONF.validation.image_ssh_user,
                                 self.keypair['private_key'])
 
+    @utils.unstable_test('bug 1766701')
     @testtools.skipUnless(
           CONF.neutron_plugin_options.image_is_advanced,
           "Advanced image is required to run this test.")
@@ -233,9 +230,7 @@
         vlan_tag = 10
 
         vlan_network = self.create_network()
-        new_subnet_cidr = get_next_subnet(
-            config.safe_get_config_value('network', 'project_network_cidr'))
-        self.create_subnet(vlan_network, gateway=None, cidr=new_subnet_cidr)
+        self.create_subnet(vlan_network)
 
         servers = [
             self._create_server_with_port_and_subport(vlan_network, vlan_tag)
diff --git a/playbooks/neutron-tempest-plugin-api/run.yaml b/playbooks/neutron-tempest-plugin-api/run.yaml
index 12638cc..230ac10 100644
--- a/playbooks/neutron-tempest-plugin-api/run.yaml
+++ b/playbooks/neutron-tempest-plugin-api/run.yaml
@@ -34,7 +34,7 @@
           export DEVSTACK_GATE_EXERCISES=0
           export DEVSTACK_GATE_TEMPEST_REGEX="neutron_tempest_plugin.api"
           export DEVSTACK_LOCAL_CONFIG="enable_plugin neutron-tempest-plugin git://git.openstack.org/openstack/neutron-tempest-plugin"
-          export BRANCH_OVERRIDE=default
+          export BRANCH_OVERRIDE="{{ branch_override | default('default') }}"
           if [ "$BRANCH_OVERRIDE" != "default" ] ; then
               export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
           fi
diff --git a/test-requirements.txt b/test-requirements.txt
index b8835e3..84f3c18 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,6 +5,7 @@
 hacking<0.13,>=0.12.0 # Apache-2.0
 
 coverage!=4.4,>=4.0 # Apache-2.0
+flake8-import-order==0.12 # LGPLv3
 python-subunit>=1.0.0 # Apache-2.0/BSD
 sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
 oslotest>=3.2.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 06eda94..d966308 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 minversion = 2.0
-envlist = py34,py27,pypy,pep8
+envlist = pep8
 skipsdist = True
 
 [testenv]
@@ -15,7 +15,7 @@
 [testenv:pep8]
 commands =
   sh ./tools/misc-sanity-checks.sh
-  flake8 {posargs}
+  flake8
 whitelist_externals =
   sh