On previous RESTCONF posts I focused on trying to explain a way to make configurations on networking devices. In RESTCONF: A practical user guide we have translated CLI commands into RESTCONF transaction.
Today’s post objective is to keep learning about RESTCONF. This time we will look into how to get operational data from a device. We’re not going to make any change into a device configuration. This is why all requests will use the GET method. We will review some modules to get common device data such as interfaces status and forwarding tables.
Tools needed
To work with RESTCONF, my tools are:
- Postman, to make HTTP requests to the boxes without having to write any script.
- Python3.6 with the “requests” library.
- Pyang, to explore YANG models
- A code editor, like Visual Studio Code for example.
- A lab with at least one device running IOS-XE. There are CSRv available on DevNet that can be used for this purpose.
“ietf-interfaces” module
With this standard module we can get interfaces status. Using pyang we can see that there are two containers on the module:
The “interfaces” container allows a developer to make configurations on a device. The “interfaces-state” container gathers operational data. We will use the latter.
As always, the URI is comprised of the module and the container. In this case:
GET https://<IP:Port>/restconf/data/ietf-interfaces:interfaces-state/interface
Note: “/interface” at the end of the URI is not strictly necesary. But as “interface” is the only element inside the container (check pyang output) we can use it to reduce the depth of the response one level.
A request to the previous URI gave us the information shown below. Notice that the response has the operational status of each interfarce, its MAC Address, and in/out traffic statistics.
Note: some entries were omitted for brevity.
If we would like to filter the request to get a single interface, we can modify the URI (replace <INTERFACE-NAME>
with the desired interface).
GET https://<IP:Port>/restconf/data/ietf-interfaces:interfaces-state/interface=<INTERFACE-NAME>
Note: the interface identifier is “name”, this is indicatend on the YANG model. If the model is checked using pyang, the resulting tree states clearly this indentifier between square brackets, next to the container’s name.
+--ro interface* [name]
Note 2: when inserting the interface name on the URI, it has to be encoded. In particular slashes (“/”) have to be transformed into the code “%2F”. Then “GigabitEthernet0/1” is encoded as “GigabitEthernet0%2F1”.
“ietf-routing” module
“ietf-routing” is another standard module. It allows us to obtain routing information from the devices such as FIBs per VRF, o routing protocols utilized. Like “ietf-interfaces” this module has two containers: one for configurations (“routing”) and one for operational data (“routing-state”). We can check this with pyang:
Inside “routing-state” there is a “routing-instance” list. Each routing instance is a VRF, identified by its name.
The basic URI to use the container is the following:
GET https://<IP:Port>/restconf/data/ietf-routing:routing-state/routing-instance
Note: as with “ietf-interfaces”, there is no need to use “/routing-instance” at the end if there is no filter applied.
Because of the length of the unfiltered response, I decided no to include it. Instead, let’s take a look at some useful filters applied to this container: per-VRF information, routing table and specific prefix search.
Per-VRF filtering
The VRF name is the routing instance identifier and so it is simple to filter. The URI would look like the following one (replacing <VRF-NAME>
with the desired VFR name):
GET https://<IP:Port>/restconf/data/ietf-routing:routing-state/routing-instance=<VRF-NAME>
In the next example the filter is applied to a VRF named “Dummy” and the response is shown below. You can see that for the specified VRF the interfaces belonging to it are detailed. Also the RIB (both IPv4 and IPv6) and the routing protocols are present.
Routing table
Using the response from the previous example as starting point, is noticeable that following the path “ribs/rib” one can obtain the routing table. Pyang’s output for “ietf-routing” states that the identifier for each RIB container is its name. Using this information we can get each RIB for a specific VRF.
This way, we reach to the two URIs for IPv4 and IPv6 RIBs (we could get both RIBs on a single request just removing the filter):
GET https://<IP:Port>/restconf/data/ietf-routing:routing-state/routing-instance=<VRF-NAME>/ribs/rib=ipv4-default
GET https://<IP:Port>/restconf/data/ietf-routing:routing-state/routing-instance=<VRF-NAME>/ribs/rib=ipv6-default
Because the response is a subgroup of the one in the previous example, it is not copied here just to keep the post as short as possible.
Specific prefix information
We can go one step further and get a single prefix from the RIB (IPv4 or IPv6), Following the same logic used before, and taking a look also at pyang’s output, we need to get to the list in the path “ribs/rib/routes/route”. In this list, the identifier is a prefix in CIDR notation. To add some light, in this case I will use an example to understand the URI. I will search for the prefix 172.16.0.0/16 inside “Dummy” VRF’s IPv4 table.
GET https://<IP:Port>/restconf/data/ietf-routing:routing-state/routing-instance=Dummy/ribs/rib=ipv4-default/routes/route=172.16.0.0%2F16
Note: %2F is the slash (“/”) character encoded so it can be used on the URI. This way “172.16.0.0/16” becomes “172.16.0.0%2F16”.
Note 2: if the exact prefix doesn’t exist on the RIB, the status code of the response will be 404.
“Cisco-IOS-XE-interfaces-oper” module
“Cisco-IOS-XE-interfaces-oper” is Cisco’s native model equivalent to “ietf-interfaces”. This module returns a bit more data regarding network interfaces. In the same response it adds some configuration info about each interfaces, for example VRF, IPs or MTU.
Is an alternative to the standard model, which has the counterpart of being only supported by Cisco devices. The same logic used on other modules to filter and get some different fields can be replicated here. The base URI is left here for the ones who would like to give it a try:
GET https://<IP:Port>/restconf/data/Cisco-IOS-XE-interfaces-oper:interfaces
Note: I encourage everyone who wants to use this module to study it first with pyang so you can understand the structure.
“Cisco-IOS-XE-fib-oper” module
Let’s briefly discuss now an “ietf-routing” equivalent, or at least somewhat equivalent. “Cisco-IOS-XE-fib-oper” returns FIB information from a networking device. What is not available on this module is information regarding routing protocols on each VRF, like in the standard model. With native models, the operational state for each routing protocol has its own YANG model.
The base URI for “Cisco-IOS-XE-fib-oper” is the following:
GET https://<IP:Port>/restconf/data/Cisco-IOS-XE-fib-oper:fib-oper-data
Note: I encourage everyone who wants to use this module to study it first with pyang so you can understand the structure.
Other modules
As a reference, I have put below other modules that could be of interest. Remember that this modules have to be supported by the IOS-XE release that runs on the device. In case of using Cisco gear, native modules for operational data ends with “-oper”. Therefore, you can check here the existing modules per release (each releas usually adds some new ones).
- Cisco-IOS-XE-arp-oper returns ARP table information per VRF.
GET https://<IP:port>/restconf/data/Cisco-IOS-XE-arp-oper:arp-data
- Cisco-IOS-XE-ip-sla-oper returns IP SLA information.
GET https://<IP:port>/restconf/data/Cisco-IOS-XE-ip-sla-oper:ip-sla-stats
- Cisco-IOS-XE-nat-oper returns NAT information.
GET https://<IP:port>/restconf/data/Cisco-IOS-XE-nat-oper:nat-data
- Cisco-IOS-XE-ospf-oper has all the information referred with OSPF processes on the router. There are similar models for BGP and EIGRP.
GET https://<IP:port>/restconf/data/Cisco-IOS-XE-ospf-oper:ospf-oper-data
“fields” parameter
Although we can filter the response and use only the needed nodes with any script, some responses are really large and so it is useful to have a way to filter it on the request. With this is mind RFC 8040 defines the “fields” parameter. We can include this parameter on the request to reduce the amount of information received on the response. I’m concluding this post with examples of it usage.
If we would like to get specific nodes inside the response, we can indicate the on the “fields” parameter, separated by “;”. For example, to get only the name and operational status of an interfaces, we can use the following URI:
GET https://<IP:Port>/restconf/data/ietf-interfaces:interfaces-state/interface?fields=name;oper-status
The response tho the previous request is the following:
Now, what if we want to get nodes that are inside other child containers on a YANG data model? We have to travel through the relative path, using a slash (“/”) as a separator. For example, input errors on an interface are identified with the “in-errors” field inside “statistics” when using the “ietf-interfaces” module. To get this error count field for GigabitEthernet1 we can build an URI as follows:
GET https://<IP:Port>/restconf/data/ietf-interfaces:interfaces-state/interface=GigabitEthernet1?fields=statistics/in-errors
The result is this response:
Also, if more than a child node is required, instead of using an slash we can indicate the nodes between parenthesis (each one separated by a semicolon). In the next example, both in and out errors of interfaces GigabitEthernet1 are desired on the response:
GET https://<IP:Port>/restconf/data/ietf-interfaces:interfaces-state/interface=GigabitEthernet1?fields=statistics(in-errors;out-errors)
Combining the previous fields
In the examples above there was no need to specify the interface. The “fields” parameter work even when there is no specific selected (take a look at the first example). But at least on IOS-XE 16.9.3 it is not working as expected when different values are combined. For example, the following URI should return only interfaces names and error counts but instead returns all the information (as there was no “fields” parameter included):
GET https://<IP:Port>/restconf/data/ietf-interfaces:interfaces-state/interface?fields=statistics/in-errors;name
Then, the result of the previous examples are not really useful without selecting a specific interface. This is because without having the interface name it will be very difficult to identify which error counts belongs to which interface.
Today’s post ends here. I’m preparing for the next one some operations on Cisco routers using RESTCONF, stay tuned! Any doubt or suggestion feel free to reach out to me on the comments section. You can also contact me using the web’s contact form or any social network.