Skip to content
Snippets Groups Projects
Commit 121eb449 authored by Bob Lantz's avatar Bob Lantz
Browse files

Changed to support new cmd() interface.

It seems that it is more convenient to be able to call

cmd( 'foo', 'bar', 1)

for example. However, this may make it slightly less
efficient, so we will see how it works.
parent 8bc00379
No related branches found
No related tags found
No related merge requests found
......@@ -60,14 +60,16 @@ class Node( object ):
outToNode = {} # mapping of output fds to nodes
def __init__( self, name, inNamespace=True,
defaultMAC=None, defaultIP=None ):
defaultMAC=None, defaultIP=None, **kwargs ):
"""name: name of node
inNamespace: in network namespace?
defaultMAC: default MAC address for intf 0
defaultIP: default IP address for intf 0"""
self.name = name
opts = '-cdp'
self.inNamespace = inNamespace
self.defaultIP = defaultIP
self.defaultMAC = defaultMAC
opts = '-cdp'
if self.inNamespace:
opts += 'n'
cmd = [ 'mnexec', opts, 'bash', '-m' ]
......@@ -75,6 +77,7 @@ def __init__( self, name, inNamespace=True,
close_fds=False )
self.stdin = self.shell.stdin
self.stdout = self.shell.stdout
self.pid = self.shell.pid
self.pollOut = select.poll()
self.pollOut.register( self.stdout )
# Maintain mapping between file descriptors and nodes
......@@ -82,15 +85,12 @@ def __init__( self, name, inNamespace=True,
# using select.poll()
self.outToNode[ self.stdout.fileno() ] = self
self.inToNode[ self.stdin.fileno() ] = self
self.pid = self.shell.pid
self.intfs = {} # dict of port numbers to interface names
self.ports = {} # dict of interface names to port numbers
# replace with Port objects, eventually ?
self.ips = {} # dict of interfaces to ip addresses as strings
self.connection = {} # remote node connected to each interface
self.execed = False
self.defaultIP = defaultIP
self.defaultMAC = defaultMAC
self.lastCmd = None
self.lastPid = None
self.readbuf = ''
......@@ -155,11 +155,16 @@ def waitReadable( self, timeoutms=None ):
if len( self.readbuf ) == 0:
self.pollOut.poll( timeoutms )
def sendCmd( self, cmd, printPid=True ):
def sendCmd( self, *args, **kwargs ):
"""Send a command, followed by a command to echo a sentinel,
and return without waiting for the command to complete."""
and return without waiting for the command to complete.
args: command and arguments, or string
printPid: print command's PID?"""
assert not self.waiting
if isinstance( cmd, list ):
printPid = kwargs.get( 'printPid', True )
if len( args ) > 0:
cmd = args
if not isinstance( cmd, str ):
cmd = ' '.join( cmd )
if not re.search( r'\w', cmd ):
# Replace empty commands with something harmless
......@@ -221,18 +226,19 @@ def waitOutput( self, verbose=False ):
log( data )
return output
def cmd( self, cmd, verbose=False ):
def cmd( self, *args, **kwargs ):
"""Send a command, wait for output, and return it.
cmd: string"""
verbose = kwargs.get( 'verbose', False )
log = info if verbose else debug
log( '*** %s : %s\n' % ( self.name, cmd ) )
self.sendCmd( cmd )
log( '*** %s : %s\n' % ( self.name, args ) )
self.sendCmd( *args, **kwargs )
return self.waitOutput( verbose )
def cmdPrint( self, cmd ):
def cmdPrint( self, *args):
"""Call cmd and printing its output
cmd: string"""
return self.cmd( cmd, verbose=True )
return self.cmd( *args, **{ 'verbose': True } )
# Interface management, configuration, and routing
......@@ -252,10 +258,12 @@ def newPort( self ):
return max( self.ports.values() ) + 1
return 0
def addIntf( self, intf, port ):
def addIntf( self, intf, port=None ):
"""Add an interface.
intf: interface name (nodeN-ethM)
port: port number (typically OpenFlow port number)"""
intf: interface name (e.g. nodeN-ethM)
port: port number (optional, typically OpenFlow port number)"""
if port is None:
port = self.newPort()
self.intfs[ port ] = intf
self.ports[ intf ] = port
#info( '\n' )
......@@ -293,7 +301,7 @@ def linkTo( self, node2, port1=None, port2=None ):
if port1 is None:
port1 = node1.newPort()
if port2 is None:
port2 = node2.newPort()
port2 = node2.newPort()
intf1 = node1.intfName( port1 )
intf2 = node2.intfName( port2 )
makeIntfPair( intf1, intf2 )
......@@ -319,16 +327,16 @@ def deleteIntfs( self ):
def setMAC( self, intf, mac ):
"""Set the MAC address for an interface.
mac: MAC address as string"""
result = self.cmd( [ 'ifconfig', intf, 'down' ] )
result += self.cmd( [ 'ifconfig', intf, 'hw', 'ether', mac ] )
result += self.cmd( [ 'ifconfig', intf, 'up' ] )
result = self.cmd( 'ifconfig', intf, 'down' )
result += self.cmd( 'ifconfig', intf, 'hw', 'ether', mac )
result += self.cmd( 'ifconfig', intf, 'up' )
return result
def setARP( self, ip, mac ):
"""Add an ARP entry.
ip: IP address as string
mac: MAC address as string"""
result = self.cmd( [ 'arp', '-s', ip, mac ] )
result = self.cmd( 'arp', '-s', ip, mac )
return result
def setIP( self, intf, ip, prefixLen=8 ):
......@@ -337,7 +345,7 @@ def setIP( self, intf, ip, prefixLen=8 ):
ip: IP address as a string
prefixLen: prefix length, e.g. 8 for /8 or 16M addrs"""
ipSub = '%s/%d' % ( ip, prefixLen )
result = self.cmd( [ 'ifconfig', intf, ipSub, 'up' ] )
result = self.cmd( 'ifconfig', intf, ipSub, 'up' )
self.ips[ intf ] = ip
return result
......@@ -391,11 +399,16 @@ class Switch( Node ):
"""A Switch is a Node that is running (or has execed?)
an OpenFlow switch."""
def sendCmd( self, cmd, printPid=False):
def __init__( self, name, opts='', **kwargs):
Node.__init__( self, name, **kwargs )
self.opts = opts
def sendCmd( self, *cmd, **kwargs ):
"""Send command to Node.
cmd: string"""
kwargs.setdefault( 'printPid', False )
if not self.execed:
return Node.sendCmd( self, cmd, printPid )
return Node.sendCmd( self, *cmd, **kwargs )
else:
error( '*** Error: %s has execed and cannot accept commands' %
self.name )
......@@ -433,10 +446,10 @@ def start( self, controllers ):
if self.inNamespace:
intfs = intfs[ :-1 ]
self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
' punix:/tmp/' + self.name +
' punix:/tmp/' + self.name +
' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
self.cmd( 'ofprotocol unix:/tmp/' + self.name +
' tcp:' + controller.IP() + ' --fail=closed' +
' tcp:' + controller.IP() + ' --fail=closed ' + self.opts +
' 1> ' + ofplog + ' 2>' + ofplog + ' &' )
def stop( self ):
......@@ -448,14 +461,16 @@ def stop( self ):
class KernelSwitch( Switch ):
"""Kernel-space switch.
Currently only works in root namespace."""
def __init__( self, name, dp=None, **kwargs ):
"""Init.
name: name for switch
dp: netlink id (0, 1, 2, ...)
defaultMAC: default MAC as string; random value if None"""
Switch.__init__( self, name, **kwargs )
self.dp = dp
print kwargs, "opts=", self.opts
self.dp = 'nl:%i' % dp
self.intf = 'of%i' % dp
if self.inNamespace:
error( "KernelSwitch currently only works"
" in the root namespace." )
......@@ -472,28 +487,26 @@ def start( self, controllers ):
quietRun( 'ifconfig lo up' )
# Delete local datapath if it exists;
# then create a new one monitoring the given interfaces
quietRun( 'dpctl deldp nl:%i' % self.dp )
self.cmd( 'dpctl adddp nl:%i' % self.dp )
quietRun( 'dpctl deldp ' + self.dp )
self.cmd( 'dpctl adddp ' + self.dp )
if self.defaultMAC:
intf = 'of%i' % self.dp
self.cmd( [ 'ifconfig', intf, 'hw', 'ether', self.defaultMAC ] )
self.cmd( 'ifconfig', self.intf, 'hw', 'ether', self.defaultMAC )
if len( self.intfs ) != max( self.intfs ) + 1:
raise Exception( 'only contiguous, zero-indexed port ranges'
'supported: %s' % self.intfs )
intfs = [ self.intfs[ port ] for port in sorted( self.intfs.keys() ) ]
self.cmd( 'dpctl addif nl:' + str( self.dp ) + ' ' +
' '.join( intfs ) )
self.cmd( 'dpctl', 'addif', self.dp, ' '.join( intfs ) )
# Run protocol daemon
controller = controllers[ 0 ]
self.cmd( 'ofprotocol nl:' + str( self.dp ) + ' tcp:' +
controller.IP() + ':' +
str( controller.port ) +
' --fail=closed 1> ' + ofplog + ' 2>' + ofplog + ' &' )
self.cmdPrint( 'ofprotocol ' + self.dp +
' tcp:%s:%d' % ( controller.IP(), controller.port ) +
' --fail=closed ' + self.opts +
' 1> ' + ofplog + ' 2>' + ofplog + ' &' )
self.execed = False
def stop( self ):
"Terminate kernel datapath."
quietRun( 'dpctl deldp nl:%i' % self.dp )
quietRun( 'dpctl deldp ' + self.dp )
self.cmd( 'kill %ofprotocol' )
self.deleteIntfs()
......@@ -508,7 +521,8 @@ def __init__( self, name, dp=None, **kwargs ):
dp: netlink id (0, 1, 2, ...)
defaultMAC: default MAC as unsigned int; random value if None"""
Switch.__init__( self, name, **kwargs )
self.dp = dp
self.dp = 'dp%i' % dp
self.intf = self.dp
if self.inNamespace:
error( "OVSKernelSwitch currently only works"
" in the root namespace." )
......@@ -525,29 +539,27 @@ def start( self, controllers ):
quietRun( 'ifconfig lo up' )
# Delete local datapath if it exists;
# then create a new one monitoring the given interfaces
quietRun( 'ovs-dpctl del-dp dp%i' % self.dp )
self.cmd( 'ovs-dpctl add-dp dp%i' % self.dp )
quietRun( 'ovs-dpctl del-dp ' + self.dp )
self.cmd( 'ovs-dpctl add-dp ' + self.dp )
if self.defaultMAC:
intf = 'dp%i' % self.dp
mac = self.defaultMAC
self.cmd( [ 'ifconfig', intf, 'hw', 'ether', mac ] )
self.cmd( 'ifconfig', self.intf, 'hw', 'ether', mac )
if len( self.intfs ) != max( self.intfs ) + 1:
raise Exception( 'only contiguous, zero-indexed port ranges'
'supported: %s' % self.intfs )
intfs = [ self.intfs[ port ] for port in sorted( self.intfs.keys() ) ]
self.cmd( 'ovs-dpctl add-if dp' + str( self.dp ) + ' ' +
' '.join( intfs ) )
self.cmd( 'ovs-dpctl', 'add-if', self.dp, ' '.join( intfs ) )
# Run protocol daemon
controller = controllers[ 0 ]
self.cmd( 'ovs-openflowd dp' + str( self.dp ) + ' tcp:' +
controller.IP() + ':' +
' --fail=closed 1> ' + ofplog + ' 2>' + ofplog + ' &' )
self.cmd( 'ovs-openflowd ' + self.dp +
' tcp:%s:%i' % ( controller.IP(), controller.port ) +
' --fail=closed ' + self.opts +
' 1>' + ofplog + ' 2>' + ofplog + '&' )
self.execed = False
def stop( self ):
"Terminate kernel datapath."
quietRun( 'ovs-dpctl del-dp dp%i' % self.dp )
quietRun( 'ovs-dpctl del-dp ' + self.dp )
self.cmd( 'kill %ovs-openflowd' )
self.deleteIntfs()
......@@ -573,7 +585,7 @@ def start( self ):
if self.cdir is not None:
self.cmd( 'cd ' + self.cdir )
self.cmd( self.controller + ' ' + self.cargs +
' 1> ' + cout + ' 2> ' + cout + ' &' )
' 1>' + cout + ' 2>' + cout + '&' )
self.execed = False
def stop( self ):
......@@ -619,7 +631,7 @@ def __init__( self, name, noxArgs=None, **kwargs ):
controller=noxCoreDir + '/nox_core',
cargs='--libdir=/usr/local/lib -v -i ptcp: ' +
' '.join( noxArgs ),
cdir = noxCoreDir, **kwargs )
cdir=noxCoreDir, **kwargs )
class RemoteController( Controller ):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment