Quantcast
Channel: SDN Hub » tutorials
Viewing all articles
Browse latest Browse all 5

Experimenting with NETCONF connector in OpenDaylight

$
0
0

netconf-managing-routersOn the southbound, OpenDaylight has support for both NETCONF and OpenFlow for managing underlying devices. This allows your applications to manage both traditional devices with in-built control planes and the OpenFlow-enabled devices with decoupled control planes. End-to-end control and orchestration is, thus, easily achieved using a single platform.

1. Setup

In this post we get an understanding of the NETCONF support through a simple experiment with netopeer‘s NETCONF server packaged as a Docker image. Here are steps to get a hands-on experience into using NETCONF:

Step 1: Install Docker and netopeer image.

$ wget -qO- https://get.docker.com/gpg | sudo apt-key add -
$ wget -qO- https://get.docker.com/ | sudo sh
$ sudo docker pull sdnhub/netopeer

Step 2: Spin up simulated router instances. We now spin up two simulated router instances (

router1
and
router2
) that can be configured over NETCONF. (Assuming you have the SDNHub_OpenDaylight_Tutorial folder cloned)

$ git clone https://github.com/sdnhub/SDNHub_Opendaylight_Tutorial/
$ cd SDNHub_Opendaylight_Tutorial/netconf-exercise
$ ./spawn_router.sh router1
...
Spawned container with IP 172.17.0.63
$ ./spawn_router.sh router2
...
Spawned container with IP 172.17.0.64

These two simulated routers use the following custom YANG model to model some basic configurations of typical routers.

module router {
    yang-version 1;
    namespace "urn:sdnhub:odl:tutorial:router";
    prefix router;

    description "Router configuration";

    revision "2015-07-28" {
        description "Initial version.";
    }

    list interfaces {
        key id;
        leaf id {
            type string;
        }
        leaf ip-address {
            type string;
        }
    }
    container router {
        list ospf {
            key process-id;
            leaf process-id {
                type uint32;
            }
            list networks {
                key subnet-ip;
leaf subnet-ip {
                    type string;
                }
                leaf area-id {
                    type uint32;
                }
            }
        }
        list bgp {
            key as-number;
            leaf as-number {
                type uint32;
            }
            leaf router-id {
                type string;
            }
            list neighbors {
                key as-number;
                leaf as-number {
                    type uint32;
                }
                leaf peer-ip {
                    type string;
                }
            }
        }
    }
}

Step 3: Start OpenDaylight and register the two NETCONF devices. In this example, we use the pre-compiled OpenDaylight in the tutorial VM. Ensure that you install the

odl-netconf-connector-all
feature

$ cd ~/SDNHub_Opendaylight_Tutorial
$ mvn clean install -nsu
$ cd distribution/opendaylight-karaf/target/assembly
$ ./bin/karaf 
opendaylight-user@root> feature:install odl-netconf-connector-all

After waiting about 30 secs, register the two NETCONF-enabled routers with OpenDaylight using shell scripts provided. Ensure that the IP address below is updated to what was printed by the spawn_router script above.

$ ./register_netconf_device.sh router1 172.17.0.63; sleep 5
$ ./register_netconf_device.sh router2 172.17.0.64; sleep 5

2. Using RESTconf to manage the devices

Now that you have registered the two NETCONF speakers, you will be able to get and edit configurations, and perform RPC calls from the controller

  • You can see all the YANG models support by that device at this location.
  • For instance, for each router we spawned, you see the following capability in that list:
    <available-capability>
    (urn:sdnhub:odl:tutorial:router?revision=2015-07-28)router
    </available-capability>
  • This works only if your device has support for
    ietf-netconf-monitoring
    , wherein devices export their capabilities or modules to the NETCONF client.
  • If you are attempting to manage a device that does not support
    ietf-netconf-monitoring
    , there are other ways to add the YANG models directly at the controller.

We can start posting configurations from the OpenDaylight controller to the NETCONF servers in the routers using the router YANG model shown above. For instance, we can inject configurations to

router1
using RESTCONF as follows:
$ curl -u admin:admin -v -X PUT -H "Content-Type: application/xml" -d '
      <interfaces xmlns="urn:sdnhub:odl:tutorial:router">
        <id>eth0</id>
        <ip-address>10.10.1.1/24</ip-address>
      </interfaces>
' http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router1/yang-ext:mount/router:interfaces/eth0

Visit this page after making the above cUrl call to verify that the configuration was added.

Alternatively, you can use netopeer-cli (which is a NETCONF client) to verify the same data as follows:

$ sudo docker attach router1
# netopeer-cli
 netconf> connect localhost (Passwd: root)
 netconf> get-config running
   Result:
   <interfaces xmlns="urn:sdnhub:odl:tutorial:router">
     <id>eth0</id>
     <ip-address>10.10.1.1/24</ip-address>
   </interfaces>
 netconf>

As you can see, our RESTconf operation pushed configuration from the OpenDaylight controller to the data store of the device’s NETCONF server. The traditional control plane will, then, pass those configurations to the routing protocols within.

You can further experiment with this environment and push other configurations (like BGP and OSPF) for these two routers. Here is an example of how you can configure OSPF and BGP parameters (assuming all the interface IP are assigned prior to this):

$ curl -u admin:admin -v -X PUT -H "Content-Type: application/xml" -d '
  <router xmlns="urn:sdnhub:odl:tutorial:router">
    <ospf>
      <process-id>1</process-id>
      <networks>
        <subnet-ip>100.100.100.0/24</subnet-ip>
        <area-id>10</area-id>
      </networks>
    </ospf>
    <bgp>
      <as-number>1000</as-number>
      <router-id>10.10.1.1</router-id>
      <neighbors>
        <as-number>2000</as-number>
        <peer-ip>10.10.1.2</peer-ip>
      </neighbors>
    </bgp>
  </router>
' http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router1/yang-ext:mount/router:router

Here is a postman collections file with a few REST calls in case you want to add or get configurations.

3. Developing a NETCONF application in Java

Within the tutorial project, we have a Java application that uses the OpenDaylight NETCONF connector to program configurations to the underlying device. This is to illustrate the type of automation possible within the JVM. This is also a way to logically centralize state pertaining all types of devices, both OpenFlow-based devices and legacy ones, allowing for backward compatibility.

To enable this application, you will have to install the appropriate feature in the Karaf console, prior to registering the NETCONF devices using the “register_netconf_device.sh” script.

opendaylight-user@root> feature:install sdnhub-tutorial-netconf-exercise
opendaylight-user@root> log:set DEBUG org.sdnhub

Now run “register_netconf_device.sh” in another terminal for router1. That in turn will print the following output in the console, confirming that configuration has been written to data store.

opendaylight-user@root> log:tail
2015-09-05 13:38:12,560 | INFO  | sing-executor-15 | NetconfDevice                    | 244 - org.opendaylight.controller.sal-netconf-connector - 1.2.0.Lithium | RemoteDevice{router1}: Netconf connector initialized successfully
2015-09-05 13:38:14,114 | DEBUG | pool-52-thread-1 | MyRouterOrchestrator             | 274 - org.sdnhub.odl.tutorial.netconf-exercise.impl - 1.0.0.SNAPSHOT | Configuring interface eth0 for router1
2015-09-05 13:38:14,417 | DEBUG | pool-52-thread-1 | GenericTransactionUtils          | 274 - org.sdnhub.odl.tutorial.netconf-exercise.impl - 1.0.0.SNAPSHOT | Transaction success for add of object Interfaces [_id=eth0, _ipAddress=10.10.1.1/24, _key=InterfacesKey [_id=eth0], augmentation=[]]
2015-09-05 13:38:14,417 | DEBUG | pool-52-thread-1 | MyRouterOrchestrator             | 274 - org.sdnhub.odl.tutorial.netconf-exercise.impl - 1.0.0.SNAPSHOT | Configuring interface eth1 for router1
2015-09-05 13:38:14,695 | DEBUG | pool-52-thread-1 | GenericTransactionUtils          | 274 - org.sdnhub.odl.tutorial.netconf-exercise.impl - 1.0.0.SNAPSHOT | Transaction success for add of object Interfaces [_id=eth1, _ipAddress=100.100.100.1/24, _key=InterfacesKey [_id=eth1], augmentation=[]]
...

The implementation for the netconf-exercise (i.e.,

netconf-exercise-impl
) has a helper class called
MyRouterOrchestrator
that inserts interface configurations when it discovers a device called
router1
or
router2
. Visit this page for router1 after registering the device to verify that the appropriate interface configurations were added.

The basic constructs necessary for working with a NETCONF device are as follows:

public class MyRouterOrchestrator implements BindingAwareProvider, AutoCloseable, DataChangeListener {
    private MountPointService mountService;
    ....

    @Override
    public void onSessionInitiated(ProviderContext session) {
        // Get the mount service provider
        this.mountService = session.getSALService(MountPointService.class);
    }

    //When new devices are discovered through a data change notification 
    @Override
    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
        ....

        //Step 1: Get access to mount point specific to this netconf node.
        InstanceIdentifier<Node> netconfNodeIID = InstanceIdentifier.builder(NetworkTopology.class)
            .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())))
            .child(Node.class, new NodeKey(new NodeId("router1")))
            .build();
        final Optional<MountPoint> netconfNodeOptional = mountService.getMountPoint(netconfNodeIID);
        
        //Step 2: Write config data to the mount point
        if (netconfNodeOptional.isPresent()) {
            
            //Step 2.1: access data broker within this mount point
            MountPoint netconfNode = netconfNodeOptional.get();
            DataBroker netconfNodeDataBroker = netconfNode.getService(DataBroker.class).get();

            //Step 2.2: construct data and the instance identifier for the config data
            InterfacesBuilder builder = new InterfacesBuilder()
                .setId(interfaceName)
                .setKey(new InterfacesKey("eth0"))
                .setIpAddress("10.10.10.1/24");
            InstanceIdentifier<Interfaces> interfacesIID = InstanceIdentifier
                 .builder(Interfaces.class, builder.getKey()).build();
            
            //Step 2.3: write to the config data store using SDN Hub special transaction utils.
            //The netconf connector sends the new config data to the device as an "edit-config" operation.
            GenericTransactionUtils.writeData(netconfNodeDataBroker, LogicalDatastoreType.CONFIGURATION, interfacesIID, builder.build(), true);
        }
    }
}

The above skeleton code skips several steps to just highlight the basic constructs for mounting device configuration and editing it. Any changes made to the MD-SAL data store is passed along to the device. Similarly, when the controller boots up, any existing configuration is copied over from the device.

4. Summary

  • This post illustrates how easy it is to configure legacy routers over NETCONF, as long as you have the YANG model for that device. This can be extremely powerful as a global orchestrator that nicely integrates OpenFlow and traditional control planes.
  • Having said that, to manage different types of devices, one needs to build YANG-specific plugins or adapters to appropriately convert from high-level intent to device-specific configurations.
  • This device-specific adaptation can be avoided if device configurations share a common model, like OpenConfig, for the common denominator of configurations for a protocol.

Viewing all articles
Browse latest Browse all 5

Trending Articles