Merge "jobs: remove devstack-gate references"
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index 3812383..36fec30 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -97,6 +97,9 @@
     cfg.IntOpt('ssh_proxy_jump_port',
                default=22,
                help='Port used to connect to "ssh_proxy_jump_host".'),
+    cfg.IntOpt('reboots_in_test',
+               default=1,
+               help='Number of reboots to apply if tests requires reboots'),
 
     # Options for special, "advanced" image like e.g. Ubuntu. Such image can be
     # used in tests which require some more advanced tool than available in
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index 334d543..c29585f 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -206,9 +206,30 @@
         else:
             router = cls.create_admin_router(**kwargs)
         LOG.debug("Created router %s", router['name'])
+        cls._wait_for_router_ha_active(router['id'])
         return router
 
     @classmethod
+    def _wait_for_router_ha_active(cls, router_id):
+        router = cls.os_admin.network_client.show_router(router_id)['router']
+        if not router.get('ha'):
+            return
+
+        def _router_active_on_l3_agent():
+            agents = cls.os_admin.network_client.list_l3_agents_hosting_router(
+                router_id)['agents']
+            return "active" in [agent['ha_state'] for agent in agents]
+
+        error_msg = (
+            "Router %s is not active on any of the L3 agents" % router_id)
+        # NOTE(slaweq): timeout here should be lower for sure, but due to
+        # the bug https://launchpad.net/bugs/1923633 let's wait even 10
+        # minutes until router will be active on some of the L3 agents
+        utils.wait_until_true(_router_active_on_l3_agent,
+                              timeout=600, sleep=5,
+                              exception=lib_exc.TimeoutException(error_msg))
+
+    @classmethod
     def skip_if_no_extension_enabled_in_l3_agents(cls, extension):
         l3_agents = cls.os_admin.network_client.list_agents(
                 binary='neutron-l3-agent')['agents']
diff --git a/neutron_tempest_plugin/scenario/test_basic.py b/neutron_tempest_plugin/scenario/test_basic.py
index 38bc40b..7583f88 100644
--- a/neutron_tempest_plugin/scenario/test_basic.py
+++ b/neutron_tempest_plugin/scenario/test_basic.py
@@ -24,7 +24,7 @@
 
 
 class NetworkBasicTest(base.BaseTempestTestCase):
-    credentials = ['primary']
+    credentials = ['primary', 'admin']
     force_tenant_isolation = False
 
     # Default to ipv4.
diff --git a/neutron_tempest_plugin/scenario/test_connectivity.py b/neutron_tempest_plugin/scenario/test_connectivity.py
index 66c4789..ca7d755 100644
--- a/neutron_tempest_plugin/scenario/test_connectivity.py
+++ b/neutron_tempest_plugin/scenario/test_connectivity.py
@@ -88,6 +88,8 @@
         ap2_rt = self.create_router(
             router_name=data_utils.rand_name("ap2_rt"),
             admin_state_up=True)
+        self._wait_for_router_ha_active(ap1_rt['id'])
+        self._wait_for_router_ha_active(ap2_rt['id'])
 
         ap1_internal_port = self.create_port(
             ap1_net, security_groups=[self.secgroup['id']])
@@ -140,6 +142,7 @@
             router_name=data_utils.rand_name("east_west_traffic_router"),
             admin_state_up=True,
             external_network_id=CONF.network.public_network_id)
+        self._wait_for_router_ha_active(router['id'])
 
         internal_port_1 = self.create_port(
             net_1, security_groups=[self.secgroup['id']])
diff --git a/neutron_tempest_plugin/scenario/test_floatingip.py b/neutron_tempest_plugin/scenario/test_floatingip.py
index 5079615..9902b68 100644
--- a/neutron_tempest_plugin/scenario/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/test_floatingip.py
@@ -217,7 +217,6 @@
     def resource_setup(cls):
         super(FloatingIPPortDetailsTest, cls).resource_setup()
 
-    @test.unstable_test("bug 1815585")
     @decorators.idempotent_id('a663aeee-dd81-492b-a207-354fd6284dbe')
     def test_floatingip_port_details(self):
         """Tests the following:
diff --git a/neutron_tempest_plugin/scenario/test_internal_dns.py b/neutron_tempest_plugin/scenario/test_internal_dns.py
index 406af3d..c0a2c04 100644
--- a/neutron_tempest_plugin/scenario/test_internal_dns.py
+++ b/neutron_tempest_plugin/scenario/test_internal_dns.py
@@ -24,6 +24,7 @@
 
 
 class InternalDNSTest(base.BaseTempestTestCase):
+    credentials = ['primary', 'admin']
 
     @utils.requires_ext(extension="dns-integration", service="network")
     @decorators.idempotent_id('988347de-07af-471a-abfa-65aea9f452a6')
diff --git a/neutron_tempest_plugin/scenario/test_multicast.py b/neutron_tempest_plugin/scenario/test_multicast.py
index 79f835e..7c1fd2d 100644
--- a/neutron_tempest_plugin/scenario/test_multicast.py
+++ b/neutron_tempest_plugin/scenario/test_multicast.py
@@ -15,11 +15,11 @@
 
 import netaddr
 from neutron_lib import constants
-from neutron_lib.utils import test
 from oslo_log import log
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
+from neutron_tempest_plugin.common import ip
 from neutron_tempest_plugin.common import ssh
 from neutron_tempest_plugin.common import utils
 from neutron_tempest_plugin import config
@@ -111,17 +111,18 @@
            'result_file': result_file}
 
 
-def get_unregistered_script(group, result_file):
+def get_unregistered_script(interface, group, result_file):
     return """#!/bin/bash
 export LC_ALL=en_US.UTF-8
-tcpdump -i any -s0 -vv host %(group)s -vvneA -s0 -l &> %(result_file)s &
-    """ % {'group': group,
+tcpdump -i %(interface)s host %(group)s -vvneA -s0 -l -c1 &> %(result_file)s &
+    """ % {'interface': interface,
+           'group': group,
            'result_file': result_file}
 
 
 class BaseMulticastTest(object):
 
-    credentials = ['primary']
+    credentials = ['primary', 'admin']
     force_tenant_isolation = False
 
     # Import configuration options
@@ -202,9 +203,9 @@
         )['server']
         self.wait_for_server_active(server)
         self.wait_for_guest_os_ready(server)
-        port = self.client.list_ports(
+        server['port'] = self.client.list_ports(
             network_id=self.network['id'], device_id=server['id'])['ports'][0]
-        server['fip'] = self.create_floatingip(port=port)
+        server['fip'] = self.create_floatingip(port=server['port'])
         server['ssh_client'] = ssh.Client(server['fip']['floating_ip_address'],
                                           self.username,
                                           pkey=self.keypair['private_key'])
@@ -242,18 +243,21 @@
             'echo "%s" > /tmp/multicast_traffic_receiver.py' % check_script)
 
     def _prepare_unregistered(self, server, mcast_address):
-        check_script = get_unregistered_script(
-            group=mcast_address, result_file=self.unregistered_output_file)
         ssh_client = ssh.Client(
             server['fip']['floating_ip_address'],
             self.username,
             pkey=self.keypair['private_key'])
+        ip_command = ip.IPCommand(ssh_client=ssh_client)
+        addresses = ip_command.list_addresses(port=server['port'])
+        port_iface = ip.get_port_device_name(addresses, server['port'])
+        check_script = get_unregistered_script(
+            interface=port_iface, group=mcast_address,
+            result_file=self.unregistered_output_file)
         self._check_cmd_installed_on_server(ssh_client, server['id'],
                                             'tcpdump')
         server['ssh_client'].execute_script(
             'echo "%s" > /tmp/unregistered_traffic_receiver.sh' % check_script)
 
-    @test.unstable_test("bug 1850288")
     @decorators.idempotent_id('113486fc-24c9-4be4-8361-03b1c9892867')
     def test_multicast_between_vms_on_same_network(self):
         """Test multicast messaging between two servers on the same network
@@ -343,19 +347,40 @@
         for receiver_id in receiver_ids:
             self.assertIn(receiver_id, replies_result)
 
-        # Kill the tcpdump command running on the unregistered node so
-        # tcpdump flushes its output to the output file
-        unregistered['ssh_client'].execute_script(
-            "killall tcpdump && sleep 2", become_root=True)
+        def check_unregistered_host():
+            unregistered_result = unregistered['ssh_client'].execute_script(
+                "cat {path} || echo '{path} not exists yet'".format(
+                    path=self.unregistered_output_file))
+            LOG.debug("Unregistered VM result: %s", unregistered_result)
+            return expected_result in unregistered_result
 
-        unregistered_result = unregistered['ssh_client'].execute_script(
-            "cat {path} || echo '{path} not exists yet'".format(
-                path=self.unregistered_output_file))
-        LOG.debug("Unregistered VM result: %s", unregistered_result)
-        expected_result = '0 packets captured'
-        if self._is_multicast_traffic_expected(mcast_address):
-            expected_result = '1 packet captured'
-        self.assertIn(expected_result, unregistered_result)
+        expected_result = '1 packet captured'
+        unregistered_error_message = (
+            'Unregistered server did not received expected packet.')
+        if not self._is_multicast_traffic_expected(mcast_address):
+            # Kill the tcpdump command runs on the unregistered node with "-c"
+            # option so it will be stopped automatically if it will receive
+            # packet matching filters,
+            # We don't expect any packets to be captured really in this case
+            # so let's kill tcpdump so it flushes its output to the output
+            # file.
+            expected_result = (
+                '0 packets captured\n0 packets received by filter')
+            unregistered_error_message = (
+                'Unregistered server received unexpected packet(s).')
+            try:
+                unregistered['ssh_client'].execute_script(
+                    "killall tcpdump && sleep 2", become_root=True)
+            except exceptions.SSHScriptFailed:
+                # Probably some packet was captured by tcpdump and due to that
+                # it is already stopped
+                self.assertTrue(check_unregistered_host(),
+                                unregistered_error_message)
+                return
+
+        utils.wait_until_true(
+            check_unregistered_host,
+            exception=RuntimeError(unregistered_error_message))
 
 
 class MulticastTestIPv4(BaseMulticastTest, base.BaseTempestTestCase):
diff --git a/neutron_tempest_plugin/scenario/test_ports.py b/neutron_tempest_plugin/scenario/test_ports.py
index b3aeb87..fb2d2b0 100644
--- a/neutron_tempest_plugin/scenario/test_ports.py
+++ b/neutron_tempest_plugin/scenario/test_ports.py
@@ -28,7 +28,7 @@
 
 
 class PortsTest(base.BaseTempestTestCase):
-    credentials = ['primary']
+    credentials = ['primary', 'admin']
 
     @classmethod
     def resource_setup(cls):
diff --git a/neutron_tempest_plugin/scenario/test_portsecurity.py b/neutron_tempest_plugin/scenario/test_portsecurity.py
index 257627c..c90db08 100644
--- a/neutron_tempest_plugin/scenario/test_portsecurity.py
+++ b/neutron_tempest_plugin/scenario/test_portsecurity.py
@@ -21,7 +21,7 @@
 
 
 class PortSecurityTest(base.BaseTempestTestCase):
-    credentials = ['primary']
+    credentials = ['primary', 'admin']
     required_extensions = ['port-security']
 
     @decorators.idempotent_id('61ab176e-d48b-42b7-b38a-1ba571ecc033')
diff --git a/neutron_tempest_plugin/scenario/test_trunk.py b/neutron_tempest_plugin/scenario/test_trunk.py
index 8f260ea..b86c019 100644
--- a/neutron_tempest_plugin/scenario/test_trunk.py
+++ b/neutron_tempest_plugin/scenario/test_trunk.py
@@ -97,6 +97,37 @@
                                    floating_ip=floating_ip, server=server,
                                    ssh_client=ssh_client)
 
+    def _create_advanced_servers_with_trunk_port(self, num_servers=1,
+                                                 subport_network=None,
+                                                 segmentation_id=None,
+                                                 vlan_subnet=None,
+                                                 use_advanced_image=False):
+        server_list = []
+        for _ in range(0, num_servers):
+            vm = self._create_server_with_trunk_port(
+                subport_network,
+                segmentation_id,
+                use_advanced_image)
+            server_list.append(vm)
+            self._configure_vlan_subport(
+                vm=vm,
+                vlan_tag=segmentation_id,
+                vlan_subnet=vlan_subnet)
+
+        for server in server_list:
+            self.check_connectivity(
+                host=vm.floating_ip['floating_ip_address'],
+                ssh_client=vm.ssh_client)
+
+        return server_list
+
+    def _check_servers_remote_connectivity(self, vms=None,
+                                           should_succeed=True):
+        self.check_remote_connectivity(
+            vms[0].ssh_client,
+            vms[1].subport['fixed_ips'][0]['ip_address'],
+            should_succeed=should_succeed)
+
     def _create_server_port(self, network=None, **params):
         network = network or self.network
         return self.create_port(network=network, name=self.rand_name,
@@ -247,53 +278,73 @@
             self._wait_for_trunk(vm.trunk)
             self._assert_has_ssh_connectivity(vm1.ssh_client)
 
+    @testtools.skipUnless(
+        (CONF.neutron_plugin_options.advanced_image_ref or
+         CONF.neutron_plugin_options.default_image_is_advanced),
+        "Advanced image is required to run this test.")
+    @testtools.skipUnless(
+         (CONF.neutron_plugin_options.reboots_in_test > 0),
+         "Number of reboots > 0 is reqired for this test")
+    @decorators.idempotent_id('a8a02c9b-b453-49b5-89a2-cce7da6680fb')
+    def test_subport_connectivity_soft_reboot(self):
+        vlan_tag = 10
+        vlan_network = self.create_network()
+        vlan_subnet = self.create_subnet(network=vlan_network, gateway=None)
+        use_advanced_image = (
+            not CONF.neutron_plugin_options.default_image_is_advanced)
+
+        # allow intra-security-group traffic
+        sg_rule = self.create_pingable_secgroup_rule(self.security_group['id'])
+        self.addCleanup(
+            self.os_primary.network_client.delete_security_group_rule,
+            sg_rule['id'])
+
+        vms = self._create_advanced_servers_with_trunk_port(
+            num_servers=2,
+            subport_network=vlan_network,
+            segmentation_id=vlan_tag,
+            vlan_subnet=vlan_subnet,
+            use_advanced_image=use_advanced_image)
+        # check remote connectivity true before reboots
+        self._check_servers_remote_connectivity(vms=vms)
+        client = self.os_tempest.compute.ServersClient()
+        for _ in range(CONF.neutron_plugin_options.reboots_in_test):
+            client.reboot_server(vms[1].server['id'],
+                                 **{'type': 'SOFT'})
+            self.wait_for_server_active(vms[1].server)
+            self._configure_vlan_subport(vm=vms[1],
+                                         vlan_tag=vlan_tag,
+                                         vlan_subnet=vlan_subnet)
+            self._check_servers_remote_connectivity(vms=vms)
+
     @test.unstable_test("bug 1897796")
     @testtools.skipUnless(
         (CONF.neutron_plugin_options.advanced_image_ref or
          CONF.neutron_plugin_options.default_image_is_advanced),
         "Advanced image is required to run this test.")
-    @decorators.idempotent_id('a8a02c9b-b453-49b5-89a2-cce7da66aafb')
+    @decorators.idempotent_id('a8a02c9b-b453-49b5-89a2-cce7da66bbcb')
     def test_subport_connectivity(self):
         vlan_tag = 10
         vlan_network = self.create_network()
         vlan_subnet = self.create_subnet(network=vlan_network, gateway=None)
-
         use_advanced_image = (
             not CONF.neutron_plugin_options.default_image_is_advanced)
-
-        vm1 = self._create_server_with_trunk_port(
+        vms = self._create_advanced_servers_with_trunk_port(
+            num_servers=2,
             subport_network=vlan_network,
             segmentation_id=vlan_tag,
+            vlan_subnet=vlan_subnet,
             use_advanced_image=use_advanced_image)
-        vm2 = self._create_server_with_trunk_port(
-            subport_network=vlan_network,
-            segmentation_id=vlan_tag,
-            use_advanced_image=use_advanced_image)
-
-        for vm in [vm1, vm2]:
-            self.check_connectivity(
-                host=vm.floating_ip['floating_ip_address'],
-                ssh_client=vm.ssh_client)
-            self._configure_vlan_subport(vm=vm,
-                                         vlan_tag=vlan_tag,
-                                         vlan_subnet=vlan_subnet)
-
         # Ping from server1 to server2 via VLAN interface should fail because
         # we haven't allowed ICMP
-        self.check_remote_connectivity(
-            vm1.ssh_client,
-            vm2.subport['fixed_ips'][0]['ip_address'],
-            should_succeed=False)
-
+        self._check_servers_remote_connectivity(vms=vms,
+                                                should_succeed=False)
         # allow intra-security-group traffic
         sg_rule = self.create_pingable_secgroup_rule(self.security_group['id'])
         self.addCleanup(
                 self.os_primary.network_client.delete_security_group_rule,
                 sg_rule['id'])
-        self.check_remote_connectivity(
-            vm1.ssh_client,
-            vm2.subport['fixed_ips'][0]['ip_address'],
-            servers=[vm1, vm2])
+        self._check_servers_remote_connectivity(vms=vms)
 
     @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
                           'Cold migration is not available.')
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index 144abc1..db37fad 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -148,6 +148,7 @@
           $NEUTRON_CONF:
             DEFAULT:
               enable_dvr: false
+              l3_ha: true
           # NOTE(slaweq): We can get rid of this hardcoded absolute path when
           # devstack-tempest job will be switched to use lib/neutron instead of
           # lib/neutron-legacy
@@ -205,7 +206,7 @@
       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)"
+      tempest_exclude_regex: "(^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)"
       devstack_localrc:
         Q_AGENT: openvswitch
         Q_ML2_TENANT_NETWORK_TYPE: vxlan
@@ -216,6 +217,7 @@
           $NEUTRON_CONF:
             DEFAULT:
               enable_dvr: false
+              l3_ha: true
           # NOTE(slaweq): We can get rid of this hardcoded absolute path when
           # devstack-tempest job will be switched to use lib/neutron instead of
           # lib/neutron-legacy
@@ -281,7 +283,7 @@
       network_available_features: *available_features
       # TODO(eolivare): remove VLAN Transparency tests from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1907548 will be fixed
-      tempest_black_regex: "(^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)"
+      tempest_exclude_regex: "(^neutron_tempest_plugin.scenario.test_vlan_transparency.VlanTransparencyTest)"
       devstack_localrc:
         Q_AGENT: linuxbridge
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions + network_api_extensions_linuxbridge) | join(',') }}"
@@ -293,6 +295,7 @@
             DEFAULT:
               enable_dvr: false
               vlan_transparent: true
+              l3_ha: true
             AGENT:
               debug_iptables_rules: true
           # NOTE(slaweq): We can get rid of this hardcoded absolute path when
@@ -343,7 +346,7 @@
       # be fixed
       # TODO(jlibosva): Remove the NetworkWritableMtuTest test from the list
       # once east/west fragmentation is supported in core OVN
-      tempest_black_regex: "\
+      tempest_exclude_regex: "\
           (?:neutron_tempest_plugin.scenario.test_ipv6.IPv6Test)|\
           (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_trunk_subport_lifecycle)|\
           (^neutron_tempest_plugin.scenario.test_mtu.NetworkWritableMtuTest)"
@@ -365,6 +368,7 @@
         OVN_BUILD_FROM_SOURCE: True
         OVN_BRANCH: "v20.12.0"
         OVS_BRANCH: "branch-2.15"
+        OVS_SYSCONFDIR: "/usr/local/etc/openvswitch"
       devstack_services:
         br-ex-tcpdump: true
         br-int-flows: true
@@ -408,6 +412,11 @@
               available_type_drivers: local,flat,vlan,geneve
               is_igmp_snooping_enabled: True
               firewall_driver: ovn
+      zuul_copy_output:
+        '{{ devstack_base_dir }}/data/ovs': 'logs'
+        '{{ devstack_base_dir }}/data/ovn': 'logs'
+        '{{ devstack_log_dir }}/ovsdb-server-nb.log': 'logs'
+        '{{ devstack_log_dir }}/ovsdb-server-sb.log': 'logs'
     irrelevant-files:
       - ^(test-|)requirements.txt$
       - ^releasenotes/.*$
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 14f1061..055fdfc 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -154,6 +154,29 @@
         - neutron-tempest-plugin-designate-scenario-victoria
 
 
+- project-template:
+    name: neutron-tempest-plugin-jobs-wallaby
+    check:
+      jobs:
+        - neutron-tempest-plugin-api-wallaby
+        - neutron-tempest-plugin-scenario-linuxbridge-wallaby
+        - neutron-tempest-plugin-scenario-openvswitch-wallaby
+        - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-wallaby
+        - neutron-tempest-plugin-scenario-ovn-wallaby
+    gate:
+      jobs:
+        - neutron-tempest-plugin-api-wallaby
+    #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
+    #              the experimental queue when it will be more stable
+    experimental:
+      jobs:
+        - neutron-tempest-plugin-dvr-multinode-scenario-wallaby
+        # TODO(slaweq): move it back to the check queue when bug
+        # https://bugs.launchpad.net/neutron/+bug/1891309
+        # will be fixed
+        - neutron-tempest-plugin-designate-scenario-wallaby
+
+
 - project:
     templates:
       - build-openstack-docs-pti
@@ -161,6 +184,7 @@
       - neutron-tempest-plugin-jobs-train
       - neutron-tempest-plugin-jobs-ussuri
       - neutron-tempest-plugin-jobs-victoria
+      - neutron-tempest-plugin-jobs-wallaby
       - check-requirements
       - tempest-plugin-jobs
       - release-notes-jobs-python3
@@ -170,16 +194,20 @@
         - neutron-tempest-plugin-sfc-train
         - neutron-tempest-plugin-sfc-ussuri
         - neutron-tempest-plugin-sfc-victoria
+        - neutron-tempest-plugin-sfc-wallaby
         - neutron-tempest-plugin-bgpvpn-bagpipe
         - neutron-tempest-plugin-bgpvpn-bagpipe-train
         - neutron-tempest-plugin-bgpvpn-bagpipe-ussuri
         - neutron-tempest-plugin-bgpvpn-bagpipe-victoria
+        - neutron-tempest-plugin-bgpvpn-bagpipe-wallaby
         - neutron-tempest-plugin-dynamic-routing
         - neutron-tempest-plugin-dynamic-routing-ussuri
         - neutron-tempest-plugin-dynamic-routing-victoria
+        - neutron-tempest-plugin-dynamic-routing-wallaby
         - neutron-tempest-plugin-vpnaas
         - neutron-tempest-plugin-vpnaas-ussuri
         - neutron-tempest-plugin-vpnaas-victoria
+        - neutron-tempest-plugin-vpnaas-wallaby
 
     gate:
       jobs:
diff --git a/zuul.d/queens_jobs.yaml b/zuul.d/queens_jobs.yaml
index a86e9a3..33430c8 100644
--- a/zuul.d/queens_jobs.yaml
+++ b/zuul.d/queens_jobs.yaml
@@ -122,6 +122,12 @@
       branch_override: stable/queens
       network_api_extensions: *api_extensions
       network_available_features: *available_features
+      devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
+              keepalived_use_no_track: False
       # TODO(slaweq): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
       # NOTE(bcafarel): remove DNS test as queens pinned version does not have
@@ -175,6 +181,10 @@
           /$NEUTRON_CORE_PLUGIN_CONF:
             ml2:
               type_drivers: flat,vlan,local,vxlan
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           # NOTE: ignores linux bridge's trunk delete on bound port test
           # for rocky branch (as https://review.opendev.org/#/c/605589/
diff --git a/zuul.d/rocky_jobs.yaml b/zuul.d/rocky_jobs.yaml
index ceee05f..0cc84a7 100644
--- a/zuul.d/rocky_jobs.yaml
+++ b/zuul.d/rocky_jobs.yaml
@@ -147,6 +147,12 @@
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+      devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
+              keepalived_use_no_track: False
       # NOTE(bcafarel): newer tests, unstable on rocky branch
       tempest_black_regex: "\
           (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
@@ -184,6 +190,12 @@
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+      devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
+              keepalived_use_no_track: False
       # TODO(bcafarel): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
       # NOTE(bcafarel): other are newer tests, unstable on rocky branch
@@ -241,6 +253,10 @@
           /$NEUTRON_CORE_PLUGIN_CONF:
             ml2:
               type_drivers: flat,vlan,local,vxlan
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Xenial keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           # NOTE: ignores linux bridge's trunk delete on bound port test
           # for rocky branch (as https://review.opendev.org/#/c/605589/
diff --git a/zuul.d/stein_jobs.yaml b/zuul.d/stein_jobs.yaml
index a5ab0a4..28729a4 100644
--- a/zuul.d/stein_jobs.yaml
+++ b/zuul.d/stein_jobs.yaml
@@ -130,6 +130,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
@@ -150,6 +155,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
@@ -170,6 +180,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
diff --git a/zuul.d/train_jobs.yaml b/zuul.d/train_jobs.yaml
index 7d85cdb..75c8ebe 100644
--- a/zuul.d/train_jobs.yaml
+++ b/zuul.d/train_jobs.yaml
@@ -129,6 +129,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived doesn't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
@@ -148,6 +153,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
@@ -167,6 +177,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
diff --git a/zuul.d/ussuri_jobs.yaml b/zuul.d/ussuri_jobs.yaml
index 475bebb..945ec25 100644
--- a/zuul.d/ussuri_jobs.yaml
+++ b/zuul.d/ussuri_jobs.yaml
@@ -134,6 +134,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
@@ -154,6 +159,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
@@ -173,6 +183,11 @@
       devstack_localrc:
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
       devstack_local_conf:
+        post-config:
+          $NEUTRON_L3_CONF:
+            DEFAULT:
+              # NOTE(slaweq): on Bionic keepalived don't knows this option yet
+              keepalived_use_no_track: False
         test-config:
           $TEMPEST_CONFIG:
             network-feature-enabled:
@@ -197,6 +212,13 @@
         # TODO(skaplons): v2.13.1 is incompatible with kernel 4.15.0-118, sticking to commit hash until new v2.13 tag is created
         OVS_BRANCH: 0047ca3a0290f1ef954f2c76b31477cf4b9755f5
         OVN_BRANCH: "v20.03.0"
+        # NOTE(slaweq): IGMP Snooping requires OVN 20.12
+        OVN_IGMP_SNOOPING_ENABLE: False
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            neutron_plugin_options:
+              is_igmp_snooping_enabled: False
 
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-ussuri
diff --git a/zuul.d/wallaby_jobs.yaml b/zuul.d/wallaby_jobs.yaml
new file mode 100644
index 0000000..fa2ddb6
--- /dev/null
+++ b/zuul.d/wallaby_jobs.yaml
@@ -0,0 +1,198 @@
+- job:
+    name: neutron-tempest-plugin-api-wallaby
+    parent: neutron-tempest-plugin-api
+    override-checkout: stable/wallaby
+    vars:
+      # TODO(slaweq): find a way to put this list of extensions in
+      # neutron repository and keep it different per branch,
+      # then it could be removed from here
+      network_api_extensions_common: &api_extensions
+        - address-group
+        - address-scope
+        - agent
+        - allowed-address-pairs
+        - auto-allocated-topology
+        - availability_zone
+        - binding
+        - default-subnetpools
+        - dhcp_agent_scheduler
+        - dns-domain-ports
+        - dns-integration
+        - empty-string-filtering
+        - expose-port-forwarding-in-fip
+        - expose-l3-conntrack-helper
+        - ext-gw-mode
+        - external-net
+        - extra_dhcp_opt
+        - extraroute
+        - extraroute-atomic
+        - filter-validation
+        - fip-port-details
+        - flavors
+        - floating-ip-port-forwarding
+        - floatingip-pools
+        - ip-substring-filtering
+        - l3-conntrack-helper
+        - l3-flavors
+        - l3-ha
+        - l3_agent_scheduler
+        - logging
+        - metering
+        - multi-provider
+        - net-mtu
+        - net-mtu-writable
+        - network-ip-availability
+        - network_availability_zone
+        - network-segment-range
+        - pagination
+        - port-resource-request
+        - port-mac-address-regenerate
+        - port-security
+        - port-security-groups-filtering
+        - project-id
+        - provider
+        - qos
+        - qos-bw-minimum-ingress
+        - qos-fip
+        - quotas
+        - quota_details
+        - rbac-address-group
+        - rbac-address-scope
+        - rbac-policies
+        - rbac-security-groups
+        - rbac-subnetpool
+        - router
+        - router-admin-state-down-before-update
+        - router_availability_zone
+        - security-group
+        - security-groups-remote-address-group
+        - segment
+        - service-type
+        - sorting
+        - standard-attr-description
+        - standard-attr-revisions
+        - standard-attr-segment
+        - standard-attr-tag
+        - standard-attr-timestamp
+        - subnet_allocation
+        - subnet-dns-publish-fixed-ip
+        - subnetpool-prefix-ops
+        - tag-ports-during-bulk-creation
+        - trunk
+        - trunk-details
+        - uplink-status-propagation
+      network_api_extensions_tempest:
+        - dvr
+      network_available_features: &available_features
+        - ipv6_metadata
+
+- job:
+    name: neutron-tempest-plugin-scenario-openvswitch-wallaby
+    parent: neutron-tempest-plugin-scenario-openvswitch
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      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(',') }}"
+
+- job:
+    name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-wallaby
+    parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
+    override-checkout: stable-wallaby
+    vars:
+      branch_override: stable-wallaby
+      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(',') }}"
+
+- job:
+    name: neutron-tempest-plugin-scenario-linuxbridge-wallaby
+    parent: neutron-tempest-plugin-scenario-linuxbridge
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      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(',') }}"
+
+- job:
+    name: neutron-tempest-plugin-scenario-ovn-wallaby
+    parent: neutron-tempest-plugin-scenario-ovn
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      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-wallaby
+    parent: neutron-tempest-plugin-dvr-multinode-scenario
+    override-checkout: stable/wallaby
+    vars:
+      network_api_extensions_common: *api_extensions
+      branch_override: stable/wallaby
+
+- job:
+    name: neutron-tempest-plugin-designate-scenario-wallaby
+    parent: neutron-tempest-plugin-designate-scenario
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      network_api_extensions_common: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-sfc-wallaby
+    parent: neutron-tempest-plugin-sfc
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      network_api_extensions_common: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-bgpvpn-bagpipe-wallaby
+    parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      network_api_extensions: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-dynamic-routing-wallaby
+    parent: neutron-tempest-plugin-dynamic-routing
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      network_api_extensions_common: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-vpnaas-wallaby
+    parent: neutron-tempest-plugin-vpnaas
+    override-checkout: stable/wallaby
+    vars:
+      branch_override: stable/wallaby
+      network_api_extensions_common: *api_extensions