diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index c6cb02fc089036571cefb5e00f0b286ea6300521..92fb3015bbc01bdd61b7e1423b91fa0ea0a64eef 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -247,6 +247,8 @@ fluentd_syslog_port: "5140"
 
 zun_api_port: "9512"
 
+ovsdb_port: "6640"
+
 public_protocol: "{{ 'https' if kolla_enable_tls_external | bool else 'http' }}"
 internal_protocol: "http"
 admin_protocol: "http"
@@ -353,6 +355,7 @@ enable_neutron_agent_ha: "no"
 enable_neutron_bgp_dragent: "no"
 enable_nova_serialconsole_proxy: "no"
 enable_octavia: "no"
+enable_openvswitch: "{{ neutron_plugin_agent != 'linuxbridge' | bool }}"
 enable_panko: "no"
 enable_rally: "no"
 enable_sahara: "no"
@@ -493,7 +496,7 @@ designate_ns_record: "sample.openstack.org"
 # Neutron options
 #######################
 neutron_bgp_router_id: "1.1.1.1"
-
+neutron_bridge_name: "br-ex"
 
 #######################
 # Nova options
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index 23bbbb2ed6cddc9aa9bda0bd054ff0c485c83a6a..f0450c5cad59f23f08bc07f457a6b1236fac1f92 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -81,6 +81,11 @@ control
 [neutron:children]
 network
 
+[openvswitch:children]
+network
+compute
+manila-share
+
 [cinder:children]
 control
 
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index 0a2926c86c9c4047c0d580792c750b3558fff8f9..7775bdcb68076e98421f0a8d014bebc9e5c3a6e0 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -102,6 +102,11 @@ control
 [neutron:children]
 network
 
+[openvswitch:children]
+network
+compute
+manila-share
+
 [cinder:children]
 control
 
diff --git a/ansible/roles/neutron/defaults/main.yml b/ansible/roles/neutron/defaults/main.yml
index da17f3291b08f160b6c9f95cbab97e44c54c2eda..bd7f83747e38939512d1ed475a7964b81e23cf52 100644
--- a/ansible/roles/neutron/defaults/main.yml
+++ b/ansible/roles/neutron/defaults/main.yml
@@ -2,47 +2,6 @@
 project_name: "neutron"
 
 neutron_services:
-  openvswitch-db-server:
-    container_name: "openvswitch_db"
-    image: "{{ openvswitch_db_image_full }}"
-    enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
-    host_in_groups: >-
-      {{
-      True if orchestration_engine == 'KUBERNETES' else
-      inventory_hostname in groups['compute']
-      or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-      or inventory_hostname in groups['neutron-dhcp-agent']
-      or inventory_hostname in groups['neutron-l3-agent']
-      or inventory_hostname in groups['neutron-metadata-agent']
-      or inventory_hostname in groups['neutron-vpnaas-agent']
-      }}
-    volumes:
-      - "{{ node_config_directory }}/openvswitch-db-server/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
-      - "openvswitch_db:/var/lib/openvswitch/"
-  openvswitch-vswitchd:
-    container_name: "openvswitch_vswitchd"
-    image: "{{ openvswitch_vswitchd_image_full }}"
-    enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
-    host_in_groups: >-
-      {{
-      True if orchestration_engine == 'KUBERNETES' else
-      inventory_hostname in groups['compute']
-      or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-      or inventory_hostname in groups['neutron-dhcp-agent']
-      or inventory_hostname in groups['neutron-l3-agent']
-      or inventory_hostname in groups['neutron-metadata-agent']
-      or inventory_hostname in groups['neutron-vpnaas-agent']
-      }}
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/openvswitch-vswitchd/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
   neutron-server:
     container_name: "neutron_server"
     image: "{{ neutron_server_image_full }}"
@@ -280,14 +239,6 @@ neutron_bgp_dragent_image: "{{ docker_registry ~ '/' if docker_registry else ''
 neutron_bgp_dragent_tag: "{{ openstack_release }}"
 neutron_bgp_dragent_image_full: "{{ neutron_bgp_dragent_image }}:{{ neutron_bgp_dragent_tag }}"
 
-openvswitch_db_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-openvswitch-db-server"
-openvswitch_db_tag: "{{ openstack_release }}"
-openvswitch_db_image_full: "{{ openvswitch_db_image }}:{{ openvswitch_db_tag }}"
-
-openvswitch_vswitchd_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-openvswitch-vswitchd"
-openvswitch_vswitchd_tag: "{{ openstack_release }}"
-openvswitch_vswitchd_image_full: "{{ openvswitch_vswitchd_image }}:{{ openvswitch_vswitchd_tag }}"
-
 
 ####################
 # OpenStack
@@ -301,8 +252,6 @@ neutron_public_endpoint: "{{ public_protocol }}://{{ kolla_external_fqdn }}:{{ n
 
 neutron_logging_debug: "{{ openstack_logging_debug }}"
 
-neutron_bridge_name: "br-ex"
-
 openstack_neutron_auth: "{{ openstack_auth }}"
 
 ####################
diff --git a/ansible/roles/neutron/handlers/main.yml b/ansible/roles/neutron/handlers/main.yml
index 63d5b13d9e87c9ff88b3eab228d1fa15a2baa84c..197964db28e6f995cb32b8701587bccfcf51ade6 100644
--- a/ansible/roles/neutron/handlers/main.yml
+++ b/ansible/roles/neutron/handlers/main.yml
@@ -1,63 +1,4 @@
 ---
-- name: Restart openvswitch-db-server container
-  vars:
-    service_name: "openvswitch-db-server"
-    service: "{{ neutron_services[service_name] }}"
-    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
-    openvswitch_db_container: "{{ check_neutron_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
-  kolla_docker:
-    action: "recreate_or_restart_container"
-    common_options: "{{ docker_common_options }}"
-    name: "{{ service.container_name }}"
-    image: "{{ service.image }}"
-    volumes: "{{ service.volumes }}"
-  when:
-    - action != "config"
-    - service.enabled | bool
-    - service.host_in_groups | bool
-    - config_json | changed
-      or openvswitch_db_container | changed
-  notify:
-    - Waiting the openvswitch_db service to be ready
-    - Ensuring OVS bridge is properly setup
-
-- name: Waiting the openvswitch_db service to be ready
-  command: docker exec openvswitch_db ovs-vsctl --no-wait show
-  register: check_result
-  until: check_result | success
-  changed_when: False
-  retries: 30
-  delay: 2
-  notify:
-
-- name: Ensuring OVS bridge is properly setup
-  command: docker exec openvswitch_db /usr/local/bin/kolla_ensure_openvswitch_configured {{ item.0 }} {{ item.1 }}
-  register: status
-  changed_when: status.stdout.find('changed') != -1
-  with_together:
-    - "{{ neutron_bridge_name.split(',') }}"
-    - "{{ neutron_external_interface.split(',') }}"
-
-- name: Restart openvswitch-vswitchd container
-  vars:
-    service_name: "openvswitch-vswitchd"
-    service: "{{ neutron_services[service_name] }}"
-    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
-    openvswitch_vswitchd_container: "{{ check_neutron_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
-  kolla_docker:
-    action: "recreate_or_restart_container"
-    common_options: "{{ docker_common_options }}"
-    name: "{{ service.container_name }}"
-    image: "{{ service.image }}"
-    volumes: "{{ service.volumes }}"
-    privileged: "{{ service.privileged | default(False) }}"
-  when:
-    - action != "config"
-    - service.enabled | bool
-    - service.host_in_groups | bool
-    - config_json | changed
-      or openvswitch_vswitchd_container | changed
-
 - name: Restart neutron-server container
   vars:
     service_name: "neutron-server"
diff --git a/ansible/roles/openvswitch/defaults/main.yml b/ansible/roles/openvswitch/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7f04c13fde5880b422b50017d2557fdb2cc935f8
--- /dev/null
+++ b/ansible/roles/openvswitch/defaults/main.yml
@@ -0,0 +1,59 @@
+---
+project_name: "openvswitch"
+
+openvswitch_services:
+  openvswitch-db-server:
+    container_name: "openvswitch_db"
+    image: "{{ openvswitch_db_image_full }}"
+    enabled: "{{ enable_openvswitch }}"
+    group: openvswitch
+    host_in_groups: >-
+      {{
+      True if orchestration_engine == 'KUBERNETES' else
+      inventory_hostname in groups['compute']
+      or (enable_manila | bool and inventory_hostname in groups['manila-share'])
+      or inventory_hostname in groups['neutron-dhcp-agent']
+      or inventory_hostname in groups['neutron-l3-agent']
+      or inventory_hostname in groups['neutron-metadata-agent']
+      or inventory_hostname in groups['neutron-vpnaas-agent']
+      }}
+    volumes:
+      - "{{ node_config_directory }}/openvswitch-db-server/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+      - "openvswitch_db:/var/lib/openvswitch/"
+  openvswitch-vswitchd:
+    container_name: "openvswitch_vswitchd"
+    image: "{{ openvswitch_vswitchd_image_full }}"
+    enabled: "{{ enable_openvswitch }}"
+    group: openvswitch
+    host_in_groups: >-
+      {{
+      True if orchestration_engine == 'KUBERNETES' else
+      inventory_hostname in groups['compute']
+      or (enable_manila | bool and inventory_hostname in groups['manila-share'])
+      or inventory_hostname in groups['neutron-dhcp-agent']
+      or inventory_hostname in groups['neutron-l3-agent']
+      or inventory_hostname in groups['neutron-metadata-agent']
+      or inventory_hostname in groups['neutron-vpnaas-agent']
+      }}
+    privileged: True
+    volumes:
+      - "{{ node_config_directory }}/openvswitch-vswitchd/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+
+####################
+# Docker
+####################
+
+openvswitch_db_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-openvswitch-db-server"
+openvswitch_db_tag: "{{ openstack_release }}"
+openvswitch_db_image_full: "{{ openvswitch_db_image }}:{{ openvswitch_db_tag }}"
+
+openvswitch_vswitchd_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-openvswitch-vswitchd"
+openvswitch_vswitchd_tag: "{{ openstack_release }}"
+openvswitch_vswitchd_image_full: "{{ openvswitch_vswitchd_image }}:{{ openvswitch_vswitchd_tag }}"
diff --git a/ansible/roles/openvswitch/handlers/main.yml b/ansible/roles/openvswitch/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e6b6d84a116b158b546e6e89093395f303090289
--- /dev/null
+++ b/ansible/roles/openvswitch/handlers/main.yml
@@ -0,0 +1,59 @@
+---
+- name: Restart openvswitch-db-server container
+  vars:
+    service_name: "openvswitch-db-server"
+    service: "{{ openvswitch_services[service_name] }}"
+    config_json: "{{ openvswitch_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    openvswitch_db_container: "{{ check_openvswitch_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    volumes: "{{ service.volumes }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or openvswitch_db_container | changed
+  notify:
+    - Waiting for openvswitch_db service to be ready
+    - Ensuring OVS bridge is properly setup
+
+- name: Waiting for openvswitch_db service to be ready
+  command: docker exec openvswitch_db ovs-vsctl --no-wait show
+  register: check_result
+  until: check_result | success
+  changed_when: False
+  retries: 30
+  delay: 2
+  notify:
+
+- name: Ensuring OVS bridge is properly setup
+  command: docker exec openvswitch_db /usr/local/bin/kolla_ensure_openvswitch_configured {{ item.0 }} {{ item.1 }}
+  register: status
+  changed_when: status.stdout.find('changed') != -1
+  with_together:
+    - "{{ neutron_bridge_name.split(',') }}"
+    - "{{ neutron_external_interface.split(',') }}"
+
+- name: Restart openvswitch-vswitchd container
+  vars:
+    service_name: "openvswitch-vswitchd"
+    service: "{{ openvswitch_services[service_name] }}"
+    config_json: "{{ openvswitch_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    openvswitch_vswitchd_container: "{{ check_openvswitch_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or openvswitch_vswitchd_container | changed
diff --git a/ansible/roles/openvswitch/meta/main.yml b/ansible/roles/openvswitch/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6b4fff8fef6f81d35b73a30c90de45639db41cc9
--- /dev/null
+++ b/ansible/roles/openvswitch/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+  - { role: common }
diff --git a/ansible/roles/openvswitch/tasks/check.yml b/ansible/roles/openvswitch/tasks/check.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ed97d539c095cf1413af30cc23dea272095b97dd
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/check.yml
@@ -0,0 +1 @@
+---
diff --git a/ansible/roles/openvswitch/tasks/config.yml b/ansible/roles/openvswitch/tasks/config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0a24c63f4fa517103b6bc6f8ff13914d87a1f2b9
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/config.yml
@@ -0,0 +1,39 @@
+---
+- name: Ensuring config directories exist
+  file:
+    path: "{{ node_config_directory }}/{{ item.key }}"
+    state: "directory"
+    recurse: yes
+  when:
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ openvswitch_services }}"
+
+- name: Copying over config.json files for services
+  template:
+    src: "{{ item.key }}.json.j2"
+    dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
+  register: openvswitch_config_jsons
+  when:
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ openvswitch_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
+
+- name: Check openvswitch containers
+  kolla_docker:
+    action: "compare_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ item.value.container_name }}"
+    image: "{{ item.value.image }}"
+    privileged: "{{ item.value.privileged | default(False) }}"
+    volumes: "{{ item.value.volumes }}"
+  register: check_openvswitch_containers
+  when:
+    - action != "config"
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ openvswitch_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
diff --git a/ansible/roles/openvswitch/tasks/deploy.yml b/ansible/roles/openvswitch/tasks/deploy.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3fa34a2afa76672c3f064783a0b6bd756725cedb
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/deploy.yml
@@ -0,0 +1,8 @@
+---
+# enforce ironic usage only with openvswitch
+- include: ironic-check.yml
+
+- include: config.yml
+
+- name: Flush Handlers
+  meta: flush_handlers
diff --git a/ansible/roles/openvswitch/tasks/ironic-check.yml b/ansible/roles/openvswitch/tasks/ironic-check.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a578ce2c72cc52064bc9bab86792cd31068e08f6
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/ironic-check.yml
@@ -0,0 +1,6 @@
+---
+# TODO(SamYaple): run verification checks at start of playbook
+- fail: msg="neutron_plugin_agent must use openvswitch with Ironic"
+  when:
+    - enable_ironic | bool
+    - neutron_plugin_agent != "openvswitch"
diff --git a/ansible/roles/openvswitch/tasks/main.yml b/ansible/roles/openvswitch/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b017e8b4ad9edbc10e43b690b269d460e5b9b1f4
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+- include: "{{ action }}.yml"
diff --git a/ansible/roles/openvswitch/tasks/precheck.yml b/ansible/roles/openvswitch/tasks/precheck.yml
new file mode 100644
index 0000000000000000000000000000000000000000..31961dd2a3286e36ba48126adaafe916afeecfea
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/precheck.yml
@@ -0,0 +1,19 @@
+---
+- name: Get container facts
+  kolla_container_facts:
+    name:
+      - openvswitch_db
+  register: container_facts
+
+- name: Checking free port for OVSDB
+  vars:
+    openvswitch_db: "{{ openvswitch_services['openvswitch-db-server'] }}"
+  wait_for:
+    host: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}"
+    port: "{{ ovsdb_port }}"
+    connect_timeout: 1
+    state: stopped
+  when:
+    - container_facts['openvswitch_db'] is not defined
+    - inventory_hostname in groups[openvswitch_db.group]
+    - openvswitch_db.enabled | bool
diff --git a/ansible/roles/openvswitch/tasks/pull.yml b/ansible/roles/openvswitch/tasks/pull.yml
new file mode 100644
index 0000000000000000000000000000000000000000..83056917d97f25c158cf67c327f606b82b73ea1e
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/pull.yml
@@ -0,0 +1,10 @@
+---
+- name: Pulling Openvswitch images
+  kolla_docker:
+    action: "pull_image"
+    common_options: "{{ docker_common_options }}"
+    image: "{{ item.value.image }}"
+  when:
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ openvswitch_services }}"
diff --git a/ansible/roles/openvswitch/tasks/reconfigure.yml b/ansible/roles/openvswitch/tasks/reconfigure.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e078ef1318f52fd9e74ccb13343015761312ca52
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/reconfigure.yml
@@ -0,0 +1,2 @@
+---
+- include: deploy.yml
diff --git a/ansible/roles/openvswitch/tasks/upgrade.yml b/ansible/roles/openvswitch/tasks/upgrade.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5aac9f5a7f854e831b74bae654cce2a9b0dd2861
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/upgrade.yml
@@ -0,0 +1,5 @@
+---
+- include: config.yml
+
+- name: Flush Handlers
+  meta: flush_handlers
diff --git a/ansible/roles/neutron/templates/openvswitch-db-server.json.j2 b/ansible/roles/openvswitch/templates/openvswitch-db-server.json.j2
similarity index 100%
rename from ansible/roles/neutron/templates/openvswitch-db-server.json.j2
rename to ansible/roles/openvswitch/templates/openvswitch-db-server.json.j2
diff --git a/ansible/roles/neutron/templates/openvswitch-vswitchd.json.j2 b/ansible/roles/openvswitch/templates/openvswitch-vswitchd.json.j2
similarity index 100%
rename from ansible/roles/neutron/templates/openvswitch-vswitchd.json.j2
rename to ansible/roles/openvswitch/templates/openvswitch-vswitchd.json.j2
diff --git a/ansible/site.yml b/ansible/site.yml
index 41c8afce7b29f5e5e79d9d6b211da8985a1a0e46..bca1aafba7b8ebd15b0ecca7dd681c28ade7c10c 100644
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -274,6 +274,14 @@
         tags: nova,
         when: enable_nova | bool }
 
+- name: Apply role openvswitch
+  hosts:
+    - openvswitch
+  roles:
+    - { role: openvswitch,
+        tags: openvswitch,
+        when: enable_openvswitch | bool }
+
 # (gmmaha): Please do not change the order listed here. The current order is a
 # workaround to fix the bug https://bugs.launchpad.net/kolla/+bug/1546789
 - name: Apply role neutron
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index cc2360924f6c632c7d5b22e0a4a8cfb19aa64afb..7fec81ae94e8b4b007128b84a55eb47d85daa47f 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -179,6 +179,7 @@ kolla_internal_vip_address: "10.10.10.254"
 #enable_neutron_vpnaas: "no"
 #enable_nova_serialconsole_proxy: "no"
 #enable_octavia: "no"
+#enable_openvswitch: "{{ neutron_plugin_agent != 'linuxbridge' | bool }}"
 #enable_panko: "no"
 #enable_rally: "no"
 #enable_sahara: "no"