Skip to content

Module Programming Guide

Byungjoon Lee edited this page Mar 18, 2014 · 16 revisions

This document explains how to program a user-defined module. To make things easier, we explain the module programming using OFMLearningMac as an example.

OFMLearningMac Module

Maybe the easiest way to learn about module programming is to see the implementation of OFMLearningMac module, which is the most simple IRIS module. As the code of this module has come from the Floodlight, many of its detail is the same. But you should remember following:

  1. IRIS module should be defined as a subclass of OFModule
  2. you should override following methods:
    1. initialize
    2. handleMessage
    3. handleHandshakedEvent
    4. handleDisconnect
    5. getModels
  3. Module name starts with OFM

initialize method

In initialize method, you normally do the following things:

  1. call the registerFilter method that makes your module to receive specific types of messages.
  2. call the registerModule method that lets other modules to know that your module is implementing a specific service.
  3. do other module-specific initialization

Following is a code from OFMLearningMac.initialize().

@Override
protected void initialize() {
	registerFilter(
		OFMessageType.PACKET_IN,
		new OFMFilter() {
			@Override
			public boolean filter(OFMessage m) {
				return true;
			}
		}
	);
}

This call to the registerFilter makes OFMLearningMac module to receive all PACKET_IN messages. The OFMFilter.filter() determines whether m is a message that this module should receive (true or false). In the above code, OFMFilter.filter() always returns true. That means this module receives all the PACKET_IN messages.

Following code is from OFMLinkDiscovery.initialize().

...
registerModule(ILinkDiscoveryService.class, this);

// I will receive PACKET_IN messages selectively.
registerFilter(
	OFMessageType.PACKET_IN, 
	new OFMFilter() {
		@Override
		public boolean filter(OFMessage m) {
			OFPacketIn pi = (OFPacketIn) m;
			
			// this checks if the Packet-In is for LLDP!
			// This is very important to guarantee maximum performance. (-_-;)
			if ( pi.getPacketData()[12] != (byte)0x88 || 
                             pi.getPacketData()[13] != (byte)0xcc ){
				// this packet is not mine!
				return false;
			}
			return true;
		}
	}
);
	
// I will receive all PORT_STATUS messages.
registerFilter(
	OFMessageType.PORT_STATUS,
	new OFMFilter() {
		@Override
		public boolean filter(OFMessage m) {
			return true;
		}
	}
);
...

In the OFMLinkDiscovery module, you can see an example usage of the registerModule method. As OFMLinkDiscovery module implements ILinkDiscoveryService interface, it register itself as an implementer module of the interface. Because of this, other modules can find and use a module that implements the ILinkdiscoveryService interface.

handleMessage method

@Override
public boolean handleMessage(Connection conn, MessageContext context, OFMessage msg, List<OFMessage> outgoing) {
	return processPacketInMessage(conn, context, msg, outgoing);
}

As you can see, handleMessage gets 4 arguments: connection with switch, message-handling context, Openflow message to process, and a list of outgoing messages to return to switches (which is initially empty).

  • MessageContext object context is created per-message basis. That is, each Openflow message passed to a controller has a designated message context.
  • OFMessage is a superclass of all Openflow messages.
  • If you have messages to return to switches, just put it into the outgoing list. Then all the messages are sent to switches before the msg is passed to other modules. (But if you need the messages to be sent immediately, you should use conn object directly.)

This method is not only used to handle PACKET_IN message, but also used to handle every Openflow message. Thus, you should be careful to differentiate.

If you return false in this method, the message msg will not pass to other modules chained next to this module within the same pipeline.

handleHandshakedEvent method

This method is called after the connection is made between a controller and a switch. After a FEATURES_REPLY message is received by the controller, this method is called. In OFMLearningMac module, this method does nothing except for returning true.

handleDisconnect method

This method is called after a connection to a switch is released. In OFMLearningMac module, this method does nothing except for returning true.

getModels method

a few words on OFModel

  • IRIS Model Programmer usually wraps important data using OFModel.
  • By overriding getAllRestApi of OFModel you can easily create REST APIs to manipulate your data.

In most cases, a module has central data structures that hold important information. IRIS OFModel class is for such data. You usually wrap your data structures with a class that inherits OFModel. (Of course, this is not mandatory.)

Besides, You can also export the data using REST API using by overriding OFModel abstract method. Because the OFMLearningMac module does not implement OFModel related features, we’d like to give you an example of the OFMLinkDiscovery module instead.

// .. in OFMLinkDiscovery class ..
@Override
public void initialize() {
    this.links = new Links(this);
    // ...
}

@Override
public OFModel[] getModels() {
    return new OFModel[] { this.links; }
}

In getModels() method, you return the array of OFModel objects. In the above example, getModels returns an array of Links object (the array size is one).

Links is a subclass of OFModel. The Links class is defined in etri.sdn.controller.module.linkdiscovery.Links.java. In this class, you can find the following code.

// ...
private RESTApi[] apis = {
	new RESTApi(
		"/wm/topology/links/json",
		new Restlet() {
			@Override
			public void handle(Request request, Response response) {
				// create an object mapper.
				ObjectMapper om = new ObjectMapper();
				// retrieve all link information as JSON.
				List<RESTLink> list = new LinkedList<RESTLink>();
				for ( Link l : links.keySet() ){
					list.add( new RESTLink (l) );
				}

				try {
					String r = om.writeValueAsString(list);
					response.setEntity(r, MediaType.APPLICATION_JSON);
				} catch (Exception e) {
					e.printStackTrace();
					return;
				}
			}
		}
	),
	new RESTApi(
		"/wm/topology/linkinfos/json",
		new Restlet() {
			@Override
			public void handle(Request request, Response response) {
				// TBD:
			}
		}
	)
};

@Override
public RESTApi[] getAllRestApi() {
	return this.apis;
}
// ...

Maybe getAllRestApi is the only method that you need to override to implement an OFModel subclass. By that, you can export your key information to outer world by REST HTTP protocol.

We cover the REST API implementation method in depth in the other wiki page

Clone this wiki locally