6. YANG Syntax
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 use the UTF-8 [RFC3629] character encoding.6.1. Lexical Tokenization
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.6.1.1. Comments
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 "*/".6.1.2. Tokens
A token in YANG is either a keyword, a string, a semicolon (";"), or braces ("{" or "}"). A string can be quoted or unquoted. A keyword is either one of the 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.6.1.3. Quoting
If a string contains any space or tab characters, a semicolon (";"), 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 space or tab characters that are used to indent the text according to the layout in the YANG file, this leading whitespace is stripped from the string, up to and including the column of the double quote character, or to the first non-whitespace character, whichever occurs first. In this process, a tab character is treated as 8 space characters. If the double-quoted string contains space or tab characters 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 cannot occur in a single-quoted string, even when preceded by a backslash. 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 If a quoted string is followed by a plus character ("+"), followed by another quoted string, the two strings are concatenated into one string, allowing multiple concatenations to build one string. Whitespace trimming and substitution of backslash-escaped characters in double-quoted strings is done before concatenation.6.1.3.1. Quoting Examples
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 new line 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"6.2. Identifiers
Identifiers are used to identify different kinds of YANG items by name. Each identifier starts with an uppercase or lowercase 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 64 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.6.2.1. Identifiers and Their Namespaces
Each identifier is valid in a namespace that depends on the type of the YANG item being defined. All identifiers defined in a namespace MUST be unique. o All module and submodule names share the same global module identifier namespace. o All extension names defined in a module and its submodules share the same extension identifier namespace. o All feature names defined in a module and its submodules share the same feature identifier namespace. o All identity names defined in a module and its submodules share the same identity identifier namespace.
o All derived type names defined within a parent node or at the top level of the module or its submodules share the same type identifier namespace. This namespace is scoped to all descendant nodes of the parent node or module. This means that any descendent node may use that typedef, and it MUST NOT define a typedef with the same name. o All grouping names defined within a parent node or at the top level of the module or its submodules share the same grouping identifier namespace. This namespace is scoped to all descendant nodes of the parent node or module. This means that any descendent node may use that grouping, and it MUST NOT define a grouping with the same name. o All leafs, leaf-lists, lists, containers, choices, rpcs, notifications, and anyxmls defined (directly or through a uses statement) within a parent node or at the top level of the module or its submodules share the same identifier namespace. This namespace is scoped to the parent node or module, unless the parent node is a case node. In that case, the namespace is scoped to the closest ancestor node that is not a case or choice node. o All cases within a choice share the same case identifier namespace. This namespace is scoped to the parent choice node. Forward references are allowed in YANG.6.3. Statements
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 braces ("{ }"): statement = keyword [argument] (";" / "{" *statement "}") The argument is a string, as defined in Section 6.1.2.6.3.1. Language Extensions
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 that 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. If a YANG compiler does not support a particular extension, which appears in a YANG module as an unknown-statement (see Section 12), the entire unknown-statement MAY be ignored by the compiler.6.4. XPath Evaluations
YANG relies on XML Path Language (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 syntactically correct, and all prefixes used MUST be present in the XPath context (see Section 6.4.1). An implementation may choose to implement them by hand, rather than using the XPath expression directly. The data model used in the XPath expressions is the same as that used in XPath 1.0 [XPATH], with the same extension for root node children as used by XSLT 1.0 [XSLT] (Section 3.1). Specifically, it means that the root node may have any number of element nodes as its children.6.4.1. XPath Context
All YANG XPath expressions share the following XPath context definition: o The set of namespace declarations is the set of all "import" statements' prefix and namespace pairs in the module where the XPath expression is specified, and the "prefix" statement's prefix for the "namespace" statement's URI. o Names without a namespace prefix belong to the same namespace as the identifier of the current node. Inside a grouping, that namespace is affected by where the grouping is used (see Section 7.12). o The function library is the core function library defined in [XPATH], and a function "current()" that returns a node set with the initial context node. o The set of variable bindings is empty.
The mechanism for handling unprefixed names is adopted from XPath 2.0 [XPATH2.0], and helps simplify XPath expressions in YANG. No ambiguity may ever arise because YANG node identifiers are always qualified names with a non-null namespace URI. The context node varies with the YANG XPath expression, and is specified where the YANG statement with the XPath expression is defined.6.5. Schema Node Identifier
A schema node identifier is a string that identifies a node in the schema tree. It has two forms, "absolute" and "descendant", defined by the rules "absolute-schema-nodeid" and "descendant-schema-nodeid" in Section 12, respectively. A schema node identifier consists of a path of identifiers, separated by slashes ("/"). In an absolute schema node identifier, the first identifier after the leading slash is any top-level schema node in the local module or in all imported modules. References to identifiers defined in external modules MUST be qualified with appropriate prefixes, and references to identifiers defined in the current module and its submodules MAY use a prefix. For example, to identify the child node "b" of top-level node "a", the string "/a/b" can be used.7. YANG Statements
The following sections describe all of the YANG statements. Note that even a statement that does not have any substatements defined in YANG can have vendor-specific extensions as substatements. For example, the "description" statement does not have any substatements defined in YANG, but the following is legal: description "some text" { acme:documentation-flag 5; }7.1. The module Statement
The "module" statement defines the module's name, and groups all statements that 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.
Names of modules published in RFC streams [RFC4844] MUST be assigned by IANA, see Section 14. Private module names are assigned by the organization owning the module without a central registry. It is RECOMMENDED to choose module names 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 for the module name. A module typically has 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 <other statements> }
7.1.1. The module's Substatements
+--------------+---------+-------------+ | 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 | | identity | 7.16 | 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 | +--------------+---------+-------------+7.1.2. The yang-version Statement
The optional "yang-version" statement specifies which version of the YANG language was used in developing the module. The statement's argument is a string. If present, it MUST contain the value "1", which is the current YANG version and the default value. Handling of the "yang-version" statement for versions other than "1" (the version defined here) is out of scope for this specification. Any document that defines a higher version will need to define the backward compatibility of such a higher version.
7.1.3. The namespace Statement
The "namespace" statement defines the XML namespace that all identifiers defined by the module are qualified by, with the exception of data node identifiers defined inside a grouping (see Section 7.12 for details). The argument to the "namespace" statement is the URI of the namespace. See also Section 5.3.7.1.4. The prefix Statement
The "prefix" statement is used to define the prefix associated with the module and its namespace. The "prefix" statement's argument is the prefix string that 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 that generates XML or XPath that use prefixes SHOULD use the prefix defined by the module, 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 imported module 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. If there is a conflict, i.e., two different modules that both have defined the same prefix are imported, at least one of them MUST be imported with a different prefix. All prefixes, including the prefix for the module itself MUST be unique within the module or submodule.7.1.5. The import Statement
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. When a module is imported, the importing module may:
o use any grouping and typedef defined at the top level in the imported module or its submodules. o use any extension, feature, and identity defined in the imported module or its submodules. o use any node in the imported module's schema tree in "must", "path", and "when" statements, or as the target node in "augment" and "deviation" statements. The mandatory "prefix" substatement assigns a prefix for the imported module that is scoped to the importing module or submodule. Multiple "import" statements may be specified to import from different modules. When the optional "revision-date" substatement is present, any typedef, grouping, extension, feature, and identity referenced by definitions in the local module are taken from the specified revision of the imported module. It is an error if the specified revision of the imported module does not exist. If no "revision-date" substatement is present, it is undefined from which revision of the module they are taken. Multiple revisions of the same module MUST NOT be imported. The import's Substatements +---------------+---------+-------------+ | substatement | section | cardinality | +---------------+---------+-------------+ | prefix | 7.1.4 | 1 | | revision-date | 7.1.5.1 | 0..1 | +---------------+---------+-------------+7.1.5.1. The import's revision-date Statement
The import's "revision-date" statement is used to specify the exact version of the module to import. The "revision-date" statement MUST match the most recent "revision" statement in the imported module.7.1.6. The include Statement
The "include" statement is used to make content from a submodule available to that submodule's parent module, or to another submodule of that parent module. The argument is an identifier that 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). Submodules are only allowed to include other submodules belonging to the same module. 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. When the optional "revision-date" substatement is present, the specified revision of the submodule is included in the module. It is an error if the specified revision of the submodule does not exist. If no "revision-date" substatement is present, it is undefined which revision of the submodule is included. Multiple revisions of the same submodule MUST NOT be included. The includes's Substatements +---------------+---------+-------------+ | substatement | section | cardinality | +---------------+---------+-------------+ | revision-date | 7.1.5.1 | 0..1 | +---------------+---------+-------------+7.1.7. The organization Statement
The "organization" statement defines the party responsible for this module. The argument is a string that is used to specify a textual description of the organization(s) under whose auspices this module was developed.7.1.8. The contact Statement
The "contact" statement provides contact information for the module. The argument is a string that is used to specify contact information for the person or persons to whom technical queries concerning this module should be sent, such as their name, postal address, telephone number, and electronic mail address.7.1.9. The revision Statement
The "revision" statement specifies the editorial revision history of the module, including the initial revision. A series of revision 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 published editorial change, a new one SHOULD be added in front of the revisions sequence, so that all revisions are in reverse chronological order.7.1.9.1. The revision's Substatement
+--------------+---------+-------------+ | substatement | section | cardinality | +--------------+---------+-------------+ | description | 7.19.3 | 0..1 | | reference | 7.19.4 | 0..1 | +--------------+---------+-------------+7.1.10. Usage Example
module acme-system { namespace "http://acme.example.com/system"; prefix "acme"; import ietf-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 0100 EMail: joe@acme.example.com"; description "The module for entities implementing the ACME protocol."; revision "2007-06-09" { description "Initial revision."; } // definitions follow... }
7.2. The submodule Statement
While the primary unit in YANG is a module, a YANG module can itself be constructed out of several submodules. Submodules allow a module designer to split a complex model into several pieces where all the submodules contribute to a single namespace, which is defined by the module that includes the submodules. The "submodule" statement defines the submodule's name, and groups all statements that belong to the submodule together. The "submodule" statement's argument is the name of the submodule, followed by a block of substatements that hold detailed submodule information. The submodule name follows the rules for identifiers in Section 6.2. Names of submodules published in RFC streams [RFC4844] MUST be assigned by IANA, see Section 14. Private submodule names are assigned by the organization owning the submodule without a central registry. It is RECOMMENDED to choose submodule names 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 for the submodule name.
A submodule typically has 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 <other statements> }
7.2.1. The submodule's Substatements
+--------------+---------+-------------+ | 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 | | identity | 7.16 | 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 | +--------------+---------+-------------+7.2.2. The belongs-to Statement
The "belongs-to" statement specifies the module to which the submodule belongs. The argument is an identifier that is the name of the module. A submodule MUST only be included by the module to which it belongs, or by another submodule that belongs to that module. 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 | +--------------+---------+-------------+7.2.3. Usage Example
submodule acme-types { belongs-to "acme-system" { prefix "acme"; } import ietf-yang-types { prefix "yang"; } organization "ACME Inc."; contact "Joe L. User ACME, Inc. 42 Anywhere Drive Nowhere, CA 95134 USA Phone: +1 800 555 0100 EMail: joe@acme.example.com"; description "This submodule defines common ACME types."; revision "2007-06-09" { description "Initial revision."; } // definitions follows... }7.3. The typedef Statement
The "typedef" statement defines a new type that may be used locally in the module, in modules or submodules which include it, and by other modules that import from it, according to the rules in
Section 5.5. 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 that 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.7.3.1. The typedef's Substatements
+--------------+---------+-------------+ | 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 | +--------------+---------+-------------+7.3.2. The typedef's type Statement
The "type" statement, which MUST be present, defines the base type from which this type is derived. See Section 7.4 for details.7.3.3. The units Statement
The "units" statement, which is optional, takes as an argument a string that contains a textual definition of the units associated with the type.7.3.4. The typedef's default Statement
The "default" statement takes as an argument a string that contains a default value for the new type. The value of the "default" statement MUST be valid according 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.
If the type's default value is not valid according to the new restrictions specified in a derived type or leaf definition, the derived type or leaf definition MUST specify a new default value compatible with the restrictions.7.3.5. Usage Example
typedef listen-ipv4-address { type inet:ipv4-address; default "0.0.0.0"; }7.4. The type Statement
The "type" statement takes as an argument a string that 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 depend on the type being restricted. The restriction statements for all built-in types are described in the subsections of Section 9.7.4.1. The type's Substatements
+------------------+---------+-------------+ | 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 | | require-instance | 9.13.2 | 0..1 | | type | 7.4 | 0..n | +------------------+---------+-------------+7.5. The container Statement
The "container" statement is used to define an interior data 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.
7.5.1. Containers with Presence
YANG supports two styles of containers, those that 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. This is the default style. For example, the set of scrambling options for Synchronous Optical Network (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 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 it is 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 (see Section 7.5.5) is used to give semantics to the existence of the container in the data tree.
7.5.2. The container's Substatements
+--------------+---------+-------------+ | substatement | section | cardinality | +--------------+---------+-------------+ | anyxml | 7.10 | 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.3 | 0..n | | presence | 7.5.5 | 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 | +--------------+---------+-------------+7.5.3. The must Statement
The "must" statement, which is optional, takes as an argument a string that contains an XPath expression (see Section 6.4). It is used to formally declare a constraint on valid data. The constraint is enforced according to the rules in Section 8. When a datastore is validated, all "must" constraints are conceptually evaluated once for each data node in the data tree, and for all leafs with default values in use (see Section 7.6.1). If a data node 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 XPath expression is conceptually evaluated in the following context, in addition to the definition in Section 6.4.1: o The context node is the node in the data tree for which the "must" statement is defined. o The accessible tree is made up of all nodes in the data tree, and all leafs with default values in use (see Section 7.6.1).
The accessible tree depends on the context node: o If the context node represents configuration, the tree is the data in the NETCONF datastore where the context node exists. The XPath root node has all top-level configuration data nodes in all modules as children. o If the context node represents state data, the tree is all state data on the device, and the <running/> datastore. The XPath root node has all top-level data nodes in all modules as children. o If the context node represents notification content, the tree is the notification XML instance document. The XPath root node has the element representing the notification being defined as the only child. o If the context node represents RPC input parameters, the tree is the RPC XML instance document. The XPath root node has the element representing the RPC operation being defined as the only child. o If the context node represents RPC output parameters, the tree is the RPC reply instance document. The XPath root node has the elements representing the RPC output parameters as children. The result of the XPath expression is converted to a boolean value using the standard XPath rules. Note that since all leaf values in the data tree are conceptually stored in their canonical form (see Sections 7.6 and 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.
7.5.4. The must's Substatements
+---------------+---------+-------------+ | substatement | section | cardinality | +---------------+---------+-------------+ | description | 7.19.3 | 0..1 | | error-app-tag | 7.5.4.2 | 0..1 | | error-message | 7.5.4.1 | 0..1 | | reference | 7.19.4 | 0..1 | +---------------+---------+-------------+7.5.4.1. The error-message Statement
The "error-message" statement, which is optional, takes a string as an argument. If the constraint evaluates to false, the string is passed as <error-message> in the <rpc-error>.7.5.4.2. The error-app-tag Statement
The "error-app-tag" statement, which is optional, takes a string as an argument. If the constraint evaluates to false, the string is passed as <error-app-tag> in the <rpc-error>.7.5.4.3. Usage Example of must and error-message
container interface { leaf ifType { type enumeration { enum ethernet; enum atm; } } leaf ifMTU { type uint32; } must "ifType != 'ethernet' or " + "(ifType = 'ethernet' and ifMTU = 1500)" { error-message "An ethernet MTU must be 1500"; } must "ifType != 'atm' or " + "(ifType = 'atm' and ifMTU <= 17966 and ifMTU >= 64)" { error-message "An atm MTU must be 64 .. 17966"; } }
7.5.5. The presence Statement
The "presence" statement assigns a meaning to the presence of a container in the data tree. It takes as an argument a string that contains a textual description of what the node's presence means. If a container has the "presence" statement, the container's existence in the data tree carries some meaning. Otherwise, the container is used to give some structure to the data, and it carries no meaning by itself. See Section 7.5.1 for additional information.7.5.6. The container's Child Node Statements
Within a container, the "container", "leaf", "list", "leaf-list", "uses", "choice", and "anyxml" statements can be used to define child nodes to the container.7.5.7. XML Mapping Rules
A container node is encoded as an XML element. The element's local name is the container's identifier, and its namespace is the module's XML namespace (see Section 7.1.3). The container's child nodes are encoded as subelements to the container element. If the container defines RPC input or output parameters, these subelements are encoded in the same order as they are defined within the "container" statement. Otherwise, the subelements are encoded in any order. A NETCONF server that replies to a <get> or <get-config> request MAY choose not to send a container element if the container node does not have the "presence" statement and no child nodes exist. Thus, a client that receives an <rpc-reply> for a <get> or <get-config> request, must be prepared to handle the case that a container node without a "presence" statement is not present in the XML.7.5.8. NETCONF <edit-config> Operations
Containers can be created, deleted, replaced, and modified through <edit-config>, by using the "operation" attribute (see [RFC4741], Section 7.2) in the container's XML element. If a container does not have a "presence" statement and the last child node is deleted, the NETCONF server MAY delete the container.
When a NETCONF server processes an <edit-config> request, the elements of procedure for the container node are: If the operation is "merge" or "replace", the node is created if it does not exist. If the operation is "create", the node is created if it does not exist. If the node already exists, a "data-exists" error is returned. If the operation is "delete", the node is deleted if it exists. If the node does not exist, a "data-missing" error is returned.7.5.9. Usage Example
Given the following container definition: container system { description "Contains various system parameters"; container services { description "Configure externally available services"; container "ssh" { presence "Enables SSH"; description "SSH service specific configuration"; // more leafs, containers and stuff here... } } } A corresponding XML instance example: <system> <services> <ssh/> </services> </system> Since the <ssh> element is present, ssh is enabled. To delete a container with an <edit-config>:
<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <edit-config> <target> <running/> </target> <config> <system xmlns="http://example.com/schema/config"> <services> <ssh nc:operation="delete"/> </services> </system> </config> </edit-config> </rpc>7.6. The leaf Statement
The "leaf" statement is used to define a leaf node in the schema tree. It takes one argument, which is an identifier, followed by a block of substatements that holds detailed leaf information. A leaf node has a value, but no child nodes in the data tree. Conceptually, the value in the data tree is always in the canonical form (see Section 9.1). A leaf node exists in zero or one instances in the data tree. The "leaf" statement is used to define a scalar variable of a particular built-in or derived type.7.6.1. The leaf's default value
The default value of a leaf is the value that the server uses if the leaf does not exist in the data tree. The usage of the default value depends on the leaf's closest ancestor node in the schema tree that is not a non-presence container: o If no such ancestor exists in the schema tree, the default value MUST be used. o Otherwise, if this ancestor is a case node, the default value MUST be used if any node from the case exists in the data tree, or if the case node is the choice's default case, and no nodes from any other case exist in the data tree.
o Otherwise, the default value MUST be used if the ancestor node exists in the data tree. In these cases, the default value is said to be in use. When the default value is in use, the server MUST operationally behave as if the leaf was present in the data tree with the default value as its value. If a leaf has a "default" statement, the leaf's default value is the value of the "default" statement. Otherwise, if the leaf's type has a default value, and the leaf is not mandatory, then the leaf's default value is the type's default value. In all other cases, the leaf does not have a default value.7.6.2. The leaf's Substatements
+--------------+---------+-------------+ | substatement | section | cardinality | +--------------+---------+-------------+ | config | 7.19.1 | 0..1 | | default | 7.6.4 | 0..1 | | description | 7.19.3 | 0..1 | | if-feature | 7.18.2 | 0..n | | mandatory | 7.6.5 | 0..1 | | must | 7.5.3 | 0..n | | reference | 7.19.4 | 0..1 | | status | 7.19.2 | 0..1 | | type | 7.6.3 | 1 | | units | 7.3.3 | 0..1 | | when | 7.19.5 | 0..1 | +--------------+---------+-------------+7.6.3. The leaf's type Statement
The "type" statement, which MUST be present, takes as an argument the name of an existing built-in or derived type. The optional substatements specify restrictions on this type. See Section 7.4 for details.7.6.4. The leaf's default Statement
The "default" statement, which is optional, takes as an argument a string that contains a default value for the leaf. The value of the "default" statement MUST be valid according to the type specified in the leaf's "type" statement.
The "default" statement MUST NOT be present on nodes where "mandatory" is true.7.6.5. The leaf's mandatory Statement
The "mandatory" statement, which is optional, takes as an argument the string "true" or "false", and puts a constraint on valid data. If not specified, the default is "false". If "mandatory" is "true", the behavior of the constraint depends on the type of the leaf's closest ancestor node in the schema tree that is not a non-presence container (see Section 7.5.1): o If no such ancestor exists in the schema tree, the leaf MUST exist. o Otherwise, if this ancestor is a case node, the leaf MUST exist if any node from the case exists in the data tree. o Otherwise, the leaf MUST exist if the ancestor node exists in the data tree. This constraint is enforced according to the rules in Section 8.7.6.6. XML Mapping Rules
A leaf node is encoded as an XML element. The element's local name is the leaf's identifier, and its namespace is the module's XML namespace (see Section 7.1.3). The value of the leaf node is encoded to XML according to the type, and sent as character data in the element. A NETCONF server that replies to a <get> or <get-config> request MAY choose not to send the leaf element if its value is the default value. Thus, a client that receives an <rpc-reply> for a <get> or <get-config> request, MUST be prepared to handle the case that a leaf node with a default value is not present in the XML. In this case, the value used by the server is known to be the default value. See Section 7.6.8 for an example.7.6.7. NETCONF <edit-config> Operations
When a NETCONF server processes an <edit-config> request, the elements of procedure for the leaf node are:
If the operation is "merge" or "replace", the node is created if it does not exist, and its value is set to the value found in the XML RPC data. If the operation is "create", the node is created if it does not exist. If the node already exists, a "data-exists" error is returned. If the operation is "delete", the node is deleted if it exists. If the node does not exist, a "data-missing" error is returned.7.6.8. Usage Example
Given the following "leaf" statement, placed in the previously defined "ssh" container (see Section 7.5.9): leaf port { type inet:port-number; default 22; description "The port to which the SSH server listens" } A corresponding XML instance example: <port>2022</port> To set the value of a leaf with an <edit-config>: <rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <edit-config> <target> <running/> </target> <config> <system xmlns="http://example.com/schema/config"> <services> <ssh> <port>2022</port> </ssh> </services> </system> </config> </edit-config> </rpc>