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:
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: |
|
---|
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
Every controller class must implement OpenFaucet’s IOpenflowController interface, which defines the following 5 callback methods:
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 the reception of a OFPT_PACKET_IN message, i.e. an Ethernet frame forwarded by the datapath.
Parameters: |
|
---|
Handle the reception of a OFPT_FLOW_REMOVED message, i.e. the notification that a flow has been removed from the datapath.
Parameters: |
|
---|
Handle the reception of a OFPT_PORT_STATUS message, i.e. a notification that a datapath port’s status has changed.
Parameters: |
|
---|
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.
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():
Create a Callable with the given callable and args.
Parameters: |
|
---|
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)
Configuration
Request the switch features.
Parameters: |
|
---|
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:
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:
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.
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:
Parameter: | switch_config – A SwitchConfig object containing the switch configuration. |
---|
Send a OFPT_SET_CONFIG message to modify the switch configuration.
Parameter: | switch_config – A SwitchConfig object containing the switch configuration. |
---|
Send a OFPT_PORT_MOD message to modify the configuration of a port.
Parameters: |
|
---|
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)
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:
Parameters: |
|
---|
Flows and packets
Send a OFPT_PACKET_OUT message to have a packet processed by the datapath.
Parameters: |
|
---|
Send a OFPT_FLOW_MOD message to add a flow into the datapath.
Parameters: |
|
---|
Send a OFPT_FLOW_MOD message to modify a flow in the datapath.
Parameters: |
|
---|
Send a OFPT_FLOW_MOD message to delete a flow from the datapath.
Parameters: |
|
---|
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:
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
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:
Parameter: | desc_stats – A DescriptionStats that contains the switch description stats. |
---|
Request individual flow stats.
Parameters: |
|
---|
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:
Parameters: |
|
---|
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.
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:
Parameters: |
|
---|
Request table stats.
This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:
Parameters: |
|
---|
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:
Parameters: |
|
---|
Request queue stats.
Parameters: |
|
---|
This operation is asynchronous. The callback, timeout_callback, and timeout are similar as in get_features(), and callback is called as:
Parameters: |
|
---|
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: |
|
---|