diff --git a/roles/bridge/tasks/main.yml b/roles/bridge/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f96c19e4f00469daf1a790c335dfb339ce138818
--- /dev/null
+++ b/roles/bridge/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+- name: Create bridge
+  become: true
+  command: ip link add {{ bridge_name }} type bridge
+
+- name: Bring bridge interface up
+  become: true
+  command: ip link set {{ bridge_name }} up
+
+- name: Add member interface to bridge
+  become: true
+  command: ip link set {{ bridge_member_name }} master {{ bridge_name }}
diff --git a/roles/veth/tasks/main.yml b/roles/veth/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..034fec675f821d011dc1ae348f037decdc01ab00
--- /dev/null
+++ b/roles/veth/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+- name: Create veth pair
+  become: true
+  command: ip link add {{ veth_pair.0 }} type veth peer name {{ veth_pair.1 }}
+
+- name: Bring veth pair up
+  become: true
+  shell: ip link set {{ veth_pair.0 }} up && ip link set {{ veth_pair.1 }} up
+
+- name: Add first veth pair port to bridge
+  become: true
+  command: ip link set {{ veth_pair.0 }} master {{ bridge_name }}
diff --git a/tests/init-core-openstack.sh b/tests/init-core-openstack.sh
index 07c267a6cd1971449469abc58a31f55b1e5cda74..7d6dd8a9d8ec137325559991b09ea3d574891823 100755
--- a/tests/init-core-openstack.sh
+++ b/tests/init-core-openstack.sh
@@ -13,19 +13,6 @@ function init_runonce {
 
     echo "Initialising OpenStack resources via init-runonce"
     KOLLA_DEBUG=1 tools/init-runonce |& gawk '{ print strftime("%F %T"), $0; }' &> /tmp/logs/ansible/init-runonce
-
-    echo "Setting address on the external network bridge"
-    if [[ $SCENARIO == "linuxbridge" ]]; then
-        # NOTE(yoctozepto): linuxbridge agent manages its bridges by itself
-        # hence, we need to find the current name of the external network bridge
-        devname=$(basename $(readlink /sys/class/net/${EXT_NET_SLAVE_DEVICE}/master))
-    else
-        devname=br-ex
-        # NOTE(yoctozepto): ovs virtual interfaces are down (not used) by default
-        # hence, we need to bring the external network bridge up
-        sudo ip link set ${devname} up
-    fi
-    sudo ip addr add ${EXT_NET_LOCAL_ADDR} dev ${devname}
 }
 
 
diff --git a/tests/pre.yml b/tests/pre.yml
index 40583178dd1009e03dff80115537e0b12c8d47f7..0a6a9f7eb8c9a0c4d469a321cdb19659e1c12bee 100644
--- a/tests/pre.yml
+++ b/tests/pre.yml
@@ -20,8 +20,25 @@
     # because it is enslaved by a bridge
     - role: multi-node-vxlan-overlay
       vars:
-        vxlan_interface_name: "{{ neutron_external_interface_name }}"
+        vxlan_interface_name: "{{ neutron_external_vxlan_interface_name }}"
         vxlan_vni: 10001
+    - role: bridge
+      vars:
+        bridge_name: "{{ neutron_external_bridge_name }}"
+        bridge_member_name: "{{ neutron_external_vxlan_interface_name }}"
+    # TODO(mnasiadka): Update ipv6 jobs to test ipv6 in Neutron
+    - role: multi-node-managed-addressing
+      vars:
+        managed_interface_name: "{{ neutron_external_bridge_name }}"
+        managed_network_prefix: "{{ neutron_external_network_prefix }}"
+        managed_network_prefix_length: "{{ neutron_external_network_prefix_length }}"
+        managed_network_address_family: "ipv4"
+    - role: veth
+      vars:
+        veth_pair:
+          - "veth-{{ neutron_external_bridge_name }}"
+          - "veth-{{ neutron_external_bridge_name }}-ext"
+        bridge_name: "{{ neutron_external_bridge_name }}"
   tasks:
     # NOTE(yoctozepto): we use gawk to add time to each logged line
     # outside of Ansible (e.g. for init-runonce)
diff --git a/tests/run.yml b/tests/run.yml
index 86adf46f9221fecc0a733afb8bfeb23f05913d12..5c463e75ae8c21cb3038cf795ad20132007de416 100644
--- a/tests/run.yml
+++ b/tests/run.yml
@@ -374,8 +374,6 @@
             EXT_NET_CIDR: "{{ neutron_external_network_prefix }}0/{{ neutron_external_network_prefix_length }}"
             EXT_NET_RANGE: "start={{ neutron_external_network_prefix }}150,end={{ neutron_external_network_prefix }}199"
             EXT_NET_GATEWAY: "{{ neutron_external_network_prefix }}1"
-            EXT_NET_LOCAL_ADDR: "{{ neutron_external_network_prefix }}1/{{ neutron_external_network_prefix_length }}"
-            EXT_NET_SLAVE_DEVICE: "{{ neutron_external_interface_name }}"
             SCENARIO: "{{ scenario }}"
           when: openstack_core_tested or scenario in ['ironic', 'magnum', 'scenario_nfv', 'zun', 'octavia']
 
diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml
index 1e28b530b12d46a627f4fe0c74ca858322fc247c..fa9278c4937cd993f83b839eee58e48eaac05b78 100644
--- a/zuul.d/base.yaml
+++ b/zuul.d/base.yaml
@@ -37,7 +37,9 @@
       address_family: 'ipv4'
       neutron_external_network_prefix: "198.51.100."
       neutron_external_network_prefix_length: "24"
-      neutron_external_interface_name: vxlan1
+      neutron_external_bridge_name: br0
+      neutron_external_interface_name: "veth-{{ neutron_external_bridge_name }}-ext"
+      neutron_external_vxlan_interface_name: vxlan1
       tls_enabled: false
       # NOTE(yoctozepto): Ansible on Debian defaults to /usr/bin/python which is
       # python2. Let's use python3 instead as expected in 2020 and beyond.