What You’ll Learn

What You’ll Need

What You’ll Need to Set Up

Basics

NETCONF is an XML RPC that communicates over SSH utilizing TCP port 830. It is often used to provide an API to network devices.

Some of the features of NETCONF are:

YANG Data Models

Model-driven API would not be possible without YANG data models provided by IETF, ITU, OpenConfig, etc., and also provided by networking vendors, like Cisco, for device-specific features and functionality.

These data models define the structure of the NETCONF RPC XML data. How the YANG models are defined and utilized by developers is a larger subject we will not be covering here. What we will cover is how to get data from a network device through some exploration, then parse it and display the results.

NETCONF Protocol Stack

LayerExample
ContentXML Documents (XSD, YANG, etc.)
Operations<get-config>, <get>, <copy-config>, <commit>, <validate>, <lock>, <unlock>, <edit-config>, <delete-config>
Messages<rpc>, <rpc-reply>
ProtocolsSSHv2, TLS

This data encoding is used for NETCONF XML, and you can see the operations listed as they are represented in XML. The messages being passed between the client and the device (server) are encapsulated in <rpc> ...</rpc> and <rpc-reply> ... </rpc-reply>.

NETCONF Data Stores

NETCONF Data Stores

NETCONF has this concept of data stores. For Cisco IOS XE, you can see the <running> and <startup>, which should look familiar. Something to keep in mind is not all platforms and devices have the <candidate> data store.

Some key features of the data stores are:

NETCONF Transport

NETCONF Data Stores

NETCONF is a client/server type of conversation where the client makes a connection, the server responses with supported capabilities, the client sends the capabilities it supports as well as a request, then the server performs the request and issues a response. The connection can be used for additional operations until it has been disconnected.

NETCONF Transport Example

Client Request

NETCONF Request Example

Server Response

NETCONF Response Example

More Reading on This!

Introduction

At this point, we are going to use your local Python 3.6+. If you have not installed Python 3.6+, please refer to the linked setup instructions in the Overview.

We will be discussing the Python script in sections. As each section is discussed, copy and paste each code block in order to your script, so when we get to the end, you will have a fully functioning script.

Python Standard Library Imports

Time to construct our Python script to get the hostname and version of the network device.

First, we need to import the needed Python libraries.

# Include python modules
from lxml import etree
from ncclient import manager

These are the libraries we will be using in this script.

The from lxml import etree exposes the etree method used to work with XML data.

The from ncclient import manager exposes the manager method from the nclient library. This is the NETCONF client connection manager.

Define Connection Information

# Request information
username = "developer"
password = "C1sco12345"
hostname = "sandbox-iosxe-recomm-1.cisco.com"
port = "830"

Here, we are setting some NETCONF connection-related variables.

Note: For the purpose of this exercise, we are connecting the DevNet Always On CSR 1000V Sandbox for our NETCONF request. If you are having problems connecting, please make sure the Sandbox is available.

Make NETCONF Connection

# Make NETCONF connection
device = manager.connect(host=hostname, port=port,
    username=username, password=password,
    hostkey_verify=False, device_params={},
    allow_agent=False, look_for_keys=False)

Now we use the manager we imported from the ncclient library to make the NETCONF connection, using all the variables we have previously defined.

Make NETCONF Request

First, we need to define the xml_filter to get the elements we are interested in retrieving.

# Define XML Filter Request
xml_filter = """
    <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
     <version />
     <hostname />
    </native>
"""

Now we can make the request to the device.

# Request data from device with XML Filter
netconf_response = device.get(('subtree', xml_filter))

Parse the Response

First, we are going to print the XML that the device returned but formatted for us noncomputer types to read. The last print statement is where the “magic” is happening. The ncclient library holds the response in memory, and we use the lxml etree method to format the XML.

# Print the XML Response
print('XML Response:')
print('-' * 80)
print(etree.tostring(netconf_response.data_ele, pretty_print=True).decode('utf-8'))

Because we are dealing with XML here, we have to “find” the “hostname” and “version” in the response. But to do that, we need to define the XML namespaces to search. Here, we define the namespaces for the IOS XE native YANG model.

# Define XML Namespace for Find
ns_find = {
  None: "http://cisco.com/ns/yang/Cisco-IOS-XE-native",
}

Now we can use the response object, calling the find method on the data to find the “hostname” and “version”.

# Find the elements we want values
device_hostname = netconf_response.data.find(".//hostname", namespaces=ns_find).text
device_version = netconf_response.data.find(".//version", namespaces=ns_find).text

It is important to note that YANG data models do define this structure. Using tools like Cisco YANG Suite, you can load the YANG models to explore the structure of the API.

Print Hostname and Version

# Print the results
print('-' * 80)
print(f'Hostname: {device_hostname}')
print(f'Version: {device_version}')
print("\n")

Finally, we print the hostname and version of the network device using f-string templates.

workstation $ python3 get_iosxe_version.py
XML Response:
--------------------------------------------------------------------------------
<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/Cisco-IOS-XE-native">
    <version>16.9</version>
    <hostname>Router</hostname>
  </native>
</data>

--------------------------------------------------------------------------------
Hostname: Router
Version: 16.9

Awesome—it worked!

The complete script used today in this exercise is available for download.

While this is a simple script utilizing NETCONF API on Cisco IOS XE to get the hostname and version, it still shows the basics of how to use Python and the ncclient and lxml libraries to utilize the NETCONF API. There are a few things that can be done to extend the Python script beyond the basic demonstration in this exercise to make it more functional, but that is for a later time.

I hope this exercise was helpful and inspires you to learn more!

Training Resources

Learn More