Changes between Version 5 and Version 6 of Internal/OpenFlow/VendorTutorial


Ignore:
Timestamp:
Dec 28, 2012, 5:17:15 AM (11 years ago)
Author:
akoshibe
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Internal/OpenFlow/VendorTutorial

    v5 v6  
    11= How-To: Extending OpenFlow with Vendor messages =
    2 !OpenFlow provides a vendor message type as a way to offer third parties a way to customize the protocol without going out of spec. This tutorial attempts to describe the openflowj implementations of the vendor type message and how to use them in Floodlight. We'll mostly use snippets of the Nicira vendor messages, found in org.openflow.vendor.nicira, as examples in this page.
     2This tutorial attempts to describe how to use the !OpenFlow vendor message to create custom messages. We first provide an overview of the message structure. We then describe the vendor message implementations found in openflowj, the Java implementations of the !OpenFlow protocol used in Floodlight and !FlowVisor.
    33
    4 == Overview ==
     4We'll mostly use snippets of the Nicira vendor messages, found in org.openflow.vendor.nicira of the Floodlight source, as working examples in this page. The Nicira extensions add !OpenFlow role features, introduced in !OpenFlow v1.2, to the v1.0 protocol used in Floodlight.
     5
     6== 1. Overview: The Vendor Message ==
     7!OpenFlow provides a vendor message type as a way to offer third parties a way to customize the protocol without going out of spec. Although called the "Vendor message", this message type provides a handy way for a developer to implement and test out experimental features without wantonly modifying the protocol.
     8
    59Vendor messages are identified by !OpenFlow message type (OFType) value of 4. In addition to the standard !OpenFlow header, The vendor type message has its own message header and a fully customizable payload. 
    610
    7 A vendor message header contains a vendor ID and a data type. The vendor ID identifies the vendor implementing the custom message, and is typically the OUI of the vendor. The data type is used to indicate any subtypes that this message may have. For example, Nicira's vendor messages use Nicira's OUI (002320) as the vendor ID and come in two types, a Request and Reply, indicated by the data types of "10" and "11".
     11A vendor message header contains a vendor ID and a data type. The vendor ID identifies the vendor implementing the custom message, and is typically the organizationally unique identifier (OUI) of the vendor. As an individual, you can randomly pick and use an integral value for this purpose and nothing would balk at this, but this is highly discouraged. The proper conduct for this case is either to use your institution's OUI (if it has one), or to apply for an ID from the Open Networking Foundation (see [https://www.opennetworking.org/wiki/display/PUBLIC/ONF+Registry here] for details).   
    812
    9 The rest of the message is the vendor message payload, and can be freely defined. To sum it up, the full !OpenFlow vendor message takes on the following format:
    10 {{{
    11 <-------OpenFlow header-------><---Vendor message header--><----Vendor message payload----->
    12 [OF ver(1)|OFType(1)|length(2)][Vendor ID(2-8)|dataType(4)][user-defined structures(varied)]
    13 }}}
    14 Where the numbers in the parenthesis denote the field size in Bytes. The Vendor message header and payloads, in combination, make up the full payload of the vendor message.
     13The data type is used to indicate any subtypes that this message may have. For example, Nicira's vendor messages use Nicira's OUI (002320) as the vendor ID and comes in two types, a Request and Reply, indicated by the data type values of "10" and "11".
    1514
    16 == In openflowj ==
    17 The base interface and framework needed for defining vendor messages are found in the package org.openflow.protocol.vendor.
     15The rest of the message is the vendor message payload, and can be freely defined. To sum it up, the full !OpenFlow vendor message takes on the following general format:
     16 {{{
     17    |<------OpenFlow header------>||<----------------------Vendor Data------------------------>|
     18    |                             ||<-Vendor message header-->||<---Vendor message payload---->|
     19    [OF ver(1)|OFType(1)|length(2)][Vendor ID(2-8)|dataType(4)][user-defined structures(varied)]
     20 }}}
     21Where the numbers in the parenthesis denote the field size in bytes. The vendor message header and payload in combination make up the full payload of the !OpenFlow message, the vendor data.
    1822
    19 `OFVendorData` is the Java interface for the full payload. All vendor type messages must implement `OFVendorData`. The vendor message header is typically defined in the class that implements this interface. As an example, the vendor ID and data type are part of `OFNiciraVendorData`, the base class for all Nicira vendor messages:
     23== 2. In openflowj == #iface
     24In openflowj, the base interface and framework needed for creating vendor messages are found in the package org.openflow.protocol.vendor. Specifically, openflowj provides developers with a way to define custom vendor data classes. 
     25
     26`OFVendorData` is the Java interface required by any class defining custom vendor data. `OFVendorData` imposes just a few methods on a class implementing it:
     27 
     28 * getLength() : return length of the data
     29 * readFrom(!ChannelBuffer data, int length) : Read the vendor data from the specified !ChannelBuffer
     30 * writeTo(!ChannelBuffer data) : Write the vendor data to the specified !ChannelBuffer
     31
     32These methods are needed for the serialization/deserialization of the message.
     33
     34=== 2.1 The Vendor Message Header ===
     35What we're referring to as the vendor message header is typically a set of variables defined in the class that implements `OFVendorData`. The class in which these variables are declared typically becomes the base class for further message types.
     36
     37For example, the vendor ID and data type are part of `OFNiciraVendorData`, the base class for all Nicira vendor messages:
    2038{{{
    2139public class OFNiciraVendorData implements OFVendorData {
     
    2947...
    3048}}}
    31 This base class is extended to implement the Request and Reply message types (OFRoleRequestVendorData and OFRoleReplyVendorData, respectively). 
     49This class is extended to implement the Request and Reply message types (`OFRoleRequestVendorData` and `OFRoleReplyVendorData`, respectively). Note how the value of dataType is not set here - this value is set with the values declared in each subclass, as we can see here in    `OFRoleReplyVendorData`:
     50{{{
     51    /**
     52     * The data type value for a role reply
     53     */
     54    public static final int NXT_ROLE_REPLY = 11;
    3255
    33 The Vendor ID and data type are the only requirements in terms of vendor header content. The rest may be structured as needed, such as various message fields, getters and setters, and !ChannelBuffer manipulators, which we'll discuss in the section on [#serial serialization]. 
     56    /**
     57     * Construct a role reply vendor data with an unspecified role value.
     58     */
     59    public OFRoleReplyVendorData() {
     60        super(NXT_ROLE_REPLY);
     61    }
     62}}}
     63super() refers to `OFRoleVendorData`, a subclass of `OFNiciraVendorData`. Tracing back a step further, we end up in `OFNiciraVendorData` whose constructor sets the value of dataType:
     64{{{
     65   /**
     66     * Contruct Nicira vendor data with the specified data type
     67     * @param dataType the data type value at the beginning of the vendor data.
     68     */
     69    public OFNiciraVendorData(int dataType) {
     70        this.dataType = dataType;
     71    }
     72}}}
    3473
    35 === Message Registration ===
    36 The Vendor ID and message classes must be registered before it can properly be parsed. This is a two step process:
     74The Vendor ID and data type are the only requirements in terms of vendor header content. Given that the methods required by `OFVendorData` are provided, along with those required for message registration, the message implementation may be structured as needed. The usual additions are various message fields and their getters and setters. 
     75
     76=== 2.2 Message Registration ===
     77As expected from the variable structure of vendor messages, a given vendor message must be registered before openflowj can handle it properly. Registration is a two step process:
     78
    3779 1. Vendor ID registration
    3880 2. Message type registration
    3981
    40 We cn confirm this by taking a look at the method ''initVendorMessages()'' from Floodlight's core controller class `Controller`. We see that (1) the vendor ID is registered first, and (2) followed by each subclass representing a message type:
     82We can see this by taking a look at the method ''initVendorMessages()'' from Floodlight's core controller class `Controller`. We see that (1) the vendor ID is registered first, and (2),(3) followed by each class representing a message type:
    4183{{{
    4284    // Configure openflowj to be able to parse the role request/reply vendor messages.
     
    5395        niciraVendorId.registerVendorDataType(roleRequestVendorData);
    5496   
    55    //then the repy
     97   // then the reply
    5698        OFBasicVendorDataType roleReplyVendorData =                          (3)
    5799                new OFBasicVendorDataType(
     
    61103
    62104}}}
    63 Where NXT_ROLE_REQUEST and NXT_ROLE_REPLY are the request and reply data type values for the two Nicira vendor message data types.
     105Where, as seen earlier, NXT_ROLE_REQUEST and NXT_ROLE_REPLY are the request and reply data type values for the two Nicira vendor message data types.
    64106
    65 Several things to point out here:
    66  * Since vendor IDs may vary in length, we indicate the length in bytes that the vendor ID is when we instantiate the OFBasicVendorId. In (1) we provide the constructor with the value 4 along with the actual Vendor ID, indicating that the Nicira vendor ID is an integer (4 bytes long).
     107There are several things to point out here:
     108 1. Since vendor IDs may vary in length, we indicate the length in bytes that the vendor ID is when we instantiate the OFBasicVendorId. In (1) we provide the constructor with the value 4 along with the actual Vendor ID, indicating that the Nicira vendor ID is an integer (4 bytes long).
    67109 
    68  * As seen above in (2) and (3), the class implementing the vendor data should be instantiable, so that it can be registered properly. The method getInstantiable() should be available in your message classes for this purpose. The following snippet was taken from `OFRoleRequestVendorData`, but the structure will pretty much be the same for any vendor data class (e.g. replace OFRoleRequestVendorData below with your class):
     110 2. As seen above in (2) and (3), the class implementing the vendor data should include the method ''getInstantiable()''. `OFBasicVendorDataType`, is a container for an instantiator of a `OFVendorData` subclass. By allowing the custom class to provide it a format, `OFBasicVendorDataType` avoids making assumptions about the structure of the message payload.   
     111
     1122. indicates that we also need a ''getInstantiable()'' in our vendor data. The following snippet was taken from `OFRoleRequestVendorData`, but the structure will pretty much be the same for any vendor data class (e.g. replace OFRoleRequestVendorData below with your class):
    69113{{{
    70114    protected static Instantiable<OFVendorData> instantiable =
     
    83127    }
    84128}}}
    85 A non-registered Vendor message data payload is interpreted simply as a byte array (OFByteArrayVendorData to be precise), and cannot be cast to your message (sub)class(es) for further handling.
     129A non-registered Vendor message data payload is interpreted simply as a byte array (OFByteArrayVendorData to be precise), and cannot be cast to your message (sub)class(es) for further handling. Aside from throwing a !ClassCastException, this is inconvenient since you won't be able to invoke the class methods specific to your vendor data class for message-specific processing. 
    86130
    87 === Message Serialization === #serial
    88 Each class implementing OFVendorData must have a readFrom(!ChannelBuffer data, int length) and writeTo(!ChannelBuffer data) method for reading and writing the data from/to a !ChannelBuffer. A getLength() method that returns the size of the messages is also required for reading. This value does not count the !OpenFlow header, which is added in by helper methods to produce the full message length. The message length must be correct in order for it to be processed by the !OpenFlow channel pipeline.
     131=== 2.3 Message Serialization === #serial
     132As mentioned [#iface earlier], a class implementing OFVendorData must have a readFrom(!ChannelBuffer data, int length) and writeTo(!ChannelBuffer data) method for reading and writing the data from/to a !ChannelBuffer. A getLength() method that returns the size of the vendor data sans the Vendor ID in bytes is also required for properly reading/writing from the !ChannelBuffer. We do not count the !OpenFlow header length since helper methods take it into account along with the Vendor ID length to produce the full message length.
    89133
    90 The packet structure is determined by the order in which the various fields are written to the !ChannelBuffer, so readFrom() and writeTo() should read/write the fields in the same order.
     134The packet structure is determined by the order in which the various fields are written to the !ChannelBuffer, so readFrom() and writeTo() should read/write the fields to/from the !ChannelBuffer in the same order.
    91135
    92 == In Floodlight ==
    93 Floodlight uses openflowj as its !OpenFlow implementation. Custom vendor messages are usually placed in their own packages, such as org.openflow.vendor.nicira for Nicira messages. Message registration occurs, as mentioned before, in method ''initVendorMessages()'' in `Controller.java`, found in net.floodlightcontroller.core.internal.
     136As an example, we can look at `OFRoleVendorData`, the parent class of the Nicira Request and Reply messages. Since both messages only differ in the values of the ''role'' field, the readFrom(), writeTo(), and getLength() methods for the final packet structure are defined in this class. The message structure looks like this:
     137{{{
     138                     |<-Vendor ID->||<-dataType->|<----payload(4)--->|                             
     139    [OpenFlow Header][ 0x00002320  ][    10|11   ][      0|1|2       ]
     140}}}
     141Where the values within the square brackets separated by pipes are the various decimal values that the fields can take. What we had dubbed the vendor payload is one integral value of 4 bytes, used to indicate controller role. The packet structure is reflected in readFrom() and writeTo():
     142{{{
     143    public void readFrom(ChannelBuffer data, int length) {
     144        super.readFrom(data, length);
     145        role = data.readInt();
     146    }
     147
     148    public void writeTo(ChannelBuffer data) {
     149        super.writeTo(data);
     150        data.writeInt(role);
     151    }
     152}}}
     153super() points to `OFNiciraVendorData`, which takes care of reading and writing the integral dataType field:
     154{{{
     155    @Override
     156    public void readFrom(ChannelBuffer data, int length) {
     157        dataType = data.readInt();
     158    }
     159
     160    @Override
     161    public void writeTo(ChannelBuffer data) {
     162        data.writeInt(dataType);
     163    }
     164}}}
     165
     166As for getLength(), the total returned is the length of the two fields (8 bytes). looking at the two classes side-by-side makes this clear. First `OFRoleVendorData`:
     167{{{
     168    @Override
     169    public int getLength() {
     170        return super.getLength() + 4;
     171    }
     172}}}
     173Then `OFNiciraVendorData`:
     174{{{
     175    @Override
     176    public int getLength() {
     177        return 4;
     178    }
     179}}}