Introducing SDN-MQ: A Powerful and Simple-to-Use Northbound Interface for OpenDaylight

One of the essential parts of an SDN controller is the so-called northbound interface through which network control applications implementing control logic interface with the SDN controller. The SDN controller then uses the OpenFlow protocol to program the switches according to the instructions of the control application. Since the northbound interface is the “API to the network”, a well-designed interface is essential for the acceptance and success of the SDN controller.

Ideally, the northbound interface should be powerful and still simple. Powerful means that it should expose all essential functionalities of OpenFlow to the control application. Certainly, the most essential function of SDN is flow programming to define forwarding table entries on the switches. Flow programming should include pro-active flow-programming, where the control application proactively decides to program a flow (e.g., a static flow), on the one hand. On the other hand, the northbound interface should support reactive flow programming where the control application reacts to packet-in events triggered by packets without matching forwarding table entries.

Simple means that the programmer should be able to use technologies that he is familiar with. So in short, the ideal northound interface should be as simple as possible, but not simpler.

Current Northbound Interfaces and Observed Limitations

OpenDaylight currently offers two kinds of northbound interfaces:

  1. RESTful interfaces using XML/JSON over HTTP.
  2. OSGi allowing for implementing control logic as OSGi services.

RESTful interfaces are simple to use since they are based on technologies that many programmers are familiar with and that are used in many web services. Parsing and creating JSON or XML messages and sending or receiving these messages over HTTP is straightforward and well-supported by many libraries. However, due to the request/response nature of REST and HTTP, these interfaces are restricted to proactive flow programming. The very essential feature of reacting to packet-in events is missing.

OSGi interfaces are powerful. Control applications can use any feature of the OpenFlow standard (implemented by the controller). However, they are much more complex than RESTful interfaces since OSGi itself is a complex technology. Moreover, OSGi is targeted at Java, which is nice for integrating it with the Java-based OpenDaylight controller, but bad if you want to use any other language to implement your control logic like C++ or Python.

So none of these interface seems to be simple and powerful at the same time.

How SDN can Benefit from Message-oriented Middleware

So how can we have the best of both worlds: a simple and powerful interface? The keyword (or maybe at least one possible keyword) is message-oriented middleware. As shown in the following figure, a message-oriented middleware (MOM) decouples the SDN controller from the control application through message queues for request/response interaction (proactive flow programming) and publish/subscribe topics for event-based interaction (reactive flow programming). So we can program flows through a request-response interface implemented by message queues and react to packet-in events by subscribing to events through message topics.

mom

Moreover, messages can be based on simple textual formats like XML or JSON making message creation and interpretation as simple as for the RESTful interfaces mentioned above, however, without their restriction to request/response interaction.

Since a MOM decouples the SDN controller from the control application, the control logic can be implemented in any programming language. SDN controller and application talk to each other using JSON/XML, and the MOM takes care to transport messages from application to SDN controller and vice versa.

This decoupling also allows for the horizontal distribution of control logic by running control applications on several hosts. Such a decoupling “in space” is perfect for scaling out horizontally.

MOMs not only decouple the controller and control application in space but also in time. So the receiver does not need to consume the message at the time when it is sent. Messages can be buffered by the MOM and delivered when the control application or SDN controller are available and ready to process it. Although being a nice feature in general, time decoupling might not be strictly essential for SDN since usually we want a timely reaction of both controller and application. Still, it might be handy for some delay tolerant functions.

SDN-MQ: Integrating Message-oriented Middleware and SDN Controller

SDN-MQ integrates a message-oriented middleware with the OpenDaylight controller. In more detail, SDN-MQ is based on the Java Messaging Service (JMS) standard. The basic fatures of SDN-MQ are:

  • All messages are consequently based on JSON making message generation and interpretation straightforward.
  • SDN-MQ supports proactive and reactive flow programming without the need to implement complex OSGi services.
  • SDN-MQ supports message filtering for packet-in events through standard JMS selectors. So the control application can define, which packet-in events to receive based on packet header fields like source and destination adddresses. According to the publish/subscribe paradigm, multiple control applications can receive packet-in event notifications for the same packet.
  • SDN control logic can be distributed horizontally to different hosts for scaling out control logic.
  • Although SDN-MQ is based on the Java-based JMS standard, JMS servers such as Apache ActiveMQ support further language-independent protocols like STOMP (Streaming Text Oriented Messaging Protocol). Therefore, cross-language control applications implemented in C++, Python, JavaScript, etc. are supported.
  • Besides packet-in events and flow programming, SDN-MQ supports further essential functionality such as packet forwarding/injection via the controller.
  • SDN-MQ is open source and licensed through the Eclipse license (similar to OpenDaylight). The full source code is available at GitHub.

The figure below shows the basic architecture of SDN-MQ. SDN-MQ is implemented as OSGi services executed within the same OSGi framework as the the OpenDaylight OSGi services. SDN-MQ uses the OpenDaylight services to provide its service to the control application. So basically, SDN-MQ acts as a bridge between OpenDaylight and control application.

sdn-mq

Three services are implemented by SDN-MQ to date:

  • Packet-in service to receive packet-in events including packet filtering based on header fields using JMS selectors.
  • Flow programming to define flow table entries on switches.
  • Packet forwarding to forward either packets received through packet-in events or new packets created by the application.

The JMS middleware transports messages between the SDN-MQ services and the control applications. As JMS middleware, we have used ActiveMQ so far, but any JMS-compliant service should work. If the message-oriented middleware is supporting other language-independent protocols (such as STOMP), control applications can be implemented in any supported language.

Where to go from here

In my next blog post, I will explain in detail how to use SDN-MQ. Until then, you can find more details and programming examples on the SDN-MQ website at GitHub.

Stay tuned!

OpenDaylight: Programming Flows with the REST Interface and cURL

The SDN controller OpenDaylight comes with a Flow Programmer service, which makes it very easy for applications to program flows by using a REST interface. In this post, I will show how to use this service together with the command line tool cURL to add, modify, and delete flows.

What is so nice about REST?

REST is based on technologies that many programmers already know, in particular, HTTP to transport requests and responses between client (control application) and service (e.g., OpenDaylight’s Flow Programmer), and XML and JSON to describe the parameters of a request and the result. Because of its simplicity (compared to other web service standads like SOAP), REST is very popular and used by many web services in the World Wide Web, e.g., by Twitter or Flickr.

Since REST is based on popular technologies like HTTP, JSON, and XML, you can use it in a more or less straightforward way with most programming languages like Java, Python, C (you name it), and even command line tools like cURL. Therefore, the barrier to use it is very low. I think, this very nicely shows how software-defined networking reduces the gap between application (programmer) and network. I am sure, after you have read this post, you will agree.

Having said this, it is also important to understand the limitations of REST in the scope of SDN. REST is based on request/response interaction, i.e., the control application (client) makes a request, and the service executes the request and returns the response. REST is less suited for event-based interaction, where the controller calls the application (strictly speaking, then the controller would be the client and the application the service since client and server are only roles of two communicating entities).

In OpenFlow, there is one important event that signals to the control application that a packet without matching flow table entry has arrived at a switch (packet-in event). In this case, a controll application implementing the control logic has to decide what to do: dropping the packet, forwarding it, or setting up a flow table entry for similar packets. Because of this limitation, the REST interface is limited to proactive flow programming, where the control application proactively programs the flow table of the switches; reactive flow programming where the control application reacts on packet-in events is implemented in OpenDaylight using OSGI components.

Programming Flows with REST

REST is all about resources and their states. REST stands for Representational State Transfer. What does that mean in the context of OpenDaylight’s Flow Programmer service? For the Flow Programmer service, you can think of resources as the whole network, a switch, or a flow. The basic job of the Flow Programmer is to query and change the state of these resources by returning, adding, or deleting flows. The state of a resource can be represented in different formats, namely, XML or JSON.

Adding Flows

That was still very abstract, wasn’t it? According to Einstein, the only way to explain something is by example. So let’s make some examples. First of all, we will add a flow to a switch. We use a very simple linear topology with two switches and two hosts depicted in the following figure.

mininet-topology

You can create this topology in Mininet with the following command assuming the OpenDaylight controller is running on the machine with IP 192.168.1.1:

mn --controller=remote,ip=192.168.1.1 --topo linear,2

We also open X-terminals for both hosts using the following commands:

mininet> xterm h1
mininet> xterm h2

With the command ifconfig in the respective terminal, you can find out the IP addresses of the hosts (h1: 10.0.0.1; h2: 10.0.0.2).

OpenDaylight already implements reactive forwarding logic, so a ping between host h1 and host h2 already works! You can send a ping from h1 to h2 to check this:

h1> ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=0.368 ms
64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=0.050 ms
64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=0.059 ms
64 bytes from 10.0.0.2: icmp_req=4 ttl=64 time=0.058 ms

Since these flows were programmed reactively using an OSGI module, we cannot see them in the Flow Programmer service! This service only knows about the flows that were created via the Flow Programmer itself.

Now let’s program a flow that blocks all TCP requests to port 80 (web server) targeted at Host 2. You can think of this as an in-network firewall. Instead of blocking the traffic at the host using a software firewall, we already block it on a switch, e.g., at a top-of-rack switch of the rack where h2 is located or even earlier at the core switches of your data center to keep your network free from unwanted traffic.

Before we setup our blocking flow entry, we verify that h1 can send requests on port 80 to h2 using netcat to simulate a web server and client:

h2> nc -lk 10.0.0.2 80
Hello
h1> echo "Hello" | nc 10.0.0.2 80

Here, h2 is listening (option -l) on port 80 for incoming requests (and stays listening; option -k). h1 sends the String “Hello”, and h2 displays this string showing that the connection works.

I will now show you the cURL command to block TCP datagrams to port 80 at switch s2, and then explain the details:

controller> curl -u admin:admin -H 'Content-type: application/json' -X PUT -d '{"installInHw":"true", "name":"flow1", "node": {"id":"00:00:00:00:00:00:00:02", "type":"OF"}, "ingressPort":"2", "etherType": "0x800", "protocol": "6", "tpDst": "80", "priority":"65535","actions":["DROP"]}' 'http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:02/staticFlow/flow1'

We are using option “-u” to specify the user name and password (both “admin” which you might want to change for obvious reasons). OpenDaylight uses HTTP Basic authentication, so every request to a northbound REST interface must be authenticated with a user name and password.

According to the REST paradigm, resources are added using HTTP PUT requests. Therefore, we set the cURL option “-X PUT” to add the flow. If a resource with the same id already exists, it will be modified.

Moreover, we specify the HTTP content type as “application/json” since we are sending our request as JSON representation. You could as well use XML (Content-type: application/XML), however, here we use the simpler JSON format.

With option “-d”, we set the payload of the HTTP request, which in our case is a JSON document defining the flow to be added. A JSON document consists of a number of key value pairs separated by colon, so it should be very easy to read the above example. Our new flow gets the name “flow1″, so we can later refer to it to modify or delete it. It will be installed in hardware on the switch — whatever that means for our emulated mininet ;) The value of the key “node” consists of a JSON structure (marked by “{..}” in JSON) with the keys “id” and “type”. These are the data path id and type (OF = OpenFlow) of the switch. Actually, adding node id, type, and flow name is redundant from my point of view, because it is also included in the URL as you can see. According to the REST paradigm, the URL is the right place to specify the path of the resource. Anyway, it will not work without, so we better include it.

The rest defines the values of our flow. In order to match datagrams to port 80 over TCP/IP, you have to specify (1) the ethertype “0×800″ to identify IPv4 packets; (2) protocol id 6 to identify TCP datagrams; (3) the transport layer destination address (also known as port) 80. Moreover, we specify the incoming port and a flow priority. Priority 65535 is the highest priority, so we are sure that this entry will be effective if there are other entries that match the same packet (e.g., setup by the reactive forwarding module of OpenDaylight). Finally, we have to specify an action. In this case, the packet will be dropped. Another frequently used action is to output the packet on a certain port (e.g., “OUTPUT=1″). As you can see, the action field is an array (marked by “[..]” in JSON), so you can specify multiple actions.

So let’s see whether our flow table entry has some effect by sending another hello message via TCP/IP to port 80:

h1> echo "Hello" | nc 10.0.0.2 80
h2> echo $?
1

The second command returns the exit status of the first command, which is 1, i.e, non-zero, so it failed. Therefore, no packets to port 80 arrived at h2 anymore. You can check whether other ports are still accessible by changing the port number of the netcat commands. Actually, they are, so everything worked as expected and we successfully programmed our first flow.

Querying Flows

Now that we have programmed a flow, we can query for installed flows. According to the REST paradigm, you can query the state of a resource using a GET request. The specific request for querying all flows of the network looks as follows:

controller> curl -u admin:admin -H 'Accept: application/xml' 'http://localhost:8080/controller/nb/v2/flowprogrammer/default'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><list><flowConfig><installInHw>true</installInHw><name>flow1</name><node><id>00:00:00:00:00:00:00:02</id><type>OF</type></node><ingressPort>2</ingressPort><priority>65535</priority><etherType>0x800</etherType><protocol>6</protocol><tpDst>80</tpDst><actions>DROP</actions></flowConfig></list>

Note that this time, we are using XML as accpeted content type by setting the HTTP header field “Accepted” to “application/xml”. We could as well use JSON again, which is easier to parse and smaller.

We can also query a particular switch by specifying its data path id in the URL:

curl -u admin:admin -H 'Accept: application/xml' 'http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:02'

Or we can query the definition of a certain flow using the flow’s name in the resource URL:

curl -u admin:admin -H 'Accept: application/xml' 'http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:02/staticFlow/flow1'

Deleting Flows

Finally, we can also delete flows using the HTTP DELETE request:

curl -u admin:admin -X DELETE 'http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:02/staticFlow/flow1'

The URL specifies the resource (here of a flow) to be deleted. HTTP DELETE requests have no payload — I am just mentioning this because the Floodlight controller required a payload for delete requests, which most HTTP implementations refuse to send; so the OpenDaylight interface is cleaner and more REST’ish in that respect.

Summary

That’s basically it. I hope, you agree that programming flows using REST is really simple. In future posts, I plan to introduce other northbound REST APIs of OpenDaylight and also the OSGI interface for reactive flow programming. If you are interested, I hope to see you again.

If you need further information about the Flow Programmer REST interface, you can visit the OpenDaylight website.