Floodlight OpenFlow Controller: Using the Static Flow Entry Pusher

Floodlight OpenFlow Controller: Using the Static Flow Entry Pusher

Openflow Programming Header Sm

Floodlight OpenFlow Controller: Using the Static Flow Entry Pusher

Floodlight OpenFlow Controller: Using the Static Flow Entry Pusher: The first post in this tutorial can be found at Tutorial to Build a FloodLight SDN OpenFlow Controller .


For those looking to do things with early SDN / OpenFlow controllers this post may be of some use to kickstart your efforts. I am posting a Java class below that Cory Fowler and I put together. There are lots of good guides out there but what exactly I was looking for was unavaialble at the time.

Packet-in Logic

The goal was to get the framework together for this project, but I didn’t see anything out there that did it from within Floodlight with a Java module. Fortunately, the guys from BigSwitch built a nice module that abstracted some of the nuances of doing a FlowMod like OFAction fields, setting lengths, flushing between flows and the dozens of other little gotchas that need layers of abstraction to simplify.

OpenFlow FlowMod

Using the Floodlight Static Flow Entry Pusher Service

What this allows for is to proactively instantiate a static flow to define a predetermined path based on a match and then the corresponding action.

Simple OpenFlow workflow
The flow logic looks like the following minus lots of details:
  1. Flow comes into the OpenFlow enabled switch.
  2. Switch looks in its forwarding table to see if there is a match. If there is a match the switch forwards that packet per the forwarding table instruction. The matches can either be a coarse match like anything destined to IPv4 10.0.0.0/8 —> do this action, or as fine as anything matching {port 80, mac addr 0000.1111.2222, dest_ipv4 10.1.1.1/32, (any other tuple in the header) etc}. Think traditional _access-lists_.
  3. If there is not a matching flow in the switch an event is triggered creating a packet-in packet to the controller where the logic in the code below could be processed.
  4. After the controller determines an action it then creates a packet-out packet that tells the switch what action to take with that flow and subsequent packets in that same flow.
Note on a FlowMod for IPv4 destination prefix matching
If you are matching on a IPv4 destination you need to set the ethertype per the OpenFlow spec. In the next section code, that looks like: .setDataLayerType(Ethernet.TYPE_IPv4)

The method to add a flow requires three parameters addFlow(String name, OFFlowMod fm, String swDpid);

  1. String name: The name variable is an arbitrary name, but it must be unique to the static flow. If you use the same name it will be overwritten. Very similar to access list line numbers.
  2. OFFlowMod fm: fm is the flow to push.
  3. String swDpid: Is the switch datapath ID (DPID) to push it to. The Mininet default DPID is 00:00:00:00:00:00:00:01.
Floodlight package net.floodlightcontroller.staticflowentry Javadoc
The package net.floodlightcontroller.staticflowentry is documented at the OpenFlow Hub.

Below is a module that I threw together for this post but mainly as part of another project, ehem* disclaimer if completely inefficient :-)

//net.floodlightcontroller.names is a created package for something else, not part of FloodLight to make sure there isn't any confusion.
 package net.floodlightcontroller.names;
import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
import org.openflow.protocol.OFFlowMod;
 import org.openflow.protocol.OFMatch;
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPacketIn;
 import org.openflow.protocol.OFType;
 import org.openflow.protocol.action.OFAction;
 import org.openflow.protocol.action.OFActionOutput;
import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
 //import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher;
public class Names implements IFloodlightModule, IOFMessageListener {
protected IFloodlightProviderService floodlightProvider;
 protected IStaticFlowEntryPusherService staticFlowEntryPusher;
@Override
 public String getName() {
 return "Names";
 }
@Override
 public boolean isCallbackOrderingPrereq(OFType type, String name) {
 return false;
 }
@Override
 public boolean isCallbackOrderingPostreq(OFType type, String name) {
 return false;
 }
@Override
 public net.floodlightcontroller.core.IListener.Command receive(
 IOFSwitch sw, OFMessage msg, FloodlightContext cntx ) {
String dp = "00:00:00:00:00:00:00:01";
 OFPacketIn pi = (OFPacketIn) msg;
 OFMatch match = new OFMatch();
 match.loadFromPacket(pi.getPacketData(), (short) 0);
 System.out.println("$$$$$$$$$OFMATCH$$$$$$$$$$$");
 System.out.println(match);
 System.out.println("$$$$$$$$$IP-Destination$$$$$$$$$$$");
 System.out.println("$$$$$$$$$IP-Destination$$$$$$$$$$$");
 System.out.println(IPv4.fromIPv4Address(match.getNetworkDestination()));
//IPv4-To
 List actionsTo = new ArrayList();
 // Declare the flow
 OFFlowMod fmTo = new OFFlowMod();
 fmTo.setType(OFType.FLOW_MOD);
 // Declare the action
 OFAction outputTo = new OFActionOutput((short) 2);
 actionsTo.add(outputTo);
 // Declare the match
 OFMatch mTo = new OFMatch();
 mTo.setNetworkDestination(IPv4.toIPv4Address("10.0.0.3"));
 mTo.setDataLayerType(Ethernet.TYPE_IPv4);
 fmTo.setActions(actionsTo);
 fmTo.setMatch(mTo);
 // Push the flow
 staticFlowEntryPusher.addFlow("FlowTo", fmTo, dp);
//IPv4-From
 List actionsFrom = new ArrayList();
 // Declare the flow
 OFFlowMod fmFrom = new OFFlowMod();
 fmFrom.setType(OFType.FLOW_MOD);
 // Declare the action
 OFAction outputFrom = new OFActionOutput((short) 1);
 actionsFrom.add(outputFrom);
 // Declare the match
 OFMatch mFrom = new OFMatch();
 mFrom.setNetworkDestination(IPv4.toIPv4Address("10.0.0.2"));
 mFrom.setDataLayerType(Ethernet.TYPE_IPv4);
 fmFrom.setActions(actionsFrom);
 fmFrom.setMatch(mFrom);
 // Push the flow
 staticFlowEntryPusher.addFlow("FlowFrom", fmFrom, dp);
//ToArp
 List actionsToArp = new ArrayList();
 // Declare the flow
 OFFlowMod fmToArp = new OFFlowMod();
 fmToArp.setType(OFType.FLOW_MOD);
 // Declare the action
 OFAction outputToArp = new OFActionOutput((short) 2);
 actionsToArp.add(outputToArp);
 // Declare the match
 OFMatch mToArp = new OFMatch();
 mToArp.setNetworkDestination(IPv4.toIPv4Address("10.0.0.3"));
 mToArp.setDataLayerType(Ethernet.TYPE_ARP);
 fmToArp.setActions(actionsToArp);
 fmToArp.setMatch(mToArp);
 // Push the flow
 staticFlowEntryPusher.addFlow("FlowToArp", fmToArp, dp);
//ArpFrom
 List actionsFromArp = new ArrayList();
 // Declare the flow
 OFFlowMod fmFromArp = new OFFlowMod();
 fmFromArp.setType(OFType.FLOW_MOD);
 // Declare the action
 OFAction outputFromArp = new OFActionOutput((short) 1);
 actionsFromArp.add(outputFromArp);
 // Declare the match
 OFMatch mFromArp = new OFMatch();
 mFromArp.setNetworkDestination(IPv4.toIPv4Address("10.0.0.2"));
 mFromArp.setDataLayerType(Ethernet.TYPE_ARP);
 fmFromArp.setActions(actionsFromArp);
 fmFromArp.setMatch(mFromArp);
 // Push the flow
 staticFlowEntryPusher.addFlow("FlowFromArp", fmFromArp, dp);
System.out.println("$$$$$$$$$OFMATCH$$$$$$$$$$$");
 System.out.println(mTo);
return Command.CONTINUE;
 }
@Override
 public Collection<Class> getModuleServices() {
 // TODO Auto-generated method stub
 return null;
 }
@Override
 public Map<Class, IFloodlightService> getServiceImpls() {
 // TODO Auto-generated method stub
 return null;
 }
 //Service Class l.add(IStaticFlowEntryPusherService.class);
 @Override
 public Collection<Class> getModuleDependencies() {
 Collection<Class> l = new ArrayList<Class>();
 l.add(IFloodlightProviderService.class);
 l.add(IStaticFlowEntryPusherService.class);
 return l;
 }
// Context object SFP Class
 @Override
 public void init(FloodlightModuleContext context)
 throws FloodlightModuleException {
 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
 staticFlowEntryPusher = context.getServiceImpl(IStaticFlowEntryPusherService.class);
 }
@Override
 public void startUp(FloodlightModuleContext context) {
 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
 }
 }

Testing the Class with Mininet

For testing I normally use Mininet. If you look at the first post you can see the video and how to attach mininet switches to the controller running in Eclipse and use Xterm to source traffic from your simulated hosts.

Additional OpenFlow SDN Development Resources

Here are some open source OpenFlow controller projects and links to their documentation tutorials and guides.

  • Floodlight – Lots of nice documents for developers to understand how to get started. The Floodlight listserv is very helpful also.
  • Beacon – David has lots of good tutorials at the Beacon OpenFlow homepage. FloodLight was built on top of Ericksons controller Beacon. David is a nice guy that does an amazing job answering questions on the Beacon forum. Pretty neat to have the chance to ask questions directly from a pioneer like him. He has just updated his development tutorial so take a look at Creating a Learning Switch and help with feedback on the Beacon forum if interested.
  • POX - For those more comfortable with programming with Python have a look at Murphy McCauley’s project POX. Murphy is another very accessible community oriented researcher.
  • For those wanting to just get a basic understanding of OpenFlow or even just watch a video of it and  don’t care about the nitty gritty programming details, this tutorial I did a while back. It needs a makeover but its probably enough to get the point. I need to update it but its just basic usage of the RESTful Floodlight API.

Programming applications directly into OpenFlow primitives is likely not the path for any semblance of DevOps networking gets in to. There will be additional layers that will enable :Policy in -> Flows out. These additional layers are cropping up in the form of APIs and additional languages that are creating the SDN policy wood chipper to create flows. I discussed a couple of those projects in this post: Software Defined Network (SDN) -Looking Toward 2013


Here are some additional reading on networking APIs from some friends:

Learn more about Floodlight development on the Floodlight-Dev Listserv


Hope this helps add some documentation for those looking to dig under the hood a bit and create their own networking applications for research or a network that fits their needs. Thanks for stopping by.


Download OpenFlow v1.3


About the Author

Brent SalisburyBrent Salisbury works as a Network Architect, CCIE #11972. He blogs at NetworkStatic.net with a focus on disruptive technologies, that have a focus on operational efficiencies. Brent can be reached on Twitter @NetworkStatic.View all posts by Brent Salisbury →

  1. Paul LappasPaul Lappas12-10-2012


    Thanks Brent! Please also check out the Circuit Pusher app – it’s a python application that utilizes the Floodlight REST APIs to create a bidirectional circuit, i.e., permanent flow entry, on all switches in route between two hosts (based on IP addresses with specified priority).

    http://www.openflowhub.org/display/floodlightcontroller/Circuit+Pusher

    • phenterminephentermine02-17-2013


      The report offers established helpful to myself.
      It’s quite useful and you are certainly really well-informed in this field.

      You get opened our eye to varying views on this subject together
      with intriguing, notable and reliable content material.

  2. Brent SalisburyBrent Salisbury12-10-2012


    Good mention Paul. Also worth mentioning that the Circuit Pusher app uses the REST API or the FloodLight “Northbound API” for abstraction. I have not had a chance to test with that. The concept is really important, how to stitch a flow through multiple OF switches. I need to ask on the listserv if that is going to have a RESTful exposure in the future also.

    Thanks for the feedback Paul
    -Brent

  3. RaviRavi01-01-2013


    In your Java example code, I did not see ‘table_id’ parameter being passed while flows are being pushed. Is it that the floodlight controller assumes table_id 0 by default if it is not given. Just curious.
    - Ravi

  4. Brent SalisburyBrent Salisbury01-02-2013


    Hi Ravi,

    Last I looked Floodlight is OpenFlow v1.0 which doesn’t support a multi-table OF pipeline. It just lumps everything into one table. OF spec v1.1 and greater supports multi-table options. I believe Floodlight is releasing v1.2 support in Q1 2013.

    v1.0 has a little mention to multiple tables w/ regard to pulling stats in the OFPST_FLOW function.
    “The table_id field indicates the index of a single table to read, or 0xff for all tables.”

    /* Instruction structure for OFPIT_GOTO_TABLE */
    struct ofp_instruction_goto_table {
    uint16_t type;
    uint16_t len;
    uint8_t table_id;
    uint8_t pad[3];
    /* OFPIT_GOTO_TABLE */
    /* Length of this struct in bytes. */
    /* Set next table in the lookup pipeline */
    /* Pad to 64 bits. */
    };

    Thats from the v1.3 spec: https://www.opennetworking.org/images/stories/downloads/specification/openflow-spec-v1.3.0.pdf

    There is a table_name value in Floodlight that is where the persistent static flows are written to disk.
    public static final String TABLE_NAME = “controller_staticflowtableentry”;
    storageSource.createTable(TABLE_NAME, null);
    storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_NAME);

    I havent tinkered with much outside of FloodLight and POX on the controller side. CPqD released a v1.3 NOX if you want to give v1.3 a go at:
    https://mailman.stanford.edu/pipermail/openflow-discuss/2012-December/004032.html
    If you don’t mind a C+ controller it should have multi-table support if it is v1.3 compliant.

    Let me know if I missed your question.

    Thanks,
    -Brent

  5. DeepankarDeepankar03-12-2013


    Hi
    I am try to learn about openflow and openvswitch. The setup which I am trying to create

    Controller
    / \
    / \
    / \
    / \
    Ovs Br0———-Ovs Br1
    | |
    | |
    VM0 VM1

    The setup is on single Ubuntu host machine. The OVS Br0 and Br1 is connected using patch cable and VM0(Qemu-kvm) and VM1(Qemu-kvm) are connected to respective Bridges using tap interface created using tunctl. VM0 and VM1 are different subnet. I want ping from VM0 to VM1. How should I do it using openflow controllers.

    Thanks in Advance
    Deepankar

  6. Don FrazierDon Frazier04-04-2013


    Brent,

    I’m having problems implementing your setup on my Procurve 6600 switches. In particular I am not sure what port to use if we are using the OOBM (out of band management port) for command and control. You are using port ’0′. How should I modify my code to take advantage of this port.

    IOFSwitch sw, OFMessage msg, FloodlightContext cntx ) {
    44
    String dp = “00:00:00:00:00:00:00:01″;
    45
    OFPacketIn pi = (OFPacketIn) msg;
    46
    OFMatch match = new OFMatch();
    47
    match.loadFromPacket(pi.getPacketData(), (short) 0);
    48
    System.out.println(“$$$$$$$$$OFMATCH$$$$$$$$$$$”);
    49
    System.out.println(match);