blob: 1526cee4beb016278a902d9b7b78cdc894e59d7a [file] [log] [blame]
"""
OpenFlow Test Framework
Controller class
Provide the interface to the control channel to the switch under test.
Class inherits from thread so as to run in background allowing
asynchronous callbacks (if needed, not required). Also supports
polling.
The controller thread maintains a queue. Incoming messages that
are not handled by a callback function are placed in this queue for
poll calls.
Callbacks and polling support specifying the message type
@todo Support transaction semantics via xid
"""
import sys
sys.path.append("../ofmsg")
import os
import socket
import time
import promisc
from threading import Thread
from threading import Lock
from message import *
class Controller(Thread):
"""
Class abstracting the control interface to the switch.
For receiving messages, two mechanism will be implemented. First,
query the interface with poll. Second, register to have a
function called by message type. The callback is passed the
message type as well as the raw packet (or message object)
One of the main purposes of this object is to translate between network
and host byte order. 'Above' this object, things should be in host
byte order.
"""
def __init__(port=6633, passive=1):
if (passive):
# FIXME: add error handling
self.sock = open_ctrlsocket()
self.clientsock, self.clientaddr = self.sock.accept()
else:
print "Error in controller init: Active cxn not supported"
def register(self, msg_type, handler):
"""
Register a callback to receive a specific message type.
Only one handler may be registered for a given message type.
@param msg_type The type of message to receive. May be DEFAULT
for all non-handled packets.
@param handler The function to call when a message of the given
type is received.
"""
print "Controller message handler registration not supported"
def poll(self, exp_msg=None, timeout=None):
"""
Wait for the next OF message received from the switch.
@param exp_msg If set, return only when this type of message
is received.
@param timeout If set, return E_TIMEOUT if mesage is not
received in this time. If set to 0, will not block.
@retval A triple (msg_type, msg, data) where msg_type is the OpenFlow
message type value OFPT_xxx, msg is a message object (from a
SWIG generated class) appropriate to the message type and data is
a string of any additional information following the
normal message. Note that
many messages do not have classes so ofp_hello is returned which
simply has the header.
The data members in the message are in host endian order.
If a timeout (or other error) occurs, None is returned
"""
while 1:
okay, pkt = rcv_data_from_socket(self.clientsoc, timeout)
if not okay or not pkt:
# FIXME: Check for error
return None, None
# Convert msg to the proper OpenFlow message object
msg_type, msg = ofpkt.pkt_to_msg(pkt)
print "DEBUG: Got msg type %d of len %d" % (msg_type, len(msg))
if not exp_msg or (exp_msg and (hdr.type == exp_msg)):
return msg_type, msg
def flow_install(self, flow):
"""
Install the flow indicated through the control interface
TBD: We may just use message_send below with ofp_flow_mod objects
@param flow The ofp_flow_mod object to install
"""
def message_send(self, msg):
"""
Send the message to the switch
@param msg An OpenFlow message object (from a SWIG generated
class) to be forwarded to the switch. The data members of the
object must be in host endian order when pased to message_send.
"""
def kill(self):
self.clientsock.close()