diff --git a/geant/gap_ansible/playbooks/l3_core_service.yaml b/geant/gap_ansible/playbooks/l3_core_service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9b1548170ddcf531ff63919da5f70968798b8324
--- /dev/null
+++ b/geant/gap_ansible/playbooks/l3_core_service.yaml
@@ -0,0 +1,118 @@
+- name: Manage GEANT IP instance
+  hosts: all
+  gather_facts: false
+  tasks:
+    - name: Generate an ID for this run
+      ansible.builtin.set_fact:
+        opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
+
+    - name: Print the ID
+      ansible.builtin.debug:
+        msg: "{{ opid }}"
+
+    - name: Create a folder for all compiled output
+      ansible.builtin.file:
+        path: "/var/tmp/ansible_run_{{ opid }}"
+        state: directory
+        mode: '0755'
+      delegate_to: localhost
+
+    - name: Import group_vars/all
+      ansible.builtin.include_vars:
+        dir: /opt/ansible_inventory/group_vars/all
+
+    - name: Import standard variables for "{{ subscription.product.product_type }}/{{ subscription.l3_core_service_type | replace(' ', '_') }}"
+      ansible.builtin.include_vars:
+        dir: /opt/ansible_inventory/geant_services/{{ subscription.product.product_type }}/{{ subscription.l3_core_service_type | replace(' ', '_') }}
+
+    - name: Import partner specific variables for "{{ partner_name | upper }}"
+      ansible.builtin.include_vars:
+        dir: /opt/ansible_inventory/geant_partners/{{ partner_name | upper }}
+
+
+    - name: Compile SBP-related config
+      when: object == 'sbp'
+      block:
+        - name: Include Filter role
+          ansible.builtin.include_role:
+            name: fw_filters
+          loop:
+            "{{ subscription.l3_core_service.ap_list }}"
+          loop_control:
+            loop_var: ap
+
+        - name: Include SBP role
+          ansible.builtin.include_role:
+            name: sbp
+          loop:
+            "{{ subscription.l3_core_service.ap_list }}"
+          loop_control:
+            loop_var: ap
+
+    # - name: Compile SBP config
+    #   block:
+    #     - name: Include SBP role
+    #       ansible.builtin.include_role:
+    #         name: sbp
+    #       loop:
+    #         "{{ subscription.l3_core_service.ap_list }}"
+    #       loop_control:
+    #         loop_var: ap
+    #
+    - name: Compile BGP-related config
+      when: object == "bgp"
+      block:
+        - name: Include Prefix-list role
+          ansible.builtin.include_role:
+            name: prefix_lists
+          loop:
+            "{{ subscription.l3_core_service.ap_list }}"
+          loop_control:
+            loop_var: ap
+
+        - name: Include BGP policies
+          ansible.builtin.include_role:
+            name: policy_options
+          loop:
+            "{{ subscription.l3_core_service.ap_list }}"
+          loop_control:
+            loop_var: ap
+
+        - name: Include BGP session
+          ansible.builtin.include_role:
+            name: bgp_config
+          loop:
+            "{{ subscription.l3_core_service.ap_list }}"
+          loop_control:
+            loop_var: ap
+
+    # - name: Compile BGP policies
+    #   block:
+    #     - name: Include BGP policies
+    #       ansible.builtin.include_role:
+    #         name: policy_options
+    #       loop:
+    #         "{{ subscription.l3_core_service.ap_list }}"
+    #       loop_control:
+    #         loop_var: ap
+    #
+    # - name: Compile BGP sesssions config
+    #   block:
+    #     - name: Include BGP session
+    #       ansible.builtin.include_role:
+    #         name: bgp_config
+    #       loop:
+    #         "{{ subscription.l3_core_service.ap_list }}"
+    #       loop_control:
+    #         loop_var: ap
+
+    - name: Deploy
+      # when: verb == deploy
+      block:
+        - name: Include deployment role
+          ansible.builtin.include_role:
+            name: deploy_service_config
+          loop:
+            "{{ subscription.l3_core_service.ap_list }}"
+          loop_control:
+            loop_var: ap
diff --git a/geant/gap_ansible/roles/bgp_config/README.md b/geant/gap_ansible/roles/bgp_config/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..225dd44b9fc5b3abff7e9c68ff9e91d505cdd5f0
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/bgp_config/defaults/main.yml b/geant/gap_ansible/roles/bgp_config/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..41a4846107cb9d801075bd33c4848668621402ab
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for bgp_config
diff --git a/geant/gap_ansible/roles/bgp_config/handlers/main.yml b/geant/gap_ansible/roles/bgp_config/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e488bebccf375987286e5faebd59ab3f85881f4b
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for bgp_config
diff --git a/geant/gap_ansible/roles/bgp_config/meta/main.yml b/geant/gap_ansible/roles/bgp_config/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..36d899dd86d8c01083aefc8c7000b2cf64cacd75
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/meta/main.yml
@@ -0,0 +1,35 @@
+galaxy_info:
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  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:
+
+  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.
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml b/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ff6d54929b5bd2f5c40ef32320bfaabf6ddefd55
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
@@ -0,0 +1,15 @@
+---
+- name: Set ansible host to localhost to compile template
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf"
+  # when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "bgp.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/deploy_bgp.yaml b/geant/gap_ansible/roles/bgp_config/tasks/deploy_bgp.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4353e467dec54a2eb51020a8bfe02bf8e2748ebc
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/deploy_bgp.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy BGP config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy BGP config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/main.yml b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..13eca9efa55c06677c5a50df361cb0c55512cff5
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
@@ -0,0 +1,15 @@
+---
+# tasks file for bgp_config
+- name: Load Standard Policy Statements vars
+  ansible.builtin.include_tasks: merge_vars.yaml
+
+# - name: Debug bgp_session_list
+#   ansible.builtin.debug:
+#     var: bgp_obj
+#
+- name: Compile templates
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Deploy templates if standalone run
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_bgp.yaml
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..77676232f0a50f972531cc23264d6429c2fff79f
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
@@ -0,0 +1,7 @@
+---
+- name: Set Standard Import and export policies names
+  ansible.builtin.set_fact:
+    import_policies_v4: "{{ bgp.policies.import.v4 }}"
+    import_policies_v6: "{{ bgp.policies.import.v6 }}"
+    export_policies_v4: "{{ bgp.policies.export.v4 }}"
+    export_policies_v6: "{{ bgp.policies.export.v6 }}"
diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp.j2
new file mode 100644
index 0000000000000000000000000000000000000000..47b82cfbed8b479f485baaa1b02904c55fb4bd2b
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp.j2
@@ -0,0 +1,9 @@
+
+        <router 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">
+            <router-name>Base</router-name>
+            <bgp 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">
+            {% include 'bgp_neighbor.j2' %}
+            </bgp>
+
+       </router>
+
diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
new file mode 100644
index 0000000000000000000000000000000000000000..dc71e135265b4cde7a6c3d7b74fd0f3ff28f2e2e
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
@@ -0,0 +1,60 @@
+                {% for neighbor in bgp_obj %}
+                <neighbor alu:operation="replace">
+                    <ip-address>{{ neighbor.peer_address }}</ip-address>
+                    <admin-state>enable</admin-state>
+                    {% if neighbor.bfd_enabled %}
+                    <bfd-liveness>true</bfd-liveness>
+                    {% endif %}
+                    <description>{{ partner_name | upper }}_{{ partner.type }}</description>
+
+                    {% if neighbor.ip_type == 'ipv4' %}
+                    <group>{{ bgp.group.ipv4 }}</group>
+                    {% elif neighbor.ip_type == 'ipv6' %}
+                    <group>{{ bgp.group.ipv6 }}</group>
+                    {% endif %}
+                    <peer-as>{{ partner.asn }}</peer-as>
+                  {% if neighbor.authentication_key is not none %}
+                    <authentication-key>{{ neighbor.authentication_key }}</authentication-key>
+                  {% endif %}
+                  {% if neighbor.hold_time is defined %}
+                    <hold-time>
+                      <seconds>{{ neighbor.hold_time }}</seconds>
+                    </hold-time>
+                  {% endif %}
+                  {% if neighbor.multipath_enabled %}
+                  <multipath-eligible>true</multipath-eligible>
+                  {% endif %}
+
+                    <family>
+                      {% for family in neighbor.families %}
+                        <{{ family }}>true</{{ family }}>
+                      {% endfor %}
+                    </family>
+                    <import>
+                      {% if neighbor.ip_type == 'ipv4' %}
+                        {% for pol in import_policies_v4 %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                      {% elif neighbor.ip_type == 'ipv6' %}
+                        {% for pol in import_policies_v6 %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                      {% endif %}
+                    </import>
+                    <export>
+                      {% if neighbor.ip_type == 'ipv4' %}
+                        {% for pol in export_policies_v4 %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                      {% elif neighbor.ip_type == 'ipv6' %}
+                        {% for pol in export_policies_v6 %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                      {% endif %}
+                    </export>
+                    {% if neighbor.is_passive %}
+                    <passive>true</passive>
+                    {% endif %}
+                </neighbor>
+                {% endfor %}
+ 
diff --git a/geant/gap_ansible/roles/bgp_config/vars/main.yml b/geant/gap_ansible/roles/bgp_config/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5bdb6c9dd621ca56bca93a096c64bb52e05fa670
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/vars/main.yml
@@ -0,0 +1,5 @@
+---
+# vars file for bgp_config
+is_standalone_run: false
+
+bgp_obj: "{{ ap.sbp.bgp_session_list }}"
diff --git a/geant/gap_ansible/roles/deploy_service_config/README.md b/geant/gap_ansible/roles/deploy_service_config/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f4038c76704239f5aabe916a9b1de2a6f8f60e79
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/README.md
@@ -0,0 +1,41 @@
+Role Name
+=========
+
+The role identifies the vendor of the target walking through the subscription that it receives as an extra-var. The position in the subscription of this information dependes by the product type. 
+If nokia, then nokia netconf and nokia config modules, the same goes for Juniper. 
+First of all it should collect all the config files contained in the /var/tmp/$ops_id directory and assemble a single configuration file. 
+Then it should do a dry run and finally, when dry_run is false, a commit run .
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/deploy_service_config/defaults/main.yml b/geant/gap_ansible/roles/deploy_service_config/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..224547bab1797380b10d2a6ce0e85b52a3d73392
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for deploy_service_config
diff --git a/geant/gap_ansible/roles/deploy_service_config/files/nokia/footer b/geant/gap_ansible/roles/deploy_service_config/files/nokia/footer
new file mode 100644
index 0000000000000000000000000000000000000000..3da5889a7c45ad41277b41e7e687fe055ca6f028
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/files/nokia/footer
@@ -0,0 +1,2 @@
+  </configure>
+</config>
diff --git a/geant/gap_ansible/roles/deploy_service_config/files/nokia/header b/geant/gap_ansible/roles/deploy_service_config/files/nokia/header
new file mode 100644
index 0000000000000000000000000000000000000000..8116557828284e2499c03f9fc9f6995dd8f44f7b
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/files/nokia/header
@@ -0,0 +1,2 @@
+<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">
diff --git a/geant/gap_ansible/roles/deploy_service_config/handlers/main.yml b/geant/gap_ansible/roles/deploy_service_config/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f5d286b34c8bee3a896e57d6024555900eba3460
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for deploy_service_config
diff --git a/geant/gap_ansible/roles/deploy_service_config/meta/main.yml b/geant/gap_ansible/roles/deploy_service_config/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c8cc947eb4c0069bbd18bc40595b09b3742b52b8
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/meta/main.yml
@@ -0,0 +1,35 @@
+galaxy_info:
+  author: Milos Zdravkovic
+  description: GOAT
+  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:
+
+  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.
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..83c77e192238d7fe87e8ef340edcd17c20f6d071
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
@@ -0,0 +1,51 @@
+---
+# Although I was working on a separate branch, I had
+# to resist the temptation of not modifying the entry
+# playbook in order to introduce the opid_dir variable
+# and avoid it's use all over the place.
+
+- name: Locally-delegated assemble block
+  delegate_to: localhost
+  block:
+  # Because ansible.builtin.assemble works with a single directory
+    - name: Create a subdirectory for the assembled output
+      ansible.builtin.file:
+        path: "/var/tmp/ansible_run_{{ opid }}/assembled/"
+        state: directory
+        mode: '0755'
+
+    # Enumeration prefix is needed to impact the order of assembly
+    - name: Copy Nokia SR OS header for assembly
+      ansible.builtin.copy:
+        src: "{{ vendor }}/header"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/00_header"
+        mode: '0644'
+
+    # Enumeration prefix is needed to impact the order of assembly
+    - name: Copy Nokia SR OS footer for assembly
+      ansible.builtin.copy:
+        src: "{{ vendor }}/footer"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/02_footer"
+        mode: '0644'
+
+    # Enumeration prefix is needed to impact the order of assembly
+    - name: Assemble body of the config
+      ansible.builtin.assemble:
+        src: "/var/tmp/ansible_run_{{ opid }}/"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/01-body"
+        mode: '0644'
+
+    # Use the enumeration prefixes to assemble fragments in the right order
+    - name: Merge header, body and footer to get the final config
+      ansible.builtin.assemble:
+        src: "/var/tmp/ansible_run_{{ opid }}/assembled"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment"
+        mode: '0644'
+
+    - name: Clean up the fragments
+      ansible.builtin.file:
+        path: "{{ item }}"
+        state: absent
+        mode: '0755'
+      with_fileglob:
+        - "/var/tmp/ansible_run_{{ opid }}/assembled/0*"
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6dd169a32d9fa7e30ac3f416e12e1259f4682072
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
@@ -0,0 +1,11 @@
+---
+- name: Set ansible_host to terminal server when router is offline
+  ansible.builtin.set_fact:
+    ansible_host: "{{ router.router_site.site_ts_address }}"
+    ansible_port: "{{ router.router_ts_port }}"
+  when: router.router_access_via_ts | ansible.builtin.bool
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[router.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[router.vendor].ansible_network_os }}"
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..cfb638df3b10df8611561393735c74c38c1388be
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
@@ -0,0 +1,26 @@
+---
+# - name: Fetch access port info from the subscription
+#   ansible.builtin.include_tasks: traverse_subscription.yml
+
+# The "delegate_to" works as expected in conjuction with "import_tasks".
+# However, mixing "imports" with "includes" is not recommended.
+# Another way is to "apply" the "delegate_to: localhost".
+- name: Assemble the config from fragments in previous roles
+  ansible.builtin.include_tasks: assemble_config.yml
+
+- name: Include set connection tasks
+  ansible.builtin.include_tasks: connection_tasks.yml
+
+# The "verb == deploy" is (probably) not needed
+# because it has already been checked in the
+# invoking playbook (nren_l3_core_services.yaml):
+#
+# - name: Deploy
+#    block:
+#    - name: Include deployment role
+#      ansible.builtin.include_role:
+#        name: deploy_service_config
+#     when: verb == deploy
+#
+- name: Push assembled config to device
+  ansible.builtin.include_tasks: push_config.yml
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8835da0a2d72a5872bf5296d60db97fc8a6a4e20
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
@@ -0,0 +1,39 @@
+---
+- name: Config deploy [CHECK ONLY][NOKIA]
+  when: >
+    dry_run | ansible.builtin.bool
+    and
+    vendor == "nokia"
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Fail if there is any diff
+  when: >
+    output.changed | ansible.builtin.bool
+    and
+    is_verification_workflow | ansible.builtin.bool
+  ansible.builtin.fail:
+    msg: Service "{{ subscription.product.product_type }}" config for "{{ partner_name | upper }}" drifted!
+
+- name: Config deploy [AND COMMIT][NOKIA]
+  when: >
+    not dry_run | ansible.builtin.bool
+    and
+    vendor == "nokia"
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  check_mode: false
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
new file mode 100644
index 0000000000000000000000000000000000000000..86ae5601a65b44bc57a1e8e389fadd11ea061ac3
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
@@ -0,0 +1,45 @@
+---
+
+# The following tarversal of JSON should be part of
+# the entry playbook. Or maybe even better, a separate
+# role invoked at its very beginning so that all other
+# roles can use it.
+
+#
+# Note: This requires python3-jmespath to be installed.
+#
+
+- name: Find matching nren_ap_list element
+  ansible.builtin.set_fact:
+    filtered_ap_list: "{{ subscription['l3_core_service']['ap_list'] | json_query(query) }}"
+  vars:
+    query: "[?sbp.edge_port.node.router_fqdn == `{{ inventory_hostname }}`]"
+
+- name: Check if subscription contradicts inventory_hostname
+  ansible.builtin.fail:
+    msg: "The number of router_fqdn elements that match is {{ filtered_ap_list | length }}."
+  when: filtered_ap_list | length != 1
+
+- name: Find matching nren_ap_list element
+  ansible.builtin.set_fact:
+    ap: "{{ filtered_ap_list[0] }}"
+
+- name: Print the matched nren_ap_list element
+  ansible.builtin.debug:
+    msg: "{{ ap }}"
+
+- name: Set the short name for node
+  ansible.builtin.set_fact:
+    router: "{{ ap.sbp.edge_port.node }}"
+
+- name: Print the node
+  ansible.builtin.debug:
+    msg: "{{ router }}"
+
+- name: Set the short name for vendor
+  ansible.builtin.set_fact:
+    vendor: "{{ router.vendor }}"
+
+- name: Print the vendor
+  ansible.builtin.debug:
+    msg: "{{ vendor }}"
diff --git a/geant/gap_ansible/roles/deploy_service_config/vars/main.yml b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5def5f74b90481c8b0e62b06a281ee954dc18eba
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
@@ -0,0 +1,7 @@
+---
+# vars file for deploy_service_config
+dry_run: true
+is_verification_workflow: false
+
+router: "{{ ap.sbp.edge_port.node }}"
+vendor: "{{ router.vendor }}"
diff --git a/geant/gap_ansible/roles/fw_filters/README.md b/geant/gap_ansible/roles/fw_filters/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d5e73d983743f7e493c25eb312ecd1a035952d7a
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/README.md
@@ -0,0 +1,36 @@
+Role Name
+=========
+
+A role for configuring IP filters in Nokia SROS.
+
+Requirements
+------------
+
+GEANT custom netconf module with Nokia "commit_comment" and "config_mode" features.
+
+Role Variables
+--------------
+
+- vars/main.yaml
+- external inventory (group_vars)
+- orchestrator (GSO)
+
+Dependencies
+------------
+
+n/a
+
+Example Playbook
+----------------
+
+Role is supposed to be driven by GSO.
+
+License
+-------
+
+MIT
+
+Author Information
+------------------
+
+A. Kurbatov, S. Spinelli. GEANT Orchestration and Automation Team (GOAT).
diff --git a/geant/gap_ansible/roles/fw_filters/defaults/main.yml b/geant/gap_ansible/roles/fw_filters/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..79fb8886c14bebf27eed7f37e175984c6de11728
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for fw_filters
diff --git a/geant/gap_ansible/roles/fw_filters/handlers/main.yml b/geant/gap_ansible/roles/fw_filters/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5d927097d084d7388ecf1e580afcee8757612461
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for fw_filters
diff --git a/geant/gap_ansible/roles/fw_filters/meta/main.yml b/geant/gap_ansible/roles/fw_filters/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..36d899dd86d8c01083aefc8c7000b2cf64cacd75
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/meta/main.yml
@@ -0,0 +1,35 @@
+galaxy_info:
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  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:
+
+  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.
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..542c04d554e9fd07eeb9ec4f15c05b2958d4a2c9
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
@@ -0,0 +1,15 @@
+---
+- name: Set ansible host to localhost to compile template
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf"
+  # when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "filters/gen_filters.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1d7d8d4cd2900597ca030251eca823b1fc84de7a
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/main.yml b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..15281b5117800b45af3ca21c49b933fa207c590c
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+# tasks file for fw_filters
+
+- name: Include preparation of FW vars
+  ansible.builtin.include_tasks: merge_variables.yaml
+
+- name: Include filter compilation
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Include filter compilation
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_fw.yaml
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e332f5121481844376651990f764490f0fe8e42d
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
@@ -0,0 +1,30 @@
+---
+# Prepare FW vars depending on the "service_type" and "custom_filters"
+- name: Prepare FW vars for NREN L3 Core Service with custom filters
+  when: >-
+    subscription.product.product_type == "L3CoreService"
+    and
+    subscription.l3_core_service_type == "GÉANT IP"
+    and
+    ap.sbp.custom_firewall_filters | ansible.builtin.bool
+  block:
+    - name: Merge NREN custom filters if selected
+      ansible.builtin.set_fact:
+        custom_edge_fw: "{{ [STANDARD_NREN_FW__to_merge, CUSTOM_NREN_FW] | community.general.lists_mergeby('name',
+                                                                            recursive=true, list_merge='append') }}"
+
+    - name: Combine Custom and standard EDGE filters
+      ansible.builtin.set_fact:
+        gen_filters: "{{ [STANDARD_EDGE_FW__to_merge, custom_edge_fw] | community.general.lists_mergeby('name') }}"
+
+- name: Prepare FW vars for NREN L3 Core Service with standard filters
+  when: >-
+    subscription.product.product_type == "L3CoreService"
+    and
+    subscription.l3_core_service_type == "GÉANT IP"
+    and
+    not ap.sbp.custom_firewall_filters | ansible.builtin.bool
+  block:
+    - name: Merge NREN standard filters
+      ansible.builtin.set_fact:
+        gen_filters: "{{ lookup('community.general.merge_variables', 'FW__to_merge', pattern_type='suffix') }}"
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/cpm_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/cpm_filters.j2
new file mode 100644
index 0000000000000000000000000000000000000000..f7a35874dadee962cf9b5440db091dfba84de7f6
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/cpm_filters.j2
@@ -0,0 +1,12 @@
+{% with is_cpm_filter=true, filters=cpm_filters %}
+{% include "filters/port_list_definitions.j2" %}
+
+<system>
+  <security>
+    <cpm-filter 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">
+      <default-action>{{ cpm_filter_policy.default_action }}</default-action>
+        {% include "filters/fw_filters.j2" %}
+    </cpm-filter>
+{% endwith %}
+  </security>
+</system>
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
new file mode 100644
index 0000000000000000000000000000000000000000..3396d8a5e74ef7a0bab5eab4a9bff98398135a38
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
@@ -0,0 +1,295 @@
+{# Template is meant to be called from either gen_filters.j2 or cmp_filters.j2 #}
+{% for filter in filters %}
+  {% if filter.family == "ipv4" %}
+        <ip-filter alu:operation="replace">
+  {% elif filter.family == "ipv6" %}
+        <ipv6-filter alu:operation="replace">
+  {% endif %}
+  {% if not is_cpm_filter %}
+        <filter-name>{{ filter.name }}</filter-name>
+      {% if filter.scope is defined %}
+        <scope>{{ filter.scope }}</scope>
+      {% endif %}
+      {% if filter.default_action is defined %}
+        <default-action>{{ filter.default_action }}</default-action>
+      {% endif %}
+      {% if filter.chain_to_system_filter is defined %}
+        <chain-to-system-filter>{{ filter.chain_to_system_filter | lower }}</chain-to-system-filter>
+      {% endif %}
+      {% if filter.embed is defined %}
+        <embed>
+         {% for embed in filter.embed %}
+            {% if embed.type == 'filter' %}
+            <filter>
+                <name>{{ embed.name }}</name>
+                <offset>{{ embed.offset }}</offset>
+            </filter>
+            {% elif embed.type == 'flowspec' %}
+            <flowspec>
+                <offset>{{ embed.offset }}</offset>
+                <router-instance>{{ embed.router_instance }}</router-instance>
+            </flowspec>
+            {% endif %}
+         {% endfor %}
+        </embed>
+      {% endif %}
+  {% endif %}
+  {% if filter.offset is defined %}
+    {% set ns3 = namespace(entry_id = filter.offset | int) %}
+  {% else %}
+    {% set ns3 = namespace(entry_id = 10 | int) %}
+  {% endif %}
+  {% if is_cpm_filter %}
+        <admin-state>{{ filter.admin_state }}</admin-state>
+  {% endif %}
+  {# Filter can be without terms, but with embedded items #}
+  {% if filter.terms is defined %}
+    {% for term in filter.terms %}
+      {% if term.offset is defined %}
+        {% set ns3 = namespace(entry_id = term.offset | int) %}
+      {% endif %}
+      {% if term.from is not defined %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            {% include 'filters/term_action.j2' if term.action is defined %}
+          </entry>
+      {% endif %}
+
+      {% if term.from is defined %}
+        {# Special cases where from.protocol is defined #}
+        {% if term.from.protocol is defined %}
+          {# This is the case for TCP_ESTABLISHED #}
+          {% if term.from.protocol == "tcp" and term.from.tcp_flag is defined %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+              {% if filter.family == "ipv4" %}
+              <protocol>{{ term.from.protocol }}</protocol>
+              {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+              {% endif %}
+              <tcp-flags>
+                <{{ term.from.tcp_flag }}>true</{{ term.from.tcp_flag }}>
+              </tcp-flags>
+            </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+          </entry>
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+          {% endif %}
+        {# Generic ICMP filters with ICMP types #}
+          {% if (term.from.protocol == "icmp" or term.from.protocol == "ipv6-icmp") %}
+            {% if term.from.icmp_types is defined %}
+              {% for icmp_type in term.from.icmp_types %}
+            <entry>
+              <entry-id>{{ ns3.entry_id }}</entry-id>
+              <description>{{ term.name }}</description>
+                {% if term.log is defined %}
+              <log>{{ term.log }}</log>
+                {% endif %}
+              <match>
+                    {% if filter.family == "ipv4" %}
+                <protocol>{{ term.from.protocol }}</protocol>
+                    {% else %}
+                <next-header>{{ term.from.protocol }}</next-header>
+                    {% endif %}
+                  <icmp>
+                    <type>{{ icmp_type }}</type>
+                  </icmp>
+              </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+            </entry>
+          {% set ns3.entry_id = ns3.entry_id + 10 %}
+              {% endfor %}
+            {% endif %}
+          {% endif %}
+        {# Case when only need to match on protocol, e.g. PIM #}
+          {% if term.from.protocol in ['pim', '58'] %}
+            <entry>
+              <entry-id>{{ ns3.entry_id }}</entry-id>
+              <description>{{ term.name }}</description>
+              {% if term.log is defined %}
+              <log>{{ term.log }}</log>
+              {% endif %}
+              <match>
+                    {% if filter.family == "ipv4" %}
+                <protocol>{{ term.from.protocol }}</protocol>
+                    {% else %}
+                <next-header>{{ term.from.protocol }}</next-header>
+                    {% endif %}
+              </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+            </entry>
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+          {% endif %}
+        {% endif %}
+      {# Case when both src_prefix_list and dst_prefix_list are defined #}
+        {% if term.from.src_prefix_list is defined %}
+          {% for src_prefix_list_item in term.from.src_prefix_list%}
+            {% set src_index = loop.index0 %}
+            {% if term.from.dst_prefix_list is defined %}
+              {% for dst_prefix_list_item in term.from.dst_prefix_list %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+                {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+                {% endif %}
+            <match>
+                {% if term.from.protocol is defined %}
+                  {% if filter.family == "ipv4" %}
+              <protocol>{{term.from.protocol}}</protocol>
+                  {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                  {% endif %}
+                {% elif term.from.protocol_list is defined %}
+                  {% if filter.family == "ipv4" %}
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list>
+                  {% else %}
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTO</next-header-list>
+                  {% endif %}
+                {% endif %}
+              {% include 'filters/port_list_entries.j2' %}
+              <src-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.src_prefix_list[src_index]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.src_prefix_list[src_index]}}</ipv6-prefix-list>
+                {% endif %}
+              </src-ip>
+              <dst-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ipv6-prefix-list>
+                {% endif %}
+              </dst-ip>
+            </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+              {% set ns3.entry_id = ns3.entry_id + 10 %}
+          </entry>
+              {% endfor %}
+            {% else %}
+            {# src_prefix_list is defined, dst_prefix_list is not #}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+              {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+              {% endif %}
+            <match>
+              {% if term.from.protocol is defined %}
+                  {% if filter.family == "ipv4" %}
+              <protocol>{{term.from.protocol}}</protocol>
+                  {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                  {% endif %}
+              {% elif term.from.protocol_list is defined %}
+                  {% if filter.family == "ipv4" %}
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list>
+                  {% else %}
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTO</next-header-list>
+                  {% endif %}
+              {% endif %}
+            {% include 'filters/port_list_entries.j2' %}
+              <src-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.src_prefix_list[src_index]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.src_prefix_list[src_index]}}</ipv6-prefix-list>
+                {% endif %}
+              </src-ip>
+            </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+              {% set ns3.entry_id = ns3.entry_id + 10 %}
+          </entry>
+            {% endif %}
+          {% endfor %}
+      {# Case where only DST prefix list is defined #}
+        {% elif term.from.dst_prefix_list is defined %}
+          {% for dst_prefix_list_item in term.from.dst_prefix_list %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+              {% if term.from.protocol is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol>{{term.from.protocol}}</protocol>
+                {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                {% endif %}
+              {% elif term.from.protocol_list is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list>
+                {% else %}
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTO</next-header-list>
+                {% endif %}
+              {% endif %}
+            {% include 'filters/port_list_entries.j2' %}
+              <dst-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ipv6-prefix-list>
+                {% endif %}
+              </dst-ip>
+            </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+          </entry>
+          {% endfor %}
+      {# term.from.protocol and ports are defined, but not SRC or DST prefix list - e.g. IPv4 traceroute #}
+        {% elif term.from.protocol is defined and term.from.protocol in ['udp'] %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+                  {% if filter.family == "ipv4" %}
+              <protocol>{{ term.from.protocol }}</protocol>
+                  {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                  {% endif %}
+            {% include 'filters/port_list_entries.j2' %}
+            </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+            </action>
+          </entry>
+          {% set ns3.entry_id = ns3.entry_id + 10 %}
+        {% endif %}
+      {% endif %}
+    {% endfor %}
+  {% endif %}
+  {# Terms end #}
+  {% if filter.family == "ipv4" %}
+        </ip-filter>
+  {% elif filter.family == "ipv6" %}
+        </ipv6-filter>
+  {% endif %}
+{% endfor %}
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
new file mode 100644
index 0000000000000000000000000000000000000000..e4b84c31c4ade44c50a914b67959f2431c1afa78
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
@@ -0,0 +1,20 @@
+{% if is_standalone_run %}
+<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">
+{% endif %}
+
+{% with is_cpm_filter=False, filters=gen_filters %}
+
+  <filter 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">
+    {% include "filters/port_list_definitions.j2" %}
+    {% include "filters/protocol_list_definitions.j2" %}
+    {% include "filters/fw_filters.j2" %}
+  </filter>
+
+{% endwith %}
+
+{% if is_standalone_run %}
+   </configure>
+</config>
+{% endif %}
+
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
new file mode 100644
index 0000000000000000000000000000000000000000..dad8d8f88554598acbe01cbe3b39304bd5b9082f
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
@@ -0,0 +1,68 @@
+{# Goes through the list of terms in a filter and configures port-lists #}
+
+    <match-list>
+{% for filter in filters %}
+  {% if filter.terms is defined %}
+    {% for term in filter.terms %}
+      {% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-PORTS</port-list-name>
+        {%for port in term.from.port %}
+            <port>
+                <value>{{port}}</value>
+            </port>
+        {% endfor %}
+        </port-list>
+      {% endif %}
+      {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list-name>
+        {%for port in term.from.src_port %}
+            <port>
+                <value>{{port}}</value>
+            </port>
+        {% endfor %}
+        </port-list>
+      {% endif %}
+      {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-DST_PORTS</port-list-name>
+        {%for port in term.from.dst_port %}
+            <port>
+                <value>{{port}}</value>
+            </port>
+        {% endfor %}
+          </port-list>
+      {% endif %}
+      {% if term.from.port_range is defined %}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list-name>
+            <range>
+                <start>{{ term.from.port_range.start }}</start>
+                <end>{{ term.from.port_range.end }}</end>
+            </range>
+        </port-list>
+      {% endif %}
+      {% if term.from.src_port_range is defined %}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list-name>
+            <range>
+                <start>{{ term.from.src_port_range.start }}</start>
+                <end>{{ term.from.src_port_range.end }}</end>
+            </range>
+        </port-list>
+      {% endif %}
+      {% if term.from.dst_port_range is defined %}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list-name>
+            <range>
+                <start>{{ term.from.dst_port_range.start }}</start>
+                <end>{{ term.from.dst_port_range.end }}</end>
+            </range>
+        </port-list>
+      {% endif %}
+    {% endfor %}
+  {% endif %}
+{% endfor %}
+    </match-list>
+
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
new file mode 100644
index 0000000000000000000000000000000000000000..48c50c70851aac20e37a49ad4a39d0a7fbf9f44c
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
@@ -0,0 +1,48 @@
+{#This is the case it's a port-list #}
+{% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
+            <port>
+                <port-list>{{filter.name}}-{{term.name}}-PORTS</port-list>
+            </port>
+{% endif %}
+{% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
+            <src-port>
+                <port-list>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list>
+            </src-port>
+{% endif %}
+{% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
+            <dst-port>
+                <port-list>{{filter.name}}-{{term.name}}-DST_PORTS</port-list>
+            </dst-port>
+{% endif %}
+{#This is the case it's a single port #}
+{% if term.from.port is defined and term.from.port.__class__.__name__ != 'list'%}
+            <port>
+                <eq>{{term.from.port}}</eq>
+            </port>
+{% endif %}
+{% if term.from.src_port is defined and term.from.src_port.__class__.__name__ != 'list'%}
+            <src-port>
+                <eq>{{term.from.src_port}}</eq>
+            </src-port>
+{% endif %}
+{% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ != 'list'%}
+            <dst-port>
+                <eq>{{term.from.dst_port}}</eq>
+            </dst-port>
+{% endif %}
+ {# Port range #}
+ {% if term.from.port_range is defined %}
+            <port>
+                <port-list>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list>
+            </port>
+{% endif %}
+{% if term.from.src_port_range is defined %}
+            <src-port>
+                <port-list>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list>
+            </src-port>
+{% endif %}
+{% if term.from.dst_port_range is defined %}
+            <dst-port>
+                <port-list>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list>
+            </dst-port>
+{% endif %}
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
new file mode 100644
index 0000000000000000000000000000000000000000..2c985ecc774a3ac8dcd84dcbef668a20f9252337
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
@@ -0,0 +1,21 @@
+{# This template takes care of configuring connectors and breakouts #}
+
+    <match-list>
+{% for filter in filters %}
+  {% if filter.terms is defined %}
+    {% for term in filter.terms %}
+      {% if term.from.protocol_list is defined and term.from.protocol_list.__class__.__name__ == 'list' %}
+        <protocol-list>
+            <protocol-list-name>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list-name>
+        {%for protocol in term.from.protocol_list %}
+            <protocol>
+                <protocol-id>{{ protocol }}</protocol-id>
+            </protocol>
+        {% endfor %}
+        </protocol-list>
+      {% endif %}
+    {% endfor %}
+  {% endif %}
+{% endfor %}
+    </match-list>
+
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/term_action.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/term_action.j2
new file mode 100644
index 0000000000000000000000000000000000000000..e9c2d0249235cbce310be070bffd25ff4756d456
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/term_action.j2
@@ -0,0 +1,15 @@
+            <action>
+                <{{term.action}}></{{term.action}}>
+                {% if term.action_context is defined %}
+                  {% for act in term.action_context %}
+                    {% if act.type in ['rate-limit'] %}
+                <{{ act.type }}>
+                    {% for kind, kind_val in act.kinds.items() %}
+                      <{{ kind }}>{{ kind_val }}</{{ kind }}>
+                    {% endfor %}
+                </{{ act.type }}>
+                    {% endif %}
+                  {% endfor %}
+                {% endif %}
+            </action>
+
diff --git a/geant/gap_ansible/roles/fw_filters/vars/main.yml b/geant/gap_ansible/roles/fw_filters/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2b4e499d80414911093a339e0fdf66dcadcc3ea5
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/vars/main.yml
@@ -0,0 +1,3 @@
+---
+# vars file for fw_filters
+is_standalone_run: false
diff --git a/geant/gap_ansible/roles/policy_options/README.md b/geant/gap_ansible/roles/policy_options/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..59f3169b51df03537a0cbc08d30969f07d6a7f08
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/README.md
@@ -0,0 +1,36 @@
+Role Name
+=========
+
+A role for configuring policy options stanza in Nokia SROS.
+
+Requirements
+------------
+
+GEANT custom netconf module with Nokia "commit_comment" and "config_mode" features.
+
+Role Variables
+--------------
+
+- vars/main.yaml
+- external inventory (group_vars)
+- orchestrator (GSO)
+
+Dependencies
+------------
+
+n/a
+
+Example Playbook
+----------------
+
+Role is supposed to be driven by GSO.
+
+License
+-------
+
+MIT
+
+Author Information
+------------------
+
+A. Kurbatov, S. Spinelli. GEANT Orchestration and Automation Team (GOAT).
diff --git a/geant/gap_ansible/roles/policy_options/defaults/main.yml b/geant/gap_ansible/roles/policy_options/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9304af02ad1fe2cb4569f056476a2366d9b91739
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for policy_options
diff --git a/geant/gap_ansible/roles/policy_options/handlers/main.yml b/geant/gap_ansible/roles/policy_options/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..144f2424c79fc7c69509cefc0c47f4f63180ea74
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for policy_options
diff --git a/geant/gap_ansible/roles/policy_options/meta/main.yml b/geant/gap_ansible/roles/policy_options/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..36d899dd86d8c01083aefc8c7000b2cf64cacd75
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/meta/main.yml
@@ -0,0 +1,35 @@
+galaxy_info:
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  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:
+
+  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.
diff --git a/geant/gap_ansible/roles/policy_options/tasks/compile.yaml b/geant/gap_ansible/roles/policy_options/tasks/compile.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6414d2ba2d338c301ba2c66d9230be37d98e303e
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/compile.yaml
@@ -0,0 +1,15 @@
+---
+- name: Set ansible host to localhost to compile template
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf"
+  # when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "policy_options.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/policy_options/tasks/deploy_po.yaml b/geant/gap_ansible/roles/policy_options/tasks/deploy_po.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..70b027dec1eda014c9c26bf09c5914df8c39ee7d
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/deploy_po.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy PO config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy PO config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/policy_options/tasks/main.yml b/geant/gap_ansible/roles/policy_options/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4fbe967f80775b9e7ef898ff32ebc7922baf54fc
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/main.yml
@@ -0,0 +1,11 @@
+---
+# tasks file for policy_options
+- name: Load Standard Policy Statements vars
+  ansible.builtin.include_tasks: merge_vars.yaml
+
+- name: Compile templates
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Deploy templates if standalone run
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_po.yaml
diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f4bfd77a985d4b5f0dd4c2d1db2d3000b9bbe757
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -0,0 +1,93 @@
+---
+- name: Prepare Policy vars for L3 Core Service with standard filters
+  when: >-
+    subscription.product.product_type == "L3CoreService"
+    and
+    subscription.l3_core_service_type == "GÉANT IP"
+  block:
+    - name: Merge NREN standard policies V4
+      ansible.builtin.set_fact:
+        standard_nren_policies_v4: "{{ lookup('community.general.merge_variables', 'STANDARD_PO_POL_STATEMENTS_V4') }}"
+
+    - name: Merge NREN standard policies v6
+      ansible.builtin.set_fact:
+        standard_nren_policies_v6: "{{ lookup('community.general.merge_variables', 'STANDARD_PO_POL_STATEMENTS_V6') }}"
+
+    - name: Set NREN community name
+      ansible.builtin.set_fact:
+        nren_community_names: ["GEANT_{{ partner_name | upper }}", "GEANT_{{ partner_name | upper }}_BLOCK"]
+
+    - name: Set NREN community value (2-byte ASN)
+      when: (partner.asn | int) < 65536
+      ansible.builtin.set_fact:
+        nren_community_values: ["{{ geant_re_as_number }}:{{ partner.asn }}", "{{ bgp.block_community_prefix }}:{{ partner.asn }}"]
+
+    - name: Set NREN community value (4-byte ASN)
+      when: (partner.asn | int) > 65535
+      ansible.builtin.set_fact:
+        nren_community_values: ["origin:{{ partner.asn }}:{{ geant_re_as_number }}", "origin:{{ partner.asn }}:{{ block_community_prefix }}"]
+
+    - name: Create a list of NREN communities
+      ansible.builtin.set_fact:
+        nren_po_communities: "{{ nren_po_communities | default([]) + [ {'name': item.0, 'member': item.1} ] }}"
+      loop: "{{ nren_community_names | zip(nren_community_values) | list }}"
+
+- name: Set BGP V4 session object
+  ansible.builtin.set_fact:
+    bgp_session_v4: "{{ ap.sbp | json_query(query) }}"
+  vars:
+    query: "bgp_session_list[?ip_type == 'ipv4'] | [0]"
+
+- name: Set BGP V6 session object
+  ansible.builtin.set_fact:
+    bgp_session_v6: "{{ ap.sbp | json_query(query) }}"
+  vars:
+    query: "bgp_session_list[?ip_type == 'ipv6'] | [0]"
+
+- name: Select Custom V4 policies if specified by GSO
+  when: >-
+    bgp_session_v4.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    custom_nren_policies_v4: "{{ lookup('community.general.merge_variables', 'CUSTOM_PO_POL_STATEMENTS_V4') }}"
+
+- name: Select Custom V6 policies if specified by GSO
+  when: >-
+    bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    custom_nren_policies_v6: "{{ lookup('community.general.merge_variables', 'CUSTOM_PO_POL_STATEMENTS_V6') }}"
+
+- name: Combine policies when V4 is custom and V6 is standard
+  when: >
+    bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    not bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [custom_nren_policies_v4, standard_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Combine policies when V4 is custom and V6 is custom
+  when: >
+    bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [custom_nren_policies_v4, custom_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Combine policies when V4 is standard and V6 is custom
+  when: >
+    not bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [standard_nren_policies_v4, custom_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Combine policies when V4 is standard and V6 is standard
+  when: >
+    not bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    not bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [standard_nren_policies_v4, standard_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Debug final nren_policies
+  ansible.builtin.debug:
+    var: nren_policies
diff --git a/geant/gap_ansible/roles/policy_options/templates/as_paths.j2 b/geant/gap_ansible/roles/policy_options/templates/as_paths.j2
new file mode 100644
index 0000000000000000000000000000000000000000..fadb9c5b01a5b69c57cd13877f0c9b4d86dea62a
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/as_paths.j2
@@ -0,0 +1,6 @@
+    {% for as_path in as_paths_obj %}
+    <as-path alu:operation="replace">
+      <name>{{ as_path.name }}</name>
+      <expression>{{ as_path.expression}}</expression>
+    </as-path>
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/communities.j2 b/geant/gap_ansible/roles/policy_options/templates/communities.j2
new file mode 100644
index 0000000000000000000000000000000000000000..631ddacf38c264784038e969961227f8a09f186c
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/communities.j2
@@ -0,0 +1,8 @@
+    {% for community in communities_obj %}
+    <community alu:operation="replace">
+      <name>{{ community.name }}</name>
+        <member>
+          <member>{{ community.member }}</member>
+        </member>
+    </community>
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
new file mode 100644
index 0000000000000000000000000000000000000000..47e5933d851d8d1dda839b92e5660f0bca78ff88
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
@@ -0,0 +1,39 @@
+{% if is_standalone_run %}
+<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">
+{% endif %}
+
+  <policy-options 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">
+  {#  {% if nokia_po_prefix_lists is defined %} #}
+  {#    {% with prefix_lists_obj=nokia_po_prefix_lists %} #}
+  {#    {% include 'policy_options/prefix_lists.j2' %} #}
+  {#    {% endwith %} #}
+  {#  {% endif %} #}
+
+    {# Communities #}
+    {% if nren_po_communities is defined %}
+      {% with communities_obj=nren_po_communities %}
+      {% include 'communities.j2' %}
+      {% endwith %}
+    {% endif %}
+
+    {# AS paths #}
+  {#  {% if nokia_po_as_paths is defined %} #}
+  {#    {% with as_paths_obj=nokia_po_as_paths %} #}
+  {#    {% include 'policy_options/as_paths.j2' %} #}
+  {#    {% endwith %} #}
+  {#  {% endif %} #}
+
+  {# Policy statements #}
+    {% if nren_policies is defined %}
+      {% with policy_obj=nren_policies %}
+      {% include 'policy_statements.j2' %}
+      {% endwith %}
+    {% endif %}
+ 
+  </policy-options>
+ 
+{% if is_standalone_run %}
+   </configure>
+</config>
+{% endif %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
new file mode 100644
index 0000000000000000000000000000000000000000..32570140396d4ae3b13b8daeccea839f4f1f8b39
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
@@ -0,0 +1,77 @@
+    {% for pol in policy_obj %}
+    <policy-statement alu:operation="replace">
+      <name>{{ pol.name }}</name>
+      <entry-type>{{ pol.entry_type }}</entry-type>
+      {% for entry in pol.entries %}
+        {% if pol.entry_type == 'named' %}
+      <named-entry>
+        {% endif %}
+        <entry-name>{{ entry.name }}</entry-name>
+        {% if entry.from is defined %}
+        <from>
+          {% if entry.from.as_path is defined %}
+            <as-path>
+            {% if entry.from.as_path.name is defined %}
+                <name>{{ entry.from.as_path.name }}</name>
+            {% endif %}
+            {% if entry.from.as_path.length is defined %}
+                <length>
+                      <value>{{ entry.from.as_path.length }}</value>
+                </length>
+            {% endif %}
+            </as-path>
+          {% endif %}
+          {% if entry.from.prefix_list is defined %}
+            {% for pl in entry.from.prefix_list %}
+            <prefix-list>{{ pl }}</prefix-list>
+            {% endfor %}
+          {% endif %}
+          {% if entry.from.policy is defined %}
+            <policy>{{ entry.from.policy }}</policy>
+          {% endif %}
+          {% if entry.from.community is defined %}
+            <community>
+                <name>{{ entry.from.community }}</name>
+            </community>
+          {% endif %}
+          {% if entry.from.origin_validation_state is defined %}
+            <origin-validation-state>{{ entry.from.origin_validation_state }}</origin-validation-state>
+          {% endif %}
+          {% if entry.from.protocol is defined %}
+            {% for proto in entry.from.protocol %}
+            <protocol>
+                  <name>{{ proto }}</name>
+            </protocol>
+            {% endfor %}
+          {% endif %}
+        </from>
+        {% endif %}
+        <action>
+            <action-type>{{ entry.action_type }}</action-type>
+          {% if entry.action is defined %}
+            {% for action_item in entry.action %}
+              {% for act_k, act_v in action_item.items() %}
+                {% if act_k == "community_add" %}
+                  {% for community in act_v %}
+            <community>
+                <add>{{ community }}</add>
+            </community>
+                  {% endfor %}
+                {% elif act_k == "bgp_med" %}
+            <bgp-med>
+                <set>{{ act_v | default(bgp.standard_metric.med[ap_type]) }}</set>
+            </bgp-med>
+                {% elif act_k == "local_preference" %}
+            <local-preference>{{ act_v | default(bgp.standard_metric.loca_pref[ap_type]) }}</local-preference>
+                {% else %}
+            <{{ act_k | replace("_", "-") }}>{{ act_v }}</{{act_k  | replace("_", "-") }}>
+                {% endif %}
+              {% endfor %}
+            {% endfor %}
+          {% endif %}
+        </action>
+      </named-entry>
+      {% endfor %}
+    </policy-statement>
+
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/prefix_lists.j2 b/geant/gap_ansible/roles/policy_options/templates/prefix_lists.j2
new file mode 100644
index 0000000000000000000000000000000000000000..507986e60983c0445d2110328584695d67b2b70a
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/prefix_lists.j2
@@ -0,0 +1,15 @@
+    {% for prefix_list in prefix_lists_obj %}
+    <prefix-list alu:operation="replace">
+        <name>{{ prefix_list.name }}</name>
+        {% for prefix in prefix_list.prefixes %}
+        <prefix>
+          <ip-prefix>{{ prefix.ip }}</ip-prefix>
+          <type>{{ prefix.type }}</type>
+          {% if prefix.type == 'range' %}
+          <start-length>{{ prefix.range_start_length }}</start-length>
+          <end-length>{{ prefix.range_end_length }}</end-length>
+          {% endif %}
+        </prefix>
+        {% endfor %}
+    </prefix-list>
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/vars/main.yml b/geant/gap_ansible/roles/policy_options/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8f15eb5c4769d25fcb5dbc695a31466d007380fc
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/vars/main.yml
@@ -0,0 +1,6 @@
+---
+# vars file for policy_options
+is_standalone_run: false
+
+site_name: "{{ ap.sbp.edge_port.node.router_site.site_name }}"
+ap_type: "{{ ap.ap_type }}"
diff --git a/geant/gap_ansible/roles/prefix_lists/README.md b/geant/gap_ansible/roles/prefix_lists/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..225dd44b9fc5b3abff7e9c68ff9e91d505cdd5f0
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/prefix_lists/defaults/main.yml b/geant/gap_ansible/roles/prefix_lists/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c35214fe9a12af4dce48979dbfc7a04b6023f0cc
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for prefix_lists
diff --git a/geant/gap_ansible/roles/prefix_lists/handlers/main.yml b/geant/gap_ansible/roles/prefix_lists/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..678e7dfe1305013489b5c8117b609d0cdbb585d0
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for prefix_lists
diff --git a/geant/gap_ansible/roles/prefix_lists/meta/main.yml b/geant/gap_ansible/roles/prefix_lists/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ed3d2d88a7dbec99025adc52984c3cdbec461720
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/meta/main.yml
@@ -0,0 +1,24 @@
+galaxy_info:
+  author: Simone Spinelli, A. Kurbatov
+  description: Geant Orchestration and Automation Team
+  company: Geant
+
+  license: MIT
+
+  min_ansible_version: '2.10'
+
+  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/prefix_lists/tasks/deploy_prefix_lists.yaml b/geant/gap_ansible/roles/prefix_lists/tasks/deploy_prefix_lists.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0062393ff9a211b22c303fd2af8457b326e8856a
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/deploy_prefix_lists.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..966e0cb0844e93eaa91d364742bb6e0a9d744324
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
@@ -0,0 +1,60 @@
+---
+# tasks file for prefix_lists
+- name: Collect prefixes and render the prefix template
+  delegate_to: localhost
+  block:
+    - name: Collect IPV4 routes from bgpq4
+      ansible.builtin.command: bgpq4 -j4 "{{ partner.as_set }}"
+      register: bgpq4_ipv4_routes_in_json
+      changed_when: true
+
+    - name: Convert IPV4 output to real json
+      ansible.builtin.set_fact:
+        ipv4_prefix_list_name: "{{ partner_name | upper }}_{{ partner.type }}_PREFIXES_IPV4"
+        routes: "{{ bgpq4_ipv4_routes_in_json.stdout | from_json }}"
+
+    - name: Fail if IPV4 routes list lenght is too short
+      when: routes.NN | length  <= 1
+      ansible.builtin.meta: end_play
+
+    - name: Form IPV4 route object
+      ansible.builtin.set_fact:
+        bgpq4_ipv4_routes: "{{ bgpq4_ipv4_routes | default([]) + [item.prefix] }}"
+      loop: "{{ routes.NN }}"
+
+
+    - name: Collect IPV6 routes from bgpq4
+      ansible.builtin.command: bgpq4 -j6 "{{ partner.as_set }}"
+      register: bgpq4_ipv6_routes_in_json
+      changed_when: true
+
+    - name: Convert IPV6 outeput to real json
+      ansible.builtin.set_fact:
+        ipv6_prefix_list_name: "{{ partner_name | upper }}_{{ partner.type }}_PREFIXES_IPV6"
+        routes: "{{ bgpq4_ipv6_routes_in_json.stdout | from_json }}"
+
+    - name: Fail if IPV6 routes list lenght is too short
+      when: routes.NN | length  <= 1
+      ansible.builtin.meta: end_play
+
+    - name: Form IPV6 route object
+      ansible.builtin.set_fact:
+        bgpq4_ipv6_routes: "{{ bgpq4_ipv6_routes | default([]) + [item.prefix] }}"
+      loop: "{{ routes.NN }}"
+
+    - name: Put everything together
+      ansible.builtin.set_fact:
+        nren_prefix_lists: "{{ nren_prefix_lists | default([]) + [{'name': ipv4_prefix_list_name, 'prefixes': bgpq4_ipv4_routes},
+                                                                  {'name': ipv6_prefix_list_name, 'prefixes': bgpq4_ipv6_routes}] }}"
+
+    - name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf"
+      ansible.builtin.template:
+        src: "nokia/prefix_lists.j2"
+        dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf"
+        lstrip_blocks: true
+        trim_blocks: true
+        mode: '0755'
+
+- name: Include deploy if standalone run
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_prefix_lists.yaml
diff --git a/geant/gap_ansible/roles/prefix_lists/templates/juniper/prefix-lists.j2 b/geant/gap_ansible/roles/prefix_lists/templates/juniper/prefix-lists.j2
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix_lists.j2 b/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix_lists.j2
new file mode 100644
index 0000000000000000000000000000000000000000..030fe1e1d3d30930a92513e16579940fc4e9ffe4
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix_lists.j2
@@ -0,0 +1,24 @@
+{% if is_standalone_run %}
+<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">
+{% endif %}
+
+  <policy-options 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">
+    {% for prefix_list in nren_prefix_lists %}
+    <prefix-list alu:operation="replace">
+        <name>{{ prefix_list.name }}</name>
+        {% for prefix in prefix_list.prefixes %}
+        <prefix>
+          <ip-prefix>{{ prefix }}</ip-prefix>
+          <type>exact</type>
+        </prefix>
+        {% endfor %}
+    </prefix-list>
+    {% endfor %}
+
+  </policy-options>
+  
+{% if is_standalone_run %}
+   </configure>
+</config>
+{% endif %}
diff --git a/geant/gap_ansible/roles/prefix_lists/vars/main.yml b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..38f88d46ab30a9d0b77121b91b60e28c746f4a78
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
@@ -0,0 +1,3 @@
+---
+# vars file for prefix_lists
+is_standalone_run: false
diff --git a/geant/gap_ansible/roles/sbp/README.md b/geant/gap_ansible/roles/sbp/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..225dd44b9fc5b3abff7e9c68ff9e91d505cdd5f0
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/sbp/defaults/main.yml b/geant/gap_ansible/roles/sbp/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1f4c6c4e52eae554499e650d0fa82826dfad1848
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for sbp
diff --git a/geant/gap_ansible/roles/sbp/handlers/main.yml b/geant/gap_ansible/roles/sbp/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..21997a5bce3295840afc2f38b81189eb14a6db85
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for sbp
diff --git a/geant/gap_ansible/roles/sbp/meta/main.yml b/geant/gap_ansible/roles/sbp/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..36d899dd86d8c01083aefc8c7000b2cf64cacd75
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/meta/main.yml
@@ -0,0 +1,35 @@
+galaxy_info:
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  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:
+
+  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.
diff --git a/geant/gap_ansible/roles/sbp/tasks/compile.yaml b/geant/gap_ansible/roles/sbp/tasks/compile.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7fe1709483e04a08bdc56e41d338fb466d84b247
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/compile.yaml
@@ -0,0 +1,15 @@
+---
+- name: Set ansible host to localhost to compile template
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf"
+  # when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "{{ verb }}_sbp.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml b/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..89bdd754d41c1a836a7a4d220367cb7b0c8dea04
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/sbp/tasks/main.yml b/geant/gap_ansible/roles/sbp/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6b1049e77622a5f133abc07b9a49335fb0190824
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/main.yml
@@ -0,0 +1,11 @@
+---
+# tasks file for sbp
+- name: Merge vars
+  ansible.builtin.include_tasks: merge_vars.yaml
+
+- name: Include filter compilation
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Include filter compilation
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_sbp.yaml
diff --git a/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml b/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9107bbca567a366b1e8cc51d4cddea6afa54d030
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
@@ -0,0 +1,36 @@
+---
+- name: Set interface v4 BFD values
+  when: ap.sbp.v4_bfd_settings.bfd_enabled | ansible.builtin.bool
+  block:
+    - name: Set v4 BFD RX interval to GSO value
+      when: ap.sbp.v4_bfd_settings.bfd_interval_rx != None
+      ansible.builtin.set_fact:
+        sbp_v4_bfd_interval_rx: "{{ ap.sbp.v4_bfd_settings.bfd_interval_rx }}"
+
+    - name: Set v4 BFD TX interval to GSO value
+      when: ap.sbp.v4_bfd_settings.bfd_interval_tx != None
+      ansible.builtin.set_fact:
+        sbp_v4_bfd_interval_tx: "{{ ap.sbp.v4_bfd_settings.bfd_interval_tx }}"
+
+    - name: Set v4 BFD multiplier to GSO value
+      when: ap.sbp.v4_bfd_settings.bfd_multiplier != None
+      ansible.builtin.set_fact:
+        sbp_v4_bfd_multiplier: "{{ ap.sbp.v4_bfd_settings.bfd_multiplier }}"
+
+- name: Set interface v6 BFD values
+  when: ap.sbp.v6_bfd_settings.bfd_enabled | ansible.builtin.bool
+  block:
+    - name: Set v6 BFD RX interval to GSO value
+      when: ap.sbp.v6_bfd_settings.bfd_interval_rx != None
+      ansible.builtin.set_fact:
+        sbp_v6_bfd_interval_rx: "{{ ap.sbp.v6_bfd_settings.bfd_interval_rx }}"
+
+    - name: Set v6 BFD TX interval to GSO value
+      when: ap.sbp.v6_bfd_settings.bfd_interval_tx != None
+      ansible.builtin.set_fact:
+        sbp_v6_bfd_interval_tx: "{{ ap.sbp.v6_bfd_settings.bfd_interval_tx }}"
+
+    - name: Set v6 BFD multiplier to GSO value
+      when: ap.sbp.v6_bfd_settings.bfd_multiplier != None
+      ansible.builtin.set_fact:
+        sbp_v6_bfd_multiplier: "{{ ap.sbp.v6_bfd_settings.bfd_multiplier }}"
diff --git a/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2 b/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
new file mode 100644
index 0000000000000000000000000000000000000000..18748b50deeee2a445fb409d4eab7317764a6d3f
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
@@ -0,0 +1,92 @@
+{% if is_standalone_run %}
+<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">
+{% endif %}
+
+        <service 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">
+            <ies 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">
+                <service-name>{{ ies_re_name }}</service-name>
+                <interface alu:operation="replace">
+                    <interface-name>{{ lag_name }}.{{ ap.sbp.vlan_id }}</interface-name>
+                    <description>SRV_GLOBAL CUSTOMER {{ partner_name }} #{{ partner_name }}-{{ ap.ap_type }} ${{ ap.sbp.geant_sid }} | ASN{{ partner.asn }} | </description>
+                    <ip-mtu>{{ sbp_params.ip_mtu }}</ip-mtu>
+                    <sap>
+                      {% if ap.sbp.is_tagged %}
+                        <sap-id>{{ lag_name }}:{{ ap.sbp.vlan_id }}</sap-id>
+                      {% else %}
+                        <sap-id>{{ lag_name }}</sap-id>
+                      {% endif %}
+                        <admin-state>enable</admin-state>
+                        <ingress>
+                            <filter>
+                                <ip>{{ partner_name | upper }}_EDGE_IN</ip>
+                                <ipv6>{{ partner_name | upper }}_EDGE_IN_V6</ipv6>
+                            </filter>
+                        </ingress>
+                        <egress>
+                            <filter>
+                                <ip>{{ partner_name | upper }}_EDGE_OUT</ip>
+                                <ipv6>{{ partner_name | upper }}_EDGE_OUT_V6</ipv6>
+                            </filter>
+                        </egress>
+                    </sap>
+                    <ipv4>
+                      {% if ap.sbp.v4_bfd_settings.bfd_enabled %}
+                        <bfd>
+                            <admin-state>enable</admin-state>
+                            {% if ap.sbp.v4_bfd_settings.bfd_interval_tx is not none %}
+                            <transmit-interval>{{ ap.sbp.v4_bfd_settings.bfd_interval_tx }}</transmit-interval>
+                            {% else %}
+                            <transmit-interval>{{ sbp_params.bfd.ipv4.transmit }}</transmit-interval>
+                            {% endif %}
+                            {% if ap.sbp.v4_bfd_settings.bfd_interval_rx is not none %}
+                            <receive>{{ ap.sbp.v4_bfd_settings.bfd_interval_rx  }}</receive>
+                            {% else %}
+                            <receive>{{ sbp_params.bfd.ipv4.receive }}</receive>
+                            {% endif %}
+                            {% if ap.sbp.v4_bfd_settings.bfd_multiplier is not none %}
+                            <multiplier>{{ ap.sbp.v4_bfd_settings.bfd_multiplier  }}</multiplier>
+                            {% else %}
+                            <multiplier>{{ sbp_params.bfd.ipv4.multiplier }}</multiplier>
+                            {% endif %}
+                        </bfd>
+                      {% endif %}
+                        <primary>
+                            <address>{{ ap.sbp.ipv4_address }}</address>
+                            <prefix-length>{{ ap.sbp.ipv4_mask }}</prefix-length>
+                        </primary>
+                    </ipv4>
+                    <ipv6>
+                      {% if ap.sbp.v6_bfd_settings.bfd_enabled %}
+                        <bfd>
+                            <admin-state>enable</admin-state>
+                            {% if ap.sbp.v6_bfd_settings.bfd_interval_tx is not none %}
+                            <transmit-interval>{{ ap.sbp.v6_bfd_settings.bfd_interval_tx }}</transmit-interval>
+                            {% else %}
+                            <transmit-interval>{{ sbp_params.bfd.ipv6.transmit }}</transmit-interval>
+                            {% endif %}
+                            {% if ap.sbp.v6_bfd_settings.bfd_interval_rx is not none %}
+                            <receive>{{ ap.sbp.v6_bfd_settings.bfd_interval_rx  }}</receive>
+                            {% else %}
+                            <receive>{{ sbp_params.bfd.ipv6.receive }}</receive>
+                            {% endif %}
+                            {% if ap.sbp.v6_bfd_settings.bfd_multiplier is not none %}
+                            <multiplier>{{ ap.sbp.v6_bfd_settings.bfd_multiplier  }}</multiplier>
+                            {% else %}
+                            <multiplier>{{ sbp_params.bfd.ipv6.multiplier }}</multiplier>
+                            {% endif %}
+                        </bfd>
+                      {% endif %}
+                        <address>
+                            <ipv6-address>{{ ap.sbp.ipv6_address }}</ipv6-address>
+                            <prefix-length>{{ ap.sbp.ipv6_mask }}</prefix-length>
+                        </address>
+                    </ipv6>
+                </interface>
+            </ies>
+        </service>
+
+{% if is_standalone_run %}
+   </configure>
+</config>
+{% endif %}
diff --git a/geant/gap_ansible/roles/sbp/vars/main.yml b/geant/gap_ansible/roles/sbp/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..116ca033093b9f9f533ec056c1998972bc3af6e7
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/vars/main.yml
@@ -0,0 +1,12 @@
+---
+# vars file for sbp
+is_standalone_run: false
+
+lag_name: "{{ ap.sbp.edge_port.edge_port_name }}"
+
+sbp_v4_bfd_multiplier: "{{ sbp_params.bfd.ipv4.multiplier }}"
+sbp_v4_bfd_interval_rx: "{{ sbp_params.bfd.ipv4.receive }}"
+sbp_v4_bfd_interval_tx: "{{ sbp_params.bfd.ipv4.transmit }}"
+sbp_v6_bfd_multiplier: "{{ sbp_params.bfd.ipv6.multiplier }}"
+sbp_v6_bfd_interval_rx: "{{ sbp_params.bfd.ipv6.receive }}"
+sbp_v6_bfd_interval_tx: "{{ sbp_params.bfd.ipv6.transmit }}"
diff --git a/requirements.txt b/requirements.txt
index 08f36aa2a74d41afd897d8880d22153fa22d0e4f..691676c82ba1dd79367447518b6ce463212a41de 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1,3 @@
-ncclient
\ No newline at end of file
+ncclient
+ansible
+ansible-lint
\ No newline at end of file