OpenFlow controller developer’s guide

Controller instantiation

OpenFaucet is based on the Twisted framework for managing transport connections (e.g. TCP connections) between OpenFlow switches and controllers. Once a transport connection is established, the connection object is controlled by a controller stub object, which in turn controls a controller object and zero of more vendor extension handler objects. There is therefore a one-to-one binding between the transport connection and controller stub, a one-to-one binding between the controller stub and the controller, and one one-to-one binding between the controller stub and every vendor handler:

                         +---------+
                         |transport|
                         +---------+           1 +--------+
                            1 ^          +------>|vendor_1|
                              |          |       +--------+
                            1 v         1|
+----------+ 1      1 +---------------+<-+ 1   1 +--------+
|controller|<-------->|controller_stub|<-------->|vendor_2|
+----------+          +---------------+<-+       +--------+
                                        1|
                                         |     1 +--------+
                                         +------>|vendor_3|
                                                 +--------+

Every controller stub is an instance of class ControllerStub that is created by a factory object which is an instance of class OpenflowControllerStubFactory. This factory class implements Twisted’s IProtocolFactory interface, so it can be used the standard way to manage Twisted transport connections. It must be configured by passing arguments to the its constructor:

class openfaucet.ofcontroller.OpenflowControllerStubFactory
__init__(controller[, protocol, error_data_bytes, logger, vendor_handlers, reactor, default_op_timeout, echo_op_period])

Create a factory of OpenflowControllerStub objects and of controllers and vendor handlers bound to them. The only mandatory parameter is controller, the class of controller objects to create.

Parameters:
  • controller (class) – The class of controller objects to create, which must implement interface IOpenflowController.
  • protocol (class) – The class of protocol objects (controller stubs) to create. Defaults to class OpenflowControllerStub.
  • error_data_bytes (integer) – The maximum number of bytes of erroneous requests to send back in an error message. Must be >= 64. Defaults to 64.
  • logger – The Python logger object used for logging in every created protocol object. Defaults to the root logger, as obtained with logging.getLogger('').
  • vendor_handlers (class list) – A sequence of vendor handler classes. One instance of every class is instantiated (with no arguments) and passed to every created protocol object. Defaults to an empty sequence.
  • reactor (reactor object) – An object implementing Twisted’s IReactorTime interface, used to do delayed calls. Defaults to Twisted’s default reactor twisted.internet.reactor.
  • default_op_timeout (float) – The default period, in seconds, before an operation times out. This is also used as the timeout for echo operations, and as the timeout for initial handshakes. Defaults to 3.0 (seconds).
  • echo_op_period (float) – The period, in seconds, between two echo operations. Defaults to 5.0 (seconds).

For example, to configure a factory to create controller objects that are instance of class MyController, and to connect to an OpenFlow switch using a TCP connection:

from twisted.internet import reactor
from openfaucet import ofcontroller

factory = ofcontroller.OpenflowControllerStubFactory(
    controller=MyController)
reactor.connectTCP('switch1.example.com', 6633, factory)
reactor.run()

Controller objects are created by the factory by calling the given controller class with no arguments, so every controller class must implement an __init__() constructor with no arguments. If a controller object requires attributes to be set, implement a factory that is a subclass of OpenflowControllerStubFactory which sets the attributes after the controller stub, the controller and vendor handlers are created, and override method buildProtocol():

from openfaucet import ofcontroller

class MyController(object):

    def __init__():
        pass

    # ...

class MyControllerStubFactory(ofcontroller.OpenflowControllerStubFactory):

    def buildProtocol(self, addr):
        p = ofcontroller.OpenflowControllerStubFactory.buildProtocol(self, addr)
        controller = p.controller
        # Complete controller initialization.
        controller.some_attribute = self._some_value
        return p

Asynchronous message callbacks

Every controller class must implement OpenFaucet’s IOpenflowController interface, which defines the following 5 callback methods:

class openfaucet.ofcontroller.IOpenflowController
connection_made()
Initialize the resources to manage the newly opened OpenFlow connection. This callback is made once the handshake is completed with the switch, i.e. once the description of the switch’s features have been received. This callback is never made in case the handshake times out, in which case the connection is closed.
connection_lost(reason)

Release any resources used to manage the connection that was just lost.

All operations that are still pending when this method is called back are cancelled silently.

Parameter:reason – The reason why the connection was lost, as a Failure that wraps a ConnectionDone or ConnectionLost instance (or a subclass of one of those).
handle_packet_in(buffer_id, total_len, in_port, reason, data)

Handle the reception of a OFPT_PACKET_IN message, i.e. an Ethernet frame forwarded by the datapath.

Parameters:
  • buffer_id (integer) – The buffer ID assigned by datapath. If 0xffffffff, the frame is not buffered, and the entire frame is passed in data.
  • total_len (integer) – The full length of the frame, in bytes.
  • in_port (integer) – The port on which the frame was received.
  • reason (integer) – The reason why the frame is being sent, either OFPR_NO_MATCH (no matching flow) or OFPR_ACTION (action explicitly output to controller).
  • data (binary string) – The Ethernet frame.
handle_flow_removed(match, cookie, priority, reason, duration_sec, duration_nsec, idle_timeout, packet_count, byte_count)

Handle the reception of a OFPT_FLOW_REMOVED message, i.e. the notification that a flow has been removed from the datapath.

Parameters:
  • match – A Match object describing the fields of the flow.
  • cookie (64-bit unsigned integer) – An opaque value issued by the controller when the flow was added.
  • priority (16-bit unsigned integer) – The priority level of the expired flow entry.
  • reason (integer) – The reason why the flow entry expired, either OFPRR_IDLE_TIMEOUT (flow idle time exceeded idle_timeout), OFPRR_HARD_TIMEOUT (time exceeded hard_timeout), or OFPRR_DELETE (evicted by a DELETE flow mod message).
  • duration_sec (32-bit unsigned integer) – Time the flow was alive in seconds.
  • duration_nsec (32-bit unsigned integer) – Time flow was alive in nanoseconds beyond duration_sec.
  • idle_timeout (16-bit unsigned integer) – The idle timeout in seconds from the original flow mod.
  • packet_count (64-bit unsigned integer) – The number of packets in the flow.
  • byte_count (64-bit unsigned integer) – The number of bytes in packets in the flow.
handle_port_status(reason, desc)

Handle the reception of a OFPT_PORT_STATUS message, i.e. a notification that a datapath port’s status has changed.

Parameters:
  • reason (integer) – The reason for the port status change, either OFPPR_ADD (the port was added), OFPPR_DELETE (the port was removed), or OFPPR_MODIFY (some attribute of the port has changed).
  • desc – A PhyPort object defining the physical port, including its new status.

Sending messages to datapaths

Every controller object is bound to an OpenflowControllerStub object that provides methods for sending requests and messages to the connected OpenFlow datapath, as defined in interface IOpenflowControllerStub. The stub is referenced by a weak reference set in the controller’s protocol attribute, so it must be retrieved by calling self.protocol(). For instance, to print the datapath ID once the handshake with the datapath is terminated:

class MyController(object):

    def connection_made(self):
        dp_id = self.protocol().features.datapath_id
        print 'connected to datapath', dp_id

The controller stub provides several asynchronous methods for request / reply operations with the datapath. Those methods take callables as arguments to specify callbacks to be made when the operation’s reply is received or when the operation times out.

If a callable needs to get additional positional or keyword arguments in addition to the arguments passed by the protocol object, the caller must wrap the callable into a Callable object.

class openfaucet.ofprotoops.Callable

A namedtuple object that decorates a callable to pass additional arguments to it when called. The additional arguments to the callable are passed in addition to the arguments given by the caller. The preferred way to create a Callable is by calling make_callable():

classmethod make_callable(callable[, *args, **kwargs])

Create a Callable with the given callable and args.

Parameters:
  • callable – A callable.
  • args – The (possibly empty) sequence of additional positional arguments to pass to the callable.
  • kwargs – The (possibly empty) dict of additional keyword arguments to pass to the callable.

A callable object can then be called directly, possibly with positional and keyword arguments. The positional arguments given to the call correspond to the signature of the method expected by the caller. The additional positional and keyword arguments given to make_callable() can be used to pass context information to the callable, for example:

from openfaucet import ofprotoops

def my_callable(data, log_prefix=None):
    print '%s: %r' % (log_prefix, data)

def call_me_back(callback):
    data = 'world'
    callback(data)

callback= ofprotoops.Callable.make_callable(log_prefix='hello')
call_me_back(callback)
class openfaucet.ofcontroller.OpenflowControllerStub
class openfaucet.ofcontroller.IOpenflowControllerStub

Configuration

features
The SwitchFeatures object describing the switch features. None if the handshake with the datapath has not yet been completed, i.e. before connection_made() has been called back. This SwitchFeatures object is automatically updated by this stub when any port status changes.
get_features(callback[, timeout_callback, timeout])

Request the switch features.

Parameters:
  • callback – The callable to be called with the replied data.
  • timeout_callback – The callable to be called in case the operation times out.
  • timeout (integer or None) – The period, in seconds, before the operation times out. If None, defaults to the default timeout.

Note

Using this object’s features attribute is more efficient than calling this method, so this method should normally not be called by controllers.

This operation is asynchronous: the switch features are passed back by calling the given callback as:

callback(switch_features)
Parameter:switch_features – A SwitchFeatures object containing the switch features.

If the operation times out, i.e. if no reply is received before the timeout period, and if timeout_callback is not None, timeout_callback is called as:

timeout_callback()

callback and / or timeout_callback must be None if no callback must be made when the reply is received and / or the operation times out. They may also be Callable objects to pass additional arguments to the callables.

get_config(callback[, timeout_callback, timeout])

Request the switch config.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(switch_config)
Parameter:switch_config – A SwitchConfig object containing the switch configuration.
send_set_config(switch_config)

Send a OFPT_SET_CONFIG message to modify the switch configuration.

Parameter:switch_config – A SwitchConfig object containing the switch configuration.
send_port_mod(port_no, hw_addr, config, mask, advertise)

Send a OFPT_PORT_MOD message to modify the configuration of a port.

Parameters:
  • port_no (16-bit unsigned integer) – The port’s unique number. Must be between 1 and OFPP_MAX.
  • hw_addr (binary string) – The port’s MAC address. The hardware address is not configurable. This is used only to sanity-check the request, so it must be the same as returned in PhyPort object.
  • config – The PortConfig containing the new values of fields to replace. Only the fields which are True in mask are replaced, the others are ignored.
  • mask – The PortConfig indicating which fields are to be replaced with values from config.
  • advertise – The PortFeatures indicating the features to be advertised by the port. If None or all fields are False, the advertised features are not replaced.

The config and mask arguments can be obtained by calling get_diff() on a PortConfig object. For instance, to disable flooding on every port at connection time:

from openfaucet import ofproto

class MyController(object):

    def connection_made(self):
        for port in self.protocol().features.ports:
            if not port.config.no_flood:
                new_config = port.config._replace(no_flood=True)
                config, mask = new_config.get_diff(port.config)
                self.protocol().send_port_mod(port.port_no, port.hw_addr,
                                              config, mask, None)
get_queue_config(port_no, callback[, timeout_callback, timeout])

Request a port’s queues configs.

Parameter:port_no (16-bit unsigned integer) – The port’s unique number. Must be a valid physical port, i.e. < OFPP_MAX.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(port_no, queues)
Parameters:
  • port_no (16-bit unsigned integer) – The port’s unique number. Must be a valid physical port, i.e. < OFPP_MAX.
  • queues – A sequence of PacketQueue objects describing the port’s queues.

Flows and packets

send_packet_out(buffer_id, in_port, actions, data)

Send a OFPT_PACKET_OUT message to have a packet processed by the datapath.

Parameters:
  • buffer_id (32-bit unsigned integer) – The buffer ID assigned by the datapath. If 0xffffffff, the frame is not buffered, and the entire frame must be passed in data.
  • in_port (integer) – The port from which the frame is to be sent. OFPP_NONE if none. OFPP_TABLE to perform the actions defined in the flow table.
  • actions – The sequence of action objects (implementing IAction) specifying the actions to perform on the frame.
  • data – The entire Ethernet frame, as a sequence of binary strings. Should be of length 0 if buffer_id is -1, and should be of length >0 otherwise.
send_flow_mod_add(match, cookie, idle_timeout, hard_timeout, priority, buffer_id, send_flow_rem, check_overlap, emerg, actions)

Send a OFPT_FLOW_MOD message to add a flow into the datapath.

Parameters:
  • match – A Match object describing the fields of the flow.
  • cookie (64-bit unsigned integer) – An opaque value issued by the controller. 0xffffffffffffffff is reserved and must not be used.
  • idle_timeout (16-bit unsigned integer) – The idle time in seconds before discarding.
  • hard_timeout (16-bit unsigned integer) – The maximum time before discarding in seconds.
  • priority (16-bit unsigned integer) – The priority level of the flow entry.
  • buffer_id (32-bit unsigned integer) – The buffer ID assigned by the datapath of a buffered packet to apply the flow to. If 0xffffffff, no buffered packet is to be applied the flow actions.
  • send_flow_rem (bool) – If True, send a OFPT_FLOW_REMOVED message when the flow expires or is deleted.
  • check_overlap (bool) – If True, check for overlapping entries first, i.e. if there are conflicting entries with the same priority, the flow is not added and the modification fails.
  • emerg (bool) – if True, the switch must consider this flow entry as an emergency entry, and only use it for forwarding when disconnected from the controller.
  • actions – The sequence of action objects (see ofaction) specifying the actions to perform on the flow’s packets.
send_flow_mod_modify(strict, match, cookie, idle_timeout, hard_timeout, priority, buffer_id, send_flow_rem, check_overlap, emerg, actions)

Send a OFPT_FLOW_MOD message to modify a flow in the datapath.

Parameters:
  • strict (bool) – If True, all args, including the wildcards and priority, are strictly matched against the entry, and only an identical flow is modified. If False, a match will occur when a flow entry exactly matches or is more specific than the given match and priority.
  • match – A Match object describing the fields of the flow.
  • cookie (64-bit unsigned integer) – An opaque value issued by the controller. 0xffffffffffffffff is reserved and must not be used.
  • idle_timeout (16-bit unsigned integer) – The idle time in seconds before discarding.
  • hard_timeout (16-bit unsigned integer) – The maximum time before discarding in seconds.
  • priority (16-bit unsigned integer) – The priority level of the flow entry.
  • buffer_id (32-bit unsigned integer) – The buffer ID assigned by the datapath of a buffered packet to apply the flow to. If 0xffffffff, no buffered packet is to be applied the flow actions.
  • send_flow_rem (bool) – If True, send a OFPT_FLOW_REMOVED message when the flow expires or is deleted.
  • check_overlap (bool) – If True, check for overlapping entries first, i.e. if there are conflicting entries with the same priority, the flow is not added and the modification fails.
  • emerg (bool) – if True, the switch must consider this flow entry as an emergency entry, and only use it for forwarding when disconnected from the controller.
  • actions – The sequence of action objects (see ofaction) specifying the actions to perform on the flow’s packets.
send_flow_mod_delete(strict, match, priority, out_port)

Send a OFPT_FLOW_MOD message to delete a flow from the datapath.

Parameters:
  • strict (bool) – If True, all args, including the wildcards and priority, are strictly matched against the entry, and only an identical flow is deleted. If False, a match will occur when a flow entry exactly matches or is more specific than the given match and priority.
  • match – A Match object describing the fields of the flow.
  • priority (16-bit unsigned integer) – The priority level of the flow entry.
  • out_port (integer) – An output port that is required to be included in matching flows’ output actions. If OFPP_NONE, no restriction applies in matching.
barrier(callback[, timeout_callback, timeout])

Request a synchronization barrier.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback()

The callback is called when the barrier has been reached, i.e. any message sent before the barrier has been completely processed by the datapath.

Statistics

get_stats_desc(callback[, timeout_callback, timeout])

Request the switch stats.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(desc_stats)
Parameter:desc_stats – A DescriptionStats that contains the switch description stats.
get_stats_flow(match, table_id, out_port, callback[, timeout_callback, timeout])

Request individual flow stats.

Parameters:
  • match – A Match object describing the fields of the flows to match.
  • table_id (8-bit unsigned integer) – The ID of the table to read. 0xff for all tables or 0xfe for emergency.
  • out_port (integer) – Require matching flows to include this as an output port. A value of OFPP_NONE indicates no restriction.

The callback is called with the individual stats of every flow matching the given criteria.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(flow_stats, reply_more)
Parameters:
  • flow_stats – A tuple of FlowStats objects each containing the stats for an individual flow.
  • reply_more (bool) – If True, more callbacks will be made to the callable after this one to completely terminate this operation. If False, this is the last callback in this operation.

One or more calls to the callback may be made, to reply the stats for all matching flows: zero or more calls with reply_more set to True, followed by one call with reply_more set to False. The operation’s timeout applies to the whole sequence of calls. So zero or more calls may be made to callback with reply_more set to True, before the operation times out and timeout_callback is called back.

get_stats_aggregate(match, table_id, out_port, callback[, timeout_callback, timeout])

Request aggregate flow stats.

The arguments are identical to those of get_stats_flow(), except that the callback is called with the aggregate stats of all flows matching the given criteria.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(packet_count, byte_count, flow_count)
Parameters:
  • packet_count (64-bit unsigned integer) – The number of packets in aggregated flows.
  • byte_count (64-bit unsigned integer) – The number of bytes in aggregated flows.
  • flow_count (32-bit unsigned integer) – The number of aggregated flows.
get_stats_table(callback[, timeout_callback, timeout])

Request table stats.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(table_stats, reply_more)
Parameters:
  • table_stats – A tuple of TableStats objects containing each the stats for an individual table.
  • reply_more (bool) – Indicates if this callback is not the last in this operation, cf. get_stats_flow().
get_stats_port(port_no, callback[, timeout_callback, timeout])

Request port stats.

Parameter:port_no (16-bit unsigned integer) – The port’s unique number. If OFPP_NONE, stats for all ports are replied.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(port_stats, reply_more)
Parameters:
  • port_stats – A tuple of PortStats objects containing each the stats for an individual port.
  • reply_more (bool) – Indicates if this callback is not the last in this operation, cf. get_stats_flow().
get_stats_queue(port_no, queue_id, callback[, timeout_callback, timeout])

Request queue stats.

Parameters:
  • port_no (16-bit unsigned integer) – The port’s unique number. If OFPP_ALL, stats for all ports are replied.
  • queue_id (32-bit unsigned integer) – The queue’s ID. If OFPQ_ALL, stats for all queues are replied.

This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:

callback(queue_stats, reply_more)
Parameters:
  • queue_stats – A tuple of QueueStats objects containing each the stats for an individual queue.
  • reply_more (bool) – Indicates if this callback is not the last in this operation, cf. get_stats_flow().
raise_error_with_request(error_type, error_code)

Raise an OpenflowError with the failed request.

The raised exception’s data contains at least 64 bytes of the currently handled message. This method must be called from a message handling callback.

Parameters:
  • error_type – The error type, as one of the OFPET_* constants.
  • error_code – The error code, as one of the OFP* error code constants.

Table Of Contents

Previous topic

Installing OpenFaucet

Next topic

OpenFlow flow matching