Coding Essentials II – NetDevOps Series, Part 4

Previous posts in the NetDevOps Series are available here.

Let’s continue our review of the different foundational coding building blocks that network engineers need to understand and use when entering the programmability world.

NETCONF and RESTCONF

Now that we understand data models and data transfer formats, we need to consider what protocol to use in order to exchange that information. NETCONF and RESTCONF are different protocols that you will need to use depending on the availability provided by your platform.

NETCONF

Network Configuration Protocol (RFC 6241), is a network management protocol developed and standardized by the Internet Engineering Task Force (IETF). It supports a rich set of functionality to manage configuration and operational data, being able to manage network devices running, candidate and startup configurations. The NETCONF protocol defines a simple mechanism through which a network device can be managed, configuration data can be retrieved, and new configuration data can be uploaded and manipulated. The NETCONF protocol uses Remote Procedure Calls (RPCs) for its paradigm, such as get-config, edit-config, or get. A client encodes an RPC in XML and sends it to a server using a secure, connection-oriented session (such as Secure Shell Protocol [SSH]). The client (application) initiates a connection using SSH port 830 towards the server (network device). The server responds with a reply encoded in XML, and there is a capability exchange during session initiation, using XML encoding.

Let’s take a look at an example on how we could use Python to connect to a device via NETCONF.

from ncclient import manager
import xml
import xml.dom.minidom

with manager.connect(host=RW_HOST, port=PORT, username=USER, password=PASS, hostkey_verify=False, device_params={'name': 'default'}, allow_agent=False, look_for_keys=False) as m:
# XML filter to issue with the get operation
# IOS-XE 16.6.2+ YANG model called "ietf-interfaces"
interface_filter = '''
<filter xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>GigabitEthernet1</name>
</interface>
</interfaces-state>
</filter>
'''
result = m.get(interface_filter)
xml_doc = xml.dom.minidom.parseString(result.xml)

We start by importing the NETCONF and XML libraries we will be using (ncclient is a Python library that facilitates client-side scripting and application development around the NETCONF protocol). Then we connect to the device IP (RW_HOST), using the specified port for SSH (PORT) and the required credentials (USER/PASS). Once connected we define specifically what we want to receive (interface_filter) and make the request (m.get). get is the method used to request operational data, but you could also ask for configuration data using get-config, or modify that configuration using edit-config. Final step is just to parse the result into a Python dictionary, using the minidom library, to be able to work it.

And voilá, you get an XML response showing operational data for the requested interface.

<rpc-reply message-id="urn:uuid:50bf9d6e-7e5c-4182-ae6b-972a055ceef7" 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</name>
<admin-status>up</admin-status>
<oper-status>up</oper-status>
<phys-address>00:0c:29:6c:81:06</phys-address>
<speed>1024000000</speed>
<statistics>
<in-octets>5432293472</in-octets>
<in-unicast-pkts>28518075</in-unicast-pkts>
……………
<out-octets>2901845514</out-octets>
<out-unicast-pkts>18850398</out-unicast-pkts>
</statistics>
</interface>
</interfaces-state>
</rpc-reply>

RESTCONF

RESTCONF (RFC 8040) is based on the idea of adding a REST API to NETCONF. It can manage manage configuration and operational data defined in YANG models, and the URLs, HTTP verbs, and Request bodies are automatically generated from those associated YANG models. RESTCONF uses HTTP(S) as transport, and supports both XML and JSON as data transfer formats, while NETCONF only supports XML. Also, RESTCONF supports only a sub-set of NETCONF, so not all operations are supported.

Remember that since REST principles are being used, RESTCONF is based on stateless connections. As such, every application using RESTCONF writes directly to the running configuration, with no support for candidate configuration.
Being based on REST, RESTCONF supports the following methods:
• GET, to read/retrieve info
• POST, to create a new record
• PATCH, to update only some values of an existing record
• PUT, to update all values of an existing record
• DELETE, to erase an existing record
Let’s take a look at how to use it.

url = 'https://RO_HOST/restconf/data/interfaces-state/interface=GigabitEthernet1'

header = {'Content-type': 'application/yang-data+json',
'accept': 'application/yang-data+json'}

response = requests.get(url, headers=header, verify=False, auth=ROUTER_AUTH)
interface_info = response.json()
oper_data = interface_info['ietf-interfaces:interface']

In this case we are sending a HTTP(S) request to our network device REST API. The URL structure will include the network device IP address (RO_HOST) and the resource we are asking about (interface=GigabitEthernet1). Then we will have to define the HTTP headers to send, specifying in this case what is the content type we are sending (YANG encoded in JSON) and the content we expect to receive in the response (YANG encoded in JSON). Finally we parse the JSON into a Python dictionary and extract the relevant info from the structured data.

{
"ietf-interfaces:interface": {
"name": "GigabitEthernet1",
"admin-status": "up",
"oper-status": "up",
"last-change": "2018-01-17T21:49:17.000387+00:00",
"phys-address": "00:0c:29:6c:81:06",
"speed": 1024000000,
"statistics": {
"in-octets": 5425386232,
"in-unicast-pkts": 28489134,
……………
"out-octets": 2899535736,
"out-unicast-pkts": 18844784
}
}
}

So the overall picture looks like this now:

Network devices information is modelled in YANG to make it consistent, independent of the underlying infrastructure. Then than information can be represented with JSON or XML, and accessed by mean of NETCONF or RESTCONF from a remote client.

In my next post we will continue exploring some of the required coding essentials. See you in a couple of weeks, stay tuned!

Any questions or comments please let me know in the comments section below, Twitter or LinkedIn.

Join DevNet: access the learning labs, docs, and sandboxes you need for network automation. And check out this expert-led, video course for learning network programmability basics.