--- /dev/null
+Openflowplugin Developer Guides
+===============================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 1
+
+ Plugin Guide <plugin>
+ Library Guide <library>
--- /dev/null
+.. _openflow-protocol-library-dev-guide:
+
+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/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/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/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/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**
+
--- /dev/null
+OpenFlow Plugin Project Developer Guide
+=======================================
+
+This section covers topics which are developer specific and which have
+not been covered in the user guide. Please see the OpenFlow
+plugin user guide first.
+
+It can be found on `the OpenDaylight software download
+page <https://www.opendaylight.org/downloads>`__.
+
+Event Sequences
+---------------
+
+Session Establishment
+~~~~~~~~~~~~~~~~~~~~~
+
+The OpenFlow Protocol
+Library provides
+interface **SwitchConnectionHandler** which contains method
+*onSwitchConnected* (step 1). This event is raised in the OpenFlow
+Protocol Library when an OpenFlow device connects to OpenDaylight and
+caught in the **ConnectionManagerImpl** class in the OpenFlow plugin.
+
+There the plugin creates a new instance of the **ConnectionContextImpl**
+class (step 1.1) and also instances of **HandshakeManagerImpl** (which
+uses **HandshakeListenerImpl**) and **ConnectionReadyListenerImpl**.
+**ConnectionReadyListenerImpl** contains method *onConnectionReady()*
+which is called when connection is prepared. This method starts the
+handshake with the OpenFlow device (switch) from the OpenFlow plugin
+side. Then handshake can be also started from device side. In this case
+method *shake()* from **HandshakeManagerImpl** is called (steps 1.1.1
+and 2).
+
+The handshake consists of an exchange of HELLO messages in addition to
+an exchange of device features (steps 2.1. and 3). The handshake is
+completed by **HandshakeManagerImpl**. After receiving device features,
+the **HandshakeListenerImpl** is notifed via the
+*onHanshakeSuccessfull()* method. After this, the device features, node
+id and connection state are stored in a **ConnectionContext** and the
+method *deviceConnected()* of **DeviceManagerImpl** is called.
+
+When *deviceConnected()* is called, it does the following:
+
+1. creates a new transaction chain (step 4.1)
+
+2. creates a new instance of **DeviceContext** (step 4.2.2)
+
+3. initializes the device context: the static context of device is
+ populated by calling *createDeviceFeaturesForOF<version>()* to
+ populate table, group, meter features and port descriptions (step
+ 4.2.1 and 4.2.1.1)
+
+4. creates an instance of **RequestContext** for each type of feature
+
+When the OpenFlow device responds to these requests (step 4.2.1.1) with
+multipart replies (step 5) they are processed and stored to MD-SAL
+operational datastore. The *createDeviceFeaturesForOF<version>()* method
+returns a **Future** which is processed in the callback (step 5.1) (part
+of *initializeDeviceContext()* in the *deviceConnected()* method) by
+calling the method *onDeviceCtxLevelUp()* from **StatisticsManager**
+(step 5.1.1).
+
+The call to *createDeviceFeaturesForOF<version>()*: . creates a new
+instance of **StatisticsContextImpl** (step 5.1.1.1).
+
+1. calls *gatherDynamicStatistics()* on that instance which returns a
+ **Future** which will produce a value when done
+
+ a. this method calls methods to get dynamic data (flows, tables,
+ groups) from the device (step 5.1.1.2, 5.1.1.2.1, 5.1.1.2.1.1)
+
+ b. if everything works, this data is also stored in the MD-SAL
+ operational datastore
+
+If the **Future** is successful, it is processed (step 6.1.1) in a
+callback in **StatisticsManagerImpl** which:
+
+1. schedules the next time to poll the device for statistics
+
+2. sets the device state to synchronized (step 6.1.1.2)
+
+3. calls *onDeviceContextLevelUp()* in **RpcManagerImpl**
+
+The *onDeviceContextLevelUp()* call:
+
+1. creates a new instance of **RequestContextImpl**
+
+2. registers implementation for supported services
+
+3. calls *onDeviceContextLevelUp()* in **DeviceManagerImpl** (step
+ 6.1.1.2.1.2) which causes the information about the new device be be
+ written to the MD-SAL operational datastore (step 6.1.1.2.2)
+
+.. figure:: ../images/odl-ofp-session-establishment.jpg
+ :alt: Session establishment
+
+ Session establishment
+
+Handshake
+~~~~~~~~~
+
+The first thing that happens when an OpenFlow device connects to
+OpenDaylight is that the OpenFlow plugin gathers basic information about
+the device and establishes agreement on key facts like the version of
+OpenFlow which will be used. This process is called the handshake.
+
+The handshake starts with HELLO message which can be sent either by the
+OpenFlow device or the OpenFlow plugin. After this, there are several
+scenarios which can happen:
+
+1. if the first HELLO message contains a *version bitmap*, it is
+ possible to determine if there is a common version of OpenFlow or
+ not:
+
+ a. if there is a single common version use it and the **VERSION IS
+ SETTLED**
+
+ b. if there are more than one common versions, use the highest
+ (newest) protocol and the **VERSION IS SETTLED**
+
+ c. if there are no common versions, the device is **DISCONNECTED**
+
+2. if the first HELLO message does not contain a *version bitmap*, then
+ STEB-BY-STEP negotiation is used
+
+3. if second (or more) HELLO message is received, then STEP-BY-STEP
+ negotiation is used
+
+STEP-BY-STEP negotiation:
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- if last version proposed by the OpenFlow plugin is the same as the
+ version received from the OpenFlow device, then the **VERSION IS
+ SETTLED**
+
+- if the version received in the current HELLO message from the device
+ is the same as from previous then negotiation has failed and the
+ device is **DISCONNECTED**
+
+- if the last version from the device is greater than the last version
+ proposed from the plugin, wait for the next HELLO message in the hope
+ that it will advertise support for a lower version
+
+- if the last version from the device is is less than the last version
+ proposed from the plugin:
+
+ - propose the highest version the plugin supports that is less than
+ or equal to the version received from the device and wait for the
+ next HELLO message
+
+ - if if the plugin doesn’t support a lower version, the device is
+ **DISCONNECTED**
+
+After selecting of version we can say that the **VERSION IS SETTLED**
+and the OpenFlow plugin can ask device for its features. At this point
+handshake ends.
+
+.. figure:: ../images/odl-ofp-handshake.png
+ :alt: Handshake process
+
+ Handshake process
+
+Adding a Flow
+~~~~~~~~~~~~~
+
+There are two ways to add a flow in in the OpenFlow plugin: adding it to
+the MD-SAL config datastore or calling an RPC. Both of these can either
+be done using the native MD-SAL interfaces or using RESTCONF. This
+discussion focuses on calling the RPC.
+
+If user send flow via REST interface (step 1) it will cause that
+*invokeRpc()* is called on **RpcBroker**. The **RpcBroker** then looks
+for an appropriate implementation of the interface. In the case of the
+OpenFlow plugin, this is the *addFlow()* method of
+**SalFlowServiceImpl** (step 1.1). The same thing happens if the RPC is
+called directly from the native MD-SAL interfaces.
+
+The *addFlow()* method then
+
+1. calls the *commitEntry()* method (step 2) from the OpenFlow Protocol
+ Library which is responsible for sending the flow to the device
+
+2. creates a new **RequestContext** by calling *createRequestContext()*
+ (step 3)
+
+3. creates a callback to handle any events that happen because of
+ sending the flow to the device
+
+The callback method is triggered when a barrier reply message (step 2.1)
+is received from the device indicating that the flow was either
+installed or an appropriate error message was sent. If the flow was
+successfully sent to the device, the RPC result is set to success (step
+5). // **SalFlowService** contains inside method *addFlow()* other
+callback which caught notification from callback for barrier message.
+
+At this point, no information pertaining to the flow has been added to
+the MD-SAL operational datastore. That is accomplished by the periodic
+gathering of statistics from OpenFlow devices.
+
+The **StatisticsContext** for each given OpenFlow device periodically
+polls it using *gatherStatistics()* of **StatisticsGatheringUtil** which
+issues an OpenFlow OFPT\_MULTIPART\_REQUEST - OFPMP\_FLOW. The response
+to this request (step 7) is processed in **StatisticsGatheringUtil**
+class where flow data is written to the MD-SAL operational datastore via
+the *writeToTransaction()* method of **DeviceContext**.
+
+.. figure:: ../images/odl-ofp-add-flow.png
+ :alt: Add flow
+
+ Add flow
+
+Description of OpenFlow Plugin Modules
+--------------------------------------
+
+The OpenFlow plugin project contains a variety of OpenDaylight modules,
+which are loaded using the configuration subsystem. This section
+describes the YANG files used to model each module.
+
+**General model (interfaces)** - openflow-plugin-cfg.yang.
+
+- the provided module is defined (``identity openflow-provider``)
+
+- and target implementation is assigned (``...OpenflowPluginProvider``)
+
+.. code::
+
+ module openflow-provider {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:openflow:common:config[urn:opendaylight:params:xml:ns:yang:openflow:common:config]";
+ prefix "ofplugin-cfg";
+
+ import config {prefix config; revision-date 2013-04-05; }
+ description
+ "openflow-plugin-custom-config";
+ revision "2014-03-26" {
+ description
+ "Initial revision";
+ }
+ identity openflow-provider{
+ base config:service-type;
+ config:java-class "org.opendaylight.openflowplugin.openflow.md.core.sal.OpenflowPluginProvider";
+ }
+ }
+
+**Implementation model** - openflow-plugin-cfg-impl.yang
+
+- the implementation of module is defined
+ (``identity openflow-provider-impl``)
+
+ - class name of generated implementation is defined
+ (ConfigurableOpenFlowProvider)
+
+- via augmentation the configuration of module is defined:
+
+ - this module requires instance of binding-aware-broker
+ (``container binding-aware-broker``)
+
+ - and list of openflow-switch-connection-provider (those are
+ provided by openflowjava, one plugin instance will orchestrate
+ multiple openflowjava modules)
+
+.. code::
+
+ module openflow-provider-impl {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl[urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl]";
+ prefix "ofplugin-cfg-impl";
+
+ import config {prefix config; revision-date 2013-04-05;}
+ import openflow-provider {prefix openflow-provider;}
+ import openflow-switch-connection-provider {prefix openflow-switch-connection-provider;revision-date 2014-03-28;}
+ import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+
+
+ description
+ "openflow-plugin-custom-config-impl";
+
+ revision "2014-03-26" {
+ description
+ "Initial revision";
+ }
+
+ identity openflow-provider-impl {
+ base config:module-type;
+ config:provided-service openflow-provider:openflow-provider;
+ config:java-name-prefix ConfigurableOpenFlowProvider;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case openflow-provider-impl {
+ when "/config:modules/config:module/config:type = 'openflow-provider-impl'";
+
+ container binding-aware-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-broker-osgi-registry;
+ }
+ }
+ }
+ list openflow-switch-connection-provider {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity openflow-switch-connection-provider:openflow-switch-connection-provider;
+ }
+ }
+ }
+ }
+ }
+ }
+
+Generating config and sal classes out of yangs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to involve suitable code generators, this is needed in pom:
+
+.. code:: xml
+
+ <build> ...
+ <plugins>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ </codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <additionalConfiguration>
+ <namespaceToPackage1>
+ urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+ </namespaceToPackage1>
+ </additionalConfiguration>
+ </generator>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/generated-sources/sal</outputBaseDir>
+ </generator>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/site/models</outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator-plugin</artifactId>
+ <version>0.2.5-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>maven-sal-api-gen-plugin</artifactId>
+ <version>${yangtools.version}</version>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+ </plugin>
+ ...
+
+- JMX generator (target/generated-sources/config)
+
+- sal CodeGeneratorImpl (target/generated-sources/sal)
+
+Altering generated files
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Those files were generated under src/main/java in package as referred in
+yangs (if exist, generator will not overwrite them):
+
+- ConfigurableOpenFlowProviderModuleFactory
+
+ here the **instantiateModule** methods are extended in order to
+ capture and inject osgi BundleContext into module, so it can be
+ injected into final implementation - **OpenflowPluginProvider** +
+ ``module.setBundleContext(bundleContext);``
+
+- ConfigurableOpenFlowProviderModule
+
+ here the **createInstance** method is extended in order to inject
+ osgi BundleContext into module implementation +
+ ``pluginProvider.setContext(bundleContext);``
+
+Configuration xml file
+~~~~~~~~~~~~~~~~~~~~~~
+
+Configuration file contains
+
+- required capabilities
+
+ - modules definitions from openflowjava
+
+ - modules definitions from openflowplugin
+
+- modules definition
+
+ - openflow:switch:connection:provider:impl (listening on port 6633,
+ name=openflow-switch-connection-provider-legacy-impl)
+
+ - openflow:switch:connection:provider:impl (listening on port 6653,
+ name=openflow-switch-connection-provider-default-impl)
+
+ - openflow:common:config:impl (having 2 services (wrapping those 2
+ previous modules) and binding-broker-osgi-registry injected)
+
+- provided services
+
+ - openflow-switch-connection-provider-default
+
+ - openflow-switch-connection-provider-legacy
+
+ - openflow-provider
+
+.. code:: xml
+
+ <snapshot>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl?module=openflow-switch-connection-provider-impl&revision=2014-03-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider?module=openflow-switch-connection-provider&revision=2014-03-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl?module=openflow-provider-impl&revision=2014-03-26</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:openflow:common:config?module=openflow-provider&revision=2014-03-26</capability>
+ </required-capabilities>
+
+ <configuration>
+
+
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <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>
+ <switch-idle-timeout>15000</switch-idle-timeout>
+ </module>
+ <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>
+ <switch-idle-timeout>15000</switch-idle-timeout>
+ </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>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">prefix:openflow-switch-connection-provider</type>
+ <instance>
+ <name>openflow-switch-connection-provider-default</name>
+ <provider>/modules/module[type='openflow-switch-connection-provider-impl'][name='openflow-switch-connection-provider-default-impl']</provider>
+ </instance>
+ <instance>
+ <name>openflow-switch-connection-provider-legacy</name>
+ <provider>/modules/module[type='openflow-switch-connection-provider-impl'][name='openflow-switch-connection-provider-legacy-impl']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:common:config">prefix:openflow-provider</type>
+ <instance>
+ <name>openflow-provider</name>
+ <provider>/modules/module[type='openflow-provider-impl'][name='openflow-provider-impl']</provider>
+ </instance>
+ </service>
+ </services>
+
+
+ </configuration>
+ </snapshot>
+
+API changes
+~~~~~~~~~~~
+
+In order to provide multiple instances of modules from openflowjava
+there is an API change. Previously OFPlugin got access to
+SwitchConnectionProvider exposed by OFJava and injected collection of
+configurations so that for each configuration new instance of tcp
+listening server was created. Now those configurations are provided by
+configSubsystem and configured modules (wrapping the original
+SwitchConnectionProvider) are injected into OFPlugin (wrapping
+SwitchConnectionHandler).
+
+Providing config file (IT, local distribution/base, integration/distributions/base)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+openflowplugin-it
+^^^^^^^^^^^^^^^^^
+
+Here the whole configuration is contained in one file (controller.xml).
+Required entries needed in order to startup and wire OEPlugin + OFJava
+are simply added there.
+
+OFPlugin/distribution/base
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Here new config file has been added
+(src/main/resources/configuration/initial/42-openflow-protocol-impl.xml)
+and is being copied to config/initial subfolder of build.
+
+integration/distributions/build
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In order to push the actual config into config/initial subfolder of
+distributions/base in integration project there was a new artifact in
+OFPlugin created - **openflowplugin-controller-config**, containing only
+the config xml file under src/main/resources. Another change was
+committed into integration project. During build this config xml is
+being extracted and copied to the final folder in order to be accessible
+during controller run.
+
+Internal message statistics API
+-------------------------------
+
+To aid in testing and diagnosis, the OpenFlow plugin provides
+information about the number and rate of different internal events.
+
+The implementation does two things: collects event counts and exposes
+counts. Event counts are grouped by message type, e.g.,
+**PacketInMessage**, and checkpoint, e.g.,
+*TO\_SWITCH\_ENQUEUED\_SUCCESS*. Once gathered, the results are logged
+as well as being exposed using OSGi command line (deprecated) and JMX.
+
+Collect
+~~~~~~~
+
+Each message is counted as it passes through various processing
+checkpoints. The following checkpoints are defined as a Java enum and
+tracked:
+
+.. code:: java
+
+ /**
+ * statistic groups overall in OFPlugin
+ */
+ enum STATISTIC_GROUP {
+ /** message from switch, enqueued for processing */
+ FROM_SWITCH_ENQUEUED,
+ /** message from switch translated successfully - source */
+ FROM_SWITCH_TRANSLATE_IN_SUCCESS,
+ /** message from switch translated successfully - target */
+ FROM_SWITCH_TRANSLATE_OUT_SUCCESS,
+ /** message from switch where translation failed - source */
+ FROM_SWITCH_TRANSLATE_SRC_FAILURE,
+ /** message from switch finally published into MD-SAL */
+ FROM_SWITCH_PUBLISHED_SUCCESS,
+ /** message from switch - publishing into MD-SAL failed */
+ FROM_SWITCH_PUBLISHED_FAILURE,
+
+ /** message from MD-SAL to switch via RPC enqueued */
+ TO_SWITCH_ENQUEUED_SUCCESS,
+ /** message from MD-SAL to switch via RPC NOT enqueued */
+ TO_SWITCH_ENQUEUED_FAILED,
+ /** message from MD-SAL to switch - sent to OFJava successfully */
+ TO_SWITCH_SUBMITTED_SUCCESS,
+ /** message from MD-SAL to switch - sent to OFJava but failed*/
+ TO_SWITCH_SUBMITTED_FAILURE
+ }
+
+When a message passes through any of those checkpoints then counter
+assigned to corresponding checkpoint and message is incremented by 1.
+
+Expose statistics
+~~~~~~~~~~~~~~~~~
+
+As described above, there are three ways to access the statistics:
+
+- OSGi command line (this is considered deprecated)
+
+ ``osgi> dumpMsgCount``
+
+- OpenDaylight logging console (statistics are logged here every 10
+ seconds)
+
+ required logback settings :
+ ``<logger name="org.opendaylight.openflowplugin.openflow.md.queue.MessageSpyCounterImpl" level="DEBUG"\/>``
+
+- JMX (via JConsole)
+
+ start OpenFlow plugin with the ``-jmx`` parameter
+
+ start JConsole by running ``jconsole``
+
+ the JConsole MBeans tab should contain
+ org.opendaylight.controller
+
+ RuntimeBean has a msg-spy-service-impl
+
+ Operations provides makeMsgStatistics report functionality
+
+Example results
+^^^^^^^^^^^^^^^
+
+.. figure:: ../images/odl-ofp-ofplugin-debug-stats.png
+ :alt: OFplugin Debug stats.png
+
+ OFplugin Debug stats.png
+
+::
+
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_ENQUEUED: MSG[PortStatusMessage] -> +0 | 1
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_ENQUEUED: MSG[MultipartReplyMessage] -> +24 | 81
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_ENQUEUED: MSG[PacketInMessage] -> +8 | 111
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_IN_SUCCESS: MSG[PortStatusMessage] -> +0 | 1
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_IN_SUCCESS: MSG[MultipartReplyMessage] -> +24 | 81
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_IN_SUCCESS: MSG[PacketInMessage] -> +8 | 111
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[QueueStatisticsUpdate] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[NodeUpdated] -> +0 | 3
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[NodeConnectorStatisticsUpdate] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[GroupDescStatsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[FlowsStatisticsUpdate] -> +3 | 19
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[PacketReceived] -> +8 | 111
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[MeterFeaturesUpdated] -> +0 | 3
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[GroupStatisticsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[GroupFeaturesUpdated] -> +0 | 3
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[MeterConfigStatsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[MeterStatisticsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[NodeConnectorUpdated] -> +0 | 12
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_OUT_SUCCESS: MSG[FlowTableStatisticsUpdate] -> +3 | 8
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_TRANSLATE_SRC_FAILURE: no activity detected
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[QueueStatisticsUpdate] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[NodeUpdated] -> +0 | 3
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[NodeConnectorStatisticsUpdate] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[GroupDescStatsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[FlowsStatisticsUpdate] -> +3 | 19
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[PacketReceived] -> +8 | 111
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[MeterFeaturesUpdated] -> +0 | 3
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[GroupStatisticsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[GroupFeaturesUpdated] -> +0 | 3
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[MeterConfigStatsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[MeterStatisticsUpdated] -> +3 | 7
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[NodeConnectorUpdated] -> +0 | 12
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_SUCCESS: MSG[FlowTableStatisticsUpdate] -> +3 | 8
+ DEBUG o.o.o.s.MessageSpyCounterImpl - FROM_SWITCH_PUBLISHED_FAILURE: no activity detected
+ DEBUG o.o.o.s.MessageSpyCounterImpl - TO_SWITCH_ENQUEUED_SUCCESS: MSG[AddFlowInput] -> +0 | 12
+ DEBUG o.o.o.s.MessageSpyCounterImpl - TO_SWITCH_ENQUEUED_FAILED: no activity detected
+ DEBUG o.o.o.s.MessageSpyCounterImpl - TO_SWITCH_SUBMITTED_SUCCESS: MSG[AddFlowInput] -> +0 | 12
+ DEBUG o.o.o.s.MessageSpyCounterImpl - TO_SWITCH_SUBMITTED_FAILURE: no activity detected
+
+Application: Forwarding Rules Synchronizer
+------------------------------------------
+
+Basics
+~~~~~~
+
+Description
+^^^^^^^^^^^
+
+Forwarding Rules Synchronizer (FRS) is a newer version of Forwarding
+Rules Manager (FRM). It was created to solve most shortcomings of FRM.
+FRS solving errors with retry mechanism. Sending barrier if needed.
+Using one service for flows, groups and meters. And it has less changes
+requests send to device since calculating difference and using
+compression queue.
+
+It is located in the Java package:
+
+.. code:: java
+
+ package org.opendaylight.openflowplugin.applications.frsync;
+
+Listeners
+^^^^^^^^^
+
+- 1x config - FlowCapableNode
+
+- 1x operational - Node
+
+System of work
+^^^^^^^^^^^^^^
+
+- one listener in config datastore waiting for changes
+
+ - update cache
+
+ - skip event if operational not present for node
+
+ - send syncup entry to reactor for synchronization
+
+ - node added: after part of modification and whole operational
+ snapshot
+
+ - node updated: after and before part of modification
+
+ - node deleted: null and before part of modification
+
+- one listener in operational datastore waiting for changes
+
+ - update cache
+
+ - on device connected
+
+ - register for cluster services
+
+ - on device disconnected remove from cache
+
+ - remove from cache
+
+ - unregister for cluster services
+
+ - if registered for reconciliation
+
+ - do reconciliation through syncup (only when config present)
+
+- reactor *(provides syncup w/decorators assembled in this order)*
+
+ - Cluster decorator - skip action if not master for device
+
+ - FutureZip decorator (FutureZip extends Future decorator)
+
+ - Future - run delegate syncup in future - submit task to
+ executor service
+
+ - FutureZip - provides state compression - compress optimized
+ config delta if waiting for execution with new one
+
+ - Guard decorator - per device level locking
+
+ - Retry decorator - register for reconciliation if syncup failed
+
+ - Reactor impl - calculate diff from after/before parts of syncup
+ entry and execute
+
+Strategy
+^^^^^^^^
+
+In the *old* FRM uses an incremental strategy with all changes made one
+by one, where FRS uses a flat batch system with changes made in bulk. It
+uses one service SalFlatBatchService instead of three (flow, group,
+meter).
+
+Boron release
+^^^^^^^^^^^^^
+
+FRS is used in Boron as separate feature and it is not loaded by any
+other feature. It has to be run separately.
+
+::
+
+ odl-openflowplugin-app-forwardingrules-sync
+
+FRS additions
+~~~~~~~~~~~~~
+
+Retry mechanism
+^^^^^^^^^^^^^^^
+
+- is started when change request to device return as failed (register
+ for reconcile)
+
+- wait for next consistent operational and do reconciliation with
+ actual config (not only diff)
+
+ZipQueue
+^^^^^^^^
+
+- only the diff (before/after) between last config changes is sent to
+ device
+
+- when there are more config changes for device in a row waiting to be
+ processed they are compressed into one entry (after is still replaced
+ with the latest)
+
+Cluster-aware
+^^^^^^^^^^^^^
+
+- FRS is cluster aware using ClusteringSingletonServiceProvider from
+ the MD-SAL
+
+- on mastership change reconciliation is done (register for reconcile)
+
+SalFlatBatchService
+^^^^^^^^^^^^^^^^^^^
+
+FRS uses service with implemented barrier waiting logic between
+dependent objects
+
+Service: SalFlatBatchService
+----------------------------
+
+Basics
+~~~~~~
+
+SalFlatBatchService was created along forwardingrules-sync application
+as the service that should application used by default. This service uses
+only one input with bag of flow/group/meter objects and their common
+add/update/remove action. So you practically send only one input (of specific
+bags) to this service.
+
+- interface: *org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.SalFlatBatchService*
+
+- implementation: *org.opendaylight.openflowplugin.impl.services.SalFlatBatchServiceImpl*
+
+- method: *processFlatBatch(input)*
+
+- input: *org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchInput*
+
+Usage benefits
+^^^^^^^^^^^^^^
+
+- possibility to use only one input bag with particular failure analysis preserved
+
+- automatic barrier decision (chain+wait)
+
+- less RPC routing in cluster environment (since one call encapsulates all others)
+
+ProcessFlatBatchInput
+~~~~~~~~~~~~~~~~~~~~~
+
+Input for SalFlatBatchService (ProcessFlatBatchInput object) consists of:
+
+- node - NodeRef
+
+- batch steps - List<Batch> - defined action + bag of objects + order for failures analysis
+
+ - BatchChoice - yang-modeled action choice (e.g. FlatBatchAddFlowCase) containing batch bag of objects (e.g. flows to be added)
+
+ - BatchOrder - (integer) order of batch step (should be incremented by single action)
+
+- exitOnFirstError - boolean flag
+
+Workflow
+~~~~~~~~
+#. prepare **list of steps** based on input
+
+#. **mark barriers** in steps where needed
+
+#. prepare particular **F/G/M-batch** service calls from **Flat-batch** steps
+
+ - F/G/M-batch services encapsulate bulk of single service calls
+
+ - they actually chain barrier after processing all single calls if actual step is marked as barrier-needed
+
+#. **chain** futures and **start** executing
+
+ - start all actions that can be run simultaneously (chain all on one starting point)
+
+ - in case there is a step marked as barrier-needed
+
+ - wait for all fired jobs up to one with barrier
+
+ - merge rpc results (status, errors, batch failures) into single one
+
+ - the latest job with barrier is new starting point for chaining
+
+Services encapsulation
+^^^^^^^^^^^^^^^^^^^^^^
+
+- SalFlatBatchService
+
+ - SalFlowBatchService
+
+ - SalFlowService
+
+ - SalGroupBatchService
+
+ - SalGroupService
+
+ - SalMeterBatchService
+
+ - SalMeterService
+
+Barrier decision
+^^^^^^^^^^^^^^^^
+
+- decide on actual step and all previous steps since the latest barrier
+
+- if condition in table below is satisfied the latest step before actual is marked as barrier-needed
+
++---------------------------+------------------------------------------------------------------+
+| actual step | previous steps contain |
++===========================+==================================================================+
+| FLOW_ADD *or* FLOW_UPDATE | GROUP_ADD *or* METER_ADD |
++---------------------------+------------------------------------------------------------------+
+| GROUP_ADD | GROUP_ADD *or* GROUP_UPDATE |
++---------------------------+------------------------------------------------------------------+
+| GROUP_REMOVE | FLOW_UPDATE *or* FLOW_REMOVE *or* GROUP_UPDATE *or* GROUP_REMOVE |
++---------------------------+------------------------------------------------------------------+
+| METER_REMOVE | FLOW_UPDATE *or* FLOW_REMOVE |
++---------------------------+------------------------------------------------------------------+
+
+Error handling
+^^^^^^^^^^^^^^
+
+There is flag in ProcessFlatBatchInput to stop process on the first error.
+
+- *true* - if partial step is not successful stop whole processing
+
+- *false* (default) - try to process all steps regardless partial results
+
+If error occurs in any of partial steps upper FlatBatchService call will return as unsuccessful in both cases.
+However every partial error is attached to general flat batch result along with BatchFailure (contains BatchOrder
+and BatchItemIdChoice to identify failed step).
+
+Cluster singleton approach in plugin
+------------------------------------
+
+Basics
+~~~~~~
+
+Description
+^^^^^^^^^^^
+
+The existing OpenDaylight service deployment model assumes symmetric
+clusters, where all services are activated on all nodes in the cluster.
+However, many services require that there is a single active service
+instance per cluster. We call such services *singleton services*. The
+Entity Ownership Service (EOS) represents the base Leadership choice for
+one Entity instance. Every Cluster Singleton service **type** must have
+its own Entity and every Cluster Singleton service **instance** must
+have its own Entity Candidate. Every registered Entity Candidate should
+be notified about its actual role. All this "work" is done by MD-SAL so
+the Openflowplugin need "only" to register as service in
+**SingletonClusteringServiceProvider** given by MD-SAL.
+
+Change against using EOS service listener
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In this new clustering singleton approach plugin uses API from the
+MD-SAL project: SingletonClusteringService which comes with three
+methods.
+
+::
+
+ instantiateServiceInstance()
+ closeServiceInstance()
+ getIdentifier()
+
+This service has to be registered to a
+SingletonClusteringServiceProvider from MD-SAL which take care if
+mastership is changed in cluster environment.
+
+First method in SingletonClusteringService is being called when the
+cluster node becomes a MASTER. Second is being called when status
+changes to SLAVE or device is disconnected from cluster. Last method
+plugins returns NodeId as ServiceGroupIdentifier Startup after device is
+connected
+
+On the start up the plugin we need to initialize first four managers for
+each working area providing information and services
+
+- Device manager
+
+- RPC manager
+
+- Role manager
+
+- Statistics manager
+
+After connection the device the listener Device manager get the event
+and start up to creating the context for this connection. Startup after
+device connection
+
+Services are managed by SinlgetonClusteringServiceProvider from MD-SAL
+project. So in startup we simply create a instance of LifecycleService
+and register all contexts into it.
+
+Role change
+~~~~~~~~~~~
+
+Plugin is no longer registered as Entity Ownership Service (EOS)
+listener therefore does not need to and cannot respond on EOS ownership
+changes.
+
+Service start
+^^^^^^^^^^^^^
+
+Services start asynchronously but the start is managed by
+LifecycleService. If something goes wrong LifecycleService stop starting
+services in context and this speeds up the reconnect process. But the
+services haven’t changed and plugin need to start all this:
+
+- Activating transaction chain manager
+
+- Initial gathering of device statistics
+
+- Initial submit to DS
+
+- Sending role MASTER to device
+
+- RPC services registration
+
+- Statistics gathering start
+
+Service stop
+^^^^^^^^^^^^
+
+If closeServiceInstance occurred plugin just simply try to store all
+unsubmitted transactions and close the transaction chain manager, stop
+RPC services, stop Statistics gathering and after that all unregister
+txEntity from EOS.
+
+Yang models and API
+-------------------
+
++--------------------------------------------------------+
+| Model |
++========================================================+
+| ***Openflow basic types*** |
++--------------------------------------------------------+
+| `opendaylight-table-types.yang <https://git.opendaylig |
+| ht.org/gerrit/gitweb?p=openflowplugin.git;f=model/mode |
+| l-flow-base/src/main/yang/opendaylight-table-types.yan |
+| g;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-action-types.yang <https://git.opendayli |
+| ght.org/gerrit/gitweb?p=openflowplugin.git;f=model/mod |
+| el-flow-base/src/main/yang/opendaylight-action-types.y |
+| ang;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-flow-types.yang <https://git.opendayligh |
+| t.org/gerrit/gitweb?p=openflowplugin.git;f=model/model |
+| -flow-base/src/main/yang/opendaylight-flow-types.yang; |
+| a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-meter-types.yang <https://git.opendaylig |
+| ht.org/gerrit/gitweb?p=openflowplugin.git;f=model/mode |
+| l-flow-base/src/main/yang/opendaylight-meter-types.yan |
+| g;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-group-types.yang <https://git.opendaylig |
+| ht.org/gerrit/gitweb?p=openflowplugin.git;f=model/mode |
+| l-flow-base/src/main/yang/opendaylight-group-types.yan |
+| g;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-match-types.yang <https://git.opendaylig |
+| ht.org/gerrit/gitweb?p=openflowplugin.git;f=model/mode |
+| l-flow-base/src/main/yang/opendaylight-match-types.yan |
+| g;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-port-types.yang <https://git.opendayligh |
+| t.org/gerrit/gitweb?p=openflowplugin.git;f=model/model |
+| -flow-base/src/main/yang/opendaylight-port-types.yang; |
+| a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-queue-types.yang <https://git.opendaylig |
+| ht.org/gerrit/gitweb?p=openflowplugin.git;f=model/mode |
+| l-flow-base/src/main/yang/opendaylight-queue-types.yan |
+| g;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| ***Openflow services*** |
++--------------------------------------------------------+
+| `sal-table.yang <https://git.opendaylight.org/gerrit/g |
+| itweb?p=openflowplugin.git;f=model/model-flow-service/ |
+| src/main/yang/sal-table.yang;a=blob;hb=refs/heads/stab |
+| le/boron>`__ |
++--------------------------------------------------------+
+| `sal-group.yang <https://git.opendaylight.org/gerrit/g |
+| itweb?p=openflowplugin.git;f=model/model-flow-service/ |
+| src/main/yang/sal-group.yang;a=blob;hb=refs/heads/stab |
+| le/boron>`__ |
++--------------------------------------------------------+
+| `sal-queue.yang <https://git.opendaylight.org/gerrit/g |
+| itweb?p=openflowplugin.git;f=model/model-flow-service/ |
+| src/main/yang/sal-queue.yang;a=blob;hb=refs/heads/stab |
+| le/boron>`__ |
++--------------------------------------------------------+
+| `flow-errors.yang <https://git.opendaylight.org/gerrit |
+| /gitweb?p=openflowplugin.git;f=model/model-flow-servic |
+| e/src/main/yang/flow-errors.yang;a=blob;hb=refs/heads/ |
+| stable/boron>`__ |
++--------------------------------------------------------+
+| `flow-capable-transaction.yang <https://git.opendaylig |
+| ht.org/gerrit/gitweb?p=openflowplugin.git;f=model/mode |
+| l-flow-service/src/main/yang/flow-capable-transaction. |
+| yang;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `sal-flow.yang <https://git.opendaylight.org/gerrit/gi |
+| tweb?p=openflowplugin.git;f=model/model-flow-service/s |
+| rc/main/yang/sal-flow.yang;a=blob;hb=refs/heads/stable |
+| /boron>`__ |
++--------------------------------------------------------+
+| `sal-meter.yang <https://git.opendaylight.org/gerrit/g |
+| itweb?p=openflowplugin.git;f=model/model-flow-service/ |
+| src/main/yang/sal-meter.yang;a=blob;hb=refs/heads/stab |
+| le/boron>`__ |
++--------------------------------------------------------+
+| `flow-topology-discovery.yang <https://git.opendayligh |
+| t.org/gerrit/gitweb?p=openflowplugin.git;f=model/model |
+| -flow-service/src/main/yang/flow-topology-discovery.ya |
+| ng;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `node-errors.yang <https://git.opendaylight.org/gerrit |
+| /gitweb?p=openflowplugin.git;f=model/model-flow-servic |
+| e/src/main/yang/node-errors.yang;a=blob;hb=refs/heads/ |
+| stable/boron>`__ |
++--------------------------------------------------------+
+| `node-config.yang <https://git.opendaylight.org/gerrit |
+| /gitweb?p=openflowplugin.git;f=model/model-flow-servic |
+| e/src/main/yang/node-config.yang;a=blob;hb=refs/heads/ |
+| stable/boron>`__ |
++--------------------------------------------------------+
+| `sal-echo.yang <https://git.opendaylight.org/gerrit/gi |
+| tweb?p=openflowplugin.git;f=model/model-flow-service/s |
+| rc/main/yang/sal-echo.yang;a=blob;hb=refs/heads/stable |
+| /boron>`__ |
++--------------------------------------------------------+
+| `sal-port.yang <https://git.opendaylight.org/gerrit/gi |
+| tweb?p=openflowplugin.git;f=model/model-flow-service/s |
+| rc/main/yang/sal-port.yang;a=blob;hb=refs/heads/stable |
+| /boron>`__ |
++--------------------------------------------------------+
+| `packet-processing.yang <https://git.opendaylight.org/ |
+| gerrit/gitweb?p=openflowplugin.git;f=model/model-flow- |
+| service/src/main/yang/packet-processing.yang;a=blob;hb |
+| =refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `flow-node-inventory.yang <https://git.opendaylight.or |
+| g/gerrit/gitweb?p=openflowplugin.git;f=model/model-flo |
+| w-service/src/main/yang/flow-node-inventory.yang;a=blo |
+| b;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| ***Openflow statistics*** |
++--------------------------------------------------------+
+| `opendaylight-queue-statistics.yang <https://git.opend |
+| aylight.org/gerrit/gitweb?p=openflowplugin.git;f=model |
+| /model-flow-statistics/src/main/yang/opendaylight-queu |
+| e-statistics.yang;a=blob;hb=refs/heads/stable/boron>`_ |
++--------------------------------------------------------+
+| `opendaylight-flow-table-statistics.yang <https://git. |
+| opendaylight.org/gerrit/gitweb?p=openflowplugin.git;f= |
+| model/model-flow-statistics/src/main/yang/opendaylight |
+| -flow-table-statistics.yang;a=blob;hb=refs/heads/stabl |
+| e/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-port-statistics.yang <https://git.openda |
+| ylight.org/gerrit/gitweb?p=openflowplugin.git;f=model/ |
+| model-flow-statistics/src/main/yang/opendaylight-port- |
+| statistics.yang;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-statistics-types.yang <https://git.opend |
+| aylight.org/gerrit/gitweb?p=openflowplugin.git;f=model |
+| /model-flow-statistics/src/main/yang/opendaylight-stat |
+| istics-types.yang;a=blob;hb=refs/heads/stable/boron>`_ |
++--------------------------------------------------------+
+| `opendaylight-group-statistics.yang <https://git.opend |
+| aylight.org/gerrit/gitweb?p=openflowplugin.git;f=model |
+| /model-flow-statistics/src/main/yang/opendaylight-grou |
+| p-statistics.yang;a=blob;hb=refs/heads/stable/boron>`_ |
++--------------------------------------------------------+
+| `opendaylight-flow-statistics.yang <https://git.openda |
+| ylight.org/gerrit/gitweb?p=openflowplugin.git;f=model/ |
+| model-flow-statistics/src/main/yang/opendaylight-flow- |
+| statistics.yang;a=blob;hb=refs/heads/stable/boron>`__ |
++--------------------------------------------------------+
+| `opendaylight-meter-statistics.yang <https://git.opend |
+| aylight.org/gerrit/gitweb?p=openflowplugin.git;f=model |
+| /model-flow-statistics/src/main/yang/opendaylight-mete |
+| r-statistics.yang;a=blob;hb=refs/heads/stable/boron>`_ |
++--------------------------------------------------------+
+
+Karaf feature tree
+------------------
+
+.. figure:: ../images/odl-ofp-feature-tree.png
+ :alt: Openflow plugin karaf feature tree
+
+ Openflow plugin karaf feature tree
+
+Short
+`HOWTO <https://wiki.opendaylight.org/view/OpenDaylight_OpenFlow_Plugin:FeatureTreeHowto>`__
+create such a tree.
+
+Wiring up notifications
+-----------------------
+
+Introduction
+~~~~~~~~~~~~
+
+We need to translate OpenFlow messages coming up from the OpenFlow
+Protocol Library into
+MD-SAL Notification objects and then publish them to the MD-SAL.
+
+Mechanics
+~~~~~~~~~
+
+1. Create a Translator class
+
+2. Register the Translator
+
+3. Register the notificationPopListener to handle your Notification
+ Objects
+
+Create a Translator class
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can see an example in
+`PacketInTranslator.java <https://git.opendaylight.org/gerrit/gitweb?p=openflowplugin.git;a=blob;f=openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/translator/PacketInTranslator.java;hb=refs/heads/stable/boron>`__.
+
+First, simply create the class
+
+::
+
+ public class PacketInTranslator implements IMDMessageTranslator<OfHeader, List<DataObject>> {
+
+Then implement the translate function:
+
+::
+
+ public class PacketInTranslator implements IMDMessageTranslator<OfHeader, List<DataObject>> {
+
+ protected static final Logger LOG = LoggerFactory
+ .getLogger(PacketInTranslator.class);
+ @Override
+ public PacketReceived translate(SwitchConnectionDistinguisher cookie,
+ SessionContext sc, OfHeader msg) {
+ ...
+ }
+
+Make sure to check that you are dealing with the expected type and cast
+it:
+
+::
+
+ if(msg instanceof PacketInMessage) {
+ PacketInMessage message = (PacketInMessage)msg;
+ List<DataObject> list = new CopyOnWriteArrayList<DataObject>();
+
+Do your transation work and return
+
+::
+
+ PacketReceived pktInEvent = pktInBuilder.build();
+ list.add(pktInEvent);
+ return list;
+
+Register your Translator Class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Next you need to go to
+`MDController.java <https://git.opendaylight.org/gerrit/gitweb?p=openflowplugin.git;a=blob;f=openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/MDController.java;hb=refs/heads/stable/boron>`__
+and in init() add register your Translator:
+
+::
+
+ public void init() {
+ LOG.debug("Initializing!");
+ messageTranslators = new ConcurrentHashMap<>();
+ popListeners = new ConcurrentHashMap<>();
+ //TODO: move registration to factory
+ addMessageTranslator(ErrorMessage.class, OF10, new ErrorTranslator());
+ addMessageTranslator(ErrorMessage.class, OF13, new ErrorTranslator());
+ addMessageTranslator(PacketInMessage.class,OF10, new PacketInTranslator());
+ addMessageTranslator(PacketInMessage.class,OF13, new PacketInTranslator());
+
+Notice that there is a separate registration for each of OpenFlow 1.0
+and OpenFlow 1.3. Basically, you indicate the type of OpenFlow Protocol
+Library message you wish to translate for, the OpenFlow version, and an
+instance of your Translator.
+
+Register your MD-SAL Message for Notification to the MD-SAL
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Now, also in MDController.init() register to have the
+notificationPopListener handle your MD-SAL Message:
+
+::
+
+ addMessagePopListener(PacketReceived.class, new NotificationPopListener<DataObject>());
+
+You are done
+^^^^^^^^^^^^
+
+That’s all there is to it. Now when a message comes up from the OpenFlow
+Protocol Library, it will be translated and published to the MD-SAL.
+
+Message Order Preservation
+--------------------------
+
+While the Helium release of OpenFlow Plugin relied on queues to ensure
+messages were delivered in order, subsequent releases instead ensure
+that all the messages from a given device are delivered using the same
+thread and thus message order is guaranteed without queues. The OpenFlow
+plugin allocates a number of threads equal to twice the number of
+processor cores on machine it is run, e.g., 8 threads if the machine has
+4 cores.
+
+.. note::
+
+ While each device is assigned to one thread, multiple devices can be
+ assigned to the same thread.
Openflowplugin Documentation
============================
-This documentation provides information needed to help you write ODL
-Applications/Projects that can co-exist with other ODL Projects.
Contents:
.. toctree::
:maxdepth: 2
+ users/index
+ devs/index
specs/index
testplans/index
Openflowplugin Design Specifications
====================================
-Starting from Nitrogen, Openflowplugin uses RST format Design Specification document for all new features.
-These specifications are perfect way to understand various Openflowplugin features.
-
Contents:
.. toctree::
Openflowplugin Test Plans
=========================
-Starting from Nitrogen, Openflowplugin uses RST format Test Plan document for
-all new Test Suites.
-
Contents:
.. toctree::
--- /dev/null
+.. _ofp-architecture:
+
+OpenFlow Plugin Architeture
+===========================
+
+Overview
+--------
+
+OpenFlow is a vendor-neutral standard communications interface defined
+to enable interaction between the control and forwarding layers of an
+SDN architecture. The OpenFlow plugin project intends to develop a
+plugin to support implementations of the OpenFlow specification as it
+develops and evolves. Specifically the project has developed a plugin
+aiming to support OpenFlow 1.0 and 1.3.x. It can be extended to add
+support for subsequent OpenFlow specifications. The plugin is based on
+the Model Driven Service Abstraction Layer (MD-SAL) architecture.
+
+Goals
+-----
+
+- Southbound plugin and integration of OpenFlow 1.0/1.3.x library.
+
+- Ongoing support and integration of the OpenFlow specification.
+
+- The plugin should be implemented in an easily extensible manner.
+
+- Protocol verification activities will be performed on supported
+ OpenFlow specifications.
+
+High Level Architecture
+-----------------------
+
+.. figure:: ../images/plugin_arch.png
+
+- **OpenFlowJava**: is a library that implements the OpenFlow codec –
+ it translates OpenFlow messages into their respective internal
+ representations and vice versa.
+
+- **OpenFlow Plugin**: terminates sessions to OpenFlow switches,
+ provides a per-switch low-level OpenFlow service API (add-modify-flow,
+ delete-flow, etc.)
+
+- **Statistics Manager**: is responsible for collecting statistics and
+ status from attached OpenFlow switches and storing them into the
+ operational data store for applications’ use.
+
+- **Topology Manager**: is responsible for discovering the OpenFlow
+ topology using LLDP and putting them into the operational data store
+ for applications’ use.
+
+- **Forwarding Rules Manager**: the “top level” OpenFlow module that
+ exposes the OF functionality to controller apps, provides the app-level
+ API. Main entity that manages the OpenFlow switch inventory and the
+ configuration (programming) of flows in switches. It also reconciles
+ user configuration with network state discovered by the OpenFlow plugin.
+
+
+Security
+--------
+
+It is strongly recommended that any production deployments utilising
+the OpenFlow Plugin do so with **TLS** encryption to protect against
+various man-in-the-middle attacks. For more details please refer
+to the :ref:`TLS section of the Operations guide <ofp-tls-guide>`.
+
+Protocol Coverage
+-----------------
+
+Coverage has been moved to a `GoogleDoc Spreadsheet
+<https://docs.google.com/spreadsheet/ccc?key=0AtpUuSEP8OyMdHNTZjBoM0VjOE9BcGhHMzk3N19uamc&usp=sharing%23gid=2#gid=0>`_
+
+OF 1.3 Considerations
+~~~~~~~~~~~~~~~~~~~~~
+
+The baseline model is a OF 1.3 model, and the coverage tables primarily
+deal with OF 1.3. However for OF 1.0, we have a column to indicate
+either N/A if it doesn’t apply, or whether its been confirmed working.
+
+OF 1.0 Considerations
+~~~~~~~~~~~~~~~~~~~~~
+
+OF 1.0 is being considered as a switch with: \* 1 Table \* 0 Groups \* 0
+Meters \* 1 Instruction (Apply Actions) \* and a limited vocabulary of
+matches and actions.
+
--- /dev/null
+.. _ofp-flow-examples:
+
+Flow Examples
+-------------
+
+Overview
+~~~~~~~~
+
+The flow examples on this page are tested to work with OVS.
+
+Use, for example, POSTMAN with the following parameters:
+
+::
+
+ PUT http://<ctrl-addr>:8181/restconf/config/opendaylight-inventory:nodes/node/<Node-id>/table/<Table-#>/flow/<Flow-#>
+
+ - Accept: application/xml
+ - Content-Type: application/xml
+
+For example:
+
+::
+
+ PUT http://localhost:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2/flow/127
+
+Make sure that the Table-# and Flow-# in the URL and in the XML match.
+
+The format of the flow-programming XML is determined by by the grouping
+*flow* in the opendaylight-flow-types yang model: MISSING LINK.
+
+Match Examples
+~~~~~~~~~~~~~~
+
+The format of the XML that describes OpenFlow matches is determined by
+the opendaylight-match-types yang model: .
+
+IPv4 Dest Address
+^^^^^^^^^^^^^^^^^
+
+- Flow=124, Table=2, Priority=2,
+ Instructions=\\{Apply\_Actions={dec\_nw\_ttl}},
+ match=\\{ipv4\_destination\_address=10.0.1.1/24}
+
+- Note that ethernet-type MUST be 2048 (0x800)
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>124</id>
+ <cookie_mask>255</cookie_mask>
+ <installHw>false</installHw>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv4-destination>10.0.1.1/24</ipv4-destination>
+ </match>
+ <hard-timeout>12</hard-timeout>
+ <cookie>1</cookie>
+ <idle-timeout>34</idle-timeout>
+ <flow-name>FooXf1</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+ </flow>
+
+Ethernet Src Address
+^^^^^^^^^^^^^^^^^^^^
+
+- Flow=126, Table=2, Priority=2,
+ Instructions=\\{Apply\_Actions={drop}},
+ match=\\{ethernet-source=00:00:00:00:00:01}
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <drop-action/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>126</id>
+ <cookie_mask>255</cookie_mask>
+ <installHw>false</installHw>
+ <match>
+ <ethernet-match>
+ <ethernet-source>
+ <address>00:00:00:00:00:01</address>
+ </ethernet-source>
+ </ethernet-match>
+ </match>
+ <hard-timeout>12</hard-timeout>
+ <cookie>3</cookie>
+ <idle-timeout>34</idle-timeout>
+ <flow-name>FooXf3</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+ </flow>
+
+Ethernet Src & Dest Addresses, Ethernet Type
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Flow=127, Table=2, Priority=2,
+ Instructions=\\{Apply\_Actions={drop}},
+ match=\\{ethernet-source=00:00:00:00:23:ae,
+ ethernet-destination=ff:ff:ff:ff:ff:ff, ethernet-type=45}
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-mpls-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>127</id>
+ <cookie_mask>255</cookie_mask>
+ <installHw>false</installHw>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>45</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:ff:ff:ff:ff</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:00:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ </match>
+ <hard-timeout>12</hard-timeout>
+ <cookie>4</cookie>
+ <idle-timeout>34</idle-timeout>
+ <flow-name>FooXf4</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+ </flow>
+
+Ethernet Src & Dest Addresses, IPv4 Src & Dest Addresses, Input Port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Note that ethernet-type MUST be 34887 (0x8847)
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-mpls-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>128</id>
+ <cookie_mask>255</cookie_mask>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34887</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:ff:ff:ff:ff</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:00:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>10.1.2.3/24</ipv4-source>
+ <ipv4-destination>20.4.5.6/16</ipv4-destination>
+ <in-port>0</in-port>
+ </match>
+ <hard-timeout>12</hard-timeout>
+ <cookie>5</cookie>
+ <idle-timeout>34</idle-timeout>
+ <flow-name>FooXf5</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+ </flow>
+
+Ethernet Src & Dest Addresses, IPv4 Src & Dest Addresses, IP
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Protocol #, IP DSCP, IP ECN, Input Port
+
+- Note that ethernet-type MUST be 2048 (0x800)
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>130</id>
+ <cookie_mask>255</cookie_mask>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:ff:ff:ff:aa</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>10.1.2.3/24</ipv4-source>
+ <ipv4-destination>20.4.5.6/16</ipv4-destination>
+ <ip-match>
+ <ip-protocol>56</ip-protocol>
+ <ip-dscp>15</ip-dscp>
+ <ip-ecn>1</ip-ecn>
+ </ip-match>
+ <in-port>0</in-port>
+ </match>
+ <hard-timeout>12000</hard-timeout>
+ <cookie>7</cookie>
+ <idle-timeout>12000</idle-timeout>
+ <flow-name>FooXf7</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+ </flow>
+
+Ethernet Src & Dest Addresses, IPv4 Src & Dest Addresses, TCP Src &
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Dest Ports, IP DSCP, IP ECN, Input Port
+
+- Note that ethernet-type MUST be 2048 (0x800)
+
+- Note that IP Protocol Type MUST be 6
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>131</id>
+ <cookie_mask>255</cookie_mask>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>17.1.2.3/8</ipv4-source>
+ <ipv4-destination>172.168.5.6/16</ipv4-destination>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>2</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>25364</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ <in-port>0</in-port>
+ </match>
+ <hard-timeout>1200</hard-timeout>
+ <cookie>8</cookie>
+ <idle-timeout>3400</idle-timeout>
+ <flow-name>FooXf8</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+ </flow>
+
+Ethernet Src & Dest Addresses, IPv4 Src & Dest Addresses, UDP Src &
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Dest Ports, IP DSCP, IP ECN, Input Port
+
+- Note that ethernet-type MUST be 2048 (0x800)
+
+- Note that IP Protocol Type MUST be 17
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>132</id>
+ <cookie_mask>255</cookie_mask>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>20:14:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>19.1.2.3/10</ipv4-source>
+ <ipv4-destination>172.168.5.6/18</ipv4-destination>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ <in-port>0</in-port>
+ </match>
+ <hard-timeout>1200</hard-timeout>
+ <cookie>9</cookie>
+ <idle-timeout>3400</idle-timeout>
+ <flow-name>FooXf9</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+
+Ethernet Src & Dest Addresses, IPv4 Src & Dest Addresses, ICMPv4
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Type & Code, IP DSCP, IP ECN, Input Port
+
+- Note that ethernet-type MUST be 2048 (0x800)
+
+- Note that IP Protocol Type MUST be 1
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>134</id>
+ <cookie_mask>255</cookie_mask>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>17.1.2.3/8</ipv4-source>
+ <ipv4-destination>172.168.5.6/16</ipv4-destination>
+ <ip-match>
+ <ip-protocol>1</ip-protocol>
+ <ip-dscp>27</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <icmpv4-match>
+ <icmpv4-type>6</icmpv4-type>
+ <icmpv4-code>3</icmpv4-code>
+ </icmpv4-match>
+ <in-port>0</in-port>
+ </match>
+ <hard-timeout>1200</hard-timeout>
+ <cookie>11</cookie>
+ <idle-timeout>3400</idle-timeout>
+ <flow-name>FooXf11</flow-name>
+ <priority>2</priority>
+ </flow>
+
+Ethernet Src & Dest Addresses, ARP Operation, ARP Src & Target
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Transport Addresses, ARP Src & Target Hw Addresses
+
+- Note that ethernet-type MUST be 2054 (0x806)
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ <action>
+ <order>1</order>
+ <dec-mpls-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>137</id>
+ <cookie_mask>255</cookie_mask>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2054</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:ff:ff:FF:ff</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:FC:01:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <arp-op>1</arp-op>
+ <arp-source-transport-address>192.168.4.1</arp-source-transport-address>
+ <arp-target-transport-address>10.21.22.23</arp-target-transport-address>
+ <arp-source-hardware-address>
+ <address>12:34:56:78:98:AB</address>
+ </arp-source-hardware-address>
+ <arp-target-hardware-address>
+ <address>FE:DC:BA:98:76:54</address>
+ </arp-target-hardware-address>
+ </match>
+ <hard-timeout>12</hard-timeout>
+ <cookie>14</cookie>
+ <idle-timeout>34</idle-timeout>
+ <flow-name>FooXf14</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+
+Ethernet Src & Dest Addresses, Ethernet Type, VLAN ID, VLAN PCP
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>2</table_id>
+ <id>138</id>
+ <cookie_mask>255</cookie_mask>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <vlan-match>
+ <vlan-id>
+ <vlan-id>78</vlan-id>
+ <vlan-id-present>true</vlan-id-present>
+ </vlan-id>
+ <vlan-pcp>3</vlan-pcp>
+ </vlan-match>
+ </match>
+ <hard-timeout>1200</hard-timeout>
+ <cookie>15</cookie>
+ <idle-timeout>3400</idle-timeout>
+ <flow-name>FooXf15</flow-name>
+ <priority>2</priority>
+ <barrier>false</barrier>
+ </flow>
+
+Ethernet Src & Dest Addresses, MPLS Label, MPLS TC, MPLS BoS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <flow-name>FooXf17</flow-name>
+ <id>140</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>17</cookie>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <priority>2</priority>
+ <table_id>2</table_id>
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34887</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <protocol-match-fields>
+ <mpls-label>567</mpls-label>
+ <mpls-tc>3</mpls-tc>
+ <mpls-bos>1</mpls-bos>
+ </protocol-match-fields>
+ </match>
+ </flow>
+
+IPv6 Src & Dest Addresses
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Note that ethernet-type MUST be 34525
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf18</flow-name>
+ <id>141</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>18</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>fe80::2acf:e9ff:fe21:6431/128</ipv6-source>
+ <ipv6-destination>aabb:1234:2acf:e9ff::fe21:6431/64</ipv6-destination>
+ </match>
+ </flow>
+
+Metadata
+^^^^^^^^
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf19</flow-name>
+ <id>142</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>19</cookie>
+ <table_id>2</table_id>
+ <priority>1</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ </match>
+ </flow>
+
+Metadata, Metadata Mask
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf20</flow-name>
+ <id>143</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>20</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <metadata>
+ <metadata>12345</metadata>
+ <metadata-mask>//FF</metadata-mask>
+ </metadata>
+ </match>
+ </flow>
+
+IPv6 Src & Dest Addresses, Metadata, IP DSCP, IP ECN, UDP Src & Dest Ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Note that ethernet-type MUST be 34525
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf21</flow-name>
+ <id>144</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>21</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80::2acf:e9ff:fe21:6431/128</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ </match>
+ </flow>
+
+IPv6 Src & Dest Addresses, Metadata, IP DSCP, IP ECN, TCP Src & Dest Ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Note that ethernet-type MUST be 34525
+
+- Note that IP Protocol MUST be 6
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf22</flow-name>
+ <id>145</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>22</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+ </flow>
+
+IPv6 Src & Dest Addresses, Metadata, IP DSCP, IP ECN, TCP Src & Dest Ports, IPv6 Label
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Note that ethernet-type MUST be 34525
+
+- Note that IP Protocol MUST be 6
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf23</flow-name>
+ <id>146</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>23</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ipv6-label>
+ <ipv6-flabel>33</ipv6-flabel>
+ </ipv6-label>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+ </flow>
+
+Tunnel ID
+^^^^^^^^^
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf24</flow-name>
+ <id>147</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>24</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <tunnel>
+ <tunnel-id>2591</tunnel-id>
+ </tunnel>
+ </match>
+ </flow>
+
+IPv6 Src & Dest Addresses, Metadata, IP DSCP, IP ECN, ICMPv6 Type & Code, IPv6 Label
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Note that ethernet-type MUST be 34525
+
+- Note that IP Protocol MUST be 58
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf25</flow-name>
+ <id>148</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>25</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ipv6-label>
+ <ipv6-flabel>33</ipv6-flabel>
+ </ipv6-label>
+ <ip-match>
+ <ip-protocol>58</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <icmpv6-match>
+ <icmpv6-type>6</icmpv6-type>
+ <icmpv6-code>3</icmpv6-code>
+ </icmpv6-match>
+ </match>
+ </flow>
+
+IPv6 Src & Dest Addresses, Metadata, IP DSCP, IP ECN, TCP Src & Dst Ports, IPv6 Label, IPv6 Ext Header
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Note that ethernet-type MUST be 34525
+
+- Note that IP Protocol MUST be 58
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf27</flow-name>
+ <id>150</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>27</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <dec-nw-ttl/>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ipv6-label>
+ <ipv6-flabel>33</ipv6-flabel>
+ </ipv6-label>
+ <ipv6-ext-header>
+ <ipv6-exthdr>0</ipv6-exthdr>
+ </ipv6-ext-header>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+ </flow>
+
+Actions
+~~~~~~~
+
+The format of the XML that describes OpenFlow actions is determined by
+the opendaylight-action-types yang model: .
+
+Apply Actions
+^^^^^^^^^^^^^
+
+Output to TABLE
+'''''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf101</flow-name>
+ <id>256</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>101</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>TABLE</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+ </flow>
+
+Output to INPORT
+''''''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf102</flow-name>
+ <id>257</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>102</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>INPORT</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ 7 </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>17.1.2.3/8</ipv4-source>
+ <ipv4-destination>172.168.5.6/16</ipv4-destination>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>2</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>25364</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+ </flow>
+
+Output to Physical Port
+'''''''''''''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf103</flow-name>
+ <id>258</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>103</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>1</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>ff:ff:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>17.1.2.3/8</ipv4-source>
+ <ipv4-destination>172.168.5.6/16</ipv4-destination>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>2</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>25364</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+ </flow>
+
+Output to LOCAL
+'''''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf104</flow-name>
+ <id>259</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>104</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>LOCAL</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/76</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/94</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>60</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <tcp-source-port>183</tcp-source-port>
+ <tcp-destination-port>8080</tcp-destination-port>
+ </match>
+ </flow>
+
+Output to NORMAL
+''''''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf105</flow-name>
+ <id>260</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>105</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>NORMAL</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/84</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/90</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>45</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>20345</tcp-source-port>
+ <tcp-destination-port>80</tcp-destination-port>
+ </match>
+ </flow>
+
+Output to FLOOD
+'''''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf106</flow-name>
+ <id>261</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>106</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>FLOOD</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34525</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv6-source>1234:5678:9ABC:DEF0:FDCD:A987:6543:210F/100</ipv6-source>
+ <ipv6-destination>fe80:2acf:e9ff:fe21::6431/67</ipv6-destination>
+ <metadata>
+ <metadata>12345</metadata>
+ </metadata>
+ <ip-match>
+ <ip-protocol>6</ip-protocol>
+ <ip-dscp>45</ip-dscp>
+ <ip-ecn>2</ip-ecn>
+ </ip-match>
+ <tcp-source-port>20345</tcp-source-port>
+ <tcp-destination-port>80</tcp-destination-port>
+ </match>
+ </flow>
+
+Output to ALL
+'''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf107</flow-name>
+ <id>262</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>107</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>ALL</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>20:14:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>19.1.2.3/10</ipv4-source>
+ <ipv4-destination>172.168.5.6/18</ipv4-destination>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ <in-port>0</in-port>
+ </match>
+ </flow>
+
+Output to CONTROLLER
+''''''''''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf108</flow-name>
+ <id>263</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>108</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>CONTROLLER</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>20:14:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>19.1.2.3/10</ipv4-source>
+ <ipv4-destination>172.168.5.6/18</ipv4-destination>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ <in-port>0</in-port>
+ </match>
+ </flow>
+
+Output to ANY
+'''''''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <flow-name>FooXf109</flow-name>
+ <id>264</id>
+ <cookie_mask>255</cookie_mask>
+ <cookie>109</cookie>
+ <table_id>2</table_id>
+ <priority>2</priority>
+ <hard-timeout>1200</hard-timeout>
+ <idle-timeout>3400</idle-timeout>
+ <installHw>false</installHw>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <output-node-connector>ANY</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>20:14:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:ae</address>
+ </ethernet-source>
+ </ethernet-match>
+ <ipv4-source>19.1.2.3/10</ipv4-source>
+ <ipv4-destination>172.168.5.6/18</ipv4-destination>
+ <ip-match>
+ <ip-protocol>17</ip-protocol>
+ <ip-dscp>8</ip-dscp>
+ <ip-ecn>3</ip-ecn>
+ </ip-match>
+ <udp-source-port>25364</udp-source-port>
+ <udp-destination-port>8080</udp-destination-port>
+ <in-port>0</in-port>
+ </match>
+ </flow>
+
+Push VLAN
+'''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <strict>false</strict>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <push-vlan-action>
+ <ethernet-type>33024</ethernet-type>
+ </push-vlan-action>
+ <order>0</order>
+ </action>
+ <action>
+ <set-field>
+ <vlan-match>
+ <vlan-id>
+ <vlan-id>79</vlan-id>
+ <vlan-id-present>true</vlan-id-present>
+ </vlan-id>
+ </vlan-match>
+ </set-field>
+ <order>1</order>
+ </action>
+ <action>
+ <output-action>
+ <output-node-connector>5</output-node-connector>
+ </output-action>
+ <order>2</order>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <table_id>0</table_id>
+ <id>31</id>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ <ethernet-destination>
+ <address>FF:FF:29:01:19:61</address>
+ </ethernet-destination>
+ <ethernet-source>
+ <address>00:00:00:11:23:AE</address>
+ </ethernet-source>
+ </ethernet-match>
+ <in-port>1</in-port>
+ </match>
+ <flow-name>vlan_flow</flow-name>
+ <priority>2</priority>
+ </flow>
+
+Push MPLS
+'''''''''
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow
+ xmlns="urn:opendaylight:flow:inventory">
+ <flow-name>push-mpls-action</flow-name>
+ <instructions>
+ <instruction>
+ <order>3</order>
+ <apply-actions>
+ <action>
+ <push-mpls-action>
+ <ethernet-type>34887</ethernet-type>
+ </push-mpls-action>
+ <order>0</order>
+ </action>
+ <action>
+ <set-field>
+ <protocol-match-fields>
+ <mpls-label>27</mpls-label>
+ </protocol-match-fields>
+ </set-field>
+ <order>1</order>
+ </action>
+ <action>
+ <output-action>
+ <output-node-connector>2</output-node-connector>
+ </output-action>
+ <order>2</order>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <strict>false</strict>
+ <id>100</id>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ </ethernet-match>
+ <in-port>1</in-port>
+ <ipv4-destination>10.0.0.4/32</ipv4-destination>
+ </match>
+ <idle-timeout>0</idle-timeout>
+ <cookie_mask>255</cookie_mask>
+ <cookie>401</cookie>
+ <priority>8</priority>
+ <hard-timeout>0</hard-timeout>
+ <installHw>false</installHw>
+ <table_id>0</table_id>
+ </flow>
+
+Swap MPLS
+'''''''''
+
+- Note that ethernet-type MUST be 34887
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow
+ xmlns="urn:opendaylight:flow:inventory">
+ <flow-name>push-mpls-action</flow-name>
+ <instructions>
+ <instruction>
+ <order>2</order>
+ <apply-actions>
+ <action>
+ <set-field>
+ <protocol-match-fields>
+ <mpls-label>37</mpls-label>
+ </protocol-match-fields>
+ </set-field>
+ <order>1</order>
+ </action>
+ <action>
+ <output-action>
+ <output-node-connector>2</output-node-connector>
+ </output-action>
+ <order>2</order>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <strict>false</strict>
+ <id>101</id>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34887</type>
+ </ethernet-type>
+ </ethernet-match>
+ <in-port>1</in-port>
+ <protocol-match-fields>
+ <mpls-label>27</mpls-label>
+ </protocol-match-fields>
+ </match>
+ <idle-timeout>0</idle-timeout>
+ <cookie_mask>255</cookie_mask>
+ <cookie>401</cookie>
+ <priority>8</priority>
+ <hard-timeout>0</hard-timeout>
+ <installHw>false</installHw>
+ <table_id>0</table_id>
+ </flow>
+
+Pop MPLS
+''''''''
+
+- Note that ethernet-type MUST be 34887
+
+- Issue with OVS 2.1 `OVS
+ fix <http://git.openvswitch.org/cgi-bin/gitweb.cgi?p=openvswitch;a=commitdiff;h=b3f2fc93e3f357f8d05a92f53ec253339a40887f>`_
+
+.. code:: xml
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow
+ xmlns="urn:opendaylight:flow:inventory">
+ <flow-name>FooXf10</flow-name>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <pop-mpls-action>
+ <ethernet-type>2048</ethernet-type>
+ </pop-mpls-action>
+ <order>1</order>
+ </action>
+ <action>
+ <output-action>
+ <output-node-connector>2</output-node-connector>
+ <max-length>60</max-length>
+ </output-action>
+ <order>2</order>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <id>11</id>
+ <strict>false</strict>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>34887</type>
+ </ethernet-type>
+ </ethernet-match>
+ <in-port>1</in-port>
+ <protocol-match-fields>
+ <mpls-label>37</mpls-label>
+ </protocol-match-fields>
+ </match>
+ <idle-timeout>0</idle-timeout>
+ <cookie>889</cookie>
+ <cookie_mask>255</cookie_mask>
+ <installHw>false</installHw>
+ <hard-timeout>0</hard-timeout>
+ <priority>10</priority>
+ <table_id>0</table_id>
+ </flow>
+
+Learn
+'''''
+
+- Nicira extension defined in
+ https://github.com/osrg/openvswitch/blob/master/include/openflow/nicira-ext.h
+
+- Example section is -
+ https://github.com/osrg/openvswitch/blob/master/include/openflow/nicira-ext.h#L788
+
+.. code:: xml
+
+ <flow>
+ <id>ICMP_Ingress258a5a5ad-08a8-4ff7-98f5-ef0b96ca3bb8</id>
+ <hard-timeout>0</hard-timeout>
+ <idle-timeout>0</idle-timeout>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ </ethernet-match>
+ <metadata>
+ <metadata>2199023255552</metadata>
+ <metadata-mask>2305841909702066176</metadata-mask>
+ </metadata>
+ <ip-match>
+ <ip-protocol>1</ip-protocol>
+ </ip-match>
+ </match>
+ <cookie>110100480</cookie>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>1</order>
+ <nx-resubmit
+ xmlns="urn:opendaylight:openflowplugin:extension:nicira:action">
+ <table>220</table>
+ </nx-resubmit>
+ </action>
+ <action>
+ <order>0</order>
+ <nx-learn
+ xmlns="urn:opendaylight:openflowplugin:extension:nicira:action">
+ <idle-timeout>60</idle-timeout>
+ <fin-idle-timeout>0</fin-idle-timeout>
+ <hard-timeout>60</hard-timeout>
+ <flags>0</flags>
+ <table-id>41</table-id>
+ <priority>61010</priority>
+ <fin-hard-timeout>0</fin-hard-timeout>
+ <flow-mods>
+ <flow-mod-add-match-from-value>
+ <src-ofs>0</src-ofs>
+ <value>2048</value>
+ <src-field>1538</src-field>
+ <flow-mod-num-bits>16</flow-mod-num-bits>
+ </flow-mod-add-match-from-value>
+ </flow-mods>
+ <flow-mods>
+ <flow-mod-add-match-from-field>
+ <src-ofs>0</src-ofs>
+ <dst-ofs>0</dst-ofs>
+ <dst-field>4100</dst-field>
+ <src-field>3588</src-field>
+ <flow-mod-num-bits>32</flow-mod-num-bits>
+ </flow-mod-add-match-from-field>
+ </flow-mods>
+ <flow-mods>
+ <flow-mod-add-match-from-field>
+ <src-ofs>0</src-ofs>
+ <dst-ofs>0</dst-ofs>
+ <dst-field>518</dst-field>
+ <src-field>1030</src-field>
+ <flow-mod-num-bits>48</flow-mod-num-bits>
+ </flow-mod-add-match-from-field>
+ </flow-mods>
+ <flow-mods>
+ <flow-mod-add-match-from-field>
+ <src-ofs>0</src-ofs>
+ <dst-ofs>0</dst-ofs>
+ <dst-field>3073</dst-field>
+ <src-field>3073</src-field>
+ <flow-mod-num-bits>8</flow-mod-num-bits>
+ </flow-mod-add-match-from-field>
+ </flow-mods>
+ <flow-mods>
+ <flow-mod-copy-value-into-field>
+ <dst-ofs>0</dst-ofs>
+ <value>1</value>
+ <dst-field>65540</dst-field>
+ <flow-mod-num-bits>8</flow-mod-num-bits>
+ </flow-mod-copy-value-into-field>
+ </flow-mods>
+ <cookie>110100480</cookie>
+ </nx-learn>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <installHw>true</installHw>
+ <barrier>false</barrier>
+ <strict>false</strict>
+ <priority>61010</priority>
+ <table_id>253</table_id>
+ <flow-name>ACL</flow-name>
+ </flow>
+
--- /dev/null
+Openflowplugin User Guides
+==========================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 1
+
+ Architecture <architecture>
+ Installation <installation>
+ Operation <operation>
+ Flow examples <flow-examples>
--- /dev/null
+.. _ofp-installation:
+
+OpenFlow Plugin Installation
+============================
+
+OpenFlow Plugin installation follows standard OpenDaylight installation procedure
+described in install-odl_.
+
+Next sections describe typical OpenFlow user and test features. For a complete list
+of available features check the OpenFlow Plugin Release Notes.
+
+Typical User features
+---------------------
+
+- **odl-openflowplugin-flow-services-rest**: OF plugin with REST API.
+- **odl-openflowplugin-app-table-miss-enforcer**: Adds default flow to controller.
+- **odl-openflowplugin-nxm-extensions**: Nicira extensions for OVS.
+
+Typical Test features
+---------------------
+
+- **odl-openflowplugin-app-table-miss-enforcer**: Adds default flow to controller.
+- **odl-openflowplugin-drop-test**: Test application for pushing flows on packet-in.
+- **odl-openflowplugin-app-bulk-o-matic**: Test application for pushing bulk flows.
+
+.. _install-odl: https://docs.opendaylight.org/en/latest/getting-started-guide/installing_opendaylight.html
+
--- /dev/null
+.. _ofp-operation:
+
+OpenFlow Plugin Operation
+=========================
+
+Overview
+--------
+
+The OpenFlow standard describes a communications protocol that allows
+an external application, such as an SDN Controller, to access and
+configure the forwarding plane of a network device normally called
+the OpenFlow-enabled switch.
+
+The switch and the controller communicate by exchanging OpenFlow
+protocol messages, which the controller uses to add, modify, and delete
+flows in the switch. By using OpenFlow, it is possible to control
+various aspects of the network, such as traffic forwarding, topology
+discovery, Quality of Service, and so on.
+
+For more information about OpenFlow, refer to the Open Networking
+Foundation website openflow-specs_.
+
+The OpenFlow Plugin provides the following RESTCONF APIs:
+
+- OpenFlow Topology
+- OpenFlow Statistics
+- OpenFlow Programming
+
+OpenFlow Topology
+-----------------
+
+The controller provides a centralized logical view of the OpenFlow network.
+
+The controller uses Link Layer Discovery Protocol (LLDP) messages to discover
+the links between the connected OpenFlow devices. The topology manager
+stores and manages the information (nodes and links) in the controller
+data stores.
+
+This works as follows:
+
+- LLDP speaker application sends LLDP packets to all the node connectors of
+ all the switches that are connected.
+
+- LLDP speaker application also monitors status events for a node connector.
+ If the status of a node connector for the connected switch changes from up
+ to down, the LLDP speaker does not send packets out to that node connector.
+ If the status changes from down to up, the LLDP speaker sends packets to
+ that node connector.
+
+- The LLDP discovery application monitors the LLDP packets that are sent by a
+ switch to the controller and notifies the topology manager of a new
+ link-discovery event. The information includes: source node, source node
+ connector, destination node, and destination node connector, from the
+ received LLDP packets.
+
+- The LLDP discovery application also checks for an expired link and notifies
+ the topology manager. A link expires when it does not receive an update from
+ the switch for the three LLDP speaker cycles.
+
+Retrieving topology details by using RESTCONF
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can retrieve OpenFlow topology information (nodes and links) from the
+controller by sending a RESTCONF request. The controller fetches the topology
+data from the operational datastore and returns it in response to the RESTCONF
+request.
+
+To view the topology data for all the connected nodes, send the following
+request to the controller:
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/network-topology:network-topology/topology/flow:1``
+
+**Method:** GET
+
+**Sample output:**
+
+.. code-block:: none
+
+ <topology xmlns="urn:TBD:params:xml:ns:yang:network-topology">
+ <topology-id>flow:1</topology-id>
+ <node>
+ <node-id>openflow:1</node-id>
+ <inventory-node-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:1']</inventory-node-ref>
+ <termination-point>
+ <tp-id>openflow:1:1</tp-id>
+ <inventory-node-connector-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:1']/a:node-connector[a:id='openflow:1:1']</inventory-node-connector-ref>
+ </termination-point>
+ <termination-point>
+ <tp-id>openflow:1:LOCAL</tp-id>
+ <inventory-node-connector-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:1']/a:node-connector[a:id='openflow:1:LOCAL']</inventory-node-connector-ref>
+ </termination-point>
+ <termination-point>
+ <tp-id>openflow:1:2</tp-id>
+ <inventory-node-connector-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:1']/a:node-connector[a:id='openflow:1:2']</inventory-node-connector-ref>
+ </termination-point>
+ </node>
+ <node>
+ <node-id>openflow:2</node-id>
+ <inventory-node-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:2']</inventory-node-ref>
+ <termination-point>
+ <tp-id>openflow:2:2</tp-id>
+ <inventory-node-connector-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:2']/a:node-connector[a:id='openflow:2:2']</inventory-node-connector-ref>
+ </termination-point>
+ <termination-point>
+ <tp-id>openflow:2:LOCAL</tp-id>
+ <inventory-node-connector-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:2']/a:node-connector[a:id='openflow:2:LOCAL']</inventory-node-connector-ref>
+ </termination-point>
+ <termination-point>
+ <tp-id>openflow:2:1</tp-id>
+ <inventory-node-connector-ref xmlns="urn:opendaylight:model:topology:inventory" xmlns:a="urn:opendaylight:inventory">/a:nodes/a:node[a:id='openflow:2']/a:node-connector[a:id='openflow:2:1']</inventory-node-connector-ref>
+ </termination-point>
+ </node>
+ <link>
+ <link-id>openflow:2:2</link-id>
+ <source>
+ <source-node>openflow:2</source-node>
+ <source-tp>openflow:2:2</source-tp>
+ </source>
+ <destination>
+ <dest-node>openflow:1</dest-node>
+ <dest-tp>openflow:1:2</dest-tp>
+ </destination>
+ </link>
+ <link>
+ <link-id>openflow:1:2</link-id>
+ <source>
+ <source-node>openflow:1</source-node>
+ <source-tp>openflow:1:2</source-tp>
+ </source>
+ <destination>
+ <dest-node>openflow:2</dest-node>
+ <dest-tp>openflow:2:2</dest-tp>
+ </destination>
+ </link>
+ </topology>
+
+.. note:: In the example above the OpenFlow node is represented as openflow:1
+ where 1 is the datapath ID of the OpenFlow-enabled device.
+
+.. note:: In the example above the OpenFlow node connector is represented as
+ openflow:1:2 where 1 is the datapath ID and 2 is the port ID of the
+ OpenFlow-enabled device.
+
+OpenFlow Statistics
+-------------------
+
+The controller provides the following information for the connected
+OpenFlow devices:
+
+**Inventory information:**
+
+- **Node description:** Description of the OpenFlow-enabled device, such as
+ the switch manufacturer, hardware revision, software revision, serial number,
+ and so on.
+
+- **Flow table features:** Features supported by flow tables of the switch.
+
+- **Port description:** Properties supported by each node connector of the
+ node.
+
+- **Group features:** Features supported by the group table of the switch.
+
+- **Meter features:** Features supported by the meter table of the switch.
+
+**Statistics:**
+
+- **Individual flow statistics:** Statistics related to individual flow
+ installed in the flow table.
+
+- **Aggregate flow statistics:** Statistics related to aggregate flow for
+ each table level.
+
+- **Flow table statistics:** Statistics related to the individual flow table
+ of the switch.
+
+- **Port statistics:** Statistics related to all node connectors of the node.
+
+- **Group description:** Description of the groups installed in the switch
+ group table.
+
+- **Group statistics:** Statistics related to an individual group installed
+ in the group table.
+
+- **Meter configuration:** Statistics related to the configuration of the
+ meters installed in the switch meter table.
+
+- **Meter statistics:** Statistics related to an individual meter installed
+ in the switch meter table.
+
+- **Queue statistics:** Statistics related to the queues created on each
+ node connector of the switch.
+
+The controller fetches both inventory and statistics information whenever a
+node connects to the controller. After that the controller fetches statistics
+periodically within a time interval of three seconds. The controller augments
+inventory information and statistics fetched from each connected node to its
+respective location in the operational data store. The controller also cleans
+the stale statistics at periodic intervals.
+
+You can retrieve the inventory information (nodes, ports, and tables) and
+statistics (ports, flows, groups and meters) by sending a RESTCONF request.
+The controller fetches the inventory data from the operational data store
+and returns it in response to the RESTCONF request.
+
+The following sections provide a few examples for retrieving inventory and
+statistics information.
+
+Example of node inventory data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To view the inventory data of a connected node, send the following request to
+the controller:
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/opendaylight-inventory:nodes/node/openflow:1``
+
+**Method:** ``GET``
+
+**Sample output:**
+
+.. code-block:: none
+
+ <node>
+ <hardware xmlns="urn:opendaylight:flow:inventory">Open vSwitch</hardware>
+ <description xmlns="urn:opendaylight:flow:inventory">None</description>
+ <switch-features xmlns="urn:opendaylight:flow:inventory">
+ <max_tables>254</max_tables>
+ <max_buffers>0</max_buffers>
+ <capabilities>flow-feature-capability-queue-stats</capabilities>
+ <capabilities>flow-feature-capability-table-stats</capabilities>
+ <capabilities>flow-feature-capability-flow-stats</capabilities>
+ <capabilities>flow-feature-capability-port-stats</capabilities>
+ <capabilities>flow-feature-capability-group-stats</capabilities>
+ </switch-features>
+ <manufacturer xmlns="urn:opendaylight:flow:inventory">Nicira, Inc.</manufacturer>
+ <serial-number xmlns="urn:opendaylight:flow:inventory">None</serial-number>
+ <software xmlns="urn:opendaylight:flow:inventory">2.8.1</software>
+ <ip-address xmlns="urn:opendaylight:flow:inventory">192.168.0.24</ip-address>
+
+ --- Omitted output —--
+
+.. note:: In the example above the OpenFlow node is represented as openflow:1
+ where 1 is the datapath ID of the OpenFlow-enabled device.
+
+Example of port description and port statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To view the port description and port statistics of a connected node, send the
+following request to the controller:
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/node-connector/openflow:1:2``
+
+**Method:** ``GET``
+
+**Sample output:**
+
+.. code-block:: none
+
+ <node-connector xmlns="urn:opendaylight:inventory">
+ <id>openflow:1:2</id>
+ <supported xmlns="urn:opendaylight:flow:inventory"></supported>
+ <peer-features xmlns="urn:opendaylight:flow:inventory"></peer-features>
+ <port-number xmlns="urn:opendaylight:flow:inventory">2</port-number>
+ <hardware-address xmlns="urn:opendaylight:flow:inventory">4e:92:4a:c8:4c:fa</hardware-address>
+ <current-feature xmlns="urn:opendaylight:flow:inventory">ten-gb-fd copper</current-feature>
+ <maximum-speed xmlns="urn:opendaylight:flow:inventory">0</maximum-speed>
+ <reason xmlns="urn:opendaylight:flow:inventory">update</reason>
+ <configuration xmlns="urn:opendaylight:flow:inventory"></configuration>
+ <advertised-features xmlns="urn:opendaylight:flow:inventory"></advertised-features>
+ <current-speed xmlns="urn:opendaylight:flow:inventory">10000000</current-speed>
+ <name xmlns="urn:opendaylight:flow:inventory">s1-eth2</name>
+ <state xmlns="urn:opendaylight:flow:inventory">
+ <link-down>false</link-down>
+ <blocked>false</blocked>
+ <live>true</live>
+ </state>
+ <flow-capable-node-connector-statistics xmlns="urn:opendaylight:port:statistics">
+ <receive-errors>0</receive-errors>
+ <packets>
+ <transmitted>444</transmitted>
+ <received>444</received>
+ </packets>
+ <receive-over-run-error>0</receive-over-run-error>
+ <transmit-drops>0</transmit-drops>
+ <collision-count>0</collision-count>
+ <receive-frame-error>0</receive-frame-error>
+ <bytes>
+ <transmitted>37708</transmitted>
+ <received>37708</received>
+ </bytes>
+ <receive-drops>0</receive-drops>
+ <transmit-errors>0</transmit-errors>
+ <duration>
+ <second>2181</second>
+ <nanosecond>550000000</nanosecond>
+ </duration>
+ <receive-crc-error>0</receive-crc-error>
+ </flow-capable-node-connector-statistics>
+ </node-connector>
+
+.. note:: In the example above the OpenFlow node connector is represented as
+ openflow:1:2 where 1 is the datapath ID and 2 is the port ID of the
+ OpenFlow-enabled device.
+
+.. _example-of-table-statistics:
+
+Example of flow table and aggregated statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To view the flow table and flow aggregated statistics for a connected node,
+send the following request to the controller:
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/table/0/``
+
+**Method:** ``GET``
+
+**Sample output:**
+
+.. code-block:: none
+
+ <table xmlns="urn:opendaylight:flow:inventory">
+ <id>0</id>
+ <flow-table-statistics xmlns="urn:opendaylight:flow:table:statistics">
+ <active-flows>3</active-flows>
+ <packets-looked-up>548</packets-looked-up>
+ <packets-matched>535</packets-matched>
+ </flow-table-statistics>
+
+ --- Omitted output —--
+
+.. note:: In the example above the OpenFlow node table is 0.
+
+.. _example-of-individual-flow-statistics:
+
+Example of flow description and flow statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To view the individual flow statistics, send the following request to the
+controller:
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/table/0/flow/fm-sr-link-discovery``
+
+**Method:** ``GET``
+
+**Sample output:**
+
+.. code-block:: none
+
+ <flow>
+ <id>fm-sr-link-discovery</id>
+ <flow-statistics xmlns="urn:opendaylight:flow:statistics">
+ <packet-count>536</packet-count>
+ <duration>
+ <nanosecond>174000000</nanosecond>
+ <second>2681</second>
+ </duration>
+ <byte-count>45560</byte-count>
+ </flow-statistics>
+ <priority>99</priority>
+ <table_id>0</table_id>
+ <cookie_mask>0</cookie_mask>
+ <hard-timeout>0</hard-timeout>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>35020</type>
+ </ethernet-type>
+ </ethernet-match>
+ </match>
+ <cookie>1000000000000001</cookie>
+ <flags></flags>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <max-length>65535</max-length>
+ <output-node-connector>CONTROLLER</output-node-connector>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <idle-timeout>0</idle-timeout>
+ </flow>
+
+.. note:: In the example above the flow ID fm-sr-link-discovery is internal to
+ the controller and has to match the datastore configured flow ID.
+ For more information see flow ID match section
+ :ref:`flow-id-match-function`.
+
+.. _example-of-group-description-and-group-statistics:
+
+Example of group description and group statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To view the group description and group statistics, send the following request
+to the controller:
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/group/2``
+
+**Method:** ``GET``
+
+**Sample output:**
+
+.. code-block:: none
+
+ <group xmlns="urn:opendaylight:flow:inventory">
+ <group-id>2</group-id>
+ <buckets>
+ <bucket>
+ <bucket-id>0</bucket-id>
+ <action>
+ <order>1</order>
+ <output-action>
+ <max-length>0</max-length>
+ <output-node-connector>2</output-node-connector>
+ </output-action>
+ </action>
+ <action>
+ <order>0</order>
+ <pop-mpls-action>
+ <ethernet-type>34887</ethernet-type>
+ </pop-mpls-action>
+ </action>
+ <watch_group>4294967295</watch_group>
+ <weight>0</weight>
+ <watch_port>2</watch_port>
+ </bucket>
+ </buckets>
+ <group-type>group-ff</group-type>
+ <group-statistics xmlns="urn:opendaylight:group:statistics">
+ <buckets>
+ <bucket-counter>
+ <bucket-id>0</bucket-id>
+ <packet-count>0</packet-count>
+ <byte-count>0</byte-count>
+ </bucket-counter>
+ </buckets>
+ <group-id>2</group-id>
+ <packet-count>0</packet-count>
+ <byte-count>0</byte-count>
+ <duration>
+ <second>4116</second>
+ <nanosecond>746000000</nanosecond>
+ </duration>
+ <ref-count>1</ref-count>
+ </group-statistics>
+ </group>
+
+.. note:: In the example above the group ID 2 matches the switch stored
+ group ID.
+
+.. _example-of-meter-description-and-meter-statistics:
+
+Example of meter description and meter statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To view the meter description and meter statistics, send the following request
+to the controller:
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/meter/2``
+
+**Method:** ``GET``
+
+**Sample output:**
+
+.. code-block:: none
+
+ <?xml version="1.0"?>
+ <meter xmlns="urn:opendaylight:flow:inventory">
+ <meter-id>2</meter-id>
+ <flags>meter-kbps</flags>
+ <meter-statistics xmlns="urn:opendaylight:meter:statistics">
+ <packet-in-count>0</packet-in-count>
+ <byte-in-count>0</byte-in-count>
+ <meter-band-stats>
+ <band-stat>
+ <band-id>0</band-id>
+ <byte-band-count>0</byte-band-count>
+ <packet-band-count>0</packet-band-count>
+ </band-stat>
+ </meter-band-stats>
+ <duration>
+ <nanosecond>364000000</nanosecond>
+ <second>114</second>
+ </duration>
+ <meter-id>2</meter-id>
+ <flow-count>0</flow-count>
+ </meter-statistics>
+ <meter-band-headers>
+ <meter-band-header>
+ <band-id>0</band-id>
+ <band-rate>100</band-rate>
+ <band-burst-size>0</band-burst-size>
+ <meter-band-types>
+ <flags>ofpmbt-drop</flags>
+ </meter-band-types>
+ <drop-burst-size>0</drop-burst-size>
+ <drop-rate>100</drop-rate>
+ </meter-band-header>
+ </meter-band-headers>
+ </meter>
+
+.. note:: In the example above the meter ID 2 matches the switch stored
+ meter ID.
+
+.. _openflow-programming-overview:
+
+OpenFlow Programming
+--------------------
+
+The controller provides interfaces that can be used to program the connected
+OpenFlow devices. These interfaces interact with the OpenFlow southbound plugin
+that uses OpenFlow modification messages to program flows, groups and meters
+in the switch.
+
+The controller provides the following RESTCONF interfaces:
+
+- **Configuration Datastore:** allows user to configure flows, groups and
+ meters. The configuration is stored in the controller datastore, persisted
+ in disk and replicated in the controller cluster. The OpenFlow southbound
+ plugin reads the configuration and sends the appropriate OpenFlow
+ modification messages to the connected devices.
+
+- **RPC Operations:** allows user to configure flows, groups and meters
+ overriding the datastore. In this case the OpenFlow southbound plugin
+ translates the use configuration straight into an OpenFlow modification
+ message that is sent to the connected device.
+
+Example of flow programming by using config datastore
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example programs a flow that matches IPv4 packets (ethertype 0x800)
+with destination address in the 10.0.10.0/24 subnet and sends them to port 1.
+The flow is installed in table 0 of the switch with datapath ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/flow/1``
+
+**Method:** ``PUT``
+
+**Request body:**
+
+.. code-block:: none
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <flow xmlns="urn:opendaylight:flow:inventory">
+ <hard-timeout>0</hard-timeout>
+ <idle-timeout>0</idle-timeout>
+ <cookie>1</cookie>
+ <priority>2</priority>
+ <flow-name>flow1</flow-name>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv4-destination>10.0.10.0/24</ipv4-destination>
+ </match>
+ <id>1</id>
+ <table_id>0</table_id>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <output-action>
+ <output-node-connector>1</output-node-connector>
+ </output-action>
+ <order>0</order>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ </flow>
+
+.. note:: In the example above the flow ID 1 is internal to the controller and
+ the same ID can be found when retrieving the flow statistics if
+ controller finds a match between the configured flow and the flow
+ received from switch. For more information see flow ID match section
+ :ref:`flow-id-match-function`.
+
+.. note:: To use a different flow ID or table ID, ensure that the URL and the
+ request body are synchronized.
+
+.. note:: For more examples of flow programming using datastore, refer to
+ the OpenDaylight OpenFlow plugin :ref:`ofp-flow-examples`.
+
+For more information about flow configuration options check the
+opendaylight_models_.
+
+To verify that the flow has been correctly programmed in the switch, issue the
+RESTCONF request as provided in :ref:`example-of-individual-flow-statistics`.
+
+Deleting flows from config datastore:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example deletes the flow with ID 1 in table 0 of the switch with datapath
+ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/flow/1``
+
+**Method:** ``DELETE``
+
+You can also use the below URL to delete all flows in table 0 of the switch
+with datapath ID 1:
+
+**URL:** ``/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0``
+
+To verify that the flow has been correctly removed in the switch, issue the
+RESTCONF request as provided in :ref:`example-of-table-statistics`.
+
+Example of flow programming by using RPC operation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example programs a flow that matches IPv4 packets (ethertype 0x800)
+with destination address in the 10.0.10.0/24 subnet and sends them to port 1.
+The flow is installed in table 0 of the switch with datapath ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operations/sal-flow:add-flow``
+
+**Method:** ``POST``
+
+**Request body:**
+
+.. code-block:: none
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <input xmlns="urn:opendaylight:flow:service">
+ <node xmlns:inv="urn:opendaylight:inventory">/inv:nodes/inv:node[inv:id="openflow:1"]</node>
+ <table_id>0</table_id>
+ <priority>2</priority>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv4-destination>10.0.1.0/24</ipv4-destination>
+ </match>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <output-action>
+ <output-node-connector>1</output-node-connector>
+ </output-action>
+ <order>0</order>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ </input>
+
+.. note:: This payload does not require flow ID as this value is internal to
+ controller and only used to store flows in the datastore. When
+ retrieving flow statistics users will see an alien flow ID for flows
+ created this way. For more information see flow ID match section
+ :ref:`flow-id-match-function`.
+
+To verify that the flow has been correctly programmed in the switch, issue the
+RESTCONF request as provided in :ref:`example-of-table-statistics`.
+
+Deleting flows from switch using RPC operation:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example removes a flow that matches IPv4 packets (ethertype 0x800)
+with destination address in the 10.0.10.0/24 subnet from table 0 of the switch
+with datapath ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operations/sal-flow:remove-flow``
+
+**Method:** ``POST``
+
+**Request body:**
+
+.. code-block:: none
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <input xmlns="urn:opendaylight:flow:service">
+ <node xmlns:inv="urn:opendaylight:inventory">/inv:nodes/inv:node[inv:id="openflow:1"]</node>
+ <table_id>0</table_id>
+ <priority>2</priority>
+ <strict>true</strict>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>2048</type>
+ </ethernet-type>
+ </ethernet-match>
+ <ipv4-destination>10.0.10.0/24</ipv4-destination>
+ </match>
+ </input>
+
+To verify that the flow has been correctly programmed in the switch, issue the
+RESTCONF request as provided in :ref:`example-of-table-statistics`.
+
+Example of a group programming by using config datastore
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example programs a select group to equally load balance traffic across
+port 1 and port 2 in switch with datapath ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/json``
+
+- **Accept:** ``application/json``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/config/opendaylight-inventory:nodes/node/openflow:1/group/1``
+
+**Method:** ``PUT``
+
+**Request body:**
+
+.. code-block:: none
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <group xmlns="urn:opendaylight:flow:inventory">
+ <group-type>group-select</group-type>
+ <buckets>
+ <bucket>
+ <weight>1</weight>
+ <action>
+ <output-action>
+ <output-node-connector>1</output-node-connector>
+ </output-action>
+ <order>1</order>
+ </action>
+ <bucket-id>1</bucket-id>
+ </bucket>
+ <bucket>
+ <weight>1</weight>
+ <action>
+ <output-action>
+ <output-node-connector>2</output-node-connector>
+ </output-action>
+ <order>1</order>
+ </action>
+ <bucket-id>2</bucket-id>
+ </bucket>
+ </buckets>
+ <barrier>false</barrier>
+ <group-name>SelectGroup</group-name>
+ <group-id>1</group-id>
+ </group>
+
+.. note:: In the example above the group ID 1 will be stored in the switch
+ and will be used by the switch to report group statistics.
+
+.. note:: To use a different group ID, ensure that the URL and the request
+ body are synchronized.
+
+For more information about group configuration options check the
+opendaylight_models_.
+
+To verify that the group has been correctly programmed in the switch,
+issue the RESTCONF request as provided in
+:ref:`example-of-group-description-and-group-statistics`.
+
+To add a group action in a flow just add this statement in the flow body:
+
+.. code-block:: none
+
+ <apply-actions>
+ <action>
+ <group-action>
+ <group-id>1</group-id>
+ </group-action>
+ <order>1</order>
+ </action>
+ </apply-actions>
+
+Deleting groups from config datastore
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example deletes the group ID 1 in the switch with datapath ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/config/opendaylight-inventory:nodes/node/openflow:1/group/1``
+
+**Method:** ``DELETE``
+
+Example of a meter programming by using config datastore
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example programs a meter to drop traffic exceeding 256 kbps with a burst
+size of 512 in switch with datapath ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/json``
+
+- **Accept:** ``application/json``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/config/opendaylight-inventory:nodes/node/openflow:1/meter/1``
+
+**Method:** ``PUT``
+
+**Request body:**
+
+.. code-block:: none
+
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <meter xmlns="urn:opendaylight:flow:inventory">
+ <flags>meter-kbps</flags>
+ <meter-band-headers>
+ <meter-band-header>
+ <band-id>0</band-id>
+ <drop-rate>256</drop-rate>
+ <drop-burst-size>512</drop-burst-size>
+ <meter-band-types>
+ <flags>ofpmbt-drop</flags>
+ </meter-band-types>
+ </meter-band-header>
+ </meter-band-headers>
+ <meter-id>1</meter-id>
+ <meter-name>Foo</meter-name>
+ </meter>
+
+.. note:: In the example above the meter ID 1 will be stored in the switch
+ and will be used by the switch to report group statistics.
+
+.. note:: To use a different meter ID, ensure that the URL and the request
+ body are synchronized.
+
+For more information about meter configuration options check the
+opendaylight_models_.
+
+To verify that the meter has been correctly programmed in the switch,
+issue the RESTCONF request as provided in
+:ref:`example-of-meter-description-and-meter-statistics`.
+
+To add a meter instruction in a flow just add this statement in the flow body:
+
+.. code-block:: none
+
+ <instructions>
+ <instruction>
+ <order>1</order>
+ <meter>
+ <meter-id>1</meter-id>
+ </meter>
+ </instruction>
+ </instructions>
+
+Deleting meters from config datastore
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example deletes the meter ID 1 in the switch with datapath ID 1.
+
+**Headers:**
+
+- **Content-type:** ``application/xml``
+
+- **Accept:** ``application/xml``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/config/opendaylight-inventory:nodes/node/openflow:1/meter/1``
+
+**Method:** ``DELETE``
+
+.. _flow-id-match-function:
+
+Flow ID match function
+----------------------
+
+When the controller receives flow information from a switch, this information
+is compared with all flows stored in the configuration datastore, in case of
+a match the flow ID in the flow configuration is automatically added to the
+flow operational information. This way we can easily relate flows stored
+in controller with flows received from the switch.
+
+However in case of flows added via RPC or in general when the controller
+cannot match received flow information with any flow in datastore, it adds
+an alien ID in the flow operational information like in the example below.
+
+.. code-block:: none
+
+ <flow>
+ <id>#UF$TABLE*0-555</id>
+ <flow-statistics xmlns="urn:opendaylight:flow:statistics">
+ <packet-count>5227</packet-count>
+ <duration>
+ <nanosecond>642000000</nanosecond>
+ <second>26132</second>
+ </duration>
+ <byte-count>444295</byte-count>
+ </flow-statistics>
+ <priority>99</priority>
+ <table_id>0</table_id>
+ <cookie_mask>0</cookie_mask>
+ <hard-timeout>0</hard-timeout>
+ <match>
+ <ethernet-match>
+ <ethernet-type>
+ <type>35020</type>
+ </ethernet-type>
+ </ethernet-match>
+ </match>
+ <cookie>1000000000000001</cookie>
+ <flags></flags>
+ <instructions>
+ <instruction>
+ <order>0</order>
+ <apply-actions>
+ <action>
+ <order>0</order>
+ <output-action>
+ <max-length>65535</max-length>
+ <output-node-connector>CONTROLLER</output-node-connector>
+ </output-action>
+ </action>
+ </apply-actions>
+ </instruction>
+ </instructions>
+ <idle-timeout>0</idle-timeout>
+ </flow>
+
+
+OpenFlow clustering
+-------------------
+
+For high availability, it is recommended a three-node cluster setup in
+which each switch is connected to all nodes in the controller cluster.
+
+.. note:: Normal OpenFlow operations, such as adding a flow, can be done on
+ any cluster member. For more information about OpenFlow operations,
+ refer to :ref:`openflow-programming-overview`.
+
+In OpenFlow 1.3, one of the following roles is assigned to each
+switch-controller connection:
+
+- Master: All synchronous and asynchronous messages are sent to the
+ master controller. This controller has write privileges on the
+ switch.
+
+- Slave: Only synchronous messages are sent to this controller. Slave
+ controllers have only read privileges on the switch.
+
+- Equal: When the equal role is assigned to a controller, it has the
+ same privileges as the master controller. By default, a controller is
+ assigned the equal role when it first connects to the switch.
+
+A switch can be connected to one or more controllers. Each controller
+communicates the OpenFlow channel role through an OFTP\_ROLE\_REQUEST
+message. The switch must retain the role of each switch connection; a
+controller may change this role at any time.
+
+If a switch connects to multiple controllers in the cluster, the cluster
+selects one controller as the master controller; the remaining
+controllers assume the slave role. The election of a master controller
+proceeds as follows.
+
+#. Each controller in the cluster that is handling switch connections
+ registers to the Entity Ownership Service (EOS) as a candidate for
+ switch ownership.
+
+ .. note:: The EOS is a clustering service that plays the role of the
+ arbiter to elect an owner (master) of an entity from a registered
+ set of candidates.
+
+#. The EOS then selects one controller as the owner.
+
+ .. note:: Master ownership is for each device; each individual controller
+ can be a master for a set of connected devices and a slave for the
+ remaining set of connected devices.
+
+#. The selected owner then sends an OFTP\_ROLE\_REQUEST message to the
+ switch to set the connection to the master role, and the other
+ controllers send the role message to set the slave role.
+
+When the switch master connection goes down, the election of a new
+master controller proceeds as follows.
+
+#. The related controller deregisters itself as a candidate for Entity
+ Ownership from the EOS.
+
+#. The EOS then selects a new owner from the remaining candidates.
+
+#. The new owner accordingly sends an OFTP\_ROLE\_REQUEST message to the
+ switch to set the connection to the master role.
+
+If a controller that currently has the master role is shut down, a new
+master from the remaining candidate controllers is selected.
+
+Verifying the EOS owner and candidates by using RESTCONF
+--------------------------------------------------------
+
+To verify the EOS owner and candidates in an OpenFlow cluster, send the
+following request to the controller:
+
+**Headers:**
+
+- **Content-type:** ``application/json``
+
+- **Accept:** ``application/json``
+
+- **Authentication:** ``admin:admin``
+
+**URL:** ``/restconf/operational/entity-owners:entity-owners``
+
+**Method:** ``GET``
+
+**Sample output:**
+
+.. code-block:: none
+
+ {
+ "entity-owners":{
+ "entity-type":[
+ {
+ "type":"org.opendaylight.mdsal.ServiceEntityType",
+ "entity":[
+ {
+ "id":"/odl-general-entity:entity[odl-general-entity:name='openflow:1']",
+ "candidate":[
+ {
+ "name":"member-3"
+ },
+ {
+ "name":"member-2"
+ },
+ {
+ "name":"member-1"
+ }
+ ],
+ "owner":"member-3"
+ },
+ {
+ "id":"/odl-general-entity:entity[odl-general-entity:name='openflow:2']",
+ "candidate":[
+ {
+ "name":"member-1"
+ },
+ {
+ "name":"member-3"
+ },
+ {
+ "name":"member-2"
+ }
+ ],
+ "owner":"member-1"
+ },
+ {
+ "id":"/odl-general-entity:entity[odl-general-entity:name='openflow:3']",
+ "candidate":[
+ {
+ "name":"member-1"
+ },
+ {
+ "name":"member-2"
+ },
+ {
+ "name":"member-3"
+ }
+ ],
+ "owner":"member-1"
+ }
+ ]
+ },
+ {
+ "type":"org.opendaylight.mdsal.AsyncServiceCloseEntityType",
+ "entity":[
+ {
+ "id":"/odl-general-entity:entity[odl-general-entity:name='openflow:1']",
+ "candidate":[
+ {
+ "name":"member-3"
+ }
+ ],
+ "owner":"member-3"
+ },
+ {
+ "id":"/odl-general-entity:entity[odl-general-entity:name='openflow:2']",
+ "candidate":[
+ {
+ "name":"member-1"
+ }
+ ],
+ "owner":"member-1"
+ },
+ {
+ "id":"/odl-general-entity:entity[odl-general-entity:name='openflow:3']",
+ "candidate":[
+ {
+ "name":"member-1"
+ }
+ ],
+ "owner":"member-1"
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+In the above sample output, ``member 3`` is the master controller
+(EOS owner) for the OpenFlow device with datapath ID ``1``, and
+``member-1`` is the master controller (EOS owner) for the OpenFlow
+devices with the datapath IDs of ``2`` and ``3``.
+
+Configuring the OpenFlow Plugin
+-------------------------------
+
+OpenFlow plugin configuration file is in the opendaylight /etc folder:
+``opendaylight-0.9.0/etc/org.opendaylight.openflowplugin.cfg``
+
+The ``org.opendaylight.openflowplugin.cfg`` file can be modified at any
+time, however a controller restart is required for the changes to take
+effect.
+
+This configuration is local to a given node. You must repeat these steps
+on each node to enable the same functionality across the cluster.
+
+.. _ofp-tls-guide:
+
+Configuring OpenFlow TLS
+------------------------
+
+This section describes how to secure OpenFlow connections between
+controller and OpenFlow devices using Transport Layer Security (TLS).
+
+TLS Concepts
+~~~~~~~~~~~~
+
+TLS uses digital certificates to perform remote peer authentication,
+message integrity and data encryption. Public Key Infrastructure (PKI)
+is required to create, manage and verify digital certificates.
+
+For OpenFlow symmetric authentication (controller authenticates device
+and device authenticates controller) both controller and device require:
+
+#. A private key: used to generate own public certificate and therefore
+ required for own authentication at the other end.
+
+#. A public certificate or a chain of certificates if public certificate
+ is signed by an intermediate (not root) CA: the chain contains the public
+ certificate as well as all the intermediate CA certificates used to
+ validate the public certificate, this public information is sent to the
+ other peer during the TLS negotiation and it is used for own
+ authentication at the other end.
+
+#. A list of root CA certificates: this contains the root CA certificate
+ that signed the remote peer certificate or the remote peer intermediate
+ CA certificate (in case of certificate chain). This public information
+ is used to authenticate the other end.
+
+.. note:: Some devices like Open vSwitch (OVS) do not support certificate
+ chains, this means controller can only send its own certificate
+ and receive the switch certificate without any intermediate CA
+ certificates. For TLS negotiation to be successful in this scenario
+ both ends need to store all intermediate CA certificates used by
+ the other end (in addition to the remote peer root CA certificate).
+
+Generate Controller Private Key and Certificate
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You may skip this step if you already have the required key and certificate
+from an external Public Key Infrastructure (PKI). In the examples below we
+use openSSL tool to generate private key and certificates for controller.
+
+#. Generate controller private key
+
+ The command below generates 2048 bytes RSA key:
+
+ .. code-block:: none
+
+ openssl genrsa -out controller.key 2048
+
+ This will generate the private key file controller.key
+
+#. Generate controller certificate
+
+ The command below creates a certificate sign request:
+
+ .. code-block:: none
+
+ openssl req -new -sha256 -key controller.key -out controller.csr
+
+ This will generate the certificate signing request file controller.csr
+
+ Submit the file to the desired Certificate Authority (CA) and get the CA
+ signed certificate along with any intermediate CA certificate in the file
+ controller.crt (X.509 format).
+
+ The following is not recommended for production but if you want to just
+ check the TLS communication you can create a "self-signed" certificate for
+ the controller using below command:
+
+ .. code-block:: none
+
+ openssl req -new -x509 -nodes -sha1 -days 1825 -key controller.key -out controller.crt
+
+Create Controller Key Stores
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Controller requires 2 Key Stores for OpenFlow TLS:
+
+- Keystore: Used for controller authentication in the remote device. This
+ contains the controller private key (controller.key) and the controller
+ certificate or the controller certificate chain (controller.crt) in case
+ of an intermediate CA signs the controller certificate.
+
+- Truststore: Used to authenticate remote devices. This contains the root
+ CA certificates signing the OpenFlow devices certificates or the
+ intermediate CA certificates (in case of certificate chain).
+
+You may skip this step if you already generated the Key Stores from a
+previous TLS installation. In the examples below we will use openSSL and
+Java keytool tooling to create the Key Stores.
+
+#. Create the controller Keystore
+
+ The command below generates the controller Keystore in PKCS12 format:
+
+ .. code-block:: none
+
+ openssl pkcs12 -export -in controller.crt -inkey controller.key -out keystore.p12 -name controller
+
+ When asked for a password select 'opendaylight' (or anything else).
+
+ This will generate the keystore.p12 file.
+
+ .. note:: If device (e.g. Open vSwitch) does not support certificate chains,
+ make sure controller.crt only contains the controller certificate
+ with no extra intermediate CA certificates.
+
+#. Create the controller Truststore
+
+ The command below generates the controller Truststore in PKCS12 format
+ and adds the device root CA certificates rootca1.crt and rootca2.crt:
+
+ .. code-block:: none
+
+ keytool -importcert -storetype pkcs12 -file rootca1.crt -keystore truststore.p12 -storepass opendaylight -alias root-ca-1
+ keytool -importcert -storetype pkcs12 -file rootca2.crt -keystore truststore.p12 -storepass opendaylight -alias root-ca-2
+
+ Note in the examples we use 'opendaylight' as the store password.
+
+ This will generate the truststore.p12 file.
+
+ .. note:: If device (e.g. Open vSwitch) does not support certificate chains,
+ make sure you add all device intermediate CA certificates in the
+ controller Truststore.
+
+Enable Controller TLS
+~~~~~~~~~~~~~~~~~~~~~
+
+Controller listens for OpenFlow connections on ports 6633 and 6653 (TCP).
+You can enable TLS in both or just one of the ports.
+
+#. Copy the Key Stores to a controller folder (e.g. opendaylight /etc folder)
+
+#. Enable TLS on port 6633:
+
+ Create file legacy-openflow-connection-config.xml with following content:
+
+ .. code-block:: none
+
+ <switch-connection-config xmlns="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:config">
+ <instance-name>openflow-switch-connection-provider-legacy-impl</instance-name>
+ <port>6633</port>
+ <transport-protocol>TLS</transport-protocol>
+ <tls>
+ <keystore>etc/keystore.p12</keystore>
+ <keystore-type>PKCS12</keystore-type>
+ <keystore-path-type>PATH</keystore-path-type>
+ <keystore-password>opendaylight</keystore-password>
+ <truststore>etc/truststore.p12</truststore>
+ <truststore-type>PKCS12</truststore-type>
+ <truststore-path-type>PATH</truststore-path-type>
+ <truststore-password>opendaylight</truststore-password>
+ <certificate-password>opendaylight</certificate-password>
+ </tls>
+ </switch-connection-config>
+
+ .. note:: Change password 'opendaylight' above if you used different password.
+
+ .. note:: Change the path above of you used different folder than opendaylight /etc.
+
+ Copy the file to opendaylight folder: /etc/opendaylight/datastore/initial/config
+
+#. Enable TLS on port 6653:
+
+ Create file default-openflow-connection-config.xml with following content:
+
+ .. code-block:: none
+
+ <switch-connection-config xmlns="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:config">
+ <instance-name>openflow-switch-connection-provider-default-impl</instance-name>
+ <port>6653</port>
+ <transport-protocol>TLS</transport-protocol>
+ <tls>
+ <keystore>etc/keystore.p12</keystore>
+ <keystore-type>PKCS12</keystore-type>
+ <keystore-path-type>PATH</keystore-path-type>
+ <keystore-password>opendaylight</keystore-password>
+ <truststore>etc/truststore.p12</truststore>
+ <truststore-type>PKCS12</truststore-type>
+ <truststore-path-type>PATH</truststore-path-type>
+ <truststore-password>opendaylight</truststore-password>
+ <certificate-password>opendaylight</certificate-password>
+ </tls>
+ </switch-connection-config>
+
+ .. note:: Change password 'opendaylight' above if you used different password.
+
+ .. note:: Change the path above of you used different folder than opendaylight /etc.
+
+ Copy the file to opendaylght folder /etc/opendaylight/datastore/initial/config
+
+#. Restart Controller
+
+For changes to take effect, controller has to be restarted.
+
+Troubleshooting
+---------------
+
+Controller log is in opendaylight /data/log folder:
+``opendaylight-0.9.0/data/log/karaf.log``
+
+Logs can be also displayed on karaf console:
+
+.. code-block:: none
+
+ log:display
+
+To troubleshoot OpenFlow plugin enable this TRACE in karaf console:
+
+.. code-block:: none
+
+ log:set TRACE org.opendaylight.openflowplugin.openflow.md.core
+ log:set TRACE org.opendaylight.openflowplugin.impl
+
+To restore log settings:
+
+.. code-block:: none
+
+ log:set INFO org.opendaylight.openflowplugin.openflow.md.core
+ log:set INFO org.opendaylight.openflowplugin.impl
+
+.. _openflow-specs: https://www.opennetworking.org/software-defined-standards/specifications
+.. _opendaylight_models: https://wiki.opendaylight.org/view/OpenDaylight_Controller:Config:Model_Reference
+