diff --git a/overcloud-resource-registry-puppet.j2.yaml b/overcloud-resource-registry-puppet.j2.yaml
index c7cd96762b..4db3a0b589 100644
--- a/overcloud-resource-registry-puppet.j2.yaml
+++ b/overcloud-resource-registry-puppet.j2.yaml
@@ -164,6 +164,7 @@ resource_registry:
   OS::TripleO::Services::OVNController: OS::Heat::None
 
   OS::TripleO::Services::NeutronCorePluginMidonet: puppet/services/neutron-midonet.yaml
+  OS::TripleO::Services::NeutronCorePluginVTS: puppet/services/neutron-plugin-ml2-cisco-vts.yaml
   OS::TripleO::Services::NeutronOvsAgent: puppet/services/neutron-ovs-agent.yaml
   OS::TripleO::Services::NeutronLinuxbridgeAgent: OS::Heat::None
   OS::TripleO::Services::ComputeNeutronOvsAgent: puppet/services/neutron-ovs-agent.yaml
diff --git a/puppet/services/neutron-plugin-ml2-cisco-vts.yaml b/puppet/services/neutron-plugin-ml2-cisco-vts.yaml
new file mode 100644
index 0000000000..b8352047a8
--- /dev/null
+++ b/puppet/services/neutron-plugin-ml2-cisco-vts.yaml
@@ -0,0 +1,87 @@
+heat_template_version: pike
+
+description: >
+  VTS Controller Settings for the Cisco VTS Neutron ML2 Plugin.
+
+parameters:
+  ServiceData:
+    default: {}
+    description: Dictionary packing service data
+    type: json
+  ServiceNetMap:
+    default: {}
+    description: >
+      Mapping of service_name -> network name. Typically set
+      via parameter_defaults in the resource registry.  This
+      mapping overrides those in ServiceNetMapDefaults.
+    type: json
+  VTSUsername:
+    default: 'admin'
+    description: The username for the VTS server.
+    type: string
+  VTSPassword:
+    default: 'admin'
+    type: string
+    description: The password for the VTS server.
+    hidden: true
+  VTSServer:
+    description: VTS Server IP address
+    type: string
+  VTSVMMID:
+    description: VMM ID used on VTS
+    type: string
+    default: ''
+  VTSPort:
+    description: Port of the VTS Server
+    type: number
+    default: 8888
+  VTSTimeout:
+    description: Timeout for VTS server
+    type: number
+    default: 120
+  RoleName:
+    default: ''
+    description: Role name on which the service is applied
+    type: string
+  RoleParameters:
+    default: {}
+    description: Parameters specific to the role
+    type: json
+  EndpointMap:
+    default: {}
+    description: >
+      Mapping of service endpoint -> protocol. Typically set
+      via parameter_defaults in the resource registry.
+    type: json
+  DefaultPasswords:
+    default: {}
+    type: json
+
+resources:
+
+  NeutronMl2Base:
+    type: ./neutron-plugin-ml2.yaml
+    properties:
+      ServiceData: {get_param: ServiceData}
+      ServiceNetMap: {get_param: ServiceNetMap}
+      DefaultPasswords: {get_param: DefaultPasswords}
+      EndpointMap: {get_param: EndpointMap}
+      RoleName: {get_param: RoleName}
+      RoleParameters: {get_param: RoleParameters}
+
+outputs:
+  role_data:
+    description: Role data for the VTS ML2 Plugin.
+    value:
+      service_name: neutron_plugin_ml2_cisco_vts
+      config_settings:
+        map_merge:
+          - get_attr: [NeutronMl2Base, role_data, config_settings]
+          - vts::vts_ip: {get_param: VTSServer}
+            vts::vts_port: {get_param: VTSPort}
+            neutron::plugins::ml2::cisco::vts::vts_username: {get_param: VTSUsername}
+            neutron::plugins::ml2::cisco::vts::vts_password: {get_param: VTSPassword}
+            neutron::plugins::ml2::cisco::vts::vts_vmmid: {get_param: VTSVMMID}
+            neutron::plugins::ml2::cisco::vts::vts_timeout: {get_param: VTSTimeout}
+      step_config: |
+        include ::tripleo::profile::base::neutron::plugins::ml2
diff --git a/releasenotes/notes/add-cisco_vts_ml2-fa96d8edb117c416.yaml b/releasenotes/notes/add-cisco_vts_ml2-fa96d8edb117c416.yaml
new file mode 100644
index 0000000000..f0dbe958da
--- /dev/null
+++ b/releasenotes/notes/add-cisco_vts_ml2-fa96d8edb117c416.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add neutron-plugin-ml2-cisco-vts as a Neutron Core service template in support of the cisco VTS controller
+    ml2 plugin.
+