cancel
Showing results for 
Search instead for 
Did you mean: 
cancel

How to Configure LSA in Layman's Terms

916
Views
30
Helpful
3
Comments
Beginner

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.

 

Example Network Topology.png

 

 

 

 

 

 

 

 

 

 LSA-Logical.JPG

 

LSA-Detailed.JPG

 

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:With Leafrefs.png

 

Once I removed the leafref it compiled just fine:Without Leafrefs.png

 

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.

NETCONF NED Installed.png

 

 

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:

NED Configuration.png

 

 

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.

Stacked CFS Service Configuration.png

 

Hopefully you found this helpful in understanding how to setup LSA!

Thanks,

TG

3 Comments
Beginner

Stephen hi,

 

Very useful post. Thanks a lot. Steps are very clearly explained.

 

May you help me understanding the following :

 

In your post above, you explained how to create the upper layer NSO NED to manage the lower layer NSO. 

 

I am wondering why there isn't any NED to manage the lower layer NSO in the upper layer NSO in the examples under examples.ncs folder. Also, upper layer NSO template addresses the RFS node as device but not the managed device, this also tells me there needs to be a NED to manage the lower layer NSO.

 

So, where are the upper layer NSO NEDs in the examples , or am i missing something ?

 

note : i couldn't quite clearly understand the lsa example under service-provider folder as it is java based. But for the other 2 lsa examples ( 22 and 24 ), under getting-started/developing-with-ncs folder , my question is valid.

 

Thanks in advance.

erdemk, sorry for the delay in my response, there is no ned needed to communicate with lower nso because it uses netconf to learn the service models supported by the lower nso

 

Since nso speaks native netconf for lsa communications there is no need for a ned only the lsa  configurations declaring it an lsa netconf device

 

Let me know if that answers your question

 

TG

Beginner
Hello Stephen,
Yes this is clear enough.
Many thanks for reply