Changed to use class vars and method to track nodes.
Useful for monitoring the output of a set of nodes.
This commit is contained in:
+20
-25
@@ -105,6 +105,8 @@ def quietRun( cmd ):
|
|||||||
class Node( object ):
|
class Node( object ):
|
||||||
"""A virtual network node is simply a shell in a network namespace.
|
"""A virtual network node is simply a shell in a network namespace.
|
||||||
We communicate with it using pipes."""
|
We communicate with it using pipes."""
|
||||||
|
inToNode = {}
|
||||||
|
outToNode = {}
|
||||||
def __init__( self, name, inNamespace=True ):
|
def __init__( self, name, inNamespace=True ):
|
||||||
self.name = name
|
self.name = name
|
||||||
closeFds = False # speed vs. memory use
|
closeFds = False # speed vs. memory use
|
||||||
@@ -118,8 +120,11 @@ class Node( object ):
|
|||||||
self.stdout = self.shell.stdout
|
self.stdout = self.shell.stdout
|
||||||
self.pollOut = select.poll()
|
self.pollOut = select.poll()
|
||||||
self.pollOut.register( self.stdout )
|
self.pollOut.register( self.stdout )
|
||||||
outToNode[ self.stdout ] = self
|
# Maintain mapping between file descriptors and nodes
|
||||||
inToNode[ self.stdin ] = self
|
# This could be useful for monitoring multiple nodes
|
||||||
|
# using select.poll()
|
||||||
|
self.outToNode[ self.stdout.fileno() ] = self
|
||||||
|
self.inToNode[ self.stdin.fileno() ] = self
|
||||||
self.pid = self.shell.pid
|
self.pid = self.shell.pid
|
||||||
self.intfCount = 0
|
self.intfCount = 0
|
||||||
self.intfs = []
|
self.intfs = []
|
||||||
@@ -127,6 +132,9 @@ class Node( object ):
|
|||||||
self.connection = {}
|
self.connection = {}
|
||||||
self.waiting = False
|
self.waiting = False
|
||||||
self.execed = False
|
self.execed = False
|
||||||
|
def fdToNode( self, f ):
|
||||||
|
node = self.outToNode.get( f )
|
||||||
|
return node or self.inToNode.get( f )
|
||||||
def cleanup( self ):
|
def cleanup( self ):
|
||||||
# Help python collect its garbage
|
# Help python collect its garbage
|
||||||
self.shell = None
|
self.shell = None
|
||||||
@@ -134,8 +142,8 @@ class Node( object ):
|
|||||||
def read( self, max ): return os.read( self.stdout.fileno(), max )
|
def read( self, max ): return os.read( self.stdout.fileno(), max )
|
||||||
def write( self, data ): os.write( self.stdin.fileno(), data )
|
def write( self, data ): os.write( self.stdin.fileno(), data )
|
||||||
def terminate( self ):
|
def terminate( self ):
|
||||||
self.cleanup()
|
|
||||||
os.kill( self.pid, signal.SIGKILL )
|
os.kill( self.pid, signal.SIGKILL )
|
||||||
|
self.cleanup()
|
||||||
def stop( self ): self.terminate()
|
def stop( self ): self.terminate()
|
||||||
def waitReadable( self ): self.pollOut.poll()
|
def waitReadable( self ): self.pollOut.poll()
|
||||||
def sendCmd( self, cmd ):
|
def sendCmd( self, cmd ):
|
||||||
@@ -211,29 +219,19 @@ class Node( object ):
|
|||||||
return self.cmd( 'route add default ' + intf )
|
return self.cmd( 'route add default ' + intf )
|
||||||
def IP( self ):
|
def IP( self ):
|
||||||
"Return IP address of first interface"
|
"Return IP address of first interface"
|
||||||
return self.ips[ self.intfs[ 0 ] ]
|
if len( self.intfs ) > 0:
|
||||||
|
return self.ips.get( self.intfs[ 0 ], None )
|
||||||
def intfIsUp( self, intf ):
|
def intfIsUp( self, intf ):
|
||||||
"Check if one of our interfaces is up."
|
"Check if one of our interfaces is up."
|
||||||
return 'UP' in self.cmd( 'ifconfig ' + self.intfs[ 0 ] )
|
return 'UP' in self.cmd( 'ifconfig ' + self.intfs[ 0 ] )
|
||||||
# Other methods
|
# Other methods
|
||||||
def __str__( self ):
|
def __str__( self ):
|
||||||
result = self.name
|
result = self.name
|
||||||
result += ": IP=" + self.IP() + " intfs=" + self.intfs
|
result += ": IP=" + self.IP() + " intfs=" + ','.join( self.intfs )
|
||||||
result += " waiting=", self.waiting
|
result += " waiting=" + `self.waiting`
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Maintain mapping between i/o pipes and nodes
|
|
||||||
# This could be useful for monitoring multiple nodes
|
|
||||||
# using select.poll()
|
|
||||||
|
|
||||||
inToNode = {}
|
|
||||||
outToNode = {}
|
|
||||||
def outputs(): return outToNode.keys()
|
|
||||||
def nodes(): return outToNode.values()
|
|
||||||
def inputs(): return [ node.stdin for node in nodes() ]
|
|
||||||
def nodeFromFile( f ):
|
|
||||||
node = outToNode.get( f )
|
|
||||||
return node or inToNode.get( f )
|
|
||||||
|
|
||||||
class Host( Node ):
|
class Host( Node ):
|
||||||
"""A host is simply a Node."""
|
"""A host is simply a Node."""
|
||||||
@@ -303,18 +301,16 @@ class Switch( Node ):
|
|||||||
# However, this takes time, so we're better off to remove them
|
# However, this takes time, so we're better off to remove them
|
||||||
# explicitly so that we won't get errors if we run before they
|
# explicitly so that we won't get errors if we run before they
|
||||||
# have been removed by the kernel. Unfortunately this is very slow.
|
# have been removed by the kernel. Unfortunately this is very slow.
|
||||||
|
self.cmd( 'kill %ofprotocol')
|
||||||
for intf in self.intfs:
|
for intf in self.intfs:
|
||||||
quietRun( 'ip link del ' + intf )
|
quietRun( 'ip link del ' + intf )
|
||||||
sys.stdout.write( '.' ) ; flush()
|
sys.stdout.write( '.' ) ; flush()
|
||||||
self.cmd( 'kill %ofprotocol')
|
|
||||||
def start( self, controller ):
|
def start( self, controller ):
|
||||||
if self.dp is None: self.startUserDatapath( controller )
|
if self.dp is None: self.startUserDatapath( controller )
|
||||||
else: self.startKernelDatapath( controller )
|
else: self.startKernelDatapath( controller )
|
||||||
def stop( self ):
|
def stop( self ):
|
||||||
if self.dp is None: self.stopUserDatapath()
|
if self.dp is None: self.stopUserDatapath()
|
||||||
else: self.stopKernelDatapath()
|
else: self.stopKernelDatapath()
|
||||||
# Handle non-interaction if we've execed
|
|
||||||
self.terminate()
|
|
||||||
def sendCmd( self, cmd ):
|
def sendCmd( self, cmd ):
|
||||||
if not self.execed: return Node.sendCmd( self, cmd )
|
if not self.execed: return Node.sendCmd( self, cmd )
|
||||||
else: print "*** Error:", self.name, "has execed and cannot accept commands"
|
else: print "*** Error:", self.name, "has execed and cannot accept commands"
|
||||||
@@ -455,9 +451,9 @@ def configureRoutedControlNetwork( controller, switches, ips):
|
|||||||
while not switch.intfIsUp( switch.intfs[ 0 ] ):
|
while not switch.intfIsUp( switch.intfs[ 0 ] ):
|
||||||
print "*** Waiting for ", switch.intfs[ 0 ], "to come up"
|
print "*** Waiting for ", switch.intfs[ 0 ], "to come up"
|
||||||
sleep( 1 )
|
sleep( 1 )
|
||||||
if pingTest( hosts=[ switch, controller ] ) != 0:
|
if pingTest( hosts=[ switch, controller ] ) != 0:
|
||||||
print "*** Error: control network test failed"
|
print "*** Error: control network test failed"
|
||||||
exit( 1 )
|
exit( 1 )
|
||||||
|
|
||||||
def configHosts( hosts, ips ):
|
def configHosts( hosts, ips ):
|
||||||
"Configure a set of hosts, starting at IP address a.b.c.d"
|
"Configure a set of hosts, starting at IP address a.b.c.d"
|
||||||
@@ -535,7 +531,7 @@ class Network( object ):
|
|||||||
print "*** Stopping switches"
|
print "*** Stopping switches"
|
||||||
for switch in self.switches:
|
for switch in self.switches:
|
||||||
print switch.name, ; flush()
|
print switch.name, ; flush()
|
||||||
switch.stop() ; switch.terminate()
|
switch.stop()
|
||||||
print
|
print
|
||||||
print "*** Stopping controller"
|
print "*** Stopping controller"
|
||||||
for controller in self.controllers:
|
for controller in self.controllers:
|
||||||
@@ -716,7 +712,6 @@ def iperf( hosts, verbose=False ):
|
|||||||
"Run iperf between two hosts."
|
"Run iperf between two hosts."
|
||||||
assert len( hosts ) == 2
|
assert len( hosts ) == 2
|
||||||
host1, host2 = hosts[ 0 ], hosts[ 1 ]
|
host1, host2 = hosts[ 0 ], hosts[ 1 ]
|
||||||
# dumpNodes( [ host1, host2 ] )
|
|
||||||
host1.cmd( 'killall -9 iperf') # XXX shouldn't be global killall
|
host1.cmd( 'killall -9 iperf') # XXX shouldn't be global killall
|
||||||
server = host1.cmd( 'iperf -s &' )
|
server = host1.cmd( 'iperf -s &' )
|
||||||
if verbose: print server ; flush()
|
if verbose: print server ; flush()
|
||||||
|
|||||||
Reference in New Issue
Block a user