Using YANG Deviations

YANG deviations change the effective schema of another module in the server. They describe how a particular implementation differs from the published module, without editing that module's source file. The compiler applies the deviation statements when it loads the target module. For example, a server can declare a container unsupported or replace a leaf's default value.

Clients need these changes to understand the server's actual schema. The server advertises the deviation module so that clients can apply the same changes to their own schema view. See RFC 7950, section 7.20.3, for the YANG deviation rules.

The original module and deviation module enter the compiler. The effective schema is used by the server and reconstructed by clients from the advertised modules and deviations.

The source module stays unchanged; the compiled schema reflects deviations.

Write a Deviation Module

Use this naming pattern for a separate module:

<organization>-<deviated-module>-dev.yang

For example, Acme's deviations for ietf-interfaces would be defined in acme-ietf-interfaces-dev.yang.

Apart from the module header, imports, and descriptive metadata, it is recommended to keep the module limited to deviation statements. Do not put regular definitions such as containers, leafs, RPCs, typedefs, or groupings in it, even though this is allowed by RFC 7950. The --deviation loading mode collects deviations for later application; it is not a substitute for loading regular module definitions.

Example: ietf-interfaces module

For this tutorial, use ietf-interfaces.yang, revision date 2018-02-20.

  • Remove the deprecated /interfaces-state container

  • Change the default of the /interfaces/interface/enabled leaf

Save the following as acme-ietf-interfaces-dev.yang in a working directory:

module acme-ietf-interfaces-dev {
  yang-version 1.1;
  namespace "urn:acme:params:xml:ns:yang:acme-ietf-interfaces-dev";
  prefix acme-if-dev;

  import ietf-interfaces {
    prefix if;
    revision-date 2018-02-20;
  }

  organization "Acme";
  description
    "Example deviations for the Acme implementation of ietf-interfaces.";

  revision 2026-09-17 {
    description "Initial example.";
  }

  deviation "/if:interfaces-state" {
    description "The legacy state container is not implemented.";
    deviate not-supported;
  }

  deviation "/if:interfaces/if:interface/if:enabled" {
    description "Interfaces are disabled by default on this platform.";
    deviate replace {
      default "false";
    }
  }
}

The import prefix if identifies nodes in ietf-interfaces. Each deviation uses an absolute schema node path, including a prefix on each node in these examples. The import's revision-date pins the tutorial to the revision whose schema was checked.

Make a Data Node Unsupported

The first deviation uses deviate not-supported. The compiler removes /interfaces-state and its descendants from the effective schema. Clients must no longer treat that subtree as implemented. This does not remove the separate /interfaces container or its state data in this module revision.

Change a Default Value

The second deviation uses deviate replace to change the existing enabled default from true to false. Use replace when the property already exists; use deviate add to introduce a default when the node has none, provided the resulting schema permits it.

This changes the schema default used when a value is absent and the YANG default rules apply. It does not overwrite an explicitly configured enabled value. The new value must remain valid for the leaf's type.

Before deviations, interfaces-state exists and enabled defaults to true. After deviations, interfaces-state is unsupported and enabled defaults to false. The interfaces container remains supported.

Two deviations change the same module's effective schema.

Inspect the Compiler Result

Check the effective schema before starting the server. Run the commands below from the directory containing acme-ietf-interfaces-dev.yang. The target module and its imports must be on the module search path; use --modpath if they are not in the installed SDK module directories.

First validate the original module:

yangdump-pro --no-config --module=ietf-interfaces@2018-02-20

Then validate the target with the deviation module and enable compiler tracing with --log-level:

yangdump-pro --no-config \
  --deviation=acme-ietf-interfaces-dev \
  --module=ietf-interfaces@2018-02-20 --log-level=debug3

The debug output includes these messages (other messages are omitted):

apply_dev: mark target obj ietf-interfaces:interfaces-state for removal
apply_dev: replacing default in target obj ietf-interfaces:enabled
Rechecking ietf-interfaces:enabled after applying deviation(s)
Deviation caused deletion of object ietf-interfaces:interfaces-state

Check that compilation finishes without errors or warnings. These messages show that the compiler applied the statements to the target and rechecked the changed leaf. The replacement value is false, as specified in the deviate replace statement. --no-config prevents a default yangdump-pro configuration file from adding unrelated compiler options.

Effective schema after compilation

Target

Before

After

/interfaces-state

Container and descendants

Not supported; subtree absent

/interfaces/interface/enabled

default true

default false

Make Sure the SIL or SIL-SA Code Does Not Register Unsupported Objects

The SIL or SIL-SA code may need to be modified if any objects are changed to be 'not-supported'.

If the YumaPro libietf-interfaces.so is loaded, the following error messages will be seen:

Deviation caused deletion of object ietf-interfaces:interfaces-state
...

Invoking load module callback 0
agt_cb: got new module 'ietf-interfaces', rev '2018-02-20'
yang_parse: Finish module 'ietf-interfaces@2018-02-20' OK
Error: sil init function failed for module ietf-interfaces (definition not found)

The deviation causes the interfaces-state container to be deleted from the schema tree, which results in the 'definition not found' error.

The source code in y_ietf-interfaces.c contains a commented out #define for the NO_INTERFACES_STATE constant. If this is defined then no SIL registrations will be done for the /interfaces-state subtree.

After this is done, the server should load correctly.

Start the Server with the Deviations

Install the deviation module on the server's module search path along with the target module and its imports. In a development setup, start netconfd-pro from the directory containing the deviation file:

netconfd-pro --deviation=acme-ietf-interfaces-dev \
  --module=ietf-interfaces@2018-02-20 --module=iana-if-type

The --deviation option makes the deviations available before the target module is compiled. The --module option loads the target module as an implemented module. Loading a deviations-only module with --module alone is not a replacement for --deviation. iana-if-type supplies interface type identities and is also explicitly loaded in this example.

Alternatively, add these entries to the existing netconfd-pro block in your server configuration file and restart the server:

netconfd-pro {
  deviation acme-ietf-interfaces-dev
  module ietf-interfaces@2018-02-20
  module iana-if-type
}

Use either the command-line entries or the configuration entries for this example. Keep the server's normal instrumentation and other required startup settings. Deviations describe schema differences; they do not implement the remaining interface operations or replace the SIL code.

After startup, inspect the server's YANG library. With the current YANG library structure, the ietf-interfaces entry under /yang-library/module-set/module should name acme-ietf-interfaces-dev in its deviation leaf-list. The deviation module should also be listed. For details, see Using the YANG Library. A client uses this information to obtain the original module and its deviations and reconstruct the effective schema. Do not expect retrieval of the original YANG source to return a flattened, modified module.

If a client sends a retrieval request for this subtree, then an empty data container should be returned by the server.

agt_tree: pre-process prune 'interfaces-state' unknown name or namespace
agt_tree: pre_process empty return
agt_tree: process_val empty return
ses_msg: send 1.1 buff:260 for s:3

trace_buff:

#250
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="4"
 xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
 ncx:last-modified="2026-09-30T18:47:52Z" ncx:etag="687"
 xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
 <data></data>
</rpc-reply>

The sget command in yangcli-pro should show:

andy@localhost> sget /interfaces-state

RPC Data Reply 3 for session 3 [default]:

rpc-reply {
  data {
  }
}

Make IF-MIB Objects Writable

The SDK's netconf/modules/mib/IF-MIB.yang is post-processed: the top-level IF-MIB container has config true, selected controls and their list key are configuration data, and state nodes have explicit config false statements. This tutorial instead targets the raw smidump output, before the SDK's mib-config.py post-processing. Do not use the checked-in SDK module as the target for this example: several of its explicit config false statements would conflict with the deviations below.

The following example shows how to change the effective YANG module so that selected SNMP read-write objects become YANG configuration data. Generate IF-MIB.yang with smidump in a separate working directory, and ensure the compiler or server resolves that raw file as the target module. Do not run mib-config.py on it. The example retains the generated source and advertises the changes in a separate acme-IF-MIB-dev.yang module. The target module name is case-sensitive, so the deviation filename preserves IF-MIB.

Why the Converter Produces Read-Only Data

The standard SMIv2-to-YANG mapping intentionally makes all data config false, including SNMP read-write and read-create objects. SNMP writability alone does not establish NETCONF datastore persistence or edit semantics. RFC 6643, section 11, describes using deviations for selected objects whose implementation can provide compatible configuration behavior.

The open-source libsmi smidump tool performs the conversion:

smidump -f yang IF-MIB > IF-MIB.yang

Run this in a separate working directory with the SMIv2 IF-MIB and its imports on the libsmi MIB search path. Retain the generated file as the base module. SMIv2 metadata such as smiv2:max-access preserves the original SNMP access information; it does not generate config true. See also Creating MIB Instrumentation.

The upstream smidump YANG converter has no option to map SNMP read-write objects automatically to config true. Its conversion implementation sets config false on the generated top-level container. An application-specific generator could produce a deviation module, but it still needs a reviewed selection of writable objects, key handling, and persistence rules. Open-source yanglint, supplied by libyang, can validate and display the resulting schema as shown below; it does not infer those implementation decisions.

Change Ancestors and Preserve State Data

In the raw smidump output, IF-MIB is explicitly config false and its descendants inherit that setting. Setting config true only on ifAdminStatus is invalid while its ancestor is state data. Conversely, changing only the top-level container to config true would make counters and other state objects inherit configuration status too.

For this example, expose four controls under IF-MIB/ifTable/ifEntry: ifAdminStatus, ifLinkUpDownTrapEnable, ifPromiscuousMode, and ifAlias.

It makes these coordinated changes:

  1. Replace the root's explicit config false with config true. ifTable, ifEntry, its ifIndex key, and the selected controls inherit config true.

  2. Add config false to the complete interfaces, ifMIBObjects, ifStackTable, and ifRcvAddressTable subtrees.

  3. Add config false to every remaining non-key leaf in ifEntry, including leafs contributed by the ifXEntry and ifTestEntry augments. This preserves counters, operational status, and all other unselected objects as state data.

These excerpts illustrate the changes; use the complete download so that no unselected state leaf accidentally becomes configuration:

deviation "/if-mib:IF-MIB" {
  deviate replace {
    config true;
  }
}

deviation "/if-mib:IF-MIB/if-mib:interfaces" {
  deviate add { config false; }
}

deviation "/if-mib:IF-MIB/if-mib:ifTable/if-mib:ifEntry"
        + "/if-mib:ifOperStatus" {
  deviate add { config false; }
}

Use replace for the root's existing statement and add where the original node has no explicit config statement. No extra statement is needed on the four controls because they inherit true. The effect is equivalent to changing the root's source statement and adding the state statements at the selected boundaries, while leaving the generated file unchanged.

The list key requires special care: ifIndex is SNMP read-only but must have the same YANG config value as ifEntry. Keeping it config false would make this configuration list invalid. Its role as a configuration key identifies the row; it does not mean an existing interface index can be renamed. Instrumentation must enforce which interface rows can be created or deleted and how keys map to real devices.

This example deliberately leaves the stack and receive-address tables and the deprecated test controls read-only, including their SNMP-writable objects. Promoting RowStatus or action-like test controls requires additional decisions about row lifecycle and edit semantics. Do not promote every read-write or read-create object without reviewing those rules.

Validate and Inspect the Changed Module

Put the downloaded deviation file, the raw IF-MIB.yang generated by smidump, and its YANG imports on the module search path. Ensure that the SDK's post-processed IF-MIB.yang does not shadow the raw file. From that working directory, validate with the server's compiler:

yangdump-pro --no-config --deviation=acme-IF-MIB-dev \
  --module=IF-MIB --log-level=debug3

To see the effective read/write classification with the open-source yanglint tool, compare these two commands. Replace yang-modules with the directory containing the imported YANG modules; add more -p options if needed:

yanglint -p yang-modules -f tree IF-MIB.yang
yanglint -p yang-modules -f tree IF-MIB.yang acme-IF-MIB-dev.yang

In the original tree, all IF-MIB data nodes are ro. After loading the deviations, the following selected nodes have these classifications (other nodes omitted):

module: IF-MIB
  +--rw IF-MIB
     +--ro interfaces
     |  +--ro ifNumber
     +--rw ifTable
        +--rw ifEntry* [ifIndex]
           +--rw ifIndex
           +--rw ifAdminStatus
           +--ro ifOperStatus
           +--ro ifInOctets
           +--rw ifLinkUpDownTrapEnable
           +--rw ifPromiscuousMode
           +--rw ifAlias

Here rw means YANG configuration data and ro means state data; these markers are not a report of SNMP MAX-ACCESS permissions. Start a server that has instrumentation for the changed schema with:

netconfd-pro --deviation=acme-IF-MIB-dev --module=IF-MIB

Load this as a deviation, not an annotation: clients must learn which nodes are now configuration. Generate or adapt the SIL code using the same deviations, and implement edit validation, application, rollback, and persistence. Changing the schema alone does not add write callbacks to the supplied IF-MIB example SIL or enable SNMP SET support. Check the yp-snmp Features for the supported SNMP operations.

Choose Deviations or Annotations

YumaPro also supports server-side annotation modules loaded with --annotation. They use deviation syntax to attach extensions to another module, but are not advertised to clients or shown in the YANG library. Here, an annotation module means this server startup mechanism, not an RFC 7952 md:annotation definition for protocol metadata.

Choose the mechanism according to who needs the information:

  • Use an annotation to add an extension that only server instrumentation needs, such as a callback-ordering hint. The client does not need that implementation detail.

  • Use a deviation for any schema change that clients must see, including unsupported nodes, changed defaults, types, or constraints. Hiding such changes leaves clients with an incorrect schema.

  • Use a deviation for extension usage from which a client might benefit. Check that the extension permits the intended deviation and that the client can obtain the module defining the extension.

For an annotation example using deviate add with a server-only extension, see --annotation. Do not load this tutorial's module as an annotation: both of its changes need to be visible to clients.

Usage Guidelines

Deviations need to be used carefully, and the SIL or SIL-SA callback code needs to be aligned with any deviations used.

Note

Some deviations are quite dangerous if done incorrectly.

Changing the type of a data node (e.g. string to uint32) will cause a callback to crash if the SIL or SIL-SA code is not updated to expect the new data type.

  • Keep deviations in a dedicated module named for the organization and the module being deviated. Retain the original target module unchanged, and distribute the deviation module to clients that need it.

  • Keep only deviation statements as the module's functional content. Use imports for target prefixes and extension definitions, and descriptions to explain each implementation difference.

  • Validate against the exact target revision and the complete set of modules, features, and deviations used in the deployment. Removing a subtree can invalidate references to it from other modules.

  • Keep the resulting schema valid and avoid deviations that conflict or depend on application order. Recheck compiler validation after changing any deviation or upgrading the target module.

  • Align instrumentation and existing configuration with the effective schema. A changed default affects clients that previously relied on the original default, even if they never explicitly configured that leaf.

SIL bundles can include deviations when their code is generated and built.

  • The make_sil_bundle and make_sil_sa_bundle helpers accept --deviation options, and generated initialization code loads those deviations before loading the target modules.

  • Check the bundle's build options before adding deviations in the server configuration.

  • Repeating or conflicting with bundled deviations can cause compilation failures or make the effective schema inconsistent with the generated instrumentation.

  • Keep bundle generation and server configuration coordinated, and validate the combined deviation set rather than assuming the configuration overrides the bundle.

  • Hard-wired deviations should not be mixed with deviations from the command line or config file.