Skip to content

Module Programming Guide (English)

Byungjoon Lee edited this page Mar 28, 2014 · 8 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. (This is only an example. Never use OFMLearningMac in a production environment.)

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 create all the member variables and initialize them within the constructor. You should be careful because some of the variables are accessed by other modules before initialize is called. This is especially the case when your module implements some IService subtype and export the service through services() callback.
  3. you should override following methods:
  4. services
  5. initialize
  6. handleMessage
  7. handleHandshakedEvent
  8. handleDisconnect
  9. getModels
  10. Module name starts with OFM

services method

This method should return the collection of all services that a module implements. Let's see the example from OFMTopologyManager.

@Override
protected Collection<Class<? extends IService>> services() {
	List<Class<? extends IService>> ret = new LinkedList<Class<? extends IService>>();
	ret.add(ITopologyService.class);
	ret.add(IRoutingService.class);
	return ret;
}

As OFMTopologyManager module implements ITopologyService and IRoutingService interfaces, it register itself as an implementer module of the interfaces. Because of this, other modules can find and use a module that implements the ITopologyService or IRoutingService interface by calling the getModule(Class<? extends IService>) method.

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. do other module-specific initialization

Following is a code from OFMLearningMac.initialize().

@Override
protected void initialize() {
	registerFilter(
		OFType.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().

...

// I will receive PACKET_IN messages selectively.
registerFilter(
	OFType.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(
	OFType.PORT_STATUS,
	new OFMFilter() {
		@Override
		public boolean filter(OFMessage m) {
			return true;
		}
	}
);
...

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