diff --git a/geant/gap_ansible/playbooks/deploy_twamp.yaml b/geant/gap_ansible/playbooks/deploy_twamp.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..01d004f9e25521be391ab057d73441bd9c3e66aa
--- /dev/null
+++ b/geant/gap_ansible/playbooks/deploy_twamp.yaml
@@ -0,0 +1,5 @@
+- name: Manage iptrunks TWAMP playbook
+  hosts: all
+  gather_facts: false
+  roles:
+    - ../roles/iptrunk_twamp
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/README.md b/geant/gap_ansible/roles/iptrunk_twamp/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9f9c9906de47894c0592efefa32d81a862e55d60
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A role to configure TWAMP on a newly provisioned trunks.
+
+Nokia side is always server;
+Juniper side is client.
+
+Requirements
+------------
+
+GEANT custom netconf module with Nokia "commit_comment" feature.
+
+Role Variables
+--------------
+- vars/main.yaml
+- external inventory (group_vars)
+- orchestrator
+
+Dependencies
+------------
+
+n/a
+
+Example Playbook
+----------------
+
+Role is supposed to be driven by GSO.
+
+License
+-------
+
+MIT
+
+Author Information
+------------------
+
+A. Kurbatov, GEANT Orchestration and Automation Team.
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/defaults/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bff214c5e92c17c13bb7fa012dfa06d336e714f2
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for iptrunk_twamp
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/handlers/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..88a40b5bcb4960b23c8f5939a13763cd7c50f44a
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for iptrunk_twamp
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/meta/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..176f5ec62b59dfca599c98bc47a079810573e372
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/meta/main.yml
@@ -0,0 +1,56 @@
+galaxy_info:
+  author: Aleksandr Kurbatov, GEANT Orchestration and Automation Team
+  description: Deploy TWAMP probe on a IPtrunk
+  company: GEANT
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: MIT
+
+  min_ansible_version: '2.10'
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  #
+  # Provide a list of supported platforms, and for each platform a list of versions.
+  # If you don't wish to enumerate all versions for a particular platform, use 'all'.
+  # To view available platforms and versions (or releases), visit:
+  # https://galaxy.ansible.com/api/v1/platforms/
+  #
+  # platforms:
+  # - name: Fedora
+  #   versions:
+  #   - all
+  #   - 25
+  # - name: SomePlatform
+  #   versions:
+  #   - all
+  #   - 1.0
+  #   - 7
+  #   - 99.99
+
+  galaxy_tags:
+    - network
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
+
+collections:
+  - geant.gap_ansible
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/tasks/compile_object.yaml b/geant/gap_ansible/roles/iptrunk_twamp/tasks/compile_object.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f248c392804407ce71365a6186d6eae365e7d372
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/tasks/compile_object.yaml
@@ -0,0 +1,29 @@
+---
+- name: Set ansible_host to terminal server when router is offline
+  ansible.builtin.set_fact:
+    ansible_host: localhost
+  when:
+    ( local_side.iptrunk_side_node.router_access_via_ts | ansible.builtin.bool ) is true
+
+- name: Create a folder for all the templates
+  ansible.builtin.file:
+    path: "/var/tmp/ansible_run_{{ opid }}"
+    state: directory
+    mode: '0755'
+  delegate_to: localhost
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf"
+  ansible.builtin.template:
+    src: "{{ local_side.iptrunk_side_node.vendor }}/{{ config_object }}.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
+
+- name: Set ansible_host to terminal server when router is offline
+  ansible.builtin.set_fact:
+    ansible_host: "{{ local_side.iptrunk_side_node.router_site.site_ts_address }}"
+    ansible_port: "{{ local_side.iptrunk_side_node.router_ts_port }}"
+  when:
+    ( local_side.iptrunk_side_node.router_access_via_ts | ansible.builtin.bool ) is true
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/tasks/deploy_object.yaml b/geant/gap_ansible/roles/iptrunk_twamp/tasks/deploy_object.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f319ad2cdd73d09491997777307bdfe4fd84dace
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/tasks/deploy_object.yaml
@@ -0,0 +1,49 @@
+---
+- name: Deploy "{{ config_object }}" on "{{ inventory_hostname }}" [CHECK ONLY][JUNIPER]
+  junipernetworks.junos.junos_config:
+    update: 'replace'
+    src: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf"
+    src_format: text
+    check_commit: true
+  diff: true
+  when: >
+    local_side.iptrunk_side_node.vendor == "juniper" and
+    dry_run | ansible.builtin.bool
+
+- name: Deploy "{{ config_object }}" on "{{ inventory_hostname }}" [AND COMMIT][JUNIPER]
+  junipernetworks.junos.junos_config:
+    update: 'replace'
+    src: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf"
+    src_format: text
+    comment: "{{ commit_comment }}"
+  diff: true
+  when: >
+    local_side.iptrunk_side_node.vendor == "juniper" and
+    not (dry_run | ansible.builtin.bool)
+
+- name: Deploy "{{ config_object }}" on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  # ansible.netcommon.netconf_config:
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.template', '{{ local_side.iptrunk_side_node.vendor }}/{{ config_object }}.j2') }}"
+    commit: true
+  diff: true
+  check_mode: true
+  when: >
+    ( dry_run | ansible.builtin.bool ) is true and
+    local_side.iptrunk_side_node.vendor == "nokia"
+
+- name: Deploy "{{ config_object }}"on "{{ inventory_hostname }}" [AND COMMIT][NOKIA]
+  # ansible.netcommon.netconf_config:
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.template', '{{ local_side.iptrunk_side_node.vendor }}/{{ config_object }}.j2') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+  diff: true
+  check_mode: false
+  when: >
+    ( dry_run | ansible.builtin.bool ) is false and
+    local_side.iptrunk_side_node.vendor == "nokia"
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/tasks/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e1434ed912bf16c109e29f5a7ae0b9f4ece3b252
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/tasks/main.yml
@@ -0,0 +1,72 @@
+---
+# tasks file for iptrunk_twamp
+
+- name: Import routers variables
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/routers
+
+- name: Set an ID for this run
+  ansible.builtin.set_fact:
+    opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
+    config_is_different: "False"
+
+- name: Load local info
+  ansible.builtin.set_fact:
+    local_side: "{{ subscription | community.general.json_query(query) }}"
+  vars:
+    query: "iptrunk.iptrunk_sides[?iptrunk_side_node.router_fqdn == '{{ inventory_hostname }}'] | [0]"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[local_side.iptrunk_side_node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[local_side.iptrunk_side_node.vendor].ansible_network_os }}"
+
+- name: Load remote info
+  ansible.builtin.set_fact:
+    remote_side: "{{ subscription | community.general.json_query(query) }}"
+  vars:
+    query: "iptrunk.iptrunk_sides[?iptrunk_side_node.router_fqdn != '{{ inventory_hostname }}'] | [0]"
+
+- name: Set ansible_host to terminal server when router is offline
+  ansible.builtin.set_fact:
+    ansible_host: "{{ local_side.iptrunk_side_node.router_site.site_ts_address }}"
+    ansible_port: "{{ local_side.iptrunk_side_node.router_ts_port }}"
+  when:
+    ( local_side.iptrunk_side_node.router_access_via_ts | ansible.builtin.bool ) is true
+
+- name: Print the ID
+  ansible.builtin.debug:
+    msg: "{{ opid }}"
+
+- name: Set short router names for local and remote sides
+  ansible.builtin.set_fact:
+    local_side_short_name: '{{ local_side.iptrunk_side_node.router_fqdn | replace(".geant.net", "") }}'
+    remote_side_short_name: '{{ remote_side.iptrunk_side_node.router_fqdn | replace(".geant.net", "") }}'
+
+- name: Set Local and Remote side IPv4 addresses nodeA
+  ansible.builtin.set_fact:
+    local_side_address: "{{ trunks[0].config.nodeA.ipv4_address }}"
+    remote_side_address: "{{ trunks[0].config.nodeB.ipv4_address }}"
+  when: local_side.iptrunk_side_node.router_fqdn == trunks[0].config.nodeA.name
+
+- name: Set Local and Remote side IPv4 addresses nodeB
+  ansible.builtin.set_fact:
+    local_side_address: "{{ trunks[0].config.nodeB.ipv4_address }}"
+    remote_side_address: "{{ trunks[0].config.nodeA.ipv4_address }}"
+  when: local_side.iptrunk_side_node.router_fqdn == trunks[0].config.nodeB.name
+
+- name: Set the "config_object" to "twamp_client" when trunks side is Juniper
+  ansible.builtin.set_fact:
+    config_object: "twamp_client"
+  when: local_side.iptrunk_side_node.vendor == "juniper"
+
+- name: Set the "config_object" to "twamp_server" when trunk side is Nokia
+  ansible.builtin.set_fact:
+    config_object: "twamp_server"
+  when: local_side.iptrunk_side_node.vendor == "nokia"
+
+- name: Include compiling the template
+  ansible.builtin.include_tasks: compile_object.yaml
+
+- name: Include the deployment tasks if specified
+  ansible.builtin.include_tasks: deploy_object.yaml
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/templates/juniper/twamp_client.j2 b/geant/gap_ansible/roles/iptrunk_twamp/templates/juniper/twamp_client.j2
new file mode 100644
index 0000000000000000000000000000000000000000..32363a7348676f853920211b26ee073c6fdb9176
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/templates/juniper/twamp_client.j2
@@ -0,0 +1,21 @@
+services {
+  rpm {
+    twamp {
+      client {
+replace: control-connection {{ remote_side_short_name }} {
+          destination port {{ juniper_twamp_client.destination_port }};
+          history-size {{ juniper_twamp_client.history_size }};
+          target-address {{ remote_side_address }};
+          test-count {{ juniper_twamp_client.test_count }};
+          test-session "{{ local_side_short_name }}--{{ remote_side_short_name }}" {
+            target-address {{ remote_side_short_name }};
+            data-fill-with-zeros;
+            data-size {{ juniper_twamp_client.data_size }};
+            probe-count {{ juniper_twamp_client.probe_count }};
+            probe-interval {{ juniper_twamp_client.proble_interval }};
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/templates/nokia/twamp_server.j2 b/geant/gap_ansible/roles/iptrunk_twamp/templates/nokia/twamp_server.j2
new file mode 100644
index 0000000000000000000000000000000000000000..a0029b80476ce219e3f3357611975a9dae5d912c
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/templates/nokia/twamp_server.j2
@@ -0,0 +1,15 @@
+<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
+        <twamp xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+            <server>
+                <admin-state>enable</admin-state>
+                <prefix alu:operation="replace">
+                    <ip-prefix>{{ remote_side_address }}/32</ip-prefix>
+                    <description>{{ remote_side_short_name }}</description>
+                    <max-connections>{{ nokia_twamp_server_max_conn }}</max-connections>
+                    <max-sessions>{{ nokia_twamp_server_max_sess }}</max-sessions>
+                </prefix>
+            </server>
+        </twamp>
+  </configure>
+</config>
diff --git a/geant/gap_ansible/roles/iptrunk_twamp/vars/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..161f1b440e35f626feb0671a2ca83f82882bc22b
--- /dev/null
+++ b/geant/gap_ansible/roles/iptrunk_twamp/vars/main.yml
@@ -0,0 +1,38 @@
+---
+# vars file for iptrunk_twamp
+#
+#
+
+dry_run: "True"
+
+nokia_twamp_server:
+  max_conn: 1
+  max_sess: 1
+
+juniper_twamp_client:
+  destination_port: 862
+  history_size: 20
+  test_count: 0
+  test_interval: 30
+  data_size: 200
+  probe_count: 500
+  probe_interval: 1
+
+side_a_ipv4_address: "{{ subscription.iptrunk.iptrunk_ipv4_network | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('address') }}"
+side_b_ipv4_address: "{{ subscription.iptrunk.iptrunk_ipv4_network | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}"
+
+trunks:
+  - id: "{{ subscription.iptrunk.geant_s_sid }}"
+    config:
+      common:
+        description: "{{ subscription.iptrunk.iptrunk_description }}"
+      nodeA:
+        name: "{{ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn }}"
+        router_access_via_ts: "{{ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_access_via_ts }}"
+        loopback: "{{ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_lo_ipv4_address }}"
+        ipv4_address: "{{ side_a_ipv4_address }}"
+      nodeB:
+        name: "{{ subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn }}"
+        router_access_via_ts: "{{ subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_access_via_ts }}"
+        loopback: "{{ subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_lo_ipv4_address }}"
+        ipv4_address: "{{ side_b_ipv4_address }}"