-
Notifications
You must be signed in to change notification settings - Fork 6
Warp OpenFlow Driver vs. OpenFlowJ
#Warp OpenFlow Driver vs. OpenFlowJ
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.
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.
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());
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 */
OFMessageFlowModRef fmRef = buildFlowModMsg();
fmRef.addMatchInPort("128");
/* And so on, and so forth */
OFStructureInstructionRef instrRef = provider.buildInstructionApplyActions();
instrRef.addActionOutput("12");