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 are using v0.9, v0.91, a copy of the master branch prior to December 30, 2014, or another prior version of Floodlight, this tutorial does not apply. If you are using the old openflow-1.3 branch, you should consider updating to the main repository's v1.2 (or even better master) branch to ensure you have the latest updates.

...

Floodlight v1.0 and up is backed by the new OpenFlowJ-Loxigen library. OpenFlowJ-Loxigen supports multiple OpenFlow versions, from 1.0 to 1.5. Floodlight v1.2 supports up to 1.4 and the master branch supports up to v1.5), through a single, common, version-agnostic API. Developers can take advantage of the API to write applications compatible with switches of multiple and various OpenFlow versions. All OpenFlow concepts and types are accessible from the OpenFlowJ-Loxigen library. The idea is that each OpenFlow version has a factory that can build all types and messages as they are defined for that version of OpenFlow.

OpenFlowJ-Loxigen also sports a new and very much improved way to create OpenFlow Messages, Matches, Actions, FlowMods, etc. The creation of many OpenFlow objects has been greatly simplified using builders, all accessible from a common OpenFlow factory. Simply set your fields and build. The handling of low-level details such as Message lengths wildcards are dealt with behind the scenes. Never again will you have to worry about keeping track of and (in)correctly setting Message lengths. When composing FlowMods, all Match fields are automatically wildcarded, except for those fields you specifically set in the FlowMod. Masked fields are also supported, and the mask can be specified with the Match, which will automatically set the appropriate wildcard bits if necessary. All objects produced from builders are immutable, which allows for safer code and makes your applications easier to debug.

All switches that connect to Floodlight contain a factory for the version of OpenFlow the switch speaks. There can be multiple switches, all speaking different versions of OpenFlow, where OpenFlowJ-Loxigen handles the low-level protocol differences behind the scenes. From the perspective of modules and application developers, the switch is simply exposed as an IOFSwitch, which has the function getOFFactory() to return the OpenFlowJ-Loxigen factory appropriate for the OpenFlow version the switch is speaking. Once you have the correct factory, you can create OpenFlow types and concepts through the common API OpenFlowJ-Loxi exposes.

As such, you do not need to switch APIs when composing your FlowMods and other types. Let's say you wish to build a FlowMod and send it to a switch. Each switch known to the switch manager has a reference to an OpenFlow factory of the same version negotiated in the initial handshake between the switch and the controller. Simply reference the factory from your switch, create the builder, build the FlowMod, and write it to the switch. The same API is exposed for the construction of all OpenFlow objects, regardless of the OpenFlow version. You will however need to know what you are allowed to do for each OpenFlow version; otherwise, if you e.g. tell an OF1.0 switch to perform some action such as add a Group, which is not supported for it's OpenFlow version, the OpenFlowJ-Loxi library will kindly inform you with an UnsupportedOperationException.

There are some other subtle changes introduced, for the better, with OpenFlowJ-Loxigen. For example, many common types such as switch datapath IDs, OpenFlow ports, and IP and MAC addresses are defined by the OpenFlowJ-Loxi library through the DatapathId, OFPort, IPv4Address, and MacAddress, respectively. You are encouraged to explore org.projectfloodlight.openflow.types, where you will find a wide variety of common types that are now conveniently defined in a single location. Like the objects produced from builders above, all types are immutable.

Lastly, OpenFlowJ-Loxigen is open source, has a comprehensive suite of auto-generated protocol unit tests, an automated integration-tested release process, and is in use in production by the current family of commercial BSN products. 

If you want to know more about the architecture of OpenFlowJ-Loxigen, take a look at this wiki page: https://github.com/floodlight/loxigen/wiki/OpenFlowJ-Loxi

Prerequisites and Goals

The goal of this tutorial is to introduce the most common uses of the OpenFlowJ-Loxigen library within a user module. Examples are given on how to perform everyday operations like compose a FlowMod, handle a PacketIn, and many more. These examples introduce the techniques and assume you have a module written in which you can apply them. If you would like to know how to create a module for Floodlight v1.0, please refer to this tutorial.

OpenFlow Concepts

Factories

...

Code Block
DatapathId dpid1 = DatapathId.of(1); /* Create a DatapathId from a long. */
DatapathId dpid2 = DatapathId.of("00:00:00:00:00:00:00:02"); /* ...from a String. */
DatapathId dpid3 = DatapathId.of(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}); /* ...from a byte array. */


String dpid1String = dpid1.toString(); /* Return the DPID in proper String format, "00:00:00:00:00:00:00:01". */
long dpid2Long = dpid2.getLong(); /* Return the DPID as a long, 2. */U64 dpid3ULong = dpid3.getUnsignedLong(); /* Return the DPID as an unsigned long, 3. */
byte[] dpid3Bytes = dpid3.getBytes(); /* Return the DPID as a byte array, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}. */

...

Code Block
IPv4Address ip1 = IPv4Address.of(1); /* ...from integer. */
IPv4Address ip2 = IPv4Address.of("0.0.0.2"); /* ...from String. */
IPv4Address mask = IPv4Address.of(new byte[] {0xFF, 0xFF, 0xFF, 0x00}); /* ...from byte array. */


IPv4Address ipMasked = ip1.applyMask(mask); /* Get IP with mask. */
IPv4Address ipFromCIDR = IPv4Address.ofCidrMaskLength(24); /* Same as "mask" above. */
if ( mask.isBroadcast() ) { ... } /* Is the IP 255.255.255.255? (no) */

if ( mask.equals(ipFromCIDR) ) { ... } /* Deep equality check. */
IPVersion version = ip2.getVersion(); /* Returns enum IPVersion.IPv4. */
IPv4Address ip3 = ip1.or(ip2); /* Bitwise OR: 0.0.0.1 | 0.0.0.2 --> 0.0.0.3. */

...

Code Block
MacAddress mac1 = MacAddress.of("FF:ff:FF:ff:FF:ff"); /* ...from String. */
MacAddress mac2 = (MacAddress.of("11:22:33:44:55:66")).applyMask(mac1); /* Apply a mask. */
String macStr = mac2.toString(); /* Returns String "11:22:33:44:55:66". */


if ( mac1.isBroadcast() ) { ... } /* Is the MAC all 1's? (yes) */
if ( mac2.isMulticast() ) { ... } /* Does MAC have a 1 in LSB of 1st octet? XXXXXXX1:XX:XX:XX:XX:XX (yes) */
if ( mac2.isLLDPAddress() ) { ... } /* Does the MAC look like 01:80:C2:00:00:0X, ignoring the LS-Byte? (no) */

...

Code Block
OFPort port1 = OFPort.of(1); /* Port numbers 1 through 48 are precached for efficiency. */
OFPort port2 = OFPort.ofShort((short) 2);


OFPort pLocal = OFPort.LOCAL; /* 66534 */
OFPort pZero = OFPort.ZERO; /* Wildcarded default for OF1.0; not used in OF1.1+. */
OFPort pAny = OFPort.ANY; /* a.k.a. "NONE" in OF1.0; used in wildcarding. */
OFPort pAll = OFPort.ALL; /* All physical ports except input port. */
OFPort pCont = OFPort.CONTROLLER;
OFPort pFlood = OFPort.FLOOD; /* All physical ports in VLAN, except input and those that are down/blocked. */
OFPort pTable = OFPort.TABLE; /* In PacketOuts, send to first flow table. */
OFPort pIn = OFPort.IN_PORT;
OFPort pNorm = OFPort.NORMAL; /* Process as L2/L3 learning switch. */


int raw = port1.getPortNumber();
short raw2 = port1.getShortPortNumber();

...

Code Block
IpProtocol ipp1 = IpProtocol.of(6); /* Decimal TCP IP protocol. */
IpProtocol ipp2 = IpProtocol.of(0x11); /* Hexadecimal UDP IP protocol. */
IpProtocol ipp3 = IpProtocol.TCP; /* Like EthType, almost every common IP protocol is precached/predefined. */


if ( ipp1.compareTo(ipp3) == 0 ) { ... } /* ipp1 is the same IP protocol as ipp3. */
if ( ipp1.equals(ipp3) ) { ... } /* ipp1 does equal ipp2. */
if ( ipp1 == ipp3 ) { ... } /* ipp1 and ipp3 are the SAME OBJECT, since all common, predefined IP protocol numbers are precached. */

...

Code Block
TransportPort tp1 = TransportPort.of(80); /* Decimal transport port number; not associated with any specific protocol. */
TransportPort tp2 = TransportPort.of(-1); /* Throws IllegalArgumentException; not possible to get a TransportPort outside MAX_PORT and MIN_PORT. */
TransportPort tp3 = TransportPort.MAX_PORT;
TransportPort tp4 = TransportPort.MIN_PORT;


int raw = tp1.getPort(); /* Get integer port value. */

Others include VlanVid, OFGroup, TableId, U8, U16, U32, U64, U128, and many more... please check out org.projectfloodlight.openflow.types for the complete list and API. Javadoc for OpenFlowJ-Loxi is available here.