Note: This is an outdated tutorial. Please visit this link for the latest tutorial.

This tutorial is intended for developers new to SDN application development with OpenDaylight. We cover AD-SAL, MD-SAL, OSGi and Karaf in this tutorial. Some familiarity with Java and IDEs such as Eclipse will prove useful, though isn’t absolutely necessary. An introductory presentation is available at slideshare.

1. Setup

To get started, download and set up the SDN Hub Tutorial VM in Virtualbox or VMware. The actual source for this tutorial is available at https://github.com/sdnhub/SDNHub_Opendaylight_Tutorial. We encourage you to update the tutorial code on the VM before you start:

$ cd SDNHub_Opendaylight_Tutorial && git pull --rebase

2. Quickstart

  • Boot up our tutorial VM with OpenDaylight already installed. The complete source code for the Hydrogen Release is at /home/ubuntu/opendaylight, and the tutorial application that we will work with is located in /home/ubuntu/SDNHub_OpenDaylight_tutorial directory.
  • If you’re interested in setting up the OpenDaylight installation from scratch, follow the instructions here
  • Let’s now create a simple (virtual) network topology using Mininet and Open vSwitch. In a Terminal window, run the following command, which starts a network emulation environment to emulate 1 switch with 3 hosts, that attempts to connect to a remote controller.
$ sudo mn --topo single,3 --mac --switch ovsk,protocols=OpenFlow13 --controller remote
  • You will now see a mininet terminal. Begin a ping between two of the hosts. The ping fails because there is no intelligence  in the switch to learn the MAC addresses of each host and forward traffic to the correct switch ports
mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
From 10.0.0.1 icmp_seq=2 Destination Host Unreachable
From 10.0.0.1 icmp_seq=3 Destination Host Unreachable
  • Let us now add that intelligence. Open a Terminal tab (Ctrl-Shift-T) and go into the SDNHub_Opendaylight_Tutorial folder and run the following commands to build the example application we will walk through for the tutorial – a Hub / L2 learning switch:
ubuntu@ubuntu:~$ cd SDNHub_Opendaylight_Tutorial
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$ mvn install -nsu

... lots of text ...

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] SDN Hub OpenDaylight tutorial POM ................. SUCCESS [  0.495 s]
[INFO] L2 forwarding tutorial with AD-SAL OpenFlow plugins  SUCCESS [ 11.837 s]
[INFO] L2 forwarding tutorial with MD-SAL OpenFlow plugins  SUCCESS [  4.118 s]
[INFO] OpenDaylight OSGi AD-SAL tutorial Distribution .... SUCCESS [ 32.992 s]
[INFO] OpenDaylight OSGi MD-SAL tutorial Distribution .... SUCCESS [ 43.150 s]
[INFO] tutorial .......................................... SUCCESS [  0.184 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:33 min
[INFO] Finished at: 2014-09-30T09:48:27-08:00
[INFO] Final Memory: 60M/371M
[INFO] ------------------------------------------------------------------------

This indicates that the build went successfully.

  • This command uses Apache Maven to build the tutorial code. “mvn” is the maven command that compiles code based on the pom.xml file in that directory. “clean” is not essential if you do not wish to clean the temporary build files. “install” is essential for compilation.
  • The way Maven works is by resolving dependencies between packages. The tutorial_L2_forwarding package (the hub/switch code we will edit) depends on the Opendaylight controller package, so Maven will download the pre-compiled jar files from Opendaylight.org, resolve dependencies, and so on.
    • Maven has a module name and Java code has a package name. They do not need to match. The module adsal_L2_forwarding has following attributes. The Maven group-id and artifact-id are used for the name of the Jar file generated, while package name is only recognized within the source code.
      • pom.xml group-id: org.sdnhub.odl.tutorial”
      • pom.xml artifact-id: adsal_L2_forwarding
      • Source code package name: org.opendaylight.tutorial.tutorial_L2_forwarding
    • Creating your own installation in this manner is much, much faster than compiling the tutorial code within the full source of the Opendaylight controller. This can be compared with compiling an application instead of compiling the full operating system.
    • Note: to speed up subsequent compilations, you can run “mvn install -DskipTests -DskipIT -nsu”. The “nsu” is short for no-snapshot-updates. It ensures that the compilation does not download definitions from nexus.opendaylight.org
  • Next, let’s run the controller itself; preferably in a different terminal
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$ cd distribution/opendaylight-osgi-adsal/target/distribution-osgi-adsal-1.1.0-SNAPSHOT-osgipackage/opendaylight
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-osgi-adsal/target/distribution-osgi-adsal-1.1.0-SNAPSHOT-osgipackage/opendaylight$ ./run.sh
  • The above command starts all the OSGi bundles installed as jar files in the plugins directory. Once all bundles are started, you will be able to check the status of bundles using the “ss” command
osgi> ss tutorial
"Framework is launched."
id    State       Bundle
36    ACTIVE      org.sdnhub.odl.tutorial.adsal_L2_forwarding-0.5.0-SNAPSHOT

In the above OSGi output, the word “ACTIVE” means the module/bundle is running, while “RESOLVED” would mean that it has been stopped, either explicitly by other modules or implicitly through a missing dependent module.

  • Since OpenDaylight today does not have a way to specif which modules get precedence over other modules, we require that any conflict modules (such as SimpleForwarding and ARPHandler) be stopped using the “stop” OSGi command. This way, all packet forwarding decisions will be left to the tutorial applications.
    • Note: To make it easier, the adsal_L2_forwarding package has some code in its init() to automatically “uninstall” these conflicting modules.
  • After the controller finishes loading, you should be able to see the list of switches connected using the command “printnodes”. In our environment, we have 1 OpenFlow switch connected with Datapath-id “00:00:00:00:00:00:00:01″.
osgi> printnodes
Nodes connected to this controller :
[OF|00:00:00:00:00:00:00:01]
  • Now when you go back to the mininet terminal, you will  see that the pings succeed
From 10.0.0.1 icmp_seq=17 Destination Host Unreachable
From 10.0.0.1 icmp_seq=18 Destination Host Unreachable
64 bytes from 10.0.0.2: icmp_req=19 ttl=64 time=94.1 ms
64 bytes from 10.0.0.2: icmp_req=20 ttl=64 time=21.2 ms
64 bytes from 10.0.0.2: icmp_req=21 ttl=64 time=21.9 ms
  • You will have noticed that the pings are actually taking longer than they should for a learning switch (sub-1ms) for such a simple topology. This is because the controller is currently functioning in “Hub” mode.
  • Let’s do a small trick to start appreciating OSGi. While the controller is running, open a new terminal, and edit TutorialL2Forwarding.java to change the function variable from “hub” to “switch”. This can be done as follows:
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$ sed -i -e "s/function = \"hub\"/function = \"switch\"/g" `find . -name TutorialL2Forwarding.java`
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$ cd adsal_L2_forwarding
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial/adsal_L2_forwarding$ mvn install -DskipTests -DskipIT -nsu
  • This will recompile the change you made and generate new Jar files that will be placed in the appropriate location so that OSGi will be able to pick up the changes at run-time. On the OSGi console, you will see the automatic reloading of the bundle:
2014-03-13 13:35:23.001 MDT [fileinstall-./plugins] INFO  o.o.t.t.i.TutorialL2Forwarding - Stopped
2014-03-13 13:35:23.086 MDT [fileinstall-./plugins] INFO  o.o.t.t.i.TutorialL2Forwarding - Initialized
2014-03-13 13:35:23.097 MDT [fileinstall-./plugins] INFO  o.o.t.t.i.TutorialL2Forwarding - Started
  • If everything went right, you will also see the ping RTT times drop to sub-millisecond.

In the next few sections, we will walk through how we can turn the hub into a switch.

3. Introduction to OpenDaylight

Before we jump into the code, a high-level overview of the OpenDaylight controller is in order. OpenDaylight is a modular platform with most modules reusing some common services and interfaces. Each module is developed under a multi-vendor sub-project. You can find the list of projects here.
opendaylight_helium

OpenDayLight uses the following software tools/paradigms. It is important to become familiar with them. The Service Abstraction Layer (SAL) is your friend for most development aspects.

  • Java interfaces: Java Interfaces are used for event listening, specifications and forming patterns. This is the main way in which specific bundles implement call-back functions for events and also to indicate awareness of specific state.
  • Maven: OpenDayLight uses Maven for easier build automation. Maven uses pom.xml (Project Object Model for this bundle) to script the dependencies between bundles and also to describe what bundles to load on start.
  • OSGi: This framework in the backend of OpenDayLight allows dynamically loading bundles and packaged Jar files, and binding bundles together for information exchange.
  • Karaf: Karaf is a small OSGi based runtime which provides a lightweight container for loading different modules.

The controller project offers certain core bundles, each of which export important services through Java interfaces. Here is a brief list of important ones that come in handy while developing network services. See this link for more information.

Bundle Exported interface Description
arphandler IHostFinder Component responsible for learning about host location by handling ARP.
hosttracker IfIptoHost Track the location of the host relatively to the SDN network.
switchmanager ISwitchManager Component holding the inventory information for all the known nodes (i.e., switches) in the controller.
topologymanager ITopologyManager Component holding the whole network graph.
usermanager IUserManager Component taking care of user management.
statisticsmanager IStatisticsManager Component in charge of using the SAL ReadService to collect several statistics from the SDN network.
sal IReadService Interface for retrieving the network node’s flow/port/queue hardware view
sal ITopologyService Topology methods provided by SAL toward the applications
sal IFlowProgrammerService Interface for installing/modifying/removing flows on a network node
sal IDataPacketService Data Packet Services SAL provides to the applications
web IDaylightWeb Component tracking the several pieces of the UI depending on bundles installed on the system.

4. Basic steps to writing an OpenDayLight Application

For beginners, we recommend using Eclipse for viewing and editing the source code, and command-line for compiling and running the controller. Open Eclipse using the desktop shortcut.

We have already setup the Eclipse environment for you. But, if you wish to do it from scratch, you should follow these instructions to setup Maven-Eclipse integration. After that you can and go to File->Import. Choose ‘Maven > Existing Maven Projects’. On the next screen, choose as the Root Directory ~/ubuntu/SDNHub_Opendaylight_Tutorial. Select ‘adsal_L2_forwarding’ and ‘mdsal_L2_forwarding’ pom.xml that it finds, click on ‘Add project(s) to working set’ below, and click ‘Finish’.

Once Eclipse is setup, you should now see ‘adsal_L2_forwarding’ and ‘mdsal_L2_forwarding’ on your Project explorer pane. Double-click on one of the two and src/main/java > org.opendaylight.tutorial.tutorial_L2_forwarding > and walk-through through the code.

Most controller platforms expose some native features to allow these key features:

  1. Ability to listen to asynchronous events (e.g., PACKET_IN, FLOW_REMOVED) and to register call back functions (e.g., receiveDataPacket)
  2. Ability to parse incoming packets (e.g., ARP, ICMP, TCP) and fabricate packets to send out into the network
  3. Ability to create and send an OpenFlow/SDN message (e.g., PACKET_OUT, FLOW_MOD, STATS_REQUEST) to the programmable dataplane.
  4. Managing decision making modules on the same controller

With OpenDayLight you can achieve all of those using a combination of SAL implementation classes and listener interfaces.

Now is a good point in the tutorial to mention that there are two types of SAL:

  1. API-driven SAL (AD-SAL), where the API is statically defined at compile/build time, and the “provider” and “consumer” of events/data are directly plumbed to each other in code.
  2. Model-driven (MD-SAL), where the API code is generated from models during compile time and loaded into the controller when the plugin OSGI bundle is loaded into the controller. All event calls and data go from “provider” to a “consumer” through a central datastore with MD-SAL.

The app development is different based on which type of SAL you’re building it with. Each type of SAL has different tradeoffs like ease of use, scalability, debuggability, and feature set. Once you get the hang of both, you can choose which is best for you. It may be that you use both in an application you build. In this tutorial, we will have a look at both types. If you’re more interested in the MD-SAL approach, you can jump directly there.

5. Writing an AD-SAL OpenDayLight Application

5.1. Theory

A. Receiving events

There are listener interfaces for several types of events including events thrown by modules like TopologyManager. For instance, to allow a module to receive packets sent by the switch to the controller, the class needs to implement IListenDataPacket:

public class TutorialL2Forwarding implements IListenDataPacket

When the class implements that IListenDataPacket interface, any packet that arrives at a node without a pre-cached rule will result in a callback of receiveDataPacket. So overriding that method allows the application to get a copy of the packet.

public PacketResult receiveDataPacket(RawPacket inPkt) { ... }

One other feature that was useful was generating the list of ports in a node/switch. Assuming incoming_node is the switch whose ports I want to list, I use the SwitchManager class as follows:

Set<NodeConnector> nodeConnectors =
this.switchManager.getUpNodeConnectors(incoming_node);

B. Parsing packets

Once the packet is received, you can decode the packet using the dataPacketService. Usage of command is shown below. Today, according to the org.opendaylight.controller.sal.packet package, we can inspect the packet headers the following packet types: ARP, Ethernet, ICMP, IPv4, LLDP, TCP, UDP.

Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);

Along with the packet header fields, you can extract the incoming node (i.e., switch) and node-connector (i.e., switchport) using the following:

NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();

We use the following two useful commands to extract header details to use in the MAC learning switch:

byte[] srcMAC = ((Ethernet)formattedPak).getSourceMACAddress();
long srcMAC_val = BitBufferHelper.toNumber(srcMAC);

C. Sending messages to switch

Once the decisions are taken and the controller decides that a packet needs to be forwarded, I can use the dataPacketService to send a packet out of a node-connector (switchport). In the following example, we resend the incoming packet out of node-connector ‘p’:

RawPacket destPkt = new RawPacket(inPkt);
destPkt.setOutgoingNodeConnector(p);
this.dataPacketService.transmitDataPacket(destPkt);

Besides a PACKET_OUT, we can also perform a FLOW_MOD style rule insertion into a switch. For that, we use the Match, Action and Flow classes. Here is an example of how to create a match rule where the IN_PORT matches the value extracted from the PACKET_IN:

Match match = new Match();
match.setField(MatchType.IN_PORT, incoming_connector);

There are several other fields you can match one. Following are what I see in the org.opendaylight.controller.sal.match: “inPort”, “dlSrc”, “dlDst”, “dlVlan”, “dlVlanPriority”, “dlOuterVlan”, “dlOuterVlanPriority”, “dlType”, “nwTOS”, “nwProto”, “nwSrc”, “nwDst”, “tpSrc”, “tpDst”.

In the package org.opendaylight.controller.sal.action, I see the following supported actions: “drop”, “loopback”, “flood”, “floodAll”, “controller”, “interface”, “software path”, “harware path”, “output”, “enqueue”, “setDlSrc”, “setDlDst”, “setVlan”, “setVlanPcp”, “setVlanCif”, “stripVlan”, “pushVlan”, “setDlType”, “setNwSrc”, “setNwDst”, “setNwTos”, “setTpSrc”, “setTpDst”, “setNextHop”. Here is an example of creating an action list for the flow rule, for OUTPUT to anoutgoing_connector that is pre-calculated.

List<Action> actions = new ArrayList<Action>();
actions.add(new Output(outgoing_connector));

Once the match rule is formed and action list is created, we can create a Flow and add it to a particular switch. In this case, the rule is inserted to the switch where the original packet arrived:

Flow f = new Flow(match, actions);
Status status = programmer.addFlow(incoming_node, f);
if (status.isSuccess())
    logger.trace("Installed flow {} in node {}", f, incoming_node);
else 
    //What to do in case of flow insertion failure?

D. Managing multiple modules

As highlighted in the Quick-start, it is possible that there are multiple modules contesting for the same events and want to act upon it. OpenDaylight today does not provide a precedence order among modules. This requires some coordination among modules to ensure there is no conflict.

Given that, it is possible for a module to signal to the platform when it has finished processing a packet. Once the packet is appropriately handled, the controller application has 3 choices on returning status back to the SAL. It can be

  • return PacketResult.CONSUME: Packet has been processed and none in the chain after us should handle it
  • return PacketResult.KEEP_PROCESSING: Packet has been processed, but still pass onto other bundles
  • return PacketResult.IGNORED: Packet has been ignored and ready to pass to other bundles

Now that you’re updated on the theory, you are now ready to create a new module.

5.2. Sample AD-SAL application: Learning Switch

For the purposes of this tutorial, you should attempt to convert the hub application to a MAC learning switch by writing code from scratch, using the above code snippets. The main logic for hub and learning switch are available here.

We provide a skeleton file to write your own code. Overwrite that TutorialL2Forwarding.skeleton file over the current TutorialL2Forwarding as follows:

ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$ cd adsal_L2_forwarding/src/\
main/java/org/opendaylight/tutorial/tutorial_L2_forwarding/internal && cp TutorialL2Forwarding.skeleton TutorialL2Forwarding.java

Modify the implementation of the application by editing this new TutorialL2Forwarding.java. We have provided you hints through Java comments.

Once you make the necessary changes, successfully compile and run, you will see that mininet ping succeeds (Note: RTT time is less than 1ms once flow rules are inserted, unlike the hub case):

mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
From 10.0.0.1 icmp_seq=2 Destination Host Unreachable
From 10.0.0.1 icmp_seq=3 Destination Host Unreachable
From 10.0.0.1 icmp_seq=4 Destination Host Unreachable
64 bytes from 10.0.0.2: icmp_req=5 ttl=64 time=0.529 ms
64 bytes from 10.0.0.2: icmp_req=6 ttl=64 time=0.133 ms
64 bytes from 10.0.0.2: icmp_req=7 ttl=64 time=0.047 ms

The OSGi console shows the following sample log:

2013-06-13 21:00:31.844 PDT [SwitchEvent Thread] INFO o.o.t.t.i.TutorialL2Forwarding 
- Installed flow Flow[match = Match[[DL_DST(00:00:00:00:00:01,null),
IN_PORT(OF|2@OF|00:00:00:00:00:00:00:01,null)]], 
actions = [OUTPUT[OF|1@OF|00:00:00:00:00:00:00:01]], priority = 0, id = 0,
idleTimeout = 0, hardTimeout = 0] in node OF|00:00:00:00:00:00:00:01

Solutions

In the tutorial_L2_forwarding/internal directory, you will see three solutions files:

  • TutorialL2Forwarding_singleswitch.solution: L2 MAC Learning switch that pushes flow_mod rules to the switch based on the packet_in. It only tracks MAC for a single switch.
  • TutorialL2Forwarding_multiswitch.solution: L2 MAC Learning switch that pushes flow_mod rules to the switch based on the packet_in. It tracks MAC for multiple switches independently.
  • TutorialL2Forwarding_statelesslb.solution: Stateless load-balancer code where you can statically set the list of servers and their IP addresses. When traffic arrives for the virtual IP of the load-balancer, it selects the server in a round-robin basis and sends request to a different server after doing IP header rewriting in both directions.

5.3. Workflow, dependencies and information sharing

Maven and OSGI

  • pom.xml: Generally the pom.xml is used to indicate the inter-bundle dependencies. The syntax for that must be fairly apparent from the format of the pom.xml in the arphandler directory
  • Activator.java: This handles the configuration of the dependencies during run-time. The configureInstance function in the bottom of Activator.java of each bundle has two main tasks:
    1. tells the list of Java interfaces implemented by a bundle ‘X’ using setInterface call
    2. registers other bundles that the bundle ‘X’ uses using add call
  • set/unset binding: The bundle ‘X’ gets a reference to the instantiated object of other needed bundle ‘Y’ through the setY and unsetY calls in the main class. For example, TutorialL2Forwarding needs data from SwitchManager. This is accomplished by defining two methods setSwitchManager and unsetSwitchManager. These are called by OSGi and object references are appropriately passed.

ODL_Life_of_a_packet

Life of a packet

In OpenDaylight, the SAL is in charge of all plumbing between the applications and the underlying plugins. Here is an illustration of the life of a packet.

  1. A packet arriving at Switch1 will be sent to the appropriate plugin managing the switch
  2. The plugin will parse the packet, generate an event for SAL
  3. SAL will dispatch the packet to the modules listening for DataPacket
  4. Module handles packet and sends packet_out through IDataPacketService
  5. SAL dispatches the packet to the modules listening for DataPacket
  6. OpenFlow message sent to appropriate switch

5.4. AD-SAL OpenDaylight Web UI

One of the advantages with using OpenDaylight as your controller platform is that it offers hooks for providing a Web UI with many pre-existing features. The GUI can also be extended for user-defined applications. To access the GUI, point your browser at http://localhot:8080 and you should be able to see the login page.

  • Login with username “admin” and password “admin”

You can see the different tabs on top that offer different features. Each feature has a “web” module (for rendering the web page), a “northbound” module (for providing web API for the web module to call), and a backend module that does all the relevant functionality in the state management. For instance, here are the bundles loaded for rending the topology in the UI:

osgi> ss topology
"Framework is launched."

id      State       Bundle
81      ACTIVE      org.opendaylight.controller.topology.northbound_0.4.2.SNAPSHOT
98      ACTIVE      org.opendaylight.controller.topology.web_0.4.2.SNAPSHOT
181     ACTIVE      org.opendaylight.controller.topologymanager_0.4.2.SNAPSHOT

The TopologyManager module tracks the topology of the underlying network, while the “web” and “northbound” modules are responsible for the UI portion.

6. Writing an MD-SAL OpenDayLight Application

In the environment, we included have the sample learning-switch tutorial application that uses the MD-SAL OpenFlow 1.3 plugin. Here is how you can start that application, after stopping the AD-SAL controller application. We use the maven option “pl” to restrict building only the MD-SAL relevant packages:

ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$  mvn install -pl distribution/opendaylight-osgi-mdsal --also-make -DskipTests -DskipIT -nsu
 ....
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] SDN Hub OpenDaylight tutorial POM ................. SUCCESS [  0.157 s]
[INFO] L2 forwarding tutorial with MD-SAL OpenFlow plugins  SUCCESS [  3.965 s]
[INFO] OpenDaylight OSGi MD-SAL tutorial Distribution .... SUCCESS [ 32.674 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$ cd distribution/opendaylight-osgi-mdsal/target/distribution-osgi-mdsal-1.1.0-SNAPSHOT-osgipackage/opendaylight
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-osgi-mdsal/target/distribution-osgi-mdsal-1.1.0-SNAPSHOT-osgipackage/opendaylight$ ./run.sh

After the controller is started, you can use RestConf API to access all the details in the data store. The information is routed over HTTP and is based on the Yang models for that particular information. For instance, you can query the list of nodes and the details stored for them in the data store by accessing: http://localhost:8080/restconf/operational/opendaylight-inventory:nodes/. You will see data as follows.odl-restconf-inventory-nodes

odl-mdsal-apidocs-explorerTo get list of all APIs exported over RestConf, you can use the API explorer and seeing the list of API by acccessing http://localhost:8080/apidoc/explorer/. Here is an example of list of API.

We encourage you to play with this data access and possibly create new flows through this REST interface. Once you create a new flow, you can see it in the Open vSwitch table using the command:

$ sudo ovs-ofctl dump-flows s1 -O OpenFlow13
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x0, duration=35.255s, table=0, n_packets=22, n_bytes=1668, priority=0 actions=CONTROLLER:65535
 cookie=0x2a00000000000000, duration=35.248s, table=0, n_packets=36, n_bytes=3416, priority=512,dl_src=00:00:00:00:00:02,dl_dst=00:00:00:00:00:01 actions=output:2
 cookie=0x2a00000000000001, duration=35.247s, table=0, n_packets=35, n_bytes=3374, priority=512,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02 actions=output:1

7. Karaf

Considering all future releases of OpenDaylight will be made available as a Karaf-based distribution, it is good to understand how to use Karaf. As mentioned before it is an OSGi-based runtime. This brings all the goodness of OSGi, like hot deployment of modules, and the Karaf-specific features like the ability to prescribe a streamlined set of bundles to load for an application.

opendaylight-tutorial-karaf-adsal
In the SDNHub_OpenDaylight_tutorial project, we also have the Karaf configurations to allow you to experiment with Karaf. Here are two main configurations we had to make:

  1. feature files: There are two folders ‘features-tutorial/adsal’ and ‘features-tutorial/mdsal’ that defines two features ‘sdnhub-tutorial-adsal’ and ‘sdnhub-tutorial-mdsal’ in the respective pom.xml, as well as describes the exact version and set of bundles that are needed by each feature in ‘src/main/resources/features.xml’ file.
  2. distribution POM: The directory SDNHub_OpenDaylight_tutorial/opendaylight/distribution-karaf is specifically crafted to generate the Karaf-based distribution that includes both sample applications.

For instance, the figure on the right shows how the Karaf dependency chart looks like for the feature ‘sdnhub-tutorial-adsal’. The green box represents bundles and the blue box represents Karaf features.

After compiling all features and the Karaf distribution, you can run Karaf as follows:

ubuntu@sdnhubvm:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-karaf$ cd target
ubuntu@sdnhubvm:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-karaf/target$ tar xvfz distribution-karaf-0.5.0-SNAPSHOT.tar.gz
ubuntu@sdnhubvm:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-karaf/target$ cd distribution-karaf-0.5.0-SNAPSHOT
ubuntu@sdnhubvm:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-karaf/target/distribution-karaf-0.5.0-SNAPSHOT$ ./bin/karaf 
karaf: JAVA_HOME not set; results may vary
                                                                                           
    ________                       ________                .__  .__       .__     __       
    \_____  \ ______   ____   ____ \______ \ _____  ___.__.|  | |__| ____ |  |___/  |_     
     /   |   \\____ \_/ __ \ /    \ |    |  \\__  \<   |  ||  | |  |/ ___\|  |  \   __\    
    /    |    \  |_> >  ___/|   |  \|    `   \/ __ \\___  ||  |_|  / /_/  >   Y  \  |      
    \_______  /   __/ \___  >___|  /_______  (____  / ____||____/__\___  /|___|  /__|      
            \/|__|        \/     \/        \/     \/\/            /_____/      \/          
                                                                                           

Hit '' for a list of available commands
and '[cmd] --help' for help on a specific command.
Hit '' or type 'system:shutdown' or 'logout' to shutdown OpenDaylight.

opendaylight-user@root>feature:install sdnhub-tutorial-adsal
Refreshing bundles org.apache.aries.util (13)
GossipRouter started at Tue Sep 30 22:39:51 PDT 2014
Listening on port 12001 bound on address 0.0.0.0/0.0.0.0
Backlog is 1000, linger timeout is 2000, and read timeout is 0
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [bundleresource://126.fwk126488680:1/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [bundleresource://126.fwk126488680:2/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [bundleresource://126.fwk126488680:3/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.JDK14LoggerFactory]
opendaylight-user@root>bundle:list -s | grep sdnhub
230 | Active   |  80 | 0.5.0.SNAPSHOT          | org.sdnhub.odl.tutorial.adsal_L2_forwarding                        
231 | Active   |  80 | 0.1.0.SNAPSHOT          | org.sdnhub.odl.ofbroker                                            
232 | Active   |  80 | 0.1.0.SNAPSHOT          | org.sdnhub.odl.protocol_plugins.openflow10                         
233 | Active   |  80 | 0.1.0.SNAPSHOT          | org.sdnhub.odl.protocol_plugins.openflow13                         
opendaylight-user@root>feature:uninstall sdnhub-tutorial-adsal
opendaylight-user@root>bundle:list -s | grep sdnhub
opendaylight-user@root>feature:install sdnhub-tutorial-mdsal
Refreshing bundles osgi.cmpn (75), org.ops4j.pax.web.pax-web-api (110), org.apache.xbean.finder-shaded (109), org.ops4j.pax.web.pax-web-runtime (112), org.apache.xbean.bundleutils (106), org.ops4j.pax.web.pax-web-spi (111), org.apache.aries.util (13), javax.persistence (90)
opendaylight-user@root>bundle:list -s | grep sdnhub
329 | Active |  80 | 0.1.0.SNAPSHOT          | org.sdnhub.odl.tutorial.mdsal_L2_forwarding
opendaylight-user@root>feature:list | grep sdnhub
sdnhub-tutorial-mdsal                 | 1.0.0-SNAPSHOT      | x         | tutorial-mdsal-1.0.0-SNAPSHOT          | SDN Hub Tutorial :: OpenDaylight :: MD-SAL
sdnhub-tutorial-adsal                 | 1.0.0-SNAPSHOT      |           | tutorial-adsal-1.0.0-SNAPSHOT          | SDN Hub Tutorial :: OpenDaylight :: AD-SAL

opendaylight-user@root>feature:install odl-restconf-all
opendaylight-user@root>feature:install odl-mdsal-apidocs
opendaylight-user@root>^D (to quit)
ubuntu@sdnhubvm:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-karaf/target/distribution-karaf-0.5.0-SNAPSHOT$ rm -rf data
  • In the above output, “x” means the feature is loaded.
  • In the Karaf shell, you can get a list of all the bundles and features, as well as check on what interfaces are imported or exported (by using commands “imports” and “exports”).
  • If you had mininet running, you will notice that the ping will succeed after the “feature:install” is performed for either of the two features.
  • With Karaf, the RESTConf and REST API doc explorer are available on TCP port 8181 (not 8080). For instance see http://localhost:8181/restconf/operational/opendaylight-inventory:nodes and http://localhost:8181/apidoc/explorer/.
  • As a last step, we delete the “data” directory to clear all the cache and configs from the earlier run. This is good practice in a dev environment.

8. Debugging

Debugging is an important part of app development. Once you get the Eclipse environment fine-tuned to an advanced level, you will be able to Run and Debug within that IDE. In the meantime, we suggest another route through the maven-eclipse integration. We illustrate the debugging with AD-SAL app, but the concepts are same for the MD-SAL app too.

To debug your code, you need to start OpenDaylight including the parameter “-debug”:

ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial$ cd distribution/opendaylight-osgi-adsal/target/distribution-osgi-adsal-1.1.0-SNAPSHOT-osgipackage/opendaylight
ubuntu@ubuntu:~/SDNHub_Opendaylight_Tutorial/distribution/opendaylight-osgi-adsal/target/distribution-osgi-adsal-1.1.0-SNAPSHOT-osgipackage/opendaylight$ ./run.sh -debug

“-debug” will allow us to connect to OSGI (listening at port 8000) for debugging purposes.

The first step to starting the debugger is to click “Connect to ODL” as shown below. This will allow you to debug your code using all the Eclipse benefits.

opendaylight_connect_debug

If everything works fine, you should be able to see the Debug tab:
opendaylight_debug_tab