diff --git a/.gitignore b/.gitignore
index 3c7bd387010700ff33161c4f86c529b0833ab4b5..43751b0e020f729378a4a9981724da5fdb207e32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@
 *.egg-info
 dist/
 __pycache__/
-.DS_Store
\ No newline at end of file
+.DS_Store
+.vscode
diff --git a/geant/gap_ansible/roles/ibgp_update/README.md b/geant/gap_ansible/roles/ibgp_update/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..225dd44b9fc5b3abff7e9c68ff9e91d505cdd5f0
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/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/ibgp_update/meta/main.yml b/geant/gap_ansible/roles/ibgp_update/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3bc04a23a853a60a9373b41e92a8f1178196c62a
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/meta/main.yml
@@ -0,0 +1,52 @@
+galaxy_info:
+  author: GOAT
+  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.1"
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  #
+  # Provide a list of supported platforms, and for each platform a list of versions.
+  # If you don't wish to enumerate all versions for a particular platform, use 'all'.
+  # To view available platforms and versions (or releases), visit:
+  # https://galaxy.ansible.com/api/v1/platforms/
+  #
+  # platforms:
+  # - name: Fedora
+  #   versions:
+  #   - all
+  #   - 25
+  # - name: SomePlatform
+  #   versions:
+  #   - all
+  #   - 1.0
+  #   - 7
+  #   - 99.99
+
+  galaxy_tags: []
+    # 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/ibgp_update/tasks/add_p_to_pe.yaml b/geant/gap_ansible/roles/ibgp_update/tasks/add_p_to_pe.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b63274a376b4bdaaf63c445c263b00d66830cdee
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/tasks/add_p_to_pe.yaml
@@ -0,0 +1,24 @@
+# P to PE tasks:
+# We need to add the new P to all the PEs
+# PEs can be either Juniper or Nokia
+
+- name: Adjust network connection according to the vendor
+  block:
+  #
+   - name: Set variable to connect to nokia
+     ansible.legacy.set_fact:
+      ansible_network_os: nokia.sros.md
+      ansible_connection: netconf
+     when: vendor == "nokia"
+
+   - name: Set variables for connecting to Junos
+     ansible.legacy.set_fact:
+      ansible_network_os: junos
+      ansible_connection: netconf
+     when: vendor == "juniper"
+
+- name: Include compile tasks
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Include deploy tasks
+  ansible.builtin.include_tasks: deploy.yaml
diff --git a/geant/gap_ansible/roles/ibgp_update/tasks/add_pe_to_p.yaml b/geant/gap_ansible/roles/ibgp_update/tasks/add_pe_to_p.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..34b4d5cbd319808dd2bb4f658bbf797a44d7fa94
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/tasks/add_pe_to_p.yaml
@@ -0,0 +1,25 @@
+# PE to P tasks:
+# We need to add all the existing PE the new P
+# P routers will always be NOKIA
+# In this case you have wfo_router as external variable
+
+- name: Set variable to connect to nokia
+  ansible.legacy.set_fact:
+    ansible_network_os: nokia.sros.md
+    ansible_connection: netconf
+
+- name: Set ansible_host to terminal server when router is offline
+  ansible.legacy.set_fact:
+    ansible_host: "{{ subscription.router.router_site.site_ts_address }}"
+    ansible_port: "{{ subscription.router.router_ts_port }}"
+  when: ( subscription.router.router_access_via_ts | ansible.builtin.bool ) is true
+
+- name: Set the vendor variable so I can select the template
+  ansible.legacy.set_fact:
+    vendor: "{{ subscription.router.router_vendor }}"
+
+- name: Include compile tasks
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Include deploy tasks
+  ansible.builtin.include_tasks: deploy.yaml
diff --git a/geant/gap_ansible/roles/ibgp_update/tasks/compile.yaml b/geant/gap_ansible/roles/ibgp_update/tasks/compile.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..988dcabfaff9b87e0f995022805bb4238366b174
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/tasks/compile.yaml
@@ -0,0 +1,31 @@
+- name: Set ansible host to localhost to compile config when router is offline
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+  when:
+    wfo_router.router.router_access_via_ts is defined and
+    ( wfo_router.router.router_access_via_ts | ansible.builtin.bool ) is true
+
+- name: Create a folder for all the things
+  ansible.builtin.file:
+    path: "/var/tmp/ansible_run_{{ opid }}"
+    state: directory
+    mode: '0755'
+  delegate_to: localhost
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ verb }}.conf"
+  ansible.builtin.template:
+    src: "{{ vendor }}/{{ verb }}.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ verb }}.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
+
+- name: Set back ansible_host to target terminal server
+  ansible.builtin.set_fact:
+    ansible_host: "{{ wfo_router.router.router_site.site_ts_address }}"
+    ansible_connection: netconf
+  when:
+    wfo_router.router.router_access_via_ts is defined and
+    ( wfo_router.router.router_access_via_ts | ansible.builtin.bool ) is true
diff --git a/geant/gap_ansible/roles/ibgp_update/tasks/deploy.yaml b/geant/gap_ansible/roles/ibgp_update/tasks/deploy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6bd85804a8f9dfc61e57d1cf16f7c700755d56f7
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/tasks/deploy.yaml
@@ -0,0 +1,74 @@
+- name: Update iBGP mesh ["{{ verb }}"] on "{{ inventory_hostname }}" [CHECK ONLY][Juniper]
+  juniper_junos_config:
+    load: 'replace'
+    src: "/var/tmp/ansible_run_{{ opid }}/{{ verb }}.conf"
+    format: text
+    config_mode: "private"
+    check: true
+    commit: false
+  register: response
+  when: >
+    ( dry_run | ansible.builtin.bool ) is true and
+    vendor == "juniper"
+
+- name: Show diff for dry run
+  ansible.builtin.debug:
+    msg: "{{ response }}"
+  when: >
+    ( dry_run | ansible.builtin.bool ) is true and
+    vendor == "juniper"
+
+- name: Update iBGP mesh ["{{ verb }}"] on "{{ inventory_hostname }}" [AND COMMIT][Juniper]
+  juniper_junos_config:
+    load: 'replace'
+    src: "/var/tmp/ansible_run_{{ opid }}/{{ verb }}.conf"
+    format: text
+    config_mode: "private"
+    comment: "{{ commit_comment }}"
+  register: response
+  when: >
+    ( dry_run | ansible.builtin.bool ) is false and
+    vendor == "juniper"
+
+- name: Show diff
+  ansible.builtin.debug:
+    msg: "{{ response }}"
+  when: >
+    ( dry_run | ansible.builtin.bool ) is false and
+    vendor == "juniper"
+
+- name: Update iBGP mesh ["{{ verb }}"] on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  ansible.netcommon.netconf_config:
+  # geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.template', 'routers/{{ vendor }}/{{ verb }}.j2') }}"
+    commit: true
+    validate: true
+  # diff: true
+  check_mode: true
+  when: >
+    ( dry_run | ansible.builtin.bool ) is true and
+    vendor == "nokia"
+
+- name: Validation succeeded
+  ansible.builtin.debug:
+    msg: "Base config has been validated against the router and no syntax errors were found"
+  when: >
+    ( dry_run | ansible.builtin.bool ) is true and
+    vendor == "nokia"
+
+
+- name: Update iBGP mesh ["{{ verb }}"] on "{{ inventory_hostname }}" [AND COMMIT][NOKIA]
+  ansible.netcommon.netconf_config:
+  # geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.template', 'routers/{{ vendor }}/{{ verb }}.j2') }}"
+    commit: true
+    # commit_comment: "Base-config provisioned using GSO."
+  # diff: true
+  check_mode: false
+  when: >
+    ( dry_run | ansible.builtin.bool ) is false and
+    vendor == "nokia"
diff --git a/geant/gap_ansible/roles/ibgp_update/tasks/main.yml b/geant/gap_ansible/roles/ibgp_update/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1e925b748f144753d29e280691fe2af373643f4f
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/tasks/main.yml
@@ -0,0 +1,32 @@
+---
+# tasks file for ibg_update
+- name: Print the usage
+  ansible.builtin.debug:
+    msg:
+      - "Allowed verbs: 'add_pe_to_p' and 'add_p_to_pe'. Use: -e 'verb=$verb'."
+  when: (verb is not defined) or (verb not in verbs)
+
+- name: Fail if arguments are missing
+  ansible.legacy.meta: end_play
+  when: (verb is not defined) or (verb not in verbs)
+
+- name: Import routers variables
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/routers
+
+- name: Generate an ID for this run
+  ansible.legacy.set_fact:
+    opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
+    config_is_different: "False"
+
+- name: Print the ID
+  ansible.builtin.debug:
+    msg: "{{ opid }}"
+
+- name: Include P into PEs tasks if selected
+  ansible.builtin.include_tasks: add_p_to_pe.yaml
+  when: verb == "add_p_to_pe"
+
+- name: Include PE into P tasks if selected
+  ansible.builtin.include_tasks: add_pe_to_p.yaml
+  when: verb == "add_pe_to_p"
diff --git a/geant/gap_ansible/roles/ibgp_update/templates/juniper/add_p_to_pe.j2 b/geant/gap_ansible/roles/ibgp_update/templates/juniper/add_p_to_pe.j2
new file mode 100644
index 0000000000000000000000000000000000000000..f8ca8a8d6ee98b8d4a2292be11bb7409b59076b9
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/templates/juniper/add_p_to_pe.j2
@@ -0,0 +1,2 @@
+set protocols bgp group iGEANT6-P-ONLY neighbor {{ p_lo_ipv6_address }} description {{ p_router_fqdn }}
+set protocols bgp group iGEANT-P-ONLY neighbor {{ p_lo_ipv4_address }} description {{ p_router_fqdn }}
diff --git a/geant/gap_ansible/roles/ibgp_update/templates/juniper/add_pe_to_p.j2 b/geant/gap_ansible/roles/ibgp_update/templates/juniper/add_pe_to_p.j2
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/geant/gap_ansible/roles/ibgp_update/templates/nokia/add_p_to_pe.j2 b/geant/gap_ansible/roles/ibgp_update/templates/nokia/add_p_to_pe.j2
new file mode 100644
index 0000000000000000000000000000000000000000..76f0cbffad592a293d0aa971926f874d17dde4bc
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/templates/nokia/add_p_to_pe.j2
@@ -0,0 +1,14 @@
+<router>
+    <bgp>
+        <neighbor 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">
+          <ip-address>{{ p_lo_ipv4_address }}</ip-address>
+          <description>{{ p_router_fqdn }}</description>
+          <group>iGEANT-P-ONLY</group>
+        </neighbor>
+        <neighbor 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">
+          <ip-address>{{ p_lo_ipv6_address }}</ip-address>
+          <description>{{ p_router_fqdn }}</description>
+          <group>iGEANT-P-ONLY-v6</group>
+        </neighbor>
+    </bgp>
+</router>
diff --git a/geant/gap_ansible/roles/ibgp_update/templates/nokia/add_pe_to_p.j2 b/geant/gap_ansible/roles/ibgp_update/templates/nokia/add_pe_to_p.j2
new file mode 100644
index 0000000000000000000000000000000000000000..4e4d22506225e1002e03ead7a7d39b4e12297e45
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/templates/nokia/add_pe_to_p.j2
@@ -0,0 +1,22 @@
+<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">
+    <router>
+        <bgp>
+        {% for pe_router in pe_router_list %}
+          {% for pe_fqdn, pe_ipadd in pe_router.items() %}
+            <neighbor 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">
+              <ip-address>{{ pe_ipadd.lo4 }}</ip-address>
+              <description>{{ pe_fqdn }}</description>
+              <group>iGEANT-P-ONLY</group>
+            </neighbor>
+            <neighbor 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">
+              <ip-address>{{ pe_ipadd.lo6 }}</ip-address>
+              <description>{{ pe_fqdn }}</description>
+              <group>iGEANT-P-ONLY-v6</group>
+            </neighbor>
+          {% endfor %}
+        {% endfor %}
+        </bgp>
+    </router>
+  </configure>
+</config>
diff --git a/geant/gap_ansible/roles/ibgp_update/vars/main.yml b/geant/gap_ansible/roles/ibgp_update/vars/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fb278f0af2cc5328436e9136ddcec727fc285f5f
--- /dev/null
+++ b/geant/gap_ansible/roles/ibgp_update/vars/main.yml
@@ -0,0 +1,15 @@
+---
+# vars file for ibg_update
+dry_run: "True"
+verbs:
+  - add_pe_to_p # Adds all the existing PEs in the P-GROUP on the newly installed P
+  - add_p_to_pe # Adds the newly installed P to the P-GROUP in all the existing PEs
+  - remove_p_from_pe # placeholder for future use | Removes the P that is going to be promoted to PE from the P-GROUP on all PEs
+  - add_pe_to_pe # placeholder for future use | Adds the newly installed PE (could be an EX-P or a new PE) to the PE-GROUP on all the other PEs
+  - add_new_pe_to_p # placeholder for future use | Adds the newly installed PE (could be an EX-P or a new PE) the P-GROUP on all the Ps
+  - remove_pe_from_net # placeholder for future use | When decommissiong a PE we remove it from PE-GROUP and P-GROUP on all the PE and P routers
+  - promote_p_to_pe # placeholder for future use | Deletes P-GROUP and adds
+wfo_router: "{{ subscription }}"
+p_lo_ipv4_address: "{{ wfo_router.router.router_lo_ipv4_address }}"
+p_lo_ipv6_address: "{{ wfo_router.router.router_lo_ipv6_address }}"
+p_router_fqdn: "{{ wfo_router.router.router_fqdn }}"