Ansible - Lag 3 Interface, OSPF og BGP

Ansible - Lag 3 Interface, OSPF og BGP


I dette eksempelet så kommer vi til å lage en lag 3 interface på våre rutere.
Vi kommer også til å konfigurere OSPF og BGP på disse rutere.

Oppsett av lag 3 interface
For å lage en lag 3 interface så må vi bruke ios_l3_interface modulen.
Vi kommer til å opprette ne vars fil som vi referer til i playbooken.
vars filen kommer til å inneholde informasjon om l3 interfacene.
vars_files: vars/l3_interfaces.yml

l3_interfaces:
  IOS_XE_ruter_3:
  -  { interface: GigabitEthernet2, ip: 10.190.0.2/28, description: "OSPF interface"}
  IOS_XE_ruter_2:
  -  { interface: GigabitEthernet2, ip: 10.190.0.1/28, description: "OSPF interface"}
  IOS_ruter_1:
  -  { interface: GigabitEthernet0/2, ip: 10.190.0.11/28, description: "OSPF interface"}
                

Playbook
---
- name: L3 interface konfigurasjon
  hosts: rutere
  gather_facts: no
  vars_files: vars/l3_interfaces.yaml
  
  tasks:
  
  -  name: l3 interfaces
     ios_l3_interfaces:
       config:
         - name: "{{ item.interface }}"
           ipv4:
             - address: "{{ item.ip }}"
       state: merged
     loop: "{{ l3_interfaces[inventory_hostname] }}"
                

ansible-playbook playbook_l3_interfaces.yaml -k
SSH password: 

PLAY [L3 interface konfigurasjon] ************************************************************************************************************************************************************************************

TASK [l3 interfaces] *************************************************************************************************************************************************************************************************
changed: [IOS_ruter_1] => (item={'interface': 'GigabitEthernet0/2', 'ip': '10.190.0.11/28', 'description': 'OSPF interface'})
changed: [IOS_XE_ruter_2] => (item={'interface': 'GigabitEthernet2', 'ip': '10.190.0.1/28', 'description': 'OSPF interface'})
changed: [IOS_XE_ruter_3] => (item={'interface': 'GigabitEthernet2', 'ip': '10.190.0.2/28', 'description': 'OSPF interface'})

PLAY RECAP ***********************************************************************************************************************************************************************************************************
IOS_XE_ruter_2             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_XE_ruter_3             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_ruter_1                : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
                

Aggregate
Det finnes en modul som heter aggregate som kan brukes til å slå sammen taskene som kjøres til en task
Så vi ser om vi kan bruke denne modulen ved å endre litt på oppbygningen av variablene.
ios_l3_interfaces tar ikke i mot aggregate feltet, men vi bygger opp variabel filen på en måte som gjør at det støttes.
vars_files: vars/l3_interfaces_aggregate.yml
Normalt så syns jeg det er mest oversiktlig å fordele variablene på flere linjer,
men i dette tilfellet syns jeg det enklere å bruke en linje for hvert interface.
For å se at det stemmer at tasken kun kjøres en gang så legger jeg til flere interface.
l3_interfaces:
  IOS_XE_ruter_3:
  - name: GigabitEthernet2
    ipv4: 
      - address: 10.190.0.2/28
  - name: GigabitEthernet3
    ipv4: 
      - address: 10.190.1.2/28
  IOS_XE_ruter_2:
  -  { name: GigabitEthernet2, ipv4: [{ address: "10.190.0.1/28" }] }
  -  { name: GigabitEthernet3, ipv4: [{ address: "10.190.1.1/28" }] }
  IOS_ruter_1:
  - { name: GigabitEthernet0/2, ipv4: [{address: 10.190.0.11/28}] }
  - { name: GigabitEthernet0/3, ipv4: [{address: 10.190.1.11/28}] }
                   

vars_files: vars/l3_interfaces.yml
Også oppdatere vi den andre varibalen for å legge til flere interface.
l3_interfaces:
  IOS_XE_ruter_3:
  -  { interface: GigabitEthernet2, ip: 10.190.0.2/28, description: "OSPF interface"}
  -  { interface: GigabitEthernet3, ip: 10.190.1.2/28, description: "OSPF interface"}
  IOS_XE_ruter_2:
  -  { interface: GigabitEthernet2, ip: 10.190.0.1/28, description: "OSPF interface"}
  -  { interface: GigabitEthernet3, ip: 10.190.1.1/28, description: "OSPF interface"}
  IOS_ruter_1:
  -  { interface: GigabitEthernet0/2, ip: 10.190.0.11/28, description: "OSPF interface"}
  -  { interface: GigabitEthernet0/3, ip: 10.190.1.11/28, description: "OSPF interface"}

                    

For å kunne se hvor lang tid playbooken tar, så legger jeg til callbacks_enabled = profile_tasks i ansible.cfg filen.
[defaults]
inventory = inventory
# Vi setter host_key_checking til false for å ikke verifisere host keys
host_key_checking = False
# aktivere tidtaking for å se hvor lang tid det tar å kjøre playbook
callbacks_enabled = profile_tasks
[persistent_connection]
# Vi setter timeout verdiene høyere for å unngå timeout feil ved kjøring av playbook
command_timeout = 180
connect_timeout = 100
connect_retry_timeout = 100
                    

playbook_l3_interfaces_aggregate.yaml
---
- name: L3 interface konfigurasjon
  hosts: rutere
  gather_facts: no
  vars_files: vars/l3_interfaces.yaml
  
  tasks:
  
  -  name: l3 interfaces
     ios_l3_interfaces:
       config:
         - name: "{{ item.interface }}"
           ipv4:
             - address: "{{ item.ip }}"
       state: deleted
     loop: "{{ l3_interfaces[inventory_hostname] }}"
                    

Når vi kjører playbooken uten aggregate så ser vi at tasken kjøres flere ganger.
ansible-playbook playbook_l3_interfaces.yaml -k
SSH password: 

PLAY [L3 interface konfigurasjon] ************************************************************************************************************************************************************************************

TASK [l3 interfaces] *************************************************************************************************************************************************************************************************
Thursday 27 June 2024  15:49:58 +0200 (0:00:00.151)       0:00:00.151 *********
changed: [IOS_ruter_1] => (item={'interface': 'GigabitEthernet0/2', 'ip': '10.190.0.11/28', 'description': 'OSPF interface'})
changed: [IOS_ruter_1] => (item={'interface': 'GigabitEthernet0/3', 'ip': '10.190.1.11/28', 'description': 'OSPF interface'})
changed: [IOS_XE_ruter_2] => (item={'interface': 'GigabitEthernet2', 'ip': '10.190.0.1/28', 'description': 'OSPF interface'})
changed: [IOS_XE_ruter_3] => (item={'interface': 'GigabitEthernet2', 'ip': '10.190.0.2/28', 'description': 'OSPF interface'})
changed: [IOS_XE_ruter_2] => (item={'interface': 'GigabitEthernet3', 'ip': '10.190.1.1/28', 'description': 'OSPF interface'})
changed: [IOS_XE_ruter_3] => (item={'interface': 'GigabitEthernet3', 'ip': '10.190.1.2/28', 'description': 'OSPF interface'})

PLAY RECAP ***********************************************************************************************************************************************************************************************************
IOS_XE_ruter_2             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_XE_ruter_3             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_ruter_1                : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Thursday 27 June 2024  15:50:14 +0200 (0:00:16.421)       0:00:16.573 *********
===============================================================================
l3 interfaces ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 16.42s 
                        

Når vi kjører playbooken med aggregate så ser vi at tasken kun kjøres en gang.
ansible-playbook playbook_l3_interfaces_aggregate.yaml -k
SSH password: 

PLAY [L3 interface konfigurasjon] ************************************************************************************************************************************************************************************

TASK [l3 interfaces aggregate] ***************************************************************************************************************************************************************************************
Thursday 27 June 2024  15:50:59 +0200 (0:00:00.171)       0:00:00.171 *********
changed: [IOS_ruter_1]
changed: [IOS_XE_ruter_2]
changed: [IOS_XE_ruter_3]

PLAY RECAP ***********************************************************************************************************************************************************************************************************
IOS_XE_ruter_2             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_XE_ruter_3             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_ruter_1                : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Thursday 27 June 2024  15:51:14 +0200 (0:00:14.918)       0:00:15.089 *********
===============================================================================
l3 interfaces aggregate -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 14.92s 
                           

Det tar nesten 2 sekunder kortere å bruke aggregate metoden.
Du kan se at tasken kun kjøres en gang, istedenfor to ganger pr enhet.
Her er det nok mye tid å spare hvis du har en stor playbook og mange enheter.

Neste steg blir å aktivere interfacene på ruterne og få lagt til vlan på switchene.
Vi har tidligere opprettet rollen collapsed_core som vi kan bruke til å konfigurere switchene.
Jeg oppretter en jinja2 template for l2 interfaces.
rolles/collapsed_core/templates/l2.j2
{% for int in l2interfaces %}
{% if int.switchport_mode == 'trunk' %}
interface {{ int.name }}
  description {{ int.description }}
  switchport mode {{ int.switchport_mode }}
  switchport trunk allowed vlan {{ int.switchport_allowed_vlan }}
{% endif %}
{% if int.switchport_mode == 'access' %}
interface {{ int.name }}
  description {{ int.description }}
  switchport mode {{ int.switchport_mode }}
  switchport access vlan {{ int.switchport_allowed_vlan }}
{% endif %}
{% endfor %}
                             

rolles/collapsed_core/tasks/l2int.yml
---
   - name: Opprett l2 med jinja2
     ios_config:
        src: "l2.j2"
        match: line
                             

Jeg importerer tasken i main.yml
  - name: Opprett l2 interfaces
    import_tasks: l2int.yaml
    tags: l2
                                

Variablene er lagt til i goup_vars/collapsed_core/vars
l2interfaces:
  - name: GigabitEthernet1/0/4
    description: "L2 trunk mellom core"
    switchport_mode: trunk
    switchport_allowed_vlan: 170,309
  - name: GigabitEthernet1/0/5
    description: "mot IOS-XE-ruter interface g2"
    switchport_mode: access
    switchport_allowed_vlan: 309
                                

På dette tidspunktet er vlan lagt til på trunk mellom core switchene og access porten mot IOS-XE ruterne.
Neste steg blir å aktivere interfacene på IOS-XE ruterne og konfigurere OSPF

playbook_l3_interfaces_aggregate.yaml
---
- name: L3 interface konfigurasjon
  hosts: rutere
  gather_facts: no
  vars_files: vars/l3_interfaces_aggregate.yaml
  
  tasks:
    -  name: l3 interfaces aggregate
       ios_l3_interfaces:   
         config: "{{ l3_interfaces[inventory_hostname] }}"
    
    - name: Enable interface
      cisco.ios.ios_interfaces:
        config:
          - name: "{{ item.name }}"
            enabled: true
        state: replaced
      loop: "{{ l3_interfaces[inventory_hostname] }}"
                                     

For å konfigurere OSPF så kan vi bruke ios_ospf, ios_config modulen eller jinja2 templates. .
Det eneste formålet i denne laben er å aktivere OSPF og få naboskapet mellom ruterne til å fungere
Så det blir en veldig forenklet versjon av OSPF konfigurasjonen.
Jeg oppretter en jinja2 template for OSPF konfigurasjonen, med minimum konfigurasjon.
templates/ospf.j2
router ospf 1
 network 10.190.0.0 0.0.0.15 area 0
                                         

Playbooken for å aktivere OSPF
---
- name: L3 interface konfigurasjon
  hosts: IOS_XE_rutere
  gather_facts: no
  
  
  tasks:
  -  name: OSPF
     ios_config:
       src: templates/ospf.j2
                                          

Vi sjekker at OSPF er aktivert ved å bruke add hoc ios_command modulen.
ansible -m ios_command -a "commands='show ip ospf neighbor'" IOS_XE_rutere -k
SSH password: 
IOS_XE_ruter_2 | SUCCESS => {
    "changed": false,
    "stdout": [
        "Neighbor ID     Pri   State           Dead Time   Address         Interface
10.170.0.253      1   FULL/DR         00:00:30    10.190.0.2      GigabitEthernet2"
    ],
    "stdout_lines": [
        [
            "Neighbor ID     Pri   State           Dead Time   Address         Interface",
            "10.170.0.253      1   FULL/DR         00:00:30    10.190.0.2      GigabitEthernet2"
        ]
    ]
}
IOS_XE_ruter_3 | SUCCESS => {
    "changed": false,
    "stdout": [
        "Neighbor ID     Pri   State           Dead Time   Address         Interface
10.170.0.252      1   FULL/BDR        00:00:36    10.190.0.1      GigabitEthernet2"
    ],
    "stdout_lines": [
        [
            "Neighbor ID     Pri   State           Dead Time   Address         Interface",
            "10.170.0.252      1   FULL/BDR        00:00:36    10.190.0.1      GigabitEthernet2"
        ]
    ]
}
                                                 

IPv6 er ikke aktivert, så jeg bruker ios_ospfv2 modulen
Legg til tasken i playbooken
  - name: OSPFV2 modul konfigurasjon
    cisco.ios.ios_ospfv2:
      config:
        processes:
          - process_id: 2
            network:
              - address: "10.170.0.0"
                wildcard_bits: "0.0.0.255"
                area: 0                                                
                                                      

Vi sjekker at OSPF er aktivert ved å bruke add hoc ios_command modulen.
ansible -m ios_command -a "commands='show ip ospf neighbor'" IOS_XE_rutere -k
SSH password: 
IOS_XE_ruter_2 | SUCCESS => {
    "changed": false,
    "stdout": [
        "Neighbor ID     Pri   State           Dead Time   Address         Interface
10.190.1.2        1   FULL/DR         00:00:38    10.170.0.253    GigabitEthernet1
10.170.0.253      1   FULL/DR         00:00:35    10.190.0.2      GigabitEthernet2"
    ],
    "stdout_lines": [
        [
            "Neighbor ID     Pri   State           Dead Time   Address         Interface",
            "10.190.1.2        1   FULL/DR         00:00:38    10.170.0.253    GigabitEthernet1",
            "10.170.0.253      1   FULL/DR         00:00:35    10.190.0.2      GigabitEthernet2"
        ]
    ]
}
IOS_XE_ruter_3 | SUCCESS => {
    "changed": false,
    "stdout": [
        "Neighbor ID     Pri   State           Dead Time   Address         Interface
10.190.1.1        1   FULL/BDR        00:00:38    10.170.0.252    GigabitEthernet1
10.170.0.252      1   FULL/BDR        00:00:38    10.190.0.1      GigabitEthernet2"
    ],
    "stdout_lines": [
        [
            "Neighbor ID     Pri   State           Dead Time   Address         Interface",
            "10.190.1.1        1   FULL/BDR        00:00:38    10.170.0.252    GigabitEthernet1",
            "10.170.0.252      1   FULL/BDR        00:00:38    10.190.0.1      GigabitEthernet2"
        ]
    ]
}
                                                        

Siste del er å få på plass BGP konfig
Jeg oppretter en jinja2 template for iBGP konfigurasjonen, med minimum konfigurasjon.
templates/ibgp.j2
router bgp {{ bgp_data[inventory_hostname]['as'] }}
{% for net in bgp_data[inventory_hostname]['networks'] %}
  network {{ net['address'] }} mask {{ net['netmask'] }}
{% endfor %}
{% for nei in bgp_data[inventory_hostname]['neighbors'] %}
  neighbor {{ nei['address'] }} remote-as {{ nei['remote_as'] }}
{% endfor %}
                                                     

Jeg legger til variablene i vars/ibgp.yaml
bgp_data:
  IOS_XE_ruter_2:
    as: 65500
    networks:
        - { address: 10.190.2.0, netmask: 255.255.255.0 }
        - { address: 10.190.3.0, netmask: 255.255.255.0 }
    neighbors:
        - { address: 10.190.1.2, remote_as: 65500 }
  IOS_XE_ruter_3:
    as: 65500
    networks:
        - { address: 10.190.2.0, netmask: 255.255.255.0 }
        - { address: 10.190.3.0, netmask: 255.255.255.0 }
    neighbors:
        - { address: 10.190.1.1, remote_as: 65500 }
                                                          

Playbooken for å aktivere iBGP
                                            

---
- name: iBGP
  hosts: IOS_XE_rutere
  gather_facts: no
  vars_files: vars/ibgp.yaml

  tasks:
  -  name: iBGP
     ios_config:
       src: templates/ibgp.j2
                                                             

Resultatet når vi kjører playbooken:
ansible-playbook playbook_ibgp.yaml -k 
SSH password: 

PLAY [iBGP] *****************************************************************************************************************************************************************************

TASK [iBGP] *****************************************************************************************************************************************************************************
changed: [IOS_XE_ruter_3]
changed: [IOS_XE_ruter_2]

PLAY RECAP ******************************************************************************************************************************************************************************
IOS_XE_ruter_2             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_XE_ruter_3             : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
                                                                  

Vi sjekker at BGP er aktivert ved å bruke add hoc ios_command modulen.
ansible -m ios_command -a "commands='show ip bgp summary'" IOS_XE_rutere -k
SSH password: 
IOS_XE_ruter_3 | SUCCESS => {
    "changed": false,
    "stdout": [
        "BGP router identifier 10.170.0.253, local AS number 65500
BGP table version is 1, main routing table version 1

Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
10.190.1.1      4        65500       7       7        1    0    0 00:03:32        0"
    ],
    "stdout_lines": [
        [
            "BGP router identifier 10.170.0.253, local AS number 65500",
            "BGP table version is 1, main routing table version 1",
            "",
            "Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd",
            "10.190.1.1      4        65500       7       7        1    0    0 00:03:32        0"
        ]
    ]
}
IOS_XE_ruter_2 | SUCCESS => {
    "changed": false,
    "stdout": [
        "BGP router identifier 10.170.0.252, local AS number 65500
BGP table version is 1, main routing table version 1

Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
10.190.1.2      4        65500       7       7        1    0    0 00:03:32        0"
    ],
    "stdout_lines": [
        [
            "BGP router identifier 10.170.0.252, local AS number 65500",
            "BGP table version is 1, main routing table version 1",
            "",
            "Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd",
            "10.190.1.2      4        65500       7       7        1    0    0 00:03:32        0"
                                                                        
        ]
    ]
}