IOS-XR route-policies in NSO

I’m currently working on the freely available edition of Cisco’s NSO software, which comes with rather old networks element drivers for Cisco IOS-XR (dated 2015). Trying to build services for proof-of-concept purposes, I had to establish a route-policy for an Internet service that only allows specific prefixes defined for the customer.

The most obvious and scalable approach would’ve been to build a prefix-set and reference it in a route-policy. However during updates to the prefix-set, the NED tried to negate old prefixes and add new ones through CLI. In IOS-XR, modifications to a prefix-set in config-mode requires a complete re-deployment of the prefix-set and the NED did this wrong in that specific version.

Instead, I wrote an inline prefix-list in the route-policy, and kept it in one if-sequence, as this would force it to re-deploy the route-policy as IOS-XR required if any modifications occured. It’s not pretty but it works..

Partial YANG model

module inetsvcs {
  namespace "http://com/example/inetsvcs";
  prefix inetsvcs;
  import ietf-inet-types {
    prefix inet;
  import tailf-ncs {
    prefix ncs;
  import tailf-common {
    prefix tailf;
  import tailf-ned-cisco-ios {
    prefix ios;
  import tailf-ned-cisco-ios-xr {
    prefix cisco-ios-xr;
  augment "/ncs:services" {
    list inetsvcs {
      key "name";
      uses ncs:service-data;
      ncs:servicepoint "inetsvcs";
      leaf customer {
        tailf:info "Customer name";
        type leafref {
          path "/ncs:customers/ncs:customer/ncs:id";
      list prefixes {
        tailf:info "List of allowed prefixes from customer";
        key "prefix";
        leaf prefix {
          tailf:info "Public prefix from customer";
          type inet:ipv4-prefix;
        leaf prfx_length {
          tailf:info "Acceptable subnet sizes";
          type uint8 {
            range "1..24";

Partial XML template:

<?xml version="1.0" encoding="UTF-8"?>
 <config-template xmlns="" servicepoint="inetsvcs">
 <?set CUSTOMER = {/customer}?>
 <?set NUM_PRFX = {count(/prefixes)}?>
 <devices xmlns="">
    <?foreach {/link}?>
      <device tags="nocreate">
          <?set COUNTER=1?>
          <?set RPL=''?>
          <?foreach {/prefixes}?>
            <?if {$COUNTER != $NUM_PRFX} ?>
              <?set RPL={concat($RPL, prefix, ' le ', prfx_length, ', ')}?>
              <?set RPL={concat($RPL, prefix, ' le ', prfx_length)}?>
            <?set COUNTER={$COUNTER+1}?>
          <route-policy xmlns="" tags="merge">
            <value> if destination in {string("(")} {$RPL} {string(")")} then&#xD;&#xA;