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="http://tail-f.com/ns/config/1.0" servicepoint="inetsvcs">
 <?set CUSTOMER = {/customer}?>
 <?set NUM_PRFX = {count(/prefixes)}?>
 <devices xmlns="http://tail-f.com/ns/ncs">
    <?foreach {/link}?>
      <device tags="nocreate">
        <name>{device}</name>
        <config>
          <?set COUNTER=1?>
          <?set RPL=''?>
          <?foreach {/prefixes}?>
            <?if {$COUNTER != $NUM_PRFX} ?>
              <?set RPL={concat($RPL, prefix, ' le ', prfx_length, ', ')}?>
            <?else?>
              <?set RPL={concat($RPL, prefix, ' le ', prfx_length)}?>
            <?end?>
            <?set COUNTER={$COUNTER+1}?>
          <?end?>
          <route-policy xmlns="http://tail-f.com/ned/cisco-ios-xr" tags="merge">
            <name>RPL_INET_{$CUSTOMER}</name>
            <value> if destination in {string("(")} {$RPL} {string(")")} then&#xD;&#xA;
              pass&#xD;&#xA;
            endif&#xD;&#xA;
            </value>
          </route-policy>
        </config>
      </device>
    <?end?>
  </devices>
</config-template>