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.
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
- Flow comes into the OpenFlow enabled switch.
- 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_.
- 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.
- 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
The method to add a flow requires three parameters addFlow(String name, OFFlowMod fm, String swDpid);
- 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.
- OFFlowMod fm: fm is the flow to push.
- 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
Below is a module that I threw together for this post but mainly as part of another project, ehem* disclaimer if completely inefficient 🙂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
//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:
- Brad Casemore
- Greg Ferro
- Ivan Pepelnjak
- Roy Chua
- OpenStack Quantum: Take a look at a real life networking API in production today in the OpenStack project.
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
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
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.
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
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
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
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
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);