-
Notifications
You must be signed in to change notification settings - Fork 10
Module Programming Guide (English)
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.)
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:
- IRIS module should be defined as a subclass of OFModule
- 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 someIService
subtype and export the service throughservices()
callback. - you should override following methods:
- services
- initialize
- handleMessage
- handleHandshakedEvent
- handleDisconnect
- getModels
- Module name starts with OFM
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.
In initialize method, you normally do the following things:
- call the
registerFilter
method that makes your module to receive specific types of messages. - 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;
}
}
);
...
@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
objectcontext
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 themsg
is passed to other modules. (But if you need the messages to be sent immediately, you should useconn
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.
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.
This method is called after a connection to a switch is released. In OFMLearningMac
module, this method does nothing except for returning true.
- IRIS Model Programmer usually wraps important data using OFModel.
- By overriding
getAllRestApi
ofOFModel
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.
OpenIRIS Development Team: contact [email protected]