It's somewhat difficult to use OFTest, in my opinion, because you need to be root, work with OS network devices, and so on. Today I played around with some code to avoid those two needs.
First, I have a patch series starting here: http://openvswitch.org/pipermail/dev/2012-October/022300.html that adds an ability for OVS to use Unix domain sockets as simulated network devices. Second, I'm attaching a file meant to be put in platforms/dummy.py in the OFTest tree to use these simulated network devices. Finally, I'm attaching a shell script that starts OVS in a sandboxed mode using these dummy devices. It passes a few tests; I've only tried a few. Now that I look at it, there are some bugs here that will prevent traffic from actually passing through, but they are not fundamental to the approach. I'm mostly passing this along in case anyone wants to comment on the idea; I've already spent more time on it than I should have.
""" Dummy platform This platform uses Open vSwitch dummy interfaces. """ import logging import os import select import socket import struct import sys import time from threading import Thread from threading import Lock RCV_TIMEOUT = 10000 SOCKET_DIR = os.environ.get("OVS_RUNDIR", """/var/run""") + "/openvswitch" class DataPlanePortUnix: """ Class defining a port monitoring object that uses Unix domain sockets for ports, intended for connecting to Open vSwitch "dummy" netdevs. """ def __init__(self, interface_name, port_number, parent, max_pkts=1024): """ Set up a port monitor object @param interface_name The name of the physical interface like eth1 @param port_number The port number associated with this port @param parent The controlling dataplane object; for pkt wait CV @param max_pkts Maximum number of pkts to keep in queue """ Thread.__init__(self) self.interface_name = interface_name self.max_pkts = max_pkts self.packets_total = 0 self.packets = [] self.packets_discarded = 0 self.port_number = port_number self.txq = [] self.txq_lock = Lock() logname = "dp-" + interface_name self.logger = logging.getLogger(logname) try: self.socket = DataPlanePortUnix.interface_open(interface_name) except: self.logger.info("Could not open socket") raise self.logger.info("Opened port monitor (class %s)", type(self).__name__) self.parent = parent @staticmethod def interface_open(interface_name): """ Open a Unix domain socket interface. @param interface_name port name as a string such as 'eth1' @retval s socket """ s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.settimeout(RCV_TIMEOUT) s.setblocking(0) s.connect("%s/%s" % (SOCKET_DIR, interface_name)) return s def run(self): """ Activity function for class """ self.running = True rxbuf = "" while self.running: try: self.txq_lock.acquire() if self.txq: wlist = [self.socket] else: wlist = [] self.txq_lock.release() rout, wout, eout = select.select([self.socket], wlist, [], 1) except: print sys.exc_info() self.logger.error("Select error, exiting") break if not self.running: break if wout: self.txq_lock.acquire() if self.txq: retval = self.socket.send(self.txq[0]) if retval > 0: self.txq[0] = self.txq[0][retval:] if len(self.txq[0]) == 0: self.txq = self.txq[1:] self.txq_lock.release() if rout: if len(rxbuf) < 2: n = 2 - len(rxbuf) else: frame_len = struct.unpack('>h', rxbuf[:2])[0] n = (2 + frame_len) - len(rxbuf) data = self.socket.recv(n) rxbuf += data if len(data) == n and len(rxbuf) > 2: rcvtime = time.clock() self.logger.debug("Pkt len " + str(len(rxbuf)) + " in at " + str(rcvtime) + " on port " + str(self.port_number)) # Enqueue packet with self.parent.pkt_sync: if len(self.packets) >= self.max_pkts: # Queue full, throw away oldest self.packets.pop(0) self.packets_discarded += 1 self.logger.debug("Discarding oldest packet to make room") self.packets.append((rxbuf, rcvtime)) self.packets_total += 1 self.parent.pkt_sync.notify_all() rxbuf = '' self.logger.info("Thread exit") def kill(self): """ Terminate the running thread """ self.logger.debug("Port monitor kill") self.running = False try: self.socket.close() except: self.logger.info("Ignoring dataplane soc shutdown error") def timestamp_head(self): """ Return the timestamp of the head of queue or None if empty """ rv = None try: rv = self.packets[0][1] except: rv = None return rv def flush(self): """ Clear the packet queue """ with self.parent.pkt_sync: self.packets_discarded += len(self.packets) self.packets = [] def send(self, packet): """ Send a packet to the dataplane port @param packet The packet data to send to the port @retval The number of bytes sent """ self.txq_lock.acquire() if len(self.txq) < self.max_pkts: self.txq.append(struct.pack('>h', len(packet)) + packet) self.txq_lock.release() def register(self, handler): """ Register a callback function to receive packets from this port. The callback will be passed the packet, the interface name and the port number (if set) on which the packet was received. To be implemented """ pass def show(self, prefix=''): print prefix + "Name: " + self.interface_name print prefix + "Pkts pending: " + str(len(self.packets)) print prefix + "Pkts total: " + str(self.packets_total) print prefix + "socket: " + str(self.socket) # Update this dictionary to suit your environment. dummy_port_map = { 1 : "p1", 2 : "p2", 3 : "p3", 4 : "p4" } def platform_config_update(config): """ Update configuration for the dummy platform @param config The configuration dictionary to use/update """ global dummy_port_map config["port_map"] = dummy_port_map.copy() config["caps_table_idx"] = 0 config["dataplane"] = {"portclass": DataPlanePortUnix} config["allow_user"] = True
#! /bin/sh set -ex srcdir=$HOME/ovs builddir=$srcdir/_build PATH=$builddir/ovsdb:$builddir/vswitchd:$builddir/utilities:$PATH cd $builddir rm -rf sandbox mkdir sandbox cd sandbox OVS_RUNDIR=`pwd`; export OVS_RUNDIR OVS_LOGDIR=`pwd`; export OVS_LOGDIR OVS_DBDIR=`pwd`; export OVS_DBDIR OVS_SYSCONFDIR=`pwd`; export OVS_SYSCONFDIR trap 'kill `cat *.pid`' 0 touch .conf.db.~lock~ rm -f conf.db ovsdb-tool create conf.db $srcdir/vswitchd/vswitch.ovsschema ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:$OVS_RUNDIR/db.sock ovs-vsctl --no-wait init ovs-vswitchd --detach --no-chdir --pidfile --enable-dummy --disable-system -vvconn -vofproto_dpif ovs-vsctl \ -- add-br br0 \ -- set bridge br0 datapath-type=dummy fail-mode=secure \ -- add-port br0 p1 -- set interface p1 type=dummy \ -- add-port br0 p2 -- set interface p2 type=dummy \ -- add-port br0 p3 -- set interface p3 type=dummy \ -- add-port br0 p4 -- set interface p4 type=dummy \ -- set-controller br0 tcp:127.0.0.1 read line
_______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev