cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
15311
Views
51
Helpful
13
Comments
aradford
Cisco Employee
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

13 Comments
Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: