Developing NEDs
Develop your own NEDs to integrate unsupported devices in your network.
Creating a NED
A Network Element Driver (NED) represents a key NSO component that allows NSO to communicate southbound with network devices. The device YANG models contained in the Network Element Drivers (NEDs) enable NSO to store device configurations in the CDB and expose a uniform API to the network for automation. The YANG models can cover only a tiny subset of the device or all of the device. Typically, the YANG models contained in a NED represent the subset of the device's configuration data, state data, Remote Procedure Calls, and notifications to be managed using NSO.
This guide provides information on NED development, focusing on building your own NED package. For a general introduction to NEDs, Cisco-provided NEDs, and NED administration, refer to the NED Administration in Administration.
Types of NED Packages
A NED package allows NSO to manage a network device of a specific type. NEDs typically contain YANG models and the code, specifying how NSO should configure and retrieve status. When developing your own NED, there are four categories supported by NSO.
A NETCONF NED is used with the NSO's built-in NETCONF client and requires no code. Only YANG models. This NED is suitable for devices that strictly follow the specification for the NETCONF protocol and YANG mappings to NETCONF targeting a standardized machine-to-machine interface.
CLI NED targeted devices that use a Cisco-style CLI as a human-to-machine configuration interface. Various YANG extensions are used to annotate the YANG model representation of the device together with code-converting data between NSO and device formats.
A generic NED is typically used to communicate with non-CLI devices, such as devices using protocols like REST, TL1, Corba, SOAP, RESTCONF, or gNMI as a configuration interface. Even NETCONF-enabled devices often require a generic NED to function properly with NSO.
NSO's built-in SNMP client can manage SNMP devices by supplying NSO with the MIBs, with some additional declarative annotations and code to handle the communication to the device. Usually, this legacy protocol is used to read state data. Albeit limited, NSO has support for configuring devices using SNMP.
In summary, the NETCONF and SNMP NEDs use built-in NSO clients; the CLI NED is model-driven, whereas the generic NED requires a Java program to translate operations toward the device.
Dumb Versus Capable Devices
NSO differentiates between managed devices that can handle transactions and devices that can not. This discussion applies regardless of NED type, i.e., NETCONF, SNMP, CLI, or Generic.
NEDs for devices that cannot handle abort must indicate so in the reply of the newConnection()
method indicating that the NED wants a reverse diff in case of an abort. Thus, NSO has two different ways to abort a transaction towards a NED, invoke the abort()
method with or without a generated reverse diff.
For non-transactional devices, we have no other way of trying out a proposed configuration change than to send the change to the device and see what happens.
The table below shows the seven different data-related callbacks that could or must be implemented by all NEDs. It also differentiates between 4 different types of devices and what the NED must do in each callback for the different types of devices.
The table below displays the device types:
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
SNMP, Cisco IOS, NETCONF devices with startup+running. | Devices that can abort, NETCONF devices without confirmed commit. | Cisco XR type of devices. | ConfD, Junos. |
INITIALIZE: The initialize phase is used to initialize a transaction. For instance, if locking or other transaction preparations are necessary, they should be performed here. This callback is not mandatory to implement if no NED-specific transaction preparations are needed.
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
|
|
| Built in, NSO will lock. |
UNINITIALIZE: If the transaction is not completed and the NED has done INITIALIZE, this method is called to undo the transaction preparations, that is restoring the NED to the state before INITIALIZE. This callback is not mandatory to implement if no NED-specific preparations were performed in INITIALIZE.
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
|
|
| Built in, NSO will unlock. |
PREPARE: In the prepare phase, the NEDs get exposed to all the changes that are destined for each managed device handled by each NED. It is the responsibility of the NED to determine the outcome here. If the NED replies successfully from the prepare phase, NSO assumes the device will be able to go through with the proposed configuration change.
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
|
|
| Built in, NSO will edit-config towards the candidate, validate and commit confirmed with a timeout. |
ABORT: If any participants in the transaction reject the proposed changes, all NEDs will be invoked in the abort()
method for each managed device the NED handles. It is the responsibility of the NED to make sure that whatever was done in the PREPARE phase is undone. For NEDs that indicate as a reply in newConnection()
that they want the reverse diff, they will get the reverse data as a parameter here.
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
|
|
| Built in, discard-changes and close. |
COMMIT: Once all NEDs that get invoked in commit(Timeout)
reply OK, the transaction is permanently committed to the system. The NED may still reject the change in COMMIT. If any NED rejects the COMMIT, all participants will be invoked in REVERT, NEDs that support confirmed commit with a timeout, Cisco XR may choose to use the provided timeout to make REVERT easy to implement.
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
|
|
| Built in, commit confirmed with the timeout. |
REVERT: This state is reached if any NED reports failure in the COMMIT phase. Similar to the ABORT state, the reverse diff is supplied to the NED if the NED has asked for that.
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
|
|
| Built in, discard-changes and close. |
PERSIST: This state is reached at the end of a successful transaction. Here it's the responsibility of the NED to make sure that if the device reboots, the changes are still there.
Non transactional devices | Transactional devices | Transactional devices with confirmed commit | Fully capable NETCONF server |
---|---|---|---|
|
|
| Built in, commit confirm. |
The following state diagram depicts the different states the NED code goes through in the life of a transaction.
Statistics
NED devices have runtime data and statistics. The first part of being able to collect non-configuration data from a NED device is to model the statistics data we wish to gather. In normal YANG files, it is common to have the runtime data nested inside the configuration data. In gathering runtime data for NED devices we have chosen to separate configuration data and runtime data. In the case of the archetypical CLI device, the show running-config ...
and friends are used to display the running configuration of the device whereas other different show ...
commands are used to display runtime data, for example show interfaces
, show routes
. Different commands for different types of routers/switches and in particular, different tabular output format for different device types.
To expose runtime data from a NED controlled device, regardless of whether it's a CLI NED or a Generic NED, we need to do two things:
Write YANG models for the aspects of runtime data we wish to expose northbound in NSO.
Write Java NED code that is responsible for collecting that data.
The NSO NED for the Avaya 4k device contains a data model for some real statistics for the Avaya router and also the accompanying Java NED code. Let's start to take a look at the YANG model for the stats portion, we have:
It's a config false;
list of counters per interface. We compile the NED stats module with the --ncs-compile-module
flag or with the --ncs-compile-bundle
flag. It's the same non-config
module that contains both runtime data as well as commands and rpcs.
The config false;
data from a module that has been compiled with the --ncs-compile-module
flag will end up mounted under /devices/device/live-status
tree. Thus running the NED towards a real router we have:
It is the responsibility of the NED code to populate the data in the live device tree. Whenever a northbound agent tries to read any data in the live device tree for a NED device, the NED code is invoked.
The NED code implements an interface called, NedConnection
This interface contains:
This interface method is invoked by NSO in the NED. The Java code must return what is requested, but it may also return more. The Java code always needs to signal errors by invoking NedWorker.error()
and success by invoking NedWorker.showStatsPathResponse()
. The latter function indicates what is returned, and also how long it shall be cached inside NSO.
The reason for this design is that it is common for many show
commands to work on for example an entire interface, or some other item in the managed device. Say that the NSO operator (or MAAPI code) invokes:
requesting a single leaf, the NED Java code can decide to execute any arbitrary show
command towards the managed device, parse the output, and populate as much data as it wants. The Java code also decides how long time the NSO shall cache the data.
When the
showStatsPath()
is invoked, the NED should indicate the state/value of the node indicated by the path (i.e. if a leaf was requested, the NED should write the value of this leaf to the provided transaction handler (th) using MAAPI, or indicate its absence as described below; if a list entry or a presence container was requested then the NED should indicate presence or absence of the element, if the whole list is requested then the NED should populate the keys for this list). Often requesting such data from the actual device will give the NED more data than specifically requested, in which case the worker is free to write other values as well. The NED is not limited to populating the subtree indicated by the path, it may also write values outside this subtree. NSO will then not request those paths but read them directly from the transaction. Different timeouts can be provided for different paths. If a leaf does not have a value or does not exist, the NED can indicate this by returning a TTL for the path to the leaf, without setting the value in the provided transaction. This has changed from earlier versions of NSO. The same applies to optional containers and list entries. If the NED populates the keys for a certain list (both when it is requested to do so or when it decided to do so because it has received this data from the device), it should set the TTL value for the list itself to indicate the time the set of keys should be considered up to date. It may choose to provide different TTL values for some or all list entries, but it is not required to do so.
Making the NED Handle Default Values Properly
One important task when implementing a NED of any type is to make it mimic the devices handling of default values as close as possible. Network equipment can typically deal with default values in many different ways.
Some devices display default values on leafs even if they have not been explicitly set. Others use trimming, meaning that if a leaf is set to its default value it will be 'unset' and disappear from the devices configuration dump.
It is the responsibility of the NED to make the NSO aware of how the device handles default values. This is done by registering a special NED Capability entry with the NSO. Two modes are currently supported by the NSO: trim
and report-all
.
Example 129. A device trimming default values
This is the typical behavior of a Cisco IOS device. The simple YANG code snippet below illustrates the behavior. A container with a boolean leaf. Its default value is true.
Try setting the leaf to true in NSO and commit. Then compare the configuration:
The result shows that the configurations differ. The reason is that the device does not display the value of the leaf 'enabled'. It has been trimmed since it has its default value. The NSO is now out of sync with the device.
To solve this issue, make the NED tell the NSO that the device is trimming default values. Register an extra NED Capability entry in the Java code.
Now, try the same operation again:
The NSO is now in sync with the device.
Example: A Device Displaying All Default Values
Some devices display default values for leafs even if they have not been explicitly set. The simple YANG code below will be used to illustrate this behavior. A list containing a key and a leaf with a default value.
Try creating a new list entry in NSO and commit. Then compare the configuration:
The result shows that the configurations differ. The NSO is out of sync. This is because the device displays the default value of the 'threshold' leaf even if it has not been explicitly set through the NSO.
To solve this issue, make the NED tell the NSO that the device is reporting all default values. Register an extra NED Capability entry in the Java code.
Now, try the same operation again:
The NSO is now in sync with the device.
Dry-run Considerations
The possibility to do a dry-run on a transaction is a feature in NSO that allows to examine the changes to be pushed out to the managed devices in the network. The output can be produced in different formats, namely cli
, xml
, and native
. In order to produce a dry run in the native output format NSO needs to know the exact syntax used by the device, and the task of converting the commands or operations produced by the NSO into the device-specific output belongs the corresponding NED. This is the purpose of the prepareDry()
callback in the NED interface.
In order to be able to invoke a callback an instance of the NED object needs to be created first. There are two ways to instantiate a NED:
newConnection()
callback that tells the NED to establish a connection to the device which can later be used to perform any action such as show configuration, apply changes, or view operational data as well as produce dry-run output.Optional
initNoConnect()
callback that tells the NED to create an instance that would not need to communicate with the device, and hence must not establish a connection or otherwise communicate with the device. This instance will only be used to calculate dry-run output. It is possible for a NED to reject theinitNoConnect()
request if it is not able to calculate the dry-run output without establishing a connection to the device, for example, if a NED is capable of managing devices with different flavors of syntax and it is not known at the moment which syntax is used by this particular device.
The following state diagram displays NED states specific to the dry-run scenario.
NED Identification
Each managed device in NSO has a device type, which informs NSO how to communicate with the device. The device type is one of netconf
, snmp
, cli
, or generic
. In addition, a special ned-id
identifier is needed.
NSO uses a technique called YANG Schema Mount, where all the data models from a device are mounted into the /devices
tree in NSO. Each set of mounted data models is completely separated from the others (they are confined to a "mount jail"). This makes it possible to load different versions of the same YANG module for different devices. The functionality is called Common Data Models (CDM).
In most cases, there are many devices running the same software version in the network managed by NSO, thus using the exact same set of YANG modules. With CDM, all YANG modules for a certain device (or family of devices) are contained in a NED package (or just NED for short). If the YANG modules on the device are updated in a backward-compatible way, the NED is also updated.
However, if the YANG modules on the device are updated in an incompatible way in a new version of the device's software, it might be necessary to create a new NED package for the new set of modules. Without CDM, this would not be possible, since there would be two different packages that contained different versions of the same YANG module.
When a NED is being built, its YANG modules are compiled to be mounted into the NSO YANG model. This is done by device compilation of the device's YANG modules and is performed via the ncsc
tool provided by NSO.
The ned-id identifier is a YANG identity, which must be derived from one of the pre-defined identities in $NCS_DIR/src/ned/yang/tailf-ncs-ned.yang
.
A YANG model for devices handled by NED code needs to extend the base identity and provide a new identity that can be configured.
The Java NED code registers the identity it handles with NSO.
Similar to how we import device models for NETCONF-based devices, we use the ncsc --ncs-compile-bundle
command to import YANG models for NED-handled devices.
Once we have imported such a YANG model into NSO, we can configure the managed device in NSO to be handled by the appropriate NED handler (which is user Java code, more on that later)
When NSO needs to communicate southbound towards a managed device which is not of type NETCONF, it will look for a NED that has registered with the name of the identity, in the case above, the string "ios".
Thus before the NSO attempts to connect to a NED device before it tries to sync, or manipulate the configuration of the device, a user-based Java NED code must have registered with the NSO service manager indicating which Java class is responsible for the NED with the string of the identity, in this case, the string "ios". This happens automatically when the NSO Java VM gets a instantiate-component
request for an NSO package component of type ned
.
The component Java class myNed
needs to implement either of the interfaces NedGeneric
or NedCli
. Both interfaces require the NED class to implement the following:
The above three callbacks are used by the NSO Java VM to connect the NED Java class with NSO. They are called at when the NSO Java VM receives the instantiate-component request
.
The underlying NedMux will start a number of threads, and invoke the registered class with other data callbacks as transactions execute.
Migrating to the juniper-junos_nc
NED
juniper-junos_nc
NEDNSO has supported Junos devices from early on. The legacy Junos NED is NETCONF-based, but as Junos devices did not provide YANG modules in the past, complex NSO machinery translated Juniper's XML Schema Description (XSD) files into a single YANG module. This was an attempt to aggregate several Juniper device modules/versions.
Juniper nowadays provides YANG modules for Junos devices. Junos YANG modules can be downloaded from the device and used directly in NSO with the new juniper-junos_nc
NED.
By downloading the YANG modules using juniper-junos_nc
NED tools and rebuilding the NED, the NED can provide full coverage immediately when the device is updated instead of waiting for a new legacy NED release.
This guide describes how to replace the legacy juniper-junos
NED and migrate NSO applications to the juniper-junos_nc
NED using the NSO MPLS VPN example from the NSO examples collection as a reference.
Prepare the example:
Add the
juniper-junos
andjuniper-junos_nc
NED packages to the example.Configure the connection to the Junos device.
Add the MPLS VPN service configuration to the simulated network, including the Junos device using the legacy
juniper-junos
NED.
Adapting the service to the juniper-junos_nc
NED:
Un-deploy MPLS VPN service instances with
no-networking
.Delete Junos device config with
no-networking
.Set the Junos device to NETCONF/YANG compliant mode.
Switch the ned-id for the Junos device to the
juniper-junos_nc
NED package.Download the compliant YANG models, build, and reload the
juniper-junos_nc
NED package.Sync from the Junos device to get the compliant Junos device config.
Update the MPLS VPN service to handle the difference between the non-compliant and compliant configurations belonging to the service.
Re-deploy the MPLS VPN service instances with
no-networking
to make the MPLS VPN service instances own the device configuration again.
If applying the steps for this example on a production system, you should first take a backup using the ncs-backup
tool before proceeding.
Prepare the Example
This guide uses the MPLS VPN example in Python from the NSO example set under $NCS_DIR/examples.ncs/getting-started/developing-with-ncs/17-mpls-vpn-python
to demonstrate porting an existing application to use the juniper-junos_nc
NED. The simulated Junos device is replaced with a Junos vMX 21.1R1.11 container, but other NETCONF/YANG-compliant Junos versions also work.
Add the juniper-junos
and juniper-junos_nc
NED Packages
juniper-junos
and juniper-junos_nc
NED PackagesThe first step is to add the latest juniper-junos
and juniper-junos_nc
NED packages to the example's package directory. The NED tar-balls must be available and downloaded from your https://software.cisco.com/download/home account to the 17-mpls-vpn-python
example directory. Replace the NSO_VERSION
and NED_VERSION
variables with the versions you use:
Build and start the example:
Configure the Connection to the Junos Device
Replace the netsim device connection configuration in NSO with the configuration for connecting to the Junos device. Adjust the USER_NAME
, PASSWORD
, and HOST_NAME/IP_ADDR
variables and the timeouts as required for the Junos device you are using with this example:
Open a CLI terminal or use NETCONF on the Junos device to verify that the rfc-compliant
and yang-compliant
modes are not yet enabled. Examples:
Or:
The rfc-compliant
and yang-compliant
nodes must not be enabled yet for the legacy Junos NED to work. If enabled, delete in the Junos CLI or using NETCONF. A netconf-console example:
Back to the NSO CLI to upgrade the legacy juniper-junos
NED to the latest version:
Add the MPLS VPN Service Configuration to the Simulated Network
Turn off autowizard
and complete-on-space
to make it possible to paste configs:
The example service config for two MPLS VPNs where the endpoints have been selected to pass through the PE
node PE2
, which is a Junos device:
To verify that the traffic passes through PE2
:
Toward the end of this lengthy output, observe that some config changes are going to the PE2
device using the http://xml.juniper.net/xnm/1.1/xnm
legacy namespace:
Looks good. Commit to the network:
Adapting the Service to the juniper-junos_nc
NED
juniper-junos_nc
NEDNow that the service's configuration is in place using the legacy juniper-junos
NED to configure the PE2
Junos device, proceed and switch to using the juniper-junos_nc
NED with PE2
instead. The service template and Python code will need a few adaptations.
Un-deploy MPLS VPN Services Instances with no-networking
no-networking
To keep the NSO service meta-data information intact when bringing up the service with the new juniper-junos_nc
NED, first un-deploy
the service instances in NSO, only keeping the configuration on the devices:
Delete Junos Device Config with no-networking
no-networking
First, save the legacy Junos non-compliant mode device configuration to later diff against the compliant mode config:
Delete the PE2
configuration in NSO to prepare for retrieving it from the device in a NETCONF/YANG compliant format using the new NED:
Set the Junos Device to NETCONF/YANG Compliant Mode
Using the Junos CLI:
Or, using the NSO netconf-console
tool:
Switch the NED ID for the Junos Device to the juniper-junos_nc
NED Package
juniper-junos_nc
NED PackageDownload the Compliant YANG models, Build, and Load the juniper-junos_nc
NED Package
juniper-junos_nc
NED PackageThe juniper-junos_nc
NED is delivered without YANG modules, enabling populating it with device-specific YANG modules. The YANG modules are retrieved directly from the Junos device:
See the juniper-junos_nc
README
for more options and details.
Build the YANG modules retrieved from the Junos device with the juniper-junos_nc
NED:
Reload the packages to load the juniper-junos_nc
NED with the added YANG modules:
Sync From the Junos Device to get the Device Configuration in NETCONF/YANG Compliant Format
Update the MPLS VPN Service
The service must be updated to handle the difference between the Junos device's non-compliant and compliant configuration. The NSO service uses Python code to configure the Junos device using a service template. One way to find the required updates to the template and code is to check the difference between the non-compliant and compliant configurations for the parts covered by the template.
Checking the packages/l3vpn/templates/l3vpn-pe.xml
service template Junos device part under the legacy http://xml.juniper.net/xnm/1.1/xnm
namespace, you can observe that it configures interfaces
, routing-instances
, policy-options
, and class-of-service
.
You can save the NETCONF/YANG compliant Junos device configuration and diff it against the non-compliant configuration from the previously stored legacy.xml
file:
Examining the difference between the configuration in the legacy.xml
and new.xml
files for the parts covered by the service template:
There is no longer a single namespace covering all configurations. The configuration is now divided into multiple YANG modules with a namespace for each.
The
/configuration/policy-options/policy-statement/then/community
node choice identity is no longer provided with a leaf namedkey1
. Instead, the leaf name ischoice-ident
, and achoice-value
leaf is set.The
/configuration/class-of-service/interfaces/interface/unit/shaping-rate/rate
leaf format has changed from using anint32
value to a string with either no suffix or a "k", "m" or "g" suffix. This differs from the other devices controlled by the template, so a new templateBW_SUFFIX
variable set from the Python code is needed.
To enable the template to handle a Junos device in NETCONF/YANG compliant mode, add the following to the packages/l3vpn/templates/l3vpn-pe.xml
service template:
The Python file changes to handle the new BW_SUFFIX
variable to generate a string with a suffix instead of an int32
:
Code that uses the function and set the string to the service template:
After making the changes to the service template and Python code, reload the updated package(s):
Re-deploy the MPLS VPN Service Instances
The service instances need to be re-deployed to own the device configuration again:
The service is now in sync with the device configuration stored in NSO CDB:
When re-deploying the service instances, any issues with the added service template section for the compliant Junos device configuration, such as the added namespaces and nodes, are discovered.
As there is no validation for the rate leaf string with a suffix in the Junos device model, no errors are discovered if it is provided in the wrong format until updating the Junos device. Comparing the device configuration in NSO with the configuration on the device shows such inconsistencies without having to test the configuration with the device:
If there are issues, correct them and redo the re-deploy no-networking
for the service instances.
When all issues have been resolved, the service configuration is in sync with the device configuration, and the NSO CDB device configuration matches to the configuration on the Junos device:
The NSO service instances are now in sync with the configuration on the Junos device using the juniper-junos_nc
NED.
Last updated