diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index aae2c1b4dc..6e2fadb84e 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -122,7 +122,7 @@ bifrost_network_interface: "{{ network_interface }}"
 dns_interface: "{{ network_interface }}"
 tunnel_interface_address: "{{ hostvars[inventory_hostname]['ansible_' + tunnel_interface]['ipv4']['address'] }}"
 
-# Valid options are [ openvswitch, linuxbridge ]
+# Valid options are [ openvswitch, linuxbridge, vmware_nsxv, vmware_dvs ]
 neutron_plugin_agent: "openvswitch"
 
 # The default ports used by each service.
@@ -512,14 +512,14 @@ designate_ns_record: "sample.openstack.org"
 # Neutron options
 #######################
 neutron_bgp_router_id: "1.1.1.1"
-neutron_bridge_name: "br-ex"
+neutron_bridge_name: "{{ 'br-dvs' if neutron_plugin_agent == 'vmware_dvs' else 'br-ex' }}"
 # Comma-separated type of enabled ml2 type drivers
 neutron_type_drivers: "flat,vlan,vxlan"
 # Comma-separated types of tenant networks (should be listed in 'neutron_type_drivers')
 # NOTE: for ironic this list should also contain 'flat'
 neutron_tenant_network_types: "vxlan"
 
-computes_need_external_bridge: "{{ enable_neutron_dvr | bool or enable_neutron_provider_networks | bool }}"
+computes_need_external_bridge: "{{ enable_neutron_dvr | bool or enable_neutron_provider_networks | bool and neutron_plugin_agent != 'vmware_dvs' }}"
 
 #######################
 # Nova options
diff --git a/ansible/roles/neutron/defaults/main.yml b/ansible/roles/neutron/defaults/main.yml
index db2b834adf..f24ab2b4aa 100644
--- a/ansible/roles/neutron/defaults/main.yml
+++ b/ansible/roles/neutron/defaults/main.yml
@@ -81,7 +81,7 @@ neutron_services:
     container_name: "neutron_l3_agent"
     image: "{{ neutron_l3_agent_image_full }}"
     privileged: True
-    enabled: "{{ not enable_neutron_vpnaas | bool and neutron_plugin_agent != 'vmware_nsxv' }}"
+    enabled: "{{ not enable_neutron_vpnaas | bool and neutron_plugin_agent not in ['vmware_nsxv', 'vmware_dvs'] }}"
     host_in_groups: >-
       {{
       inventory_hostname in groups['neutron-l3-agent']
@@ -97,7 +97,7 @@ neutron_services:
     container_name: "neutron_lbaas_agent"
     image: "{{ neutron_lbaas_agent_image_full }}"
     privileged: True
-    enabled: "{{ enable_neutron_lbaas | bool and neutron_plugin_agent != 'vmware_nsxv' }}"
+    enabled: "{{ enable_neutron_lbaas | bool and neutron_plugin_agent not in ['vmware_nsxv', 'vmware_dvs'] }}"
     group: "neutron-lbaas-agent"
     host_in_groups: "{{ inventory_hostname in groups['neutron-lbaas-agent'] }}"
     volumes:
@@ -125,7 +125,7 @@ neutron_services:
     container_name: "neutron_vpnaas_agent"
     image: "{{ neutron_vpnaas_agent_image_full }}"
     privileged: True
-    enabled: "{{ enable_neutron_vpnaas | bool and neutron_plugin_agent != 'vmware_nsxv' }}"
+    enabled: "{{ enable_neutron_vpnaas | bool and neutron_plugin_agent not in ['vmware_nsxv', 'vmware_dvs'] }}"
     group: "neutron-vpnaas-agent"
     host_in_groups: "{{ inventory_hostname in groups['neutron-vpnaas-agent'] }}"
     volumes:
@@ -138,7 +138,7 @@ neutron_services:
     container_name: "neutron_bgp_dragent"
     image: "{{ neutron_bgp_dragent_image_full }}"
     privileged: True
-    enabled: "{{ enable_neutron_bgp_dragent | bool and neutron_plugin_agent != 'vmware_nsxv' }}"
+    enabled: "{{ enable_neutron_bgp_dragent | bool and neutron_plugin_agent not in ['vmware_nsxv', 'vmware_dvs'] }}"
     group: "neutron-bgp-dragent"
     host_in_groups: "{{ inventory_hostname in groups['neutron-bgp-dragent'] }}"
     volumes:
@@ -291,3 +291,14 @@ vmware_nsxv_backup_edge_pool: "service:compact:1:2"
 vmware_nsxv_spoofguard_enabled: "false"
 vmware_nsxv_metadata_initializer: "false"
 vmware_nsxv_edge_ha: "false"
+
+####################
+# VMware DVS
+####################
+vmware_dvs_host_ip: "192.168.1.1"
+vmware_dvs_host_port: "443"
+vmware_dvs_host_username: "admin"
+vmware_dvs_host_password: "password"
+vmware_dvs_insecure: "True"
+vmware_dvs_dvs_name: "VDS-1"
+vmware_dvs_dhcp_override_mac: ""
diff --git a/ansible/roles/neutron/tasks/config.yml b/ansible/roles/neutron/tasks/config.yml
index 474f06ff37..40fd1af8bd 100644
--- a/ansible/roles/neutron/tasks/config.yml
+++ b/ansible/roles/neutron/tasks/config.yml
@@ -283,7 +283,7 @@
   when:
     - neutron_server.enabled | bool
     - neutron_server.host_in_groups | bool
-    - neutron_plugin_agent == 'vmware_nsxv'
+    - neutron_plugin_agent in ['vmware_nsxv', 'vmware_dvs']
   notify:
     - "Restart {{ service_name }} container"
 
diff --git a/ansible/roles/neutron/templates/dhcp_agent.ini.j2 b/ansible/roles/neutron/templates/dhcp_agent.ini.j2
index c6ba97f65b..71c40967cc 100644
--- a/ansible/roles/neutron/templates/dhcp_agent.ini.j2
+++ b/ansible/roles/neutron/templates/dhcp_agent.ini.j2
@@ -5,6 +5,17 @@ enable_isolated_metadata = true
 force_metadata = true
 dnsmasq_dns_servers = 8.8.8.8,8.8.4.4
 
+{% if neutron_plugin_agent == 'vmware_dvs' %}
+ovs_integration_bridge = {{ neutron_bridge_name }}
+enable_metadata_network = True
+dhcp_driver = vmware_nsx.plugins.dvs.dhcp.Dnsmasq
+use_namespaces = True
+ovs_use_veth = False
+{% if vmware_dvs_dhcp_override_mac != '' %}
+dhcp_override_mac = {{ vmware_dvs_dhcp_override_mac }}
+{% endif %}
+{% endif %}
+
 [ovs]
 ovsdb_interface = native
 ovsdb_connection = tcp:{{ api_interface_address }}:6640
diff --git a/ansible/roles/neutron/templates/neutron-server.json.j2 b/ansible/roles/neutron/templates/neutron-server.json.j2
index 15182dada9..076e9a5eae 100644
--- a/ansible/roles/neutron/templates/neutron-server.json.j2
+++ b/ansible/roles/neutron/templates/neutron-server.json.j2
@@ -1,5 +1,5 @@
 {
-    "command": "neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/neutron_lbaas.conf --config-file /etc/neutron/neutron_vpnaas.conf --config-file /etc/neutron/fwaas_driver.ini {% if neutron_plugin_agent == 'vmware_nsxv' %} --config-file /etc/neutron/plugins/vmware/nsx.ini {% endif %}",
+    "command": "neutron-server --config-file /etc/neutron/neutron.conf {% if neutron_plugin_agent in ['openvswitch', 'linuxbridge'] %} --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/neutron_lbaas.conf --config-file /etc/neutron/neutron_vpnaas.conf {% elif neutron_plugin_agent in ['vmware_nsx', 'vmware_dvs'] %} --config-file /etc/neutron/plugins/vmware/nsx.ini {% endif %} --config-file /etc/neutron/fwaas_driver.ini",
     "config_files": [
         {
             "source": "{{ container_config_directory }}/neutron.conf",
@@ -37,14 +37,14 @@
             "owner": "neutron",
             "perm": "0600",
             "optional": true
-        }{% if neutron_plugin_agent == 'vmware_nsxv' -%},
+        }{% if neutron_plugin_agent in ['vmware_nsxv', 'vmware_dvs'] -%},
         {
             "source": "{{ container_config_directory }}/nsx.ini",
             "dest": "/etc/neutron/plugins/vmware/nsx.ini",
             "owner": "neutron",
+            "optional": {{ (neutron_plugin_agent not in ['vmware_nsxv', 'vmware_dvs']) | string | lower }}
             "perm": "0600"
-        }
-        {% endif -%}
+        }{% endif %}
     ],
     "permissions": [
         {
diff --git a/ansible/roles/neutron/templates/neutron.conf.j2 b/ansible/roles/neutron/templates/neutron.conf.j2
index a196d49809..919c7422c6 100644
--- a/ansible/roles/neutron/templates/neutron.conf.j2
+++ b/ansible/roles/neutron/templates/neutron.conf.j2
@@ -39,6 +39,8 @@ allow_overlapping_ips = true
 
 {% if neutron_plugin_agent == 'vmware_nsxv' %}
 core_plugin = vmware_nsx.plugin.NsxVPlugin
+{% elif neutron_plugin_agent == 'vmware_dvs' %}
+core_plugin = vmware_nsx.plugin.NsxDvsPlugin
 {% else %}
 core_plugin = ml2
 service_plugins = {{ neutron_service_plugins|map(attribute='name')|join(',') }}
diff --git a/ansible/roles/neutron/templates/nsx.ini.j2 b/ansible/roles/neutron/templates/nsx.ini.j2
index 45307eb61c..2dda41d28a 100644
--- a/ansible/roles/neutron/templates/nsx.ini.j2
+++ b/ansible/roles/neutron/templates/nsx.ini.j2
@@ -1,3 +1,4 @@
+{% if neutron_plugin_agent == 'vmware_nsxv' %}
 [nsxv]
 user = {{ vmware_nsxv_user }}
 password = {{ vmware_nsxv_password }}
@@ -14,4 +15,14 @@ backup_edge_pool = {{ vmware_nsxv_backup_edge_pool }}
 spoofguard_enabled = {{ vmware_nsxv_spoofguard_enabled }}
 metadata_initializer = {{ vmware_nsxv_metadata_initializer }}
 edge_ha = {{ vmware_nsxv_edge_ha }}
-
+{% elif neutron_plugin_agent == 'vmware_dvs' %}
+[dvs]
+host_ip = {{ vmware_dvs_host_ip }}
+host_port = {{ vmware_dvs_host_port }}
+host_username = {{ vmware_dvs_host_username }}
+host_password = {{ vmware_dvs_host_password }}
+task_poll_interval = 0.5
+insecure = {{ vmware_dvs_insecure }}
+api_retry_count = 10
+dvs_name = {{ vmware_dvs_dvs_name }}
+{% endif %}
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index 69d7c0be19..617e0fd4b7 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -86,7 +86,7 @@ kolla_internal_vip_address: "10.10.10.254"
 # addresses for that reason.
 #neutron_external_interface: "eth1"
 
-# Valid options are [ openvswitch, linuxbridge, vmware_nsxv ]
+# Valid options are [ openvswitch, linuxbridge, vmware_nsxv, vmware_dvs ]
 #neutron_plugin_agent: "openvswitch"