From 121eb4496b71e7e3574c8c67257ea327b530017f Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 22 Apr 2010 17:06:34 -0700 Subject: [PATCH] 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. --- mininet/node.py | 118 ++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 77696a5..6a3673b 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -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 @@ class Node( object ): 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 @@ class Node( object ): # 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 @@ class Node( object ): 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 @@ class Node( object ): 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 @@ class Node( object ): 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 @@ class Node( object ): 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 @@ class Node( object ): 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 @@ class Node( object ): 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 @@ class UserSwitch( Switch ): 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 @@ class UserSwitch( Switch ): 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 @@ class KernelSwitch( Switch ): 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 @@ class OVSKernelSwitch( Switch ): 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 @@ class OVSKernelSwitch( Switch ): 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 @@ class Controller( Node ): 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 @@ class NOX( Controller ): controller=noxCoreDir + '/nox_core', cargs='--libdir=/usr/local/lib -v -i ptcp: ' + ' '.join( noxArgs ), - cdir = noxCoreDir, **kwargs ) + cdir=noxCoreDir, **kwargs ) class RemoteController( Controller ):