Skip to content

Warp OpenFlow Driver vs. OpenFlowJ

Dmitry-Orekhov edited this page Jan 27, 2014 · 21 revisions

#Warp OpenFlow Driver vs. OpenFlowJ

Introduction

The main difference Warp OpenFlow Driver from OpenFlowJ is how OpenFlow messages are built and serialized. OpenFlowJ represents OpenFlow messages using POJOs. Serialization/deserialization is performing using writeTo() and readFrom() methods. So if you need to change or update a protocol like bugs fixing, new version introduction and so on, you should change these methods, modifying size of fields, structures, order of serialization them inside a message, and recompile the code getting new binaries.

In Warp OpenFlow driver all information about messages and structures (size, order) is concentrated in Avro JSON file (*.avpr by default). Then you should build a Message provider instance and initialize it:

provider.init();

and the you can use Provider instance to serialize/deserialize OpenFlow messages according to new version of the OF protocol.
It gives some advantages. First of all, in JSON is more clear to see the whole protocol: size, orders etc.
For instance, Avro protocol file which describes OFP Hello message may looks like:

{ "namespace" :"of",
  "protocol":"ofp",
  "types":[
   {"name":"uint_8", "type":"fixed", "size":1},
   {"name":"uint_16", "type":"fixed", "size":2},
   {"name":"uint_32", "type":"fixed", "size":4},

   {"name":"ofp_type",
    "type":"enum",
    "items":"uint_8",
    "list":[
     {"name":"OFPT_HELLO", "default":[0]},
     {"name":"OFPT_ERROR",  "default":[1]}
    ]
   },
   
   {"name":"ofp_length",
    "type":"enum",
    "items":"uint_16",
    "list":[
     {"name":"OFPL_HELLO_LEN", "default":[0,8]},
     {"name":"OFPL_ERROR_LEN", "default":[0,16]}
    ]
   },

   {"name":"ofp_hello_header",
    "type":"record",
    "fields":[
      {"name":"version", "type":"uint_8", "default":[4]},
      {"name":"type", "type":"ofp_type", "default":"OFPT_HELLO"},
      {"name":"length", "type":"ofp_length", "default":"OFPL_HELLO_LEN"},
      {"name":"xid", "type":"uint_32", "default":[0,0,0,0]}
    ]
   },
   
   {"name":"ofp_hello",
    "type":"record",
    "fields":[
      {"name":"header", "type":"ofp_hello_header"}
    ]
   },  
  ]
}

Listing 1. Avro protocol file
You don’t need to recompile the code to make changes in the protocol, like bug fixing, new features introduction etc. What you need is to change Avro protocol file and re-initialize Message provider.

Message Provider

The key element of Warp OpenFlow driver is the OpenFlow Message provider. It is the class which encapsulates all necessary information about OpenFlow protocol. It implements the interface:

import org.flowforwarding.warp.protocol.ofmessages.IOFMessageProvider;

You should use a Factory to create a provider. You can get the Provider instance with two ways, using Version string and Byte array containing incoming Hello message:

public IOFMessageProvider getMessageProvider(String version);
public IOFMessageProvider getMessageProvider(byte[] hello);

So the code to create an OFP Hello message based on incoming OFP Hello message is:

byte[] incomingHello; /* This array should contain incoming message */
/*---------------------------------------------------------------------------------*/
IOFMessageProviderFactory factory = new OFMessageProviderFactoryAvroProtocol();
IOFMessageProvider provider = factory.getMessageProvider(incomingHello);
provider.init();

This code creates and initializes Message Provider instance, and this Provider will provide OpenFlow messages the same version as the incoming Hello message.

OFP Hello message creation: OpenFlowJ and Warp ways

The quickest and simplest example is to create a Hello message. With OpenFlowJ:

factory = new BasicFactory();
hello1 = (OFHello)factory.getMessage(OFType.HELLO);

Then you can serialize it using writeTo method:

public void writeTo(ChannelBuffer data);

Using Warp, to do the same you should:

IOFMessageProviderFactory factory = new OFMessageProviderFactoryAvroProtocol(); 
IOFMessageProvider provider = factory.getMessageProvider("1.3");
provider.init();

The code above should be performed once, during initialization. Then you just use provider:

byte [] hello = provider.encodeHelloMessage()); 

OpenFlow Flow Mod message: OpenFlowJ vs. Warp way

Message building with OpenFlowJ

OFFlowMod fm = (OFFlowMod) factory.getMessage(OFType.FLOW_MOD);

OFMatch match = new OFMatch();
match.setWildcards(OFMatch.OFPFW_ALL);

// Ingress Port
short inPort = 128;
match.setInputPort(inPort.value());

}
/* And so on, and so forth */

Message building with Warp

OFMessageFlowModRef fmRef = buildFlowModMsg();

fmRef.addMatchInPort("128");
/* And so on, and so forth */

OFStructureInstructionRef instrRef = provider.buildInstructionApplyActions();
instrRef.addActionOutput("12");
/* And so on, and so forth */

fmRef.addInstuction(instrRef);
byte [] fmBuffer = provider.encodeFlowMod(fmRef);