Networking

Writing OpenDaylight Applications

2 Feb 2015 11:34am, by

The New Stack has had a continuing series on software defined networking. Today’s post is part of that ongoing series. In part one, we defined SDN and detailed different SDN controllers and frameworks. In part two of our series we wrote about Trema, a framework for developing OpenFlow controllers in Ruby and C. Part three explored NOX, the original OpenFlow controller. In part four, we wrote about Ryu, an open source SDN Controller supported by NTT Labs. For part five we looked at FloodLight, an OpenFlow controller with more than 15,000 downloads. OpenDaylight, an SDN controller with broad industry support, was the subject of part six. In part eight, The New Stack Founder Alex Williams wrote about SDN, Docker and the Real Changes Ahead.

An application for OpenDaylight Platform can be developed using two broad methodologies:

  • Writing an application using the RESTful APIs exposed by one or more plugins. This way, the application is part of the OpenDaylight ecosystem, but not necessarily native to the framework.
  • Writing a ‘native’ OpenDaylight application which uses the OSGi interfaces (Java APIs) exposed by OpenDaylight framework. The interfaces are derivatives of various other plugins existing in the framework.

image1

Figure 1 – The two fundamental ways of visualizing an application as part of OpenDaylight Platform

Using the RESTful way, an application can be agnostic to the complexities associated with the OpenDaylight framework as well as being completely language independent – for example, using Python for issuing RESTful requests and handling responses. Whereas, using the OSGi interfaces, the application can exploit much more functionality as well as have higher performance. Using a particular philosophy would essentially be a matter of deciding between ease and turnaround time versus flexibility and performance.

Either of the methodologies defined above allows the application to be considered as a northbound application, one that includes a business logic consuming the functionalities provided by OpenDaylight as a platform.

As RESTful way of development is more towards development of a web application, we would only briefly touch it before digging deeper into the OSGi method, in the following sections.

Writing an Application using RESTful API

RESTful APIs can be provided by any plugin integrated into the OpenDaylight platform as part of their northbound interfaces. Specifically for the OpenDaylight Controller plugin, which provides various core network services, following are some of the RESTful APIs exposed:

  1. Topology: Contains RESTful APIs to access the network graph represented by edges, nodes and their properties. A predefined XML schema defines the data elements for this API.
  2. Host Tracker: RESTful API for extracting or setting information, based on the nodes identified by topology service, for a host machine on the network. The XML Schema defining the data elements for this API includes information like network address and VLAN information.
  3. Flow Programmer: APIs exposed for configuring flows on the network elements, controlled by their respective protocol plugins on the southbound side. The XML Schema for this API includes information for configuring flows with their match conditions and actions.
  4. Static Routing APIs: Simple APIs for creating IP L3 static routing entries on the networking fabric.
  5. Statistics: APIs providing the statistics of flow entries, and the node elements.
  6. Subnets: APIs for configuring network nodes and the hosts attached to them into predefined IP Subnets.
  7. Switch Manager: APIs which focus on exposing various nodes in underlying network as a switch profile, listing their ports and properties.
  8. User Manager: APIs which are used for configuring the authenticated users, with their roles, of the OpenDaylight platform.

Though almost all the APIs provide the RESTful XML Schema for data interaction, some of the APIs may as well support the JSON structure. Using the MDSAL methodology of module development, YANG models can be created which can automatically generate the RESTful bindings for a module.

Using the various APIs listed above, and others available through the OpenDaylight documentation, northbound applications can be created over the OpenDaylight platform.

These applications, though connected using a more generic HTTP interfaces, are still fully qualified members of the OpenDaylight platform. As these are not necessarily in the same space as the controller itself, security becomes important. Thus, for providing a secure environment for accessing sensitive network information like network topology, OpenDaylight provide a basic framework for authentication of requests send using the RESTful mechanism.

Example Application: The CableGuy

I’m sharing a simple application that is developed (not well tested, though) for ODL using only the REST-APIs. This application does the following:

  1. Takes the expected topology in the .DOT file format as input.
  2. Obtains the topology information from the ODL using the rest-APIs
  3. Compares the two topologies and displays and missing/lost ‘cable-connectivity’.

The REST requests used in this application to obtain information from the ODL can be enlisted as below:

  1. Topology Request: “http://”+odl_ip+”:”+odl_port_num+”/controller/nb/v2/topology/default”
  2. Switches connected to ODL:  “http://”+odl_ip+”:”+odl_port_num+”/controller/nb/v2/switchmanager/default/nodes”
  1. List of ports: “http://”+odl_ip+”:”+odl_port_num+”/controller/nb/v2/switchmanager/default/node/OF/”

The application can be found here: https://github.com/cosanti/TheCableGuy

Writing an Application using OSGi interfaces

Before we discuss ODL-application development using the OSGi interfaces, let me just introduce to a few pre-requisite concepts. Readers can obtain the details of these concepts online at the provided references.

OSGi and OSGi Bundles

The Open Service Gateway Interface (OSGi) forms the backend of the OpenDaylight platform. An OSGi framework essentially provides an environment for the modularization of applications into smaller bundles. As Wiki says, “Each bundle is a tightly coupled, dynamically loadable collection of classes, jars, and configuration files that explicitly declare their external dependencies (if any)” [1]. The user has the freedom to use any of the OSGi containers, such as Apache Felix or Equinox. We can find various resources online explaining the process of creating such bundles, including the javaworld.com.

Maven, maven-bundle plugin and POM

OpenDaylight uses Maven for build automation and dependency management. Maven, whose primary goal is to allow a developer to understand the complete state of a development process, can be used for building and managing any Java-based project. Maven-bundle-plugin provides a maven plugin that supports creating an OSGi bundle. Maven allows a project to build using its project object model (POM) and a common set of plugins. Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information (resources – directories of the source code, external dependencies, etc) about the project and configuration details used by Maven to build the project. The POM file is named as pom.xml, and is typically located in the root directory of a project. If a project is divided into subprojects, it will typically have one POM file for the parent project, and one POM file for each subproject. This structure allows both building the complete-project in one step or building the subprojects separately [3].

Karaf

Apache Karaf is an OSGi based runtime, which provides a lightweight container, within which various components and applications can be deployed [4]. It is a very flexible and extensible container – allowing the scaling from a very lightweight container to a feature-rich enterprise service.

YANG

Modelling language and YANG Tool are used for generating various compatible interfaces for a model driven plugin. Models are defined in YANG, which when compiled using YANG compiler, produces definitions for various APIs (like RPC, RESTful) applicable for the plugin. Using the templates generated, the logic can be written by developer.

ODL’s existing Projects’ Modules/Bundles and Interfaces

Opendaylight includes list of the modules/bundles, which export a collection of interfaces. Similar to other controller platforms, ODL modules also provide the features such as ability to listen to asynchronous events, parse incoming packets, send openflow messages, etc. The platform provides Java interfaces, which are used by the application for event listening and processing, decision making based on events etc.

Writing an application using the OSGi Interfaces, essentially a plugin in OpenDaylight platform, requires a developer to focus on two broad methodologies – Model Driven or Application Driven. As explained earlier in the previous article, model driven methodology focuses on developing an OpenDaylight plugin through the use of YANG based models for internal and external APIs. Whereas, application driven methodology focuses on development of a standalone service consumer, consuming services produced by basic or domain-specific service plugins.

In OSGi parlance, a bundle is equivalent to a plugin integrated into the OpenDaylight framework. A bundle is collection of Java code, POM files and hierarchy, defining the plugin that can be plugged into the framework as and when required. An OpenDaylight application using OSGi Interfaces is effectively a northbound plugin, developed and embedded into the framework as a bundle. Each plugin essentially defines a list of services, which it provides and consumes. For the list of consumed services, all necessary dependency structure is resolved by OSGi using the definitions in pom.xml file. For all the provided services, OSGi makes a note so as to provide necessary binding if some other module requests these services in future.

For example, a plugin expecting to receive packets from the southbound network layer would convey to OSGi that it would like to consume the services provided by the controller for receiving packets (IListenDataPacket) and parsing it for extracting information (IDataPacketService). These are Java Interfaces which a plugin would have to implement after inheriting the Controller class hierarchy for the SAL to bind the reception of packets as callback to the interface implementation.

Below is an example list of services exposed via different bundles, or plugins, as part of the Controller APIs. A detailed list can be found here [2].

Table 1 – Example services provided by the OpenDaylight Controller

 

Bundle Exported interface
ARP Handler IHostFinder
Host Tracker IfIptoHost
Switch Manager ISwitchManager
Topology Manager ITopologyManager
User Manager IUserManager
Statistics Manager IStatisticsManager
SAL IReadServiceITopologyServiceIFlowProgrammerServiceIDataPacketService

Northbound plugins are generally treated as a consumer to SAL as it consumes the services provide by the Southbound Protocol Plugins. Each of the northbound modules also provides a RESTful API that would allow outside application to use its services.  The implementation of custom RESTful API completely depends on the use cases of the application module. Below we describe these two processes; (a) writing application plugin module with ADSAL (b) writing northbound APIs for the plugin, in detail.

Writing Application Plugin Module in ADSAL

A brief series of high-level steps for developing an ADSAL compliant plugin in OpenDaylight has been shown in below image. The following section drills these steps further to present a deeper understanding of this process.

image2

Figure 2 – The steps to create a plugin in ADSAL

Setup of Development Environment

Development environment for OpenDaylight essentially includes the Java compiler and the Maven build tools. IDE is not mandatory, but certainly recommended to ease the process of building and integrating the plugin with the framework. An elaborate Eclipse based environment setup is available in the Wiki for OpenDaylight [5]. Besides the setup, it is also recommended to get accustomed to the GIT way of managing the code for plugin and pulling in latest repositories for various other plugins. This is also explained well in the wiki pages [6] of OpenDaylight. For example, before developing any plugin using the OSGi interface using Controller provided services, it is recommended to fetch the code for the Controller from its GIT repository so as to reduce the chances of using stale interfaces.

Setup of OSGi Bundle Specifications

Once the development environment is setup, the next step towards creating a plugin is to define a bundle and its specifications which would house the plugin code. Bundle specifications would define which services are required by the plugin, thereby requesting OSGi to load plugins providing those services.

OpenDaylight framework uses the Maven tool for resolving the dependencies between bundles. This is done through use of a POM or Project Object Model file, named as pom.xml. For adding entries into the POM file, some knowledge of naming conventions of other bundles and their services, might be required. This can be found through the OSGi interface documentation available through auto-generated Javadocs for various main stream bundles.

Following image, Figure 3, shows snippet of a pom.xml file, which has a XML Schema. This schema includes details about the complete project, including various packages to import while building and dependencies across the framework. More details about the POM XML Schema can be found at Maven Apache portal.

image3

Figure 3 – A snippet showing pom.xml file

Some key points to remember while creating POM file are:

  • POM is a hierarchical model: A bundle is created in a hierarchy where a parent is defined, which is used for broader specifications of the plugin. For OpenDaylight, the controller’s pom.xml file placed in “<framework root>/controller/opendaylight/commons/opendaylight/” directory is the parent of all bundles willing to integrate with the controller. There are certain rules which the Maven build system would use from the parent including resolving dependency bundle names.
  • Importing and exporting packages: Using the <Import-Package> tag, other bundles which are required for operation of this bundle are imported. Similarly, this bundle can expose itself for being imported by other bundles using <Export-Package> tag.
  • Resolving dependencies: Besides importing the packages to be used, it also required to convey the maven system about various sub-systems from a bundle which are expected to be used by this bundle. For example, an application might intend to use the switch manager for extracting information about switches and their ports. Switch Manager sub-system is part of the controller bundle and for accessing its exposed services; maven is conveyed through dependency tags of pom.xml file.

Initializing Bundle Activator

Besides the pom.xml file, another important file for setting up the environment is the Activator.java file. This file acts as a template for bridging between the framework and the plugin being developed.

imag4 Figure 4 – A snippet showing Activator.java file

Activator file defines various entry points through which control enters the plugin code from the framework. It is essentially a class extending the ComponentActivatorAbstractBase class of the SAL service. By overriding the getImplementations() function, the plugin would be visible to the SAL and it would receive the callbacks against the services subscribed to.

But, before the callbacks are registered, the code needs to configure the callback hooks by overriding the configureInstance() method. For example, for using the data packet services of receiving, parsing and sending packets, the plugin would register callback functions through use of createContainerServiceDependency()→setService() method.

Further, the activator file serves as entry point of control flow into the plugin; the init() method is called when the bundle is loaded and all dependencies have been satisfied by the OSGi engine – this includes loading any module which was not initially loaded. start() method is called after init() has been called and plugin has confirmed about having initialized all necessary information, for example, data structures. Similarly, stop() and destroy() methods are called when bundle has to be removed.

Implementing Plugin Code

Once the environment is setup and the bundle activation is in place, only thing remains is to implement the business logic of the plugin. This would include using the services of other bundles which have been imported by calling their methods or extending their interfaces.

Completing Build using Maven and Inserting bundle into OSGi

Once the code has been completed, maven can be used for compiling the build and inserting the bundle into OSGi platform. Once the bundle has been inserted, it would start receiving callbacks from the platforms for various services it has registered itself for. For example, if a packet analyzer has been created, it would start receiving packets as and when packets are received by the SAL from southbound plugins. Thereafter, the plugin would be responsible for parsing the packets and optionally setup appropriate flow entries using the flow services exposed by controller.

Example AD-SAL application: PortStateExaminer.

Similar to REST-only application, I’m also sharing a reference to an example application developed using AD-SAL methodology. This application, PortStateExaminer, as name suggests simply provides list of all active ports on all the switches that are managed by the ODL-controller.

The application includes a PortStateExaminer service plugin, which uses ISwitchManager service implementation, and implement the IInventoryListener callback and IPortStateExaminerService API. ISwitchManager is used to get the list of active ports for a switch identified by a switchId, whereas IInventoryListener callbacks are implemented to receive Switch and Port notification in the PortStateExaminer plugin.

IPortStateExaminerService API is implemented to use the PortStateExaminer Services from other plugins. The PortStateExaminer service is used to store the list of all active ports, which is populated by the Node notification received from SAL. It also stores the list of active ports Names for the corresponding port Number. IPortStateExaminerService exposes two API (a) public HashMap getSwitch() , which  is used to get list of all the active switches (b) public HashMap getPort(String switchId), which is used to get all the ports for a switch. PSESwitch and PSEPort variables are used to hold information of switches and ports, respectively.

The application can be found here: https://github.com/cosanti/PortStateExaminer

Sridhar received his Ph.D degree in computer science from National University of Singapore, in 2007, his M.Tech. degree in computer science from KREC, Suratkal, India, in 2000, and his B.E. degree in instrumentation and electronics from SIT, Tumkur, Bangalore University, India, in August 1997. He worked as Research lead at SRM Research Institute, India, Post-doctoral fellow at Microsoft Innovation Center, Politecnico Di Torino, Turin, Italy, and as a research fellow at Institute for Infocomm Research (I2R) Singapore. He has worked on various development and deployment projects involving ZigBee, WiFi and WiMax. Sridhar is currently working as Group Technical Specialist with NEC Technologies India Limited. Sridhar’s research interests are mainly in the domain of next-generation wired and wireless networking, such as OpenFlow, software defined networking, software defined radio based systems for cognitive networks, Hotspot 2.0 and the Internet of Things.

Feature image via Flickr Creative Commons.

A newsletter digest of the week’s most important stories & analyses.