cancel
Showing results for 
Search instead for 
Did you mean: 
cancel

Getting Started with NETCONF/YANG – Part 2

9334
Views
46
Helpful
12
Comments
Cisco Employee

Introduction

Cisco has recently introduced NETCONF/YANG support across the enterprise network portfolio.  This capability is available in the 16.3 XE code for routers and switches.  NETCONF/YANG allows programmatic access to network devices using structured data.

Blog Getting Started with NETCONF/YANG – Part 1 covered some of the basics to get started with NETCONF/YANG.  It showed how to get access to device configuration as well as configuration changes.

Making things Easier – NCC

ncc (netconf client) is a tool we have been working on to make it a bit easier to get started learning about NETCONF/YANG.  You can download it from github at https://github.com/CiscoDevNet/ncc .

Getting Started with NETCONF/YANG – Part 2

To create a virtual environment for python and install the required packages, follow the instructions below.  If you are new to python and want to understand a little more about virtual environments, take a look at this article http://docs.python-guide.org/en/latest/dev/virtualenvs

This is assuming a LINUX or Mac. 

git clone https://github.com/CiscoDevNet/ncc.git

cd ncc

virtualenv v

. v/bin/activate

pip install --upgrade pip

pip install -r requirements.txt

For a Mac you might need the following two commands if you do not have pip and virtualenv installed.

sudo easy_install pip

sudo pip install virtualenv

You will need a device running IOS-XE 16.3.2 or greater for the examples below.  The following example just connects to the device and gets a list of capabilities

$ ./ncc.py --host 10.10.6.2 --username sdn --password password --capabilities

urn:cisco:params:xml:ns:yang:cisco-qos-common?module=cisco-qos-common&revision=2015-05-09

urn:cisco:params:xml:ns:yang:cisco-environment?module=cisco-environment&revision=2015-04-09

urn:cisco:params:xml:ns:yang:cisco-process-cpu?module=cisco-process-cpu&revision=2015-04-09

urn:cisco:params:xml:ns:yang:cisco-efp-stats?module=cisco-efp-stats&revision=2015-07-07

<SNIPPED>

Structured Data – YANG

One thing we skipped over last time was YANG and why structured is so important.   One question people often ask, is what is wrong with SNMP?  SNMP also provides structured data.   The SNMP Object ID (OID) mappings are structured but quite challenging to manage. For a start, it is quite difficult to tell what is operational data (statistics) vs configuration data.

snmp.png

YANG is much simpler and easier to understand.  Looking at the interfaces module, there are a couple of core concepts.

  • A container called "interfaces".  A container only has a single instance (which differentiates it from a list).  It can have multiple components, in this example there is just one ("interface").
  • A list called "interface".  There can be multiple elements in a list (as you would expect with an interface list).  A list requires a key to reference list members. In this case the key is a leaf called "name".
  • A leaf node is an attribute that holds data.  Examples below include "name" and "description" etc.

interface-yang.png

This module contains all of the configuration data for an interface.  In reality there are many more leaves as these modules can be augmented. There will be an augmentation example very soon.

Yang models can be mapped quite simply into xml payloads and searched using filters/xpath statements as seen in earlier blogs.    ncc.py contains some prebuilt filters to demonstrate this.   To get a list of ncc filters, you can run the following command.

$./ncc.py --host 10.10.6.2 --username sdn --password password --list-filters --snippets ./snippets-xe

Named filters:

  MIB-filter :{ "MIB" : "" }

  confd-state

  ietf-intf-named-description :{ "INTF_NAME" : "" }

  ietf-intf-named :{ "INTF_NAME" : "" }

  ietf-intf

  native-intf-named :{ "INTF_NAME" : "" }

  netconf-state

To get the configuration of all of the interfaces, use the "ietf-intf" filter.

$ ./ncc.py --host 10.10.6.2 --username sdn --password password --snippets ./snippets-xe --get-running --named-filter ietf-intf

<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">

  <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">

    <interface>

      <name>GigabitEthernet0/0</name>

      <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>

      <enabled>true</enabled>

      <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"/>

      <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"/>

    </interface>

Notice the "interfaces", "interface", "name", "type" and "enabled" tags from the YANG module.  There is another component "ipv4" (and "ipv6").  This is an example of augmentation, and will be covered later.

The contents of the filter "ietf-intf" are shown below.  It is very simple, just extracting the <interfaces> container from the configuration.

$ cat snippets-xe/filters/ietf-intf.tmpl

<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"/>

We can use another filter, to get the configuration of a specific interface.  The string {{INTF_NAME}} is a variable for a jinja template and can be provided as an option.  This allows you to get the configuration of a specific interface.


$ cat snippets-xe/filters/ietf-intf-named.tmpl

<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">

  <interface>

    <name>{{INTF_NAME}}</name>

  </interface>

</interfaces>

This allows you to get the configuration of a specific interface.  For example, to specify interface "GigabitEthernet1/0/1", you would provide a JSON dictionary of  {"variable":"value"}.  In this case '{"INTF_NAME" : "GigabitEthernet1/0/1"}.

$./ncc.py --host 10.10.6.2 --username sdn --password password --snippets ./snippets-xe --get-running --named-filter ietf-intf-named --params '{"INTF_NAME" : "GigabitEthernet1/0/1"}'

<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">

  <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">

    <interface>

      <name>GigabitEthernet1/0/1</name>

      <description>uplink to router</description>

      <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>

      <enabled>true</enabled>

      <diffserv-target-entry xmlns="urn:ietf:params:xml:ns:yang:ietf-diffserv-target">

        <direction>outbound</direction>

        <policy-name>EasyQos-Egress</policy-name>

      </diffserv-target-entry>

      <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">

        <address>

          <ip>10.10.6.2</ip>

          <netmask>255.255.255.0</netmask>

        </address>

      </ipv4>

      <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"/>

    </interface>

  </interfaces>

</data>

Again, you can see that the "interfaces" module has been augmented with extra capabilities including <diffserv-target-entry.

Augmenting Modules

We saw earlier that the interfaces module had IP attributes that were not defined in the module.   A hint to finding them is contained in the namespace <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">.  The module "ietf-ip" will contain the augmentation of the interfaces module.

All of the Modules are published on github,  Cisco specific modules are located here https://github.com/YangModels/yang/tree/master/vendor/cisco/xe/1632  and standard models (e.g. IETF) are here https://github.com/YangModels/yang/tree/master/standard/ietf/RFC

The ietf.ip module can be downloaded here (in a later blog we will cover downloading the modules directly from the device).

https://github.com/YangModels/yang/blob/master/standard/ietf/RFC/ietf-ip%402014-06-16.yang

The file "ietf-ip.yang" file, contains the following lines:

<SNIPPED>

/*

  * Configuration data nodes

  */

augment "/if:interfaces/if:interface" {

   description

     "Parameters for configuring IP on interfaces.

      If an interface is not capable of running IP, the server

      must not allow the client to configure these parameters.";

   container ipv4 {

     presence

       "Enables IPv4 unless the 'enabled' leaf

        (which defaults to 'true') is set to 'false'";

     description

       "Parameters for the IPv4 address family.";

     leaf enabled {

       type boolean;

       default true;

       description

<SNIPPED>

interfaces/interface is being augmented with containers and leaves for ipv4.

We can visualise these extensions using the pyang tool, then look at the ietf-ip.html file in a browser. (I have saved the .yang files in a directory called YANG)

pyang -f jstree YANG/ietf-interfaces.yang YANG/ietf-ip.yang > /tmp/ietf-ip.html

ietf-int-ext.png

This shows the extra attributes added to the interface for ipv4 and ipv6 addresses.

Operational Data (oper-data)

NETCONF uses a Remote Procedure Call (RPC) approach.  We saw two examples of this earlier, <get-config> and <edit-config>. These were the two operations used to access and change the configuration.

NETCONF also supports a <get> RPC call.  This is used for "operational data" or statistics on the device.

In order to enable operational data, a chunk of NETCONF configuration needs to be applied.   We will use the "ncc.py" tool to do this.

To simplify the command line options, we set some environment variables to make using ncc.py a bit simpler.  These will set a default username, password and snippets directory.

export NCC_USERNAME=sdn

export NCC_PASSWORD=password

export NCC_SNIPPETS=snippets-xe

First, get the list of current configuration templates.   The "--list-templates" option does this.  Remember it is using the snippets directory specified in the environment variable above.


$ ./ncc.py --host 10.10.6.2  --list-templates

Edit-config templates:

  00-oper-data-enable-16.4

  00-oper-data-enable

  00-snmp-config

  01-oper-data-disable

  01-snmp-config-disable

  native-intf-vlan-change :{ "INTF_NAME" : "","VLAN" : "" }

We want to apply the 00-oper-data-enable template.  Take a look at the contents first.

$ cat snippets-xe/editconfigs/00-oper-data-enable.tmpl

<config>

      <netconf-yang xmlns="http://cisco.com/yang/cisco-self-mgmt">

        <cisco-odm xmlns="http://cisco.com/yang/cisco-odm">

         <polling-enable>true</polling-enable>

          <on-demand-default-time>30000</on-demand-default-time>

          <on-demand-enable>false</on-demand-enable>

          <actions>

<action-name>parse.showACL</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

<action-name>parse.showArchive</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

            <action-name>parse.showEnvironment</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

<action-name>parse.showFlowMonitor</action-name>

            <polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

<action-name>parse.showInterfaces</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

<action-name>parse.showIpRoute</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

            <action-name>parse.showMemoryStatistics</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

<action-name>parse.showPlatformSoftware</action-name>

            <polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

<action-name>parse.showProcessesCPU</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

          <actions>

<action-name>parse.showProcessesMemory</action-name>

<polling-interval>120000</polling-interval>

            <mode>poll</mode>

          </actions>

        </cisco-odm>

      </netconf-yang>

  </config>

This shows the polling that will be enabled on a 120second update cycle.  "parse.showInterfaces" enables interface statistics.

Now enable operational data using the following command.

$ ./ncc.py --host 10.10.6.2  --do-edits 00-oper-data-enable

We can now get oper-data. Remember from the earlier example of ietf-interfaces, there was a container called "interfaces-state". We will use an xpath instead of a filter, but it achieves a similar result. The first example will get all stats for all interfaces.

$ ./ncc.py --host 10.10.6.2  --get-oper -x /interfaces-state

<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">

  <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">

    <interface>

      <name>GigabitEthernet0/0</name>

      <oper-status>down</oper-status>

      <phys-address>7c:95:f3:bd:2b:00</phys-address>

      <speed>1000000000</speed>

      <statistics>

        <in-octets>0</in-octets>

        <in-broadcast-pkts>0</in-broadcast-pkts>

        <in-multicast-pkts>0</in-multicast-pkts>

        <in-discards>0</in-discards>

        <in-errors>0</in-errors>

        <out-octets>956</out-octets>

        <out-discards>0</out-discards>

        <out-errors>0</out-errors>

        <in-pkts xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces-ext">0</in-pkts>

        <out-pkts xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces-ext">12</out-pkts>

      </statistics>

    </interface>

    <interface>

      <name>GigabitEthernet1/0/1</name>

      <oper-status>up</oper-status>

      <phys-address>7c:95:f3:bd:2b:64</phys-address>

      <speed>1000000000</speed>

      <statistics>

        <in-octets>17658998</in-octets>

        <in-broadcast-pkts>15360</in-broadcast-pkts>

        <in-multicast-pkts>15359</in-multicast-pkts>

        <in-discards>0</in-discards>

        <in-errors>0</in-errors>

        <out-octets>64951892</out-octets>

        <out-discards>0</out-discards>

        <out-errors>0</out-errors>

        <in-pkts xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces-ext">185652</in-pkts>

        <out-pkts xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces-ext">302509</out-pkts>

      </statistics>

    </interface>

  <SNIPPED>

We could also just get the in-octets for GigabitEthernet1/0/1 if required.  Note the use of '' around the xpath to avoid UNIX shell issues.

$./ncc.py --host 10.10.6.2  --get-oper -x '/interfaces-state/interface[name="GigabitEthernet1/0/1"]/statistics/in-octets'

<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">

  <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">

    <interface>

      <name>GigabitEthernet1/0/1</name>

      <statistics>

        <in-octets>17723702</in-octets>

      </statistics>

    </interface>

  </interfaces-state>

</data>

You can specify multiple keys.  In this case we are interested in both "Gig1/0/1" and "G1/0/9". Note you need to specify the full name of the interface "GigabitEthernet1/0/1".

$./ncc.py --host 10.10.6.2  --get-oper -x '/interfaces-state/interface[name="GigabitEthernet1/0/1" or name="GigabitEthernet1/0/9"]/statistics/in-octets'

<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">

  <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">

    <interface>

    <name>GigabitEthernet1/0/1</name>

      <statistics>

        <in-octets>36977042</in-octets>

      </statistics>

    </interface>

    <interface>

    <name>GigabitEthernet1/0/9</name>

      <statistics>

        <in-octets>0</in-octets>

      </statistics>

   </interface>

  </interfaces-state>

</data>

XPATH supports wildcards, so I could get all of the "in-octets" stats for all interfaces.  In the following example, the string "//" replaces "interface/statistics". Note that "name " is also returned because it is the key for the interface list.

$ ./ncc.py --host 10.10.6.2  --get-oper -x '/interfaces-state//in-octets'

<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">

  <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">

    <interface>

      <name>GigabitEthernet0/0</name>

      <statistics>

        <in-octets>0</in-octets>

      </statistics>

    </interface>

    <interface>

    <name>GigabitEthernet1/0/1</name>

      <statistics>

     <in-octets>17741531</in-octets>

      </statistics>

    </interface>

    <interface>

     <name>GigabitEthernet1/0/10</name>

      <statistics>

        <in-octets>0</in-octets>

      </statistics>

    </interface>

    <interface>

    <name>GigabitEthernet1/0/11</name>

      <statistics>

        <in-octets>0</in-octets>

      </statistics>

    </interface>

    <interface>

     <name>GigabitEthernet1/0/12</name>

      <statistics>

        <in-octets>0</in-octets>

      </statistics>

    </interface>

    <interface>

     <name>GigabitEthernet1/0/13</name>

      <statistics>

        <in-octets>0</in-octets>

      </statistics>

    </interface>

    <interface>

  <SNIPPED>

Remember the XPATH statements can also be implemented as filters.

VLAN template

Remember the change VLAN example from the first blog.  I have turned that into a template that you can run from the ncc.py tool with parameters for interface and vlan.

$ cat snippets-xe/editconfigs/native-intf-vlan-change.tmpl

<config>

<native xmlns="http://cisco.com/ns/yang/ned/ios">

      <interface>

        <GigabitEthernet>

          <name>{{INTF_NAME}}</name>

          <switchport>

            <access>

              <vlan>

                <vlan>{{VLAN}}</vlan>

              </vlan>

            </access>

          </switchport>

        </GigabitEthernet>

      </interface>

    </native>

The template requires two variables "INTF_NAME" and "VLAN". Remember that the interface name will be just the number "1/0/9" as the native model has an implicit "GigabitEthernet" in the outside container.

If you list the templates , you will see an empty JSON dictionary you can provide with parameters for the call.

$ ./ncc.py --host 10.10.6.2 --list-templates

Edit-config templates:

  00-oper-data-enable-16.4

  00-oper-data-enable

  00-snmp-config

  01-oper-data-disable

  01-snmp-config-disable

  native-intf-vlan-change :{ "INTF_NAME" : "","VLAN" : "" }

Now can run the template

$ ./ncc.py --host 10.10.6.2 --do-edits native-intf-vlan-change --params '{"INTF_NAME":"1/0/9","VLAN":"20"}'

A get-running will show the vlan has been changed to vlan 20.

$ ./ncc.py --host 10.10.6.2 --get-running –x '/native//GigabitEthernet[name="1/0/9"]//vlan/vlan'

<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">

  <native xmlns="http://cisco.com/ns/yang/ned/ios">

    <interface>

      <GigabitEthernet>

        <name>1/0/9</name>

        <switchport>

          <access>

            <vlan>

              <vlan>20</vlan>

            </vlan>

          </access>

        </switchport>

      </GigabitEthernet>

    </interface>

  </native>

</data>

What Next?

In the meantime, if you would like to learn more about this, you could come hang out with us in The Cisco Devnet DNA Community.  We’ll have a continuous stream of blogs like this and you can ask questions and we’ll get you answers.

Future blogs will contain more advanced snippet templates, transactions, downloading modules, SNMP MIBs and RESTCONF.

Thanks for reading,

@adamradford123

12 Comments
Contributor

Another good resource to learn about NETCONF and YANG are the tail-f videos (Now Cisco NSO) (Tail-f Systems - YouTube).

At least for me, those videos were helpful to understand both concepts.

Beginner

The yang files for use with pyang are missing in the repo.

Cisco Employee

Thanks for the question.

All of the yang models are published on GitHub in their own repository

yang/vendor/cisco/xe at master · YangModels/yang · GitHub

For example: the 16.3 models i used in these examples are yang/vendor/cisco/xe/1631 at master · YangModels/yang · GitHub

Beginner

Hi Adam,

I was trying out a Python ncclient script to retrieve(using NETCONF get()) an interfaces with a given name from NXOS 7.x switch. The filter I use is shown below, but it give an error.

Is my filter correct? What will be the correct filter to use to get an interface with a given name? Thanks..

int_filter = '''

<xmlns="http://www.cisco.com/nxos:1.0:if_manager">

<interface>Ethernet1/1</interface>

<

'''

Cisco Employee

Hi Adam,

thanks for these articles!

Is my understanding of netconf/yang/xml correct from a 30k foot view? This is in regards to pulling data from the networking device.

1. The network device has various data models describing(structuring) interfaces, running-config, memory etc.

2. When the client wants to extract data (for example interface stats), it uses the netconf protocol.

3. The network device responds to the request by instantiating the data model related to interface stats, filling in the necessary information on that instantiated data model and sends it over the wire in XML format (or JSON format).

thanks

Cisco Employee

Hi Prakash,

a couple of points:

1) Data models describe either configuration (the running-config for example) or operational data (statistics etc, often called oper-data).

2) Netconf is a protocol for accessing and modifying the data.  For example Oper-data can be accessed with the "get" RPC call.  Configuration can be read with "get-config" and written with "edit-config".

3) Netconf only allows XML format.  RESTCONF can do XML or JSON.

Adam

Cisco Employee

thanks, got it!

Thanks. Great post. Couple things

  • I've noticed this post is not fully compatible with IOS-XE 16.5 and up, because in 16.5.1 YANG models have been fully rewritten and are not compatible with the previous IOS-XE versions
  • What's the advantage of NCC compared to Netconf-Console? Just snippets and possibility to supply dynamic values for snippet attributes? I was using netconf-console 2.0.1 which I got from PyPy and it looks very similar to NCC which I had to clone from https://github.com/CiscoDevNet/ncc.git. The only difference is that netconf-console doesn't support snippets, but if XML RPCs are pre-compiled into files, then its capabilities are very similar.
  • Why Cisco haven't implemented 'startup' config capability? or 'candidate' config? Is it planned?
  • Assuming the above is not possible - what is the way to save config via netconf?

Thanks!

Cisco Employee

Hi Tymofiy. We will support the candidate config store in our next major release circa end of July. We do not have a date for when startup store will be supported. You can essentially do a 'copy run start' today, with via the following model --> https://github.com/YangModels/yang/blob/master/vendor/cisco/xe/1681/cisco-ia.yang. Look for the [save-config] RPC.

Cisco Employee

Tymofiy,

ncc has no specific advantages over netconf-console (apart from simple variable substitution in XML files). It's just another tool you can choose to use.

Adam & I make the ncc source code available via github to allow people to see the boiler plate code such that they can get more familiar with how libraries like ncclient can be used. Also, if you want it to do more, please feel free to submit any enhancements as pull requests!

FYI, ncc is now pip-installable as well, "pip install ncc" will get you version 0.2.2.

I would add that there are now copy and delete commands in the 16.8.1 version onwards of Cisco-IOS-XE-rpc.yang.

Cheers,

Einar

@jafrazie Thanks a lot! Good to know it is possible to save config via netconf!

@einarnn Thank you. I will have a look.

Cisco Employee

The link for NETCONF/YANG – Part 1 is broken, could you please provide the right link for part1?

Content for Community-Ad
July's Community Spotlight Awards
This widget could not be displayed.