libyang  0.16.105
YANG data modeling language library
YANG Extension and User Type Support

Extensions and user types are supported in the form of plugins. These are loaded from the plugin directory (LIBDIR/libyang/) whenever a context is created. However, the list of plugins can be refreshed manually by ly_load_plugins(). The extension plugin directory path (default LIBDIR/libyang/extensions/) can be change via the LIBYANG_EXTENSIONS_PLUGINS_DIR environment variable and similarly the user type directory (default LIBDIR/libyang/user_types/) via LIBYANG_USER_TYPES_PLUGINS_DIR. Note, that unavailable plugins are not removed, only any new plugins are loaded. Also note that the availability of new plugins does not affect the current schemas in the contexts, they are applied only to the newly parsed schemas.

The plugins list can be cleaned by ly_clean_plugins(). However, since various contexts (respectively their schemas) can link to the plugins, the cleanup is successful only when there is no remaining context.

Extensions

YANG provides extensions as a mechanism how to add new statements into the language. Since they are very generic - extension instance can appear anywhere, they can contain any other YANG statement including extension instances and their specification has a form of the description text, it is very challenging for libyang to provide working and useful implementation. Therefore, you can reach some limitation regarding the extensions support, but the common use cases should be covered and supported.

Since libyang does not understand human text, it is not possible to get the complete definition of the extension from its description statement. Therefore, libyang allows the schema authors to provide extension plugin that provides information from the extension description to libyang.

Here are some notes about the implementation of the particular YANG extensions features

  • Extension instance can appear anywhere This is completely supported. In addition, the extension plugins are allowed to provide callback function to check if the extension instance is actually allowed to be instantiated as a substatement of the particular node. In some case the extension instance is not stored in the libyang structures inside the statement it is instantiated since some statements (such as description, position and several others listed as LYEXT_SUBSTMT) are not stored as a structure, but directly as a value. The extension instances of such statements are then actually stored besides the extension instances of the parent structure (e.g. in lys_type_bit in case of position's extension instances). These extension instances are indicated by the lys_ext_instance::insubstmt value which refers (sometimes in combination with lys_ext_instance::insubstmt_index) to the substatement where the particular extension is actually instantiated.
  • Extension instance can contain any other YANG statement This is supported with exceptions - the list of YANG statements is defined as LY_STMT enumeration with the description if the specific statement can appear as an extension instance substatement or if there is some limitation regarding its cardinality. It also specifies how the specific statement is stored in the extension instance (which data type or structure is used). In some cases, like include or yang-version statements, it make no sense to have them inside an extension instance, so they are not supported by libyang.

    The list of allowed substatement for the specific extension instances is provided by the extension plugin. Besides the list of substatement, the plugin also specifies where the data are stored and the cardinality for each substatement. Other extension instances as an extension instance substatements are always allowed. Note, that if there is no extension plugin defined or if the list of the allowed substatements is empty, no substatement (except extension instances) is allowed.

There are several extension types (enumerated as LYEXT_TYPE) according to their purpose and content:

  • LYEXT_FLAG - simple extension with no content (no substatement is allowed). The extension instance serves just as a flag with or without an argument and its value. The example of such an extension is NACM's default-deny-write or default-deny-all. This is the default type of extension for the case there is no extension plugin available for the specific extension. Extension instances of this type are represented as lys_ext_instance.
  • LYEXT_COMPLEX - complex extension with content. The specific rules for the content and how it is stored in the extension instance structure is specified by the plugin. Extension instances of this type are represented as lys_ext_instance_complex.

Note that the lys_ext_instance structure serves as a generic structure for all extension instances. In case the lys_ext_instance::ext_type is set to a different value than LYEXT_FLAG, the structure can be cast to the particular extension instance structure to access the type-specific members.

Extension Plugins

Extension plugins provide more detailed information about the extension in a understandable form for libyang. These information is usually provided in a text form in the extension's description statement. libyang provides several plugins for the common IETF extensions (NACM, Metadata, ...) that can be used as a code examples for other extensions.

There are several types of extension plugins which corresponds to the extension types:

  • lyext_plugin - the plugin for a simple extensions of type LYEXT_FLAG. The plugin is supposed to provide callbacks for:
  • lyext_plugin_complex - the plugin for the complex extension instances (LYEXT_COMPLEX). The structure extends the lyext_plugin structure by:
    • instance_size - the overall size of the lyext_plugin_complex structure to allocate. The substatement list is flexible array, so the size of the plugin structure depends on the content of the array.
    • substmt - the list of the allowed substatements to the extension instance, besides the substatement id, it also specifies its cardinality and the specific position in the lys_ext_instance_complex where the data are stored (as offset to the lys_ext_instance_complex::content member). The way how the data are stored is specified descriptions of LY_STMT values.

Metadata Support

YANG Metadata annotations are defined in RFC 7952 as YANG extension. In practice, it allows to have XML attributes (there is also a special encoding for JSON) in YANG modeled data. libyang does not allow to have any XML attribute without the appropriate annotation definition describing the data as it is done e.g. for leafs. When an attribute without a matching annotation definition is found in the input data, it is silently dropped (with warning) or an error is reported in case the LYD_OPT_STRICT parser option is provided to the parser function.

There are some XML attributes, described by YANG and NETCONF specifications, which are not defined as annotations, but libyang implements them this way. In case of attributes in the YANG namespace (insert, value and key attributes for the NETCONF edit-config operation), they are defined in special libyang's internal module yang, which is available in each context and the content of this schema can be printed via schema printers.

In case of the attributes described in NETCONF specification, the libyang's annotations structures are hidden and cannot be printed despite, internally, they are part of the ietf-netconf's schema structure. Therefore, these attributes are available only when the ietf-netconf schema is loaded in the context. The definitions of these annotations are as follows:

md:annotation operation {
  type enumeration {
    enum merge;
    enum replace;
    enum create;
    enum delete;
    enum remove;
  }
}

md:annotation type {
  type enumeration {
    enum subtree;
    enum xpath {
      if-feature "nc:xpath";
    }
  }
}

md:annotation select {
  type string;
}

Note, that, following the specification,

  • the type and select XML attributes are supposed to be unqualified (without namespace) and that
  • the select's content is XPath and it is internally transformed by libyang into the format where the XML namespace prefixes are replaced by the YANG module names.

User Types

Using this plugin mechanism, it is also possible to define what can be called user types. Values are always stored as a string in addition to being in a lyd_val union. It is possible to customize how the value is stored in the union using a lytype_store_clb callback.

Generally, it is meant for storing certain types more effectively. For instance, when working with ipv4-address from the ietf-inet-types model, an application will most likely use the address in a binary form, not as a string. So, in the callback the value is simply transformed into the desired format and saved into lyd_val value. However, the callback is allowed to store anything in the union. Another example, if there are many strings being created and handled, is to store the string length instead having 2 pointers to the same string.

Also, it is possible to perform some additional validation of the value except for the standard YANG one. Even if the value should only be validated, this callback can be defined and used, it will just keep the lyd_val value unchanged.

User Type Plugins

There are simple example user type plugins in src/user_types.

Functions List