YANG In-Depth
In the previous article we took a quick look at YANG. YANG is a data modeling language which is used by NETCONF to standardize the configuration of network devices. YANG defines how data should “look” by defining the structure of the data and constraints for each data entry.
YANG is quite difficult to read when you are new to it. There are terms and rules unique to YANG itself, so there is a bit of a learning curve. YANG is most similar to XML, especially in terms of its heirarchical nature. In fact YANG actually maps directly to XML.
First we will look at a generic, made-up example of a YANG model to examine the basic nodes types and how YANG enforces constraints on data type. Then we’ll go more in depth with node types and data types and look at real-world examples from IETF models.
If this is your first time looking at YANG, I would highly recommend going through the links at the bottom of this article, and going back-and-forth between reading and watching content. YANG starts to make sense the more you look at it from different perspectives.
Example (Car Inventory)
The following is a YANG model called car-inventory which is used to keep an inventory of used cars for sale on a car lot.
We can use this simple example to explain common Yang statements.
module names the YANG model. The module name should be the same as the filename. For example, the file name here should be car-inventory.yang
namespace is required for each module. It should be unique for every module. Sometimes you see this referencing a URL but the URL doesn’t have to be reachable via HTTP. It is essentially just a string. Often an organization uses their own domain for the namespace because this gaurantees uniqueness.
prefix is the short-hand for the full namespace
container groups like items together and defines the heirarchy
list defines nodes that are alike. Each car we define will be a node of this list.
key defines how to index a node in the list. So if we want to lookup a particular car in this list, we need to pass the inventory-num.
Each leaf is basically an attribute of a car. A leaf must be a single value. A leaf can be required or optional. Each leaf has a type, which can be used for validation. If price is not a decimal that has two decimal places, it will be rejected for not conforming to the YANG model.
We can use pyang to print this model in a more readable tree format:
Notice above that the brackets around inventory-num mean that is it the key for the list cars.
Let’s make this model a little more specific and create better constraints. First we can limit what integers are used for the inventory number. Let’s start at 100 and go no higher than 10,000.
Let’s also limit the “make” leaf to a set of known car manufacturers, instead of just allowing any string. To do this we create our own type defintion, and enumerate (list) each allowed value.
We can also limit the fuel-type to gasoline or diesel.
Putting it all togther we now have this:
Our YANG module in tree format:
Notice that in the tree output, you don’t see our additional type defintions, but you do see the types have changed next to the associated leafs.
This example hopefully gives you a sense of how YANG models are used and the power of the data type constraints. This allows a YANG model to assert the format of data. The constraints ensure that data conforms correctly to the given model.
YANG Node Types
Let’s now more broadly look at YANG types. We’ll use real world YANG examples as we go through each definition.
Leaf node
A leaf node contains a single value and it must have a specific type.
This is from ietf-bfd-ip-sh@2021-10-21.yang. We see three leafs here - interface, dest-addr, and source-addr. Each of these can only have a single value. Notice that each has a specific type associated with it. These three leafs are “attirbutes” of a BFD session.
List node
A list contains a sequence of entries. In the example above, session is a list and it contains our three leaf values. A list must have a key entry. This is how each node of the list is indexed. You can have multiple keys but this gets a little more advanced. The idea behind a list node is that you can have multiple entries of the same type. Here we can have multiple BFD sessions, each having an interface, dest-addr, and source-addr.
Container Node
A container contains a grouping of related nodes. It is an organizational YANG type. A container doesn’t itself have any data associated with it, it simply provides organization to the YANG tree. You can think of a container kind of like a file system directory which only has other directories and files within it. It is a parent node in the tree. In the example above, everything is under the container sessions.
You can also nest containers inside each other like this:
Leaf-list node
A leaf-list node is a seqeunce of leaf nodes. From what I can tell, you always see a single type value under a leaf-list. It means that you can have a list of leafs of this one type.
An example will help. This comes from ietf-igmp-mld@2019-11-01.yang
This output is a bit lengthy so let’s focus on the major groupings. I have edited down the YANG model:
This grouping defines IGMP attributes on a per-interface basis. There will be an IGMP querier on the subnet (leaf querier). Each group (list group) will have a group address, last-reporter, source, and list of hosts that signaled membership for the group. Additionally the router itself can join groups on this interface. (Think about how a Cisco router joins 224.0.1.40 by default).
The joined-group is a leaf-list because there can be multiple groups that a router joins on an interface. Each group is the same “type” of value - a multicast group address.
When a list has only one leaf, it can be a leaf-list. When a list has multiple leafs, it is just a list.
Grouping
I believe this isn’t exactly considered a node, but it is important that we examine this YANG statement. A grouping groups together common types that might be reused in a data model. It is almost like a shorthand - instead of defining values every time you use them, over and over again, you can reference the group each time you need that data.
Let’s look at ietf-vrrp@2018-03-13.yang. A grouping called vrrp-common-attributes defines attributes that are used for both IPv4 and IPv6. Then the groupings for vrrp-ipv4-attributes and vrrp-ipv6-attributes can “inherit” the definitions in the common attributes with the uses statement.
YANG Data Types
There are three main data types: built-in (base), common, and custom (derived).
Built-in (Base) types
Yang comes with built-in data types you can use without needing to reference another model. These data types are available for use by default.
Some examples are:
int8/16/32/64
8/16/32/64 bit integer
uint8/16/32/64
unsigned integer
decimal64
string
enumeration
boolean
You can assign a leaf any of these types:
Here leaf accept-mode is type boolean. Boolean is a built-in data type.
Common data types
These data types are defined by the IETF in RFC 6991. You must reference the ietf-yang-types YANG model when using these data types.
These include:
date-and-time
timestamp
mac-address
ipv4-address
ipv4-prefix
as-number
You can assign a leaf one of these common data types:
From ietf-interfaces@2018-02-20.yang
It is common to import this YANG module with the prefix yang. Notice that when using these data types you preface the type with yang:. We will see how the import statement works in more detail later in this article.
Derived (Custom) data types
You can also define your own data types, as we did in the very first example in this chapter. When you define a data type you also typically associate a constraint with it. A custom/derived data type uses a typedef statement and uses an existing data type with some type of restriction.
In this example, we create an ACL number type. An ACL in IOS can only be particular numbers (1-199 and 1300-2699).
This custom type must be an integer in the range 1 through 199 or 1300 through 2699.
You can also use a pattern statement to specify what characters are allowed on a string. For example, this is the mac-address typedef statement from ietf-yang-types, which is a common data type.
As you can see, common data types are really just dervied data types that are defined in the well-known ietf-yang-types module.
XPath
XPath is a query language for XML. Personally, it reminds me of indexing python dictionaries but with an added “find” feature.
Let’s say we have the following python code:
This prints the two IP address values:
Compare this to using XPath to print out the same values:
Notice that XPath uses an index that starts at 1, and python lists use a zero-based index. However, besides this, the XPath query and the python indexing is very similar.
XPath being a query language is much more powerful than just indexing a given tree. Above we have an absolute XPath, because it starts at the root of the document, denoted by the first / character. If we start the XPath query with two slashes (//) we use a relative XPath. In a relative XPath we can use wildcard characters.
We can even omit the first asterik altogether, and tell XPath to find the occurance of “interface” wherever it is in the document.
You can also find the particular interface based on the name attribute instead of the index number:
RW vs. RO Data
YANG is used for both configuration data (making changes to a device) and operational data (obtaining stats and settings on a device). Operational data is often used in model-driven telemetry which we will see in a future article. In model-driven telemetry, a network device periodically pushes data to a central server, such as interface statistics over time. The pushed data follows a YANG model, and the central server can subscribe to only parts of the YANG model by specifying an XPath filter.
In a YANG model you will frequently see a mix of configurable data and operational data. By default a leaf can be configured. If you see config false, this means everything under that statement is only operational data.
For example, look at this grouping from ietf-isis@2022-10-19.yang
Everything under the local-rib container is only operational data. In pyang you see this as ro instead of rw. When the config statement is missing, it is implicitly config true.
Here is that same section in tree format:
Import and Include statements
Import
Import is used to refer to definitions in another YANG module. It pulls in references, but not the body of the file. Common typedefs and groupings and be referred to by importing a YANG module.
As an example, look at the import statements for ietf-isis@2022-10-19.yang
All of the import statement above reference another YANG module. Only the typedefs and groupings are able to be referenced - the entirety of the file is not included. You use an import statement when you want to use common typedefs and groupings from another module.
Include
An include statement pulls submodules into a main module. It completely pulls in that entire YANG file. You would use this when you split a big module into separate, smaller modules.
As an example, look at ietf-ipv6-unicast-routing@2016-11-04.yang. It pulls in the ietf-ipv6-router-advertisements submodule.
Looking at this submodule (below), we see that it has a different header. The first line is submodule rather than module, and it belongs-to the parent ipv6-uinicast-routing module. The belongs-to statement takes the place of a namespace declaration in a regular module.
Must statement
A must statement is another tool to constrain data. It is used when a leaf has some type of relational constraint to another leaf. An example will explain how this works.
This is from ietf-isis@2022-10-19.yang. The YANG author needs some way to make sure than an ISIS interface priority is only applied to an interface if it is in broadcast mode. The interface priority leaf is relationally dependent on the interface-type leaf. If an interface is p2p, interface priority is unnecessary because an interface priority is only used to elect the DIS.
The grouping priority-cfg-with-default at the top is used for the priority container, with the uses statement on the last line. The must statement uses an XPath filter which goes up one level (denoted by .. just like in linux), and into the interface-type, which must equal broadcast. The interface-type and priority are both under the grouping of interface-config.
Augment statement
An augment statement adds definitions to an existing model. You use this when you want to use a separate module via an import statement but also add some node types to it.
This is an example from ietf-isis@2020-10-19.yang. The ietf-interfaces module is imported. The author wishes to add a leaf called clns-mtu to the module.
YANG Model Sources
There are two types of YANG models: Industry standard, and native models. Industry standard YANG models are defined by the IETF and the OpenConfig working group. These are meant to be vendor and platform independent. Items such as interfaces, open routing protocols, BFD, etc. should be vendor neutral and be able to apply to any networking equipment. You might ask why the need for both the IETF and OpenConfig to develop industry standard models. Historically IETF has taken longer to produce models, so the OpenConfig working group was created to accelerate the pace of producing industry standard models.
Native YANG models are defined by vendors to support features that are not industry standard. For example, EIGRP and HSRP are Cisco proprietary technologies that the IETF would not write YANG models for. Therefore Cisco must write the YANG models themselves. There are two types of native models: common and platform-specific. Common models can apply to any Cisco device, while platform-specific models only apply to that specific device platform.
On a Cisco device you will see all of these types of models supported: IETF, OpenConfig, native common, and native platform-specifc models.
Yin
The XML representation of a YANG model is called Yin. YANG maps to XML 1-to-1 without loss of any features or defintions. A tool such as pyang can convert a YANG model to Yin, representing the YANG data model in XML format.
As an example, here is the car-inventory.yang file in XML:
Further Reading/Watching
https://en.wikipedia.org/wiki/YANG
https://www.youtube.com/watch?v=zy9QA-uU0u4&ab_channel=UltraConfig
https://www.youtube.com/watch?v=b7IumSFInTs&ab_channel=AristaNetworks
This video is OK, you could skip it
https://www.youtube.com/watch?v=AdIcYrz3AjU&ab_channel=Tail-fSystems
This is the most thorough resource for learning YANG but it is quite dense. I recommend understand some of the basics before watching this, otherwise you will become lost pretty quickly.
https://www.youtube.com/watch?v=23iu0RWZ0UE
Part 2 of the video above.
https://www.youtube.com/watch?v=U-MZJ6rbqi4&ab_channel=AutomationStepbyStep
https://www.cbtnuggets.com/blog/technology/networking/native-yang-models-ietf-vs-openconfig-vs-cisco
Last updated