Merge "Skip TrunkTestMtusJSONBase class tests when provider_vlans is not defined" into mcp/epoxy
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index 7ea22e6..532fa43 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -546,8 +546,7 @@
         """
 
         if not cls.try_reserve_subnet_cidr(addr, **ipnetwork_kwargs):
-            raise ValueError('Subnet CIDR already reserved: {0!r}'.format(
-                addr))
+            LOG.info("Subnet CIDR already reserved: %r", addr)
 
     @classmethod
     def try_reserve_subnet_cidr(cls, addr, **ipnetwork_kwargs):
diff --git a/neutron_tempest_plugin/api/test_subnetpools.py b/neutron_tempest_plugin/api/test_subnetpools.py
index eaaee33..a9e2303 100644
--- a/neutron_tempest_plugin/api/test_subnetpools.py
+++ b/neutron_tempest_plugin/api/test_subnetpools.py
@@ -28,6 +28,13 @@
 class SubnetPoolsTestBase(base.BaseAdminNetworkTest):
 
     @classmethod
+    def skip_checks(cls):
+        super(SubnetPoolsTestBase, cls).skip_checks()
+        if not utils.is_extension_enabled('default-subnetpools', 'network'):
+            msg = "default-subnetpools extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
     def resource_setup(cls):
         super(SubnetPoolsTestBase, cls).resource_setup()
         min_prefixlen = '29'
@@ -328,7 +335,6 @@
         self.assertIsNone(body['subnetpool']['address_scope_id'])
 
     @decorators.idempotent_id('4c6963c2-f54c-4347-b288-75d18421c4c4')
-    @utils.requires_ext(extension='default-subnetpools', service='network')
     def test_tenant_create_non_default_subnetpool(self):
         """Test creates a subnetpool, the "is_default" attribute is False."""
         created_subnetpool = self._create_subnetpool()
diff --git a/neutron_tempest_plugin/api/test_subnetpools_negative.py b/neutron_tempest_plugin/api/test_subnetpools_negative.py
index 934d3cd..a85014c 100644
--- a/neutron_tempest_plugin/api/test_subnetpools_negative.py
+++ b/neutron_tempest_plugin/api/test_subnetpools_negative.py
@@ -62,7 +62,6 @@
 
     @decorators.attr(type='negative')
     @decorators.idempotent_id('6ae09d8f-95be-40ed-b1cf-8b850d45bab5')
-    @utils.requires_ext(extension='default-subnetpools', service='network')
     def test_tenant_create_default_subnetpool(self):
         # 'default' subnetpool can only be created by admin.
         self.assertRaises(lib_exc.Forbidden, self._create_subnetpool,
diff --git a/neutron_tempest_plugin/api/test_timestamp.py b/neutron_tempest_plugin/api/test_timestamp.py
index c39c523..0cf28d5 100644
--- a/neutron_tempest_plugin/api/test_timestamp.py
+++ b/neutron_tempest_plugin/api/test_timestamp.py
@@ -15,7 +15,6 @@
 
 from neutron_lib import constants
 from tempest.common import utils
-from tempest import config as tempestconf
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
@@ -307,7 +306,7 @@
             security_group['id'], name=security_group['name'] + 'new')[
                 'security_group']
         # Workaround for PRODX-7986
-        if tempestconf.is_tungstenfabric_backend_enabled():
+        if CONF.service_available.contrail:
             updated_security_group = self.client.show_security_group(
                 security_group['id'])['security_group']
 
diff --git a/neutron_tempest_plugin/bgpvpn/api/test_bgpvpn.py b/neutron_tempest_plugin/bgpvpn/api/test_bgpvpn.py
index 4610686..14fa320 100644
--- a/neutron_tempest_plugin/bgpvpn/api/test_bgpvpn.py
+++ b/neutron_tempest_plugin/bgpvpn/api/test_bgpvpn.py
@@ -257,6 +257,7 @@
         self.assertRaises(exceptions.BadRequest,
                           self.bgpvpn_admin_client.update_bgpvpn,
                           bgpvpn['bgpvpn']['id'], **updatedata)
+        self.delete_bgpvpn(self.bgpvpn_admin_client, bgpvpn['bgpvpn'])
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('f049ce21-d239-47c0-b13f-fb57a2a558ce')
@@ -279,6 +280,7 @@
                           self.bgpvpn_client.create_network_association,
                           uuidutils.generate_uuid(),
                           network['network']['id'])
+        self.delete_bgpvpn(self.bgpvpn_admin_client, bgpvpn['bgpvpn'])
 
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('078b2660-4adb-4c4c-abf0-b77bf0bface5')
@@ -306,6 +308,7 @@
                           self.bgpvpn_client.delete_network_association,
                           uuidutils.generate_uuid(),
                           association['network_association']['id'])
+        self.delete_bgpvpn(self.bgpvpn_admin_client, bgpvpn['bgpvpn'])
 
     @decorators.idempotent_id('de8d94b0-0239-4a48-9574-c3a4a4f7cacb')
     def test_associate_disassociate_router(self):
diff --git a/neutron_tempest_plugin/bgpvpn/base.py b/neutron_tempest_plugin/bgpvpn/base.py
index b436a5d..46c2c78 100644
--- a/neutron_tempest_plugin/bgpvpn/base.py
+++ b/neutron_tempest_plugin/bgpvpn/base.py
@@ -17,6 +17,7 @@
 from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 
 from neutron_tempest_plugin.bgpvpn.services import bgpvpn_client
 
@@ -34,12 +35,6 @@
     bgpvpn_alt_client = None
 
     @classmethod
-    def resource_cleanup(cls):
-        for bgpvpn in cls.bgpvpns:
-            cls.bgpvpn_admin_client.delete_bgpvpn(bgpvpn['id'])
-        super(BaseBgpvpnTest, cls).resource_cleanup()
-
-    @classmethod
     def resource_setup(cls):
         cls.route_distinguishers = []
         cls.bgpvpns = []
@@ -87,9 +82,9 @@
 
         body = client.create_bgpvpn(**kwargs)
         bgpvpn = body['bgpvpn']
-        self.bgpvpns.append(bgpvpn)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.bgpvpn_admin_client.delete_bgpvpn, bgpvpn['id'])
         return bgpvpn
 
     def delete_bgpvpn(self, client, bgpvpn):
         client.delete_bgpvpn(bgpvpn['id'])
-        self.bgpvpns.remove(bgpvpn)
diff --git a/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_advanced.py b/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_advanced.py
new file mode 100644
index 0000000..c7b2f8f
--- /dev/null
+++ b/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_advanced.py
@@ -0,0 +1,267 @@
+# Copyright 2021 Mirantis, Inc.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_log import log as logging
+from tempest.common import compute
+from tempest.common import utils
+from tempest.common import waiters
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+import testtools
+
+from neutron_tempest_plugin.bgpvpn import base
+from neutron_tempest_plugin.bgpvpn.scenario import manager
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class TestBGPVPNAdvanced(base.BaseBgpvpnTest, manager.NetworkScenarioTest):
+    def setUp(self):
+        super(TestBGPVPNAdvanced, self).setUp()
+        self.security_group = self._create_security_group(
+            tenant_id=self.bgpvpn_client.tenant_id
+        )
+
+    @decorators.idempotent_id("734213fb-8213-487d-9fe3-c8ff31758e18")
+    @utils.services("compute", "network")
+    @testtools.skipUnless(
+        CONF.bgpvpn.l2vpn_endpoint and CONF.bgpvpn.route_target,
+        "Required ip address of L2 endpoint and route target.",
+    )
+    def test_bgpvpn_l2vpn_endpoint(self):
+        """This test checks L2VPN connectivity.
+
+        1. Create network with respective subnet
+        2. Start up server
+        4. Associate network to a given L2 BGPVPN
+        5. Create router and connect it to network
+        6. Give a FIP to server
+        7. Check that server can ping l2vpn vtep/endpoint
+        """
+
+        self._create_networks_and_subnets(
+            subnet_cidr=CONF.bgpvpn.l2vpn_endpoint
+        )
+        self._create_server()
+        self._create_bgpvpn(
+            type="l2",
+            rts=CONF.bgpvpn.route_target,
+            vni=CONF.bgpvpn.route_target.split(":")[1],
+        )
+        self._associate_all_nets_to_bgpvpn()
+        self._associate_fip_and_check_bgpvpn(
+            CONF.bgpvpn.l2vpn_endpoint.split("/")[0]
+        )
+
+    @decorators.idempotent_id("124fe1bd-e18a-4482-9c52-855c81a58cd2")
+    @utils.services("compute", "network")
+    @testtools.skipUnless(
+        CONF.bgpvpn.l3vpn_endpoint and CONF.bgpvpn.route_target,
+        "Required ip address of L3 endpoint and route target.",
+    )
+    def test_bgpvpn_l3vpn_endpoint(self):
+        """This test checks L3VPN connectivity.
+
+        1. Create network with respective subnet
+        2. Start up server
+        4. Associate network to a given L3 BGPVPN
+        5. Create router and connect it to network
+        6. Give a FIP to server
+        7. Check that server can ping l3vpn endpoint
+        """
+
+        self._create_networks_and_subnets(
+            subnet_cidr=CONF.bgpvpn.l3vpn_subnet_cidr
+        )
+        self._create_server()
+        self._create_bgpvpn(rts=CONF.bgpvpn.route_target)
+        self._associate_all_nets_to_bgpvpn()
+        self._associate_fip_and_check_bgpvpn(
+            CONF.bgpvpn.l3vpn_endpoint.split("/")[0]
+        )
+
+    def _create_networks_and_subnets(
+        self, name="bgp", subnet_cidr=None, port_security=True
+    ):
+        self.network = self._create_network(
+            namestart=name, port_security_enabled=port_security
+        )
+        self.subnet = self._create_subnet_with_cidr(
+            self.network, cidr=subnet_cidr, ip_version=4
+        )
+        self._reserve_ip_address(subnet_cidr.split("/")[0], self.os_primary)
+
+    def _create_subnet_with_cidr(
+        self, network, subnets_client=None, namestart="subnet-bgp", **kwargs
+    ):
+        if not subnets_client:
+            subnets_client = self.subnets_client
+        subnet = dict(
+            name=data_utils.rand_name(namestart),
+            network_id=network["id"],
+            tenant_id=network["tenant_id"],
+            **kwargs
+        )
+        result = subnets_client.create_subnet(**subnet)
+        self.assertIsNotNone(result, "Unable to allocate tenant network")
+        subnet = result["subnet"]
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            subnets_client.delete_subnet,
+            subnet["id"],
+        )
+        return subnet
+
+    def _create_fip_router(
+        self, client=None, public_network_id=None, subnet_id=None
+    ):
+        router = self._create_router(client, namestart="router-")
+        router_id = router["id"]
+        if public_network_id is None:
+            public_network_id = CONF.network.public_network_id
+        if client is None:
+            client = self.routers_client
+        kwargs = {"external_gateway_info": {"network_id": public_network_id}}
+        router = client.update_router(router_id, **kwargs)["router"]
+        if subnet_id is not None:
+            client.add_router_interface(router_id, subnet_id=subnet_id)
+            self.addCleanup(
+                test_utils.call_and_ignore_notfound_exc,
+                client.remove_router_interface,
+                router_id,
+                subnet_id=subnet_id,
+            )
+        return router
+
+    def _create_router_and_associate_fip(self, subnet):
+        router = self._create_fip_router(subnet_id=subnet["id"])
+        self.server_fip = self.create_floating_ip(
+            self.server, external_network_id=CONF.network.public_network_id
+        )
+        return router
+
+    def _reserve_ip_address(self, ip_address, clients):
+        create_port_kwargs = {
+            "fixed_ips": [{"ip_address": ip_address}],
+            "namestart": "port-endpoint",
+        }
+        self._create_port(
+            network_id=self.network["id"],
+            client=clients.ports_client,
+            **create_port_kwargs
+        )
+
+    def _create_server(self, name="server-bgp", port_security=True):
+        self.keypair = self.create_keypair()
+        security_group_name = self.security_group["name"]
+        clients = self.os_primary
+
+        security_groups = {}
+        if port_security:
+            security_groups = {
+                "security_groups": [{"name": security_group_name}]
+            }
+
+        create_server_kwargs = {
+            "key_name": self.keypair["name"],
+            "networks": [{"uuid": self.network["id"]}],
+            **security_groups,
+        }
+        body, _ = compute.create_test_server(
+            clients, wait_until="ACTIVE", name=name, **create_server_kwargs
+        )
+        self.addCleanup(
+            waiters.wait_for_server_termination,
+            clients.servers_client,
+            body["id"],
+        )
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            clients.servers_client.delete_server,
+            body["id"],
+        )
+        self.server = clients.servers_client.show_server(body["id"])["server"]
+        LOG.debug(
+            "Created server: %s with status: %s",
+            self.server["id"],
+            self.server["status"],
+        )
+
+    def _create_bgpvpn(
+        self,
+        name="test-bgpvpn",
+        type="l3",
+        rts=None,
+        import_rts=None,
+        export_rts=None,
+        vni=None,
+    ):
+        import_rts = import_rts or []
+        export_rts = export_rts or []
+        self.bgpvpn = self.create_bgpvpn(
+            self.bgpvpn_admin_client,
+            tenant_id=self.bgpvpn_client.tenant_id,
+            name=name,
+            route_targets=rts,
+            export_targets=export_rts,
+            import_targets=import_rts,
+            type=type,
+            vni=vni,
+        )
+        return self.bgpvpn
+
+    def _associate_all_nets_to_bgpvpn(self, bgpvpn=None):
+        bgpvpn = bgpvpn or self.bgpvpn
+        self.bgpvpn_client.create_network_association(
+            bgpvpn["id"], self.network["id"]
+        )
+        LOG.debug("BGPVPN network associations completed")
+
+    def _setup_ssh_client(self, server):
+        server_fip = self.server_fip["floating_ip_address"]
+        private_key = self.keypair["private_key"]
+        ssh_client = self.get_remote_client(
+            server_fip, private_key=private_key
+        )
+        return ssh_client
+
+    def _check_bgpvpn(self, from_server=None, to_server_ip=None):
+        from_server = from_server or self.server
+        from_server_ip = self.server_fip["floating_ip_address"]
+        ssh_client = self._setup_ssh_client(from_server)
+        msg = "Timed out waiting for {ip} to become reachable".format(
+            ip=to_server_ip
+        )
+        try:
+            result = self._check_remote_connectivity(
+                ssh_client, to_server_ip, True
+            )
+            self.assertTrue(result, msg)
+        except Exception:
+            LOG.exception(
+                "Error validating connectivity to %s "
+                "from VM with IP address %s: %s",
+                to_server_ip,
+                from_server_ip,
+                msg,
+            )
+            raise
+
+    def _associate_fip_and_check_bgpvpn(self, to_server_ip=None):
+        self.router = self._create_router_and_associate_fip(self.subnet)
+        self._check_bgpvpn(to_server_ip=to_server_ip)
diff --git a/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py b/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py
index 9cca602..47d0fa4 100644
--- a/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py
+++ b/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py
@@ -27,6 +27,7 @@
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
+import testtools
 
 from neutron_tempest_plugin.bgpvpn import base
 from neutron_tempest_plugin.bgpvpn.scenario import manager
@@ -763,6 +764,101 @@
             self._check_l3_bgpvpn_by_specific_ip(
                 should_succeed=False, to_server_ip=ip)
 
+    @decorators.idempotent_id('910e6d89-5703-4a5e-a5c7-0743ddffbeb7')
+    @utils.services('compute', 'network')
+    @utils.requires_ext(extension='bgpvpn-routes-control', service='network')
+    def test_bgpvpn_port_association_create_and_delete_association(self):
+        """This test checks port association in BGPVPN.
+
+        1. Create networks A and B with their respective subnets
+        2. Create L3 BGPVPN
+        3. Create router and connect it to network A
+        5. Start up server 1 in network A
+        6. Start up server 2 in network B
+        7. Give a FIP to server 1
+        LOG.debug("Check that server 1 cannot ping server's 2")
+        LOG.debug("Check that server 1 can ping server's 2")
+        import rpdb; rpdb.set_trace()
+        LOG.debug("Check that server 1 cannot ping server's 2")
+        8. Check that server 1 cannot ping server's 2
+        10. Associate network A to a given L3 BGPVPN
+        11. Associate port of server 2 to a given L3 BGPVPN
+        12. Check that server 1 can ping server's 2
+        13. Remove created before port association
+        14. Check that server 1 cannot ping server's 2
+        """
+        self._create_networks_and_subnets(port_security=False)
+        self._create_l3_bgpvpn()
+        self._create_servers([[self.networks[NET_A], IP_A_S1_1],
+                              [self.networks[NET_B], IP_B_S1_1]],
+                             port_security=False)
+        self._create_fip_router(subnet_id=self.subnets[NET_A][0]['id'])
+        self._associate_fip(0)
+
+        # preliminary check that no connectivity to 192.168.0.1 initially
+        # exists
+        self._check_l3_bgpvpn_by_specific_ip(
+            should_succeed=False, to_server_ip=IP_B_S1_1)
+        self.bgpvpn_client.create_network_association(
+            self.bgpvpn['id'], self.networks[NET_A]['id'])
+        port_id = self.ports[self.servers[1]['id']]['id']
+        body = self.bgpvpn_client.create_port_association(self.bgpvpn['id'],
+                                                          port_id=port_id)
+        port_association = body['port_association']
+        self._check_l3_bgpvpn_by_specific_ip(
+            should_succeed=True, to_server_ip=IP_B_S1_1)
+        self.bgpvpn_client.delete_port_association(
+            self.bgpvpn['id'], port_association['id'])
+        self._check_l3_bgpvpn_by_specific_ip(
+            should_succeed=False, to_server_ip=IP_B_S1_1)
+
+    @decorators.idempotent_id('8de130c1-778a-4d86-913b-ff41be3c2f0b')
+    @utils.services('compute', 'network')
+    @utils.requires_ext(extension='bgpvpn-routes-control', service='network')
+    @testtools.skipUnless(False, "Skip unless PRODX-25126 is fixed")
+    def test_bgpvpn_port_association_create_and_delete_bgpvpn(self):
+        """This test checks port association in BGPVPN.
+
+        1. Create networks A and B with their respective subnets
+        2. Create L3 BGPVPN
+        3. Create router and connect it to network A
+        5. Start up server 1 in network A
+        6. Start up server 2 in network B
+        7. Give a FIP to server 1
+        LOG.debug("Check that server 1 cannot ping server's 2")
+        LOG.debug("Check that server 1 can ping server's 2")
+        import rpdb; rpdb.set_trace()
+        LOG.debug("Check that server 1 cannot ping server's 2")
+        8. Check that server 1 cannot ping server's 2
+        10. Associate network A to a given L3 BGPVPN
+        11. Associate port of server 2 to a given L3 BGPVPN
+        12. Check that server 1 can ping server's 2
+        13. Remove created before bgpvpn
+        14. Check that server 1 cannot ping server's 2
+        """
+        self._create_networks_and_subnets(port_security=False)
+        self._create_l3_bgpvpn()
+        self._create_servers([[self.networks[NET_A], IP_A_S1_1],
+                              [self.networks[NET_B], IP_B_S1_1]],
+                             port_security=False)
+        self._create_fip_router(subnet_id=self.subnets[NET_A][0]['id'])
+        self._associate_fip(0)
+
+        # preliminary check that no connectivity to 192.168.0.1 initially
+        # exists
+        self._check_l3_bgpvpn_by_specific_ip(
+            should_succeed=False, to_server_ip=IP_B_S1_1)
+        self.bgpvpn_client.create_network_association(
+            self.bgpvpn['id'], self.networks[NET_A]['id'])
+        port_id = self.ports[self.servers[1]['id']]['id']
+        self.bgpvpn_client.create_port_association(self.bgpvpn['id'],
+                                                   port_id=port_id)
+        self._check_l3_bgpvpn_by_specific_ip(
+            should_succeed=True, to_server_ip=IP_B_S1_1)
+        self.delete_bgpvpn(self.bgpvpn_admin_client, self.bgpvpn)
+        self._check_l3_bgpvpn_by_specific_ip(
+            should_succeed=False, to_server_ip=IP_B_S1_1)
+
     @decorators.idempotent_id('9c3280b5-0b32-4562-800c-0b50d9d52bfd')
     @utils.services('compute', 'network')
     @utils.requires_ext(extension='bgpvpn-routes-control', service='network')
@@ -1256,6 +1352,9 @@
             tenant_id=self.bgpvpn_admin_client.project_id,
             name=name, route_targets=rts, export_targets=export_rts,
             import_targets=import_rts)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.bgpvpn_admin_client.delete_bgpvpn,
+                        self.bgpvpn['id'])
         return self.bgpvpn
 
     def _update_l3_bgpvpn(self, rts=None, import_rts=None, export_rts=None,
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index 8136e47..74f7c03 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -194,6 +194,22 @@
                default=200,
                help=("Maximum number for the range of "
                      "assigned number for distinguishers.")),
+    cfg.StrOpt('l3vpn_endpoint',
+               default=None,
+               help=("IP Address/Mask, which will be used to "
+                     "test the l3vpn connectivity.")),
+    cfg.StrOpt('l3vpn_subnet_cidr',
+               default="192.168.0.254/24",
+               help=("IP Address/Mask, which will be used as private network"
+                     "test the l3vpn connectivity.")),
+    cfg.StrOpt('l2vpn_endpoint',
+               default=None,
+               help=("IP Address/Mask, which will be used to "
+                     "test the l2vpn connectivity.")),
+    cfg.StrOpt('route_target',
+               default=None,
+               help=("Route-target (RT) extended community attributes "
+                     "identify the VPN membership of routes.")),
 ]
 
 bgpvpn_group = cfg.OptGroup(name="bgpvpn", title=("Networking-Bgpvpn Service "
diff --git a/neutron_tempest_plugin/neutron_dynamic_routing/api/test_bgp_speaker_extensions.py b/neutron_tempest_plugin/neutron_dynamic_routing/api/test_bgp_speaker_extensions.py
index 551cc12..7b15485 100644
--- a/neutron_tempest_plugin/neutron_dynamic_routing/api/test_bgp_speaker_extensions.py
+++ b/neutron_tempest_plugin/neutron_dynamic_routing/api/test_bgp_speaker_extensions.py
@@ -250,7 +250,7 @@
         self.admin_routers.append(router)
         bgp_speaker_id = bgp_speaker['id']
         self.bgp_adm_client.add_bgp_gateway_network(bgp_speaker_id,
-                                                  self.ext_net_id)
+                                                  ext_net['id'])
         routes = self.bgp_adm_client.get_bgp_advertised_routes(bgp_speaker_id)
         self.assertEqual(0, len(routes['advertised_routes']))
 
@@ -275,10 +275,10 @@
         bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args)
         bgp_speaker_id = bgp_speaker['id']
         self.bgp_adm_client.add_bgp_gateway_network(bgp_speaker_id,
-                                                    self.ext_net_id)
+                                                    ext_net['id'])
         tenant_net = self.create_network()
         tenant_subnet = self.create_subnet(tenant_net)
-        ext_gw_info = {'network_id': self.ext_net_id}
+        ext_gw_info = {'network_id': ext_net['id']}
         router = self.create_router(ext_gw_info)
         self.admin_routers.append(router)
         self.admin_client.add_router_interface_with_subnet_id(
@@ -287,7 +287,7 @@
         self.admin_routerports.append({'router_id': router['id'],
                                        'subnet_id': tenant_subnet['id']})
         tenant_port = self.create_port(tenant_net)
-        floatingip = self.create_floatingip(self.ext_net_id)
+        floatingip = self.create_floatingip(ext_net['id'])
         self.admin_floatingips.append(floatingip)
         self.client.update_floatingip(floatingip['id'],
                                       port_id=tenant_port['id'])
diff --git a/neutron_tempest_plugin/scenario/test_dhcp.py b/neutron_tempest_plugin/scenario/test_dhcp.py
index d0545e2..31d2930 100644
--- a/neutron_tempest_plugin/scenario/test_dhcp.py
+++ b/neutron_tempest_plugin/scenario/test_dhcp.py
@@ -66,7 +66,7 @@
         test_domain = "test.domain"
         extra_dhcp_opts = [
             {'opt_name': 'domain-name',
-             'opt_value': '"%s"' % test_domain}]
+             'opt_value': '%s' % test_domain}]
         port = self.create_port(
             network=self.network, name=self.rand_name,
             security_groups=[self.security_group['id']],
diff --git a/neutron_tempest_plugin/scenario/test_dns_integration.py b/neutron_tempest_plugin/scenario/test_dns_integration.py
index d6bafef..df9406f 100644
--- a/neutron_tempest_plugin/scenario/test_dns_integration.py
+++ b/neutron_tempest_plugin/scenario/test_dns_integration.py
@@ -17,11 +17,9 @@
 
 import testtools
 
-from oslo_log import log
 from tempest.common import utils
 from tempest.common import waiters
 from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -32,8 +30,6 @@
 
 
 CONF = config.CONF
-LOG = log.getLogger(__name__)
-
 
 # Note(jh): Need to do a bit of juggling here in order to avoid failures
 # when designate_tempest_plugin is not available
@@ -47,15 +43,36 @@
     DNSMixin = object
 
 
+def rand_zone_name(name='', prefix='rand', suffix=None):
+    """Generate a random zone name
+
+    :param str name: The name that you want to include
+    :param prefix: the exact text to start the string. Defaults to "rand"
+    :param suffix: the exact text to end the string
+    :return: a random zone name e.g. example.org.
+    :rtype: string
+    """
+
+    if suffix is None:
+        suffix = '.{}.'.format(CONF.dns.tld_suffix)
+    name = data_utils.rand_name(name=name, prefix=prefix)
+    return name + suffix
+
+
 class BaseDNSIntegrationTests(base.BaseTempestTestCase, DNSMixin):
     credentials = ['primary', 'admin']
 
     @classmethod
     def setup_clients(cls):
         super(BaseDNSIntegrationTests, cls).setup_clients()
-        cls.zone_client = cls.os_tempest.dns_v2.ZonesClient()
-        cls.recordset_client = cls.os_tempest.dns_v2.RecordsetClient()
-        cls.query_client.build_timeout = 60
+        cls.dns_client = cls.os_tempest.dns_v2.ZonesClient()
+        cls.query_client.build_timeout = 30
+        if CONF.enforce_scope.designate:
+            cls.admin_tld_client = cls.os_system_admin.dns_v2.TldClient()
+            cls.rec_client = cls.os_system_admin.dns_v2.RecordsetClient()
+        else:
+            cls.admin_tld_client = cls.os_admin.dns_v2.TldClient()
+            cls.rec_client = cls.os_admin.dns_v2.RecordsetClient()
 
     @classmethod
     def skip_checks(cls):
@@ -65,18 +82,27 @@
             raise cls.skipException("Designate support is required")
         if not (dns_base and dns_waiters):
             raise cls.skipException("Designate tempest plugin is missing")
+        # Neutron creates zones for reverse lookups and designate requires
+        # related TLD if there is any
+        if CONF.production:
+            if CONF.dns.existing_tlds and not set([CONF.dns.tld_suffix,
+                    "arpa", "in-addr.arpa"]).issubset(CONF.dns.existing_tlds):
+                raise cls.skipException("Skip on production environment "
+                            "because it doesn't match TLD configuration.")
 
     @classmethod
     @utils.requires_ext(extension="dns-integration", service="network")
     def resource_setup(cls):
         super(BaseDNSIntegrationTests, cls).resource_setup()
-        cls.zone_name = dns_data_utils.rand_zone_name(
-            name="basednsintegrationtests")
-        cls.zone = cls.zone_client.create_zone(
-            name=cls.zone_name, wait_until='ACTIVE')[1]
-        cls.addClassResourceCleanup(
-            cls.zone_client.delete_zone, cls.zone['id'],
-            ignore_errors=lib_exc.NotFound)
+
+        zone_name = rand_zone_name(
+            name="dnsinttest", prefix='')
+        _, cls.zone = cls.dns_client.create_zone(name=zone_name)
+        cls.addClassResourceCleanup(cls.dns_client.delete_zone,
+            cls.zone['id'], ignore_errors=lib_exc.NotFound)
+        dns_waiters.wait_for_zone_status(
+            cls.dns_client, cls.zone['id'], 'ACTIVE')
+
         cls.network = cls.create_network(dns_domain=cls.zone['name'])
         cls.subnet = cls.create_subnet(cls.network)
         cls.subnet_v6 = cls.create_subnet(cls.network, ip_version=6)
@@ -84,6 +110,10 @@
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.keypair = cls.create_keypair()
 
+    @classmethod
+    def resource_cleanup(cls):
+        super(BaseDNSIntegrationTests, cls).resource_cleanup()
+
     def _create_floatingip_with_dns(self, dns_name):
         return self.create_floatingip(client=self.os_primary.network_client,
                                       dns_name=dns_name,
@@ -102,79 +132,12 @@
         fip = self.create_floatingip(port=port)
         return {'port': port, 'fip': fip, 'server': server}
 
-    def _check_type_in_recordsets(self, zone_id, rec_type):
-        types = [rec['type'] for rec in self.recordset_client.list_recordset(
-            zone_id)[1]['recordsets']]
-        if rec_type in types:
-            return True
-        return False
-
-    def _wait_for_type_in_recordsets(self, zone_id, type):
-        test_utils.call_until_true(
-            func=self._check_type_in_recordsets, zone_id=zone_id,
-            rec_type=type, duration=self.query_client.build_timeout,
-            sleep_for=5)
-
-    def _check_recordset_deleted(
-            self, recordset_client, zone_id, recordset_id):
-        return test_utils.call_and_ignore_notfound_exc(
-            recordset_client.show_recordset, zone_id, recordset_id) is None
-
-    def _verify_designate_recordset(
-            self, address, found=True, record_type='A'):
-        if found:
-            self._wait_for_type_in_recordsets(self.zone['id'], record_type)
-            recordsets = self.recordset_client.list_recordset(
-                self.zone['id'])[1]['recordsets']
-            relevant_type = [rec for rec in recordsets if
-                             rec['type'] == record_type]
-            self.assertTrue(
-                relevant_type,
-                'Failed no {} type recordset has been detected in the '
-                'Designate DNS DB'.format(record_type))
-            rec_id = [rec['id'] for rec in relevant_type if address in
-                      str(rec['records'])][0]
-            self.assertTrue(
-                rec_id, 'Record of type:{} with IP:{} was not detected in '
-                        'the Designate DNS DB'.format(record_type, address))
-            dns_waiters.wait_for_recordset_status(
-                self.recordset_client, self.zone['id'], rec_id, 'ACTIVE')
-        else:
-            rec_id = None
-            recordsets = self.recordset_client.list_recordset(
-                self.zone['id'])[1]['recordsets']
-            relevant_type = [rec for rec in recordsets if
-                             rec['type'] == record_type]
-            if relevant_type:
-                rec_id = [rec['id'] for rec in relevant_type if
-                          address in str(rec['records'])][0]
-            if rec_id:
-                recordset_exists = test_utils.call_until_true(
-                    func=self._check_recordset_deleted,
-                    recordset_client=self.recordset_client,
-                    zone_id=self.zone['id'], recordset_id=rec_id,
-                    duration=self.query_client.build_timeout, sleep_for=5)
-                self.assertTrue(
-                    recordset_exists,
-                    'Failed, recordset type:{} and ID:{} is still exist in '
-                    'the Designate DNS DB'.format(record_type, rec_id))
-
     def _verify_dns_records(self, address, name, found=True, record_type='A'):
         client = self.query_client
         forward = name + '.' + self.zone['name']
         reverse = ipaddress.ip_address(address).reverse_pointer
-        record_types_to_check = [record_type, 'PTR']
-        for rec_type in record_types_to_check:
-            try:
-                if rec_type == 'PTR':
-                    dns_waiters.wait_for_query(
-                        client, reverse, rec_type, found)
-                else:
-                    dns_waiters.wait_for_query(
-                        client, forward, rec_type, found)
-            except Exception as e:
-                LOG.error(e)
-                self._verify_designate_recordset(address, found, rec_type)
+        dns_waiters.wait_for_query(client, forward, record_type, found)
+        dns_waiters.wait_for_query(client, reverse, 'PTR', found)
         if not found:
             return
         fwd_response = client.query(forward, record_type)
@@ -300,15 +263,19 @@
     @classmethod
     def resource_setup(cls):
         super(BaseDNSIntegrationTests, cls).resource_setup()
-        cls.name = data_utils.rand_name('test-domain')
-        cls.zone_name = "%s.%s.%s.zone." % (cls.client.user_id,
-                                        cls.client.project_id,
-                                        cls.name)
-        dns_domain_template = "<user_id>.<project_id>.%s.zone." % cls.name
-        cls.zone = cls.zone_client.create_zone(
-            name=cls.zone_name, wait_until='ACTIVE')[1]
-        cls.addClassResourceCleanup(cls.zone_client.delete_zone,
+
+        name = data_utils.rand_name('test-domain')
+        zone_name = "%s.%s.%s.zone." % (cls.client.user_id,
+                                        cls.client.tenant_id,
+                                        name)
+        dns_domain_template = "<user_id>.<project_id>.%s.zone." % name
+
+        _, cls.zone = cls.dns_client.create_zone(name=zone_name)
+        cls.addClassResourceCleanup(cls.dns_client.delete_zone,
             cls.zone['id'], ignore_errors=lib_exc.NotFound)
+        dns_waiters.wait_for_zone_status(
+            cls.dns_client, cls.zone['id'], 'ACTIVE')
+
         cls.network = cls.create_network(dns_domain=dns_domain_template)
         cls.subnet = cls.create_subnet(cls.network,
                                        dns_publish_fixed_ip=True)
diff --git a/neutron_tempest_plugin/vpnaas/api/base_vpnaas.py b/neutron_tempest_plugin/vpnaas/api/base_vpnaas.py
index 0e54380..3ccf48b 100644
--- a/neutron_tempest_plugin/vpnaas/api/base_vpnaas.py
+++ b/neutron_tempest_plugin/vpnaas/api/base_vpnaas.py
@@ -14,7 +14,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import time
+
 from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 
 from neutron_tempest_plugin.api import base
 from neutron_tempest_plugin import config
@@ -138,6 +141,31 @@
         return ipsec_site_connection
 
     @classmethod
+    def wait_ipsec_site_connection_status(cls, site_id, status, timeout=None,
+                                          interval=None):
+        start_time = int(time.time())
+        timeout = timeout or cls.client.build_timeout
+        interval = interval or cls.client.build_interval
+        current_status = ""
+        while True:
+            if current_status.lower() == status.lower():
+                return
+
+            timed_out = int(time.time()) - start_time >= timeout
+            if timed_out:
+                message = ('IPSec site connection %(site_id)s failed to reach '
+                           'desired status %(desired_status)s, current state '
+                           '%(current_status)s in %(timeout)d' %
+                           {"site_id": site_id,
+                            "desired_status": status,
+                            "current_status": current_status,
+                            "timeout": timeout})
+                raise lib_exc.TimeoutException(message)
+            current_status = cls.client.show_ipsec_site_connection(
+                site_id)['ipsec_site_connection']['status']
+            time.sleep(interval)
+
+    @classmethod
     def create_endpoint_group(cls, name, type, endpoints):
         """Wrapper utility that returns a test ipsec policy."""
         body = cls.client.create_endpoint_group(
diff --git a/neutron_tempest_plugin/vpnaas/scenario/test_vpnaas.py b/neutron_tempest_plugin/vpnaas/scenario/test_vpnaas.py
index 30a8674..942e7f0 100644
--- a/neutron_tempest_plugin/vpnaas/scenario/test_vpnaas.py
+++ b/neutron_tempest_plugin/vpnaas/scenario/test_vpnaas.py
@@ -116,6 +116,13 @@
             cls.extra_subnet_attributes['ipv6_address_mode'] = 'slaac'
             cls.extra_subnet_attributes['ipv6_ra_mode'] = 'slaac'
 
+        left_v4_cidr = netaddr.IPNetwork('10.220.0.0/24')
+        left_v6_cidr = netaddr.IPNetwork('2001:db8:0:2::/64')
+        cls.left_cidr = left_v6_cidr if cls.inner_ipv6 else left_v4_cidr
+        right_v4_cidr = netaddr.IPNetwork('10.210.0.0/24')
+        right_v6_cidr = netaddr.IPNetwork('2001:db8:0:1::/64')
+        cls.right_cidr = right_v6_cidr if cls.inner_ipv6 else right_v4_cidr
+
         # LEFT
         cls.router = cls.create_router(
             data_utils.rand_name('left-router'),
@@ -123,14 +130,22 @@
             external_network_id=CONF.network.public_network_id)
         cls.network = cls.create_network(network_name='left-network')
         ip_version = 6 if cls.inner_ipv6 else 4
-        v4_cidr = netaddr.IPNetwork('10.20.0.0/24')
-        v6_cidr = netaddr.IPNetwork('2001:db8:0:2::/64')
-        cidr = v6_cidr if cls.inner_ipv6 else v4_cidr
-        cls.subnet = cls.create_subnet(
-            cls.network, ip_version=ip_version, cidr=cidr, name='left-subnet',
-            **cls.extra_subnet_attributes)
-        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+        is_distributed = cls.os_admin.network_client.show_router(
+            cls.router['id'])['router'].get('distributed')
 
+        cls.subnet = cls.create_subnet(
+            cls.network, ip_version=ip_version, cidr=cls.left_cidr,
+            name='left-subnet', **cls.extra_subnet_attributes)
+        cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+        if is_distributed:
+            snat_port = cls.os_admin.network_client.list_ports(
+                device_id=cls.router['id'],
+                device_owner='network:router_centralized_snat')
+            snat_ip = cls._get_ip_on_subnet_for_port(
+                cls, snat_port['ports'][0], cls.subnet['id'])
+            cls.os_admin.network_client.update_subnet(
+                cls.subnet['id'], host_routes=[{"destination": cls.right_cidr,
+                                                "nexthop": snat_ip}])
         # Gives an internal IPv4 subnet for floating IP to the left server,
         # we use it to ssh into the left server.
         if cls.inner_ipv6:
@@ -164,15 +179,23 @@
             data_utils.rand_name('right-router'),
             admin_state_up=True,
             external_network_id=CONF.network.public_network_id)
+        is_distributed = cls.os_admin.network_client.show_router(
+            router['id'])['router'].get('distributed')
         network = cls.create_network(network_name='right-network')
-        v4_cidr = netaddr.IPNetwork('10.10.0.0/24')
-        v6_cidr = netaddr.IPNetwork('2001:db8:0:1::/64')
-        cidr = v6_cidr if cls.inner_ipv6 else v4_cidr
         ip_version = 6 if cls.inner_ipv6 else 4
         subnet = cls.create_subnet(
-            network, ip_version=ip_version, cidr=cidr, name='right-subnet',
-            **cls.extra_subnet_attributes)
+            network, ip_version=ip_version, cidr=cls.right_cidr,
+            name='right-subnet', **cls.extra_subnet_attributes)
         cls.create_router_interface(router['id'], subnet['id'])
+        if is_distributed:
+            snat_port = cls.os_admin.network_client.list_ports(
+                device_id=router['id'],
+                device_owner='network:router_centralized_snat')
+            snat_ip = cls._get_ip_on_subnet_for_port(
+                cls, snat_port['ports'][0], subnet['id'])
+            cls.os_admin.network_client.update_subnet(
+                subnet['id'], host_routes=[{"destination": cls.left_cidr,
+                                            "nexthop": snat_ip}])
 
         return network, subnet, router
 
@@ -207,6 +230,7 @@
             site['vpnservice'] = self.create_vpnservice(
                 site['subnet']['id'], site['router']['id'],
                 name=data_utils.rand_name('%s-vpnservice' % site['name']))
+        site_connections = []
         for i in range(0, 2):
             site = sites[i]
             vpnservice = site['vpnservice']
@@ -218,7 +242,7 @@
                     raise self.skipException(msg)
             else:
                 peer_address = peer['vpnservice']['external_v4_ip']
-            self.create_ipsec_site_connection(
+            site_connection = self.create_ipsec_site_connection(
                 self.ikepolicy['id'],
                 self.ipsecpolicy['id'],
                 vpnservice['id'],
@@ -228,6 +252,10 @@
                 psk=psk,
                 name=data_utils.rand_name(
                     '%s-ipsec-site-connection' % site['name']))
+            site_connections.append(site_connection)
+        for site_connection in site_connections:
+            self.wait_ipsec_site_connection_status(site_connection['id'],
+                                                   status="ACTIVE")
 
     def _get_ip_on_subnet_for_port(self, port, subnet_id):
         for fixed_ip in port['fixed_ips']:
@@ -237,7 +265,6 @@
             subnet_id, port)
         raise self.fail(msg)
 
-    @test.unstable_test("bug 1882220")
     def _test_vpnaas(self):
         # RIGHT
         right_server = self._create_server(network=self._right_network,
@@ -275,6 +302,7 @@
 class Vpnaas4in4(Vpnaas):
 
     @decorators.idempotent_id('aa932ab2-63aa-49cf-a2a0-8ae71ac2bc24')
+    @decorators.attr(type='smoke')
     def test_vpnaas(self):
         self._test_vpnaas()
 
@@ -288,6 +316,7 @@
     @testtools.skipIf(
         CONF.neutron_vpnaas_plugin_options.skip_4in6_6in4_tests,
         'VPNaaS 4in6 test is skipped.')
+    @test.unstable_test("bug 1882220")
     def test_vpnaas_4in6(self):
         self._test_vpnaas()
 
@@ -299,11 +328,9 @@
     @testtools.skipUnless(CONF.network_feature_enabled.ipv6,
                           'IPv6 tests are disabled.')
     @testtools.skipIf(
-        CONF.neutron_vpnaas_plugin_options.skip_4in6_6in4_tests,
-        'VPNaaS 6in4 test is skipped.')
-    @testtools.skipIf(
         CONF.neutron_vpnaas_plugin_options.skip_6in4_tests,
         'VPNaaS 6in4 test is skipped.')
+    @test.unstable_test("bug 1882220")
     def test_vpnaas_6in4(self):
         self._test_vpnaas()
 
@@ -318,5 +345,6 @@
     @testtools.skipIf(
         CONF.neutron_vpnaas_plugin_options.skip_6in6_tests,
         'VPNaaS 6in6 test is skipped.')
+    @test.unstable_test("bug 1882220")
     def test_vpnaas_6in6(self):
         self._test_vpnaas()