Advanced NSO Template Service #2

Load blank.ssh.enabled.cfg

#IOS-XE
config replace flash:blank.ssh.enabled.cfg
 
#IOS-XR
configure
load bootflash:blank.ssh.enabled.cfg
commit replace

Create a template service

Create a template service that configures a basic EVPN-VPWS. The template should take the following variables:

  • Instance #

  • Service # (source and target number)

  • Name

  • PE-CE link (two)

    • PE device name

    • interface type

    • interface number

    • vlan ID

  • Handle both IOS-XE and IOS-XR PEs

If you are starting this lab without doing the previous one, you can add all devices to NSO with this config:

Initial NSO Configuration

Answer

Create the vpws service-skeleton:

Create a YANG module as follows:

Above, the VPWS service is identified by the leaf “name” (using the key statement). The VPWS service has an instance_id, service_id, and a list of links. Each link is identified by the link ID, and contains a device, vlan_id, interface_type, and interface_number.

Notice that we can restrict the options for an interface_type by using an enumeration. In the CLI, we are only allowed to enter a type that was pre-specified as an enum:

Next, we create a template. I created this by generating the config in NCS and doing a dry-run commit outputted to XML.

Explanation

To accomplish this service, we must handle several things:

  • Multiple links

  • IOS-XE and IOS-XR config

  • Multiple interface types (i.e. GigabitEthernet and TenGigabitEthernet)

To handle multiple links, we simply iterate over every link in the list called “link.” This is done using NSO XML template processing instructions:

To iterate over each item in a list, you use <?foreach {Xpath}?>.

We can also use processing instructions such as if/else statements. This can be used to handle multiple interface types. The issue is that we can’t use an XPath for the XML tag. For example, we cannot do this:

Instead, we can do an if statement. In this template, I do not add TenGig support for brevity. But it can easily be added using another corresponding if statement.

In general, XPath statements are always placed in curly braces {}. There is an important thing to realize about XPath statements though. When these evaluate to a node, the XPath context for the template will change to that node. This can break your template in unexpected ways.

Notice that the l2vpn config uses {string(path)} syntax instead of just {path}. This is used because when the XPath statement resolves to a value, the XPath context does not change. If we don’t use this, the XPath context will change from root/link to just root/ when we get the /instance_id value. Then when we go to reference the interface_type later, we cannot find it under the root. We have lost our root/link context.

Luckily we can find these issues out by debugging during a commit.

Demonstrating Debugging

Let’s change these XPath statements back to the absolute nodes:

We make the package again and reload packages in NCS.

I then apply a new VPWS service:

However, it doesn’t look like it is working as expected. Where’s my interface as a member of the VPWS?

If I pipe the commit dry-run to debug template, I can see this context change happening, which is breaking my template.

First we start in the root context node, which is /vpws[name=’ONE’]. Then we iterate over the foreach, which puts our contex as the first link:

The context stays as-is, until we process a root node. We process /instance_id, which successfully finds the value. But notice that the next evaluation is now in the root context node. We’ve left our link context.

Then when we go to process the interface_type, it cannot be found at the root context:

As a side note, using this debug we can see how the template works for both XE and XR. NCS only generates config for the namespace that a device supports. IOS-XE does not support the ios-xr namespace, so NCS knows not to generate that config:

To fix the XPath context issue, we have a few options:

  • Use string() to evaluate a value instead of a node. This prevents a context switch.

  • Saving and switching context.

Using a string() is probably the easiest method. But let’s demonstrate the use switching contexts. First we save the context under the current link:

Then we set the context back to this when we move from the root-level leafs to the link-level leafs again:

In the debug, we can see that this time the context switches back to the link context before we evaluate the link-specific leafs.

Improving the service

I’ve re-written this and made some improvements. First, the YANG module requires that the VPWS has two PEs. This breaks for a VPWS that has two interfaces on the same PE though. However, in that case, we don’t use an EVPN EVI anyways. So this service is only used for a VPWS between two separate PEs.

There is also a restriction on the VLAN ID (0-4094) and interface number (0/0/0/X).

The XML template sets variables at the beginning when we are still at the root node context, to prevent the need to worry about switching contexts.

Last updated