YANG Mount with OpenDaylight Boron: A Packet Design How-to

In addition to its day job being a chemical element with symbol B and atomic number 5, Boron is the fifth release of OpenDaylight (ODL), the leading open source platform for programmable, software-defined networks. Released just last month, Boron increases support for new methods of approaching classic traffic engineering challenges faced by network operators.

OpenDaylight already provides an exceptionally broad range of southbound protocols. It continues to build out and standardize how protocols such as OpenFlow, BGP, PCEP, MPLS, and NETCONF are used, and how to model them effectively. In this post, we will go step by step into how to mount a remote datastore into OpenDaylight’s NETCONF server.

YANG Mount

The IETF Network Working Group’s Internet-Draft for “Mounting YANG-Defined Information from Remote Datastores” introduces capabilities that allow YANG datastores to reference and incorporate information from remote datastores. This is accomplished by extending YANG with the ability to define mount points that reference data nodes in another YANG subtree, subsequently allowing those data nodes to be accessed by client applications as if part of an alternative data hierarchy, and providing the necessary means to manage and administer those mount points.

Cisco IOS-XR

IOS-XR 5.3 and later supports netconf-yang. The models are published in github. Netconf-yang is enabled using the following configuration commands:

netconf-yang agent
     ssh
!
ssh server v2
ssh server netconf port 830

OpenDaylight

Using the POSTMAN or RESTCONF client one could spawn additional netconf connectors while the controller is running.

RESTCONF

Method: POST
URIhttp://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/config:modules
Headers:
Accept: application/xml
Content-Type: application/xml

Payload:

<module xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">

<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">prefix:sal-netconf-connector</type>

<name>new-netconf-device</name>

<address xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">127.0.0.1</address>

<port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">830</port>

<username xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</username>

<password xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</password>

<tcp-only xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">false</tcp-only>

<event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">

<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-event-executor</type>    

<name>global-event-executor</name>

</event-executor>

<binding-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">

<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-broker-osgi-registry</type> 

<name>binding-osgi-broker</name>

</binding-registry> 

<dom-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">    

<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>   

<name>dom-broker</name>  

</dom-registry> 

<client-dispatcher xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">    

<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf">prefix:netconf-client-dispatcher</type>    

<name>global-netconf-dispatcher</name>  

</client-dispatcher> 

<processing-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">    

<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">prefix:threadpool</type>  

<name>global-netconf-processing-executor</name> 

</processing-executor>  

<keepalive-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">    

<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">prefix:scheduled-threadpool</type> 

<name>global-netconf-ssh-scheduled-executor</name> 

</keepalive-executor>

</module>

Once the router is mounted to OpenDaylight, router data can be retrieved from OpenDaylight using the mount point. The example below shows retrieving MPLS TE operational data.

GET http://192.168.1.21:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/xrv/yang-ext:mount/Cisco-IOS-XR-mpls-te-oper:mpls-pce

{
  "mpls-pce": {
    "tunnels": {
      "tunnel": [
        {
          "tunnel-name": "tunnel-te1007",
          "is-curr-path-option-pce": false,
          "admin-weight": 0,
          "sender-pce-address": "0.0.0.0",
          "source-address": "10.66.0.201",
          "destination-address": "10.66.0.202",
          "tunnel-state": "tunnel-state-up",
          "configured-pce-address": "0.0.0.0",
          "curr-path-option-index": 10,
          "path-state": "state-none",
          "hop-count": 0
        }
      ]
    },
    "topology": {
      "global": {
        "nodes": [
        {
            "router-id": "10.66.0.201",
            "pce-cost": 4294967295,
            "igp-area-id": 0,
            "node-id": "12.0.0.0",
            "igp-area-format": "igp-area-format-number",
            "is-pce-border-node": true
          },
          {
            "router-id": "10.66.0.202",
            "pce-cost": 4294967295,
            "igp-area-id": 0,
            "node-id": "13.0.0.0",
            "igp-area-format": "igp-area-format-number",
            "is-pce-border-node": true
          },
          {
            "router-id": "10.66.0.203",
            "pce-cost": 4294967295,
            "igp-area-id": 0,
            "node-id": "14.0.0.0",
            "igp-area-format": "igp-area-format-number",
            "is-pce-border-node": true
          },
          {
            "router-id": "10.66.0.204",
            "pce-cost": 4294967295,
            "igp-area-id": 0,
            "node-id": "15.0.0.0",
            "igp-area-format": "igp-area-format-number",
            "is-pce-border-node": true
          }
        ]
      }
    },
    "statistics": {
      "current-pceq-length": 0,
      "pce-req-timed-out": 0,
      "tunnels": 0,
      "max-teq-length": 6,
      "max-pceq-length": 7,
      "current-file-descriptors": 2,
      "pce-req-pending": 0,
      "pce-req-total": 0,
      "average-in-queue-depth": [
        0
      ],
      "current-teq-length": 0,
      "max-file-descriptors": 2,
      "neighbors": 2,
      "maximum-in-queue-depth": [
        3,
        2,
        1
      ],
      "igp-statistics": {
        "abr-lookup-timeout": 0,
        "abr-lookup-max": 0,
        "abr-lookup-min": 0,
        "abr-lookup-complete": 0,
        "abr-lookup-avg": 0
      }
    },
       …..
       …..
       …..
    }
  }
}

At Packet Design, we are excited to lead and embrace the evolution of SDN, in part by contributing to open source projects, like OpenDaylight. We eagerly look forward to other router vendors supporting this important YANG feature to enable a true vendor-neutral SDN environment.

 

  • Alexis de Talhouët

    Since Beryllium, there is a more elegant way to spawn netconf-connector, using network-topology instead of config system, see this wiki section or the slide deck from ODLSummit2016 NETCONF usability for reference.
    It basically allows you to provide only the information you need, without having to specify things you don’t know what they are, e.g. the client-dispatcher or the dom-registry…

    • Thanks for the links, Alexis. We
      will explore the alternate ways to mount.