I’m back with another question related to model driven programmability. This one came in from David Frizelle who came to the wonderful world of Model Driven Programmability through radio. The new O-RAN Alliance (Open Radio Standard) is using NETCONF for configuration interface. How cool is that! Here’s David’s question:
When considering a read only leaf in a YANG module, if a get or get-config is done in NETCONF, the read only leaves in the YANG module are returned. I am assuming that they exist in the datastore and are read out and returned. If this is true, my question is – who sets their values in the datastore, and using what method? If they are read only in YANG, then I would expect that NETCONF can’t be used to set them, so I’m trying to understand how they get set, and particularly if they are variables, like stats, that are read only in YANG but are expected to change continuously. Who does the updating of them in the datastore?
Let’s dive into the question and see if we can’t clear it up.
What is “read-only” data from a YANG perspective?
First, keep in mind that “read only” leaves in a YANG model are considered state data (I like to call it operational), while “read-write” leaves are configuration data. Let’s look at how this is shown in the actual YANG data model using my favorite model for education reasons, the ietf-interfaces module.
pyang -f tree ietf-interfaces.yang
module: ietf-interfaces
+--rw interfaces
| +--rw interface* [name]
| +--rw name string
| +--rw description? string
| +--rw type identityref
| +--rw enabled? boolean
| +--rw link-up-down-trap-enable? enumeration {if-mib}?
+--ro interfaces-state
+--ro interface* [name]
+--ro name string
+--ro type identityref
+--ro admin-status enumeration {if-mib}
Notice how the entire container of “interfaces-state” is marked as “ro” for “read-only”. If we look at this container in the underlying YANG file itself, we see that the container is listed as “config false;”.
container interfaces-state {
config false;
description
"Data nodes for the operational state of interfaces.";
If you really want to go down the rabbit hole, you can look at the RFC itself.
State (or operational) data are the statistics, telemetry, and other “calculated” parts of data from a network device. Things that tell us how the device is working rather than how the device has been “configured”.
But where does “read-only” data come from?
Now that we know what “read-only” data is… where does the value come from? For this let’s recall where YANG models fit into a typical device’s software stack.
This is a very simplified diagram that I use in the lessons. The green box represents some piece of network kit. The underlying device features and the network operating system (eg NX-OS, IOS XE, or IOS XR) work just like they always do and have before model driven programmability was a “thing”. The YANG models and new interfaces such as NETCONF, RESTCONF, and gRPC that make up model driven programmability are most often supported by running a new process (or multiple processes) alongside the network operating system on the hardware (or virtual appliance).
We can see these processes with the “show processes” command on IOS XE or NX-OS. Using the Always On Sandboxes from DevNet let’s see what we get.
# IOS XE Always On Sandbox csr1000v-1#show processes platform | inc confd 347 30237 S 130420 confd # NX-OS Always On Sandbox sbx-n9kv-ao# show processes | grep '[(net)|(rest)]conf' 3680 S f77cdbf0 1 - VU restconf 3704 S f77b5bf0 1 - VU netconf 3816 S f774bbf0 1 - O restconf 3818 S f7710bf0 1 - O restconf-wd
These processes represent the Agents that manage model driven programmability features of the device. Part of the “duties” of these agents are to keep the data stores in sync with the running configuration on the device. That’s right… in many cases the data stores we interface with NETCONF or RESTCONF are actually parallel representations of the config to the “native” configurations of the network operating systems. For example, checkout this log entry on an IOS XE device that happens whenever a configuration is updated.
*Jan 14 08:35:09.396: %DMI-5-SYNC_COMPLETE: R0/0: dmiauthd: The running configuration has been synchronized to the NETCONF running data store.
But this diversion to data stores is actually somewhat unrelated to read-only data at the heart of the question. Datastores are most commonly used for device configurations. This could be a running-configuration, startup-configuration, or some other candidate configuration. State data is not intended to be stored in a datastore, but rather retrieved from the underlying platform at the time it is requested.
As with any “rule”, there are exceptions to this state data not in datastore comment. Some software systems or architectural choices made by platforms could leverage a datastore for some operational details. However, for most network devices you won’t find state data in a datastore.
I’m quite a fan of looking at the RFC when trying to truly understand something so let’s compare the NETCONF operation of <get-config> and <get>.
7.1. <get-config> Description: Retrieve all or part of a specified configuration datastore. Example: To retrieve the entire <users> subtree: <rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <get-config> <source> <running/> </source> <filter type="subtree"> <top xmlns="http://example.com/schema/1.2/config"> <users/> </top> </filter> </get-config> </rpc> 7.7. <get> Description: Retrieve running configuration and device state information. Example: <rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <get> <filter type="subtree"> <top xmlns="http://example.com/schema/1.2/stats"> <interfaces> <interface> <ifName>eth0</ifName> </interface> </interfaces> </top> </filter> </get> </rpc>
When you use the <get-config> operation you must specify the source datastore where you’d like to retrieve the configuration from, and there is no mention of state data. While the <get> operation only retrieves configuration from “running” and allows you to get the state data.
Note: You also need to specify the target datastore when using <edit-config>.
The retrieval of state data is handled by the agents through mechanisms specific to the platforms in question. So a request for the current counters on an interface (a state request) will result in the agent querying the ASIC perhaps.
But can NETCONF set read-only data?
The questioner states “NETCONF can’t be used to set [read-only leaves]”, and this is correct. As state data, the idea of “configuring them” within a datastore doesn’t line up at all for a few reasons we’ve discussed.
- Read-only leaves are NOT stored in a datastore – datastores are for config data.
- The <edit-config> operation used to “set” values of leaves must target a datastore – so see #1
Worth noting, the value of a devices state is quite often impacted by configuration. For example, configuring a MAC address on an interface to override a hardware address will result in a new reported address when queried for state.
Final Thoughts
This was another chance for me to dive deeper into an aspect of network automation that is mentioned during many other labs and lessons, but deserved a bit of a more thorough treatment. I hope my answer helped the original questioner and others who may have scratched their head on this topic.
You can find all the past “Ask Hank” blogs here. If you’ve got a question you’d like some help tackling, let me know in the comments. Or toss it my way in email at hapresto@cisco.com. And you can always find me on Twitter @hfpreston as well. In the meantime, here are a few more related resources you can dive into in your network automation journey.
- Network Programmability Basics Video Series
- Model Driven Programmability Learning Labs
- DevNet Sandbox for Free Lab Access
We’d love to hear what you think. Ask a question or leave a comment below.
And stay connected with Cisco DevNet on social!
Twitter @CiscoDevNet | Facebook | LinkedIn
Visit the new Developer Video Channel
State data is not intended to be stored in a datastore, but rather retrieved from the underlying platform at the time it is requested.
=> where is the logic to do this retrieval?