In this blog post, we'll use Restconf to pull operational data from a Cisco switch. So far in our previous posts, we've looked at getting and changing configuration data. This time, it's all about operational data, which is more like what you see when you use 'show' commands on a switch.
Operational data gives us operational info about what's happening on the switch, like interface stats or VLAN status. With Restconf and Yang, getting this data becomes straightforward.
If you're new to YANG or Restconf, I suggest checking out my previous blog posts for a quick catch-up. They'll help you get the hang of these topics.
Yang for Operational Data
YANG, the data modelling language used in network configuration, also extends to operational data. If you take a look at the YANG GitHub repository, you'll notice modules ending with -oper
. These modules are specifically designed for operational data. Unlike their configuration counterparts, these operational modules focus on the current state of network devices.
For example, alongside the usual VLAN configuration modules, you'll find VLAN operational modules. These allow us to access VLAN information, similar to what you'd expect from show vlan
commands but in a more structured and accessible format.
Get VLAN Info
In this first example, we'll look at how to use Restconf to fetch VLAN information from a Cisco switch, akin to the show vlan
command's output. Let's break down the script and the output.
import requests
import json
requests.packages.urllib3.disable_warnings()
username = 'admin'
password = 'password'
uri = 'https://10.1.1.1:443/restconf/data/Cisco-IOS-XE-vlan-oper:vlans/vlan'
headers = {
"accept": "application/yang-data+json",
"Content-Type": "application/yang-data+json"
}
response = requests.get(
url=uri,
headers=headers,
auth=(username, password),
verify=False)
print(json.dumps(response.json(), indent=2))
The Python script for retrieving VLAN information begins in a familiar fashion, setting up the necessary imports, disabling warnings, and configuring the credentials for accessing the switch. The target URI in this case points to the Restconf endpoint for VLAN operational data (Cisco-IOS-XE-vlan-oper:vlans/vlan
). I did get this URL from the YANG suite as shown below.
After sending a GET request to the switch and receiving the response, the script prints out the JSON data. This data is nicely structured, making it easy to parse and understand, as opposed to the raw text output of traditional CLI commands.
c9300-test#show vlan
VLAN Name Status Ports
---- -------------------------------- --------- -------------------------------
1 default active Te1/0/1, Te1/0/2, Te1/0/3, Te1/0/4, Te1/0/6, Te1/0/7, Te1/0/8, Te1/0/9, Te1/0/10, Te1/0/12, Te1/0/13, Te1/0/15, Te1/0/16, Te1/0/17, Te1/0/18, Te1/0/19, Te1/0/21, Te1/0/22, Te1/0/23, Te1/0/24, Ap1/0/1
10 users active Te1/0/5, Te1/0/14, Te1/0/20
20 servers active Te1/0/11
1002 fddi-default act/unsup
1003 token-ring-default act/unsup
1004 fddinet-default act/unsup
1005 trnet-default act/unsup
VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
1 enet 100001 1500 - - - - - 0 0
10 enet 100010 1500 - - - - - 0 0
20 enet 100020 1500 - - - - - 0 0
1002 fddi 101002 1500 - - - - - 0 0
1003 tr 101003 1500 - - - - - 0 0
1004 fdnet 101004 1500 - - - ieee - 0 0
1005 trnet 101005 1500 - - - ibm - 0 0
#output
{
"Cisco-IOS-XE-vlan-oper:vlan": [
{
"id": 1,
"name": "default",
"status": "active",
"vlan-interfaces": [
{
"interface": "AppGigabitEthernet1/0/1",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/1",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/2",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/3",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/4",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/6",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/7",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/8",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/9",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/10",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/12",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/13",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/15",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/16",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/17",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/18",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/19",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/21",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/22",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/23",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/24",
"subinterface": 0
}
]
},
{
"id": 10,
"name": "users",
"status": "active",
"vlan-interfaces": [
{
"interface": "TenGigabitEthernet1/0/5",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/14",
"subinterface": 0
},
{
"interface": "TenGigabitEthernet1/0/20",
"subinterface": 0
}
]
},
{
"id": 20,
"name": "servers",
"status": "active",
"vlan-interfaces": [
{
"interface": "TenGigabitEthernet1/0/11",
"subinterface": 0
}
]
},
{
"id": 1002,
"name": "fddi-default",
"status": "suspend"
},
{
"id": 1003,
"name": "token-ring-default",
"status": "suspend"
},
{
"id": 1004,
"name": "fddinet-default",
"status": "suspend"
},
{
"id": 1005,
"name": "trnet-default",
"status": "suspend"
}
]
}
The output provides detailed information about each VLAN, such as the VLAN ID (id
), its name (name
), and status (active
or suspend
). It also lists the interfaces associated with each VLAN under vlan-interfaces
This example highlights the importance of structured data in network management. With structured data, like the JSON output we see here, it becomes significantly easier to parse and work with the information programmatically.
Get Interface Stats
In this next example, we're going to see how Restconf can be used to gather comprehensive statistics for network interfaces, just like the show interface
command on a switch. The beauty of using Restconf for this task lies in the structured format of the data it retrieves, which makes it far easier to work with programmatically.
When we run the script to fetch interface stats, it returns a wealth of information. This includes operational and administrative statuses, MAC addresses, and details on interface errors or discards. Essentially, you get all the vital stats that you would from the traditional CLI command, but in a JSON format that's much more manageable for data processing and automation tasks.
import requests
import json
requests.packages.urllib3.disable_warnings()
username = 'admin'
password = 'password'
uri = 'https://10.1.1.1:443/restconf/data/Cisco-IOS-XE-interfaces-oper:interfaces/interface'
headers = {
"accept": "application/yang-data+json",
"Content-Type": "application/yang-data+json"
}
response = requests.get(
url=uri,
headers=headers,
auth=(username, password),
verify=False)
with open ('interface.json', 'w') as w:
w.write(json.dumps(response.json(), indent=2))
As an example, let's look at the output for a single interface. It provides a detailed snapshot of the interface's current state and performance metrics. This structured output simplifies the task of monitoring network health and troubleshooting issues.
#output
{
"name": "TenGigabitEthernet1/0/11",
"interface-type": "iana-iftype-ethernet-csmacd",
"admin-status": "if-state-up",
"oper-status": "if-oper-state-lower-layer-down",
"last-change": "2023-09-12T13:55:23.759+00:00",
"if-index": 19,
"phys-address": "02:ad:87:14:27:0c",
"speed": "10000000000",
"statistics": {
"discontinuity-time": "2023-09-12T13:52:57+00:00",
"in-octets": "0",
"in-unicast-pkts": "0",
"in-broadcast-pkts": "0",
"in-multicast-pkts": "0",
"in-discards": 0,
"in-errors": 0,
"in-unknown-protos": 0,
"out-octets": 0,
"out-unicast-pkts": "0",
"out-broadcast-pkts": "0",
"out-multicast-pkts": "0",
"out-discards": "0",
"out-errors": "0",
"rx-pps": "0",
"rx-kbps": "0",
"tx-pps": "0",
"tx-kbps": "0",
"num-flaps": "0",
"in-crc-errors": "0",
"in-discards-64": "0",
"in-errors-64": "0",
"in-unknown-protos-64": "0",
"out-octets-64": "0"
},
"vrf": "",
"ipv4": "0.0.0.0",
"ipv4-subnet-mask": "0.0.0.0",
"description": "",
"mtu": 1500,
"input-security-acl": "",
"output-security-acl": "",
"v4-protocol-stats": {
"in-pkts": "0",
"in-octets": "0",
"in-error-pkts": "0",
"in-forwarded-pkts": "0",
"in-forwarded-octets": "0",
"in-discarded-pkts": "0",
"out-pkts": "0",
"out-octets": "0",
"out-error-pkts": "0",
"out-forwarded-pkts": "0",
"out-forwarded-octets": "0",
"out-discarded-pkts": "0"
},
"v6-protocol-stats": {
"in-pkts": "0",
"in-octets": "0",
"in-error-pkts": "0",
"in-forwarded-pkts": "0",
"in-forwarded-octets": "0",
"in-discarded-pkts": "0",
"out-pkts": "0",
"out-octets": "0",
"out-error-pkts": "0",
"out-forwarded-pkts": "0",
"out-forwarded-octets": "0",
"out-discarded-pkts": "0"
},
"bia-address": "04:bd:97:41:17:0b",
"ipv4-tcp-adjust-mss": 0,
"ipv6-tcp-adjust-mss": 0,
"intf-ext-state-support": [
null
],
"intf-ext-state": {
"error-type": "port-error-none",
"port-error-reason": "port-err-none",
"auto-mdix-enabled": true,
"mdix-oper-status-enabled": true,
"fec-enabled": false,
"mgig-downshift-enabled": false
},
"storm-control": {
"broadcast": {
"filter-state": "inactive"
},
"multicast": {
"filter-state": "inactive"
},
"unicast": {
"filter-state": "inactive"
},
"unknown-unicast": {
"filter-state": "inactive"
}
},
"auto-upstream-bandwidth": "0",
"auto-downstream-bandwidth": "0",
"ether-state": {
"negotiated-duplex-mode": "auto-duplex",
"negotiated-port-speed": "speed-auto",
"auto-negotiate": true,
"enable-flow-control": false,
"media-type": "ether-media-type-rj45"
},
"ether-stats": {
"in-mac-control-frames": "0",
"in-mac-pause-frames": "0",
"in-oversize-frames": "0",
"in-jabber-frames": "0",
"in-fragment-frames": "0",
"in-8021q-frames": "0",
"out-mac-control-frames": "0",
"out-mac-pause-frames": "0",
"out-8021q-frames": "0"
}
Closing thoughts
That brings us to the end of our exploration into using Cisco Restconf to fetch operational data. We've seen how it simplifies accessing crucial information like VLAN details and interface stats, presenting it in a structured, easy-to-handle format. This approach not only makes network management more efficient but also opens doors to more advanced automation possibilities.