Info |
---|
This tutorial is for Floodlight v1.0 and later. If you need to use Floodlight v0.91 or earlier, you can find the v0.91 and v0.90 documentation here. |
Table of Contents
Table of Contents outline true exclude Table of Contents
Introduction
...
There are a number of different types of OpenFlow messages for which events are generated, but most of the action happens in the PacketIn handlers. A PacketIn message is the OpenFlow message that is sent from the switch to the controller if the switch does not have a flow table rule that matches the packet. The controller is expected to handle the packet and to install any necessary flows table entries (using a set of FlowMod messages). In this tutorial, we'll be adding a new PacketIn listener will store the PacketIn messages. We will then make these messages available via the REST API.
Creating the Class
Add class in Eclipse
- Expand the "Floodlight" item in the Package Explorer and find the "src/main/java" folder.
- Right-click on the "src/main/java" folder and choose "New/Class."
- Enter "net.floodlightcontroller.pktinhistory" in the "Package" box.
- Enter "PktInHistory" in the "name" box.
- Next to the "Interfaces" box, choose "Add..."
- Type "IFloodlightModule" into the search box, and choose "OK."
- Repeat steps above for "IOFMessageListener"
- Click "Finish" in the dialog.
...
Code Block |
---|
@Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); buffer = new ConcurrentCircularBuffer<SwitchMessagePair>(SwitchMessagePair.class, 100); } |
You'll need to import the ConcurrentCircularBuffer into the PktInHistory package. It is available here. |
...
If your Floodlight version does not include this class, you can add the ConcurrentCircularBuffer.java file within the net.floodlightcontroller.util package of your controller. |
Now we have to define the behavior for what to do when the module receives a PacketIn message. This is done in the receive() function.
...
Info |
---|
You can find a more in-depth REST API tutorial here if you are curious about the 'how' and 'why' behind some things you're required to do below. |
We now have a complete module implementation, but no way to get information out of it! For this we'll need to do two things. Have our module export a service then tie it into the REST API Module.
...
The data is serialized into REST format using Jackson. Jackson will look at a class and try to serialize every field that has a getter. In this case we don't want everything to be serialized in IOFSwitch or OFMessage, so we'll need to write a custom serializer. We will add it to the net.floodlightcontroller.web.serialzers package.
Code Block |
---|
package net.floodlightcontroller.core.web.serializers; import java.io.IOException; import net.floodlightcontroller.core.IOFSwitch; org.projectfloodlight.openflow.protocol.OFPacketIn; import org.projectfloodlight.openflow.protocol.OFPacketInReason; import org.projectfloodlight.openflow.protocol.OFType; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; public class IOFSwitchJSONSerializer extends JsonSerializer<IOFSwitch> { /**import net.floodlightcontroller.core.types.SwitchMessagePair; import net.floodlightcontroller.util.OFMessageUtils; public class SwitchMessagePairSerializer extends JsonSerializer<SwitchMessagePair> { * Handles serialization for IOFSwitch */ @Override public void serialize(IOFSwitchSwitchMessagePair theSwitchm, JsonGenerator jGen, SerializerProvider arg2) throws IOException, JsonProcessingException { SerializerProvider arg2) throws IOException,jGen.writeStartObject(); jGen.writeFieldName("message"); jGen.writeStartObject(); if (m.getMessage().getType() == OFType.PACKET_IN) { jGen.writeNumberField("bufferId", ((OFPacketIn)m.getMessage()).getBufferId().getInt()); JsonProcessingException { jGen.writeNumberField("inPort", OFMessageUtils.getInPort((OFPacketIn)m.getMessage()).getPortNumber()); jGen.writeNumberField("packetDataLength", ((OFPacketIn)m.getMessage()).getData().length); jGen.writeBinaryField("packetData", ((OFPacketIn)m.getMessage()).getData()); jGen.writeStringField("reason", ((OFPacketIn)m.getMessage()).getReason().toString()); jGen.writeNumberField("totalLength", ((OFPacketIn)m.getMessage()).getTotalLen()); } jGen.writeStringField("type", m.getMessage().getType().toString()); jGen.writeStringField("version", m.getMessage().getVersion().toString()); jGen.writeNumberField("xid", m.getMessage().getXid()); jGen.writeEndObject(); jGen.writeFieldName("switch"); jGen.writeStartObject(); jGen.writeStringField("dpid", theSwitchm.getSwitch().getId().toString()); jGen.writeEndObject(); jGen.writeEndObject(); } } |
Now we have to tell Jackson to use the serializer. We do this by annotating our class which will tell Jackson to use our serializer. Open up IOFSwitch SwitchMessagePair and annotate the class as depicted below. Remove the existing serializer annotation to use your custom serializer.
Code Block |
---|
@JsonSerialize(using=IOFSwitchJSONSerializer.class)
public interface IOFSwitch extends IOFMessageWriter {
|
...
Code Block |
---|
@JsonSerialize(using=IOFSwitchSerializer SwitchMessagePairSerializer.class)in order to restore the original serializer.
public class SwitchMessagePair {
|
Loading the module
We're almost done, we just need to tell Floodlight to load the module on startup. First we have to tell the loader that the module exists. This is done by adding the fully qualified module name on it's own line in src/main/resources/META-INF/services/net.floodlight.core.module.IFloodlightModule. We open that file and append this line.
...
Code Block |
---|
floodlight.modules = net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ net.floodlightcontroller.forwarding.Forwarding,\ net.floodlightcontroller.pktinhistory.PktInHistory |
...
Note |
---|
This is just a sample |
...
excerpt from a configuration file. As Floodlight is under rapid development this file may not reflect the most current configuration required to run. Instead of using this configuration exactly, just append the PktInHistory module to the current list in the configuration file. |
Testing with mininet
We can also try testing the whole controller by connecting mininet to it. Run the controller as before, then from inside a controller vm:
...
Code Block |
---|
$ curl -s http://localhost:8080/wm/pktinhistory/history/json | python -mjson.tool [ { "message": { "bufferId": 256, "inPort": 2, "lengthpacketDataLength": 96, "lengthU": 96, "packetData": "MzP/Uk+PLoqIUk+Pht1gAAAAABg6/wAAAAAAAAAAAAAAAAAAAAD/AgAAAAAAAAAAAAH/Uk+PhwAo2gAAAAD+gAAAAAAAACyKiP/+Uk+P", "reason": "NO_MATCH", "totalLength": 78, "type": "PACKET_IN", "version": 1, "xid": 0 }, "switch": { "dpid": "00:00:00:00:00:00:00:06" } }, { "message": { "bufferId": 260, "inPort": 1, "length": 96, "lengthUpacketDataLength": 96, "packetData": "MzP/Uk+PLoqIUk+Pht1gAAAAABg6/wAAAAAAAAAAAAAAAAAAAAD/AgAAAAAAAAAAAAH/Uk+PhwAo2gAAAAD+gAAAAAAAACyKiP/+Uk+P", "reason": "NO_MATCH", "totalLength": 78, "type": "PACKET_IN", "version": 1, "xid": 0 }, "switch": { "dpid": "00:00:00:00:00:00:00:05" } }, etc....etc.... |