30 min read

In this article by Kingston Smiler. S, author of the book OpenFlow Cookbook describes the steps involved in sending and processing symmetric messages and asynchronous messages in the switch and contains the following recipes:

  • Sending and processing a hello message
  • Sending and processing an echo request and a reply message
  • Sending and processing an error message
  • Sending and processing an experimenter message
  • Handling a Get Asynchronous Configuration message from the controller, which is used to fetch a list of asynchronous events that will be sent from the switch
  • Sending a Packet-In message to the controller
  • Sending a Flow-removed message to the controller
  • Sending a port-status message to the controller
  • Sending a controller-role status message to the controller
  • Sending a table-status message to the controller
  • Sending a request-forward message to the controller
  • Handling a packet-out message from the controller
  • Handling a barrier-message from the controller

(For more resources related to this topic, see here.)

Symmetric messages can be sent from both the controller and the switch without any solicitation between them. The OpenFlow switch should be able to send and process the following symmetric messages to or from the controller, but error messages will not be processed by the switch:

  • Hello message
  • Echo request and echo reply message
  • Error message
  • Experimenter message

Asynchronous messages are sent by both the controller and the switch when there is any state change in the system. Like symmetric messages, asynchronous messages also should be sent without any solicitation between the switch and the controller. The switch should be able to send the following asynchronous messages to the controller:

  • Packet-in message
  • Flow-removed message
  • Port-status message
  • Table-status message
  • Controller-role status message
  • Request-forward message

Similarly, the switch should be able to receive, or process, the following controller-to-switch messages:

  • Packet-out message
  • Barrier message

The controller can program or instruct the switch to send a subset of interested asynchronous messages using an asynchronous configuration message. Based on this configuration, the switch should send the subset of asynchronous messages only via the communication channel.

The switch should replicate and send asynchronous messages to all the controllers based on the information present in the asynchronous configuration message sent from each controller. The switch should maintain asynchronous configuration information on a per communication channel basis.

Sending and processing a hello message

The OFPT_HELLO message is used by both the switch and the controller to identify and negotiate the OpenFlow version supported by both the devices. Hello messages should be sent from the switch once the TCP/TLS connection is established and are considered part of the communication channel establishment procedure.

The switch should send a hello message to the controller immediately after establishing the TCP/TLS connection with the controller.

How to do it…

As hello messages are transmitted by both the switch and the controller, the switch should be able to send, receive, and process the hello message. The following section explains these procedures in detail.

Sending the OFPT_HELLO message

The message format to be used to send the hello message from the switch is as follows. This message includes the OpenFlow header along with zero or more elements that have variable size:

/* OFPT_HELLO. This message includes zero or more
   hello elements having variable size. */
struct ofp_hello {
struct ofp_header header;
/* Hello element list */
struct ofp_hello_elem_header elements[0]; /* List of elements */
};

OpenFlow Cookbook

The version field in the ofp_header should be set with the highest OpenFlow protocol version supported by the switch. The elements field is an optional field and might contain the element definition, which takes the following TLV format:

/* Version bitmap Hello Element */
struct ofp_hello_elem_versionbitmap {
uint16_t type;           /* OFPHET_VERSIONBITMAP. */
uint16_t length;         /* Length in bytes of this element. */
       /* Followed by:
         * - Exactly (length - 4) bytes containing the bitmaps,
         * then Exactly (length + 7)/8*8 - (length) (between 0
         * and 7) bytes of all-zero bytes */
uint32_t bitmaps[0]; /* List of bitmaps - supported versions */
};

The type field should be set with OFPHET_VERSIONBITMAP. The length field should be set to the length of this element.

The bitmaps field should be set with the list of the OpenFlow versions the switch supports. The number of bitmaps included in the field should depend on the highest version number supported by the switch. The ofp_versions 0 to 31 should be encoded in the first bitmap, ofp_versions 32 to 63 should be encoded in the second bitmap, and so on. For example, if the switch supports only version 1.0 (ofp_versions = 0 x 01) and version 1.3 (ofp_versions = 0 x 04), then the first bitmap should be set to 0 x 00000012.

Refer to the send_hello_message() function in the of/openflow.c file for the procedure to build and send the OFPT_Hello message.

Receiving the OFPT_HELLO message

The switch should be able to receive and process the OFPT_HELLO messages that are sent from the controller. The controller also uses the same message format, structures, and enumerations as defined in the previous section of this recipe. Once the switch receives the hello message, it should calculate the protocol version to be used for messages exchanged with the controller. The procedure required to calculate the protocol version to be used is as follows:

  • If the hello message received from the switch contains an optional OFPHET_VERSIONBITMAP element and the bitmap field contains a valid value, then the negotiated version should be the highest common version among the supported protocol versions in the controller, with the bitmap field in the OFPHET_VERSIONBITMAP element.
  • If the hello message doesn’t contain any OFPHET_VERSIONBITMAP element, then the negotiated version should be the smallest of the switch-supported protocol versions and the version field set in the OpenFlow header of the received hello message.

If the negotiated version is supported by the switch, then the OpenFlow connection between the controller and the switch continues. Otherwise, the switch should send an OFPT_ERROR message with the type field set as OFPET_HELLO_FAILED, the code field set as OFPHFC_INCOMPATIBLE, and an optional ASCII string explaining the situation in the data and terminate the connection.

There’s more…

Once the switch and the controller negotiate the OpenFlow protocol version to be used, the connection setup procedure is complete. From then on, both the controller and the switch can send OpenFlow protocol messages to each other.

Sending and processing an echo request and a reply message

Echo request and reply messages are used by both the controller and the switch to maintain and verify the liveliness of the controller-switch connection. Echo messages are also used to calculate the latency and bandwidth of the controller-switch connection.

On reception of an echo request message, the switch should respond with an echo reply message.

How to do it…

As echo messages are transmitted by both the switch and the controller, the switch should be able to send, receive, and process them. The following section explains these procedures in detail.

Sending the OFPT_ECHO_REQUEST message

The OpenFlow specification doesn’t specify how frequently this echo message has to be sent from the switch. However, the switch might choose to send an echo request message periodically to the controller with the configured interval. Similarly, the OpenFlow specification doesn’t mention what the timeout (the longest period of time the switch should wait) for receiving echo reply message from the controller should be.

After sending an echo request message to the controller, the switch should wait for the echo reply message for the configured timeout period. If the switch doesn’t receive the echo reply message within this period, then it should initiate the connection interruption procedure.

The OFPT_ECHO_REQUEST message contains an OpenFlow header followed by an undefined data field of arbitrary length. The data field might be filled with the timestamp at which the echo request message was sent, various lengths or values to measure the bandwidth, or be zero-size for just checking the liveliness of the connection. In most open source implementations of OpenFlow, the echo request message only contains the header field and doesn’t contain any body.

Refer to the send_echo_request() function in the of/openflow.c file for the procedure to build and send the echo_request message.

Receiving OFPT_ECHO_REQUEST

The switch should be able to receive and process OFPT_ECHO_REQUEST messages that are sent from the controller. The controller also uses the same message format, structures, and enumerations as defined in the previous section of this recipe. Once the switch receives the echo request message, it should build the OFPT_ECHO_REPLY message. This message consists of ofp_header and an arbitrary-length data field. While forming the echo reply message, the switch should copy the content present in the arbitrary-length field of the request message to the reply message.

Refer to the process_echo_request() function in the of/openflow.c file for the procedure to handle and process the echo request message and send the echo reply message.

Processing OFPT_ECHO_REPLY message

The switch should be able to receive the echo reply message from the controller. If the switch sends the echo request message to calculate the latency or bandwidth, on receiving the echo reply message, it should parse the arbitrary-length data field and can calculate the bandwidth, latency, and so on.

There’s more…

If the OpenFlow switch implementation is divided into multiple layers, then the processing of the echo request and reply should be handled in the deepest possible layer. For example, if the OpenFlow switch implementation is divided into user-space processing and kernel-space processing, then the echo request and reply message handling should be in the kernel space.

Sending and processing an error message

Error messages are used by both the controller and the switch to notify the other end of the connection about any problem. Error messages are typically used by the switch to inform the controller about failure of execution of the request sent from the controller.

How to do it…

Whenever the switch wants to send the error message to the controller, it should build the OFPT_ERROR message, which takes the following message format:

/* OFPT_ERROR: Error message (datapath -> the controller). */
struct ofp_error_msg {
struct ofp_header header;
uint16_t type;
uint16_t code;
uint8_t data[0]; /* Variable-length data. Interpreted based
on the type and code. No padding. */
};

OpenFlow Cookbook

The type field indicates a high-level type of error. The code value is interpreted based on the type. The data value is a piece of variable-length data that is interpreted based on both the type and the value. The data field should contain an ASCII text string that adds details about why the error occurred.

Unless specified otherwise, the data field should contain at least 64 bytes of the failed message that caused this error. If the failed message is shorter 64 bytes, then the data field should contain the full message without any padding.

If the switch needs to send an error message in response to a specific message from the controller (say, OFPET_BAD_REQUEST, OFPET_BAD_ACTION, OFPET_BAD_INSTRUCTION, OFPET_BAD_MATCH, or OFPET_FLOW_MOD_FAILED), then the xid field of the OpenFlow header in the error message should be set with the offending request message.

Refer to the send_error_message() function in the of/openflow.c file for the procedure to build and send an error message.

If the switch needs to send an error message for a request message sent from the controller (because of an error condition), then the switch need not send the reply message to that request.

Sending and processing an experimenter message

Experimenter messages provide a way for the switch to offer additional vendor-defined functionalities.

How to do it…

The controller sends the experimenter message with the format. Once the switch receives this message, it should invoke the appropriate vendor-specific functions.

Handling a “Get Asynchronous Configuration message” from the controller

The OpenFlow specification provides a mechanism in the controller to fetch the list of asynchronous events that can be sent from the switch to the controller channel. This is achieved by sending the “Get Asynchronous Configuration message” (OFPT_GET_ASYNC_REQUEST) to the switch.

How to do it…

The message format to be used to get the asynchronous configuration message (OFPT_GET_ASYNC_REQUEST) doesn’t have any body other than ofp_header. On receiving this OFPT_GET_ASYNC_REQUEST message, the switch should respond with the OFPT_GET_ASYNC_REPLY message. The switch should fill the property list with the list of asynchronous configuration events / property types that the relevant controller channel is preconfigured to receive. The switch should get this information from its internal data structures.

Refer to the process_async_config_request() function in the of/openflow.c file for the procedure to process the get asynchronous configuration request message from the controller.

Sending a packet-in message to the controller

Packet-in messages (OFP_PACKET_IN) are sent from the switch to the controller to transfer a packet received from one of the switch-ports to the controller for further processing.

By default, a packet-in message should be sent to all the controllers that are in equal (OFPCR_ROLE_EQUAL) and master (OFPCR_ROLE_MASTER) roles. This message should not be sent to controllers that are in the slave state.

There are three ways by which the switch can send a packet-in event to the controller:

  1. Table-miss entry: When there is no matching flow entry for the incoming packet, the switch can send the packet to the controller.
  2. TTL checking: When the TTL value in a packet reaches zero, the switch can send the packet to the controller.
  3. The “send to the controller” action in the matching entry (either the flow table entry or the group table entry) of the packet.

How to do it…

When the switch wants to send a packet received in its data path to the controller, the following message format should be used:

/* Packet received on port (datapath -> the controller). */
struct ofp_packet_in {
struct ofp_header header;
uint32_t buffer_id; /* ID assigned by datapath. */
uint16_t total_len; /* Full length of frame. */
uint8_t reason;     /* Reason packet is being sent
                     * (one of OFPR_*) */
uint8_t table_id;   /* ID of the table that was looked up */
uint64_t cookie;   /* Cookie of the flow entry that was
                     * looked up. */
struct ofp_match match; /* Packet metadata. Variable size. */
/* The variable size and padded match is always followed by:
* - Exactly 2 all-zero padding bytes, then
* - An Ethernet frame whose length is inferred from header.length.
* The padding bytes preceding the Ethernet frame ensure that IP
* header (if any) following the Ethernet header is 32-bit aligned.
*/
uint8_t pad[2]; /* Align to 64 bit + 16 bit */
uint8_t data[0]; /* Ethernet frame */
};

OpenFlow Cookbook

The buffer-id field should be set to the opaque value generated by the switch. When the packet is buffered, the data portion of the packet-in message should contain some bytes of data from the incoming packet. If the packet is sent to the controller because of the “send to the controller” action of a table entry, then the max_len field of ofp_action_output should be used as the size of the packet to be included in the packet-in message. If the packet is sent to the controller for any other reason, then the miss_send_len field of the OFPT_SET_CONFIG message should be used to determine the size of the packet. If the packet is not buffered, either because of unavailability of buffers or an explicit configuration via OFPCML_NO_BUFFER, then the entire packet should be included in the data portion of the packet-in message with the buffer-id value as OFP_NO_BUFFER.

The date field should be set to the complete packet or a fraction of the packet. The total_length field should be set to the length of the packet included in the data field.

The reason field should be set with any one of the following values defined in the enumeration, based on the context that triggers the packet-in event:

/* Why is this packet being sent to the controller? */
enum ofp_packet_in_reason {
OFPR_TABLE_MISS = 0,   /* No matching flow (table-miss
                       * flow entry). */
OFPR_APPLY_ACTION = 1, /* Output to the controller in
                       * apply-actions. */
OFPR_INVALID_TTL = 2, /* Packet has invalid TTL */
OFPR_ACTION_SET = 3,   /* Output to the controller in action set. */
OFPR_GROUP = 4,       /* Output to the controller in group bucket. */
OFPR_PACKET_OUT = 5,   /* Output to the controller in packet-out. */
};

If the packet-in message was triggered by the flow-entry “send to the controller” action, then the cookie field should be set with the cookie of the flow entry that caused the packet to be sent to the controller. This field should be set to -1 if the cookie cannot be associated with a particular flow.

When the packet-in message is triggered by the “send to the controller” action of a table entry, there is a possibility that some changes have already been applied over the packet in previous stages of the pipeline. This information needs to be carried along with the packet-in message, and it can be carried in the match field of the packet-in message with a set of OXM (short for OpenFlow Extensible Match) TLVs. If the switch includes an OXM TLV in the packet-in message, then the match field should contain a set of OXM TLVs that include context fields. The standard context fields that can be added into the OXL TLVs are OFPXMT_OFB_IN_PORT, OFPXMT_OFB_IN_PHY_PORT, OFPXMT_OFB_METADATA, and OFPXMT_OFB_TUNNEL_ID.

When the switch receives the packet in the physical port, and this packet information needs to be carried in the packet-in message, then OFPXMT_OFB_IN_PORT and OFPXMT_OFB_IN_PHY_PORT should have the same value, which is the OpenFlow port number of that physical port. When the switch receives the packet in the logical port and this packet information needs to be carried in the packet-in message, then the switch should set the logical port’s port number in OFPXMT_OFB_IN_PORT and the physical port’s port number in OFPXMT_OFB_IN_PHY_PORT. For example, consider a packet received on a tunnel interface defined over a Link Aggregation Group (LAG) with two member ports. Then the packet-in message should carry the tunnel interface’s port_no to the OFPXMT_OFB_IN_PORT field and the physical interface’s port_no to the OFPXMT_OFB_IN_PHY_PORT field.

Refer to the send_packet_in_message() function in the of/openflow.c file for the procedure to send a packet-in message event to the controller.

How it works…

The switch can send either the entire packet it receives from the switch port to the controller, or a fraction of the packet to the controller. When the switch is configured to send only a fraction of the packet, it should buffer the packet in its memory and send a portion of packet data. This is controlled by the switch configuration.

If the switch is configured to buffer the packet, and it has sufficient memory to buffer the packet, then the packet-in message should contain the following:

  1. A fraction of the packet. This is the size of the packet to be included in the packet-in message, configured via the switch configuration message. By default, it is 128 bytes. When the packet-in message is resulted by a table-entry action, then the output action itself can specify the size of the packet to be sent to the controller. For all other packet-in messages, it is defined in the switch configuration.
  2. The buffer ID to be used by the controller when the controller wants to forward the message at a later point in time.

There’s more…

The switch that implements buffering should be expected to expose some details, such as the amount of available buffers, the period of time the buffered data will be available, and so on, through documentation. The switch should implement the procedure to release the buffered packet when there is no response from the controller to the packet-in event.

Sending a flow-removed message to the controller

A flow-removed message (OFPT_FLOW_REMOVED) is sent from the switch to the controller when a flow entry is removed from the flow table. This message should be sent to the controller only when the OFPFF_SEND_FLOW_REM flag in the flow entry is set.

The switch should send this message only to the controller channel wherein the controller requested the switch to send this event. The controller can express its interest in receiving this event by sending the switch configuration message to the switch.

By default, OFPT_FLOW_REMOVED should be sent to all the controllers that are in equal (OFPCR_ROLE_EQUAL) and master (OFPCR_ROLE_MASTER) roles. This message should not be sent to a controller that is in the slave state.

How to do it…

When the switch removes an entry from the flow table, it should build an OFPT_FLOW_REMOVED message with the following format and send this message to the controllers that have already shown interest in this event:

/* Flow removed (datapath -> the controller). */
struct ofp_flow_removed {
struct ofp_header header;
uint64_t cookie;       /* Opaque the controller-issued identifier. */
uint16_t priority;     /* Priority level of flow entry. */
uint8_t reason;         /* One of OFPRR_*. */
uint8_t table_id;       /* ID of the table */
uint32_t duration_sec; /* Time flow was alive in seconds. */
uint32_t duration_nsec; /* Time flow was alive in nanoseconds
                         * beyond duration_sec. */
uint16_t idle_timeout; /* Idle timeout from original flow mod. */
uint16_t hard_timeout; /* Hard timeout from original flow mod. */
uint64_t packet_count;
uint64_t byte_count;
struct ofp_match match; /* Description of fields.Variable size. */
};

OpenFlow Cookbook

The cookie field should be set with the cookie of the flow entry, the priority field should be set with the priority of the flow entry, and the reason field should be set with one of the following values defined in the enumeration:

/* Why was this flow removed? */
enum ofp_flow_removed_reason {
OFPRR_IDLE_TIMEOUT = 0,/* Flow idle time exceeded idle_timeout. */
OFPRR_HARD_TIMEOUT = 1, /* Time exceeded hard_timeout. */
OFPRR_DELETE = 2,       /* Evicted by a DELETE flow mod. */
OFPRR_GROUP_DELETE = 3, /* Group was removed. */
OFPRR_METER_DELETE = 4, /* Meter was removed. */
OFPRR_EVICTION = 5,     /* the switch eviction to free resources. */
};

The duration_sec and duration_nsec should be set with the elapsed time of the flow entry in the switch. The total duration in nanoseconds can be computed as duration_sec*109 + duration_nsec.

All the other fields, such as idle_timeout, hard_timeoutm, and so on, should be set with the appropriate value from the flow entry, that is, these values can be directly copied from the flow mode that created this entry.

The packet_count and byte_count should be set with the number of packet count and the byte count associated with the flow entry, respectively. If the values are not available, then these fields should be set with the maximum possible value.

Refer to the send_flow_removed_message() function in the of/openflow.c file for the procedure to send a flow removed event message to the controller.

Sending a port-status message to the controller

Port-status messages (OFPT_PORT_STATUS) are sent from the switch to the controller when there is any change in the port status or when a new port is added, removed, or modified in the switch’s data path. The switch should send this message only to the controller channel that the controller requested the switch to send it. The controller can express its interest to receive this event by sending an asynchronous configuration message to the switch.

By default, the port-status message should be sent to all configured controllers in the switch, including the controller in the slave role (OFPCR_ROLE_SLAVE).

How to do it…

The switch should construct an OFPT_PORT_STATUS message with the following format and send this message to the controllers that have already shown interest in this event:

/* A physical port has changed in the datapath */
struct ofp_port_status {
struct ofp_header header;
uint8_t reason; /* One of OFPPR_*. */
uint8_t pad[7]; /* Align to 64-bits. */
struct ofp_port desc;
};

OpenFlow Cookbook

The reason field should be set to one of the following values as defined in the enumeration:

/* What changed about the physical port */
enum ofp_port_reason {
OFPPR_ADD = 0,   /* The port was added. */
OFPPR_DELETE = 1, /* The port was removed. */
OFPPR_MODIFY = 2, /* Some attribute of the port has changed. */
};

The desc field should be set to the port description. In the port description, all properties need not be filled by the switch. The switch should fill the properties that have changed, whereas the unchanged properties can be included optionally.

Refer to the send_port_status_message() function in the of/openflow.c file for the procedure to send port_status_message to the controller.

Sending a controller role-status message to the controller

Controller role-status messages (OFPT_ROLE_STATUS) are sent from the switch to the set of controllers when the role of a controller is changed as a result of an OFPT_ROLE_REQUEST message. For example, if there are three the controllers connected to a switch (say controller1, controller2, and controller3) and controller1 sends an OFPT_ROLE_REQUEST message to the switch, then the switch should send an OFPT_ROLE_STATUS message to controller2 and controller3.

How to do it…

The switch should build the OFPT_ROLE_STATUS message with the following format and send it to all the other controllers:

/* Role status event message. */
struct ofp_role_status {
struct ofp_header header; /* Type OFPT_ROLE_REQUEST /
                           * OFPT_ROLE_REPLY. */
uint32_t role;           /* One of OFPCR_ROLE_*. */
uint8_t reason;           /* One of OFPCRR_*. */
uint8_t pad[3];           /* Align to 64 bits. */
uint64_t generation_id;   /* Master Election Generation Id */
/* Role Property list */
struct ofp_role_prop_header properties[0];
};

OpenFlow Cookbook

The reason field should be set with one of the following values as defined in the enumeration:

/* What changed about the controller role */
enum ofp_controller_role_reason {
OFPCRR_MASTER_REQUEST = 0, /* Another the controller asked
                           * to be master. */
OFPCRR_CONFIG = 1,         /* Configuration changed on the
                           * the switch. */
OFPCRR_EXPERIMENTER = 2,   /* Experimenter data changed. */
};

The role should be set to the new role of the controller. The generation_id should be set with the generation ID of the OFPT_ROLE_REQUEST message that triggered the OFPT_ROLE_STATUS message.

If the reason code is OFPCRR_EXPERIMENTER, then the role property list should be set in the following format:

/* Role property types.
*/
enum ofp_role_prop_type {
OFPRPT_EXPERIMENTER = 0xFFFF, /* Experimenter property. */
};
 
/* Experimenter role property */
struct ofp_role_prop_experimenter {
uint16_t type;         /* One of OFPRPT_EXPERIMENTER. */
uint16_t length;       /* Length in bytes of this property. */
uint32_t experimenter; /* Experimenter ID which takes the same
                       * form as struct
                       * ofp_experimenter_header. */
uint32_t exp_type;     /* Experimenter defined. */
/* Followed by:
* - Exactly (length - 12) bytes containing the experimenter data,
* - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
* bytes of all-zero bytes */
uint32_t experimenter_data[0];
};

The experimenter field in the experimenter ID should take the same format as the experimenter structure.

Refer to the send_role_status_message() function in the of/openflow.c file for the procedure to send a role status message to the controller.

Sending a table-status message to the controller

Table-status messages (OFPT_TABLE_STATUS) are sent from the switch to the controller when there is any change in the table status; for example, the number of entries in the table crosses the threshold value, called the vacancy threshold. The switch should send this message only to the controller channel in which the controller requested the switch to send it. The controller can express its interest to receive this event by sending the asynchronous configuration message to the switch.

How to do it…

The switch should build an OFPT_TABLE_STATUS message with the following format and send this message to the controllers that have already shown interest in this event:

/* A table config has changed in the datapath */
struct ofp_table_status {
struct ofp_header header;
uint8_t reason;             /* One of OFPTR_*. */
uint8_t pad[7];             /* Pad to 64 bits */
struct ofp_table_desc table; /* New table config. */
};

OpenFlow Cookbook

The reason field should be set with one of the following values defined in the enumeration:

/* What changed about the table */
enum ofp_table_reason {
OFPTR_VACANCY_DOWN = 3, /* Vacancy down threshold event. */
OFPTR_VACANCY_UP = 4,   /* Vacancy up threshold event. */
};

When the number of free entries in the table crosses the vacancy_down threshold, the switch should set the reason code as OFPTR_VACANCY_DOWN. Once the vacancy_down event is generated by the switch, the switch should not generate any further vacancy down event until a vacancy up event is generated. When the number of free entries in the table crosses the vacancy_up threshold value, the switch should set the reason code as OFPTR_VACANCY_UP. Again, once the vacancy up event is generated by the switch, the switch should not generate any further vacancy up event until a vacancy down event is generated.

The table field should be set with the table description. Refer to the send_table_status_message() function in the of/openflow.c file for the procedure to send a table status message to the controller.

Sending a request-forward message to the controller

When a the switch receives a modify request message from the controller to modify the state of a group or meter entries, after successful modification of the state, the switch should forward this request message to all other controllers as a request forward message (OFPT_REQUESTFORWAD). The switch should send this message only to the controller channel in which the controller requested the switch to send this event. The controller can express its interest to receive this event by sending an asynchronous configuration message to the switch.

How to do it…

The switch should build the OFPT_REQUESTFORWAD message with the following format, and send this message to the controllers that have already shown interest in this event:

/* Group/Meter request forwarding. */
struct ofp_requestforward_header {
struct ofp_header header; /* Type OFPT_REQUESTFORWARD. */
struct ofp_header request; /* Request being forwarded. */
};

The request field should be set with the request that received from the controller. Refer to the send_request_forward_message() function in the of/openflow.c file for the procedure to send request_forward_message to the controller.

Handling a packet-out message from the controller

Packet-out (OFPT_PACKET_OUT) messages are sent from the controller to the switch when the controller wishes to send a packet out through the switch’s data path via a switch port.

How to do it…

There are two ways in which the controller can send a packet-out message to the switch:

  1. Construct the full packet: In this case, the controller generates the complete packet and adds the action list field to the packet-out message. The action field contains a list of actions defining how the packet should be processed by the switch. If the switch receives a packet_out message with buffer_id set as OFP_NO_BUFFER, then the switch should look into the action list, and based on the action to be performed, it can do one of the following:
    1. Modify the packet and send it via the switch port mentioned in the action list
    2. Hand over the packet to OpenFlow’s pipeline processing, based on the OFPP_TABLE specified in the action list
  2. Use a packet buffer in the switch: In this mechanism, the switch should use the buffer that was created at the time of sending the packet-in message to the controller. While sending the packet_in message to the controller, the switch adds the buffer_id to the packet_in message. When the controller wants to send a packet_out message that uses this buffer, the controller includes this buffer_id in the packet_out message. On receiving the packet_out message with a valid buffer_id, the switch should fetch the packet from the buffer and send it via the switch port. Once the packet is sent out, the switch should free the memory allocated to the buffer, which was cached.

Handling a barrier message from the controller

The switch implementation could arbitrarily reorder the message sent from the controller to maximize its performance. So, if the controller wants to enforce the processing of the messages in order, then barrier messages are used. Barrier messages (OFPT_TABLE_STATUS) are sent from the controller to the switch to ensure message ordering.

The switch should not reorder any messages across the barrier message. For example, if the controller is sending a group add message, followed by a flow add message referencing the group, then the message order should be preserved in the barrier message.

How to do it…

When the controller wants to send messages that are related to each other, it sends a barrier message between these messages. The switch should process these messages as follows:

  1. Messages before a barrier request should be processed fully before the barrier, including sending any resulting replies or errors.
  2. The barrier request message should then be processed and a barrier reply should be sent. While sending the barrier reply message, the switch should copy the xid value from the barrier request message.
  3. The switch should process the remaining messages.

Both the barrier request and barrier reply messages don’t have any body. They only have the ofp_header.

Summary

This article covers the list of symmetric and asynchronous messages sent and received by the OpenFlow switch, along with the procedure for handling these messages.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here