4.14. Data Definitions
The "description" statement MUST be present in the following YANG statements: o anyxml o augment o choice o container o extension o feature o grouping o identity o leaf o leaf-list
o list o notification o rpc o typedef If the data definition semantics are defined in an external document, (other than another YANG module indicated by an import statement), then a reference statement MUST be present. The "anyxml" construct may be useful to represent an HTML banner containing markup elements, such as "<b>" and "</b>", and MAY be used in such cases. However, this construct SHOULD NOT be used if other YANG data node types can be used instead to represent the desired syntax and semantics. It has been found that the "anyxml" statement is not implemented consistently across all servers. It is possible that mixed-mode XML will not be supported or that configuration anyxml nodes will not supported. If there are referential integrity constraints associated with the desired semantics that can be represented with XPath, then one or more "must" statements SHOULD be present. For list and leaf-list data definitions, if the number of possible instances is required to be bounded for all implementations, then the max-elements statements SHOULD be present. If any "must" or "when" statements are used within the data definition, then the data definition "description" statement SHOULD describe the purpose of each one. The "choice" statement is allowed to be directly present within a "case" statement in YANG 1.1. This needs to be considered carefully. Consider simply including the nested "choice" as additional "case" statements within the parent "choice" statement. Note that the "mandatory" and "default" statements within a nested "choice" statement only apply if the "case" containing the nested "choice" statement is first selected. If a list defines any key leafs, then these leafs SHOULD be defined in order, as the first child nodes within the list. The key leafs MAY be in a different order in some cases, e.g., they are defined in a grouping, and not inline in the list statement.
4.14.1. Non-Presence Containers
A non-presence container is used to organize data into specific subtrees. It is not intended to have semantics within the data model beyond this purpose, although YANG allows it (e.g., a "must" statement within the non-presence container). Example using container wrappers: container top { container foos { list foo { ... } } container bars { list bar { ... } } } Example without container wrappers: container top { list foo { ... } list bar { ... } } Use of non-presence containers to organize data is a subjective matter similar to use of subdirectories in a file system. Although these containers do not have any semantics, they can impact protocol operations for the descendant data nodes within a non-presence container, so use of these containers SHOULD be considered carefully. The NETCONF and RESTCONF protocols do not currently support the ability to delete all list (or leaf-list) entries at once. This deficiency is sometimes avoided by use of a parent container (i.e., deleting the container also removes all child entries).4.14.2. Top-Level Data Nodes
Use of top-level objects needs to be considered carefully: o top-level siblings are not ordered o top-level siblings are not static and depend on the modules that are loaded
o for subtree filtering, retrieval of a top-level leaf-list will be treated as a content-match node for all top-level-siblings o a top-level list with many instances may impact performance4.15. Operation Definitions
If the operation semantics are defined in an external document (other than another YANG module indicated by an import statement), then a reference statement MUST be present. If the operation impacts system behavior in some way, it SHOULD be mentioned in the "description" statement. If the operation is potentially harmful to system behavior in some way, it MUST be mentioned in the Security Considerations section of the document.4.16. Notification Definitions
The "description" statement MUST be present. If the notification semantics are defined in an external document (other than another YANG module indicated by an import statement), then a reference statement MUST be present. If the notification refers to a specific resource instance, then this instance SHOULD be identified in the notification data. This is usually done by including "leafref" leaf nodes with the key leaf values for the resource instance. For example: notification interface-up { description "Sent when an interface is activated."; leaf name { type leafref { path "/if:interfaces/if:interface/if:name"; } } } Note that there are no formal YANG statements to identify any data node resources associated with a notification. The "description" statement for the notification SHOULD specify if and how the notification identifies any data node resources associated with the specific event.
4.17. Feature Definitions
The YANG "feature" statement is used to define a label for a set of optional functionality within a module. The "if-feature" statement is used in the YANG statements associated with a feature. The description-stmt within a feature-stmt MUST specify any interactions with other features. The set of YANG features defined in a module should be considered carefully. Very fine granular features increase interoperability complexity and should be avoided. A likely misuse of the feature mechanism is the tagging of individual leafs (e.g., counters) with separate features. If there is a large set of objects associated with a YANG feature, then consider moving those objects to a separate module, instead of using a YANG feature. Note that the set of features within a module is easily discovered by the reader, but the set of related modules within the entire YANG library is not as easy to identity. Module names with a common prefix can help readers identity the set of related modules, but this assumes the reader will have discovered and installed all the relevant modules. Another consideration for deciding whether to create a new module or add a YANG feature is the stability of the module in question. It may be desirable to have a stable base module that is not changed frequently. If new functionality is placed in a separate module, then the base module does not need to be republished. If it is designed as a YANG feature, then the module will need to be republished. If one feature requires implementation of another feature, then an "if-feature" statement SHOULD be used in the dependent "feature" statement. For example, feature2 requires implementation of feature1: feature feature1 { description "Some protocol feature"; } feature feature2 { if-feature "feature1"; description "Another protocol feature"; }
4.18. YANG Data Node Constraints
4.18.1. Controlling Quantity
The "min-elements" and "max-elements" statements can be used to control how many list or leaf-list instances are required for a particular data node. YANG constraint statements SHOULD be used to identify conditions that apply to all implementations of the data model. If platform-specific limitations (e.g., the "max-elements" supported for a particular list) are relevant to operations, then a data model definition statement (e.g., "max-ports" leaf) SHOULD be used to identify the limit.4.18.2. "must" versus "when"
"must" and "when" YANG statements are used to provide cross-object referential tests. They have very different behavior. The "when" statement causes data node instances to be silently deleted as soon as the condition becomes false. A false "when" expression is not considered to be an error. The "when" statement SHOULD be used together with "augment" or "uses" statements to achieve conditional model composition. The condition SHOULD be based on static properties of the augmented entry (e.g., list key leafs). The "must" statement causes a datastore validation error if the condition is false. This statement SHOULD be used for enforcing parameter value restrictions that involve more than one data node (e.g., end-time parameter must be after the start-time parameter).4.19. "augment" Statements
The YANG "augment" statement is used to define a set of data definition statements that will be added as child nodes of a target data node. The module namespace for these data nodes will be the augmenting module, not the augmented module. A top-level "augment" statement SHOULD NOT be used if the target data node is in the same module or submodule as the evaluated "augment" statement. The data definition statements SHOULD be added inline instead.4.19.1. Conditional Augment Statements
The "augment" statement is often used together with the "when" statement and/or "if-feature" statement to make the augmentation conditional on some portion of the data model.
The following example from [RFC7223] shows how a conditional container called "ethernet" is added to the "interface" list only for entries of the type "ethernetCsmacd". augment "/if:interfaces/if:interface" { when "if:type = 'ianaift:ethernetCsmacd'"; container ethernet { leaf duplex { ... } } }4.19.2. Conditionally Mandatory Data Definition Statements
YANG has very specific rules about how configuration data can be updated in new releases of a module. These rules allow an "old client" to continue interoperating with a "new server". If data nodes are added to an existing entry, the old client MUST NOT be required to provide any mandatory parameters that were not in the original module definition. It is possible to add conditional "augment" statements such that the old client would not know about the new condition and would not specify the new condition. The conditional "augment" statement can contain mandatory objects only if the condition is false, unless explicitly requested by the client. Only a conditional "augment" statement that uses the "when" statement form of a condition can be used in this manner. The YANG features enabled on the server cannot be controlled by the client in any way, so it is not safe to add mandatory augmenting data nodes based on the "if-feature" statement. The XPath "when" statement condition MUST NOT reference data outside of the target data node because the client does not have any control over this external data. In the following dummy example, it is okay to augment the "interface" entry with "mandatory-leaf" because the augmentation depends on support for "some-new-iftype". The old client does not know about this type, so it would never select this type; therefore, it would not add a mandatory data node.
module example-module { yang-version 1.1; namespace "tag:example.com,2017:example-module"; prefix mymod; import iana-if-type { prefix iana; } import ietf-interfaces { prefix if; } identity some-new-iftype { base iana:iana-interface-type; } augment "/if:interfaces/if:interface" { when "if:type = 'mymod:some-new-iftype'"; leaf mandatory-leaf { type string; mandatory true; } } } Note that this practice is safe only for creating data resources. It is not safe for replacing or modifying resources if the client does not know about the new condition. The YANG data model MUST be packaged in a way that requires the client to be aware of the mandatory data nodes if it is aware of the condition for this data. In the example above, the "some-new-iftype" identity is defined in the same module as the "mandatory-leaf" data definition statement. This practice is not safe for identities defined in a common module such as "iana-if-type" because the client is not required to know about "my-module" just because it knows about the "iana-if-type" module.4.20. Deviation Statements
Per RFC 7950, Section 7.20.3, the YANG "deviation" statement is not allowed to appear in IETF YANG modules, but it can be useful for documenting server capabilities. Deviation statements are not reusable and typically not shared across all platforms. There are several reasons that deviations might be needed in an implementation, e.g., an object cannot be supported on all platforms, or feature delivery is done in multiple development phases. Deviation statements can also be used to add annotations to a module, which does not affect the conformance requirements for the module.
It is suggested that deviation statements be defined in separate modules from regular YANG definitions. This allows the deviations to be platform specific and/or temporary. The order that deviation statements are evaluated can affect the result. Therefore, multiple deviation statements in the same module, for the same target object, SHOULD NOT be used. The "max-elements" statement is intended to describe an architectural limit to the number of list entries. It is not intended to describe platform limitations. It is better to use a "deviation" statement for the platforms that have a hard resource limit. Example documenting platform resource limits: Wrong: (max-elements in the list itself) container backups { list backup { ... max-elements 10; ... } } Correct: (max-elements in a deviation) deviation /bk:backups/bk:backup { deviate add { max-elements 10; } }4.21. Extension Statements
The YANG "extension" statement is used to specify external definitions. This appears in the YANG syntax as an "unknown-statement". Usage of extension statements in a published module needs to be considered carefully. The following guidelines apply to the usage of YANG extensions: o The semantics of the extension MUST NOT contradict any YANG statements. Extensions can add semantics not covered by the normal YANG statements.
o The module containing the extension statement MUST clearly identify the conformance requirements for the extension. It should be clear whether all implementations of the YANG module containing the extension need to also implement the extension. If not, identify what conditions apply that would require implementation of the extension. o The extension MUST clearly identify where it can be used within other YANG statements. o The extension MUST clearly identify if YANG statements or other extensions are allowed or required within the extension as substatements.4.22. Data Correlation
Data can be correlated in various ways, using common data types, common data naming, and common data organization. There are several ways to extend the functionality of a module, based on the degree of coupling between the old and new functionality: o inline: update the module with new protocol-accessible objects. The naming and data organization of the original objects is used. The new objects are in the original module namespace. o augment: create a new module with new protocol-accessible objects that augment the original data structure. The naming and data organization of the original objects is used. The new objects are in the new module namespace. o mirror: create new objects in a new module or the original module, except use a new naming scheme and data location. The naming can be coupled in different ways. Tight coupling is achieved with a "leafref" data type, with the "require-instance" substatement set to "true". This method SHOULD be used. If the new data instances are not limited to the values in use in the original data structure, then the "require-instance" substatement MUST be set to "false". Loose coupling is achieved by using key leafs with the same data type as the original data structure. This has the same semantics as setting the "require-instance" substatement to "false". The relationship between configuration and operational state has been clarified in NMDA [RFC8342].
4.22.1. Use of "leafref" for Key Correlation
Sometimes it is not practical to augment a data structure. For example, the correlated data could have different keys or contain mandatory nodes. The following example shows the use of the "leafref" data type for data correlation purposes: Not preferred: list foo { key name; leaf name { type string; } ... } list foo-addon { key name; config false; leaf name { type string; } ... } Preferred: list foo { key name; leaf name { type string; } ... } list foo-addon { key name; config false; leaf name { type leafref { path "/foo/name"; require-instance false; } } leaf addon {
type string; mandatory true; } }4.23. Operational State
The modeling of operational state with YANG has been refined over time. At first, only data that has a "config" statement value of "false" was considered to be operational state. This data was not considered to be part of any datastore, which made the YANG XPath definition much more complicated. Operational state is now modeled using YANG according to the new NMDA [RFC8342] and conceptually contained in the operational state datastore, which also includes the operational values of configuration data. There is no longer any need to duplicate data structures to provide separate configuration and operational state sections. This section describes some data modeling issues related to operational state and guidelines for transitioning YANG data model design to be NMDA compatible.4.23.1. Combining Operational State and Configuration Data
If possible, operational state SHOULD be combined with its associated configuration data. This prevents duplication of key leafs and ancestor nodes. It also prevents race conditions for retrieval of dynamic entries and allows configuration and operational state to be retrieved together with minimal message overhead. container foo { ... // contains "config true" and "config false" nodes that have // no corresponding "config true" object (e.g., counters) }4.23.2. Representing Operational Values of Configuration Data
If possible, the same data type SHOULD be used to represent the configured value and the operational value, for a given leaf or leaf- list object. Sometimes the configured value set is different than the operational value set for that object, for example, the "admin-status" and "oper-status" leafs in [RFC8343]. In this case, a separate object MAY be used to represent the configured and operational values.
Sometimes the list keys are not identical for configuration data and the corresponding operational state. In this case, separate lists MAY be used to represent the configured and operational values. If it is not possible to combine configuration and operational state, then the keys used to represent list entries SHOULD be the same type. The "leafref" data type SHOULD be used in operational state for key leafs that have corresponding configuration instances. The "require-instance" statement MAY be set to "false" (in YANG 1.1 modules only) to indicate instances are allowed in the operational state that do not exist in the associated configuration data. The need to replicate objects or define different operational state objects depends on the data model. It is not possible to define one approach that will be optimal for all data models. Designers SHOULD describe and justify any NMDA exceptions in detail, such as the use of separate subtrees and/or separate leafs. The "description" statements for both the configuration and the operational state SHOULD be used for this purpose.4.23.3. NMDA Transition Guidelines
YANG modules SHOULD be designed with the assumption that they will be used on servers supporting the operational state datastore. With this in mind, YANG modules SHOULD define "config false" nodes wherever they make sense to the data model. "Config false" nodes SHOULD NOT be defined to provide the operational value for configuration nodes, except when the value space of a configured and operational value may differ, in which case a distinct "config false" node SHOULD be defined to hold the operational value for the configured node. The following guidelines are meant to help modelers develop YANG modules that will maximize the utility of the model with both current and new implementations. New modules and modules that are not concerned with the operational state of configuration information SHOULD immediately be structured to be NMDA compatible, as described in Section 4.23.1. This transition MAY be deferred if the module does not contain any configuration datastore objects.
The remaining are options that MAY be followed during the time that NMDA mechanisms are being defined. (a) Modules that require immediate support for the NMDA features SHOULD be structured for NMDA. A temporary non-NMDA version of this type of module MAY exist, as either an existing model or a model created by hand or with suitable tools that mirror the current modeling strategies. Both the NMDA and the non-NMDA modules SHOULD be published in the same document, with NMDA modules in the document main body and the non-NMDA modules in a non-normative appendix. The use of the non-NMDA module will allow temporary bridging of the time period until NMDA implementations are available. (b) For published models, the model should be republished with an NMDA-compatible structure, deprecating non-NMDA constructs. For example, the "ietf-interfaces" model in [RFC7223] has been restructured as an NMDA-compatible model in [RFC8343]. The "/interfaces-state" hierarchy has been marked "status deprecated". Models that mark their "/foo-state" hierarchy with "status deprecated" will allow NMDA-capable implementations to avoid the cost of duplicating the state nodes, while enabling non-NMDA-capable implementations to utilize them for access to the operational values. (c) For models that augment models that have not been structured with the NMDA, the modeler will have to consider the structure of the base model and the guidelines listed above. Where possible, such models should move to new revisions of the base model that are NMDA compatible. When that is not possible, augmenting "state" containers SHOULD be avoided, with the expectation that the base model will be re-released with the state containers marked as deprecated. It is RECOMMENDED to augment only the "/foo" hierarchy of the base model. Where this recommendation cannot be followed, then any new "state" elements SHOULD be included in their own module.4.23.3.1. Temporary Non-NMDA Modules
A temporary non-NMDA module allows a non-NMDA-aware client to access operational state from an NMDA-compliant server. It contains the top-level "config false" data nodes that would have been defined in a legacy YANG module (before NMDA). A server that needs to support both NMDA and non-NMDA clients can advertise both the new NMDA module and the temporary non-NMDA module. A non-NMDA client can use separate "foo" and "foo-state" subtrees, except the "foo-state" subtree is located in a different (temporary)
module. The NMDA module can be used by a non-NMDA client to access the conventional configuration datastores and the deprecated <get> operation to access nested "config false" data nodes. To create the temporary non-NMDA model from an NMDA model, the following steps can be taken: o Change the module name by appending "-state" to the original module name o Change the namespace by appending "-state" to the original namespace value o Change the prefix by appending "-s" to the original prefix value o Add an import to the original module (e.g., for typedef definitions) o Retain or create only the top-level nodes that have a "config" statement value "false". These subtrees represent "config false" data nodes that were combined into the configuration subtree; therefore, they are not available to non-NMDA aware clients. Set the "status" statement to "deprecated" for each new node. o The module description SHOULD clearly identify the module as a temporary non-NMDA module4.23.3.2. Example: Create a New NMDA Module
Create an NMDA-compliant module, using combined configuration and state subtrees, whenever possible. module example-foo { namespace "urn:example.com:params:xml:ns:yang:example-foo"; prefix "foo"; container foo { // configuration data child nodes // operational value in operational state datastore only // may contain "config false" nodes as needed } }
4.23.3.3. Example: Convert an Old Non-NMDA Module
Do not remove non-compliant objects from existing modules. Instead, change the status to "deprecated". At some point, usually after 1 year, the status MAY be changed to "obsolete". Old Module: module example-foo { namespace "urn:example.com:params:xml:ns:yang:example-foo"; prefix "foo"; container foo { // configuration data child nodes } container foo-state { config false; // operational state child nodes } } Converted NMDA Module: module example-foo { namespace "urn:example.com:params:xml:ns:yang:example-foo"; prefix "foo"; container foo { // configuration data child nodes // operational value in operational state datastore only // may contain "config false" nodes as needed // will contain any data nodes from old foo-state } // keep original foo-state but change status to deprecated container foo-state { config false; status deprecated; // operational state child nodes } }
4.23.3.4. Example: Create a Temporary NMDA Module
Create a new module that contains the top-level operational state data nodes that would have been available before they were combined with configuration data nodes (to be NMDA compliant). module example-foo-state { namespace "urn:example.com:params:xml:ns:yang:example-foo-state"; prefix "foo-s"; // import new or converted module; not used in this example import example-foo { prefix foo; } container foo-state { config false; status deprecated; // operational state child nodes } }4.24. Performance Considerations
It is generally likely that certain YANG statements require more runtime resources than other statements. Although there are no performance requirements for YANG validation, the following information MAY be considered when designing YANG data models: o Lists are generally more expensive than containers o "when" statement evaluation is generally more expensive than "if-feature" or "choice" statements o "must" statements are generally more expensive than "min-entries", "max-entries", "mandatory", or "unique" statements o "identityref" leafs are generally more expensive than "enumeration" leafs o "leafref" and "instance-identifier" types with "require-instance" set to true are generally more expensive than if "require-instance" is set to false4.25. Open Systems Considerations
Only the modules imported by a particular module can be assumed to be present in an implementation. An open system MAY include any combination of YANG modules.
4.26. Guidelines for Constructs Specific to YANG 1.1
The set of guidelines for YANG 1.1 will grow as operational experience is gained with the new language features. This section contains an initial set of guidelines for new YANG 1.1 language features.4.26.1. Importing Multiple Revisions
Standard modules SHOULD NOT import multiple revisions of the same module into a module. This MAY be done if independent definitions (e.g., enumeration typedefs) from specific revisions are needed in the importing module.4.26.2. Using Feature Logic
The YANG 1.1 feature logic is much more expressive than YANG 1.0. A "description" statement SHOULD describe the "if-feature" logic in text, to help readers understand the module. YANG features SHOULD be used instead of the "when" statement, if possible. Features are advertised by the server, and objects conditional by the "if-feature" statement are conceptually grouped together. There is no such commonality supported for "when" statements. Features generally require less server implementation complexity and runtime resources than objects that use "when" statements. Features are generally static (i.e., set when a module is loaded and not changed at runtime). However, every client edit might cause a "when" statement result to change.4.26.3. "anyxml" versus "anydata"
The "anyxml" statement MUST NOT be used to represent a conceptual subtree of YANG data nodes. The "anydata" statement MUST be used for this purpose.4.26.4. "action" versus "rpc"
The use of "action" statements or "rpc" statements is a subjective design decision. RPC operations are not associated with any particular data node. Actions are associated with a specific data node definition. An "action" statement SHOULD be used if the protocol operation is specific to a subset of all data nodes instead of all possible data nodes.
The same action name MAY be used in different definitions within different data node. For example, a "reset" action defined with a data node definition for an interface might have different parameters than for a power supply or a VLAN. The same action name SHOULD be used to represent similar semantics. The NETCONF Access Control Model (NACM) [RFC8341] does not support parameter-based access control for RPC operations. The user is given permission (or not) to invoke the RPC operation with any parameters. For example, if each client is only allowed to reset their own interface, then NACM cannot be used. For example, NACM cannot enforce access control based on the value of the "interface" parameter, only the "reset" operation itself: rpc reset { input { leaf interface { type if:interface-ref; mandatory true; description "The interface to reset."; } } } However, NACM can enforce access control for individual interface instances, using a "reset" action. If the user does not have read access to the specific "interface" instance, then it cannot invoke the "reset" action for that interface instance: container interfaces { list interface { ... action reset { } } }4.27. Updating YANG Modules (Published versus Unpublished)
YANG modules can change over time. Typically, new data model definitions are needed to support new features. YANG update rules defined in Section 11 of [RFC7950] MUST be followed for published modules. They MAY be followed for unpublished modules. The YANG update rules only apply to published module revisions. Each organization will have their own way to identify published work that is considered to be stable and unpublished work that is considered to
be unstable. For example, in the IETF, the RFC document is used for published work, and the I-D is used for unpublished work.