Site icon Karneliuk

Ansible (part 2): parametrization for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR

Hello my friend,

In this article I’ll finalize the review of the Ansible for automation network tasks, which I’ve started the last week in the previous article. The main focus is the per-node parametrization of the playbooks, so that you can really successfully use Ansible for massive roll outs in networks, built with Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR.

1
2
3
4
5
No part of this blogpost could be reproduced, stored in a
retrieval system, or transmitted in any form or by any
means, electronic, mechanical or photocopying, recording,
or otherwise, for commercial purposes without the
prior permission of the author.

Brief overview

The last week I was discussing Ansible in general and playbooks from my previous article with my colleague from customer’s service provider. He has made reasonable remark that my automation works but it’s necessary to change IPv4/IPv6 address at the interface afterwards. This fact eliminates the positive effect from the rollout.

I’ve bought wonderful book Ansible for DevOps and found a lot of interesting and useful information, which has helped me to add parametrization depending on particular node and turn usage of Ansible for network tasks from fancy toy to real helper in roll outs. So I want to share with you this information alongside with real playbooks that you can reuse.

What are we going to test?

We are continue deploying BGP/MPLS IP VPNs, so I’m going to solve the same task as in the first article about Ansible. My task is to create such Anisble’s playbook that will automatically create VPRN/VRF and all related parameters, just like it was previously. But newly configured interfaces must have different IPv4 and IPv6 addresses at different nodes. So main focus is to achieve such agility keeping playbook simple.

Topology

Physical topology is the same as it was in previous article:

Logical topology is also the same:

Management in our lab is also the same, as it was in the previous lab:

For explanation about lab topology and used protocols refer to the previous article about Ansible for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR.

Here you can find initial configuration files: xr3_initial xr4_initial linux_initial sr1_bof sr1_initial sr2_bof sr2_initial

Resolving node names

In the previous article we have created an inventory file that is used for gathering nodes, where playbooks or ad-hoc commands must be performed. The entries were IPv4 addresses. It’s possible, but in general not very convenient. In production environment you have an established DNS system, so you can just put in hosts names of your devise. I don’t have DNS server configured, so I’ll update system hosts file in order to map names to IP addresses.

[root@localhost /]# cat /etc/hosts
127.0.0.1       localhost localhost.localdomain localhost4 localhost4.localdomain4
::1             localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.1.101   SR1
192.168.1.102   SR2
192.168.1.111   XR3
192.168.1.112   XR4
!
!
[root@localhost /]# cat /etc/ansible/hosts
[nokia]
SR1
SR2
!
[cisco]
XR3
XR4

The next step is to generate new SSH keys for these nodes, otherwise Ansible won’t able to connect to the devices. Just connect to them before playing playbooks:

[root@localhost ~]# ssh admin@SR1
RSA key fingerprint is 94:47:a9:b3:66:94:91:19:a6:12:a1:57:57:cd:fd:ef.
Are you sure you want to continue connecting (yes/no)? yes

It isn’t necessary, but it will make things more clear later.

BGP/MPLS IP VPN Service topology

At the picture above you see how the service that we are going to build looks like:

We follow the same guidelines for IP VPN service as in the previous lab. IP VPN supports both IPv4 and IPv6 address families; route-distinguisher is configured as IPv4_address_system_interface:100 and route-target is 65000:100. In each VRF/VPRN we have an interface with the same VLAN tag that is 444 and the same access-list that allows access only to certain subnet (IPv4: 192.168.0.0/24, IPv6: fc00::192:168:0:0/96) for attached nodes. But it must be possible to change all of these parameters (and some others) globally or per node easily without modifying playbook, so that by playing one book each node receives its specific values.

Short summary of Ansible’s variables

You remember that Ansible uses YAML as scripting language for its playbook. I’m pretty sure that each scripting language has possibility to define variables and to use them afterwards, and YAML isn’t something different. You may remember, we had the following code in the previous article:

[root@localhost ~]# cat new_nokia_new_service.yml
.   vars:
.     cli:
.       host: “{{ inventory_hostname }}”
.       username: admin
.       password: admin
.       transport: cli

There are dots in the beginning just to make structure visible. Omit them for the configuration.

Actually string “{{ inventory_hostname }}” is call of the variable, which has hostname of the node as it is in the inventory file. It’s a kind of built in variables, so we don’t define beforehand ourselves. But we’ve done it for one other variable, which is called “cli”:

[root@localhost ~]# cat new_nokia_new_service.yml | grep “cli”
.         provider: “{{ cli }}”

You might find such string in the previous playbooks. It’s actually call of variable “cli”, which was defined in the part “vars” in the beginning.

Another good information, which is crucial for us, is that we can keep variables in separate external files that are written in the same YAML format. These files are just mentioned in the beginning of the playbook. What is even better, the name of the file can be also variable, what allows us to call necessary variables depending on the node, which playbook is applied to.

Ok, basic theory regarding variables in YAML/Ansible is known to you, let’s use for building awesome playbooks.

Creating per node and per service configuration files

First of all let’s create files, where will be collected per node parameters, which must be applied during playbook execution. For the sake of convenience, I put them into separate folder in the folder, where the playbook lays:

[root@localhost ansible_test_scripts]# pwd
/home/aaa/ansible_test_scripts
[root@localhost ansible_test_scripts]# mkdir nodes
[root@localhost ansible_test_scripts]# cd nodes
[root@localhost nodes]# touch SR1.yml
[root@localhost nodes]# touch SR2.yml
[root@localhost nodes]# touch XR3.yml
[root@localhost nodes]# touch XR4.yml

Pay attention to the file names. They must have exactly the same name as nodes in the /etc/ansible/hosts.

After the files are created, we can put there whatever we want. For my task I’ve put there the following information:

[root@localhost nodes]# cat SR1.yml
.—
.node_var:
.  rd_base: 10.0.255.11
.  interface_name: toCUST
.  interface_port: 1/1/2
.  interface_mtu: 1518
.  interface_ipv4: 192.168.1.1/24
.  interface_ipv6: fc00::192:168:1:1/112
.  acl_ipv4_no: 10
.  acl_ipv6_no: 10
….
[root@localhost nodes]# cat SR2.yml
.—
.node_var:
.  rd_base: 10.0.255.22
.  interface_name: toCUST
.  interface_port: 1/1/2
.  interface_mtu: 1518
.  interface_ipv4: 192.168.2.1/24
.  interface_ipv6: fc00::192:168:2:1/112
.  acl_ipv4_no: 10
.  acl_ipv6_no: 10
….
[root@localhost nodes]# cat XR3.yml
.—
.node_var:
.  rd_base: 10.0.255.33
.  interface_port: GigabitEthernet0/0/0/0
.  interface_name: toCUST
.  interface_ipv4: 192.168.3.1/24
.  interface_ipv6: fc00::192:168:3:1/112
….
[root@localhost nodes]# cat XR4.yml
.—
.node_var:
.  rd_base: 10.0.255.44
.  interface_port: GigabitEthernet0/0/0/0
.  interface_name: toCUST
.  interface_ipv4: 192.168.4.1/24
.  interface_ipv6: fc00::192:168:4:1/112
….

Later in the playbook I’ll be calling this parameters in the form “{{ node_var.rd_base }}” for example. It’s possible to remove that “node_var:” string and simply call “{{ rd_base }}”, but as I have a couple of external configuration files, it’s easier for me to understand reading the playbook, which file contains certain variable. Also you might spot that some parameters are different for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR, because in this certain case we need less parameters for Cisco IOS XR’s configuration.

The next folder that I want to create will contain connectivity information. As Nokia and Cisco has different credentials, I’m going to configure them:

[root@localhost nodes]# cd ..
[root@localhost ansible_test_scripts]# mkdir login
[root@localhost ansible_test_scripts]# cd login/
[root@localhost login]# touch cisco_credentials.yml
[root@localhost login]# touch nokia_credentials.yml

In these files I put information, what was previously contained in “vars” in the previous article:

[root@localhost login]# cat nokia_credentials.yml
.—
.cli:
.  host: “{{ inventory_hostname }}”
.  username: admin
.  password: admin
.  transport: cli
….
.[root@localhost login]# cat cisco_credentials.yml
.—
.cli:
.  host: “{{ inventory_hostname }}”
.  username: cisco
.  password: cisco
.  transport: cli
….

And the third folder and file that I’m going to create contains the variables, which are common for the whole service:

[root@localhost login]# cd ..
[root@localhost ansible_test_scripts]# mkdir services
[root@localhost ansible_test_scripts]# cd services/
[root@localhost services]# touch ip_vpn_vars.yml
[root@localhost services]# cat ip_vpn_vars.yml
.—
.service_var:
. as_number: 65000
. service_id: 100
. dot1q_vlan: 444
. client_id: 100500
. client_name: ACME
. client_contact: info@acme.com
. ipv4_allowed: 192.168.0.0/16
. ipv6_allowed: fc00::192:168:0:0/96
….

It might be questionable, where to put VLAN_ID for the service: here or in per-node files. It’s absolutely up to you. From my experience, usually the VLAN id for customer or for service is the same across all routers in the network, just because it’s simple. On the other hand, PORT_IDs might be different depending on the router model. That’s why in my approach I put VLAN_ID in service template, whereas PORT_ID in the node template.

Modifying Ansible playbooks

Now it’s time to change Ansible playbooks for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR in the way they start to use variables instead of fixed values:

Remember, playbooks lay in the root folder comparing to creates sub folders

Ansible playbook Ansible playbook
Nokia (Alcatel-Lucent) SR OS Cisco IOS XR

[root@localhost ansible_test_scripts]# cat nokia_ip_vpn.yml
.—
.- hosts: nokia
.  gather_facts: no
.  connection: local
.
.  vars_files:
.    – login/nokia_credentials.yml
.    – services/ip_vpn_vars.yml
.    – nodes/{{ inventory_hostname }}.yml
.
.  tasks:
.    – name: GLOBAL / prepare port
.      sros_config:
.        lines:
.          – ethernet mode access
.          – ethernet encap-type dot1q
.          – ethernet dot1q {{ node_var.interface_mtu }}
.          – no shutdown
.        parents:
.          – configure
.          – port {{ node_var.interface_port }}
.        provider: “{{ cli }}”
.
.    – name: GLOBAL / ACL / create IPv4
.        sros_config:
.          lines:
.            – description IPv4_{{ service_var.client_name }}_{{ service_var.client_id }}_in
.        parents:
.          – configure
.          – filter
.          – ip-filter {{ node_var.acl_ipv4_no }} create
.        provider: “{{ cli }}”
.
.    – name: GLOBAL / ACL / create IPv4 / rules
.      sros_config:
.        lines:
.          – match dst-ip {{ service_var.ipv4_allowed }}
.          – action forward
.        parents:
.          – configure
.          – filter
.          – ip-filter {{ node_var.acl_ipv4_no }}
.          – entry 10 create
.        provider: “{{ cli }}”
.
.    – name: GLOBAL / ACL / create IPv6
.      sros_config:
.        lines:
.          – description IPv6_{{ service_var.client_name }}_{{ service_var.client_id }}_in
.        parents:
.          – configure
.          – filter
.          – ipv6-filter {{ node_var.acl_ipv6_no }} create
.        provider: “{{ cli }}”
.
.    – name: GLOBAL / ACL / create IPv6 / rules
.      sros_config:
.        lines:
.          – match dst-ip {{ service_var.ipv6_allowed }}
.          – action forward
.        parents:
.          – configure
.          – filter
.          – ipv6-filter {{ node_var.acl_ipv6_no }}
.          – entry 10 create
.        provider: “{{ cli }}”
.
.    – name: SERVICE / create and configure customer
.      sros_config:
.        lines:
.          – description {{ service_var.client_name }}_{{ service_var.client_id }}
.          – contact {{ service_var.client_contact }}
.        parents:
.          – configure
.          – service
.          – customer {{ service_var.client_id }} create
.        provider: “{{ cli }}”
.
.    – name: SERVICE / VPRN / create and configure parameters
.      sros_config:
.        lines:
.          – route-distinguisher {{ node_var.rd_base }}:{{ service_var.service_id }}
.          – vrf-target target:{{ service_var.as_number }}:{{ service_var.service_id }}
.          – autonomus-system {{ service_var.as_number }}
.          – auto-bind-tunnel resolution any
.        parents:
.          – configure
.          – service
.          – vprn {{ service_var.client_id }} customer {{ service_var.client_id }} create
.        provider: “{{ cli }}”
.
.    – name: SERVICE / VPRN / create and configure interface
.      sros_config:
.        lines:
.          – address {{ node_var.interface_ipv4 }}
.          – ipv6 address {{ node_var.interface_ipv6 }}
.        parents:
.          – configure
.          – service
.          – vprn {{ service_var.client_id }}
.          – interface {{ node_var.interface_name }} create
.        provider: “{{ cli }}”
.
.    – name: SERVICE / VPRN / add SAP and ACL
.      sros_config:
.        lines:
.          – ingress filter ip {{ node_var.acl_ipv4_no }}
.          – ingress filter ipv6 {{ node_var.acl_ipv6_no }}
.        parents:
.          – configure
.          – service
.          – vprn {{ service_var.client_id }}
.          – interface {{ node_var.interface_name }}
.          – sap {{ node_var.interface_port }}:{{ service_var.dot1q_vlan }} create
.        provider: “{{ cli }}”
.
.    – name: SERVICE / VPRN / launch
.      sros_config:
.        lines:
.          – no shutdown
.        parents:
.          – configure
.          – service
.          – vprn {{ service_var.client_id }}
.        provider: “{{ cli }}”
.
.    – name: SAVE
.      sros_command:
.        commands:
.          – admin save
.        provider: “{{ cli }}”
….

[root@localhost ansible_test_scripts]# cat cisco_ip_vpn.yml
.—
.- hosts: cisco
.  gather_facts: no
.  connection: local
.
.  vars_files:
.    – login/cisco_credentials.yml
.    – services/ip_vpn_vars.yml
.    – nodes/{{ inventory_hostname }}.yml
.
.  tasks:
.    – name: VRF / create and configure IPv4
.      iosxr_config:
.        lines:
.          – import route-target {{ service_var.as_number }}:{{ service_var.service_id }}
.          – export route-target {{ service_var.as_number }}:{{ service_var.service_id }}
parents:
.          – vrf {{ service_var.client_name }}_{{ service_var.client_id }}
.          – address-family ipv4 unicast
.        provider: “{{ cli }}”
.
.    – name: VRF / create and configure IPv6
.      iosxr_config:
.        lines:
.          – import route-target {{ service_var.as_number }}:{{ service_var.service_id }}
.          – export route-target {{ service_var.as_number }}:{{ service_var.service_id }}
.        parents:
.          – vrf {{ service_var.client_name }}_{{ service_var.client_id }}
.          – address-family ipv6 unicast
.        provider: “{{ cli }}”
.
.    – name: GLOBAL / ACL / create IPv4
.      iosxr_config:
.        lines:
.          – 10 permit ipv4 any {{ service_var.ipv4_allowed }}
.        parents:
.          – ipv4 access-list ACL_IPv4_{{ service_var.client_name }}_{{ service_var.client_id }}
.        provider: “{{ cli }}”
.
.    – name: GLOBAL / ACL / create IPv6
.      iosxr_config:
.        lines:
.          – 10 permit ipv6 any {{ service_var.ipv6_allowed }}
.        parents:
.          – ipv6 access-list ACL_IPv6_{{ service_var.client_name }}_{{ service_var.client_id }}
.        provider: “{{ cli }}”
.
.    – name: VRF / interface / create and configure
.      iosxr_config:
.        lines:
.          – vrf {{ service_var.client_name }}_{{ service_var.client_id }}
.          – description {{ node_var.interface_name }}_{{ service_var.client_id }}
.          – encapsulation dot1q {{ service_var.dot1q_vlan }}
.          – ipv4 address {{ node_var.interface_ipv4 }}
.          – ipv6 address {{ node_var.interface_ipv6 }}
.          – ipv4 access-group ACL_IPv4_{{ service_var.client_name }}_{{ service_var.client_id }} in
.          – ipv6 access-group ACL_IPv6_{{ service_var.client_name }}_{{ service_var.client_id }} in
.          – logging event link-status
.        parents:
.          – interface {{ node_var.interface_port }}.{{ service_var.dot1q_vlan }}
.        provider: “{{ cli }}”
.
.    – name: BGP / VRF / create and configure RD
.      iosxr_config:
.        lines:
.          – rd {{ node_var.rd_base }}:{{ service_var.service_id }}
.        parents:
.          – router bgp {{ service_var.as_number }}
.          – vrf {{ service_var.client_name }}_{{ service_var.client_id }}
.        provider: “{{ cli }}”
.
.    – name: BGP / VRF / create and configure IPv4 UNI AF
.      iosxr_config:
.        lines:
.          – redistribute connected
.        parents:
.          – router bgp {{ service_var.as_number }}
.          – vrf {{ service_var.client_name }}_{{ service_var.client_id }}
.          – address-family ipv4 unicast
.        provider: “{{ cli }}”
.
.    – name: BGP / VRF / create and configure IPv6 UNI AF
.      iosxr_config:
.        lines:
.          – redistribute connected
.        parents:
.          – router bgp {{ service_var.as_number }}
.          – vrf {{ service_var.client_name }}_{{ service_var.client_id }}
.          – address-family ipv6 unicast
.        provider: “{{ cli }}”
….

Spaces before words is absolutely important for YAML. Make sure they are consistent like in my example. Remove “.” In the beginning of each string and you copy-paste this config.

These playbooks do just the same, what they have done previously: they create IP VPN service across network devices either Nokia (Alcatel-Lucent) SR OS based or Cisco IOS XR based.

For information about BGP/MPLS IP VPN refer to corresponding article.

You may see that here we don’t have any single parameter that is defined in these playbooks. All parameters are called from external files, whereas these files are defined in the beginning of the playbook within “vars_files” part. Of particular interest is how we call per node files. You see that they are called as “nodes/{{ inventory_hostname }}.yml”. This works as follows:

Let’s execute the playbook for Nokia (Alcatel-Lucent) SR OS routers and see what is going on:

[root@localhost ansible_test_scripts]# ansible-playbook nokia_ip_vpn.yml
!
PLAY [nokia] ************************************************************
!
TASK [GLOBAL / prepare port] ********************************************
changed: [SR2]
changed: [SR1]
!
TASK [GLOBAL / ACL / create IPv4] ***************************************
changed: [SR2]
changed: [SR1]
!
TASK [GLOBAL / ACL / create IPv4 / rules] *******************************
changed: [SR2]
changed: [SR1]
!
TASK [GLOBAL / ACL / create IPv6] ***************************************
changed: [SR2]
changed: [SR1]
!
TASK [GLOBAL / ACL / create IPv6 / rules] *******************************
changed: [SR1]
changed: [SR2]
!
TASK [SERVICE / create and configure customer] **************************
changed: [SR2]
changed: [SR1]
!
TASK [SERVICE / VPRN / create and configure parameters] *****************
changed: [SR2]
changed: [SR1]
!
TASK [SERVICE / VPRN / create and configure interface] ******************
changed: [SR2]
changed: [SR1]
!
TASK [SERVICE / VPRN / add SAP and ACL] *********************************
changed: [SR2]
changed: [SR1]
!
TASK [SERVICE / VPRN / launch] ******************************************
changed: [SR1]
changed: [SR2]
!
TASK [SAVE] *************************************************************
ok: [SR2]
ok: [SR1]
!
PLAY RECAP **************************************************************
SR1 : ok=11 changed=10 unreachable=0 failed=0
SR2 : ok=11 changed=10 unreachable=0 failed=0

It looks like everything is configured properly. Let’s briefly compare created configuration for VPRN part:

Ansible playbook Ansible playbook
Nokia (Alcatel-Lucent) SR OS – SR1 Nokia (Alcatel-Lucent) SR OS – SR2

A:SR1# configure service vprn 100500
A:SR1>config>service>vprn# info
————————-
route-distinguisher 10.0.255.11:100
auto-bind-tunnel
resolution any
exit
vrf-target target:65000:100
interface “toCUST” create
address 192.168.1.1/24
ipv6
address fc00::192:168:1:1/112
exit
sap 1/1/2:444 create
ingress
filter ip 10
filter ipv6 10
exit
exit
exit
no shutdown
————————-

A:SR2# configure service vprn 100500
A:SR2>config>service>vprn# info
————————-
route-distinguisher 10.0.255.22:100
auto-bind-tunnel
resolution any
exit
vrf-target target:65000:100
interface “toCUST” create
address 192.168.2.1/24
ipv6
address fc00::192:168:2:1/112
exit
sap 1/1/2:444 create
ingress
filter ip 10
filter ipv6 10
exit
exit
exit
no shutdown
————————-

It’s very impressive, isn’t it? We have just launched playbook once, and each Nokia (Alcatel-Lucent) VSR router has got configuration modified with its specific parameters. Basically we need to prepare playbook, node-specific and service-specific templates and launch our script. Rollout is done further automatically. Let’s briefly check the content of routing tables at Nokia (Alcatel-Lucent) SR OS routers and make ping verification:

A:SR1# show router 100500 route-table
============================================================================
Route Table (Service: 100500)
============================================================================
Dest Prefix[Flags]                         Type    Proto     Age       Pref
.      Next Hop[Interface Name]                                 Metric
—————————————————————————-
192.168.1.0/24                             Local   Local     01h22m58s 0
.      toCUST                                                   0
192.168.2.0/24                             Remote  BGP VPN   00h03m32s 170
.      10.0.255.22 (tunneled)                                   0
—————————————————————————-
No. of Routes: 2
============================================================================
!
!
A:SR1# ping router 100500 192.168.2.1
PING 192.168.2.1 56 data bytes
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=9.07ms.
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=3.75ms.
^C
ping aborted by user
—- 192.168.2.1 PING Statistics —-
2 packets transmitted, 2 packets received, 0.00% packet loss
round-trip min = 3.75ms, avg = 6.41ms, max = 9.07ms, stddev = 0.000ms

You don’t see any routes from Cisco IOS XR routers, because we haven’t executed that playbook and because I’m launching separately Nokia and Cisco routers due to limited resources at my laptop.

Let’s turn to Cisco IOS XR now. As playbook and all configuration templates are ready, I just have to execute it:

[root@localhost ansible_test_scripts]# ansible-playbook cisco_ip_vpn.yml
!
PLAY [cisco] ************************************************************
!
TASK [VRF / create and configure IPv4] **********************************
changed: [XR3]
changed: [XR4]
!
TASK [VRF / create and configure IPv6] **********************************
changed: [XR4]
changed: [XR3]
!
TASK [GLOBAL / ACL / create IPv4] ***************************************
changed: [XR3]
changed: [XR4]
!
TASK [GLOBAL / ACL / create IPv6] ***************************************
changed: [XR4]
changed: [XR3]
!
TASK [VRF / interface / create and configure] ***************************
changed: [XR3]
changed: [XR4]
!
TASK [BGP / VRF / create and configure RD] ******************************
changed: [XR4]
changed: [XR3]
!
TASK [BGP / VRF / create and configure IPv4 UNI AF] *********************
changed: [XR3]
changed: [XR4]
!
TASK [BGP / VRF / create and configure IPv6 UNI AF] *********************
changed: [XR3]
changed: [XR4]
!
PLAY RECAP *************************************************************************
XR3 : ok=8 changed=8 unreachable=0 failed=0
XR4 : ok=8 changed=8 unreachable=0 failed=0

This playbook has made the following changes at our Cisco IOS XR routers:

Ansible playbook Ansible playbook
Cisco IOS XR – XR3 Cisco IOS XR – XR4

RP/0/0/CPU0:XR3#show configuration commit changes last 8
!! IOS XR Configuration 5.3.2
vrf ACME_100500
address-family ipv4 unicast
import route-target
65000:100
!
export route-target
65000:100
!
!
address-family ipv6 unicast
import route-target
65000:100
!
export route-target
65000:100
!
!
!
ipv6 access-list ACL_IPv6_ACME_100500
10 permit ipv6 any fc00::192:168:0:0/96
!
ipv4 access-list ACL_IPv4_ACME_100500
10 permit ipv4 any 192.168.0.0/16
!
interface GigabitEthernet0/0/0/0.444
description toCUST_100500
vrf ACME_100500
ipv4 address 192.168.3.1 255.255.255.0
ipv6 address fc00::192:168:3:1/112
encapsulation dot1q 444
logging events link-status
ipv4 access-group ACL_IPv4_ACME_100500 ingress
ipv6 access-group ACL_IPv6_ACME_100500 ingress
!
router bgp 65000
vrf ACME_100500
rd 10.0.255.33:100
address-family ipv4 unicast
redistribute connected
!
address-family ipv6 unicast
redistribute connected
!
!
!
end

RP/0/0/CPU0:XR4#show configuration commit changes last 8
!! IOS XR Configuration 5.3.2
vrf ACME_100500
address-family ipv4 unicast
import route-target
65000:100
!
export route-target
65000:100
!
!
address-family ipv6 unicast
import route-target
65000:100
!
export route-target
65000:100
!
!
!
ipv6 access-list ACL_IPv6_ACME_100500
10 permit ipv6 any fc00::192:168:0:0/96
!
ipv4 access-list ACL_IPv4_ACME_100500
10 permit ipv4 any 192.168.0.0/16
!
interface GigabitEthernet0/0/0/0.444
description toCUST_100500
vrf ACME_100500
ipv4 address 192.168.4.1 255.255.255.0
ipv6 address fc00::192:168:4:1/112
encapsulation dot1q 444
logging events link-status
ipv4 access-group ACL_IPv4_ACME_100500 ingress
ipv6 access-group ACL_IPv6_ACME_100500 ingress
!
router bgp 65000
vrf ACME_100500
rd 10.0.255.44:100
address-family ipv4 unicast
redistribute connected
!
address-family ipv6 unicast
redistribute connected
!
!
!
end

Our parametrization works quite well, so we make just the last check:

RP/0/0/CPU0:XR4#show route vrf ACME_100500 ipv6
B    fc00::192:168:3:0/112
.     [200/0] via ::ffff:10.0.255.33 (nexthop in vrf default), 00:02:52
C    fc00::192:168:4:0/112 is directly connected,
.     00:03:01, GigabitEthernet0/0/0/0.444
L    fc00::192:168:4:1/128 is directly connected,
.     00:03:01, GigabitEthernet0/0/0/0.444
!
!
RP/0/0/CPU0:XR4#ping vrf ACME_100500 fc00::192:168:3:1 source fc00::192:168:4:1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to fc00::192:168:3:1, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/8/19 ms

Ok, for Cisco IOS XR our playbook works as well.

I’ve collected all my Anisble’s files from this lab in one tar archive so that it will be easier for you to test it and update for your needs. This archive contains also playbooks from the previous Ansible lab: ansible_nokia_cisco

Lessons learned

By the way, I haven’t tested in the details the initial configs in the previous lab and have missed one thing in Cisco IOS XR configuration. This thing is IPv6 addresses at loopback 0. They aren’t used anywhere in configuration, but they must be configured in order to bring ipv6/vpnv6 peering (though technically we use IPv4 address for BGP session and MPLS LSPs). This issue exists only in Cisco IOS XR, because in Cisco IOS / IOS XE there is no such problem. When I started to test pings between XR3 and XR4 I’ve found that I can perform then. After discovering that BGP is dead, I’ve configured IPv6 addresses at loopbacks 0 and everything started working.

Conclusion

Ansible is great thing to reduce the time for massive deployments. Personally I’ve started using it for reconfiguration of the devices for labs. With the parameterization its power only increases, as it comes from fancy-scripting-toys into something really useful for commercial operations. You can focus on learning new technologies or designing new solutions for your Nokia (Alcatel-Lucent) SR OS or Cisco IOS XR networks. Take care and good bye!

Support us






BR,
Anton Karneliuk

Exit mobile version