Jump to: navigation, search

OpenDaylight Controller:MD-SAL:Southbound Plugin Development Guide

Note: This document is work in progress, parts of it may be changed, because it depends on API contracts, which are to be frozen by M4 Milestone

Southbound controller plugin is a functional component that does the following:

  • Provides an abstraction of network devices functionality
  • Normalizes their APIs to common contracts
  • Handles session and connections to them.

In general, the development process consists of following steps:

1. Definition of YANG models (API contracts): For Model-Driven SAL, the API contracts are defined by YANG models and the Java interfaces generated for these models. In this phase, developers select existing models which they want, write own models or augment (extend) existing ones.

2. Code Generation: Java Interfaces, implementation of Transfer Objects and mapping to Binding-Independent form is generated for the plugin. This phase requires the proper configuration of the Maven build and YANG Maven Tools.

3. Implementation of plugin: The actual implementation of the plugin functionality and the plugin components.

The order of the steps is not definitive, and it is up to developers to find the workflow which suits them best. See also, Best Practices for additional information.

Definition of YANG models

In this step, the developers select existing models, write their own models, or augment existing ones, which are provided by the controller or other plugins. The partial list of available models is available at YANG Tools:Available Models.

The mapping of YANG to Java is documented at Yang Tools:YANG to Java Mapping. This mapping provides an overview of how YANG is mapped to Java.

In general, there are multiple approaches to model the functionality of the Southbound Plugin:

  1. Using RPCs and Notifications
  2. Using Configuration Data Description
  3. Using Runtime Data Description
  4. Using a combination approach

RPCs

RPCs are used to model functionality which could be invoked by consumers (applications) and which uses the Southbound Plugin. RPCs are suitable to model any functionality. However, RPCs are usually used to model functionality which cannot be abstracted as configuration data, such as PacketOut, initiating a new session to device (controller-to-device session), or others.

RPCs are modeled with an RPC statement in the following form:

  rpc foo {}

This statement is mapped to method.

RPC Input

To define the RPC input, use the input statement within RPC. The structure of the input is defined with the same statements as the structure of notifications, configuration and so on.

 rpc foo {
    input {
       ...
    }
 }

RPC Output

To define the RPC output (structure of result), use the RPC output statement.

 rpc foo {
   output {
      ...
   }
 }

Notifications

Notifications are used to model events originating in network devices or southbound plugins which are exposed to consumers for listening.

Notification is defined with the notification statement:

   notification foo {
      ...
   }

Configuration Data

Configuration data is good for the following:

  • Model or provide CRUD access to the state of protocol plugin and network devices, or to either
  • Model any functionality which could be exposed as a configuration to consumers or applications

Configuration data in YANG is defined by using a config substatement with the true argument. For example:

  container foo {
     config true;
     ...
  }
  

Runtime (read-only) Data

Runtime (read-only) data is good to model or provide read access to the state of protocol plugin and networtk devices, or either. This type of data is good to model statistics or any state data, which could not be modified by the consumers (applications), but needs to be exposed (For example, learned topology, list of connected switches).

Runtime data in YANG is defined by using a config subsatement with the false argument:

  container foo {
     config false;
  }

Structural Elements

The structure of RPCs, notifications, configuration data and runtime data is modeled using structural elements (data schema nodes) which define the actual structure of XML, DataDOM documents, and Java APIs for accessing or storing these elements. The most commonly used elements are:

  • container
  • list
  • leaf
  • leaf-list
  • choice

Augmentations

Augmentations are used to extend existing models by providing additional structural elements and semantics from different models. Augmentation cannot change the mandatory status of nodes in the original model, or introduce any new mandatory statements.

Best Practices

  • YANG models must be located under src/main/yang folder in your project.
  • Design your models to be reusable and extendable by third-parties.
  • Always try to reuse existing models and types provided by these models. See YANG Tools:Available Models or others if there is no model that provides the data structures and types you need.

Code Generation

To configure a project for code generation, the build system currently requires Maven. To configure Java API generation, see Yang Tools:Maven Plugin Guide.

The following artifacts are generated at compile time:

  • Service interfaces
  • Transfer Object interfaces
  • Builders for Transfer Objects and immutable versions of transfer objects

Implementation

In this step, the developer implements the intended functionality of the southbound plugin using generated artifacts.

Provider implementation

To expose functionality via binding-awareness, the MD-SAL plugin needs to be compiled against these APIs and at least implement the BindingAwareProvider interface.

The provider uses an APIs which is avaible in the sal-binding-api Maven artifact. To use these dependencies, insert the following dependency into your pom.xml:

   <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-binding-api</artifactId>
       <version>1.0-SNAPSHOT</version>
   </dependency>

BindingAwareProvider Implementation

The BindingAwareProvider interface requires the implementing of four methods; registering an instance with BindingAwareBroker; and using AbstractBindingAwareProvider to simplify the implementation of this.

  • void onSessionInitialized(ConsumerContext ctx): This callback is called when the Binding-Aware Provider is initialized and the ConsumerContext is injected into it. ConsumerContext serves to access all functionality which the plugin consumes from other controller components.
  • void onSessionInitialized(ProviderContext ctx): This callback is called when the Binding-Aware Provider is initialized and ProviderContext is injected into it. ProviderContext serves to access all functionality which the plugin uses to provide its funcitonality to the controller components.
  • Collection<? extends RpcService> getImplementations(): The shorthand registration of already instantiated implementations of global RPC services. Automated registration is currently not supported.
  • public Collection<? extends ProviderFunctionality> getFunctionality(): The shorthand registration of already instatiated implementations of ProviderFunctionality. Automated registration is currently not supported.

Note: Set the implementation of the AbstractBindingAwareProvider set as Bundle Activator so that it is properly loaded by MD-SAL.

Notifications

To publish events, request an instance of NotificationProviderService from ProviderContext. Use the following:

   ExampleNotification notification = (new ExampleNotificationBuilder()).build();
   NotificationProviderService notificationProvider = providerContext.getSALService(NotificationProviderService.class);
   notificationProvider.notify(notification);

RPC Implementations

To implement the functionality exposed as RPCs, implement the generated RpcService interface and register that implementation (within ProviderContext) that was injected into the provider.

Consider that the generated RpcInterface is FooService and the implementation is FooServiceImpl:

   @Override
   public void onSessionInitiated(ProviderContext context) {
       context.addRpcImplementation(FooService.class, new FooServiceImpl());
   }

Best Practices

  • The RPC Service interface contract requires you to return Future object (to make it obvious that the call may be asynchronous), but it is not specified as to how this Future is implemented. Consider using the existing implementations provided by JDK or Google Guava.

Implement your own Future only if necessary.

  • Do not implement transfer object interfaces unless necessary. Instead, use the already generated builders and immutable versions. If you decide to implement transfer objects, ensure that instances exposed outside plugin are immutable.

Recommended Third-party Libraries for Implementation

SLF4J

SLF4J API documentation

Recommended best practices for using logging in OpenDaylight code

TBD: Usage notes for SLF4J

Google Guava

Google Guava 18 API documentation for Lithium release

Google Guava 14 API documentation for Hydrogen and Helium releases

TBD: Usage notes and pointers to useful classes from Google Guava

Netty.io

Netty 4.0 API documentation

TBD: Usage notes and pointers to useful classes from Netty.io 4