In YANG, what is the difference between a container, a list, a leaf and a leaf-list when modelling a router's interfaces?
answer
- value nodes versus interior nodes
- one instance or many
- scalar versus set of scalars
- entries told apart by key
- schema-only nodes and an escape hatch
basics
~20 sA YANG leaf holds one typed value and a leaf-list a set of values of one type; a container groups child nodes and occurs at most once under its parent, while a list holds many entries, each identified by its key leafs.
solid answer
~40 sThe four kinds split along two axes: does the node carry a value or child nodes, and does it occur once or many times. A `leaf` is one typed value (an interface's `mtu`), a `leaf-list` is many values of one type (the names of the groups an interface belongs to). A `container` holds children and occurs at most once under its parent (`statistics`); a `list` holds children and occurs many times, one entry per interface, each told apart by its `key` (`interface* [name]`). Around them, `choice` and `case` pick one of several alternative subtrees and never appear in the data themselves, and `anydata`, added in YANG 1.1 (RFC 7950), carries a subtree whose model is not known when the module is written.
code
yang · 16 linescontainer interfaces {
list interface {
key "name";
leaf name { type string; }
leaf mtu { type uint16; }
leaf-list group { type string; }
choice encapsulation {
case dot1q { leaf vlan-id { type uint16; } }
case untagged { leaf untagged { type empty; } }
}
container statistics {
config false;
leaf in-octets { type uint64; }
}
}
}go deeper
Recall the two-by-two: leaf and leaf-list carry values, container and list carry children; leaf and container occur once, leaf-list and list many times. Give one interface example of each.
Explain presence versus non-presence containers, why a configuration list needs a key, and how each kind encodes in XML and JSON, including that a choice leaves no trace in the data.
Show the modelling judgement: when existence should carry meaning, when a choice protects against contradictory settings, and why anydata belongs in state and notifications rather than configuration.
Talk about the cost of a wrong node kind once a model ships: every client and encoding depends on the shape, so a leaf-to-leaf-list change is a breaking change for consumers.
## Two questions sort every data node YANG (RFC 7950 defines **YANG 1.1**; RFC 6020 defined 1.0) describes configuration and state as a tree. Every data node in that tree answers two questions: does it carry a **value** or **child nodes**, and can it occur **once** or **many times**? The four core statements are the four answers. | | occurs at most once | occurs many times | |---|---|---| | carries a value | `leaf` | `leaf-list` | | carries child nodes | `container` | `list` | A router's interface model uses all four: a top-level `interfaces` container, an `interface` list with one entry per port, a `name` leaf that keys it, an `mtu` leaf, a leaf-list naming the groups the interface belongs to, and a `statistics` container of counters. ## Leaf and leaf-list: the values - A **leaf** holds exactly one value of one type: `mtu`, `description`, `enabled`. It has no children. - A **leaf-list** holds a sequence of values of one type, such as the names of the groups an interface belongs to. In configuration data its values **MUST be unique**; YANG 1.1 relaxed that for state data, where a leaf-list may repeat a value. - Both are typed; which types exist and how they are restricted is a separate subject, the language's type system. ## Container: plain and presence A **container** has no value of its own, only children, and exists at most once under its parent. RFC 7950 §7.5.1 defines two styles: 1. A **non-presence container** (the default) only organises its children. An empty one means the same as an absent one, and a NETCONF server MAY delete it when its last child is deleted. 2. A **presence container**, marked with the `presence` statement, means something by existing. The RFC's own example is an `ssh` container whose presence turns SSH login on while also holding SSH settings; a `loopback` container on an interface could work the same way. ## List: many entries, each with an identity A **list** is an interior node that may occur many times; each occurrence is a **list entry** with its own children. A list that holds configuration **MUST** declare a `key` (RFC 7950 §7.8.2): one or more child leafs whose combined values identify each entry, so an edit can say exactly which interface it means. A state list may omit the key. The `interface` list keyed by `name` is the canonical example; RFC 8343's standard interfaces model is built exactly that way. ## Choice and case: alternatives that are not data A **choice** offers several alternative branches, each a **case**; the nodes of at most one case exist at a time. Neither the choice nor the case node appears in the instance data — only the nodes of the case in force do. An encapsulation choice with a `dot1q` case holding a VLAN ID and an `untagged` case is a typical use. Creating a node from one case implicitly deletes the nodes of every other case, and a NETCONF request that carries nodes from two cases at once is rejected with a `bad-element` error. ## anydata: the escape hatch **anydata** (new in YANG 1.1) holds a set of nodes that YANG could model, but whose model is not known when the module is written — RFC 7950's example is a list of received notifications of kinds unknown at design time. It exists at most once, it cannot be augmented, and NETCONF treats it as an opaque chunk that is replaced whole. Because of that, the RFC says it **SHOULD NOT** be used for configuration. The older **anyxml** carries arbitrary XML; RFC 7950 RECOMMENDS anydata instead whenever the content can be modelled in YANG. ## How the kinds look on the wire The kind decides the encoding, which is why getting it right matters to every client: - In XML, a container is one element; a list is a **series of elements**, one per entry, with no wrapper for the list as a whole; a leaf-list is a series of elements, one per value. - In JSON (RFC 7951), a container is a name/object pair, a list a name/array pair whose elements are objects, and a leaf-list a name/array pair of values. - A choice and its cases add nothing to either encoding. Model a single value as a leaf-list, or a set of interfaces as a container, and every client that reads or writes the data is built around the wrong shape.
- When would you choose a presence container over a plain container?When the container's existence is itself the setting. A presence container, marked with `presence`, means something even with no children — RFC 7950's example is an `ssh` container that turns SSH login on and also holds SSH options. A plain container only organises its children: empty is the same as absent, and a NETCONF server MAY delete it once its last child goes.
- In YANG, what happens when a client writes a node from a different case of a choice?Only one case's nodes may exist at a time, so RFC 7950 §7.9 says creating a node from one case implicitly deletes the existing nodes of all other cases. Switching an interface from `dot1q` to `untagged` therefore removes the VLAN ID without a separate delete. Sending nodes from two cases in one NETCONF request is rejected with a `bad-element` error.
- Why does YANG 1.1 recommend anydata over anyxml?anyxml carries arbitrary XML with no promise that YANG could describe it. anydata carries nodes that YANG can model, only the model is not known when the module is written, so the content stays YANG-shaped data. RFC 7950 RECOMMENDS anydata whenever that holds, and says neither SHOULD be used for configuration, since a server can only replace the content as a whole.
saying these in an interview costs you the question
- A container can occur many times; a list is just a container with a key.
- A leaf-list is a list of containers.
- An empty container always means something was configured.
- A choice appears as its own element in the XML or JSON data.
- anydata is the right place for configuration you do not want to model.
- In XML, a list is one element that wraps all of its entries.