Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
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
outlinetrue
excludeTable 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

  1. Expand the "Floodlight" item in the Package Explorer and find the "src/main/java" folder.
  2. Right-click on the "src/main/java" folder and choose "New/Class."
  3. Enter "net.floodlightcontroller.pktinhistory" in the "Package" box.
  4. Enter "PktInHistory" in the "name" box.
  5. Next to the "Interfaces" box, choose "Add..."
  6. Type "IFloodlightModule" into the search box, and choose "OK."
  7. Repeat steps above for "IOFMessageListener"
  8. 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);
}

(warning)

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....