13   YANG

This chapter describes some aspects of the YANG implementation in Clixon. Regarding standard compliance, see Standards.

13.1   Leafrefs

Some notes on YANG leafref implementation in Clixon, especially as used in openconfig modules, which rely heavily on leafrefs.

Typically, a YANG leafref declaration looks something like this:

container c {
  leaf x {
    type leafref {
      path "../config/name";   /* "deferring node" */
      require-instance <bool>; /* determines existing deferred node */
    }
  }
  container config {
    leaf name {
      type unit32;             /* "deferred node" */
    }
  }
}

This YANG example is typical of Openconfig lists defined in the openconfig modeling, where a key leaf references a “config” node further down in the tree.

Other typical uses is where the path is an absolute path, such as eg path "/network-instances/network-instance/config/name";

13.1.1   Types

Consider the YANG example above, the type of x is the deferred node:s, in this example uint32. The validation/commit process, as well as the autocli type system and completion handles accordingly.

For example, if the deferred node is a more complex type such as identityref with options “a, b”, the completion of “x” will show the options “a,b”.

13.1.2   Require-instance

Assume the yang above have the following two XML trees:

<c>
  <x>foo</x>
</c>

and:

<c>
  <x>foo</x>
  <config>
    <name>foo</name>
  </config>
</c>

The validity of the trees is controlled by the require-instance property . According to this semantics:

  • If require-instance is false, both trees above are valid,
  • If require-instance is true(or not present), the upper tree is invalid and the lower is valid

In most models defined by openconfig and ietf, require-instance is typically false.

13.2   YANG Library

Clixon partially supports YANG library RFC 8525 that provides information about YANG modules and datastores,

The following configure options are associated to the YANG library

CLICON_YANG_LIBRARY
Enable YANG library support as state data according to RFC8525. Default: true
CLICON_MODULE_SET_ID
Contains a server-specific identifier representing the current set of modules and submodules.
CLICON_XMLDB_MODSTATE
Tag datastores with RFC 8525 YANG Module Library info. See datastore for details on how to tag datastores with Module-set info.

The module-set of RFC8525 can be retrieved using NETCONF get or RESTCONF GET as operational data. The fields that are supported are the following:

  • Content-id of the whole module-set
  • Name of each module
  • Namespace
  • Revision
  • Feature
  • Submodules

The following fields are not supported

  • import-only-module
  • deviation
  • schema
  • datastore

13.2.1   Example

An example of a NETCONF get reply with module-state data of the main example is the following:

<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="42">
  <data>
    <yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
      <module-set>
        <name>default</name>
        <module>
          <name>clixon-autocli</name>
          <revision>2022-02-11</revision>
          <namespace>http://clicon.org/autocli</namespace>
        </module>
        <module>
          <name>clixon-example</name>
          <revision>2020-12-01</revision>
          <namespace>urn:example:clixon</namespace>
        </module>
        ...
      </module-set>
    </yang-library>
  </data>
</rpc-reply>

13.3   Extensions

Clixon implements YANG extensions. There are several uses, but one is to “annotate” a YANG specification with application-specific data that can be used in plugin code for some reason.

An extension with an argument is introduced in YANG as follows:

module example-lib {
   namespace "urn:example:lib";
   extension mymode {
      argument annotation;
   }

Such an extension can then be used in YANG declarations in two ways, either inline or augmented.

An inlined extension is useful in a YANG module that the designer has control over and can add extension reference directly in the YANG specification.

Assume for example that an interface declaration is extended with the extension declared above, as follows:

module my-interface {
  import example-lib{
    prefix exl;
  }
  container "interfaces" {
    list "interface" {
      exl:mymode "my-interface";
      ...

If you instead use an external YANG, where you cannot edit the YANG itself, you can use augmentation instead, as follows:

module my-augments {
 import example-lib{
    prefix exl;
 }
 import ietf-interfaces{
    prefix if;
 }
 augment "/if:interfaces/if:interface"{
    exl:mymode "my-interface";
 }
 ...

When this is done, it is possible to access the extension value in plugin code and use that value to perform application-specific actions. For example, assume an XML interface object x retrieve the annotation argument:

char      *value = NULL;
int        exist = 0;
yang_stmt *y = xml_spec(x);

if (yang_extension_value(y, "mymode", "urn:example:lib", &exist, &value) < 0)
   err;
if (exist){
   // use extension value
   if (strcmp(value, "my-interface") == 0)
      ...

A more advanced usage is possible via an extension callback (ca_callback) which is defined for backend, cli, netconf and restconf plugins. This allows for advanced YANG transformations. Please consult the main example to see how this could be done.

13.4   Unique

The YANG unique statement is described in Section 7.8.3 of RFC 7950. However, the RFC is somewhat vague in the descriptions of its arguments.

Clixon therefore supports two simultaneous distinct cases: multiple direct children and single descendants

13.4.1   Multiple direct children

This is examplified in the RFC, such as:

list server {
  key "name";
  unique "ip port";
  leaf ip...
  leaf port...

where ip and port are direct children of server and the uniquess applies to their combination in all list instances.

13.4.2   Single descendants

The RFC says:
schema node identifiers, which MUST be given in the descendant form

This does not exclude more elaborate schema nodes than direct children but are not explicitly allowed.

Therefore, Clixon also supports a single advanced schema node id. Such a schema node id may define a set of leafs. The uniqueness is then validated against all instances, such as for example:

list server {
  key "name";
  unique c/inner/value;
  container c {
     list inner {
        leaf value...

However, only a single such argument is allowed. The reason is that such a schema node may potentially refer to a set of instances (not just one) and the semantics of a combination of multiple such ids is unclear.

13.5   If-feature and anydata

The YANG if-feature statement is described in Section 7.20.2 of RFC 7950. The RFC states that:

Definitions tagged with “if-feature” are ignored when the server does not support that feature.

This is implemented by doing the following to disabled YANG nodes:

  1. Configuration data nodes are replaced locally to a single ANYDATA data. This means that XML derived from disabled features are accepted but no validation is possible.
  2. Other YANG nodes, such as RPCs or state data are removed.

Example, assume the following YANG:

container c{
   if-feature A;
   leaf b {
      type string;
   }
}
rpc r {
      input {
          leaf x {
              if-feature A;
              type string;
          }
      }
}

If feature A is NOT enabled, the YANG is transformed to:

anydata c{
}
rpc r {
      input {
      }
}

The following config option is related:

CLICON_YANG_UNKNOWN_ANYDATA
Treat unknown XML/JSON nodes as anydata when loading from startup db.