--- /dev/null
+OpenFlow Protocol Library Developer Guide
+=========================================
+
+Introduction
+------------
+
+OpenFlow Protocol Library is component in OpenDaylight, that mediates
+communication between OpenDaylight controller and hardware devices
+supporting OpenFlow protocol. Primary goal is to provide user (or upper
+layers of OpenDaylight) communication channel, that can be used for
+managing network hardware devices.
+
+Features Overview
+-----------------
+
+There are three features inside openflowjava:
+
+- **odl-openflowjava-protocol** provides all openflowjava bundles, that
+ are needed for communication with openflow devices. It ensures
+ message translation and handles network connections. It also provides
+ openflow protocol specific model.
+
+- **odl-openflowjava-all** currently contains only
+ odl-openflowjava-protocol feature.
+
+- **odl-openflowjava-stats** provides mechanism for message counting
+ and reporting. Can be used for performance analysis.
+
+odl-openflowjava-protocol Architecture
+--------------------------------------
+
+Basic bundles contained in this feature are openflow-protocol-api,
+openflow-protocol-impl, openflow-protocol-spi and util.
+
+- **openflow-protocol-api** - contains openflow model, constants and
+ keys used for (de)serializer registration.
+
+- **openflow-protocol-impl** - contains message factories, that
+ translate binary messages into DataObjects and vice versa. Bundle
+ also contains network connection handlers - servers, netty pipeline
+ handlers, …
+
+- **openflow-protocol-spi** - entry point for openflowjava
+ configuration, startup and close. Basically starts implementation.
+
+- **util** - utility classes for binary-Java conversions and to ease
+ experimenter key creation
+
+odl-openflowjava-stats Feature
+------------------------------
+
+Runs over odl-openflowjava-protocol. It counts various message types /
+events and reports counts in specified time periods. Statistics
+collection can be configured in
+openflowjava-config/src/main/resources/45-openflowjava-stats.xml
+
+Key APIs and Interfaces
+-----------------------
+
+Basic API / SPI classes are ConnectionAdapter (Rpc/notifications) and
+SwitchConnectionProcider (configure, start, shutdown)
+
+Installation
+------------
+
+Pull the code and import project into your IDE.
+
+::
+
+ git clone ssh://<username>@git.opendaylight.org:29418/openflowjava.git
+
+Configuration
+-------------
+
+Current implementation allows to configure:
+
+- listening port (mandatory)
+
+- transfer protocol (mandatory)
+
+- switch idle timeout (mandatory)
+
+- TLS configuration (optional)
+
+- thread count (optional)
+
+You can find exemplary Openflow Protocol Library instance configuration
+below:
+
+::
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <!-- default OF-switch-connection-provider (port 6633) -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">prefix:openflow-switch-connection-provider-impl</type>
+ <name>openflow-switch-connection-provider-default-impl</name>
+ <port>6633</port>
+ <!-- Possible transport-protocol options: TCP, TLS, UDP -->
+ <transport-protocol>TCP</transport-protocol>
+ <switch-idle-timeout>15000</switch-idle-timeout>
+ <!-- Exemplary TLS configuration:
+ - uncomment the <tls> tag
+ - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
+ files into your virtual machine
+ - set VM encryption options to use copied keys
+ - start communication
+ Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
+ for detailed information regarding TLS -->
+ <!-- <tls>
+ <keystore>/exemplary-ctlKeystore</keystore>
+ <keystore-type>JKS</keystore-type>
+ <keystore-path-type>CLASSPATH</keystore-path-type>
+ <keystore-password>opendaylight</keystore-password>
+ <truststore>/exemplary-ctlTrustStore</truststore>
+ <truststore-type>JKS</truststore-type>
+ <truststore-path-type>CLASSPATH</truststore-path-type>
+ <truststore-password>opendaylight</truststore-password>
+ <certificate-password>opendaylight</certificate-password>
+ </tls> -->
+ <!-- Exemplary thread model configuration. Uncomment <threads> tag below to adjust default thread model -->
+ <!-- <threads>
+ <boss-threads>2</boss-threads>
+ <worker-threads>8</worker-threads>
+ </threads> -->
+ </module>
+
+::
+
+ <!-- default OF-switch-connection-provider (port 6653) -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">prefix:openflow-switch-connection-provider-impl</type>
+ <name>openflow-switch-connection-provider-legacy-impl</name>
+ <port>6653</port>
+ <!-- Possible transport-protocol options: TCP, TLS, UDP -->
+ <transport-protocol>TCP</transport-protocol>
+ <switch-idle-timeout>15000</switch-idle-timeout>
+ <!-- Exemplary TLS configuration:
+ - uncomment the <tls> tag
+ - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
+ files into your virtual machine
+ - set VM encryption options to use copied keys
+ - start communication
+ Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
+ for detailed information regarding TLS -->
+ <!-- <tls>
+ <keystore>/exemplary-ctlKeystore</keystore>
+ <keystore-type>JKS</keystore-type>
+ <keystore-path-type>CLASSPATH</keystore-path-type>
+ <keystore-password>opendaylight</keystore-password>
+ <truststore>/exemplary-ctlTrustStore</truststore>
+ <truststore-type>JKS</truststore-type>
+ <truststore-path-type>CLASSPATH</truststore-path-type>
+ <truststore-password>opendaylight</truststore-password>
+ <certificate-password>opendaylight</certificate-password>
+ </tls> -->
+ <!-- Exemplary thread model configuration. Uncomment <threads> tag below to adjust default thread model -->
+ <!-- <threads>
+ <boss-threads>2</boss-threads>
+ <worker-threads>8</worker-threads>
+ </threads> -->
+ </module>
+
+::
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl">prefix:openflow-provider-impl</type>
+ <name>openflow-provider-impl</name>
+ <openflow-switch-connection-provider>
+ <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
+ <name>openflow-switch-connection-provider-default</name>
+ </openflow-switch-connection-provider>
+ <openflow-switch-connection-provider>
+ <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
+ <name>openflow-switch-connection-provider-legacy</name>
+ </openflow-switch-connection-provider>
+ <binding-aware-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+ <name>binding-osgi-broker</name>
+ </binding-aware-broker>
+ </module>
+ </modules>
+
+Possible transport-protocol options:
+
+- TCP
+
+- TLS
+
+- UDP
+
+Switch-idle timeout specifies time needed to detect idle state of
+switch. When no message is received from switch within this time, upper
+layers are notified on switch idleness. To be able to use this exemplary
+TLS configuration:
+
+- uncomment the ``<tls>`` tag
+
+- copy *exemplary-switch-privkey.pem*, *exemplary-switch-cert.pem* and
+ *exemplary-cacert.pem* files into your virtual machine
+
+- set VM encryption options to use copied keys (please visit TLS
+ support wiki page for detailed information regarding TLS)
+
+- start communication
+
+Thread model configuration specifies how many threads are desired to
+perform Netty’s I/O operations.
+
+- boss-threads specifies the number of threads that register incoming
+ connections
+
+- worker-threads specifies the number of threads performing read /
+ write (+ serialization / deserialization) operations.
+
+Architecture
+------------
+
+Public API ``(openflow-protocol-api)``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set of interfaces and builders for immutable data transfer objects
+representing Openflow Protocol structures.
+
+Transfer objects and service APIs are infered from several YANG models
+using code generator to reduce verbosity of definition and repeatibility
+of code.
+
+The following YANG modules are defined:
+
+- openflow-types - defines common Openflow specific types
+
+- openflow-instruction - defines base Openflow instructions
+
+- openflow-action - defines base Openflow actions
+
+- openflow-augments - defines object augmentations
+
+- openflow-extensible-match - defines Openflow OXM match
+
+- openflow-protocol - defines Openflow Protocol messages
+
+- system-notifications - defines system notification objects
+
+- openflow-configuration - defines structures used in ConfigSubsystem
+
+This modules also reuse types from following YANG modules:
+
+- ietf-inet-types - IP adresses, IP prefixes, IP-protocol related types
+
+- ietf-yang-types - Mac Address, etc.
+
+The use of predefined types is to make APIs contracts more safe, better
+readable and documented (e.g using MacAddress instead of byte array…)
+
+TCP Channel pipeline ``(openflow-protocol-impl)``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Creates channel processing pipeline based on configuration and support.
+
+**TCP Channel pipeline.**
+
+imageopenflowjava/500px-TCPChannelPipeline.png[width=500]
+
+**Switch Connection Provider.**
+
+Implementation of connection point for other projects. Library exposes
+its functionality through this class. Library can be configured, started
+and shutdowned here. There are also methods for custom (de)serializer
+registration.
+
+**Tcp Connection Initializer.**
+
+In order to initialize TCP connection to a device (switch), OF Plugin
+calls method ``initiateConnection()`` in ``SwitchConnectionProvider``.
+This method in turn initializes (Bootstrap) server side channel towards
+the device.
+
+**TCP Handler.**
+
+Represents single server that is handling incoming connections over TCP
+/ TLS protocol. TCP Handler creates a single instance of TCP Channel
+Initializer that will initialize channels. After that it binds to
+configured InetAddress and port. When a new device connects, TCP Handler
+registers its channel and passes control to TCP Channel Initializer.
+
+**TCP Channel Initializer.**
+
+This class is used for channel initialization / rejection and passing
+arguments. After a new channel has been registered it calls Switch
+Connection Handler’s (OF Plugin) accept method to decide if the library
+should keep the newly registered channel or if the channel should be
+closed. If the channel has been accepted, TCP Channel Initializer
+creates the whole pipeline with needed handlers and also with
+ConnectionAdapter instance. After the channel pipeline is ready, Switch
+Connection Handler is notified with ``onConnectionReady`` notification.
+OpenFlow Plugin can now start sending messages downstream.
+
+**Idle Handler.**
+
+If there are no messages received for more than time specified, this
+handler triggers idle state notification. The switch idle timeout is
+received as a parameter from ConnectionConfiguration settings. Idle
+State Handler is inactive while there are messages received within the
+switch idle timeout. If there are no messages received for more than
+timeout specified, handler creates SwitchIdleEvent message and sends it
+upstream.
+
+**TLS Handler.**
+
+It encrypts and decrypts messages over TLS protocol. Engaging TLS
+Handler into pipeline is matter of configuration (``<tls>`` tag). TLS
+communication is either unsupported or required. TLS Handler is
+represented as a Netty’s SslHandler.
+
+**OF Frame Decoder.**
+
+Parses input stream into correct length message frames for further
+processing. Framing is based on Openflow header length. If received
+message is shorter than minimal length of OpenFlow message (8 bytes), OF
+Frame Decoder waits for more data. After receiving at least 8 bytes the
+decoder checks length in OpenFlow header. If there are still some bytes
+missing, the decoder waits for them. Else the OF Frame Decoder sends
+correct length message to next handler in the channel pipeline.
+
+**OF Version Detector.**
+
+Detects version of used OpenFlow Protocol and discards unsupported
+version messages. If the detected version is supported, OF Version
+Detector creates ``VersionMessageWrapper`` object containing the
+detected version and byte message and sends this object upstream.
+
+**OF Decoder.**
+
+Chooses correct deserilization factory (based on message type) and
+deserializes messages into generated DTOs (Data Transfer Object). OF
+Decoder receives ``VersionMessageWrapper`` object and passes it to
+``DeserializationFactory`` which will return translated DTO.
+``DeserializationFactory`` creates ``MessageCodeKey`` object with
+version and type of received message and Class of object that will be
+the received message deserialized into. This object is used as key when
+searching for appropriate decoder in ``DecoderTable``. ``DecoderTable``
+is basically a map storing decoders. Found decoder translates received
+message into DTO. If there was no decoder found, null is returned. After
+returning translated DTO back to OF Decoder, the decoder checks if it is
+null or not. When the DTO is null, the decoder logs this state and
+throws an Exception. Else it passes the DTO further upstream. Finally,
+the OF Decoder releases ByteBuf containing received and decoded byte
+message.
+
+**OF Encoder.**
+
+Chooses correct serialization factory (based on type of DTO) and
+serializes DTOs into byte messages. OF Encoder does the opposite than
+the OF Decoder using the same principle. OF Encoder receives DTO, passes
+it for translation and if the result is not null, it sends translated
+DTO downstream as a ByteBuf. Searching for appropriate encoder is done
+via MessageTypeKey, based on version and class of received DTO.
+
+**Delegating Inbound Handler.**
+
+Delegates received DTOs to Connection Adapter. It also reacts on
+channelInactive and channelUnregistered events. Upon one of these events
+is triggered, DelegatingInboundHandler creates DisconnectEvent message
+and sends it upstream, notifying upper layers about switch
+disconnection.
+
+**Channel Outbound Queue.**
+
+Message flushing handler. Stores outgoing messages (DTOs) and flushes
+them. Flush is performed based on time expired and on the number of
+messages enqueued.
+
+**Connection Adapter.**
+
+Provides a facade on top of pipeline, which hides netty.io specifics.
+Provides a set of methods to register for incoming messages and to send
+messages to particular channel / session. ConnectionAdapterImpl
+basically implements three interfaces (unified in one superinterface
+ConnectionFacade):
+
+- ConnectionAdapter
+
+- MessageConsumer
+
+- OpenflowProtocolService
+
+**ConnectionAdapter** interface has methods for setting up listeners
+(message, system and connection ready listener), method to check if all
+listeners are set, checking if the channel is alive and disconnect
+method. Disconnect method clears responseCache and disables consuming of
+new messages.
+
+**MessageConsumer** interface holds only one method: ``consume()``.
+``Consume()`` method is called from DelegatingInboundHandler. This
+method processes received DTO’s based on their type. There are three
+types of received objects:
+
+- System notifications - invoke system notifications in OpenFlow Plugin
+ (systemListener set). In case of ``DisconnectEvent`` message, the
+ Connection Adapter clears response cache and disables consume()
+ method processing,
+
+- OpenFlow asynchronous messages (from switch) - invoke corresponding
+ notifications in OpenFlow Plugin,
+
+- OpenFlow symmetric messages (replies to requests) - create
+ ``RpcResponseKey`` with XID and DTO’s class set. This
+ ``RpcResponseKey`` is then used to find corresponding future object
+ in responseCache. Future object is set with success flag, received
+ message and errors (if any occurred). In case no corresponding future
+ was found in responseCache, Connection Adapter logs warning and
+ discards the message. Connection Adapter also logs warning when an
+ unknown DTO is received.
+
+**OpenflowProtocolService** interface contains all rpc-methods for
+sending messages from upper layers (OpenFlow Plugin) downstream and
+responding. Request messages return Future filled with expected reply
+message, otherwise the expected Future is of type Void.
+
+**NOTE:** MultipartRequest message is the only exception. Basically it
+is request - reply Message type, but it wouldn’t be able to process more
+following MultipartReply messages if this was implemented as rpc (only
+one Future). This is why MultipartReply is implemented as notification.
+OpenFlow Plugin takes care of correct message processing.
+
+UDP Channel pipeline (openflow-protocol-impl)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Creates UDP channel processing pipeline based on configuration and
+support. **Switch Connection Provider**, **Channel Outbound Queue** and
+**Connection Adapter** fulfill the same role as in case of TCP
+connection / channel pipeline (please see above).
+
+.. figure:: ./images/openflowjava/500px-UdpChannelPipeline.png
+ :alt: UDP Channel pipeline
+
+ UDP Channel pipeline
+
+**UDP Handler.**
+
+Represents single server that is handling incoming connections over UDP
+(DTLS) protocol. UDP Handler creates a single instance of UDP Channel
+Initializer that will initialize channels. After that it binds to
+configured InetAddress and port. When a new device connects, UDP Handler
+registers its channel and passes control to UDP Channel Initializer.
+
+**UDP Channel Initializer.**
+
+This class is used for channel initialization and passing arguments.
+After a new channel has been registered (for UDP there is always only
+one channel) UDP Channel Initializer creates whole pipeline with needed
+handlers.
+
+**DTLS Handler.**
+
+Haven’t been implemented yet. Will take care of secure DTLS connections.
+
+**OF Datagram Packet Handler.**
+
+Combines functionality of OF Frame Decoder and OF Version Detector.
+Extracts messages from received datagram packets and checks if message
+version is supported. If there is a message received from yet unknown
+sender, OF Datagram Packet Handler creates Connection Adapter for this
+sender and stores it under sender’s address in ``UdpConnectionMap``.
+This map is also used for sending the messages and for correct
+Connection Adapter lookup - to delegate messages from one channel to
+multiple sessions.
+
+**OF Datagram Packet Decoder.**
+
+Chooses correct deserilization factory (based on message type) and
+deserializes messages into generated DTOs. OF Decoder receives
+``VersionMessageUdpWrapper`` object and passes it to
+``DeserializationFactory`` which will return translated DTO.
+``DeserializationFactory`` creates ``MessageCodeKey`` object with
+version and type of received message and Class of object that will be
+the received message deserialized into. This object is used as key when
+searching for appropriate decoder in ``DecoderTable``. ``DecoderTable``
+is basically a map storing decoders. Found decoder translates received
+message into DTO (DataTransferObject). If there was no decoder found,
+null is returned. After returning translated DTO back to OF Datagram
+Packet Decoder, the decoder checks if it is null or not. When the DTO is
+null, the decoder logs this state. Else it looks up appropriate
+Connection Adapter in ``UdpConnectionMap`` and passes the DTO to found
+Connection Adapter. Finally, the OF Decoder releases ``ByteBuf``
+containing received and decoded byte message.
+
+**OF Datagram Packet Encoder.**
+
+Chooses correct serialization factory (based on type of DTO) and
+serializes DTOs into byte messages. OF Datagram Packet Encoder does the
+opposite than the OF Datagram Packet Decoder using the same principle.
+OF Encoder receives DTO, passes it for translation and if the result is
+not null, it sends translated DTO downstream as a datagram packet.
+Searching for appropriate encoder is done via MessageTypeKey, based on
+version and class of received DTO.
+
+SPI (openflow-protocol-spi)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Defines interface for library’s connection point for other projects.
+Library exposes its functionality through this interface.
+
+Integration test (openflow-protocol-it)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Testing communication with simple client.
+
+Simple client(simple-client)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Lightweight switch simulator - programmable with desired scenarios.
+
+Utility (util)
+~~~~~~~~~~~~~~
+
+Contains utility classes, mainly for work with ByteBuf.
+
+Library’s lifecycle
+-------------------
+
+Steps (after the library’s bundle is started):
+
+- [1] Library is configured by ConfigSubsystem (adress, ports,
+ encryption, …)
+
+- [2] Plugin injects its SwitchConnectionHandler into the Library
+
+- [3] Plugin starts the Library
+
+- [4] Library creates configured protocol handler (e.g. TCP Handler)
+
+- [5] Protocol Handler creates Channel Initializer
+
+- [6] Channel Initializer asks plugin whether to accept incoming
+ connection on each new switch connection
+
+- [7] Plugin responds:
+
+ - true - continue building pipeline
+
+ - false - reject connection / disconnect channel
+
+- [8] Library notifies Plugin with onSwitchConnected(ConnectionAdapter)
+ notification, passing reference to ConnectionAdapter, that will
+ handle the connection
+
+- [9] Plugin registers its system and message listeners
+
+- [10] FireConnectionReadyNotification() is triggered, announcing that
+ pipeline handlers needed for communication have been created and
+ Plugin can start communication
+
+- [11] Plugin shutdowns the Library when desired
+
+.. figure:: ./images/openflowjava/Library_lifecycle.png
+ :alt: Library lifecycle
+
+ Library lifecycle
+
+Statistics collection
+---------------------
+
+Introduction
+~~~~~~~~~~~~
+
+Statistics collection collects message statistics. Current collected
+statistics (``DS`` - downstream, ``US`` - upstream):
+
+- ``DS_ENTERED_OFJAVA`` - all messages that entered openflowjava
+ (picked up from openflowplugin)
+
+- ``DS_ENCODE_SUCCESS`` - successfully encoded messages
+
+- ``DS_ENCODE_FAIL`` - messages that failed during encoding
+ (serialization) process
+
+- ``DS_FLOW_MODS_ENTERED`` - all flow-mod messages that entered
+ openflowjava
+
+- ``DS_FLOW_MODS_SENT`` - all flow-mod messages that were successfully
+ sent
+
+- ``US_RECEIVED_IN_OFJAVA`` - messages received from switch
+
+- ``US_DECODE_SUCCESS`` - successfully decoded messages
+
+- ``US_DECODE_FAIL`` - messages that failed during decoding
+ (deserialization) process
+
+- ``US_MESSAGE_PASS`` - messages handed over to openflowplugin
+
+Karaf
+~~~~~
+
+In orded to start statistics, it is needed to feature:install
+odl-openflowjava-stats. To see the logs one should use log:set DEBUG
+org.opendaylight.openflowjava.statistics and than probably log:display
+(you can log:list to see if the logging has been set). To adjust
+collection settings it is enough to modify 45-openflowjava-stats.xml.
+
+JConsole
+~~~~~~~~
+
+JConsole provides two commands for the statistics collection:
+
+- printing current statistics
+
+- resetting statistic counters
+
+After attaching JConsole to correct process, one only needs to go into
+MBeans
+``tab → org.opendaylight.controller → RuntimeBean → statistics-collection-service-impl
+→ statistics-collection-service-impl → Operations`` to be able to use
+this commands.
+
+TLS Support
+-----------
+
+ **Note**
+
+ see OpenFlow Plugin Developper Guide
+
+Extensibility
+-------------
+
+Introduction
+~~~~~~~~~~~~
+
+Entry point for the extensibility is ``SwitchConnectionProvider``.
+``SwitchConnectionProvider`` contains methods for (de)serializer
+registration. To register deserializer it is needed to use
+.register\*Deserializer(key, impl). To register serializer one must use
+.register\*Serializer(key, impl). Registration can occur either during
+configuration or at runtime.
+
+**NOTE**: In case when experimenter message is received and no
+(de)serializer was registered, the library will throw
+``IllegalArgumentException``.
+
+Basic Principle
+~~~~~~~~~~~~~~~
+
+In order to use extensions it is needed to augment existing model and
+register new (de)serializers.
+
+Augmenting the model: 1. Create new augmentation
+
+Register (de)serializers: 1. Create your (de)serializer 2. Let it
+implement ``OFDeserializer<>`` / ``OFSerializer<>`` - in case the
+structure you are (de)serializing needs to be used in Multipart
+TableFeatures messages, let it implement ``HeaderDeserializer<>`` /
+``HeaderSerializer`` 3. Implement prescribed methods 4. Register your
+deserializer under appropriate key (in our case
+``ExperimenterActionDeserializerKey``) 5. Register your serializer under
+appropriate key (in our case ``ExperimenterActionSerializerKey``) 6.
+Done, test your implementation
+
+**NOTE**: If you don’t know what key should be used with your
+(de)serializer implementation, please visit `Registration
+keys <#registration_keys>`__ page.
+
+Example
+~~~~~~~
+
+Let’s say we have vendor / experimenter action represented by this
+structure:
+
+::
+
+ struct foo_action {
+ uint16_t type;
+ uint16_t length;
+ uint32_t experimenter;
+ uint16_t first;
+ uint16_t second;
+ uint8_t pad[4];
+ }
+
+First, we have to augment existing model. We create new module, which
+imports "``openflow-types.yang``" (don’t forget to update your
+``pom.xml`` with api dependency). Now we create foo action identity:
+
+::
+
+ import openflow-types {prefix oft;}
+ identity foo {
+ description "Foo action description";
+ base oft:action-base;
+ }
+
+This will be used as type in our structure. Now we must augment existing
+action structure, so that we will have the desired fields first and
+second. In order to create new augmentation, our module has to import
+"``openflow-action.yang``". The augment should look like this:
+
+::
+
+ import openflow-action {prefix ofaction;}
+ augment "/ofaction:actions-container/ofaction:action" {
+ ext:augment-identifier "foo-action";
+ leaf first {
+ type uint16;
+ }
+ leaf second {
+ type uint16;
+ }
+ }
+
+We are finished with model changes. Run mvn clean compile to generate
+sources. After generation is done, we need to implement our
+(de)serializer.
+
+Deserializer:
+
+::
+
+ public class FooActionDeserializer extends OFDeserializer<Action> {
+ @Override
+ public Action deserialize(ByteBuf input) {
+ ActionBuilder builder = new ActionBuilder();
+ input.skipBytes(SIZE_OF_SHORT_IN_BYTES); *// we know the type of action*
+ builder.setType(Foo.class);
+ input.skipBytes(SIZE_OF_SHORT_IN_BYTES); *// we don't need length*
+ *// now create experimenterIdAugmentation - so that openflowplugin can
+ differentiate correct vendor codec*
+ ExperimenterIdActionBuilder expIdBuilder = new ExperimenterIdActionBuilder();
+ expIdBuilder.setExperimenter(new ExperimenterId(input.readUnsignedInt()));
+ builder.addAugmentation(ExperimenterIdAction.class, expIdBuilder.build());
+ FooActionBuilder fooBuilder = new FooActionBuilder();
+ fooBuilder.setFirst(input.readUnsignedShort());
+ fooBuilder.setSecond(input.readUnsignedShort());
+ builder.addAugmentation(FooAction.class, fooBuilder.build());
+ input.skipBytes(4); *// padding*
+ return builder.build();
+ }
+ }
+
+Serializer:
+
+::
+
+ public class FooActionSerializer extends OFSerializer<Action> {
+ @Override
+ public void serialize(Action action, ByteBuf outBuffer) {
+ outBuffer.writeShort(FOO_CODE);
+ outBuffer.writeShort(16);
+ *// we don't have to check for ExperimenterIdAction augmentation - our
+ serializer*
+ *// was called based on the vendor / experimenter ID, so we simply write
+ it to buffer*
+ outBuffer.writeInt(VENDOR / EXPERIMENTER ID);
+ FooAction foo = action.getAugmentation(FooAction.class);
+ outBuffer.writeShort(foo.getFirst());
+ outBuffer.writeShort(foo.getSecond());
+ outBuffer.writeZero(4); //write padding
+ }
+ }
+
+Register both deserializer and serializer:
+``SwitchConnectionProvider.registerDeserializer(new
+ExperimenterActionDeserializerKey(0x04, VENDOR / EXPERIMENTER ID),
+new FooActionDeserializer());``
+``SwitchConnectionProvider.registerSerializer(new
+ExperimenterActionSerializerKey(0x04, VENDOR / EXPERIMENTER ID),
+new FooActionSerializer());``
+
+We are ready to test our implementation.
+
+**NOTE:** Vendor / Experimenter structures define only vendor /
+experimenter ID as common distinguisher (besides action type). Vendor /
+Experimenter ID is unique for all vendor messages - that’s why vendor is
+able to register only one class under
+ExperimenterAction(De)SerializerKey. And that’s why vendor has to switch
+/ choose between his subclasses / subtypes on his own.
+
+Detailed walkthrough: Deserialization extensibility
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**External interface & class description.**
+
+**OFGeneralDeserializer:**
+
+- ``OFDeserializer<E extends DataObject>``
+
+ - *deserialize(ByteBuf)* - deserializes given ByteBuf
+
+- ``HeaderDeserializer<E extends DataObject>``
+
+ - *deserializeHeaders(ByteBuf)* - deserializes only E headers (used
+ in Multipart TableFeatures messages)
+
+**DeserializerRegistryInjector**
+
+- ``injectDeserializerRegistry(DeserializerRegistry)`` - injects
+ deserializer registry into deserializer. Useful when custom
+ deserializer needs access to other deserializers.
+
+**NOTE:** DeserializerRegistryInjector is not OFGeneralDeserializer
+descendand. It is a standalone interface.
+
+**MessageCodeKey and its descendants** These keys are used as for
+deserializer lookup in DeserializerRegistry. MessageCodeKey should is
+used in general, while its descendants are used in more special cases.
+For Example ActionDeserializerKey is used for Action deserializer lookup
+and (de)registration. Vendor is provided with special keys, which
+contain only the most necessary fields. These keys usually start with
+"Experimenter" prefix (MatchEntryDeserializerKey is an exception).
+
+MessageCodeKey has these fields:
+
+- short version - Openflow wire version number
+
+- int value - value read from byte message
+
+- Class<?> clazz - class of object being creating
+
+- [1] The scenario starts in a custom bundle which wants to extend
+ library’s functionality. The custom bundle creates deserializers
+ which implement exposed ``OFDeserializer`` / ``HeaderDeserializer``
+ interfaces (wrapped under ``OFGeneralDeserializer`` unifying super
+ interface).
+
+- [2] Created deserializers are paired with corresponding
+ ExperimenterKeys, which are used for deserializer lookup. If you
+ don’t know what key should be used with your (de)serializer
+ implementation, please visit `Registration
+ keys <#registration_keys>`__ page.
+
+- [3] Paired deserializers are passed to the OF Library via
+ **SwitchConnectionProvider**.\ *registerCustomDeserializer(key,
+ impl)*. Library registers the deserializer.
+
+ - While registering, Library checks if the deserializer is an
+ instance of **DeserializerRegistryInjector** interface. If yes,
+ the DeserializerRegistry (which stores all deserializer
+ references) is injected into the deserializer.
+
+This is particularly useful when the deserializer needs access to other
+deserializers. For example ``IntructionsDeserializer`` needs access to
+``ActionsDeserializer`` in order to be able to process
+OFPIT\_WRITE\_ACTIONS/OFPIT\_APPLY\_ACTIONS instructions.
+
+.. figure:: ./images/openflowjava/800px-Extensibility.png
+ :alt: Deserialization scenario walkthrough
+
+ Deserialization scenario walkthrough
+
+Detailed walkthrough: Serialization extensibility
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**External interface & class description.**
+
+**OFGeneralSerializer:**
+
+- OFSerializer<E extends DataObject>
+
+ - *serialize(E,ByteBuf)* - serializes E into given ByteBuf
+
+- ``HeaderSerializer<E extends DataObject>``
+
+ - *serializeHeaders(E,ByteBuf)* - serializes E headers (used in
+ Multipart TableFeatures messages)
+
+**SerializerRegistryInjector** \*
+``injectSerializerRegistry(SerializerRegistry)`` - injects serializer
+registry into serializer. Useful when custom serializer needs access to
+other serializers.
+
+**NOTE:** SerializerRegistryInjector is not OFGeneralSerializer
+descendand.
+
+**MessageTypeKey and its descendants** These keys are used as for
+serializer lookup in SerializerRegistry. MessageTypeKey should is used
+in general, while its descendants are used in more special cases. For
+Example ActionSerializerKey is used for Action serializer lookup and
+(de)registration. Vendor is provided with special keys, which contain
+only the most necessary fields. These keys usually start with
+"Experimenter" prefix (MatchEntrySerializerKey is an exception).
+
+MessageTypeKey has these fields:
+
+- *short version* - Openflow wire version number
+
+- *Class<E> msgType* - DTO class
+
+Scenario walkthrough
+
+- [1] Serialization extensbility principles are similar to the
+ deserialization principles. The scenario starts in a custom bundle.
+ The custom bundle creates serializers which implement exposed
+ OFSerializer / HeaderSerializer interfaces (wrapped under
+ OFGeneralSerializer unifying super interface).
+
+- [2] Created serializers are paired with their ExperimenterKeys, which
+ are used for serializer lookup. If you don’t know what key should be
+ used with your serializer implementation, please visit `Registration
+ keys <#registration_keys>`__ page.
+
+- [3] Paired serializers are passed to the OF Library via
+ **SwitchConnectionProvider**.\ *registerCustomSerializer(key, impl)*.
+ Library registers the serializer.
+
+- While registering, Library checks if the serializer is an instance of
+ **SerializerRegistryInjector** interface. If yes, the
+ SerializerRegistry (which stores all serializer references) is
+ injected into the serializer.
+
+This is particularly useful when the serializer needs access to other
+deserializers. For example IntructionsSerializer needs access to
+ActionsSerializer in order to be able to process
+OFPIT\_WRITE\_ACTIONS/OFPIT\_APPLY\_ACTIONS instructions.
+
+.. figure:: ./images/openflowjava/800px-Extensibility2.png
+ :alt: Serialization scenario walkthrough
+
+ Serialization scenario walkthrough
+
+Internal description
+~~~~~~~~~~~~~~~~~~~~
+
+**SwitchConnectionProvider** ``SwitchConnectionProvider`` constructs and
+initializes both deserializer and serializer registries with default
+(de)serializers. It also injects the ``DeserializerRegistry`` into the
+``DeserializationFactory``, the ``SerializerRegistry`` into the
+``SerializationFactory``. When call to register custom (de)serializer is
+made, ``SwitchConnectionProvider`` calls register method on appropriate
+registry.
+
+**DeserializerRegistry / SerializerRegistry** Both registries contain
+init() method to initialize default (de)serializers. Registration checks
+if key or (de)serializer implementation are not ``null``. If at least
+one of the is ``null``, ``NullPointerException`` is thrown. Else the
+(de)serializer implementation is checked if it is
+``(De)SerializerRegistryInjector`` instance. If it is an instance of
+this interface, the registry is injected into this (de)serializer
+implementation.
+
+``GetSerializer(key)`` or ``GetDeserializer(key)`` performs registry
+lookup. Because there are two separate interfaces that might be put into
+the registry, the registry uses their unifying super interface.
+Get(De)Serializer(key) method casts the super interface to desired type.
+There is also a null check for the (de)serializer received from the
+registry. If the deserializer wasn’t found, ``NullPointerException``
+with key description is thrown.
+
+Registration keys
+~~~~~~~~~~~~~~~~~
+
+**Deserialization.**
+
+**Possible openflow extensions and their keys**
+
+There are three vendor specific extensions in Openflow v1.0 and eight in
+Openflow v1.3. These extensions are registered under registration keys,
+that are shown in table below:
+
++----------------+---------+------------------------------+-----------------------+
+| Extension type | OpenFlo | Registration key | Utility class |
+| | w | | |
++================+=========+==============================+=======================+
+| Vendor message | 1.0 | ExperimenterIdDeserializerKe | ExperimenterDeseriali |
+| | | y(1, | zerKeyFactory |
+| | | experimenterId, | |
+| | | ExperimenterMessage.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Action | 1.0 | ExperimenterActionDeserializ | . |
+| | | erKey(1, | |
+| | | experimenter ID) | |
++----------------+---------+------------------------------+-----------------------+
+| Stats message | 1.0 | ExperimenterMultipartReplyMe | ExperimenterDeseriali |
+| | | ssageDeserializerKey(1, | zerKeyFactory |
+| | | experimenter ID) | |
++----------------+---------+------------------------------+-----------------------+
+| Experimenter | 1.3 | ExperimenterIdDeserializerKe | ExperimenterDeseriali |
+| message | | y(4, | zerKeyFactory |
+| | | experimenterId, | |
+| | | ExperimenterMessage.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Match entry | 1.3 | MatchEntryDeserializerKey(4, | . |
+| | | (number) ${oxm\_class}, | |
+| | | (number) ${oxm\_field}); | |
++----------------+---------+------------------------------+-----------------------+
+| | | key.setExperimenterId(experi | . |
+| | | menter | |
+| | | ID); | |
++----------------+---------+------------------------------+-----------------------+
+| Action | 1.3 | ExperimenterActionDeserializ | . |
+| | | erKey(4, | |
+| | | experimenter ID) | |
++----------------+---------+------------------------------+-----------------------+
+| Instruction | 1.3 | ExperimenterInstructionDeser | . |
+| | | ializerKey(4, | |
+| | | experimenter ID) | |
++----------------+---------+------------------------------+-----------------------+
+| Multipart | 1.3 | ExperimenterIdDeserializerKe | ExperimenterDeseriali |
+| | | y(4, | zerKeyFactory |
+| | | experimenterId, | |
+| | | MultipartReplyMessage.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Multipart - | 1.3 | ExperimenterIdDeserializerKe | ExperimenterDeseriali |
+| Table features | | y(4, | zerKeyFactory |
+| | | experimenterId, | |
+| | | TableFeatureProperties.class | |
+| | | ) | |
++----------------+---------+------------------------------+-----------------------+
+| Error | 1.3 | ExperimenterIdDeserializerKe | ExperimenterDeseriali |
+| | | y(4, | zerKeyFactory |
+| | | experimenterId, | |
+| | | ErrorMessage.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Queue property | 1.3 | ExperimenterIdDeserializerKe | ExperimenterDeseriali |
+| | | y(4, | zerKeyFactory |
+| | | experimenterId, | |
+| | | QueueProperty.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Meter band | 1.3 | ExperimenterIdDeserializerKe | ExperimenterDeseriali |
+| type | | y(4, | zerKeyFactory |
+| | | experimenterId, | |
+| | | MeterBandExperimenterCase.cl | |
+| | | ass) | |
++----------------+---------+------------------------------+-----------------------+
+
+Table: **Deserialization**
+
+**Serialization.**
+
+**Possible openflow extensions and their keys**
+
+There are three vendor specific extensions in Openflow v1.0 and seven
+Openflow v1.3. These extensions are registered under registration keys,
+that are shown in table below:
+
++----------------+---------+------------------------------+-----------------------+
+| Extension type | OpenFlo | Registration key | Utility class |
+| | w | | |
++================+=========+==============================+=======================+
+| Vendor message | 1.0 | ExperimenterIdSerializerKey< | ExperimenterSerialize |
+| | | >(1, | rKeyFactory |
+| | | experimenterId, | |
+| | | ExperimenterInput.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Action | 1.0 | ExperimenterActionSerializer | . |
+| | | Key(1, | |
+| | | experimenterId, sub-type) | |
++----------------+---------+------------------------------+-----------------------+
+| Stats message | 1.0 | ExperimenterMultipartRequest | ExperimenterSerialize |
+| | | SerializerKey(1, | rKeyFactory |
+| | | experimenter ID) | |
++----------------+---------+------------------------------+-----------------------+
+| Experimenter | 1.3 | ExperimenterIdSerializerKey< | ExperimenterSerialize |
+| message | | >(4, | rKeyFactory |
+| | | experimenterId, | |
+| | | ExperimenterInput.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Match entry | 1.3 | MatchEntrySerializerKey<>(4, | . |
+| | | (class) ${oxm\_class}, | |
+| | | (class) ${oxm\_field}); | |
++----------------+---------+------------------------------+-----------------------+
+| | | key.setExperimenterId(experi | . |
+| | | menter | |
+| | | ID) | |
++----------------+---------+------------------------------+-----------------------+
+| Action | 1.3 | ExperimenterActionSerializer | . |
+| | | Key(4, | |
+| | | experimenterId, sub-type) | |
++----------------+---------+------------------------------+-----------------------+
+| Instruction | 1.3 | ExperimenterInstructionSeria | . |
+| | | lizerKey(4, | |
+| | | experimenter ID) | |
++----------------+---------+------------------------------+-----------------------+
+| Multipart | 1.3 | ExperimenterIdSerializerKey< | ExperimenterSerialize |
+| | | >(4, | rKeyFactory |
+| | | experimenterId, | |
+| | | MultipartRequestExperimenter | |
+| | | Case.class) | |
++----------------+---------+------------------------------+-----------------------+
+| Multipart - | 1.3 | ExperimenterIdSerializerKey< | ExperimenterSerialize |
+| Table features | | >(4, | rKeyFactory |
+| | | experimenterId, | |
+| | | TableFeatureProperties.class | |
+| | | ) | |
++----------------+---------+------------------------------+-----------------------+
+| Meter band | 1.3 | ExperimenterIdSerializerKey< | ExperimenterSerialize |
+| type | | >(4, | rKeyFactory |
+| | | experimenterId, | |
+| | | MeterBandExperimenterCase.cl | |
+| | | ass) | |
++----------------+---------+------------------------------+-----------------------+
+
+Table: **Serialization**
+
== OpenFlow Protocol Library Developer Guide
-=== Introduction
-OpenFlow Protocol Library is component in OpenDaylight, that mediates communication
-between OpenDaylight controller and hardware devices supporting OpenFlow protocol.
-Primary goal is to provide user (or upper layers of OpenDaylight) communication
-channel, that can be used for managing network hardware devices.
-
-=== Features Overview
-There are three features inside openflowjava:
-
-* *odl-openflowjava-protocol* provides all openflowjava bundles, that are needed
-for communication with openflow devices. It ensures message translation and
-handles network connections. It also provides openflow protocol specific
-model.
-* *odl-openflowjava-all* currently contains only odl-openflowjava-protocol feature.
-* *odl-openflowjava-stats* provides mechanism for message counting and reporting.
-Can be used for performance analysis.
-
-=== odl-openflowjava-protocol Architecture
-Basic bundles contained in this feature are openflow-protocol-api,
-openflow-protocol-impl, openflow-protocol-spi and util.
-
-* *openflow-protocol-api* - contains openflow model, constants and keys used for
-(de)serializer registration.
-* *openflow-protocol-impl* - contains message factories, that translate binary
-messages into DataObjects and vice versa. Bundle also contains network connection
-handlers - servers, netty pipeline handlers, ...
-* *openflow-protocol-spi* - entry point for openflowjava configuration,
-startup and close. Basically starts implementation.
-* *util* - utility classes for binary-Java conversions and to ease experimenter
-key creation
-
-=== odl-openflowjava-stats Feature
-Runs over odl-openflowjava-protocol. It counts various message types / events
-and reports counts in specified time periods. Statistics collection can be
-configured in openflowjava-config/src/main/resources/45-openflowjava-stats.xml
-
-=== Key APIs and Interfaces
-Basic API / SPI classes are ConnectionAdapter (Rpc/notifications) and
-SwitchConnectionProcider (configure, start, shutdown)
-
-//=== API Reference Documentation
-//Provide links to JavaDoc, REST API documentation, etc. [TBD]
-
-=== Installation ===
-Pull the code and import project into your IDE.
-----
-git clone ssh://<username>@git.opendaylight.org:29418/openflowjava.git
-----
-=== Configuration ===
-Current implementation allows to configure:
-
-* listening port (mandatory)
-* transfer protocol (mandatory)
-* switch idle timeout (mandatory)
-* TLS configuration (optional)
-* thread count (optional)
-
-You can find exemplary Openflow Protocol Library instance configuration below:
-----
-<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <!-- default OF-switch-connection-provider (port 6633) -->
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">prefix:openflow-switch-connection-provider-impl</type>
- <name>openflow-switch-connection-provider-default-impl</name>
- <port>6633</port>
-<!-- Possible transport-protocol options: TCP, TLS, UDP -->
- <transport-protocol>TCP</transport-protocol>
- <switch-idle-timeout>15000</switch-idle-timeout>
-<!-- Exemplary TLS configuration:
- - uncomment the <tls> tag
- - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
- files into your virtual machine
- - set VM encryption options to use copied keys
- - start communication
- Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
- for detailed information regarding TLS -->
-<!-- <tls>
- <keystore>/exemplary-ctlKeystore</keystore>
- <keystore-type>JKS</keystore-type>
- <keystore-path-type>CLASSPATH</keystore-path-type>
- <keystore-password>opendaylight</keystore-password>
- <truststore>/exemplary-ctlTrustStore</truststore>
- <truststore-type>JKS</truststore-type>
- <truststore-path-type>CLASSPATH</truststore-path-type>
- <truststore-password>opendaylight</truststore-password>
- <certificate-password>opendaylight</certificate-password>
- </tls> -->
-<!-- Exemplary thread model configuration. Uncomment <threads> tag below to adjust default thread model -->
-<!-- <threads>
- <boss-threads>2</boss-threads>
- <worker-threads>8</worker-threads>
- </threads> -->
- </module>
-----
-----
- <!-- default OF-switch-connection-provider (port 6653) -->
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">prefix:openflow-switch-connection-provider-impl</type>
- <name>openflow-switch-connection-provider-legacy-impl</name>
- <port>6653</port>
-<!-- Possible transport-protocol options: TCP, TLS, UDP -->
- <transport-protocol>TCP</transport-protocol>
- <switch-idle-timeout>15000</switch-idle-timeout>
-<!-- Exemplary TLS configuration:
- - uncomment the <tls> tag
- - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
- files into your virtual machine
- - set VM encryption options to use copied keys
- - start communication
- Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
- for detailed information regarding TLS -->
-<!-- <tls>
- <keystore>/exemplary-ctlKeystore</keystore>
- <keystore-type>JKS</keystore-type>
- <keystore-path-type>CLASSPATH</keystore-path-type>
- <keystore-password>opendaylight</keystore-password>
- <truststore>/exemplary-ctlTrustStore</truststore>
- <truststore-type>JKS</truststore-type>
- <truststore-path-type>CLASSPATH</truststore-path-type>
- <truststore-password>opendaylight</truststore-password>
- <certificate-password>opendaylight</certificate-password>
- </tls> -->
-<!-- Exemplary thread model configuration. Uncomment <threads> tag below to adjust default thread model -->
-<!-- <threads>
- <boss-threads>2</boss-threads>
- <worker-threads>8</worker-threads>
- </threads> -->
- </module>
-----
-----
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl">prefix:openflow-provider-impl</type>
- <name>openflow-provider-impl</name>
- <openflow-switch-connection-provider>
- <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
- <name>openflow-switch-connection-provider-default</name>
- </openflow-switch-connection-provider>
- <openflow-switch-connection-provider>
- <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
- <name>openflow-switch-connection-provider-legacy</name>
- </openflow-switch-connection-provider>
- <binding-aware-broker>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
- <name>binding-osgi-broker</name>
- </binding-aware-broker>
- </module>
- </modules>
-----
-Possible transport-protocol options:
-
-* TCP
-* TLS
-* UDP
-
-Switch-idle timeout specifies time needed to detect idle state of switch. When
-no message is received from switch within this time, upper layers are notified
-on switch idleness.
-To be able to use this exemplary TLS configuration:
-
-* uncomment the +<tls>+ tag
-* copy _exemplary-switch-privkey.pem_, _exemplary-switch-cert.pem_ and
-_exemplary-cacert.pem_ files into your virtual machine
-* set VM encryption options to use copied keys (please visit TLS support wiki page
-for detailed information regarding TLS)
-* start communication
-
-Thread model configuration specifies how many threads are desired to perform
-Netty's I/O operations.
-
-* boss-threads specifies the number of threads that register incoming connections
-* worker-threads specifies the number of threads performing read / write
-(+ serialization / deserialization) operations.
-
-
-=== Architecture
-
-==== Public API +(openflow-protocol-api)+
-Set of interfaces and builders for immutable data transfer objects representing
-Openflow Protocol structures.
-
-Transfer objects and service APIs are infered from several YANG models
-using code generator to reduce verbosity of definition and repeatibility of code.
-
-The following YANG modules are defined:
-
-* openflow-types - defines common Openflow specific types
-* openflow-instruction - defines base Openflow instructions
-* openflow-action - defines base Openflow actions
-* openflow-augments - defines object augmentations
-* openflow-extensible-match - defines Openflow OXM match
-* openflow-protocol - defines Openflow Protocol messages
-* system-notifications - defines system notification objects
-* openflow-configuration - defines structures used in ConfigSubsystem
-
-This modules also reuse types from following YANG modules:
-
-* ietf-inet-types - IP adresses, IP prefixes, IP-protocol related types
-* ietf-yang-types - Mac Address, etc.
-
-The use of predefined types is to make APIs contracts more safe, better readable
-and documented (e.g using MacAddress instead of byte array...)
-
-==== TCP Channel pipeline +(openflow-protocol-impl)+
-
-Creates channel processing pipeline based on configuration and support.
-
-.TCP Channel pipeline
-imageopenflowjava/500px-TCPChannelPipeline.png[width=500]
-
-.Switch Connection Provider
-Implementation of connection point for other projects. Library exposes its
-functionality through this class.
-Library can be configured, started and shutdowned here. There are also methods
-for custom (de)serializer registration.
-
-.Tcp Connection Initializer
-In order to initialize TCP connection to a device (switch), OF Plugin calls method
-+initiateConnection()+ in +SwitchConnectionProvider+. This method in turn initializes
-(Bootstrap) server side channel towards the device.
-
-.TCP Handler
-Represents single server that is handling incoming connections over TCP / TLS protocol.
-TCP Handler creates a single instance of TCP Channel Initializer that will initialize
-channels. After that it binds to configured InetAddress and port. When a new
-device connects, TCP Handler registers its channel and passes control to
-TCP Channel Initializer.
-
-.TCP Channel Initializer
-This class is used for channel initialization / rejection and passing arguments.
-After a new channel has been registered it calls Switch Connection Handler's
-(OF Plugin) accept method to decide if the library should keep the newly registered
-channel or if the channel should be closed. If the channel has been accepted,
-TCP Channel Initializer creates the whole pipeline with needed handlers and also
-with ConnectionAdapter instance. After the channel pipeline is ready, Switch
-Connection Handler is notified with +onConnectionReady+ notification.
-OpenFlow Plugin can now start sending messages downstream.
-
-.Idle Handler
-If there are no messages received for more than time specified, this handler
-triggers idle state notification.
-The switch idle timeout is received as a parameter from ConnectionConfiguration
-settings. Idle State Handler is inactive while there are messages received within
-the switch idle timeout. If there are no messages received for more than timeout
-specified, handler creates SwitchIdleEvent message and sends it upstream.
-
-.TLS Handler
-It encrypts and decrypts messages over TLS protocol.
-Engaging TLS Handler into pipeline is matter of configuration (+<tls>+ tag).
-TLS communication is either unsupported or required. TLS Handler is represented
-as a Netty's SslHandler.
-
-.OF Frame Decoder
-Parses input stream into correct length message frames for further processing.
-Framing is based on Openflow header length. If received message is shorter than
-minimal length of OpenFlow message (8 bytes), OF Frame Decoder waits for more data.
-After receiving at least 8 bytes the decoder checks length in OpenFlow header.
-If there are still some bytes missing, the decoder waits for them. Else the OF
-Frame Decoder sends correct length message to next handler in the channel pipeline.
-
-.OF Version Detector
-Detects version of used OpenFlow Protocol and discards unsupported version messages.
-If the detected version is supported, OF Version Detector creates
-+VersionMessageWrapper+ object containing the detected version and byte message
-and sends this object upstream.
-
-.OF Decoder
-Chooses correct deserilization factory (based on message type) and deserializes
-messages into generated DTOs (Data Transfer Object).
-OF Decoder receives +VersionMessageWrapper+ object and passes it to
-+DeserializationFactory+ which will return translated DTO. +DeserializationFactory+
-creates +MessageCodeKey+ object with version and type of received message and
-Class of object that will be the received message deserialized into. This object
-is used as key when searching for appropriate decoder in +DecoderTable+.
-+DecoderTable+ is basically a map storing decoders. Found decoder translates
-received message into DTO. If there was no decoder found, null is returned. After
-returning translated DTO back to OF Decoder, the decoder checks if it is null or not.
-When the DTO is null, the decoder logs this state and throws an Exception. Else it
-passes the DTO further upstream. Finally, the OF Decoder releases ByteBuf containing
-received and decoded byte message.
-
-.OF Encoder
-Chooses correct serialization factory (based on type of DTO) and serializes DTOs
-into byte messages.
-OF Encoder does the opposite than the OF Decoder using the same principle.
-OF Encoder receives DTO, passes it for translation and if the result is not null,
-it sends translated DTO downstream as a ByteBuf. Searching for appropriate encoder
-is done via MessageTypeKey, based on version and class of received DTO.
-
-.Delegating Inbound Handler
-Delegates received DTOs to Connection Adapter.
-It also reacts on channelInactive and channelUnregistered events. Upon one of
-these events is triggered, DelegatingInboundHandler creates DisconnectEvent message
-and sends it upstream, notifying upper layers about switch disconnection.
-
-.Channel Outbound Queue
-Message flushing handler.
-Stores outgoing messages (DTOs) and flushes them. Flush is performed based on time
-expired and on the number of messages enqueued.
-
-.Connection Adapter
-Provides a facade on top of pipeline, which hides netty.io specifics. Provides a
-set of methods to register for incoming messages and to send messages to particular
-channel / session.
-ConnectionAdapterImpl basically implements three interfaces (unified in one
-superinterface ConnectionFacade):
-
-* ConnectionAdapter
-* MessageConsumer
-* OpenflowProtocolService
-
-
-*ConnectionAdapter* interface has methods for setting up listeners (message,
-system and connection ready listener), method to check if all listeners are set,
-checking if the channel is alive and disconnect method. Disconnect method clears
-responseCache and disables consuming of new messages.
-
-*MessageConsumer* interface holds only one method: +consume()+. +Consume()+ method
-is called from DelegatingInboundHandler. This method processes received DTO's based
-on their type. There are three types of received objects:
-
-* System notifications - invoke system notifications in OpenFlow Plugin
-(systemListener set). In case of +DisconnectEvent+ message, the Connection Adapter
-clears response cache and disables consume() method processing,
-* OpenFlow asynchronous messages (from switch) - invoke corresponding notifications
-in OpenFlow Plugin,
-* OpenFlow symmetric messages (replies to requests) - create +RpcResponseKey+
-with XID and DTO's class set. This +RpcResponseKey+ is then used to find
-corresponding future object in responseCache. Future object is set with success
-flag, received message and errors (if any occurred). In case no corresponding
-future was found in responseCache, Connection Adapter logs warning and discards
-the message. Connection Adapter also logs warning when an unknown DTO is received.
-
-*OpenflowProtocolService* interface contains all rpc-methods for sending messages
-from upper layers (OpenFlow Plugin) downstream and responding. Request messages
-return Future filled with expected reply message, otherwise the expected Future
-is of type Void.
-
-*NOTE:*
-MultipartRequest message is the only exception. Basically it is request - reply
-Message type, but it wouldn't be able to process more following MultipartReply
-messages if this was implemented as rpc (only one Future). This is why MultipartReply
-is implemented as notification. OpenFlow Plugin takes care of correct message
-processing.
-
-
-==== UDP Channel pipeline (openflow-protocol-impl)
-Creates UDP channel processing pipeline based on configuration and support.
-*Switch Connection Provider*, *Channel Outbound Queue* and *Connection Adapter*
-fulfill the same role as in case of TCP connection / channel pipeline (please
-see above).
-
-.UDP Channel pipeline
-image::openflowjava/500px-UdpChannelPipeline.png[width=500]
-
-.UDP Handler
-
-Represents single server that is handling incoming connections over UDP (DTLS)
-protocol.
-UDP Handler creates a single instance of UDP Channel Initializer that will
-initialize channels. After that it binds to configured InetAddress and port.
-When a new device connects, UDP Handler registers its channel and passes control
-to UDP Channel Initializer.
-
-.UDP Channel Initializer
-This class is used for channel initialization and passing arguments.
-After a new channel has been registered (for UDP there is always only one channel)
-UDP Channel Initializer creates whole pipeline with needed handlers.
-
-.DTLS Handler
-Haven't been implemented yet. Will take care of secure DTLS connections.
-
-.OF Datagram Packet Handler
-Combines functionality of OF Frame Decoder and OF Version Detector. Extracts
-messages from received datagram packets and checks if message version is supported.
-If there is a message received from yet unknown sender, OF Datagram Packet Handler
-creates Connection Adapter for this sender and stores it under sender's address in
-+UdpConnectionMap+. This map is also used for sending the messages and for correct
-Connection Adapter lookup - to delegate messages from one channel to multiple sessions.
-
-.OF Datagram Packet Decoder
-Chooses correct deserilization factory (based on message type) and deserializes
-messages into generated DTOs.
-OF Decoder receives +VersionMessageUdpWrapper+ object and passes it to
-+DeserializationFactory+ which will return translated DTO. +DeserializationFactory+
-creates +MessageCodeKey+ object with version and type of received message and
-Class of object that will be the received message deserialized into. This object
-is used as key when searching for appropriate decoder in +DecoderTable+.
-+DecoderTable+ is basically a map storing decoders. Found decoder translates
-received message into DTO (DataTransferObject). If there was no decoder found,
-null is returned. After returning translated DTO back to OF Datagram Packet Decoder,
-the decoder checks if it is null or not. When the DTO is null, the decoder logs
-this state. Else it looks up appropriate Connection Adapter in +UdpConnectionMap+
-and passes the DTO to found Connection Adapter. Finally, the OF Decoder releases
-+ByteBuf+ containing received and decoded byte message.
-
-.OF Datagram Packet Encoder
-Chooses correct serialization factory (based on type of DTO) and serializes DTOs
-into byte messages.
-OF Datagram Packet Encoder does the opposite than the OF Datagram Packet Decoder
-using the same principle. OF Encoder receives DTO, passes it for translation and
-if the result is not null, it sends translated DTO downstream as a datagram packet.
-Searching for appropriate encoder is done via MessageTypeKey, based on version
-and class of received DTO.
-
-==== SPI (openflow-protocol-spi)
-Defines interface for library's connection point for other projects. Library
-exposes its functionality through this interface.
-
-==== Integration test (openflow-protocol-it)
-Testing communication with simple client.
-
-==== Simple client(simple-client)
-Lightweight switch simulator - programmable with desired scenarios.
-
-==== Utility (util)
-Contains utility classes, mainly for work with ByteBuf.
-
-
-=== Library's lifecycle
-
-Steps (after the library's bundle is started):
-
-* [1] Library is configured by ConfigSubsystem (adress, ports, encryption, ...)
-* [2] Plugin injects its SwitchConnectionHandler into the Library
-* [3] Plugin starts the Library
-* [4] Library creates configured protocol handler (e.g. TCP Handler)
-* [5] Protocol Handler creates Channel Initializer
-* [6] Channel Initializer asks plugin whether to accept incoming connection on
-each new switch connection
-* [7] Plugin responds:
- - true - continue building pipeline
- - false - reject connection / disconnect channel
-* [8] Library notifies Plugin with onSwitchConnected(ConnectionAdapter)
-notification, passing reference to ConnectionAdapter, that will handle the connection
-* [9] Plugin registers its system and message listeners
-* [10] FireConnectionReadyNotification() is triggered, announcing that pipeline
-handlers needed for communication have been created and Plugin can start
-communication
-* [11] Plugin shutdowns the Library when desired
-
-.Library lifecycle
-image::openflowjava/Library_lifecycle.png[width=500]
-
-
-=== Statistics collection
-
-==== Introduction
-Statistics collection collects message statistics.
-Current collected statistics (+DS+ - downstream, +US+ - upstream):
-
-* +DS_ENTERED_OFJAVA+ - all messages that entered openflowjava (picked up from
-openflowplugin)
-* +DS_ENCODE_SUCCESS+ - successfully encoded messages
-* +DS_ENCODE_FAIL+ - messages that failed during encoding (serialization) process
-* +DS_FLOW_MODS_ENTERED+ - all flow-mod messages that entered openflowjava
-* +DS_FLOW_MODS_SENT+ - all flow-mod messages that were successfully sent
-* +US_RECEIVED_IN_OFJAVA+ - messages received from switch
-* +US_DECODE_SUCCESS+ - successfully decoded messages
-* +US_DECODE_FAIL+ - messages that failed during decoding (deserialization) process
-* +US_MESSAGE_PASS+ - messages handed over to openflowplugin
-
-==== Karaf
-In orded to start statistics, it is needed to feature:install odl-openflowjava-stats.
-To see the logs one should use log:set DEBUG org.opendaylight.openflowjava.statistics
-and than probably log:display (you can log:list to see if the logging has been set).
-To adjust collection settings it is enough to modify 45-openflowjava-stats.xml.
-
-==== JConsole
-JConsole provides two commands for the statistics collection:
-
-* printing current statistics
-* resetting statistic counters
-
-After attaching JConsole to correct process, one only needs to go into MBeans
-+tab -> org.opendaylight.controller -> RuntimeBean -> statistics-collection-service-impl
--> statistics-collection-service-impl -> Operations+ to be able to use this commands.
-
-=== TLS Support
-NOTE: see OpenFlow Plugin Developper Guide
-
-=== Extensibility
-
-==== Introduction
-
-Entry point for the extensibility is +SwitchConnectionProvider+.
-+SwitchConnectionProvider+ contains methods for (de)serializer registration.
-To register deserializer it is needed to use .register*Deserializer(key, impl).
-To register serializer one must use .register*Serializer(key, impl). Registration
-can occur either during configuration or at runtime.
-
-*NOTE*: In case when experimenter message is received and no (de)serializer was
-registered, the library will throw +IllegalArgumentException+.
-
-==== Basic Principle
-In order to use extensions it is needed to augment existing model and register new (de)serializers.
-
-Augmenting the model:
-1. Create new augmentation
-
-Register (de)serializers:
-1. Create your (de)serializer
-2. Let it implement +OFDeserializer<>+ / +OFSerializer<>+
-- in case the structure you are (de)serializing needs to be used in Multipart
-TableFeatures messages, let it implement +HeaderDeserializer<>+ / +HeaderSerializer+
-3. Implement prescribed methods
-4. Register your deserializer under appropriate key (in our case
-+ExperimenterActionDeserializerKey+)
-5. Register your serializer under appropriate key (in our case
-+ExperimenterActionSerializerKey+)
-6. Done, test your implementation
-
-*NOTE*: If you don't know what key should be used with your (de)serializer
-implementation, please visit <<registration_keys, Registration keys>> page.
-
-==== Example
-Let's say we have vendor / experimenter action represented by this structure:
-----
-struct foo_action {
- uint16_t type;
- uint16_t length;
- uint32_t experimenter;
- uint16_t first;
- uint16_t second;
- uint8_t pad[4];
-}
-----
-First, we have to augment existing model. We create new module, which imports
-"+openflow-types.yang+" (don't forget to update your +pom.xml+ with api dependency).
-Now we create foo action identity:
-----
-import openflow-types {prefix oft;}
-identity foo {
- description "Foo action description";
- base oft:action-base;
-}
-----
-
-This will be used as type in our structure. Now we must augment existing action
-structure, so that we will have the desired fields first and second. In order to
-create new augmentation, our module has to import "+openflow-action.yang+". The
-augment should look like this:
-----
-import openflow-action {prefix ofaction;}
-augment "/ofaction:actions-container/ofaction:action" {
- ext:augment-identifier "foo-action";
- leaf first {
- type uint16;
- }
- leaf second {
- type uint16;
- }
- }
-----
-We are finished with model changes. Run mvn clean compile to generate sources.
-After generation is done, we need to implement our (de)serializer.
-
-Deserializer:
-----
-public class FooActionDeserializer extends OFDeserializer<Action> {
- @Override
- public Action deserialize(ByteBuf input) {
- ActionBuilder builder = new ActionBuilder();
- input.skipBytes(SIZE_OF_SHORT_IN_BYTES); *// we know the type of action*
- builder.setType(Foo.class);
- input.skipBytes(SIZE_OF_SHORT_IN_BYTES); *// we don't need length*
- *// now create experimenterIdAugmentation - so that openflowplugin can
- differentiate correct vendor codec*
- ExperimenterIdActionBuilder expIdBuilder = new ExperimenterIdActionBuilder();
- expIdBuilder.setExperimenter(new ExperimenterId(input.readUnsignedInt()));
- builder.addAugmentation(ExperimenterIdAction.class, expIdBuilder.build());
- FooActionBuilder fooBuilder = new FooActionBuilder();
- fooBuilder.setFirst(input.readUnsignedShort());
- fooBuilder.setSecond(input.readUnsignedShort());
- builder.addAugmentation(FooAction.class, fooBuilder.build());
- input.skipBytes(4); *// padding*
- return builder.build();
- }
-}
-----
-Serializer:
-----
-public class FooActionSerializer extends OFSerializer<Action> {
- @Override
- public void serialize(Action action, ByteBuf outBuffer) {
- outBuffer.writeShort(FOO_CODE);
- outBuffer.writeShort(16);
- *// we don't have to check for ExperimenterIdAction augmentation - our
- serializer*
- *// was called based on the vendor / experimenter ID, so we simply write
- it to buffer*
- outBuffer.writeInt(VENDOR / EXPERIMENTER ID);
- FooAction foo = action.getAugmentation(FooAction.class);
- outBuffer.writeShort(foo.getFirst());
- outBuffer.writeShort(foo.getSecond());
- outBuffer.writeZero(4); //write padding
- }
-}
-----
-Register both deserializer and serializer:
-+SwitchConnectionProvider.registerDeserializer(new
-ExperimenterActionDeserializerKey(0x04, VENDOR / EXPERIMENTER ID),
-new FooActionDeserializer());+
-+SwitchConnectionProvider.registerSerializer(new
-ExperimenterActionSerializerKey(0x04, VENDOR / EXPERIMENTER ID),
-new FooActionSerializer());+
-
-We are ready to test our implementation.
-
-*NOTE:* Vendor / Experimenter structures define only vendor / experimenter ID as
-common distinguisher (besides action type). Vendor / Experimenter ID is unique
-for all vendor messages - that's why vendor is able to register only one class
-under ExperimenterAction(De)SerializerKey. And that's why vendor has to switch
-/ choose between his subclasses / subtypes on his own.
-
-==== Detailed walkthrough: Deserialization extensibility
-
-.External interface & class description
-*OFGeneralDeserializer:*
-
-* +OFDeserializer<E extends DataObject>+
-** _deserialize(ByteBuf)_ - deserializes given ByteBuf
-* +HeaderDeserializer<E extends DataObject>+
-** _deserializeHeaders(ByteBuf)_ - deserializes only E headers (used in Multipart
-TableFeatures messages)
-
-*DeserializerRegistryInjector*
-
-* +injectDeserializerRegistry(DeserializerRegistry)+ - injects deserializer
-registry into deserializer. Useful when custom deserializer needs access to
-other deserializers.
-
-*NOTE:* DeserializerRegistryInjector is not OFGeneralDeserializer descendand.
-It is a standalone interface.
-
-*MessageCodeKey and its descendants*
-These keys are used as for deserializer lookup in DeserializerRegistry.
-MessageCodeKey should is used in general, while its descendants are used in more
-special cases. For Example ActionDeserializerKey is used for Action deserializer
-lookup and (de)registration. Vendor is provided with special keys, which contain
-only the most necessary fields. These keys usually start with "Experimenter"
-prefix (MatchEntryDeserializerKey is an exception).
-
-MessageCodeKey has these fields:
-
-* short version - Openflow wire version number
-* int value - value read from byte message
-* Class<?> clazz - class of object being creating
-
-.Scenario walkthrough
-* [1] The scenario starts in a custom bundle which wants to extend library's
-functionality. The custom bundle creates deserializers which implement exposed
-+OFDeserializer+ / +HeaderDeserializer+ interfaces (wrapped under
-+OFGeneralDeserializer+ unifying super interface).
-* [2] Created deserializers are paired with corresponding ExperimenterKeys,
-which are used for deserializer lookup.
-If you don't know what key should be used with your (de)serializer implementation,
-please visit <<registration_keys, Registration keys>> page.
-* [3] Paired deserializers are passed to the OF Library
-via *SwitchConnectionProvider*._registerCustomDeserializer(key, impl)_.
-Library registers the deserializer.
-** While registering, Library checks if the deserializer is an instance of
-*DeserializerRegistryInjector* interface. If yes, the DeserializerRegistry
-(which stores all deserializer references) is injected into the deserializer.
-
-This is particularly useful when the deserializer needs access to other
-deserializers. For example +IntructionsDeserializer+ needs access to
-+ActionsDeserializer+ in order to be able to process
-OFPIT_WRITE_ACTIONS/OFPIT_APPLY_ACTIONS instructions.
-
-.Deserialization scenario walkthrough
-image::openflowjava/800px-Extensibility.png[width=500]
-
-==== Detailed walkthrough: Serialization extensibility
-.External interface & class description
-
-*OFGeneralSerializer:*
-
-* OFSerializer<E extends DataObject>
-** _serialize(E,ByteBuf)_ - serializes E into given ByteBuf
-* +HeaderSerializer<E extends DataObject>+
-** _serializeHeaders(E,ByteBuf)_ - serializes E headers (used in Multipart
-TableFeatures messages)
-
-*SerializerRegistryInjector*
-* +injectSerializerRegistry(SerializerRegistry)+ - injects serializer registry
-into serializer. Useful when custom serializer needs access to other serializers.
-
-*NOTE:* SerializerRegistryInjector is not OFGeneralSerializer descendand.
-
-*MessageTypeKey and its descendants*
-These keys are used as for serializer lookup in SerializerRegistry.
-MessageTypeKey should is used in general, while its descendants are used in more
-special cases. For Example ActionSerializerKey is used for Action serializer
-lookup and (de)registration. Vendor is provided with special keys, which contain
-only the most necessary fields. These keys usually start with "Experimenter"
-prefix (MatchEntrySerializerKey is an exception).
-
-MessageTypeKey has these fields:
-
-* _short version_ - Openflow wire version number
-* _Class<E> msgType_ - DTO class
-
-Scenario walkthrough
-
-* [1] Serialization extensbility principles are similar to the deserialization
-principles. The scenario starts in a custom bundle. The custom bundle creates
-serializers which implement exposed OFSerializer / HeaderSerializer interfaces
-(wrapped under OFGeneralSerializer unifying super interface).
-* [2] Created serializers are paired with their ExperimenterKeys, which are used
-for serializer lookup.
-If you don't know what key should be used with your serializer implementation,
-please visit <<registration_keys, Registration keys>> page.
-* [3] Paired serializers are passed to the OF Library via
-*SwitchConnectionProvider*._registerCustomSerializer(key, impl)_. Library
-registers the serializer.
-* While registering, Library checks if the serializer is an instance of
-*SerializerRegistryInjector* interface. If yes, the SerializerRegistry (which
-stores all serializer references) is injected into the serializer.
-
-This is particularly useful when the serializer needs access to other deserializers.
-For example IntructionsSerializer needs access to ActionsSerializer in order to
-be able to process OFPIT_WRITE_ACTIONS/OFPIT_APPLY_ACTIONS instructions.
-
-.Serialization scenario walkthrough
-image::openflowjava/800px-Extensibility2.png[width=500]
-
-==== Internal description
-
-*SwitchConnectionProvider*
-+SwitchConnectionProvider+ constructs and initializes both deserializer and
-serializer registries with default (de)serializers. It also injects the
-+DeserializerRegistry+ into the +DeserializationFactory+, the +SerializerRegistry+
-into the +SerializationFactory+.
-When call to register custom (de)serializer is made, +SwitchConnectionProvider+
-calls register method on appropriate registry.
-
-*DeserializerRegistry / SerializerRegistry*
-Both registries contain init() method to initialize default (de)serializers.
-Registration checks if key or (de)serializer implementation are not +null+. If at
-least one of the is +null+, +NullPointerException+ is thrown. Else the
-(de)serializer implementation is checked if it is +(De)SerializerRegistryInjector+
-instance. If it is an instance of this interface, the registry is injected into
-this (de)serializer implementation.
-
-+GetSerializer(key)+ or +GetDeserializer(key)+ performs registry lookup. Because
-there are two separate interfaces that might be put into the registry, the
-registry uses their unifying super interface. Get(De)Serializer(key) method casts
-the super interface to desired type. There is also a null check for the
-(de)serializer received from the registry. If the deserializer wasn't found,
-+NullPointerException+ with key description is thrown.
-
-
-[[registration_keys]]
-==== Registration keys
-
-.Deserialization
-
-*Possible openflow extensions and their keys*
-
-There are three vendor specific extensions in Openflow v1.0 and eight in
-Openflow v1.3. These extensions are registered under registration keys,
-that are shown in table below:
-
-.*Deserialization*
-[options="header",cols="20%,10%,40%,30%"]
-|========================================================================================================================================================
-|Extension type |OpenFlow|Registration key |Utility class
-|Vendor message |1.0 |ExperimenterIdDeserializerKey(1, experimenterId, ExperimenterMessage.class) |ExperimenterDeserializerKeyFactory
-|Action |1.0 |ExperimenterActionDeserializerKey(1, experimenter ID) |.
-|Stats message |1.0 |ExperimenterMultipartReplyMessageDeserializerKey(1, experimenter ID) |ExperimenterDeserializerKeyFactory
-|Experimenter message |1.3 |ExperimenterIdDeserializerKey(4, experimenterId, ExperimenterMessage.class) |ExperimenterDeserializerKeyFactory
-|Match entry |1.3 |MatchEntryDeserializerKey(4, (number) ${oxm_Class}, (number) ${oxm_Field}); |.
-| | |key.setExperimenterId(experimenter ID); |.
-|Action |1.3 |ExperimenterActionDeserializerKey(4, experimenter ID) |.
-|Instruction |1.3 |ExperimenterInstructionDeserializerKey(4, experimenter ID) |.
-|Multipart |1.3 |ExperimenterIdDeserializerKey(4, experimenterId, MultipartReplyMessage.class) |ExperimenterDeserializerKeyFactory
-|Multipart - Table features|1.3 |ExperimenterIdDeserializerKey(4, experimenterId, TableFeatureProperties.class) |ExperimenterDeserializerKeyFactory
-|Error |1.3 |ExperimenterIdDeserializerKey(4, experimenterId, ErrorMessage.class) |ExperimenterDeserializerKeyFactory
-|Queue property |1.3 |ExperimenterIdDeserializerKey(4, experimenterId, QueueProperty.class) |ExperimenterDeserializerKeyFactory
-|Meter band type |1.3 |ExperimenterIdDeserializerKey(4, experimenterId, MeterBandExperimenterCase.class)|ExperimenterDeserializerKeyFactory
-|========================================================================================================================================================
-
-.Serialization
-
-*Possible openflow extensions and their keys*
-
-There are three vendor specific extensions in Openflow v1.0 and seven Openflow
-v1.3. These extensions are registered under registration keys, that are shown in
-table below:
-
-
-.*Serialization*
-[options="header",cols="20%,10%,40%,30%"]
-|=============================================================================================================================================================
-|Extension type |OpenFlow|Registration key |Utility class
-|Vendor message |1.0 |ExperimenterIdSerializerKey<>(1, experimenterId, ExperimenterInput.class) |ExperimenterSerializerKeyFactory
-|Action |1.0 |ExperimenterActionSerializerKey(1, experimenterId, sub-type) |.
-|Stats message |1.0 |ExperimenterMultipartRequestSerializerKey(1, experimenter ID) |ExperimenterSerializerKeyFactory
-|Experimenter message |1.3 |ExperimenterIdSerializerKey<>(4, experimenterId, ExperimenterInput.class) |ExperimenterSerializerKeyFactory
-|Match entry |1.3 |MatchEntrySerializerKey<>(4, (class) ${oxm_Class}, (class) ${oxm_Field}); |.
-| | |key.setExperimenterId(experimenter ID) |.
-|Action |1.3 |ExperimenterActionSerializerKey(4, experimenterId, sub-type) |.
-|Instruction |1.3 |ExperimenterInstructionSerializerKey(4, experimenter ID) |.
-|Multipart |1.3 |ExperimenterIdSerializerKey<>(4, experimenterId, MultipartRequestExperimenterCase.class)|ExperimenterSerializerKeyFactory
-|Multipart - Table features|1.3 |ExperimenterIdSerializerKey<>(4, experimenterId, TableFeatureProperties.class) |ExperimenterSerializerKeyFactory
-|Meter band type |1.3 |ExperimenterIdSerializerKey<>(4, experimenterId, MeterBandExperimenterCase.class) |ExperimenterSerializerKeyFactory
-|=============================================================================================================================================================
+This content has been migrated to: http://docs.opendaylight.org/en/stable-boron/developer-guide/openflow-protocol-library-developer-guide.html