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. |
...
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 {
|
Note |
After you complete this tutorial, you should to change the serializer for IOFSwitch back to @JsonSerialize(using=IOFSwitchSerializer.class) in order to restore the original serializer.SwitchMessagePairSerializer.class)
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.
...
Note |
---|
This is just a sample file 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. |
...
Code Block |
---|
$ sudo mn --controller=remote --ip=[Your IP Address] --mac --topo=tree,2
--switch=ovsk,protocols=OpenFlow10
*** Adding controller
*** Creating network
*** Adding hosts:
h1 h2 h3 h4
*** Adding switches:
s5 s6 s7
*** Adding links:
(h1, s6) (h2, s6) (h3, s7) (h4, s7) (s5, s6) (s5, s7)
*** Configuring hosts
h1 h2 h3 h4
*** Starting controller
*** Starting 3 switches
s5 s6 s7
*** Starting CLI:
|
...
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.... |