Hello my friend,
For long time I’ve been preparing to write this article and finally you are reading it. The topic is really hot as everything, which is named “open” today, becomes automatically fancy and widely discussed. What we will do today, we’ll explore the OpenConfig capabilities on Arista EOS, Cisco IOS XR and Nokia (Alcatel-Lucent) SR OS and will try to understand how much OpenConfig is really open.
1 2 3 4 5 | No part of this blogpost could be reproduced, stored in a<br> retrieval system, or transmitted in any form or by any<br> means, electronic, mechanical or photocopying, recording,<br> or otherwise, for commercial purposes without the<br> prior permission of the author.<br> |
Disclaimer
All the information is provided on “as-is” basis with the status of OpenConfig YANG modules in particular versions of Nokia VSR, Arista vEOS and Cisco IOS XRv. Different version might have different versions of OpenCofngi models and therefore structure of YANG model can be changed.
Brief description
The first time I we heard about OpenConfig project was not too long ago. Actually it was only on Cisco Live 2018. By that time, according to the website of OpenConfig, the project was roughly 3 years old. For me it’s good as it means that project has reached minimum level of maturity, so I’m able to create some scenarios using it. Or at least I hope so, as by the time I’ve started writing it, I haven’t implemented everything I am going to do.
So, what is OpenConfig? The official website gives us the following answer:
“OpenConfig is an informal working group of network operators sharing the goal of moving our networks toward a more dynamic, programmable infrastructure by adopting software-defined networking principles such as declarative configuration and model-driven management and operations; Our initial focus in OpenConfig is on compiling a consistent set of vendor-neutral data models (written in YANG) based on actual operational needs from use cases and requirements from multiple network operators”
Basically, It’s YANG data model, which should be the same across all vendors. Sounds really “open”. Some time ago, when we were reviewing NETCONF/YANG for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR, we explained that each and every vendor has its own YANG data model, what means that the automation tool, like Ansible, has to have per-vendor drivers, what is definitely requires a lot of developers’ efforts.
Just imagine, that you need to deploy automation only once, as all the vendors understand it in the same way.
That’s the goal of the OpenConfig initiative. Let’s take a look on the status of the OpenConfig YANG model now:
As you see, the current focus of the OpenConfig model lays on standard parameters in the configuration of the network devices: interfaces, ACLs, routing protocols and etc. Actually, most of the configuration regardless of the vendor is done across these parameters. Sure, deep tuning of the performance requires much more, but how often do we need such deep tuning? So. In my eyes, OpenConfig if implemented will ease the live of the network developers and operators a lot.
What we are going to test?
Initially I started writing the article about interfaces and BGP using OpenConfig, but it turned to be very long. That’s why this article is the first in the series about OpenConfig and is focused only on interfaces.
We will try make the following things in our article for 3 OSes (Arista EOS, Cisco IOS XR and Nokia SR OS):
- Get the configuration done in OpenConfig YANG model for interfaces
- Edit the desired configuration on OpenConfig YANG model for interfaces
- Create proper Ansible playbook for configuration of interfaces
The main reason, why I’m reading the configuration from the network device is that I learned that different virtual routers supports different versions of OpenConfig, hence there are some deviations in place in terms of syntax, so I need first of all to understand exact syntax of particular device.
Software version
The following infrastructure is used in my lab:
- CentOS 7 with python 2.7.
- Ansible 2.6.0 [NEW!]
- Arista EOS 4.20.5F [NEW!]
- Nokia SR OS 16.0.R1
- Cisco IOS XR 6.1.2
See the previous article to get details how to build the lab
Just some weeks ago the new version of Ansible, which is 2.6.0 at the time of writing, was released. So I’m using it as there are some new modules for NETCONF, which might be useful for such automation.
Topology
The physical topology doesn’t vary from the something we have used previously, so it’s important that all our VNFs are somehow connected to management host:
We’ll use well known topology for data center fabric with 2 spines and 2 leafs with all vendors (Nokia VSR, Arista vEOS and Cisco XRv):
The initial configuration files just enable management access over SSH to devices over management interface: 128_config_initial_SR1 128_config_initial_vEOS2 128_config_initial_XR3 128_config_initial_XR4 128_config_initial_linux
How to read YANG model?
Let’s start with some recap about YANG data models. Some time ago, when we reviewed NETCONF/YANG for Cisco IOS XR, I have shared some information how to understand YANG structure. Here I’ll show more convenient way.
First of all, we need to download data models locally from GitHub repo of OpenConfig. Put it anywhere you like, just remember the exact path. I’ve put it into new folder:
1 2 3 4 | $ pwd<br> /home/aaa/Yang/openconfig<br> $ ls<br> public |
Then I advise to install “pyang” tool, which is very easy and convenient to read YANG data:
1 | $ sudo pip install pyang<br> |
After that is done, we can review any YANG data we have. To do that I issue the following command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | .$ pyang -f tree -p ~/Yang/openconfig/public/release/models/ ~/Yang/openconfig/public/release/models/interfaces/openconfig-interfaces.yang<br> module: openconfig-interfaces<br> +--rw interfaces<br> +--rw interface* [name]<br> +--rw name -> ../config/name<br> +--rw config<br> | +--rw name? string<br> | +--rw type identityref<br> | +--rw mtu? uint16<br> | +--rw loopback-mode? boolean<br> | +--rw description? string<br> | +--rw enabled? boolean<br> +--ro state<br> | +--ro name? string<br> | +--ro type identityref<br> | +--ro mtu? uint16<br> | +--ro loopback-mode? boolean<br> | +--ro description? string<br> | +--ro enabled? boolean<br> | +--ro ifindex? uint32<br> | +--ro admin-status enumeration<br> | +--ro oper-status enumeration<br> | +--ro last-change? oc-types:timeticks64<br> | +--ro counters<br> | +--ro in-octets? oc-yang:counter64<br> | +--ro in-unicast-pkts? oc-yang:counter64<br> | +--ro in-broadcast-pkts? oc-yang:counter64<br> | +--ro in-multicast-pkts? oc-yang:counter64<br> | +--ro in-discards? oc-yang:counter64<br> | +--ro in-errors? oc-yang:counter64<br> | +--ro in-unknown-protos? oc-yang:counter64<br> | +--ro in-fcs-errors? oc-yang:counter64<br> | +--ro out-octets? oc-yang:counter64<br> | +--ro out-unicast-pkts? oc-yang:counter64<br> | +--ro out-broadcast-pkts? oc-yang:counter64<br> | +--ro out-multicast-pkts? oc-yang:counter64<br> | +--ro out-discards? oc-yang:counter64<br> | +--ro out-errors? oc-yang:counter64<br> | +--ro carrier-transitions? oc-yang:counter64<br> | +--ro last-clear? oc-types:timeticks64<br> +--rw hold-time<br> | +--rw config<br> | | +--rw up? uint32<br> | | +--rw down? uint32<br> | +--ro state<br> | +--ro up? uint32<br> | +--ro down? uint32<br> +--rw subinterfaces<br> +--rw subinterface* [index]<br> +--rw index -> ../config/index<br> +--rw config<br> | +--rw index? uint32<br> | +--rw description? string<br> | +--rw enabled? boolean<br> +--ro state<br> +--ro index? uint32<br> +--ro description? string<br> +--ro enabled? boolean<br> +--ro name? string<br> +--ro ifindex? uint32<br> +--ro admin-status enumeration<br> +--ro oper-status enumeration<br> +--ro last-change? oc-types:timeticks64<br> +--ro counters<br> +--ro in-octets? oc-yang:counter64<br> +--ro in-unicast-pkts? oc-yang:counter64<br> +--ro in-broadcast-pkts? oc-yang:counter64<br> +--ro in-multicast-pkts? oc-yang:counter64<br> +--ro in-discards? oc-yang:counter64<br> +--ro in-errors? oc-yang:counter64<br> +--ro in-unknown-protos? oc-yang:counter64<br> +--ro in-fcs-errors? oc-yang:counter64<br> +--ro out-octets? oc-yang:counter64<br> +--ro out-unicast-pkts? oc-yang:counter64<br> +--ro out-broadcast-pkts? oc-yang:counter64<br> +--ro out-multicast-pkts? oc-yang:counter64<br> +--ro out-discards? oc-yang:counter64<br> +--ro out-errors? oc-yang:counter64<br> +--ro carrier-transitions? oc-yang:counter64<br> +--ro last-clear? oc-types:timeticks64<br> |
You can see many examples on “-f tree” in Internet, what helps to build that tree of YANG model. But there are only few examples on “-p xxx”, which used to set the path to look for dependencies in other modules. If you don’t configure path, you might see the following error:
1 2 3 4 | $ pyang -f tree ~/Yang/openconfig/public/release/models/interfaces/openconfig-interfaces.yang<br> /home/aaa/Yang/openconfig/public/release/models/interfaces/openconfig-interfaces.yang:12: error: module "openconfig-yang-types" not found in search path<br> /home/aaa/Yang/openconfig/public/release/models/interfaces/openconfig-interfaces.yang:13: error: module "openconfig-types" not found in search path<br> /home/aaa/Yang/openconfig/public/release/models/interfaces/openconfig-interfaces.yang:14: error: module "openconfig-extensions" not found in search path<br> |
After we have understood, how to treat the OpenConfig YANG data models, we can go further.
Which transport to use?
OpenConfig isn’t bounded to any particular transport mechanism according to the official website. So it can be used over:
- NETCONF
- RESTCONF
- gNMI (gRPC Network Management Interface)
In this article we will use NETCONF, as several time previously, so that we have consistent view on network management techniques.
OpenConfig and Cisco IOS XR
I will start with OpenConfig explanation with Cisco IOS XR. The reason why I’m doing it in this way is that Cisco IOS XR has some examples and demos in the Internet, which I used to get to know OpenConfig. So, for me it was essentially to start with something familiar.
#1. Cisco IOS XR. Enabling OpenConfig
There is no specific configuration for OpenConfig on Cisco IOS XR comparing to ordinary NETCONF, so we just enable NETCONF as usual:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | RP/0/0/CPU0:XR4(config)#show conf<br> Building configuration...<br> !! IOS XR Configuration 6.1.2<br> !<br> control-plane<br> management-plane<br> inband<br> interface GigabitEthernet0/0/0/0.999<br> allow NETCONF peer<br> address ipv4 192.168.0.0/16<br> !<br> !<br> !<br> !<br> !<br> netconf agent tty<br> !<br> netconf-yang agent<br> ssh<br> !<br> ssh server netconf vrf MGMT<br> !<br> end<br> |
When this configuration is done, let’s test, what we see in NETCONF call flow:
1 2 3 4 5 6 | $ ssh cisco@XR4 -p 830 -s netconf<br> The authenticity of host '[xr4]:830 ([192.168.1.112]:830)' can't be established.<br> RSA key fingerprint is SHA256:wC3Fs9LYR5erMxBxI7F98JIIycXm6EW767POJnpYh9E.<br> RSA key fingerprint is MD5:e7:16:b8:7a:5a:44:25:f9:7d:b6:93:86:ee:04:97:bb.<br> Are you sure you want to continue connecting (yes/no)? yes<br> Warning: Permanently added '[xr4]:830,[192.168.1.112]:830' (RSA) to the list of known hosts. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | IMPORTANT: READ CAREFULLY<br> Welcome to the Demo Version of Cisco IOS XRv (the "Software").<br> The Software is subject to and governed by the terms and conditions<br> of the End User License Agreement and the Supplemental End User<br> License Agreement accompanying the product, made available at the<br> time of your order, or posted on the Cisco website at<br> www.cisco.com/go/terms (collectively, the "Agreement").<br> As set forth more fully in the Agreement, use of the Software is<br> strictly limited to internal use in a non-production environment<br> solely for demonstration and evaluation purposes. Downloading,<br> installing, or using the Software constitutes acceptance of the<br> Agreement, and you are binding yourself and the business entity<br> that you represent to the Agreement. If you do not agree to all<br> of the terms of the Agreement, then Cisco is unwilling to license<br> the Software to you and (a) you may not download, install or use the<br> Software, and (b) you may return the Software as more fully set forth<br> in the Agreement. |
1 | <code lang="xml"> |
Please login with any configured user/password, or cisco/cisco
1 | <br> |
1 |
1 | cisco@xr4's password: |
1 | <code lang="xml"> |
urn:ietf:params:netconf:base:1.1
urn:ietf:params:netconf:capability:candidate:1.0
urn:ietf:params:netconf:capability:rollback-on-error:1.0
urn:ietf:params:netconf:capability:validate:1.1
urn:ietf:params:netconf:capability:confirmed-commit:1.1
http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-lib-cfg?module=Cisco-IOS-XR-aaa-lib-cfg&revision=2015-11-09
!
! Output ommited
!
http://openconfig.net/yang/bgp-multiprotocol?module=openconfig-bgp-multiprotocol&revision=2015-10-09
http://openconfig.net/yang/bgp-operational?module=openconfig-bgp-operational&revision=2015-10-09
http://openconfig.net/yang/bgp-policy?module=openconfig-bgp-policy&revision=2015-10-09&deviation=cisco-xr-bgp-policy-deviations
http://openconfig.net/yang/bgp-types?module=openconfig-bgp-types&revision=2015-05-15
http://openconfig.net/yang/bgp?module=openconfig-bgp&revision=2015-10-09&deviation=cisco-xr-bgp-deviations
http://openconfig.net/yang/openconfig-ext?module=openconfig-extensions&revision=2015-10-09
http://openconfig.net/yang/interface/aggregate?module=openconfig-if-aggregate&revision=2015-11-20&deviation=cisco-xr-openconfig-if-aggregate-deviations
http://openconfig.net/yang/interfaces/ethernet?module=openconfig-if-ethernet&revision=2015-11-20&deviation=cisco-xr-openconfig-if-ethernet-deviations
http://openconfig.net/yang/interfaces/ip?module=openconfig-if-ip&revision=2015-11-20&deviation=cisco-xr-openconfig-if-ip-deviations
http://openconfig.net/yang/interfaces?module=openconfig-interfaces&revision=2015-11-20&deviation=cisco-xr-openconfig-interfaces-deviations
http://openconfig.net/yang/ldp?module=openconfig-mpls-ldp&revision=2015-11-05
http://openconfig.net/yang/rsvp?module=openconfig-mpls-rsvp&revision=2015-11-05
http://openconfig.net/yang/sr?module=openconfig-mpls-sr&revision=2015-11-05
http://openconfig.net/yang/mpls-types?module=openconfig-mpls-types&revision=2015-11-05
http://openconfig.net/yang/mpls?module=openconfig-mpls&revision=2015-11-05&deviation=cisco-xr-openconfig-mpls-deviations
http://openconfig.net/yang/policy-types?module=openconfig-policy-types&revision=2015-10-09
http://openconfig.net/yang/routing-policy?module=openconfig-routing-policy&revision=2015-10-09&deviation=cisco-xr-routing-policy-deviations
http://openconfig.net/yang/telemetry?module=openconfig-telemetry&revision=2016-02-04&deviation=cisco-xr-openconfig-telemetry-deviations
http://openconfig.net/yang/openconfig-types?module=openconfig-types&revision=2015-10-09
http://openconfig.net/yang/vlan?module=openconfig-vlan&revision=2015-10-09&deviation=cisco-xr-openconfig-vlan-deviations
1 | <code lang="xml"> |
1743594516
1 | <br> |
1 | ]]>]]><br> |
I’ve reduced the output only to filter supported OpenConfig modules, so that I can find, which modules I should use in automation scripts using CLI or Ansible.
From this time, OpenConfig over NETCONF is ready to rock on Cisco IOS XR.
#2. Cisco IOS XR. Get the interface configuration using OpenConfig
Here we start with basic configuration on Cisco IOS XR to create one sub interface and loopback interface to get understanding on how would it look like on OpenConfig:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <br> RP/0/0/CPU0:XR4(config)#show conf<br> Building configuration...<br> !! IOS XR Configuration 6.1.2<br> interface Loopback0<br> ipv4 address 10.0.0.44 255.255.255.255<br> ipv6 address fc00::10:0:0:44/128<br> !<br> interface GigabitEthernet0/0/0/0<br> no shutdown<br> !<br> interface GigabitEthernet0/0/0/0.34<br> ipv4 address 10.33.44.44 255.255.255.0<br> ipv6 address fe80::44 link-local<br> ipv6 address fc00::10:33:44:44/112<br> encapsulation dot1q 34<br> !<br> end<br> |
After we have implemented this configuration, we briefly check, what do we have on Cisco IOS XR router XR4 configured:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <br> RP/0/0/CPU0:XR4#show ipv4 int br<br> Interface IP-Address Status Protocol Vrf-Name<br> Loopback0 10.0.0.44 Up Up default<br> MgmtEth0/0/CPU0/0 unassigned Shutdown Down default<br> GigabitEthernet0/0/0/0 unassigned Up Up default<br> GigabitEthernet0/0/0/0.34 10.33.44.44 Up Up default<br> GigabitEthernet0/0/0/0.999 192.168.1.112 Up Up MGMT<br> !<br> !<br> RP/0/0/CPU0:XR4#show ipv6 int br<br> Loopback0 [Up/Up]<br> fe80::7965:62ff:fe58:f8ec<br> fc00::10:0:0:44<br> MgmtEth0/0/CPU0/0 [Shutdown/Down]<br> unassigned<br> GigabitEthernet0/0/0/0 [Up/Up]<br> unassigned<br> GigabitEthernet0/0/0/0.12 [Up/Up]<br> fe80::44<br> fc00::10:33:44:44<br> |
Now, we see in the NETCONF session, what is configured in OpenConfig YANG model. To do this we send RPC request with “get-config” instruction through the opened NETCONF over SSH session:
1 2 3 | <br> #252<br> <!--?xml version="1.0" encoding="utf-8"?--> |
1 | <br> |
1 |
1 | <br> |
1 |
1 | <br> |
1 | ##<br> |
As response we get extensive RPC reply:
1 2 3 | <br> #3800<br> <!--?xml version="1.0"?--> |
1 | <code lang="xml"> |
Loopback0
1 | <code lang="xml"> |
Loopback0
idx:softwareLoopback
true
1 | <br> |
1 | 0<br> |
1 |
1 | <code lang="xml"> |
10.0.0.44 32
1 | <code lang="xml"> |
1 | <code lang="xml"> |
fc00::10:0:0:44 128
1 | <code lang="xml"> |
MgmtEth0/0/CPU0/0
MgmtEth0/0/CPU0/0
idx:ethernetCsmacd
false
false
GigabitEthernet0/0/0/0
GigabitEthernet0/0/0/0
idx:ethernetCsmacd
true
false
0
0
0
0
34
34
GigabitEthernet0/0/0/0.34
true
false
1 | <code lang="xml"> |
fc00::10:33:44:44 112
1 | <code lang="xml"> |
1 | <code lang="xml"> |
10.33.44.44 24
1 | <code lang="xml"> |
34
1 | <code lang="xml"> |
999
999
GigabitEthernet0/0/0/0.999
true
false
1 | <code lang="xml"> |
192.168.1.112 24
1 | <br> |
1 |
1 |
1 | <code lang="xml"> |
999
1 | <br> |
1 |
1 | <br> |
1 | ##<br> |
Remember, we have explained the framing of the message previously
In this RPC reply we see all the parameters, which is related to the interfaces we have created including management interface, which is related to another VRF though.
#3. Cisco IOS XR. Edit the interface configuration using OpenConfig
Now it’s time to create our own sub-interface and loopback interface in order to understand, if we understand this OpenConfig YANG data model for interface correct. We will create the “Loopback 1” with another IP address and new sub-interface ”GigabitEthernet0/0/0/0.13” using “edit-config” message in OpenConfg format:
1 2 3 | <br> #2111<br> <!--?xml version="1.0" encoding="utf-8"?--> |
1 | <code lang="xml"> |
rollback-on-error
1 | <code lang="xml"> |
Loopback1
1 | <code lang="xml"> |
Loopback1
idx:softwareLoopback
true
1 | <br> |
1 | 0<br> |
1 |
1 | <code lang="xml"> |
10.0.1.44 32
1 | <code lang="xml"> |
1 | <code lang="xml"> |
fc00::10:0:1:44 128
1 | <code lang="xml"> |
GigabitEthernet0/0/0/0
GigabitEthernet0/0/0/0
idx:ethernetCsmacd
true
false
14
14
GigabitEthernet0/0/0/0.14
true
false
1 | <code lang="xml"> |
fc00::10:11:44:44 112
1 | <code lang="xml"> |
1 | <code lang="xml"> |
10.11.44.44 24
1 | <br> |
1 |
1 |
1 | <code lang="xml"> |
14
1 | <br> |
1 |
1 | <br> |
1 | ##<br> |
If everything was entered correctly, we will get corresponding “OK”:
1 2 | #119<br> <!--?xml version="1.0"?--> |
1 | <br> |
1 | ##<br> |
Don’t forget, we deal with Cisco IOS XR, so we need to commit configuration using corresponding “commit” message:
1 2 | #126<br> <!--?xml version="1.0" encoding="UTF-8"?--> |
1 | <br> |
1 | ##<br> |
And we receive OK again:
1 2 | #119<br> <!--?xml version="1.0"?--> |
1 | <br> |
1 | ##<br> |
So far the trace looks nice, that’s why we are checking the output of “show interface” at Cisco IOS XR both for IPv4 and IPv6:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <br> RP/0/0/CPU0:XR4#show ipv4 int br<br> Interface IP-Address Status Protocol Vrf-Name<br> Loopback0 10.0.0.44 Up Up default<br> Loopback1 10.0.1.44 Up Down default<br> MgmtEth0/0/CPU0/0 unassigned Shutdown Down default<br> GigabitEthernet0/0/0/0 unassigned Up Up default<br> GigabitEthernet0/0/0/0.14 10.11.44.44 Up Up default<br> GigabitEthernet0/0/0/0.34 10.33.44.44 Up Up default<br> GigabitEthernet0/0/0/0.999 192.168.1.112 Up Up MGMT<br> !<br> !<br> RP/0/0/CPU0:XR4#show ipv6 int br<br> Loopback0 [Up/Up]<br> fe80::7965:62ff:fe58:f8ec<br> fc00::10:0:0:44<br> Loopback1 [Up/Up]<br> fe80::7965:62ff:fe58:f8ec<br> fc00::10:0:1:44<br> MgmtEth0/0/CPU0/0 [Shutdown/Down]<br> unassigned<br> GigabitEthernet0/0/0/0 [Up/Up]<br> unassigned<br> GigabitEthernet0/0/0/0.14 [Up/Up]<br> fe80::250:56ff:fe34:7146<br> fc00::10:11:44:44<br> GigabitEthernet0/0/0/0.34 [Up/Up]<br> fe80::44<br> fc00::10:33:44:44<br> |
Both newly created interfaces are up and running so it means that our OpenConfig understanding is correct. Let’s move further to get working Ansible playbook for interface configuration.
#4. Cisco IOS XR. Ansible for OpenConfig with Cisco
Based on the manually creation of NETCONF “edit-config” requests using OpenConfig YANG data model, we’ll create Ansible playbook to make configuration of interfaces using this OpenConfig YANG model.
OpenConfig is claimed to be vendor-agnostic, so I hope that I will need to create the script only once and all the vendors will be managed using it. Nevertheless, I will create some roles in Ansible so that it is easier to manage deviations per vendor if any arise. The structure of Ansible playbooks and roles is similar to what we did recently for Arista automation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | +--ansible<br> +--128_lab.yml<br> +--group_vars<br> | +--arista<br> | | +--arista_host.yml<br> | +--cisco<br> | | +--cisco_host.yml<br> | +--nokia<br> | +--nokia_host.yml<br> +--roles<br> +--arista<br> | +--128_lab<br> | +--tasks<br> | | +--main.yml<br> | +--templates<br> | | +--interfaces.j2<br> | +--vars<br> | +--oc_vEOS2.yml<br> +--cisco<br> | +--128_lab<br> | +--tasks<br> | | +--main.yml<br> | +--templates<br> | | +--interfaces.j2<br> | +--vars<br> | +--oc_vEOS2.yml<br> +--nokia<br> +--128_lab<br> +--tasks<br> | +--main.yml<br> +--templates<br> | +--interfaces.j2<br> | +--network_instance_interfaces.j2<br> +--vars<br> +--oc_vEOS2.yml<br> |
Here is connectivity parameters:
1 2 3 4 5 6 | $ cat group_vars/cisco/cisco_host.yml<br> ---<br> ansible_network_os: iosxr<br> ansible_user: cisco<br> ansible_pass: cisco<br> ...<br> |
The structure of the variables follows the OpenConfig YANG data model.
There is single change: there is no possibility to have variable name, which contains symbol “-“, that’s why it’s replaced with “_”.
Here is the example of variables for spine switch XR3 based on Cisco IOS XR:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | .$ cat roles/cisco/128_lab/vars/oc_XR3.yml<br> ---<br> node:<br> hostname: XR3<br> interfaces:<br> - name: Loopback0<br> type: softwareLoopback<br> enabled: true<br> subinterfaces:<br> - index: 0<br> ipv4:<br> address:<br> - ip: 10.0.0.33<br> prefix_length: 32<br> ipv6:<br> address:<br> - ip: fc00::10:0:0:33<br> prefix_length: 128<br> - name: GigabitEthernet0/0/0/0<br> type: ethernetCsmacd<br> enabled: true<br> ethernet:<br> auto_negotiate: false<br> subinterfaces:<br> - index: 13<br> enabled: true<br> vlan:<br> vlan_id: 13<br> ipv4:<br> address:<br> - ip: 10.11.33.33<br> prefix_length: 24<br> ipv6:<br> address:<br> - ip: fc00::10:11:33:33<br> prefix_length: 112<br> - index: 23<br> enabled: true<br> vlan:<br> vlan_id: 23<br> ipv4:<br> address:<br> - ip: 10.22.33.33<br> prefix_length: 24<br> ipv6:<br> address:<br> - ip: fc00::10:22:33:33<br> prefix_length: 112<br> ...<br> |
If you look carefully, you will see that this files exactly follows OpenConfig YANG data model we have seen previously in “get-config” RPC reply over NETCONF.
In the same way we create file with variable for XR4. It isn’t shown here, but will be listed in files as usually.
The next step in our Ansible-based automation is to create proper jinja2 template so that config is created automatically. As you see in variables, we are using dictionaries a lot to simplify template:
1 | $ cat roles/cisco/128_lab/templates/interfaces.j2 |
1 | <code lang="xml"> |
{% for iface in node.interfaces %}
1 | <code lang="xml"> |
{{ iface.name }}
1 | <code lang="xml"> |
{{ iface.name }}
idx:{{ iface.type }}
{{ iface.enabled|lower }}
1 | <code lang="xml"> |
{% if iface.subinterfaces is defined %}
1 | <code lang="xml"> |
{% for siface in iface.subinterfaces %}
1 | <code lang="xml"> |
{{ siface.index }}
{% if siface.index != 0 %}
1 | <code lang="xml"> |
{{ siface.index }}
{{ iface.name }}.{{ siface.index }}
{{ siface.enabled|lower }}
1 | <code lang="xml"> |
{% endif %}
{% if siface.ipv4 is defined %}
1 | <br> |
1 | {% for addr in siface.ipv4.address %} |
1 |
1 | <code lang="xml"> |
{{ addr.ip }} {{ addr.prefix_length }}
1 | <code lang="xml"> |
{% endfor %}
1 | <code lang="xml"> |
{% endif %}
{% if siface.ipv6 is defined %}
{% for addr in siface.ipv6.address %}
1 | <code lang="xml"> |
{{ addr.ip }} {{ addr.prefix_length }}
1 | <br> |
1 |
1 | {% endfor %} |
1 | <code lang="xml"> |
{% endif %}
{% if siface.vlan is defined %}
{{ siface.vlan.vlan_id }}
{% endif %}
1 | <code lang="xml"> |
{% endfor %}
1 | <code lang="xml"> |
{% endif %}
1 | <code lang="xml"> |
{% endfor %}
1 | <br> |
1 |
The last but not least point is to create the file with tasks. To be honest, I think, it’s the easiest step as it’s very straightforward:
1 2 3 4 5 | $ cat roles/cisco/128_lab/tasks/main.yml<br> ---<br> - name: IMPORTING VARS<br> include_vars:<br> file: oc_{{ inventory_hostname }}.yml |
1 2 3 4 5 | - name: CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT<br> template:<br> src: interfaces.j2<br> dest: /tmp/oc_{{ inventory_hostname }}.conf<br> mode: 0755 |
1 | <br> |
1 |
1 2 3 4 5 6 7 8 9 | - name: OPENCOFNIG // CONFIGURING INTERFACES<br> netconf_config:<br> host: "{{ inventory_hostname }}"<br> username: "{{ ansible_user }}"<br> password: "{{ ansible_pass }}"<br> hostkey_verify: false<br> look_for_keys: false<br> xml: "{{ lookup ('template', 'interfaces.j2') }}"<br> ...<br> |
The second task in play isn’t necessary and is used primary for debugging in order we can see how exactly the ”config” part of NETCONF “edit-config” message looks like.
Well, there is one more thing we need to do. We need to create general Ansible playbook, which will call roles:
1 2 3 4 5 6 7 | .$ cat 128_lab.yml<br> ---<br> - hosts: cisco<br> connection: local<br> tags: cisco<br> roles:<br> - { role: cisco/128_lab, var_vendor: cisco } |
1 2 3 4 5 | - hosts: nokia<br> connection: local<br> tags: nokia<br> roles:<br> - { role: nokia/128_lab, var_vendor: nokia } |
1 | <br> |
1 |
1 2 3 4 5 6 | - hosts: arista<br> connection: local<br> tags: arista<br> roles:<br> - { role: arista/128_lab, var_vendor: arista }<br> ...<br> |
Up to now we have created everything necessary to automate deployment of spine switches based on Cisco IOS XR.
Before we try it, I will remove all created interfaces and will leave only initial config on Cisco IOS XR based spines XR3 and XR4:
1 2 | $ ansible-playbook 128_lab.yml --limit=cisco<br> [WARNING] Ansible is in a world writable directory (/home/aaa/ansible), ignoring it as an ansible.cfg source. |
1 | PLAY [cisco] ********************************************************************************************** |
TASK [Gathering Facts] ************************************************************************************
ok: [XR3]
ok: [XR4]
TASK [cisco/128_lab : IMPORTING VARS] *********************************************************************
ok: [XR3]
ok: [XR4]
TASK [cisco/128_lab : CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT] **************
ok: [XR4]
ok: [XR3]
TASK [cisco/128_lab : OPENCOFNIG // CONFIGURING INTERFACES] ***********************************************
changed: [XR4]
changed: [XR3]
PLAY [nokia] **********************************************************************************************
skipping: no hosts matched
PLAY [arista] *********************************************************************************************
skipping: no hosts matched
1 |
1 2 3 | PLAY RECAP ************************************************************************************************<br> XR3 : ok=4 changed=1 unreachable=0 failed=0<br> XR4 : ok=4 changed=1 unreachable=0 failed=0<br> |
Looks good. Let’s double check on CLI:
1 2 | RP/0/0/CPU0:XR3#show ipv4 int br<br> Sat Jul 21 18:57:58.109 UTC |
1 | <br> |
1 2 3 4 5 6 7 | Interface IP-Address Status Protocol Vrf-Name<br> Loopback0 10.0.0.33 Up Up default<br> MgmtEth0/0/CPU0/0 unassigned Shutdown Down default<br> GigabitEthernet0/0/0/0 unassigned Up Up default<br> GigabitEthernet0/0/0/0.13 10.11.33.33 Up Up default<br> GigabitEthernet0/0/0/0.23 10.22.33.33 Up Up default<br> GigabitEthernet0/0/0/0.999 192.168.1.111 Up Up MGMT<br> |
Cisco is done. So, we have deployed configuration of the interfaces using OpenConfig YANG data model over NETCONF transport. Let’s check how other vendors behave. Hypothetically there should be no difference. Do you believe? 🙂
OpenConfig and Nokia SR OS
Nokia has introduced support of OpenConfig YANG data models only in the latest version of its SR OS, which is Nokia (Alcatel-Lucent) SR OS 16.0.R1 for the time of the writing. What is interesting, Nokia VSR doesn’t support it yet, but rather physical devices (like Nokia SR 7750/7950 and so on) or Nokia vSIM, which emulates HW of real devices. That’s why we change the initial XML file, we have used all time long (link). The change impacts only one line, which is probably the most important:
GeSHi Error: GeSHi could not find the language quotxml (using path /var/www/vhosts/karneliuk.com/httpdocs/wp-content/plugins/codecolorer/lib/geshi/) (code 2)
Usage of this line in initial XML descriptor of VM for KVM assures we launch vSIM emulating this particular HW instead of VSR.
When we launch VM and provision the card and MDA, we should see the following outputs, if everything is done correctly. The chassis is SR-1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | []<br> A:admin@SR6# show chassis<br> ===============================================================================<br> System Information<br> ===============================================================================<br> Name : SR6<br> Type : 7750 SR-1<br> Chassis Topology : Standalone<br> Location : (Not Specified)<br> Coordinates : (Not Specified)<br> CLLI code :<br> Number of slots : 2<br> Oper number of slots : 2<br> Num of faceplate ports/connectors : 6<br> Num of physical ports : 4<br> Critical LED state : Off<br> Major LED state : Red<br> Minor LED state : Off<br> Over Temperature state : OK<br> Base MAC address : 02:a6:ff:00:00:00<br> FP Generations : FP4<br> System Profile : profile-a<br> ===============================================================================<br> Chassis Summary<br> ===============================================================================<br> Chassis Role Status<br> -------------------------------------------------------------------------------<br> 1 Standalone up<br> ===============================================================================<br> |
The following card is installed in the cassis:
1 2 3 4 5 6 7 8 9 10 11 | []<br> A:admin@SR6# show card<br> ===============================================================================<br> Card Summary<br> ===============================================================================<br> Slot Provisioned Type Admin Operational Comments<br> Equipped Type (if different) State State<br> -------------------------------------------------------------------------------<br> 1 iom-1:he up up<br> A cpm-1 up up/active<br> ===============================================================================<br> |
And the following MDA is there:
1 2 3 4 5 6 7 8 9 10 | []<br> A:admin@SR6# show mda<br> ===============================================================================<br> MDA Summary<br> ===============================================================================<br> Slot Mda Provisioned Type Admin Operational<br> Equipped Type (if different) State State<br> -------------------------------------------------------------------------------<br> 1 1 me6-100gb-qsfp28 up up<br> ===============================================================================<br> |
Such Nokia (Alcatel-Lucent) vSIM supports OpenConfig, so we start with the core topic of the article.
Information about MD-CLI, how to configure and to use it you can find in separate article.
#1. Nokia SR OS. Enabling OpenConfig
We have explained previously how to enable NETCONF in Nokia (Alcatel-Lucent) VSR / SR 7750, but there are some changes in SR OS 16.0.R1, so we’ll cover the full configuration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | []<br> A:admin@SR6# admin show configuration<br> # TiMOS-B-16.0.R1 both/x86_64 Nokia 7750 SR Copyright (c) 2000-2018 Nokia.<br> configure {<br> system {<br> name "SR6"<br> management-interface {<br> netconf {<br> admin-state enable<br> }<br> yang-modules {<br> base-r13-modules true<br> nokia-modules true<br> openconfig-modules true<br> }<br> }<br> security {<br> aaa {<br> local-profiles {<br> profile "administrative" {<br> default-action permit-all<br> netconf {<br> base-op-authorization {<br> kill-session true<br> lock true<br> }<br> }<br> }<br> }<br> }<br> user-params {<br> local-user {<br> user "admin" {<br> password "$2y$10$TQrZlpBDra86.qoexZUzQeBXDY1FcdDhGWdD9lLxMuFyPVSm0OGy6"<br> access {<br> console true<br> netconf true<br> }<br> console {<br> member ["administrative"]<br> }<br> }<br> }<br> }<br> }<br> }<br> }<br> |
Only configuration related to NETCONF and OpenConfig is shown.
Comparing to previous example, here we have 2 major differences:
- It’s done in MD-CLI mode.
- Set of YANG modules are enabled explicitly.
So we need explicitly enable OpenConfig YANG model in order we can use it. Let’s connect to our Nokia SROS based leaf SR6:
1 | $ ssh admin@SR6 -p 830 -s netconf |
1 | <br> |
1 2 | admin@sr6's password:<br> <!--?xml version="1.0" encoding="UTF-8"?--> |
1 | <code lang="xml"> |
urn:ietf:params:netconf:base:1.0
urn:ietf:params:netconf:base:1.1
urn:ietf:params:netconf:capability:candidate:1.0
urn:ietf:params:netconf:capability:confirmed-commit:1.1
urn:ietf:params:netconf:capability:notification:1.0
urn:ietf:params:netconf:capability:interleave:1.0
urn:ietf:params:netconf:capability:validate:1.0
urn:ietf:params:netconf:capability:validate:1.1
urn:ietf:params:netconf:capability:startup:1.0
urn:ietf:params:netconf:capability:url:1.0?scheme=ftp,tftp,file
urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all
…
http://openconfig.net/yang/acl?module=openconfig-acl&revision=2016-01-22
http://openconfig.net/yang/bgp?module=openconfig-bgp&revision=2016-03-31
http://openconfig.net/yang/bgp-policy?module=openconfig-bgp-policy&revision=2016-06-21
http://openconfig.net/yang/bgp-types?module=openconfig-bgp-types&revision=2016-06-21
http://openconfig.net/yang/openconfig-ext?module=openconfig-extensions&revision=2015-10-05
http://openconfig.net/yang/interfaces/aggregate?module=openconfig-if-aggregate&revision=2016-12-22
http://openconfig.net/yang/interfaces/ethernet?module=openconfig-if-ethernet&revision=2016-12-22
http://openconfig.net/yang/interfaces/ip?module=openconfig-if-ip&revision=2016-12-22
http://openconfig.net/yang/interfaces/ip-ext?module=openconfig-if-ip-ext&revision=2016-12-22
http://openconfig.net/yang/types/inet?module=openconfig-inet-types&revision=2017-01-26
http://openconfig.net/yang/interfaces?module=openconfig-interfaces&revision=2016-12-22
http://openconfig.net/yang/openconfig-isis?module=openconfig-isis&revision=2016-10-18
http://openconfig.net/yang/isis-lsdb-types?module=openconfig-isis-lsdb-types&revision=2016-10-18
http://openconfig.net/yang/openconfig-isis-policy?module=openconfig-isis-policy&revision=2016-10-18
http://openconfig.net/yang/isis-types?module=openconfig-isis-types&revision=2016-10-18
http://openconfig.net/yang/lacp?module=openconfig-lacp&revision=2016-05-26
http://openconfig.net/yang/lldp?module=openconfig-lldp&revision=2016-05-16
http://openconfig.net/yang/lldp/types?module=openconfig-lldp-types&revision=2016-05-16
http://openconfig.net/yang/local-routing?module=openconfig-local-routing&revision=2016-05-11
http://openconfig.net/yang/mpls?module=openconfig-mpls&revision=2016-08-08
http://openconfig.net/yang/rsvp?module=openconfig-mpls-rsvp&revision=2016-08-08
http://openconfig.net/yang/mpls-sr?module=openconfig-mpls-sr&revision=2016-08-08
http://openconfig.net/yang/mpls-types?module=openconfig-mpls-types&revision=2016-08-08
http://openconfig.net/yang/network-instance?module=openconfig-network-instance&revision=2015-10-18
http://openconfig.net/yang/network-instance-types?module=openconfig-network-instance-types&revision=2015-10-18
http://openconfig.net/yang/header-fields?module=openconfig-packet-match&revision=2016-04-27
http://openconfig.net/yang/packet-match-types?module=openconfig-packet-match-types&revision=2016-04-27
http://openconfig.net/yang/policy-types?module=openconfig-policy-types&revision=2016-05-12
http://openconfig.net/yang/relay-agent?module=openconfig-relay-agent&revision=2016-05-16
http://openconfig.net/yang/routing-policy?module=openconfig-routing-policy&revision=2016-05-12
http://openconfig.net/yang/rsvp-sr-ext?module=openconfig-rsvp-sr-ext&revision=2017-03-06
http://openconfig.net/yang/openconfig-types?module=openconfig-types&revision=2016-05-31
http://openconfig.net/yang/vlan?module=openconfig-vlan&revision=2016-05-26
http://openconfig.net/yang/vlan-types?module=openconfig-vlan-types&revision=2016-05-26
http://openconfig.net/yang/types/yang?module=openconfig-yang-types&revision=2017-01-26
urn:nokia.com:sros:ns:yang:sr:openconfig_acl_deviations?module=nokia-sr-openconfig-acl-deviations&revision=2016-01-22
urn:nokia.com:sros:ns:yang:sr:openconfig_bgp_policy_deviations?module=nokia-sr-openconfig-bgp-policy-deviations&revision=2016-06-21
urn:nokia.com:sros:ns:yang:sr:openconfig_bgp_deviations?module=nokia-sr-openconfig-bgp-deviations&revision=2016-03-31
urn:nokia.com:sros:ns:yang:sr:openconfig_if_aggregate_deviations?module=nokia-sr-openconfig-if-aggregate-deviations&revision=2016-12-22
urn:nokia.com:sros:ns:yang:sr:openconfig_if_ethernet_deviations?module=nokia-sr-openconfig-if-ethernet-deviations&revision=2016-12-22
urn:nokia.com:sros:ns:yang:sr:openconfig_if_ip_ext_deviations?module=nokia-sr-openconfig-if-ip-ext-deviations&revision=2016-12-22
urn:nokia.com:sros:ns:yang:sr:openconfig_if_ip_deviations?module=nokia-sr-openconfig-if-ip-deviations&revision=2016-12-22
urn:nokia.com:sros:ns:yang:sr:openconfig_interfaces_deviations?module=nokia-sr-openconfig-interfaces-deviations&revision=2016-12-22
urn:nokia.com:sros:ns:yang:sr:openconfig_isis_policy_deviations?module=nokia-sr-openconfig-isis-policy-deviations&revision=2016-10-18
urn:nokia.com:sros:ns:yang:sr:openconfig_lldp_deviations?module=nokia-sr-openconfig-lldp-deviations&revision=2016-05-16
urn:nokia.com:sros:ns:yang:sr:openconfig_mpls_deviations?module=nokia-sr-openconfig-mpls-deviations&revision=2016-08-08
urn:nokia.com:sros:ns:yang:sr:openconfig_network_instance_deviations?module=nokia-sr-openconfig-network-instance-deviations&revision=2015-10-18
urn:nokia.com:sros:ns:yang:sr:openconfig_relay_agent_deviations?module=nokia-sr-openconfig-relay-agent-deviations&revision=2016-05-16
urn:nokia.com:sros:ns:yang:sr:openconfig_routing_policy_deviations?module=nokia-sr-openconfig-routing-policy-deviations&revision=2016-05-12
urn:nokia.com:sros:ns:yang:sr:openconfig_vlan_deviations?module=nokia-sr-openconfig-vlan-deviations&revision=2016-05-26
1 | <code lang="xml"> |
8
1 | <br> |
1 | ]]>]]><br> |
As I’ve enabled all YANG modules, the output was very long, that’s why only OpenConfig related capabilities are shown.
#2. Nokia SR OS. Get the interface configuration using OpenConfig
Following the same approach we’ve done for Cisco, we’ll configure some interfaces in OpenConfig model.
In MD-CLI Nokia SR OS has dedicated context for OpenConfig configuration.
To make story a shorter, I will show the configuration of one interface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | (gl)[configure openconfig]<br> A:admin@SR6# info<br> interfaces {<br> interface "1/1/c1/1" {<br> config {<br> name "1/1/c1/1"<br> type ethernetCsmacd<br> enabled true<br> }<br> subinterfaces {<br> subinterface 13 {<br> config {<br> index 13<br> enabled true<br> }<br> ipv4 {<br> addresses {<br> address 10.11.33.11 {<br> config {<br> ip 10.11.33.11<br> prefix-length 24<br> }<br> }<br> }<br> }<br> ipv6 {<br> addresses {<br> address fc00::10:11:33:11 {<br> config {<br> ip fc00::10:11:33:11<br> prefix-length 112<br> }<br> }<br> }<br> }<br> vlan {<br> config {<br> vlan-id "13"<br> }<br> }<br> }<br> }<br> }<br> }<br> network-instances {<br> network-instance "Base" {<br> config {<br> name "Base"<br> type DEFAULT_INSTANCE<br> }<br> interfaces {<br> interface "1/1/c1/1.13" {<br> config {<br> id "1/1/c1/1.13"<br> interface "1/1/c1/1"<br> subinterface 13<br> associated-address-families [IPV4 IPV6]<br> }<br> }<br> }<br> }<br> }<br> |
As you see, in Nokia we need to define interfaces in two contexts: interfaces and network-instances, what is different to Cisco implementation. The should be or will be released some documentation for OpenConfig in Nokia (Alcatel-Lucent) SR OS, but as usually I got to it just trying to bring it working using “plug and pray” approach.
That’s how the interfaces is shown in CLI:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | []<br> A:admin@SR6# show router interface<br> ===============================================================================<br> Interface Table (Router: Base)<br> ===============================================================================<br> Interface-Name Adm Opr(v4/v6) Mode Port/SapId<br> IP-Address PfxState<br> -------------------------------------------------------------------------------<br> oc_1/1/c1/1_13 Up Up/Up Network 1/1/c1/1:13<br> 10.11.33.11/24 n/a<br> fc00::10:11:33:11/112 PREFERRED<br> fe80::f8ac:a6ff:fe16:202/64 PREFERRED<br> -------------------------------------------------------------------------------<br> Interfaces : 1<br> ===============================================================================<br> |
As you might spot, we don’t define the name in this configuration. It’s created automatically based on the name of port and subinterface’s index. Now we check how that looks in NETCONF:
1 | <!--?xml version="1.0" encoding="utf-8"?--> |
1 | <br> |
1 |
1 | <br> |
1 |
1 | <br> |
1 | ]]>]]> |
1 | <!--?xml version="1.0" encoding="UTF-8"?--> |
1 | <code lang="xml"> |
1/1/c1/1
1 | <code lang="xml"> |
1/1/c1/1
ethernetCsmacd
true
1 | <code lang="xml"> |
13
1 | <code lang="xml"> |
13
true
1 | <br> |
1 |
1 | <code lang="xml"> |
10.11.33.11 24
1 | <code lang="xml"> |
1 | <code lang="xml"> |
fc00::10:11:33:11 112
1 | <code lang="xml"> |
1 | <code lang="xml"><code lang="xml"> |
13
1 | <code lang="xml"><br> |
1 | <code lang="xml"> |
1 | <code lang="xml"> |
]]>]]>
1 | <code lang="xml"> |
1 | <code lang="xml"> |
Base
]]>]]>
1 | <br> |
1 |
1 | <!--?xml version="1.0" encoding="UTF-8"?--> |
1 | <code lang="xml"> |
Base
1 | <code lang="xml"> |
1/1/c1/1.13
1 | <code lang="xml"> |
1/1/c1/1.13
1/1/c1/1
13
IPV4
IPV6
1 | <br> |
1 | ]]>]]><br> |
The output of “get-config” message looks quite similar to what we have seen in Cisco IOS XR, but for sure it isn’t identical. Even if we omit necessity to created additional network-instance context, we need to tune initial jijna2 template.
That’s what we are going to do.
#3. Nokia SR OS. Edit the interface configuration using OpenConfig
The idea of testing proper “edit-config” messages is explained earlier in Cisco part, so you can follow the logic easily.
We’ll try to create system loopback interface logic, based on the types we can read in OpenConfig YANG models or what we have seen in Cisco part.
Don’t forget to commit changes!
1 | <!--?xml version="1.0" encoding="utf-8"?--> |
1 | <code lang="xml"> |
system
1 | <code lang="xml"> |
system
softwareLoopback
true
1 | <code lang="xml"> |
0
1 | <br> |
1 |
1 2 | <code lang="xml"><br> 10.0.0.11 |
1 | <code lang="xml"> |
32
1 | <br> |
1 |
1 |
1 | <code lang="xml"> |
1 | <code lang="xml"> |
fc00::10:0:0:11 128
1 | <code lang="xml"> |
1 | <code lang="xml"> |
]]>]]>
1 | <code lang="xml"> |
Base
Base
DEFAULT_INSTANCE
system
system
system
0
IPV4
IPV6
]]>]]>
1 | <code lang="xml"> |
]]>]]>
1 | <code lang="xml"> |
]]>]]>
1 | <br> |
1 |
1 | <!--?xml version="1.0" encoding="UTF-8"?--> |
1 | <br> |
1 | ]]>]]><br> |
After we have sent the proper “edit-config” messages and committed configuration over NETCONF, we can verify, what we see in CLI:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | []<br> A:admin@SR6# show router interface<br> ===============================================================================<br> Interface Table (Router: Base)<br> ===============================================================================<br> Interface-Name Adm Opr(v4/v6) Mode Port/SapId<br> IP-Address PfxState<br> -------------------------------------------------------------------------------<br> oc_1/1/c1/1_13 Up Up/Up Network 1/1/c1/1:13<br> 10.11.33.11/24 n/a<br> fc00::10:11:33:11/112 PREFERRED<br> fe80::f8ac:a6ff:fe16:202/64 PREFERRED<br> system Up Up/Up Network system<br> 10.0.0.11/32 n/a<br> fc00::10:0:0:11/128 PREFERRED<br> -------------------------------------------------------------------------------<br> Interfaces : 2<br> ===============================================================================<br> |
As interfaces is properly reflected, it means that our understanding of OpenConfig YANG in Nokia (Alcate-Lucent) SR OS is correct and we can proceed with Ansible
#4. Nokia SR OS. Ansible for OpenConfig with Cisco
The data structure is fully identical to one we have in case of Cisco. Moreover, we copy already created files for Cisco in Nokia roles:
1 | $ cp roles/cisco/128_lab/ roles/nokia/128_lab/ |
This is data structure of Ansible playbook:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | +--ansible<br> +--128_lab.yml<br> +--group_vars<br> | +--arista<br> | | +--arista_host.yml<br> | +--cisco<br> | | +--cisco_host.yml<br> | +--nokia<br> | +--nokia_host.yml<br> +--roles<br> +--arista<br> | +--128_lab<br> | +--tasks<br> | | +--main.yml<br> | +--templates<br> | | +--interfaces.j2<br> | +--vars<br> | +--oc_vEOS2.yml<br> +--cisco<br> | +--128_lab<br> | +--tasks<br> | | +--main.yml<br> | +--templates<br> | | +--interfaces.j2<br> | +--vars<br> | +--oc_vEOS2.yml<br> +--nokia<br> +--128_lab<br> +--tasks<br> | +--main.yml<br> +--templates<br> | +--interfaces.j2<br> | +--network_instance_interfaces.j2<br> +--vars<br> +--oc_vEOS2.yml<br> |
Just in the same way as creating Ansible playbook for automating OpenConfig operation with Cisco IOS XR, we start with some authentication data, which will be used:
1 2 3 4 5 6 | $ cat group_vars/nokia/nokia_host.yml<br> ---<br> ansible_network_os: sros<br> ansible_user: admin<br> ansible_pass: admin<br> ...<br> |
Then we go to variable. As you see, there is no changes comparing to variables for Cisco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | $ cat roles/nokia/128_lab/vars/oc_SR6.yml<br> ---<br> node:<br> hostname: SR6<br> interfaces:<br> - name: system<br> type: softwareLoopback<br> enabled: true<br> subinterfaces:<br> - index: 0<br> ipv4:<br> address:<br> - ip: 10.0.0.11<br> prefix_length: 32<br> ipv6:<br> address:<br> - ip: fc00::10:0:0:11<br> prefix_length: 128<br> - name: 1/1/c1/1<br> type: ethernetCsmacd<br> enabled: true<br> ethernet:<br> auto_negotiate: false<br> subinterfaces:<br> - index: 13<br> enabled: true<br> vlan:<br> vlan_id: 13<br> ipv4:<br> address:<br> - ip: 10.11.33.11<br> prefix_length: 24<br> ipv6:<br> address:<br> - ip: fc00::10:11:33:11<br> prefix_length: 112<br> - index: 14<br> enabled: true<br> vlan:<br> vlan_id: 14<br> ipv4:<br> address:<br> - ip: 10.11.44.11<br> prefix_length: 24<br> ipv6:<br> address:<br> - ip: fc00::10:11:44:11<br> prefix_length: 112<br> ...<br> |
To be honest, I find this part particulary important. The data model is the same for all elements, thanks OpenConfig! Only such approach can create truly automation.
The next point in creating proper playbook is tuning the Jinja2 template for interfaces:
1 | $ cat roles/nokia/128_lab/templates/interfaces.j2 |
1 | <code lang="xml"> |
{% for iface in node.interfaces %}
1 | <code lang="xml"> |
{{ iface.name }}
1 | <code lang="xml"> |
{{ iface.name }}
{% if ansible_network_os == “iosxr” %}
idx:{{ iface.type }}
{% else %}
{{ iface.type }}
{% endif %}
{{ iface.enabled|lower }}
1 | <code lang="xml"> |
{% if iface.subinterfaces is defined %}
1 | <code lang="xml"> |
{% for siface in iface.subinterfaces %}
1 | <code lang="xml"> |
{{ siface.index }}
{% if siface.index != 0 %}
1 | <code lang="xml"> |
{{ siface.index }}
{% if ansible_network_os == “iosxr” %}
{{ iface.name }}.{{ siface.index }}
{% endif %}
{{ siface.enabled|lower }}
1 | <code lang="xml"> |
{% endif %}
{% if siface.ipv4 is defined %}
{% if ansible_network_os != “sros” %}
1 | <code lang="xml"> |
{% else %}
1 | <br> |
1 2 3 4 | {% endif %}<br> {% if ansible_network_os != "iosxr" %}<br> {% endif %}<br> {% for addr in siface.ipv4.address %} |
1 |
1 | <code lang="xml"> |
{{ addr.ip }} {{ addr.prefix_length }}
1 | <code lang="xml"> |
{% endfor %}
{% if ansible_network_os != “iosxr” %}
{% endif %}
1 | <code lang="xml"> |
{% endif %}
{% if siface.ipv6 is defined %}
{% if ansible_network_os != “sros” %}
{% else %}
{% endif %}
{% if ansible_network_os != “iosxr” %}
{% endif %}
{% for addr in siface.ipv6.address %}
1 | <code lang="xml"> |
{{ addr.ip }} {{ addr.prefix_length }}
1 | <br> |
1 |
1 2 3 | {% endfor %}<br> {% if ansible_network_os != "iosxr" %}<br> {% endif %} |
1 | <code lang="xml"> |
{% endif %}
{% if siface.vlan is defined %}
{% if ansible_network_os != “sros” %}
{% else %}
{% endif %}
{{ siface.vlan.vlan_id }}
{% endif %}
1 | <code lang="xml"> |
{% endfor %}
1 | <code lang="xml"> |
{% endif %}
1 | <code lang="xml"> |
{% endfor %}
1 | <br> |
1 |
It became a bit more complicated comparing to initial one. The complications come from the fact that we need to take into account particular syntax per vendor. For instance, for IP address configuration we put:
- For Cisco: <ipv4 xmlns=”http://openconfig.net/yang/interfaces/ip”>
- For Nokia: <ipv4>
Additionally, Nokia put all kind of IP addresses into <addresses> group, whereas there is no such group in Cisco IOS XR.
But again, the syntax is relevant only for Cisco IOS XRv 6.1.2 and Nokia SR OS 16.0.R1. For other versions of NOSes it might changes.
As we have additional configuration in step in Nokia SR OS, we create new template:
1 | $ cat roles/nokia/128_lab/templates/network_instance_interfaces.j2 |
1 | <code lang="xml"> |
Base
1 | <code lang="xml"> |
Base
DEFAULT_INSTANCE
1 | <code lang="xml"> |
{% for iface in node.interfaces %}
{% for siface in iface.subinterfaces %}
1 | <code lang="xml"> |
{% if iface.name == “system” %}
{{ iface.name }}
{% else %}
{{ iface.name }}.{{ siface.index }}
{% endif %}
1 | <code lang="xml"> |
{% if iface.name == “system” %}
{{ iface.name }}
{% else %}
{{ iface.name }}.{{ siface.index }}
{% endif %}
{{ iface.name }}
{{ siface.index }}
{% if siface.ipv4 is defined %}
IPV4
{% endif %}
{% if siface.ipv6 is defined %}
IPV6
{% endif %}
1 | <code lang="xml"> |
{% endfor %}
{% endfor %}
1 | <br> |
1 |
Now we need to extend the Ansible playbook with tasks:
1 2 3 4 5 | $ cat roles/nokia/128_lab/tasks/main.yml<br> ---<br> - name: IMPORTING VARS<br> include_vars:<br> file: oc_{{ inventory_hostname }}.yml |
1 2 3 4 5 | - name: CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT I<br> template:<br> src: interfaces.j2<br> dest: /tmp/oc_{{ inventory_hostname }}_if.conf<br> mode: 0755 |
1 | <code lang="yaml"> |
– name: OPENCOFNIG // CONFIGURING INTERFACES I
netconf_config:
host: “{{ inventory_hostname }}”
username: “{{ ansible_user }}”
password: “{{ ansible_pass }}”
port: 830
hostkey_verify: false
look_for_keys: false
save: yes
xml: “{{ lookup (‘template’, ‘interfaces.j2’) }}”
1 | <code lang="yaml"> |
– name: CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT II
template:
src: network_instance_interfaces.j2
dest: /tmp/oc_{{ inventory_hostname }}_ni.conf
mode: 0755
when: ansible_network_os == “sros”
1 | <br> |
1 |
1 2 3 4 5 6 7 8 9 10 11 12 | - name: OPENCOFNIG // CONFIGURING INTERFACES II<br> netconf_config:<br> host: "{{ inventory_hostname }}"<br> username: "{{ ansible_user }}"<br> password: "{{ ansible_pass }}"<br> port: 830<br> hostkey_verify: false<br> look_for_keys: false<br> save: yes<br> xml: "{{ lookup ('template', 'network_instance_interfaces.j2') }}"<br> when: ansible_network_os == "sros"<br> ...<br> |
If you don’t need to debug the messages, just remove 2nd and 4th task. As you see, we add the condition to check for “ansible_network_os” to play this part of the playbook only for Nokia (Alcatel-Lucent) SR OS. It won’t be played for Cisco IOS XR.
So, automation using Ansible for interfaces configuration in Nokia (Alcatel-Lucent) SR OS using OpenConfig YANG data models through NETCONF is ready. So we can test it:
1 2 | $ ansible-playbook 128_lab.yml --limit=nokia<br> [WARNING] Ansible is in a world writable directory (/home/aaa/ansible), ignoring it as an ansible.cfg source. |
1 2 | PLAY [cisco] **********************************************************************************************<br> skipping: no hosts matched |
PLAY [nokia] **********************************************************************************************
TASK [Gathering Facts] ************************************************************************************
ok: [SR2]
ok: [SR1]
ok: [SR6]
ok: [VSR6]
TASK [nokia/128_lab : IMPORTING VARS] *********************************************************************
fatal: [VSR6]: FAILED!
fatal: [SR1]: FAILED!
fatal: [SR2]: FAILED!
ok: [SR6]
TASK [nokia/128_lab : CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT I] ************
ok: [SR6]
TASK [nokia/128_lab : OPENCOFNIG // CONFIGURING INTERFACES I] *********************************************
changed: [SR6]
TASK [nokia/128_lab : CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT II] ***********
ok: [SR6]
TASK [nokia/128_lab : OPENCOFNIG // CONFIGURING INTERFACES II] ********************************************
changed: [SR6]
PLAY [arista] *********************************************************************************************
skipping: no hosts matched
to retry, use: –limit @/home/aaa/ansible/128_lab.retry
1 |
1 2 3 4 5 | PLAY RECAP ************************************************************************************************<br> SR1 : ok=1 changed=0 unreachable=0 failed=1<br> SR2 : ok=1 changed=0 unreachable=0 failed=1<br> SR6 : ok=6 changed=2 unreachable=0 failed=0<br> VSR6 : ok=1 changed=0 unreachable=0 failed=1<br> |
Only one of 4 VSRs are working, because I haven’t created files with variables for them. The verification shows that all the interfaces we have mentioned in variables are up and running:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | []<br> A:admin@SR6# show router interface<br> ===============================================================================<br> Interface Table (Router: Base)<br> ===============================================================================<br> Interface-Name Adm Opr(v4/v6) Mode Port/SapId<br> IP-Address PfxState<br> -------------------------------------------------------------------------------<br> oc_1/1/c1/1_13 Up Up/Up Network 1/1/c1/1:13<br> 10.11.33.11/24 n/a<br> fc00::10:11:33:11/112 PREFERRED<br> fe80::f8ac:a6ff:fe16:202/64 PREFERRED<br> oc_1/1/c1/1_14 Up Up/Up Network 1/1/c1/1:14<br> 10.11.44.11/24 n/a<br> fc00::10:11:44:11/112 PREFERRED<br> fe80::f8ac:a6ff:fe16:202/64 PREFERRED<br> system Up Up/Up Network system<br> 10.0.0.11/32 n/a<br> fc00::10:0:0:11/128 PREFERRED<br> -------------------------------------------------------------------------------<br> Interfaces : 3<br> ===============================================================================<br> |
2 out of 3 vendors are covered for OpenConfig YANG data models over NETCONF. There only one to go.
OpenConfig and Arista EOS
According to the information I’ve found in the Internet, OpenConfig in Arista EOS is supported starting EOS 4.20.2F, but that time there were a lot of limitations in terms of supported modules and operations (much more read-only rather than read-write). The actual release notes for version 4.20.5F provides much more OpenConfig capabilities, though the latter link requires authentication, so make sure you have registered at Arista website.
#1. Arista EOS. Enabling OpenConfig
According to the links provided above, the configuration of NETCONF at Arista EOS is quite straightforward and requires only configuration of corresponding management API:
1 2 3 4 5 6 7 8 9 | vEOS2(config)#management api netconf<br> vEOS2(config-mgmt-api-netconf)#transport ssh default<br> vEOS2(config-netconf-transport-default)#vrf mgmt.<br> vEOS2(config-netconf-transport-default)#show active all<br> management api netconf<br> transport ssh default<br> no shutdown<br> port 830<br> vrf mgmt<br> |
The strange thing is that the standard port 830 doesn’t work, and any other arbitrary port doesn’t work either. How did I check that? I’m truing to connect to SSH through console in Linux, as I did both for Cisco IOS XR and Nokia (Alcatel-Lucent) SR OS:
1 | $ ssh aaa@vEOS2 -p 830 -s netconf |
But it hangs and become time out after some time. In order to connect for NETCONF, I need to remove “-p 830” so that I’m connected on standard SSH port 22:
1 2 | $ ssh aaa@vEOS2 -s netconf<br> Password: |
1 | <br> |
1 | urn:ietf:params:netconf:base:1.0urn:ietf:params:netconf:base:1.1urn:ietf:params:xml:ns:netconf:base:1.0urn:ietf:params:xml:ns:yang:ietf-netconf-monitoringurn:ietf:params:netconf:capability:writable-running:1.0http://openconfig.net/yang/types/yang?module=openconfig-yang-types&revision=2017-07-30http://openconfig.net/yang/policy-types?module=openconfig-policy-types&revision=2017-07-14http://openconfig.net/yang/ospf-types?module=openconfig-ospf-types&revision=2017-08-24http://openconfig.net/yang/aft?module=openconfig-aft&revision=2017-08-24http://openconfig.net/yang/local-routing?module=openconfig-local-routing&revision=2017-05-15http://arista.com/yang/experimental/igmpsnooping?module=arista-exp-eos-igmpsnooping&revision=2017-10-23http://arista.com/yang/experimental/eos/eos-types?module=arista-eos-types&revision=2016-10-14http://openconfig.net/yang/interfaces/ip?module=openconfig-if-ip&revision=2017-12-21http://openconfig.net/yang/network-instance?module=openconfig-network-instance&revision=2017-12-13http://openconfig.net/yang/types/inet?module=openconfig-inet-types&revision=2017-08-24http://openconfig.net/yang/interfaces/aggregate?module=openconfig-if-aggregate&revision=2017-12-21http://arista.com/yang/openconfig/system/deviations?module=arista-system-deviations&revision=2017-09-24http://openconfig.net/yang/bgp-types?module=openconfig-bgp-types&revision=2017-07-30http://openconfig.net/yang/ldp?module=openconfig-mpls-ldp&revision=2017-08-24http://openconfig.net/yang/ospfv2?module=openconfig-ospfv2&revision=2017-08-24http://openconfig.net/yang/interfaces/ethernet?module=openconfig-if-ethernet&revision=2017-12-21urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2013-07-15urn:ietf:params:xml:ns:yang:iana-if-type?module=iana-if-type&revision=2017-01-19http://openconfig.net/yang/aaa/types?module=openconfig-aaa-types&revision=2017-09-18http://openconfig.net/yang/alarms?module=openconfig-alarms&revision=2017-08-24http://openconfig.net/yang/bgp?module=openconfig-bgp&revision=2017-07-30http://openconfig.net/yang/lldp/types?module=openconfig-lldp-types&revision=2016-05-16http://openconfig.net/yang/mpls?module=openconfig-mpls&revision=2017-08-24http://arista.com/yang/openconfig/lacp/augments?module=arista-lacp-augments&revision=2017-09-14http://arista.com/yang/openconfig/lldp/augments?module=arista-lldp-augments&revision=2018-03-06http://openconfig.net/yang/isis-types?module=openconfig-isis-types&revision=2017-08-24http://arista.com/yang/openconfig/policy/deviations?module=arista-rpol-deviations&revision=2016-02-01http://openconfig.net/yang/system/logging?module=openconfig-system-logging&revision=2017-09-18http://openconfig.net/yang/header-fields?module=openconfig-packet-match&revision=2017-12-15http://openconfig.net/yang/lldp?module=openconfig-lldp&revision=2016-05-16urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&revision=2011-06-01http://openconfig.net/yang/network-instance-l3?module=openconfig-network-instance-l3&revision=2017-12-13http://openconfig.net/yang/rsvp?module=openconfig-mpls-rsvp&revision=2017-08-24http://arista.com/yang/experimental/eos/qos/acl?module=arista-exp-eos-qos-acl-config&revision=2017-09-26http://openconfig.net/yang/system/terminal?module=openconfig-system-terminal&revision=2017-09-18http://openconfig.net/yang/mpls-sr?module=openconfig-mpls-sr&revision=2017-08-24http://openconfig.net/yang/relay-agent?module=openconfig-relay-agent&revision=2016-05-16http://arista.com/yang/experimental/eos/qos/config?module=arista-exp-eos-qos-config&revision=2017-09-26http://openconfig.net/yang/isis-lsdb-types?module=openconfig-isis-lsdb-types&revision=2017-08-24http://arista.com/yang/openconfig/interfaces/augments?module=arista-intf-augments&revision=2017-10-01http://arista.com/yang/openconfig/network-instance/vlan/augments?module=arista-vlan-augments&revision=2017-10-01http://arista.com/yang/cert/gnoi-cert?module=arista-gnoi-cert&revision=2018-01-15http://openconfig.net/yang/vlan?module=openconfig-vlan&revision=2017-07-14http://arista.com/yang/experimental/eos/qos?module=arista-exp-eos-qos&revision=2017-09-26http://openconfig.net/yang/system/procmon?module=openconfig-procmon&revision=2017-09-18http://arista.com/yang/openconfig/acl/deviations?module=arista-acl-deviations&revision=2017-11-01http://openconfig.net/yang/bgp-policy?module=openconfig-bgp-policy&revision=2017-07-30http://arista.com/yang/openconfig/isis/deviations?module=arista-isis-deviations&revision=2017-08-21http://openconfig.net/yang/platform-types?module=openconfig-platform-types&revision=2017-12-14http://arista.com/yang/openconfig/relay-agent/deviations?module=arista-relay-agent-deviations&revision=2016-11-21http://openconfig.net/yang/acl?module=openconfig-acl&revision=2017-05-26http://arista.com/yang/openconfig/lacp/deviations?module=arista-lacp-deviations&revision=2017-09-07http://openconfig.net/yang/openconfig-ext?module=openconfig-extensions&revision=2017-04-11http://openconfig.net/yang/openconfig-types?module=openconfig-types&revision=2017-08-16http://openconfig.net/yang/aaa?module=openconfig-aaa&revision=2017-09-18http://openconfig.net/yang/interfaces?module=openconfig-interfaces&revision=2017-12-21http://openconfig.net/yang/openconfig-isis?module=openconfig-isis&revision=2017-08-24http://openconfig.net/yang/platform?module=openconfig-platform&revision=2017-12-14http://openconfig.net/yang/network-instance-types?module=openconfig-network-instance-types&revision=2017-08-24http://arista.com/yang/openconfig/interfaces/deviations?module=arista-intf-deviations&revision=2016-12-28http://arista.com/yang/openconfig/isis/augments?module=arista-isis-augments&revision=2018-01-12http://arista.com/yang/openconfig/lldp/deviations?module=arista-lldp-deviations&revision=2017-09-07urn:ietf:params:xml:ns:yang:ietf-interfaces?module=ietf-interfaces&revision=2014-05-08http://openconfig.net/yang/vlan-types?module=openconfig-vlan-types&revision=2017-07-14http://arista.com/yang/experimental/multicast?module=arista-exp-eos-multicast&revision=2017-10-20http://openconfig.net/yang/sr?module=openconfig-segment-routing&revision=2017-01-12http://arista.com/yang/openconfig/local-routing/deviations?module=arista-local-routing-deviations&revision=2017-11-22http://arista.com/yang/openconfig/mpls/augments?module=arista-mpls-augments&revision=2017-12-21urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2013-07-15http://openconfig.net/yang/policy-forwarding?module=openconfig-policy-forwarding&revision=2017-06-21http://openconfig.net/yang/fib-types?module=openconfig-aft-types&revision=2017-08-24http://openconfig.net/yang/lacp?module=openconfig-lacp&revision=2017-05-05http://openconfig.net/yang/packet-match-types?module=openconfig-packet-match-types&revision=2017-05-26http://openconfig.net/yang/system?module=openconfig-system&revision=2017-12-15http://openconfig.net/yang/routing-policy?module=openconfig-routing-policy&revision=2017-07-14http://arista.com/yang/vlan-translation?module=vlan-translation&revision=2017-11-29http://openconfig.net/yang/mpls-types?module=openconfig-mpls-types&revision=2017-08-24http://arista.com/yang/openconfig/network-instances/deviations?module=arista-netinst-deviations&revision=2017-11-10http://arista.com/yang/experimental/eos?module=arista-exp-eos&revision=2016-11-09http://arista.com/yang/openconfig/bgp/deviations?module=arista-bgp-deviations&revision=2016-02-01http://openconfig.net/yang/aaa?module=openconfig-aaa-tacacs&revision=2017-09-18http://openconfig.net/yang/bgp?module=openconfig-bgp-common-multiprotocol&revision=2017-07-30http://openconfig.net/yang/ospfv2?module=openconfig-ospfv2-area-interface&revision=2017-08-24http://openconfig.net/yang/aft?module=openconfig-aft-pf&revision=2017-08-24http://openconfig.net/yang/openconfig-isis?module=openconfig-isis-routing&revision=2017-08-24http://openconfig.net/yang/aft?module=openconfig-aft-ipv4&revision=2017-08-24http://openconfig.net/yang/aft?module=openconfig-aft-common&revision=2017-08-24http://openconfig.net/yang/ospfv2?module=openconfig-ospfv2-global&revision=2017-08-24http://openconfig.net/yang/openconfig-isis?module=openconfig-isis-lsp&revision=2017-08-24http://openconfig.net/yang/aft?module=openconfig-aft-ipv6&revision=2017-08-24http://openconfig.net/yang/network-instance?module=openconfig-network-instance-l2&revision=2017-12-13http://openconfig.net/yang/bgp?module=openconfig-bgp-neighbor&revision=2017-07-30http://openconfig.net/yang/ospfv2?module=openconfig-ospfv2-area&revision=2017-08-24http://openconfig.net/yang/policy-forwarding?module=openconfig-pf-forwarding-policies&revision=2017-06-21http://openconfig.net/yang/bgp?module=openconfig-bgp-common&revision=2017-07-30http://openconfig.net/yang/ospfv2?module=openconfig-ospfv2-common&revision=2017-08-24http://openconfig.net/yang/ospfv2?module=openconfig-ospfv2-lsdb&revision=2017-08-24http://openconfig.net/yang/mpls?module=openconfig-mpls-igp&revision=2017-08-24http://openconfig.net/yang/aft?module=openconfig-aft-mpls&revision=2017-08-24http://openconfig.net/yang/bgp-types?module=openconfig-bgp-errors&revision=2017-07-30http://openconfig.net/yang/policy-forwarding?module=openconfig-pf-interfaces&revision=2017-06-21http://openconfig.net/yang/bgp?module=openconfig-bgp-peer-group&revision=2017-07-30http://openconfig.net/yang/mpls?module=openconfig-mpls-te&revision=2017-08-24http://openconfig.net/yang/policy-forwarding?module=openconfig-pf-path-groups&revision=2017-06-21http://openconfig.net/yang/aft?module=openconfig-aft-ethernet&revision=2017-08-24http://openconfig.net/yang/bgp?module=openconfig-bgp-common-structure&revision=2017-07-30http://openconfig.net/yang/bgp?module=openconfig-bgp-global&revision=2017-07-30http://openconfig.net/yang/mpls?module=openconfig-mpls-static&revision=2017-08-24http://openconfig.net/yang/aaa?module=openconfig-aaa-radius&revision=2017-09-182596996162]]>]]><br> |
I don’t know, if it’s problem only of Arista vEOS, as I explained previously about VXLAN L3 VNI (link), or Arista EOS in general is affected. I hope colleagues from Arista could clarify this problem.
Also there is interesting fact that Arista sends all capabilities in a single line without “/n” split between lines containing different capabilities, like Nokia and Cisco does.
#2. Arista EOS. Get the interface configuration using OpenConfig
Just in the same fashion we did two times, let’s create two interfaces from CLI to verify the output of NETCONF RPC reply message in OpenConfig YANG data model for interfaces:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | vEOS2# show run<br> !<br> interface Ethernet1<br> no switchport<br> !<br> interface Ethernet1.23<br> logging event link-status<br> encapsulation dot1q vlan 23<br> ip address 10.22.33.22/24<br> ipv6 address fc00::10:22:33:22/112<br> !<br> interface Loopback0<br> ip address 10.0.0.22/32<br> ipv6 address fc00::10:0:0:22/128<br> !<br> ip routing<br> !<br> end<br> |
Brief check that interfaces are up and running at Arista EOS based leaf vEOS2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | vEOS2#show ip int br<br> Interface IP Address Status Protocol MTU<br> Ethernet1 unassigned up up 1500<br> Ethernet1.23 10.22.33.22/24 up up 1500<br> Loopback0 10.0.0.22/32 up up 65535<br> Management1 192.168.44.82/24 up up 1500<br> !<br> !<br> vEOS2#show ipv6 int br<br> Interface Status MTU IPv6 Address Addr State Addr Source<br> ---------- ------- ------ ---------------------------- ------------ -----------<br> Et1.23 up 1500 fe80::250:56ff:fe73:2e21/64 up link local<br> fc00::10:22:33:22/112 up config<br> Lo0 up 65535 fe80::ff:fe00:0/64 up link local<br> fc00::10:0:0:22/128 up config<br> |
Now we can collect info through NETCONF using “edit-config” message:
1 2 | #252<br> <!--?xml version="1.0" encoding="utf-8"?--> |
1 | <br> |
1 |
1 | <br> |
1 |
1 | <br> |
1 | ## |
1 2 3 | #222<br> Management1<br> #35 |
1 | <code lang="xml"> |
#23
true
#96
300
#12
0
#24
Management1
#27
ethernetCsmacd
#9
1 | <code lang="xml"> |
#175
false
#28
false
#34
false
#15
1 | <code lang="xml"> |
#44
00:00:00:00:00:00
#38
SPEED_UNKNOWN
#100
false
#9
1 | <code lang="xml"> |
#11
1 | <code lang="xml"> |
#45
0
#24
0
#9
1 | <br> |
1 | #97<br> |
1 | <code lang="xml"> |
#30
192.168.44.82
#33 24 #9
#10
1 | <code lang="xml"> |
#12
#32
false
#15
1500
#9
#7
1 | <code lang="xml"> |
#87
false
#15
1500
#9
#7
#15
1 | <code lang="xml"> |
#16
1 | <code lang="xml"> |
#12
1 | <code lang="xml"> |
#33
Ethernet3
#35
#23
true
#96
300
#12
0
#22
Ethernet3
#27
ethernetCsmacd
#9
#175
false
#28
false
#34
false
#15
#44
00:00:00:00:00:00
#38 SPEED_UNKNOWN #100
false
#9
#11
#45
0
#24
0
#9
#87
false
#15
1500
#9
#7
#87
false
#15
1500
#9
#7
#15
#16
#12
#33
Ethernet2
#35
#23
true
#96
300
#12
0
#22
Ethernet2
#27
ethernetCsmacd
#9
#175
false
#28
false
#34
false
#15
#44
00:00:00:00:00:00
#38 SPEED_UNKNOWN #100
false
#9
#11
#45
0
#24
0
#9
#87
false
#15
1500
#9
#7
#87
false
#15
1500
#9
#7
#15
#16
#12
#33
Ethernet1
#35
#23
true
#96
300
#12
0
#22
Ethernet1
#27
ethernetCsmacd
#9
#175
false
#28
false
#34
false
#15
#44
00:00:00:00:00:00
#38 SPEED_UNKNOWN #100
false
#9
#11
#45
0
#24
0
#9
#66
#12
#31
true
#15
1500
#9
#7
#87
false
#15
1500
#9
#7
#15
#31
23
#35
#23
true
#17
23
#9
#95
1 | <code lang="xml"> |
#28
10.22.33.22
#33 24 #9
#10
1 | <code lang="xml"> |
#12
#31
true
#15
1500
#9
#7
1 | <code lang="xml"> |
#101
1 | <code lang="xml"> |
#34
fc00::10:22:33:22
#34 112 #9
#10
1 | <br> |
1 |
1 2 3 4 5 6 | #12<br> #32<br> false<br> #15<br> 1500<br> #9 |
1 | <br> |
1 | #7 |
1 | <code lang="xml"> |
#15
1 | <code lang="xml"> |
#16
1 | <code lang="xml"> |
#12
1 | <code lang="xml"> |
#13
1 | <code lang="xml"> |
#19
1 | <br> |
1 | ##<br> |
Well, output in Arista vEOS is a bit more difficult to read. We should remove all “#xx” framing symbols and add appropriate “/n” splitters to make it readable by human. I don’t provide the formatted output as it’s quite long (and in A4 pages’ size I’m already close to 60 pages, so I’m not sure you are still reading this article).
There are a couple of points we can spot in the output above:
- It’s more similar to Cisco in terms of naming additional schemes, like <ipv4 xmlns=”http://openconfig.net/yang/interfaces/ip”>
- It mixes Arista-proprietary parameters together with OpenConfig, like adding <sfp-1000base-t xmlns=”http://arista.com/yang/openconfig/interfaces/augments”>
- It DOESN’T contain output of interface Loopback0.
Regarding the last point, again I don’t know, if it’s the problem of Arista EOS in general or Arista vEOS in particular.
#3. Arista EOS. Edit the interface configuration using OpenConfig
As I have configured manually only very small subset of parameters, like IPv4/IPv6 addresses and VLANs, I hope it would be enough to configure them over NETCONF using OpenConfig YANG model as well, without providing rest of parameters. Otherwise we again are going away from truly automation using single data model for devices and single Jinja2 template for NETCONF.
Just in the same way, we’ve done for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR, we will configure additional subinterface on Arista EOS based leaf vEOS2:
1 2 | #1700<br> <!--?xml version="1.0" encoding="utf-8"?--> |
1 | <code lang="xml"> |
Ethernet1
1 | <code lang="xml"> |
Ethernet1
ethernetCsmacd
true
1 | <code lang="xml"> |
23
1 | <code lang="xml"> |
23
true
1 | <br> |
1 |
1 2 | <code lang="xml"><br> 10.22.33.22 |
1 | <code lang="xml"> |
24
1 | <br> |
1 |
1 |
1 | <code lang="xml"> |
1 | <code lang="xml"> |
fc00::10:22:33:22 112
1 | <code lang="xml"> |
1 | <code lang="xml"><code lang="xml"> |
23
1 | <code lang="xml"><br> |
1 | <code lang="xml"> |
1 | <code lang="xml"> |
24
24
true
1 | <code lang="xml"> |
10.22.44.22 24
1 | <code lang="xml"> |
1 | <code lang="xml"><br> |
1 | <code lang="xml"> |
fc00::10:22:44:22 112
1 | <code lang="xml"> |
1 | <code lang="xml"><code lang="xml"> |
24
1 | <code lang="xml"><br> |
1 | <code lang="xml"> |
1 | <code lang="xml"> |
##
1 | <br> |
1 |
1 | #97 |
1 | <br> |
1 | ##<br> |
And here we come to the point that no changes are applied despite “OK” response from vEOS2 and positive information in logs:
1 2 3 4 | vEOS2#<br> Jul 23 17:37:51 vEOS2 ConfigAgent: %SYS-5-CONFIG_SESSION_ENTERED: User root entered configuration session session345514592380 on UnknownTty (UnknownIpAddr)<br> Jul 23 17:37:53 vEOS2 ConfigAgent: %SYS-5-CONFIG_SESSION_COMMIT_SUCCESS: User root committed configuration session session345514592380 successfully on UnknownTty (UnknownIpAddr)<br> Jul 23 17:37:53 vEOS2 ConfigAgent: %SYS-5-CONFIG_SESSION_EXITED: User root exited configuration session session345514592380 on UnknownTty (UnknownIpAddr)<br> |
If we take a look into configuration of Arista vEOS, there are no changes:
1 2 3 4 5 6 7 8 9 10 11 12 13 | vEOS2#show run<br> ! Command: show running-config<br> ! device: vEOS2 (vEOS, EOS-4.20.7M)<br> !<br> interface Ethernet1<br> no switchport<br> !<br> interface Ethernet1.23<br> logging event link-status<br> encapsulation dot1q vlan 23<br> ip address 10.22.33.22/24<br> ipv6 address fc00::10:22:33:22/112<br> !<br> |
I have done some researches in one or another direction, but still I haven’t succeeded to make it working for Arista EOS. I hope, colleagues from Arista could provide some feedback.
#4. Arista EOS. Ansible for OpenConfig with Cisco
From the automation point of view there is no difference comparing to previous two examples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | +--ansible<br> +--128_lab.yml<br> +--group_vars<br> | +--arista<br> | | +--arista_host.yml<br> | +--cisco<br> | | +--cisco_host.yml<br> | +--nokia<br> | +--nokia_host.yml<br> +--roles<br> +--arista<br> | +--128_lab<br> | +--tasks<br> | | +--main.yml<br> | +--templates<br> | | +--interfaces.j2<br> | +--vars<br> | +--oc_vEOS2.yml<br> +--cisco<br> | +--128_lab<br> | +--tasks<br> | | +--main.yml<br> | +--templates<br> | | +--interfaces.j2<br> | +--vars<br> | +--oc_vEOS2.yml<br> +--nokia<br> +--128_lab<br> +--tasks<br> | +--main.yml<br> +--templates<br> | +--interfaces.j2<br> | +--network_instance_interfaces.j2<br> +--vars<br> +--oc_vEOS2.yml<br> |
So we just copy, what we have done in Nokia part to Arista:
1 | $ cp roles/nokia/128_lab/ roles/arista/128_lab/ |
Now, as previously, I guide you through key files. This time I do it without further explanation, as I did it twice already.
If you still have questions, refer to previous Cisco IOS XR or Nokia (Alcatel-Lucent) SR OS examples.
Number one is the authentication data:
1 2 3 4 5 6 7 8 | $ cat group_vars/arista/arista_host.yml<br> ---<br> ansible_network_os: eos<br> ansible_user: aaa<br> ansible_ssh_pass: aaa<br> ansible_become: yes<br> ansible_become_method: enable<br> ...<br> |
Number two is the per node parameters:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | $ cat roles/arista/128_lab/vars/oc_vEOS2.yml<br> ---<br> node:<br> hostname: vEOS3<br> interfaces:<br> - name: Loopback0<br> type: softwareLoopback<br> enabled: true<br> subinterfaces:<br> - index: 0<br> ipv4:<br> address:<br> - ip: 10.0.0.33<br> prefix_length: 32<br> ipv6:<br> address:<br> - ip: fc00::10:0:0:33<br> prefix_length: 128<br> - name: Ethernet2<br> type: ethernetCsmacd<br> enabled: true<br> ethernet:<br> auto_negotiate: false<br> subinterfaces:<br> - index: 13<br> enabled: true<br> vlan:<br> vlan_id: 13<br> ipv4:<br> address:<br> - ip: 10.11.33.33<br> prefix_length: 24<br> ipv6:<br> address:<br> - ip: fc00::10:11:33:33<br> prefix_length: 112<br> - index: 23<br> enabled: true<br> vlan:<br> vlan_id: 23<br> ipv4:<br> address:<br> - ip: 10.22.33.33<br> prefix_length: 24<br> ipv6:<br> address:<br> - ip: fc00::10:22:33:33<br> prefix_length: 112<br> ...<br> |
Number three is the Jinja2 template for interfaces:
1 | $ cat roles/arista/128_lab/templates/interfaces.j2 |
1 | <code lang="xml"> |
{% for iface in node.interfaces %}
1 | <code lang="xml"> |
{{ iface.name }}
1 | <code lang="xml"> |
{{ iface.name }}
{% if ansible_network_os == “iosxr” %}
idx:{{ iface.type }}
{% else %}
{{ iface.type }}
{% endif %}
{{ iface.enabled|lower }}
1 | <code lang="xml"> |
{% if iface.subinterfaces is defined %}
1 | <code lang="xml"> |
{% for siface in iface.subinterfaces %}
1 | <code lang="xml"> |
{{ siface.index }}
{% if siface.index != 0 %}
1 | <code lang="xml"> |
{{ siface.index }}
{% if ansible_network_os == “iosxr” %}
{{ iface.name }}.{{ siface.index }}
{% endif %}
{{ siface.enabled|lower }}
1 | <code lang="xml"> |
{% endif %}
{% if siface.ipv4 is defined %}
{% if ansible_network_os != “sros” %}
1 | <code lang="xml"> |
{% else %}
1 | <br> |
1 2 3 4 | {% endif %}<br> {% if ansible_network_os != "iosxr" %}<br> {% endif %}<br> {% for addr in siface.ipv4.address %} |
1 |
1 | <code lang="xml"> |
{{ addr.ip }} {{ addr.prefix_length }}
1 | <code lang="xml"> |
{% endfor %}
{% if ansible_network_os != “iosxr” %}
{% endif %}
1 | <code lang="xml"> |
{% endif %}
{% if siface.ipv6 is defined %}
{% if ansible_network_os != “sros” %}
{% else %}
{% endif %}
{% if ansible_network_os != “iosxr” %}
{% endif %}
{% for addr in siface.ipv6.address %}
1 | <code lang="xml"> |
{{ addr.ip }} {{ addr.prefix_length }}
1 | <br> |
1 |
1 2 3 | {% endfor %}<br> {% if ansible_network_os != "iosxr" %}<br> {% endif %} |
1 | <code lang="xml"> |
{% endif %}
{% if siface.vlan is defined %}
{% if ansible_network_os != “sros” %}
{% else %}
{% endif %}
{{ siface.vlan.vlan_id }}
{% endif %}
1 | <code lang="xml"> |
{% endfor %}
1 | <code lang="xml"> |
{% endif %}
1 | <code lang="xml"> |
{% endfor %}
1 | <br> |
1 |
Point out there is no single change comparing to one we did for Nokia!
Number four is the playbook with tasks:
1 2 3 4 5 | $ cat roles/arista/128_lab/tasks/main.yml<br> ---<br> - name: IMPORTING VARS<br> include_vars:<br> file: oc_{{ inventory_hostname }}.yml |
1 2 3 4 5 | - name: CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT I<br> template:<br> src: interfaces.j2<br> dest: /tmp/oc_{{ inventory_hostname }}_if.conf<br> mode: 0755 |
1 | <code lang="yaml"> |
– name: OPENCOFNIG // CONFIGURING INTERFACES I
netconf_config:
host: “{{ inventory_hostname }}”
username: “{{ ansible_user }}”
password: “{{ ansible_ssh_pass }}”
port: 22
hostkey_verify: false
look_for_keys: false
datastore: running
xml: “{{ lookup (‘template’, ‘interfaces.j2’) }}”
1 | <code lang="yaml"> |
– name: CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT II
template:
src: network_instance_interfaces.j2
dest: /tmp/oc_{{ inventory_hostname }}_ni.conf
mode: 0755
when: ansible_network_os == “sros”
1 | <br> |
1 |
1 2 3 4 5 6 7 8 9 10 11 12 | - name: OPENCOFNIG // CONFIGURING INTERFACES II<br> netconf_config:<br> host: "{{ inventory_hostname }}"<br> username: "{{ ansible_user }}"<br> password: "{{ ansible_ssh_pass }}"<br> port: 22<br> hostkey_verify: false<br> look_for_keys: false<br> datastore: running<br> xml: "{{ lookup ('template', 'network_instance_interfaces.j2') }}"<br> when: ansible_network_os == "sros"<br> ...<br> |
The key point here is port. We have changes it to “22” instead of “830”. Also we have explicitly put datastore as “running” cause it looks like Arista doesn’t support candidate config. There is default fall back, so it isn’t mandatory to specify this. I’ve done it just for sake of clarity.
So the work is done in the same fashion it was done for previous two vendors. If we test the execution of this Ansible playbook, it looks nice :
1 | $ ansible-playbook ansible/128_lab.yml --limit=arista |
1 2 | PLAY [cisco] **********************************************************************************************<br> skipping: no hosts matched |
PLAY [nokia] **********************************************************************************************
skipping: no hosts matched
PLAY [arista] *********************************************************************************************
TASK [Gathering Facts] ************************************************************************************
ok: [vEOS2]
TASK [arista/128_lab : IMPORTING VARS] ********************************************************************
k: [vEOS2]
TASK [arista/128_lab : CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT I] ***********
ok: [vEOS2]
TASK [arista/128_lab : OPENCOFNIG // CONFIGURING INTERFACES I] ********************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: SSHError: Could not open socket to vEOS1:22
changed: [vEOS2]
TASK [arista/128_lab : CREATING TEMPORARY FILE TO MANUALLY CHECK THAT EDIT-CONFIG IS CORRECT II] **********
skipping: [vEOS2]
TASK [arista/128_lab : OPENCOFNIG // CONFIGURING INTERFACES II] *******************************************
skipping: [vEOS2]
to retry, use: –limit @/home/aaa/ansible/128_lab.retry
1 |
1 2 | PLAY RECAP ************************************************************************************************<br> vEOS2 : ok=4 changed=1 unreachable=0 failed=0<br> |
But again, there are no changes in the configuration of the Arista vEOS2 after the playbook is implemented.
Here is the Ansible playbooks created in this lab:
Lessons learned
There are good and bad news:
- The good news is that vendors are working on the introduction of OpenConfig in their NOSs. And the article shows that there are a lot of similar in terms of OpenConfig in Cisco, Nokia and Arista.
- The bad news that all vendors has either deviations (something from OpenConfig YANG model isn’t supported) or augments (something vendor specific is added). Both those things you might have seen in the examples provided above.
I hope further development of OpenConfig and IETF YANG models will one day lead to purely programmable in a single manner network using single YANG data model
Greetings and acknowledges
Many thanks for Alex Nichol from Arista for sharing the latest version of Arista vEOS, which supports the latest OpenConfig models implemented in Arista. Thanks for Greg Hankins from Nokia for sharing info on OpenConfig in Nokia and providing configuration guide for VSIM. And special thanks to my friend Nicola Arnoldi, who has shown wonderful ASCII graph editor to me.
Conclusion
In this article we have reviewed what OpenConfig YANG data model is and how this model can be used for configuration of the interfaces for Arista EOS, Cisco IOS XR and Nokia (Alcatel-Lucent) SR OS. In my opinion, the results are quite positive. As we stated in the beginning of the article, in the next one we’ll review the configuration of BGP for undelaying data centre using OpenConfig YANG data model as well. Take care and good bye!
Support us
P.S.
If you have further questions or you need help with your networks, I’m happy to assist you, just send me message. Also don’t forget to share the article on your social media, if you like it.
BR,
Anton Karneliuk
Another great article =)
It’s a pity that OpenConfig models are very scanty. So you have to stick with native vendor models for now.
I can’t even imagine how hard (and maybe impossible ) it would be to develop completely vendor agnostic models.
Hi Kirill,
Thanks! I’m pretty sure everything is possible, and I hope open networking could be enabler to this area. I think that technical part, i.e. translation or adaptation of YANG model is just the visible part of the iceberg.
BR,
Anton