diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 9ad3576a20..e0322cbd0e 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -257,6 +257,7 @@ enable_mistral: "no"
 enable_mongodb: "no"
 enable_multipathd: "no"
 enable_murano: "no"
+enable_neutron_vpnaas: "no"
 enable_neutron_dvr: "no"
 enable_neutron_lbaas: "no"
 enable_neutron_qos: "no"
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index d4c96d7da9..1783a97997 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -184,6 +184,9 @@ neutron
 [neutron-metadata-agent:children]
 neutron
 
+[neutron-vpnaas-agent:children]
+neutron
+
 # Cinder
 [cinder-api:children]
 cinder
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index f54341a151..3b130ddc76 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -202,6 +202,9 @@ neutron
 [neutron-metadata-agent:children]
 neutron
 
+[neutron-vpnaas-agent:children]
+neutron
+
 # Cinder
 [cinder-api:children]
 cinder
diff --git a/ansible/roles/neutron/defaults/main.yml b/ansible/roles/neutron/defaults/main.yml
index 0de2a597f7..699c6b688c 100644
--- a/ansible/roles/neutron/defaults/main.yml
+++ b/ansible/roles/neutron/defaults/main.yml
@@ -44,6 +44,10 @@ neutron_server_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{
 neutron_server_tag: "{{ openstack_release }}"
 neutron_server_image_full: "{{ neutron_server_image }}:{{ neutron_server_tag }}"
 
+neutron_vpnaas_agent_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-neutron-vpnaas-agent"
+neutron_vpnaas_agent_tag: "{{ openstack_release }}"
+neutron_vpnaas_agent_image_full: "{{ neutron_vpnaas_agent_image }}:{{ neutron_vpnaas_agent_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 }}"
diff --git a/ansible/roles/neutron/tasks/bootstrap_service.yml b/ansible/roles/neutron/tasks/bootstrap_service.yml
index b654e56b2e..50d114535f 100644
--- a/ansible/roles/neutron/tasks/bootstrap_service.yml
+++ b/ansible/roles/neutron/tasks/bootstrap_service.yml
@@ -41,3 +41,26 @@
     - inventory_hostname in groups['neutron-lbaas-agent']
   run_once: True
   delegate_to: "{{ groups['neutron-lbaas-agent'][0] }}"
+
+- name: Running Neutron vpnaas bootstrap container
+  kolla_docker:
+    action: "start_container"
+    common_options: "{{ docker_common_options }}"
+    detach: False
+    environment:
+      KOLLA_BOOTSTRAP:
+      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
+    image: "{{ neutron_vpnaas_agent_image_full }}"
+    labels:
+      BOOTSTRAP:
+    name: "bootstrap_neutron_vpnaas_agent"
+    restart_policy: "never"
+    volumes:
+      - "{{ node_config_directory }}/neutron-vpnaas-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  when:
+    - enable_neutron_vpnaas | bool
+    - inventory_hostname in groups['neutron-vpnaas-agent']
+  run_once: True
+  delegate_to: "{{ groups['neutron-vpnaas-agent'][0] }}"
diff --git a/ansible/roles/neutron/tasks/config.yml b/ansible/roles/neutron/tasks/config.yml
index 3ece8199bd..1c7d0238b7 100644
--- a/ansible/roles/neutron/tasks/config.yml
+++ b/ansible/roles/neutron/tasks/config.yml
@@ -8,6 +8,7 @@
   when:
     - set_sysctl | bool
     - inventory_hostname in groups['neutron-l3-agent']
+      or inventory_hostname in groups['neutron-vpnaas-agent']
 
 - name: Ensuring config directories exist
   file:
@@ -24,6 +25,7 @@
     - "openvswitch-db-server"
     - "openvswitch-vswitchd"
     - "neutron-lbaas-agent"
+    - "neutron-vpnaas-agent"
 
 - name: Copying over config.json files for services
   template:
@@ -39,6 +41,7 @@
     - "openvswitch-db-server"
     - "openvswitch-vswitchd"
     - "neutron-lbaas-agent"
+    - "neutron-vpnaas-agent"
 
 - name: Copying over neutron.conf
   merge_configs:
@@ -61,6 +64,31 @@
     - "neutron-openvswitch-agent"
     - "neutron-server"
     - "neutron-lbaas-agent"
+    - "neutron-vpnaas-agent"
+
+- name: Copying over neutron_lbaas.conf
+  merge_configs:
+    vars:
+      service_name: "{{ item }}"
+    sources:
+      - "{{ role_path }}/templates/neutron_lbaas.conf.j2"
+      - "{{ node_custom_config }}/neutron/neutron_lbaas.conf"
+      - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron_lbaas.conf"
+    dest: "{{ node_config_directory }}/{{ item }}/neutron_lbaas.conf"
+  with_items:
+    - "neutron-server"
+
+- name: Copying over neutron_vpnaas.conf
+  merge_configs:
+    vars:
+      service_name: "{{ item }}"
+    sources:
+      - "{{ role_path }}/templates/neutron_vpnaas.conf.j2"
+      - "{{ node_custom_config }}/neutron/neutron_vpnaas.conf"
+      - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron_vpnaas.conf"
+    dest: "{{ node_config_directory }}/{{ item }}/neutron_vpnaas.conf"
+  with_items:
+    - "neutron-server"
 
 - name: Copying over ml2_conf.ini
   merge_configs:
@@ -79,6 +107,7 @@
     - "neutron-metadata-agent"
     - "neutron-openvswitch-agent"
     - "neutron-server"
+    - "neutron-vpnaas-agent"
 
 - name: Copying over dhcp_agent.ini
   merge_configs:
@@ -108,6 +137,7 @@
     dest: "{{ node_config_directory }}/{{ item }}/l3_agent.ini"
   with_items:
     - "neutron-l3-agent"
+    - "neutron-vpnaas-agent"
 
 - name: Copying over fwaas_driver.ini
   merge_configs:
@@ -119,6 +149,7 @@
     dest: "{{ node_config_directory }}/{{ item }}/fwaas_driver.ini"
   with_items:
     - "neutron-l3-agent"
+    - "neutron-vpnaas-agent"
 
 - name: Copying over metadata_agent.ini
   merge_configs:
@@ -141,3 +172,14 @@
     dest: "{{ node_config_directory }}/{{ item }}/lbaas_agent.ini"
   with_items:
     - "neutron-lbaas-agent"
+
+- name: Copying over vpnaas_agent.ini
+  merge_configs:
+    vars:
+      service_name: "{{ item }}"
+    sources:
+      - "{{ role_path }}/templates/vpnaas_agent.ini.j2"
+      - "/etc/kolla/config/neutron/vpnaas_agent.ini"
+    dest: "{{ node_config_directory }}/{{ item }}/vpnaas_agent.ini"
+  with_items:
+    - "neutron-vpnaas-agent"
diff --git a/ansible/roles/neutron/tasks/deploy.yml b/ansible/roles/neutron/tasks/deploy.yml
index 13d0d9d30c..7a75bdb204 100644
--- a/ansible/roles/neutron/tasks/deploy.yml
+++ b/ansible/roles/neutron/tasks/deploy.yml
@@ -13,6 +13,7 @@
         or inventory_hostname in groups['neutron-metadata-agent']
         or inventory_hostname in groups['neutron-server']
         or inventory_hostname in groups['neutron-lbaas-agent']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
 
 - include: config-neutron-fake.yml
   when:
@@ -30,3 +31,4 @@
         or inventory_hostname in groups['neutron-metadata-agent']
         or inventory_hostname in groups['neutron-server']
         or inventory_hostname in groups['neutron-lbaas-agent']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
diff --git a/ansible/roles/neutron/tasks/do_reconfigure.yml b/ansible/roles/neutron/tasks/do_reconfigure.yml
index d80e827d64..ad8ef35aba 100644
--- a/ansible/roles/neutron/tasks/do_reconfigure.yml
+++ b/ansible/roles/neutron/tasks/do_reconfigure.yml
@@ -14,8 +14,9 @@
     - { name: neutron_l3_agent, group: neutron-l3-agent }
     - { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
     - { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" }
-    - { name: neutron_metadata_agent, group: neutron-metadata-agent }
+    - { name: neutron_metadata_agent, group: neutron-metadata-agent }    
     - { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
+    - { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }
 
 - name: Ensuring the neutron_openvswitch_agent container is up
   kolla_docker:
@@ -32,12 +33,14 @@
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
           and not enable_nova_fake | bool
         ) or
         ( inventory_hostname in groups['neutron-dhcp-agent']
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
           and enable_nova_fake | bool
         )
       )
@@ -55,7 +58,8 @@
        or inventory_hostname in groups['neutron-dhcp-agent']
        or inventory_hostname in groups['neutron-l3-agent']
        or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent'])
+       or inventory_hostname in groups['neutron-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
 
 - include: config.yml
 
@@ -75,6 +79,7 @@
     - { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" }
     - { name: neutron_metadata_agent, group: neutron-metadata-agent }
     - { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
+    - { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }
 
 - name: Check the configs in the neutron_openvswitch_agent container
   command: docker exec neutron_openvswitch_agent /usr/local/bin/kolla_set_configs --check
@@ -90,12 +95,14 @@
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
           and not enable_nova_fake | bool
         ) or
         ( inventory_hostname in groups['neutron-dhcp-agent']
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
           and enable_nova_fake | bool
         )
       )
@@ -112,7 +119,8 @@
        or inventory_hostname in groups['neutron-dhcp-agent']
        or inventory_hostname in groups['neutron-l3-agent']
        or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent'])
+       or inventory_hostname in groups['neutron-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
 
 # NOTE(jeffrey4l): when config_strategy == 'COPY_ALWAYS'
 # and container env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE',
@@ -133,6 +141,7 @@
     - { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" }
     - { name: neutron_metadata_agent, group: neutron-metadata-agent }
     - { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
+    - { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }
 
 - name: Container config strategy for the neutron_openvswitch_agent container
   kolla_docker:
@@ -149,12 +158,14 @@
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
         ) or
         ( enable_nova_fake | bool
           and inventory_hostname in groups['neutron-dhcp-agent']
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
         )
       )
 
@@ -170,7 +181,8 @@
        or inventory_hostname in groups['neutron-dhcp-agent']
        or inventory_hostname in groups['neutron-l3-agent']
        or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent'])
+       or inventory_hostname in groups['neutron-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
 
 - name: Remove the containers running neutron-server and neutron agents
   kolla_docker:
@@ -189,7 +201,8 @@
        { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
        { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" },
        { name: neutron_metadata_agent, group: neutron-metadata-agent },
-       { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }]
+       { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
+       { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }]
     - "{{ neutron_container_envs.results }}"
     - "{{ neutron_check_results.results }}"
 
@@ -208,12 +221,14 @@
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
         ) or
         ( enable_nova_fake | bool
           and inventory_hostname in groups['neutron-dhcp-agent']
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
         )
       )
     - config_strategy == "COPY_ONCE" or openvswitch_agent_envs['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
@@ -231,7 +246,8 @@
        or inventory_hostname in groups['neutron-dhcp-agent']
        or inventory_hostname in groups['neutron-l3-agent']
        or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent'])
+       or inventory_hostname in groups['neutron-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - config_strategy == "COPY_ONCE" or linuxbridge_agent_envs['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
     - linuxbridge_agent_check_results['rc'] == 1
 
@@ -257,7 +273,8 @@
        { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
        { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" },
        { name: neutron_metadata_agent, group: neutron-metadata-agent },
-       { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }]
+       { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
+       { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }]
     - "{{ neutron_container_envs.results }}"
     - "{{ neutron_check_results.results }}"
 
@@ -275,12 +292,14 @@
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
           and not enable_nova_fake | bool
         ) or
         ( inventory_hostname in groups['neutron-dhcp-agent']
           or inventory_hostname in groups['neutron-l3-agent']
           or inventory_hostname in groups['neutron-lbaas-agent']
           or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
           and enable_nova_fake | bool
         )
       )
@@ -299,6 +318,7 @@
        or inventory_hostname in groups['neutron-dhcp-agent']
        or inventory_hostname in groups['neutron-l3-agent']
        or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent'])
+       or inventory_hostname in groups['neutron-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - linuxbridge_agent_envs['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
     - linuxbridge_agent_check_results['rc'] == 1
diff --git a/ansible/roles/neutron/tasks/pull.yml b/ansible/roles/neutron/tasks/pull.yml
index 9c5a4cbc6e..fa6bf505e2 100644
--- a/ansible/roles/neutron/tasks/pull.yml
+++ b/ansible/roles/neutron/tasks/pull.yml
@@ -23,7 +23,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "linuxbridge"
 
 - name: Pulling neutron-metadata-agent image
@@ -43,7 +44,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "openvswitch"
 
 - name: Pulling neutron-server image
@@ -63,7 +65,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "openvswitch"
 
 - name: Pulling openvswitch-vswitchd image
@@ -76,5 +79,6 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "openvswitch"
diff --git a/ansible/roles/neutron/tasks/reconfigure.yml b/ansible/roles/neutron/tasks/reconfigure.yml
index 5d63da5895..cc30a005b8 100644
--- a/ansible/roles/neutron/tasks/reconfigure.yml
+++ b/ansible/roles/neutron/tasks/reconfigure.yml
@@ -7,3 +7,4 @@
         or inventory_hostname in groups['neutron-l3-agent']
         or inventory_hostname in groups['neutron-lbaas-agent']
         or inventory_hostname in groups['neutron-metadata-agent']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
diff --git a/ansible/roles/neutron/tasks/start.yml b/ansible/roles/neutron/tasks/start.yml
index 2172bc5ce0..fbccfaf60a 100644
--- a/ansible/roles/neutron/tasks/start.yml
+++ b/ansible/roles/neutron/tasks/start.yml
@@ -16,7 +16,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "openvswitch"
 
 - name: Waiting the openvswitch_db service to be ready
@@ -31,7 +32,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "openvswitch"
 
 - name: Ensuring OVS bridge is properly setup
@@ -43,7 +45,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "openvswitch"
 
 - name: Starting openvswitch-vswitchd container
@@ -64,7 +67,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "openvswitch"
 
 - name: Starting neutron-server container
@@ -99,11 +103,13 @@
           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']
           and not enable_nova_fake | bool
         ) 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']
           and enable_nova_fake | bool
         )
       )
@@ -199,7 +205,8 @@
        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-metadata-agent']
+       or inventory_hostname in groups['neutron-vpnaas-agent'])
     - neutron_plugin_agent == "linuxbridge"
 
 - name: Starting neutron-dhcp-agent container
@@ -236,6 +243,7 @@
   when:
     - (inventory_hostname in groups['neutron-l3-agent']
        or (inventory_hostname in groups['compute'] and enable_neutron_dvr | bool))
+    - not enable_neutron_vpnaas | bool
 
 - name: Starting neutron-lbaas-agent container
   kolla_docker:
@@ -271,3 +279,21 @@
   when:
     - (inventory_hostname in groups['neutron-metadata-agent']
        or (inventory_hostname in groups['compute'] and enable_neutron_dvr | bool))
+
+- name: Starting neutron-vpnaas-agent container
+  kolla_docker:
+    action: "start_container"
+    common_options: "{{ docker_common_options }}"
+    image: "{{ neutron_vpnaas_agent_image_full }}"
+    name: "neutron_vpnaas_agent"
+    privileged: True
+    volumes:
+      - "{{ node_config_directory }}/neutron-vpnaas-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run:/run"
+      - "/run/netns/:/run/netns/:shared"
+      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
+      - "kolla_logs:/var/log/kolla/"
+  when:
+    - enable_neutron_vpnaas | bool
+    - inventory_hostname in groups['neutron-vpnaas-agent']
diff --git a/ansible/roles/neutron/tasks/upgrade.yml b/ansible/roles/neutron/tasks/upgrade.yml
index 3667e75a72..84b6f5b569 100644
--- a/ansible/roles/neutron/tasks/upgrade.yml
+++ b/ansible/roles/neutron/tasks/upgrade.yml
@@ -6,6 +6,7 @@
         or inventory_hostname in groups['neutron-lbaas-agent']
         or inventory_hostname in groups['neutron-metadata-agent']
         or inventory_hostname in groups['neutron-server']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
 
 - include: config-neutron-fake.yml
   when:
@@ -22,3 +23,4 @@
         or inventory_hostname in groups['neutron-lbaas-agent']
         or inventory_hostname in groups['neutron-metadata-agent']
         or inventory_hostname in groups['neutron-server']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
diff --git a/ansible/roles/neutron/templates/neutron-server.json.j2 b/ansible/roles/neutron/templates/neutron-server.json.j2
index a57ba3156c..54fed2e003 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",
+    "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_files": [
         {
             "source": "{{ container_config_directory }}/neutron.conf",
@@ -7,6 +7,18 @@
             "owner": "neutron",
             "perm": "0600"
         },
+        {
+            "source": "{{ container_config_directory }}/neutron_lbaas.conf",
+            "dest": "/etc/neutron/neutron_lbaas.conf",
+            "owner": "neutron",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/neutron_vpnaas.conf",
+            "dest": "/etc/neutron/neutron_vpnaas.conf",
+            "owner": "neutron",
+            "perm": "0600"
+        },
         {
             "source": "{{ container_config_directory }}/ml2_conf.ini",
             "dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
diff --git a/ansible/roles/neutron/templates/neutron-vpnaas-agent.json.j2 b/ansible/roles/neutron/templates/neutron-vpnaas-agent.json.j2
new file mode 100644
index 0000000000..1f76b16208
--- /dev/null
+++ b/ansible/roles/neutron/templates/neutron-vpnaas-agent.json.j2
@@ -0,0 +1,29 @@
+{
+    "command": "neutron-vpn-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/fwaas_driver.ini --config-file /etc/neutron/l3_agent.ini --config-file /etc/neutron/vpnaas_agent.ini --config-file /etc/neutron/plugins/ml2/ml2_conf.ini",
+    "config_files": [
+        {
+            "source": "{{ container_config_directory }}/neutron.conf",
+            "dest": "/etc/neutron/neutron.conf",
+            "owner": "neutron",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/ml2_conf.ini",
+            "dest": "/etc/neutron/plugins/ml2/ml2_conf.ini",
+            "owner": "neutron",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/l3_agent.ini",
+            "dest": "/etc/neutron/l3_agent.ini",
+            "owner": "neutron",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/vpnaas_agent.ini",
+            "dest": "/etc/neutron/vpnaas_agent.ini",
+            "owner": "neutron",
+            "perm": "0600"
+        }
+    ]
+}
diff --git a/ansible/roles/neutron/templates/neutron.conf.j2 b/ansible/roles/neutron/templates/neutron.conf.j2
index 557187e91c..99b2a7295a 100644
--- a/ansible/roles/neutron/templates/neutron.conf.j2
+++ b/ansible/roles/neutron/templates/neutron.conf.j2
@@ -35,7 +35,7 @@ host = {{ ansible_hostname }}_{{ item }}
 
 allow_overlapping_ips = true
 core_plugin = ml2
-service_plugins = router{% if enable_neutron_lbaas | bool %},lbaas{% endif %}{% if enable_neutron_qos | bool %},qos{% endif %},{% if neutron_plugin_agent == "sfc" %}flow_classifier,sfc{% endif %}
+service_plugins = router{% if enable_neutron_lbaas | bool %},neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPluginv2{% endif %}{% if enable_neutron_qos | bool %},qos{% endif %}{% if enable_neutron_vpnaas | bool %},vpnass{% endif %}{% if neutron_plugin_agent == "sfc" %}flow_classifier,sfc{% endif %}
 
 {% if enable_neutron_agent_ha | bool %}
 dhcp_agents_per_network = {{ dhcp_agents_per_network }}
diff --git a/ansible/roles/neutron/templates/neutron_lbaas.conf.j2 b/ansible/roles/neutron/templates/neutron_lbaas.conf.j2
new file mode 100644
index 0000000000..bfacaba544
--- /dev/null
+++ b/ansible/roles/neutron/templates/neutron_lbaas.conf.j2
@@ -0,0 +1,4 @@
+{% if enable_neutron_lbaas | bool %}
+[service_providers]
+service_provider = LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
+{% endif %}
diff --git a/ansible/roles/neutron/templates/neutron_vpnaas.conf.j2 b/ansible/roles/neutron/templates/neutron_vpnaas.conf.j2
new file mode 100644
index 0000000000..47eeefb4a7
--- /dev/null
+++ b/ansible/roles/neutron/templates/neutron_vpnaas.conf.j2
@@ -0,0 +1,4 @@
+{% if enable_neutron_vpnaas | bool %}
+[service_providers]
+service_provider = VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
+{% endif %}
diff --git a/ansible/roles/neutron/templates/vpnaas_agent.ini.j2 b/ansible/roles/neutron/templates/vpnaas_agent.ini.j2
new file mode 100644
index 0000000000..2f4d33d638
--- /dev/null
+++ b/ansible/roles/neutron/templates/vpnaas_agent.ini.j2
@@ -0,0 +1,11 @@
+{% set vpn_device_driver = 'neutron_vpnaas.services.vpn.device_drivers.strongswan_ipsec.StrongSwanDriver' if kolla_base_distro in ['ubuntu', 'debian'] else 'neutron_vpnaas.services.vpn.device_drivers.ipsec.OpenSwanDriver'%}
+[DEFAULT]
+
+[ipsec]
+enable_detailed_logging = {{ neutron_logging_debug }}
+
+[service_providers]
+service_provider = VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
+
+[vpnagent]
+vpn_device_driver = {{ vpn_device_driver }}
diff --git a/ansible/site.yml b/ansible/site.yml
index 9134db55ce..f4817498df 100644
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -145,6 +145,7 @@
     - neutron-l3-agent
     - neutron-lbaas-agent
     - neutron-metadata-agent
+    - neutron-vpnaas-agent
     - compute
     - manila-share
   serial: '{{ "30%" if action == "upgrade" else "0" }}'
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index 2a320cf99b..a23ee1646f 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -136,6 +136,7 @@ kolla_internal_vip_address: "10.10.10.254"
 #enable_neutron_lbaas: "no"
 #enable_neutron_qos: "no"
 #enable_neutron_agent_ha: "no"
+#enable_neutron_vpnaas: "no"
 #enable_rally: "no"
 #enable_senlin: "no"
 #enable_swift: "no"
diff --git a/releasenotes/notes/add-neutron-vpnaas-88e0780326100e36.yaml b/releasenotes/notes/add-neutron-vpnaas-88e0780326100e36.yaml
new file mode 100644
index 0000000000..a1bd39fba2
--- /dev/null
+++ b/releasenotes/notes/add-neutron-vpnaas-88e0780326100e36.yaml
@@ -0,0 +1,3 @@
+---
+features:
+   - Add neutron-vpnass role