Policy package version 3
Yang
module policy {
yang-version 1.1;
namespace "http://example.com/policy";
prefix policy;
import tailf-common { prefix tailf; }
import tailf-ncs { prefix ncs; }
import ietf-inet-types { prefix inet; }
description "Per-device prefix-set + route-policy using leaf-list for batch updates.";
revision 2025-07-18 { description "Refactored to leaf-list for high volume scalability"; }
list policy {
key name;
uses ncs:service-data;
ncs:servicepoint "policy-servicepoint";
leaf name { type string; }
list device {
key device-name;
min-elements 1;
leaf device-name {
type leafref { path "/ncs:devices/ncs:device/ncs:name"; }
}
list prefix-set {
key name;
leaf name { type string; }
leaf-list prefixes {
type inet:ipv4-prefix;
tailf:info "List of IPv4 prefixes (e.g., 10.0.0.0/24)";
}
}
list route-policy {
key name;
min-elements 1;
description "At least one route-policy required per device.";
leaf name { type string; }
leaf prefix-set-ref {
type leafref { path "../../prefix-set/name"; }
mandatory true;
}
}
}
}
}
python
# -*- mode: python; python-indent: 4 -*-
import ncs
from ncs.application import Service, Application
class ServiceCallbacks(Service):
@Service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info(f"Service create: {service.name}")
tmpl = ncs.template.Template(service)
for dev in service.device:
dev_name = dev.device_name
for ps in dev.prefix_set:
ps_name = ps.name
for prefix in ps.prefixes:
vars_ps = ncs.template.Variables()
vars_ps.add('DEVICE_NAME', dev_name)
vars_ps.add('PS_NAME', ps_name)
vars_ps.add('PREFIX', prefix)
tmpl.apply('prefix-set-template', vars_ps)
for rp in dev.route_policy:
ps_name = rp.prefix_set_ref
definition = f"""if destination in {ps_name} then
pass
else
drop
endif"""
vars_rp = ncs.template.Variables()
vars_rp.add('DEVICE_NAME', dev_name)
vars_rp.add('RP_NAME', rp.name)
vars_rp.add('DEFINITION', definition)
tmpl.apply('route-policy-template', vars_rp)
class Policy(Application):
def setup(self):
self.log.info('Policy package RUNNING')
self.register_service('policy-servicepoint', ServiceCallbacks)
def teardown(self):
self.log.info('Policy package STOPPING')
template
prefix-set-template.xml
<config-template xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device>
<name>{$DEVICE_NAME}</name>
<config>
<prefix-set xmlns="http://tail-f.com/ned/cisco-ios-xr">
<name>{$PS_NAME}</name>
<set>
<value>{$PREFIX}</value>
</set>
</prefix-set>
</config>
</device>
</devices>
</config-template>
route-policy-template.xml
<config-template xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device>
<name>{$DEVICE_NAME}</name>
<config>
<route-policy xmlns="http://tail-f.com/ned/cisco-ios-xr">
<name>{$RP_NAME}</name>
<value>{$DEFINITION}</value>
</route-policy>
</config>
</device>
</devices>
</config-template>