![](https://community.cisco.com/html/assets/img_tile-default.png)
Summary
I wanted to contribute by providing some step by step instructions for setting up LSA with a very simple example using an LSA service to configure firewall interfaces. The examples included with an NSO installation were good to start with, but lacked some insight on a few things which made it difficult for me to understand or get working. I tried to make this as ‘simple’ to follow as possible while capturing and explaining all the pitfalls I personally fell into trying to get this to work. This assumes you've done some reading on the LSA architecture and understand all the relevant acronyms. Kudos to Don with the Cisco team helping me get this to work!
Example Network Topology
I used VMWare workstation to host all my NSO servers and virtual firewall instances. I’m using the Fortinet NED to configure services that change the IP and subnet mask on firewall ports.
System Configurations
The only system configurations I needed to make was to allow LSA in the ncs.conf file, and to enable the NETCONF SSH interface and set the port it listens on. I’ve included copies of my ncs.conf files to this post.
<netconf-north-bound> <enabled>true</enabled> <transport> <ssh> <enabled>true</enabled> <ip>0.0.0.0</ip> <port>2022</port> </ssh> </transport> </netconf-north-bound> <large-scale> <lsa> <enabled>true</enabled> </lsa> </large-scale>
Device Configurations
RFS Devices
Here is an example configuration for an RFS device on the CFS Node. The authgroup used included admin credentials on the NSO application. Device type was netconf:lsa-netconf, and I set different NETCONF ports on the RFS ncs.conf files.
CFS Device List:
devices device lower-nso1 address 192.168.0.23 port 2023 authgroup LSA device-type netconf ned-id lsa-netconf state admin-state unlocked
devices device lower-nso2 address 192.168.0.42 port 2024 authgroup LSA device-type netconf ned-id lsa-netconf state admin-state unlocked
Firewall Devices
Standard NSO device config to allow NSO to connect and sync the device data to the CDB. The authgroup used here used an admin account to log into the firewall, and the Fortinet ned is a cli type ned.
RFS1 Device List:
devices device FGT-1 address 192.168.0.31 authgroup FGT device-type cli ned-id fortinet-fortios device-type cli protocol ssh state admin-state unlocked
RFS2 Device List:
devices device FGT-2 address 192.168.0.38 authgroup FGT device-type cli ned-id fortinet-fortios device-type cli protocol ssh state admin-state unlocked
devices device FGT-3 address 192.168.0.39 authgroup FGT device-type cli ned-id fortinet-fortios device-type cli protocol ssh state admin-state unlocked
RFS Service Configurations
On the RFS Node I created a simple service that configures the IP address and Subnet Mask on a firewall interface using the Fortinet-ned.
rfs-interface
Nothing really special or different with regards to this rfs service. It was built using the bottom up approach taking the XML from the NED config and building the YANG model around the four variables found (device name, port-name, IP, and subnet mask). I was lazy and just used ipv4-address type for both the IP and subnet mask :)
YANG:
module rfs-interface { namespace "http://com/example/rfsinterface"; prefix rfs-interface; import ietf-inet-types { prefix inet; } import tailf-ncs { prefix ncs; } list interface { key device; uses ncs:service-data; ncs:servicepoint "rfs-interface"; leaf device { type leafref { path "/ncs:devices/ncs:device/ncs:name"; } } leaf port-name { type enumeration { enum port1; enum port2; enum port3; } } leaf ip { type inet:ipv4-address; } leaf subnet { type inet:ipv4-address; } } }
XML:
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="rfs-interface"> <devices xmlns="http://tail-f.com/ns/ncs"> <device tags="nocreate"> <name>{/device}</name> <config tags="merge"> <!-- Fotigate Interface --> <system xmlns="http://tail-f.com/ned/fortinet-fortios-non-vdom"> <interface> <interface-list> <name>{/port-name}</name> <ip> <ip-mask> <class_ip>{/ip}</class_ip> <net_mask>{/subnet}</net_mask> </ip-mask> </ip> </interface-list> </interface> </system> </config> </device> </devices> </config-template>
This next step was tricky and is a point where I got lost. At this point you have to create a CFS NETCONF NED using the YANG from your service model. It was hard for me to grasp this reading the examples provided with NSO. Once I figured this out I also found out that the YANG model you reference in the command to configure a NED CANNOT include any leafrefs in it.
In my example rfs-interface service, the only leafref I had was for the device name, as it was pointed to the local NSO device list path. I copied my rfs-interface service and removed the leafref by replacing the type to a string. Once I did this, the NETCONF NED created worked and compiled properly.
Here you can see the NED has an error when compiled with leafrefs:
Once I removed the leafref it compiled just fine:
I’ve included the rfs-interface service I used to create the NETCONF NED to this post. If you compare these you’ll see that only the device leafref was changed to string.
It's important to note here that I did NOT use the RFS service without leafrefs on the RFS node, it was literally only used to build the NED, I actually moved the copied package to a directory I made to hold the edited package and the NED that was created from it.
rfs-interface YANG without leafrefs:
module rfs-interface { namespace "http://com/example/rfsinterface"; prefix rfs-interface; import ietf-inet-types { prefix inet; } import tailf-ncs { prefix ncs; } list interface { key device; uses ncs:service-data; ncs:servicepoint "rfs-interface"; leaf device { type string; } leaf port-name { type enumeration { enum port1; enum port2; enum port3; } } leaf ip { type inet:ipv4-address; } leaf subnet { type inet:ipv4-address; } } }
The command I ran to build the NETCONF NED is:
ncs-make-package --no-netsim --netconf-ned \ <YANG PATH> --build <NED NAME> ncs-make-package --no-netsim --netconf-ned \ rfs-interface/src/yang --build cfs-ned-interface
NETCONF Service NED
Once the NETCONF NED was built I copied it over to the packages directory of the CFS Node. I reloaded the packages on this node to install the NED. Once you do this you should now be able to see the rfs-interface configuration when you try configuring the RFS node directly.
CFS Service Configurations
To configure stacked services on the CFS server NSO documentation mentions the use of a dispatching service so you can map SB managed devices to RFS nodes. This allows you to apply the service configuration to the correct RFS node managing the SB device. I’ve included an example dispatch-map service you can use to keep track of this. The documentation mentions that maintenance of this list is important and you will either need to poll the RFS nodes through automation to update the list perpetually or have the RFS nodes notify the CFS of the device list update somehow. I don’t have any examples of dispatch mapping maintenance currently.
Example Dispatch-Map YANG:
module dispatch-map { namespace "http://com/example/dispatchmap"; prefix dispatch-map; import ietf-inet-types { prefix inet; } import tailf-ncs { prefix ncs; } list dispatch-map { key rfs-node; uses ncs:service-data; ncs:servicepoint "dispatch-map"; leaf rfs-node { type leafref { path "/ncs:devices/ncs:device/ncs:name"; } } list managed-device { key name; leaf name { type string; } } } }
CFS Dispatch Map Configuration:
dispatch-map lower-nso1 managed-device FGT-1 ! ! dispatch-map lower-nso2 managed-device FGT-2 ! managed-device FGT-3 ! !
The stacked service I built to interface with the RFS Service NED has leafrefs to the dispatch-map service. When you view the YANG module you’ll see I’m importing the dispatch-maps model into the stacked service. Doing this allows me to use leafrefs to the dispatch maps data in my service model. If you do this you need to make sure you update the Makefile in the src folder of your service to include the YANG path of the module you’re importing.
Stacked CFS Service YANG:
module cfs-if-svc { namespace "http://com/example/cfsifsvc"; prefix cfs-if-svc; import ietf-inet-types { prefix inet; } import tailf-ncs { prefix ncs; } import dispatch-map { prefix map; } list cfs-if-svc { key 'rfs-node managed-device'; uses ncs:service-data; ncs:servicepoint "cfs-if-svc"; leaf rfs-node { type leafref { path "/map:dispatch-map/map:rfs-node"; } } leaf managed-device { type leafref { path "deref(../rfs-node)/../map:managed-device/map:name"; } } leaf port { type enumeration{ enum port2; enum port3; } } leaf ip { type inet:ipv4-address; } leaf subnet { type inet:ipv4-address; } } }
Stacked CFS Service XML:
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="cfs-if-svc"> <devices xmlns="http://tail-f.com/ns/ncs"> <device tags="nocreate"> <name>{/rfs-node}</name> <config tags="merge"> <interface xmlns="http://com/example/rfsinterface"> <device>{/managed-device}</device> <port-name>{/port}</port-name> <ip>{/ip}</ip> <subnet>{/subnet}</subnet> </interface> </config> </device> </devices> </config-template>
Stacked Service Makefile:
Make note of the YANGPATH which points to the YANG file of the service.
all: fxs .PHONY: all # Include standard NCS examples build definitions and rules include $(NCS_DIR)/src/ncs/build/include.ncs.mk src=$(wildcard yang/*.yang) DIRS = ../load-dir FXS = $(SRC:yang/%.yang=../load-dir/%.fxs) ## Uncomment and patch the line below if you have a dependency to a NED ## or to other YANG files YANGPATH += ../../dispatch-map/src/yang NCSCPATH = $(YANGPATH:%=--yangpath %) YANGERPATH = $(YANGPATH:%=--path %) fxs: $(DIRS) $(FXS) .PHONY: fxs $(DIRS): mkdir -p $@ ../load-dir/%.fxs: yang/%.yang $(NCSC) `ls $*-ann.yang > /dev/null 2>&1 && echo "-a $*-ann.yang"` \ $(NCSCPATH) -c -o $@ $< clean: rm -rf $(DIRS) .PHONY: clean
Connect to RFS Nodes
Once you’ve compiled and reloaded all of your services and NEDs into NSO, you can connect to and sync from the RFS nodes. Once all devices are in sync, you can begin configuring devices managed by each RFS from the CFS node.
NETCONF NED Configuration Example
Here is an example configuring the RFS node directly from the CFS Node using only the NETCONF NED from your RFS service, as you can see the local device configuration is updated and the lower lsa-node’s device and service data are updated as well:
Stacked Service Configuration Example
Here we’re using the stacked service on the CFS to interface with the RFS node and configure the SB managed device. As you can see we have service data configured and saved to the CFS with the relevant mapping of the managed device to the RFS node.
Hopefully you found this helpful in understanding how to setup LSA!
Thanks,
TG
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the NSO Developer community: