| Network Working Group | M. Bjorklund, Editor |
| Internet Draft | Tail-f Systems |
| <draft-ietf-netmod-yang-02> | November 3, 2008 |
| Intended status: Standards Track | |
| Expires: May 2009 |
YANG - A data modeling language for NETCONF
draft-ietf-netmod-yang-02
By submitting this Internet-Draft, each author represents that any applicable patent or other IPR claims of which he or she is aware have been or will be disclosed, and any of which he or she becomes aware will be disclosed, in accordance with Section 6 of BCP 79.
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts.
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as “work in progress”.
The list of current Internet-Drafts can be accessed at <http://www.ietf.org/ietf/1id-abstracts.txt>.
The list of Internet-Draft Shadow Directories can be accessed at <http://www.ietf.org/shadow.html>.
This Internet-Draft will expire in May 2009.
YANG is a data modeling language used to model configuration and state data manipulated by the NETCONF protocol, NETCONF remote procedure calls, and NETCONF notifications.
Today, the NETCONF protocol [RFC4741] lacks a standardized way to create data models. Instead, vendors are forced to use proprietary solutions. In order for NETCONF to be a interoperable protocol, models must be defined in a vendor-neutral way. YANG provides the language and rules for defining such models for use with NETCONF.
YANG is a data modeling language used to model configuration and state data manipulated by the NETCONF protocol, NETCONF remote procedure calls, and NETCONF notifications. This document describes the syntax and semantics of the YANG language, how the data model defined in a YANG module is represented in XML, and how NETCONF operations are used to manipulate the data.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14, [RFC2119].
A mandatory node is one of:
YANG is a language used to model data for the NETCONF protocol. A YANG module defines a hierarchy of nodes which can be used for NETCONF-based operations, including configuration, state data, remote procedure calls (RPCs), and notifications. This allows a complete description of all data sent between a NETCONF client and server.
YANG models the hierarchical organization of data as a tree in which each node has a name, and either a value or a set of child nodes. YANG provides clear and concise descriptions of the nodes, as well as the interaction between those nodes.
YANG structures data models into modules and submodules. A module can import data from other external modules, and include data from submodules. The hierarchy can be extended, allowing one module to add data nodes to the hierarchy defined in another module. This augmentation can be conditional, with new nodes to appearing only if certain conditions are met.
YANG models can describe constraints to be enforced on the data, restricting the appearance or value of nodes based on the presence or value of other nodes in the hierarchy. These constraints are enforceable by either the client or the server, and valid content must abide by them.
YANG defines a set of built-in types, and has a type mechanism through which additional types may be defined. Derived types can restrict their base type's set of valid values using mechanisms like range or pattern restrictions that can be enforced by clients or servers. They can also define usage conventions for use of the derived type, such as a string-based type that contains a host name.
YANG permits the definition of complex types using reusable grouping of nodes. The instantiation of these groupings can refine or augment the nodes, allowing it to tailor the nodes to its particular needs. Derived types and groupings can be defined in one module or submodule and used in either that location or in another module or submodule that imports or includes it.
YANG organizational constructs include defining lists of nodes with the same names and identifying the keys which distinguish list members from each other. Such lists may be defined as either sorted by user or automatically sorted by the system. For user-sorted lists, operations are defined for manipulating the order of the nodes.
YANG modules can be translated into an XML format called YIN (Section 11), allowing applications using XML parsers and XSLT scripts to operate on the models.
YANG strikes a balance between high-level object-oriented modeling and low-level bits-on-the-wire encoding. The reader of a YANG module can easily see the high-level view of the data model while seeing how the object will be encoded in NETCONF operations.
YANG is an extensible language, allowing extension statements to be defined by standards bodies, vendors, and individuals. The statement syntax allows these extensions to coexist with standard YANG statements in a natural way, while making extensions stand out sufficiently for the reader to notice them.
YANG resists the tendency to solve all possible problems, limiting the problem space to allow expression of NETCONF data models, not arbitrary XML documents or arbitrary data models. The data models described by YANG are designed to be easily operated upon by NETCONF operations.
To the extent possible, YANG maintains compatibility with SNMP's SMIv2 (Structure of Management Information version 2 [RFC2578], [RFC2579]). SMIv2-based MIB modules can be automatically translated into YANG modules for read-only access. However YANG is not concerned with reverse translation from YANG to SMIv2.
Like NETCONF, YANG targets smooth integration with device's native management infrastructure. This allows implementations to leverage their existing access control mechanisms to protect or expose elements of the data model.
This section introduces some important constructs used in YANG that will aid in the understanding of the language specifics in later sections.
YANG defines modules using the "module" statement. This statement defines the name of the module, which is typically used as the base name of the file containing the module. The file suffix ".yang" is typically used for YANG files. A module contains three types of statements: module-header statements, revision statements, and definition statements. The module header statements describe the module and give information about the module itself, the revision statements give information about the history of the module, and the definition statements are the body of the module where the data model is defined.
Submodule are partial modules that contribute derived types, groupings, data nodes, RPCs and notifications to a module. A module may include a number of submodules, but each submodule may belong to only one module. The "include" statement allows a module or submodule to reference material in submodules, and the "import" statement allows references to material defined in other modules.
To reference an item that is defined in an external module it MUST be imported. Identifiers that are neither defined, imported nor included MUST NOT be visible in the local module.
To reference an item that is defined in one of its submodules, the module MUST include the submodule.
A submodule that needs to reference an item defined in another submodule of the same module, MUST include this submodule.
There MUST NOT be any circular chains of imports or includes. For example, if submodule "a" includes submodule "b", "b" cannot include "a".
When a definition in an external module is referenced, a locally defined prefix MUST be used, followed by ":", and then the external identifier. References to definitions in the local module MAY use the prefix notation. References to built-in data types (e.g., int32) MUST NOT use the prefix notation.
Forward references are allowed in YANG.
YANG defines four types of nodes for data modeling. In each of the following subsections, the example shows the YANG syntax as well as a corresponding NETCONF XML representation.
A leaf node contains simple data like an integer or a string. It has exactly one value of a particular type, and no child nodes.
YANG Example:
leaf host-name {
type string;
description "Hostname for this system";
}
NETCONF XML Encoding:
<host-name>my.example.com</host-name>
The "leaf" statement is covered in Section 7.6.
A leaf-list is a sequence of leaf nodes with exactly one value of a particular type per leaf.
YANG Example:
leaf-list domain-search {
type string;
description "List of domain names to search";
}
NETCONF XML Encoding:
<domain-search>high.example.com</domain-search> <domain-search>low.example.com</domain-search> <domain-search>everywhere.example.com</domain-search>
The "leaf-list" statement is covered in Section 7.7.
A container node is used to group related nodes in a subtree. A container has only child nodes and no value. A container may contain any number of child nodes of any type (including leafs, lists, containers, and leaf-lists).
YANG Example:
container system {
container login {
leaf message {
type string;
description
"Message given at start of login session";
}
}
}
NETCONF XML Encoding:
<system>
<login>
<message>Good morning, Dave</message>
</login>
</system>
The "container" statement is covered in Section 7.5.
A list is a sequence of list entries. An entry is like a structure or a record. A list entry is uniquely identified by the values of its key leafs. A list entry can have multiple keys. A list entry may contain any number of child nodes of any type (including leafs, lists, containers etc.).
YANG Example:
list user {
key "name";
leaf name {
type string;
}
leaf full-name {
type string;
}
leaf class {
type string;
}
}
NETCONF XML Encoding:
<user>
<name>glocks</name>
<full-name>Goldie Locks</full-name>
<class>intruder</class>
</user>
<user>
<name>snowey</name>
<full-name>Snow White</full-name>
<class>free-loader</class>
</user>
<user>
<name>rzull</name>
<full-name>Repun Zell</full-name>
<class>tower</class>
</user>
The "list" statement is covered in Section 7.8.
These statements are combined to define the module:
// Contents of "acme-system.yang"
module acme-system {
namespace "http://acme.example.com/system";
prefix "acme";
organization "ACME Inc.";
contact "joe@acme.example.com";
description
"The module for entities implementing the ACME system.";
revision 2007-06-09 {
description "Initial revision.";
}
container system {
leaf host-name {
type string;
description "Hostname for this system";
}
leaf-list domain-search {
type string;
description "List of domain names to search";
}
container login {
leaf message {
type string;
description
"Message given at start of login session";
}
list user {
key "name";
leaf name {
type string;
}
leaf full-name {
type string;
}
leaf class {
type string;
}
}
}
}
}
YANG can model operational data, as well as configuration data, based on the "config" statement. When a node is tagged with "config false", its subhierarchy is flagged as operational data, to be reported using NETCONF's <get> operation, not the <get-config> operation. Parent containers, lists, and key leafs are reported also, giving the context for the operational data.
In this example, two leafs are defined for each interface, a configured speed and an observed speed. The observed speed is not configuration, so it can be returned with NETCONF <get> operations, but not with <get-config> operations. The observed speed is not configuration data, and cannot be manipulated using <edit-config>.
list interface {
key "name";
config true;
leaf name {
type string;
}
leaf speed {
type enumeration {
enum 10m;
enum 100m;
enum auto;
}
}
leaf observed-speed {
type uint32;
config false;
}
}
YANG has a set of built-in types, similar to those of many programming languages, but with some differences due to special requirements from the management domain. The following table summarizes the built-in types discussed in Section 9:
| Name | Type | Description |
|---|---|---|
| binary | Text | Any binary data |
| bits | Text/Number | A set of bits or flags |
| boolean | Text | "true" or "false" |
| empty | Empty | A leaf that does not have any value |
| enumeration | Text/Number | Enumerated strings with associated numeric values |
| float32 | Number | 32-bit IEEE floating point real number |
| float64 | Number | 64-bit IEEE floating point real number |
| identityref | Text | A reference to an abstract identity |
| instance-identifier | Text | References a data tree node |
| int8 | Number | 8-bit signed integer |
| int16 | Number | 16-bit signed integer |
| int32 | Number | 32-bit signed integer |
| int64 | Number | 64-bit signed integer |
| keyref | Text/Number | A reference to a list's key value |
| string | Text | Human readable string |
| uint8 | Number | 8-bit unsigned integer |
| uint16 | Number | 16-bit unsigned integer |
| uint32 | Number | 32-bit unsigned integer |
| uint64 | Number | 64-bit unsigned integer |
| union | Text/Number | Choice of member types |
The "type" statement is covered in Section 9.
YANG can define derived types from base types using the "typedef" statement. A base type can be either a built-in type or a derived type, allowing a hierarchy of derived types.
A derived type can be used as the argument for the "type" statement.
YANG Example:
typedef percent {
type uint16 {
range "0 .. 100";
}
description "Percentage";
}
leaf completed {
type percent;
}
NETCONF XML Encoding:
<completed>20</completed>
The "typedef" statement is covered in Section 7.3.
Groups of nodes can be assembled into the equivalent of complex types using the "grouping" statement. "grouping" defines a set of nodes that are instantiated with the "uses" statement:
grouping target {
leaf address {
type inet:ip-address;
description "Target IP address";
}
leaf port {
type inet:port-number;
description "Target port number";
}
}
container peer {
container destination {
uses target;
}
}
NETCONF XML Encoding:
<peer>
<destination>
<address>192.0.2.1</address>
<port>830</port>
</destination>
</peer>
The grouping can be refined as it is used, allowing certain statements to be overridden. In this example, the description is refined:
container connection {
container source {
uses target {
refine "address" {
description "Source IP address";
}
refine "port" {
description "Source port number";
}
}
}
container destination {
uses target {
refine "address" {
description "Destination IP address";
}
refine "port" {
description "Destination port number";
}
}
}
}
The "grouping" statement is covered in Section 7.11.
YANG allows the data model to segregate incompatible nodes into distinct choices using the "choice" and "case" statements. The "choice" statement contains a set of "case" statements which define sets of schema nodes that cannot appear together. Each "case" may contain multiple nodes, but each node may appear in only one "case" under a "choice".
When an element from one case is created, all elements from all other cases are implicitly deleted. The device handles the enforcement of the constraint, preventing incompatibilities from existing in the configuration.
The choice and case nodes appear only in the schema tree, not in the data tree or XML encoding. The additional levels of hierarchy are not needed beyond the conceptual schema.
YANG Example:
container food {
choice snack {
mandatory true;
case sports-arena {
leaf pretzel {
type empty;
}
leaf beer {
type empty;
}
}
case late-night {
leaf chocolate {
type enumeration {
enum dark;
enum milk;
enum first-available;
}
}
}
}
}
NETCONF XML Encoding:
<food>
<chocolate>first-available</chocolate>
</food>
The "choice" statement is covered in Section 7.9.
YANG allows a module to insert additional nodes into data models, including both the current module (and its submodules) or an external module. This is useful e.g. for vendors to add vendor-specific parameters to standard data models in an interoperable way.
The "augment" statement defines the location in the data model hierarchy where new nodes are inserted, and the "when" statement defines the conditions when the new nodes are valid.
YANG Example:
augment system/login/user {
when "class != 'wheel'";
leaf uid {
type uint16 {
range "1000 .. 30000";
}
}
}
This example defines a "uid" node that only is valid when the user's "class" is not "wheel".
If a module augments another model, the XML representation of the data will reflect the prefix of the augmenting model. For example, if the above augmentation were in a module with prefix "other", the XML would look like:
NETCONF XML Encoding:
<user>
<name>alicew</name>
<full-name>Alice N. Wonderland</full-name>
<class>drop-out</class>
<other:uid>1024</other:uid>
</user>
The "augment" statement is covered in Section 7.15.
YANG allows the definition of NETCONF RPCs. The method names, input parameters and output parameters are modeled using YANG data definition statements.
YANG Example:
rpc activate-software-image {
input {
leaf image-name {
type string;
}
}
output {
leaf status {
type string;
}
}
}
NETCONF XML Encoding:
<rpc message-id="101"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<activate-software-image xmlns="http://acme.example.com/system">
<name>acmefw-2.3</name>
</activate-software-image>
</rpc>
<rpc-reply message-id="101"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<status xmlns="http://acme.example.com/system">
The image acmefw-2.3 is being installed.
</status>
</rpc-reply>
The "rpc" statement is covered in Section 7.13.
YANG allows the definition of notifications suitable for NETCONF. YANG data definition statements are used to model the content of the notification.
YANG Example:
notification link-failure {
description "A link failure has been detected";
leaf if-name {
type keyref {
path "/interfaces/interface/name";
}
}
leaf if-admin-status {
type ifAdminStatus;
}
}
NETCONF XML Encoding:
<notification
xmlns="urn:ietf:params:netconf:capability:notification:1.0">
<eventTime>2007-09-01T10:00:00Z</eventTime>
<link-failure xmlns="http://acme.example.com/system">
<if-name>so-1/2/3.0</if-name>
<if-admin-status>up</if-admin-status>
</link-failure>
</notification>
The "notification" statement is covered in Section 7.14.
The module is the base unit of definition in YANG. A module defines a single data model. A module can define a complete, cohesive model, or augment an existing data model with additional nodes.
A NETCONF server may implement a number of modules, allowing multiple views of the same data, or multiple views of disjoint subsections of the device's data. Alternatively, the server may implement only one module that defines all available data. Any modules that are implemented MUST be available for all defined datastores.
A module may be divided into submodules, based on the needs of the module owner. The external view remains that of a single module, regardless of the presence or size of its submodules.
A module uses the "include" statement to include its submodules, and the "import" statement to reference external modules. Similarly, a submodule may use the "import" statement to reference other modules, and may use the "include" statement to reference other submodules within its module. A module or submodule may not include submodules from other modules, nor may a submodule import its own module.
The names of all standard modules must be unique, but different revisions of the same module should have the same name. Developers of enterprise modules are encouraged to choose names for their modules that will have a low probability of colliding with standard or other enterprise modules, e.g., by using the enterprise or organization name as a prefix.
YANG allows modeling of data in multiple hierarchies, where data may have more than one root node. Models that have multiple roots nodes are sometimes convenient, and are supported by YANG.
YANG modules and submodules are typically stored in files, one module or submodule per file, with the name of the file given by the concatenation of the module or submodule name and the file suffix ".yang". YANG compilers can find imported modules and included submodules via this convention. While the YANG language defines modules, tools may compile submodules independently for performance and manageability reasons. Many errors and warnings that cannot be detected during submodule compilation may be delayed until the submodules are linked into a cohesive module.
While YANG models the configuration as a data tree, it can be used in an object-based manner as well.
The configuration and state data of the device is modeled as a tree of object instances (objects for short). Each object in the tree has a type name (or managed object class name), a namespace, a (possibly empty) set of attributes and a (possibly empty) set of child objects.
A managed object class could be defined as a grouping, containing just one list. Attributes should be defined as leafs inside the list. Child objects should be defined with the corresponding uses statements.
A defined grouping unambiguously defines its properties, it has its own unique name, so when it is referred to in the "uses" statement it is always the same well defined set of properties that we are using.
The data tree can be defined as one or more top level containers containing managed object classes defined as groupings. All further levels of the data tree are defined by managed object classes containing further managed objects.
All YANG definitions are specified within a particular XML Namespace. Each module defines an XML namespace as a globally unique URI [RFC3986]. A NETCONF client or server uses the namespace during XML encoding of data.
The namespace URI is advertised as a capability in the NETCONF <hello> message to indicate support for the YANG module by a NETCONF server. The capability URI advertised MUST be on the form:
capability-string = namespace-uri [ parameter-list ]
parameter-list = "?" parameter *( "&" parameter )
parameter = revision-parameter /
module-parameter /
feature-parameter /
deviation-parameter
revision-parameter = "revision=" revision-number
module-parameter = "module=" module-name
feature-parameter = "features=" feature *( "," feature )
deviation-parameter = "deviations=" deviation *( "," deviation )
Where "revision-number" is the revision of the module (see Section 7.1.9) that the server implements, "module-name" is the name of module as it appears in the "module" statement (see Section 7.1), "namespace-uri" is the namespace for the module as it appears in the "namespace" statement, "feature" is the name of an optional feature implemented by the device (see Section 7.18.1), and "deviation" is the name of a module defining device deviations (see Section 7.18.3).
Namespaces for standard module names will be assigned by IANA. They MUST be unique (but different revisions of the same module should have the same namespace).
Namespaces for private module names will be assigned by the organization owning the module without a central registry. It is recommended to choose namespaces that will have a low probability of colliding with standard or other enterprise modules, e.g. by using the enterprise or organization name in the namespace.
The "namespace" statement is covered in Section 7.1.3.
YANG defines its own namespace for NETCONF <edit-config> operations. This namespace is "urn:ietf:params:xml:ns:yang:1" [XXX IANA].
YANG supports two styles for ordering the entries within a list. In many lists, the order of list entries does not impact the implementation of the list's configuration, and the device is free to sort the list entries in any reasonable order. The "description" string for the list may suggest an order. YANG calls this style of list "system ordered" and they are indicated with the statement "ordered-by system".
For example, a list of valid users would typically be sorted alphabetically, since the order in which the users appeared in the configuration would not impact the creation of those users' accounts.
In the other style of lists, the order of list entries matters for the implementation of the list's configuration and the user is responsible for ordering the entries, while the device maintains that order. YANG calls this style of list "user ordered" and they are indicated with the statement "ordered-by user".
For example, the order in which firewall filters entries are applied to incoming traffic may affect how that traffic is filtered. The user would need to decide if the filter entry that discards all TCP traffic should be applied before or after the filter entry that allows all traffic from trusted interfaces. The choice of order would be crucial.
YANG provides a rich set of facilities within NETCONF's <edit-config> operation which allow the order of list entries in user-ordered lists to be controlled. List entries may be inserted or rearranged, positioned as the first or last entry in the list, or positioned before or after another specific entry.
The "ordered-by" statement is covered in Section 7.7.4.
YANG supports two styles of containers, those which exist only for organizing the hierarchy of data nodes, and those whose presence in the configuration has an explicit meaning.
In the first style, the container has no meaning of its own, existing only to contain child nodes. The container data node is implicitly created when the first child data node is created. The data node is implicitly deleted when the last non-key child is deleted, since an empty container has no meaning.
For example, the set of scrambling options for SONET interfaces may be placed inside a "scrambling" container to enhance the organization of the configuration hierarchy, and to keep these nodes together. The "scrambling" node itself has no meaning, so removing the node when it becomes empty relieves the user from the task of performing this task.
In the second style, the presence of the container itself is configuration data, representing a single bit of configuration data. The container acts as both a configuration knob and a means of organizing related configuration. These containers are explicitly created and deleted.
YANG calls this style a "presence container" and they are indicated using the "presence" statement, which takes as its argument a text string indicating what the presence of the node means.
For example, an "ssh" container may turn on the ability to log into the device using ssh, but can also contain any ssh-related configuration knobs, such as connection rates or retry limits.
The "presence" statement is covered in Section 7.5.4.
YANG uses static scoping. Grouping definitions are resolved in the context in which they are defined, rather than the context in which they are used. Users of groupings are not required to import modules or include submodules to satisfy all references made by the grouping.
For example, if a module defines a grouping in which a type is referenced, when the grouping is used in a second module, the type is resolved in the original module, not the second module. There is no worry over conflicts if both modules define the type, since there is no ambiguity.
Typedefs and groupings may appear nested under many YANG statements, allowing these to be lexically scoped by the hierarchy under which they appear. This allows types and groupings to be defined near where they are used, rather than placing them at the top level of the hierarchy. The close proximity increases readability.
Scoping also allows types to be defined without concern for naming conflicts between types in different submodules. Type names can be specified without adding leading strings designed to prevent name collisions within large modules.
Finally, scoping allows the module author to keep types and groupings private to their module or submodule, preventing their reuse. Since only top-level types and groupings can be used outside the module or submodule, the developer has more control over what pieces of their module are presented to the outside world, supporting the need to hide internal information and maintaining a boundary between what is shared with the outside world and what is kept private.
Scoped definitions MUST NOT shadow definitions at a higher scope. A type or group cannot be defined if a higher level in the schema hierarchy has a definition with a matching identifier.
When a YANG implementation resolves a reference to an unprefixed type or grouping, or one which uses the prefix of the local module, it searches up the levels of hierarchy in the schema tree, starting at the current level, for the definition of the type or grouping.
Conformance is a measure of how accurately a device follows the model. Generally speaking, devices are responsible for implementing the model faithfully, allowing applications to treat devices which implement the model identically. Deviations from the model can reduce the utility of the model and increase fragility into applications that use it.
YANG modelers have three levels of conformance:
We will consider each of these in sequence.
The model defines a contract between the client and server, which allows both parties to have faith the other knows the syntax and semantics behind the modeled data. The strength of YANG lies in the strength of this contract and the mindless devotion with which implementers follow it.
In many models, the modeler will allow sections of the model to be conditional, based on the device. The device controls whether these conditional portions of the model are supported or valid for that particular device.
For example, a syslog data model may choose to include the ability to save logs locally, but the modeler will realize that this is only possible if the device has local storage. If there is no local storage, an application should not tell the device to save logs.
YANG supports this conditional mechanism using a construct called "features". A module may declare any number of features, identified by simple strings, and may make portions of the module optional based on those feature. If the device supports a feature, then the corresponding portions of the module are valid for that device. If the device doesn't support the feature, those parts of the module are not valid, and applications should behave accordingly.
Features give the modeler a mechanism for making portions of the module conditional in a manner that is controlled by the device. The model can express constructs which are not universally present in all devices. These features are included in the model definition, allowing a consistent view and allowing applications to learn which features are supported and tailor their behavior to the device.
Features are defined using the "feature" statement. Definitions in the module that are conditional to the feature are noted by the "if-feature" statement with the name of the feature as its argument.
Further details are available in Section 7.18.1.
In an ideal world, all devices would be required to implement the model exactly as defined, and deviations from the model would not be allowed. But in the real world, devices are often not able or willing to implement the model as written. For YANG-based automation to deal with these device deviations, a mechanism must exist for devices to inform applications of the specifics of such deviations.
For example, a BGP module may allow any number of BGP peers, but a particular device may only support 16 BGP peers. Any application configuring the 17th peer will receive an error. While an error may suffice to let the application know it cannot add another peer, it would be far better if the application had prior knowledge of this limitation and could prevent the user from starting down the path that could not succeed.
Device deviations are declared using the "deviation" statement, which takes as its argument a string which identifies a node in the schema tree. The contents of the statement details the manner in which the device implementation deviates from the contract as defined in the module.
Devices indicate the names of supported features and device deviations via the <hello> message. In hello messages, the features are encoded in the "features" parameter within the URI. The value of this parameter is a comma-separated list of feature names which the device supports for the specific module.
<hello>
<capability>
http://example.com/mod/mcp?features=feat1&module=mcp
</capability>
<capability>
http://example.com/mod/some?module=some&features=one,two,three
</capability>
</hello>
Device deviations are announced via the "deviations" parameter. The value of the deviations parameter is a comma-separated list of modules containing deviations from the capability's module.
<hello>
<capability>
http://example.com/abc?deviations=my-devs
</capability>
</hello>
The YANG syntax is similar to that of SMIng [RFC3780] and programming languages like C and C++. This C-like syntax was chosen specifically for its readability, since YANG values the time and effort of the readers of models above those of modules writers and YANG tool-chain developers. This section introduces the YANG syntax.
YANG modules are written in the UTF-8 [RFC3629] character set.
YANG modules are parsed as a series of tokens. This section details the rules for recognizing tokens from an input stream. YANG tokenization rules are both simple and powerful. The simplicity is driven by a need to keep the parsers easy to implement, while the power is driven by the fact that modelers need to express their models in readable formats.
Comments are C++ style. A single line comment starts with "//" and ends at the end of the line. A block comment is enclosed within "/*" and "*/".
A token in YANG is either a keyword, a string, ";", "{", or "}". A string can be quoted or unquoted. A keyword is either one of the core YANG keywords defined in this document, or a prefix identifier, followed by ":", followed by a language extension keyword. Keywords are case sensitive. See Section 6.2 for a formal definition of identifiers.
If a string contains any whitespace characters, a semicolon (";"), curly braces ("{" or "}"), or comment sequences ("//", "/*", or "*/"), then it MUST be enclosed within double or single quotes.
If the double quoted string contains a line break followed by whitespace which is used to indent the text according to the layout in the YANG file, this leading whitespace is stripped from the string, up to at most the same column of the double quote character.
If the double quoted string contains whitespace before a line break, this trailing whitespace is stripped from the string.
A single quoted string (enclosed within ' ') preserves each character within the quotes. A single quote character can not occur in a single quoted string, even when preceded by a backslash.
If a quoted string is followed by a plus character ("+"), followed by another quoted string, the two strings are concatenated into one quoted string, allowing multiple concatenations to build one quoted string. Whitespace trimming of double quoted strings is done before concatenation.
Within a double quoted string (enclosed within " "), a backslash character introduces a special character, which depends on the character that immediately follows the backslash:
\n new line \t a tab character \" a double quote \\ a single backslash
The following strings are equivalent:
hello "hello" 'hello' "hel" + "lo" 'hel' + "lo"
The following examples show some special strings:
"\"" - string containing a double quote
'"' - string containing a double quote
"\n" - string containing a newline character
'\n' - string containing a backslash followed
by the character n
The following examples show some illegal strings:
'''' - a single-quoted string cannot contain single quotes """ - a double quote must be escaped in a double quoted string
The following strings are equivalent:
"first line
second line"
"first line\n" + " second line"
Identifiers are used to identify different kinds of YANG items by name. Each identifier starts with an upper-case or lower-case ASCII letter or an underscore character, followed by zero or more ASCII letters, digits, underscore characters, hyphens, and dots. Implementations MUST support identifiers up to 63 characters in length. Identifiers are case sensitive. The identifier syntax is formally defined by the rule "identifier" in Section 12. Identifiers can be specified as quoted or unquoted strings.
Each identifier is valid in a namespace which depends on the type of the YANG item being defined:
All identifiers defined in a namespace MUST be unique.
A YANG module contains a sequence of statements. Each statement starts with a keyword, followed by zero or one argument, followed either by a semicolon (";") or a block of substatements enclosed within curly braces ("{ }"):
statement = keyword [argument] (";" / "{" *statement "}")
The argument is a string, as defined in Section 6.1.2.
A module can introduce YANG extensions by using the "extension" keyword (see Section 7.17). The extensions can be imported by other modules with the "import" statement (see Section 7.1.5). When an imported extension is used, the extension's keyword must be qualified using the prefix with which the extension's module was imported. If an extension is used in the module where it is defined, the extension's keyword must be qualified with the module's prefix.
Since submodules cannot include the parent module, any extensions in the module which need to be exposed to submodules must be defined in a submodule. Submodules can then include this submodule to find the definition of the extension.
YANG relies on XPath 1.0 [XPATH] as a notation for specifying many inter-node references and dependencies. NETCONF clients and servers are not required to implement an XPath interpreter, but MUST ensure that the requirements encoded in the data model are enforced. The manner of enforcement is an implementation decision. The XPath expressions MUST be valid, but any implementation may choose to implement them by hand, rather than using the XPath expression directly.
XPath expressions are evaluated in the context of the current node, with the namespace of the current module defined as the null namespace. References to identifiers in external modules MUST be qualified with appropriate prefixes, and references to the current module and its submodules MAY use a prefix.
The following sections describe all of the YANG core statements.
Note that even a statement which does not have any substatements defined in core YANG can have vendor-specific extensions as substatements. For example, the "description" statement does not have any substatements defined in core YANG, but the following is legal:
description "some text" {
acme:documentation-flag 5;
}
The "module" statement defines the module's name, and groups all statements which belong to the module together. The "module" statement's argument is the name of the module, followed by a block of substatements that hold detailed module information. The module name follows the rules for identifiers in Section 6.2.
Standard module names will be assigned by IANA. The names of all standard modules MUST be unique (but different revisions of the same module should have the same name).
Private module names will be assigned by the organization owning the module without a central registry. It is recommended to choose names for their modules that will have a low probability of colliding with standard or other enterprise modules, e.g. by using the enterprise or organization name as a prefix.
A module SHOULD have the following layout:
module <module-name> {
// header information
<yang-version statement>
<namespace statement>
<prefix statement>
// linkage statements
<import statements>
<include statements>
// meta information
<organization statement>
<contact statement>
<description statement>
<reference statement>
// revision history
<revision statements>
// module definitions
<extension statements>
<feature statements>
<typedef statements>
<grouping statements>
<container statements>
<leaf statements>
<leaf-list statements>
<list statements>
<choice statements>
<uses statements>
<rpc statements>
<notification statements>
<augment statements>
<deviation statements>
}
| substatement | section | cardinality |
|---|---|---|
| anyxml | 7.10 | 0..n |
| augment | 7.15 | 0..n |
| choice | 7.9 | 0..n |
| contact | 7.1.8 | 0..1 |
| container | 7.5 | 0..n |
| description | 7.19.3 | 0..1 |
| deviation | 7.18.3 | 0..n |
| extension | 7.17 | 0..n |
| feature | 7.18.1 | 0..n |
| grouping | 7.11 | 0..n |
| import | 7.1.5 | 0..n |
| include | 7.1.6 | 0..n |
| leaf | 7.6 | 0..n |
| leaf-list | 7.7 | 0..n |
| list | 7.8 | 0..n |
| namespace | 7.1.3 | 1 |
| notification | 7.14 | 0..n |
| organization | 7.1.7 | 0..1 |
| prefix | 7.1.4 | 1 |
| reference | 7.19.4 | 0..1 |
| revision | 7.1.9 | 0..n |
| rpc | 7.13 | 0..n |
| typedef | 7.3 | 0..n |
| uses | 7.12 | 0..n |
| yang-version | 7.1.2 | 0..1 |
The "yang-version" statement specifies which version of the YANG language was used in developing the module. The statement's argument contains value "1", which is the current yang version and the default value.
This statement is intended for future-proofing the syntax of YANG against possible changes in later versions of YANG. Since the current version is the default value, the statement need not appear in YANG modules until a future version is defined. When a new version is defined, YANG modules can either use version 2 statements and add the "yang-version 2" statement, or remain within the version 1 feature set and continue to use the default setting of "yang-version 1".
The "namespace" statement defines the XML namespace for all XML elements defined by the module. Its argument is the URI of the namespace.
See also Section 5.4.
The "prefix" statement is used to define the prefix associated with the namespace of a module. The "prefix" statement's argument is the prefix string which is used as a prefix to access a module. The prefix string may be used to refer to definitions contained in the module, e.g. "if:ifName". A prefix follows the same rules as an identifier (see Section 6.2).
When used inside the "module" statement, the "prefix" statement defines the prefix to be used when this module is imported. To improve readability of the NETCONF XML, a NETCONF client or server which generates XML or XPath that use prefixes, the prefix defined by a module SHOULD be used, unless there is a conflict.
When used inside the "import" statement, the "prefix" statement defines the prefix to be used when accessing definitions inside the imported module. When a reference to an identifier from the imported module is used, the prefix string for the module from which objects are being imported is used in combination with a colon (":") and the identifier, e.g. "if:ifIndex". To improve readability of YANG modules, the prefix defined by a module SHOULD be used when the module is imported, unless there is a conflict.
All prefixes, including the prefix for the module itself MUST be unique within the module or submodule.
The "import" statement makes definitions from one module available inside another module or submodule. The argument is the name of the module to import, and the statement is followed by a block of substatements that holds detailed import information.
All identifiers contained in an imported module are imported into the current module or submodule, so that they can be referenced by definitions in the current module or submodule. The mandatory "prefix" substatement assigns a prefix for the imported module which is scoped to the importing module or submodule. Multiple "import" statements may be specified to import from different modules.
The import's Substatements
| substatement | section | cardinality |
|---|---|---|
| prefix | 7.1.4 | 1 |
The "include" statement is used to make content from a submodule available to the module. The argument is an identifier which is the name of the submodule to include. Modules are only allowed to include submodules that belong to that module, as defined by the "belongs-to" statement (see Section 7.2.2).
When a module includes a submodule, it incorporates the contents of the submodule into the node hierarchy of the module. When a submodule includes another submodule, the target submodule's definitions are made available to the current submodule.
The "organization" statement defines the party responsible for this module. The argument is a string which is used to specify a textual description of the organization(s) under whose auspices this module was developed.
The "contact" statement provides contact information for the module. The argument is a string which is used to specify the name, postal address, telephone number, and electronic mail address of the person to whom technical queries concerning this module should be sent.
The "revision" statement specifies the editorial revision history of the module, including the initial revision. A series of revisions statements detail the changes in the module's definition. The argument is a date string in the format "YYYY-MM-DD", followed by a block of substatements that holds detailed revision information. A module SHOULD have at least one initial "revision" statement. For every editorial change, a new one SHOULD be added in front of the revisions sequence, so that all revisions are in reverse chronological order.
| substatement | section | cardinality |
|---|---|---|
| description | 7.19.3 | 0..1 |
module acme-system {
namespace "http://acme.example.com/system";
prefix "acme";
import yang-types {
prefix "yang";
}
include acme-types;
organization "ACME Inc.";
contact
"Joe L. User
ACME, Inc.
42 Anywhere Drive
Nowhere, CA 95134
USA
Phone: +1 800 555 0815
EMail: joe@acme.example.com";
description
"The module for entities implementing the ACME protocol.";
revision "2007-06-09" {
description "Initial revision.";
}
// definitions follows...
}
While the primary unit in YANG is a module, a YANG module can itself be constructed out of several submodules. Submodules allow to split a complex module in several pieces where all the submodules contribute to a single namespace, which is defined by the module including the submodules.
The "submodule" statement is used to give the submodule a name, and to group all statements which belong to the submodule together.
The "submodule" statement, which must be present at most once, takes as an argument an identifier which is the name of the submodule, followed by a block of substatements that hold detailed submodule information.
Standard submodule names will be assigned by IANA. Name of all standard submodules must be unique and in addition not conflict with module names (but different revisions of the same submodule should have the same name).
Private submodule names will be assigned by the organization owning the submodule without a central registry. It is recommended to choose names for their submodules that will have a low probability of colliding with standard or other enterprise modules and submodules, e.g. by using the enterprise or organization name as a prefix.
A submodule SHOULD have the following layout:
submodule <module-name> {
<yang-version statement>
// module identification
<belongs-to statement>
// linkage statements
<import statements>
<include statements>
// meta information
<organization statement>
<contact statement>
<description statement>
<reference statement>
// revision history
<revision statements>
// module definitions
<extension statements>
<feature statements>
<typedef statements>
<grouping statements>
<container statements>
<leaf statements>
<leaf-list statements>
<list statements>
<choice statements>
<uses statements>
<rpc statements>
<notification statements>
<augment statements>
<deviation statements>
}
| substatement | section | cardinality |
|---|---|---|
| anyxml | 7.10 | 0..n |
| augment | 7.15 | 0..n |
| belongs-to | 7.2.2 | 1 |
| choice | 7.9 | 0..n |
| contact | 7.1.8 | 0..1 |
| container | 7.5 | 0..n |
| description | 7.19.3 | 0..1 |
| deviation | 7.18.3 | 0..n |
| extension | 7.17 | 0..n |
| feature | 7.18.1 | 0..n |
| grouping | 7.11 | 0..n |
| import | 7.1.5 | 0..n |
| include | 7.1.6 | 0..n |
| leaf | 7.6 | 0..n |
| leaf-list | 7.7 | 0..n |
| list | 7.8 | 0..n |
| notification | 7.14 | 0..n |
| organization | 7.1.7 | 0..1 |
| reference | 7.19.4 | 0..1 |
| revision | 7.1.9 | 0..n |
| rpc | 7.13 | 0..n |
| typedef | 7.3 | 0..n |
| uses | 7.12 | 0..n |
| yang-version | 7.1.2 | 0..1 |
The "belongs-to" statement specifies the module to which the submodule belongs. The argument is an identifier which is the name of the module. Only the module to which a submodule belongs, or another submodule that belongs to the same module, are allowed to include that submodule.
The mandatory "prefix" substatement assigns a prefix for the module to which the submodule belongs. All definitions in the local submodule and any included submodules can be accessed by using the prefix.
The belongs-to's Substatements
| substatement | section | cardinality |
|---|---|---|
| prefix | 7.1.4 | 1 |
submodule acme-types {
belongs-to "acme-system" {
prefix "acme";
}
import yang-types {
prefix "yang";
}
organization "ACME Inc.";
contact
"Joe L. User
ACME, Inc.
42 Anywhere Drive
Nowhere, CA 95134
USA
Phone: +1 800 555 0815
EMail: joe@acme.example.com";
description
"This submodule defines common ACME types.";
revision "2007-06-09" {
description "Initial revision.";
}
// definitions follows...
}
The "typedef" statement defines a new type which may be used locally in the module, in modules or submodules which include it, and by other modules which import from it. The new type is called the "derived type", and the type from which it was derived is called the "base type". All derived types can be traced back to a YANG built-in type.
The "typedef" statement's argument is an identifier which is the name of the type to be defined, and MUST be followed by a block of substatements that holds detailed typedef information.
The name of the type MUST NOT be one of the YANG built-in types. If the typedef is defined at the top level of a YANG module or submodule, the name of the type to be defined MUST be unique within the module. For details about scoping for nested typedef, see Section 5.8.
| substatement | section | cardinality |
|---|---|---|
| default | 7.3.4 | 0..1 |
| description | 7.19.3 | 0..1 |
| reference | 7.19.4 | 0..1 |
| status | 7.19.2 | 0..1 |
| type | 7.3.2 | 1 |
| units | 7.3.3 | 0..1 |
The "type" statement, which must be present, defines the base type from which this type is derived. See Section 7.4 for details.
The "units" statement, which is optional, takes as an argument a string which contains a textual definition of the units associated with the type.
The "default" statement takes as an argument a string which contains a default value for the new type.
The value of the "default" statement MUST correspond to the type specified in the "type" statement.
If the base type has a default value, and the new derived type does not specify a new default value, the base type's default value is also the default value of the new derived type. The default value MUST correspond to any restrictions in the derived type.
If the base type's default value does not correspond to the new restrictions, the derived type MUST define a new default value.
typedef listen-ipv4-address {
type inet:ipv4-address;
default "0.0.0.0";
}
The "type" statement takes as an argument a string which is the name of a YANG built-in type (see Section 9) or a derived type (see Section 7.3), followed by an optional block of substatements that are used to put further restrictions on the type.
The restrictions that can be applied depends on the type being restricted. All restriction statements are described in conjunction with the built-in types in Section 9.
| substatement | section | cardinality |
|---|---|---|
| bit | 9.7.4 | 0..n |
| enum | 9.6.4 | 0..n |
| length | 9.4.4 | 0..1 |
| path | 9.9.2 | 0..1 |
| pattern | 9.4.6 | 0..n |
| range | 9.2.4 | 0..1 |
| type | 7.4 | 0..n |
The "container" statement is used to define an interior node in the schema tree. It takes one argument, which is an identifier, followed by a block of substatements that holds detailed container information.
A container node does not have a value, but it has a list of child nodes in the data tree. The child nodes are defined in the container's substatements.
By default, a container does not carry any information, but is used to organize and give structure to the data being defined. The "presence" statement (see Section 7.5.4) is used to give semantics to the existence of the container in the data tree.
| substatement | section | cardinality |
|---|---|---|
| anyxml | 7.10 | 0..n |
| augment | 7.15 | 0..n |
| choice | 7.9 | 0..n |
| config | 7.19.1 | 0..1 |
| container | 7.5 | 0..n |
| description | 7.19.3 | 0..1 |
| grouping | 7.11 | 0..n |
| if-feature | 7.18.2 | 0..n |
| leaf | 7.6 | 0..n |
| leaf-list | 7.7 | 0..n |
| list | 7.8 | 0..n |
| must | 7.5.2 | 0..n |
| presence | 7.5.4 | 0..1 |
| reference | 7.19.4 | 0..1 |
| status | 7.19.2 | 0..1 |
| typedef | 7.3 | 0..n |
| uses | 7.12 | 0..n |
| when | 7.19.5 | 0..1 |
The "must" statement, which is optional, takes as an argument a string which contains an XPath expression. It is used to formally declare a constraint on valid data. The constraint is enforced according to the rules in Section 8.
When a data is validated, all "must" constraints are conceptually evaluated once for each corresponding instance in the data tree, and for all leafs with default values in effect. If an instance does not exist in the data tree, and it does not have a default value, its "must" statements are not evaluated.
All such constraints MUST evaluate to true for the data to be valid.
The "must" statement is ignored if the data does not represent configuration.
The XPath expression is conceptually evaluated in the following context:
The result of the XPath expression is converted to a boolean value using the standard XPath rules.
If the node with the must statement represents configuration data, any node referenced in the XPath expression MUST also represent configuration.
Note that since all leaf values in the data tree are conceptually stored in their canonical form (see Section 7.6 and Section 7.7), any XPath comparisons are done on the canonical value.
Also note that the XPath expression is conceptually evaluated. This means that an implementation does not have to use an XPath evaluator on the device. How the evaluation is done in practice is an implementation decision.
| substatement | section | cardinality |
|---|---|---|
| description | 7.19.3 | 0..1 |
| error-app-tag |