diff --git a/examples/consoles.py b/examples/consoles.py index 3b071eb..393ea84 100755 --- a/examples/consoles.py +++ b/examples/consoles.py @@ -26,9 +26,10 @@ Bob Lantz, April 2010 """ import re -from Tkinter import * -from mininet.log import setLogLevel,info +from Tkinter import Frame, Button, Label, Text, Scrollbar, Canvas, Wm, READABLE + +from mininet.log import setLogLevel from mininet.topolib import TreeNet from mininet.term import makeTerms, cleanUpScreens from mininet.util import quietRun @@ -233,11 +234,11 @@ class Graph( Frame ): scale.configure( yscrollcommand=ybar.set ) # Layout - title.grid( row=0, columnspan=3, sticky=N+E+W) - scale.grid( row=1, column=0, sticky=N+S+E+W ) - graph.grid( row=1, column=1, sticky=N+S+E+W ) - ybar.grid( row=1, column=2, sticky=N+S ) - xbar.grid( row=2, column=0, columnspan=2, sticky=E+W ) + title.grid( row=0, columnspan=3, sticky='new') + scale.grid( row=1, column=0, sticky='nsew' ) + graph.grid( row=1, column=1, sticky='nsew' ) + ybar.grid( row=1, column=2, sticky='ns' ) + xbar.grid( row=2, column=0, columnspan=2, sticky='ew' ) self.rowconfigure( 1, weight=1 ) self.columnconfigure( 1, weight=1 ) # Save for future reference @@ -249,7 +250,6 @@ class Graph( Frame ): def addBar( self, yval ): "Add a new bar to our graph." percent = yval / self.ymax - height = percent * self.gheight c = self.graph x0 = self.xpos * self.barwidth x1 = x0 + self.barwidth @@ -453,7 +453,7 @@ class Object( object ): if __name__ == '__main__': setLogLevel( 'info' ) - net = TreeNet( depth=2, fanout=4 ) + net = TreeNet( depth=2, fanout=2 ) net.start() app = ConsoleApp( net, width=4 ) app.mainloop() diff --git a/examples/emptynet.py b/examples/emptynet.py index f006a0f..4aa4f3d 100755 --- a/examples/emptynet.py +++ b/examples/emptynet.py @@ -17,7 +17,7 @@ def emptyNet(): net = Mininet( controller=Controller ) info( '*** Adding controller\n' ) - c0 = net.addController( 'c0' ) + net.addController( 'c0' ) info( '*** Adding hosts\n' ) h1 = net.addHost( 'h1', ip='10.0.0.1' ) diff --git a/examples/miniedit.py b/examples/miniedit.py index 3d215f5..41f7f63 100755 --- a/examples/miniedit.py +++ b/examples/miniedit.py @@ -11,17 +11,14 @@ Development version - not entirely functional! Bob Lantz, April 2010 """ -from Tkinter import * +from Tkinter import Frame, Button, Label, Scrollbar, Canvas +from Tkinter import Menu, BitmapImage, PhotoImage, Wm, Toplevel # someday: from ttk import * from mininet.log import setLogLevel -from mininet.net import init, Mininet -from mininet.node import KernelSwitch, UserSwitch, OVSKernelSwitch -from mininet.node import Controller, NOX -from mininet.topo import Topo -from mininet.topolib import TreeTopo -from mininet.util import quietRun, ipStr +from mininet.net import Mininet +from mininet.util import ipStr from mininet.term import makeTerm, cleanUpScreens class MiniEdit( Frame ): @@ -189,15 +186,6 @@ class MiniEdit( Frame ): c = self.canvas return c.canvasy( y_root ) - c.winfo_rooty() - def widgetCenter( self, widget ): - "Return center of widget on our canvas." - c = self.canvas - x = self.canvasx( widget.winfo_rootx() ) - y = self.canvasy( widget.winfo_rooty() ) - w = widget.winfo_width() - h = widget.winfo_height() - return x + w / 2, y + h / 2 - # Toolbar def activate( self, toolName ): @@ -347,6 +335,7 @@ class MiniEdit( Frame ): "Drag a link's endpoint to another node." if self.link is None: return + # Since drag starts in widget, we use root coords x = self.canvasx( event.x_root ) y = self.canvasy( event.y_root ) c = self.canvas @@ -426,12 +415,12 @@ class MiniEdit( Frame ): item = self.widgetToItem[ w ] c.coords( item, x, y ) # Adjust link positions - x0, y0 = self.widgetCenter( w ) for dest in w.links: link = w.links[ dest ] - x1, y1 = self.widgetCenter( dest ) - c.coords( link, x0, y0, x1, y1 ) - + item = self.widgetToItem[ dest ] + x1, y1 = c.coords( item ) + c.coords( link, x, y, x1, y1 ) + def startLink( self, event ): "Start a new link." if event.widget not in self.widgetToItem: @@ -439,7 +428,7 @@ class MiniEdit( Frame ): return w = event.widget item = self.widgetToItem[ w ] - x, y = self.widgetCenter( w ) + x, y = self.canvas.coords( item ) self.link = self.canvas.create_line( x, y, x, y, width=4, fill='blue', tag='link' ) self.linkx, self.linky = x, y @@ -464,6 +453,8 @@ class MiniEdit( Frame ): if self.link is None: return source = self.linkWidget + c = self.canvas + # Since we dragged from the widget, use root coords x, y = self.canvasx( event.x_root ), self.canvasy( event.y_root ) target = self.findItem( x, y ) dest = self.itemToWidget.get( target, None ) @@ -477,8 +468,7 @@ class MiniEdit( Frame ): if 'Host' in stags and 'Host' in dtags: self.releaseLink( event ) return - x, y = self.widgetCenter( dest ) - c = self.canvas + x, y = c.coords( target ) c.coords( self.link, self.linkx, self.linky, x, y ) self.addLink( source, dest ) @@ -562,7 +552,7 @@ class MiniEdit( Frame ): elif 'Host' in tags: net.addHost( name, ip=ipStr( nodeNum ) ) else: - exception( "Cannot create mystery node: " + name ) + raise Exception( "Cannot create mystery node: " + name ) # Make links for link in self.links.values(): ( src, dst ) = link diff --git a/examples/multitest.py b/examples/multitest.py index 5bc1202..a17da23 100755 --- a/examples/multitest.py +++ b/examples/multitest.py @@ -7,7 +7,7 @@ For a more complicated test example, see udpbwtest.py. from mininet.cli import CLI from mininet.log import lg, info -from mininet.net import init, Mininet +from mininet.net import Mininet from mininet.node import KernelSwitch from mininet.topolib import TreeTopo diff --git a/examples/sshd.py b/examples/sshd.py index 64765d7..16db692 100755 --- a/examples/sshd.py +++ b/examples/sshd.py @@ -16,7 +16,7 @@ demonstrates: - running server processes (sshd in this case) on hosts """ -from mininet.net import init, Mininet +from mininet.net import Mininet from mininet.cli import CLI from mininet.log import lg from mininet.node import Node, KernelSwitch diff --git a/examples/treeping64.py b/examples/treeping64.py index 6449bef..0f502e6 100755 --- a/examples/treeping64.py +++ b/examples/treeping64.py @@ -3,7 +3,6 @@ "Create a 64-node tree network, and test connectivity using ping." from mininet.log import setLogLevel -from mininet.net import init, Mininet from mininet.node import KernelSwitch, UserSwitch, OVSKernelSwitch from mininet.topolib import TreeNet diff --git a/examples/udpbwgraph.py b/examples/udpbwgraph.py index 9dad5be..db6a1e5 100755 --- a/examples/udpbwgraph.py +++ b/examples/udpbwgraph.py @@ -7,17 +7,13 @@ Bob Lantz 3/27/10 """ -from time import sleep - -import os import re -import sys -from time import time -from Tkinter import * +from Tkinter import Frame, Label, Button, Scrollbar, OptionMenu, Canvas +from Tkinter import StringVar from mininet.log import setLogLevel -from mininet.net import init, Mininet +from mininet.net import Mininet from mininet.node import KernelSwitch, UserSwitch, OVSKernelSwitch from mininet.node import Controller, NOX from mininet.topolib import TreeTopo @@ -61,7 +57,7 @@ class Graph( Frame ): scale.create_line( width - 1, height, width - 1, 0, fill=fill ) # Draw ticks and numbers for y in range( 0, int( ymax + 1 ) ): - ypos = height * (1 - float( y ) / ymax ) + ypos = height * ( 1 - float( y ) / ymax ) scale.create_line( width, ypos, width - 10, ypos, fill=fill ) scale.create_text( 10, ypos, text=str( y ), fill=fill ) @@ -76,9 +72,9 @@ class Graph( Frame ): self.scale.configure( scrollregion=( 0, -ofs, 0, height ) ) def yview( self, *args ): - "Scroll both scale and graph." - self.graph.yview( *args ) - self.scale.yview( *args ) + "Scroll both scale and graph." + self.graph.yview( *args ) + self.scale.yview( *args ) def createWidgets( self ): "Create initial widget set." @@ -96,11 +92,11 @@ class Graph( Frame ): scale.configure( yscrollcommand=ybar.set ) # Layout - title.grid( row=0, columnspan=3, sticky=N+E+W) - scale.grid( row=1, column=0, sticky=N+S+E+W ) - graph.grid( row=1, column=1, sticky=N+S+E+W ) - ybar.grid( row=1, column=2, sticky=N+S ) - xbar.grid( row=2, column=0, columnspan=2, sticky=E+W ) + title.grid( row=0, columnspan=3, sticky='new') + scale.grid( row=1, column=0, sticky='nsew' ) + graph.grid( row=1, column=1, sticky='nsew' ) + ybar.grid( row=1, column=2, sticky='ns' ) + xbar.grid( row=2, column=0, columnspan=2, sticky='ew' ) self.rowconfigure( 1, weight=1 ) self.columnconfigure( 1, weight=1 ) @@ -113,7 +109,6 @@ class Graph( Frame ): def addBar( self, yval ): "Add a new bar to our graph." percent = yval / self.ymax - height = percent * self.gheight c = self.graph x0 = self.xpos * self.barwidth x1 = x0 + self.barwidth @@ -151,26 +146,42 @@ class Controls( Frame ): 'NOX': NOX } - - def __init__( self, master=None ): + def optionMenu( self, name, dict, initval, opts ): + "Add a new option menu." + var = StringVar() + var.set( findKey( dict, initval ) ) + menu = OptionMenu( self, var, *dict ) + menu.config( **opts ) + menu.pack( fill='x' ) + def value(): + return dict[ var.get() ] + return value + + def __init__( self, master, start, stop, quit ): Frame.__init__( self, master ) - self.switch = StringVar() - self.switch.set( 'Kernel Switch' ) - self.switchMenu = OptionMenu( self, self.switch, - *( switches.keys() ) ) + # Option menus + opts = { 'font': 'Geneva 7 bold' } + self.switch = self.optionMenu( 'Switch', self.switches, + KernelSwitch, opts ) + self.controller = self.optionMenu( 'Controller', self.controllers, + Controller, opts) + + # Spacer + pk = { 'fill': 'x' } + Label( self, **opts ).pack( **pk ) + + # Buttons + self.start = Button( self, text='Start', command=start, **opts ) + self.stop = Button( self, text='Stop', command=stop, **opts ) + self.quit = Button( self, text='Quit', command=quit, **opts ) + for button in ( self.start, self.stop, self.quit ): + button.pack( **pk ) + - self.controller = StringVar() - self.controller.set( 'Reference Controller' ) - self.controllerMenu = OpetionMenu( self, self.controller, - *( controllers.keys() ) ) - -def App( Frame ): - - def parsebwtest( line, - r=re.compile( r'(\d+) s: in ([\d\.]+) Mbps, out ([\d\.]+) Mbps' ) ): + r=re.compile( r'(\d+) s: in ([\d\.]+) MB/s, out ([\d\.]+) MB/s' ) ): "Parse udpbwtest.c output, returning seconds, inbw, outbw." match = r.match( line ) if match: @@ -179,25 +190,50 @@ def parsebwtest( line, return None, None, None -class UdpBwTest( object ): +class UdpBwTest( Frame ): "Test and plot UDP bandwidth over time" - def __init__( self, graph, net, seconds=60 ): + def __init__( self, topo, seconds=60, master=None ): "Start up and monitor udpbwtest on each of our hosts." - hosts = net.hosts - self.graph = graph - self.hostCount = len( hosts ) + Frame.__init__( self, master ) + + self.controls = Controls( self, self.start, self.stop, self.quit ) + self.graph = Graph( self ) + # Layout + self.controls.pack( side='left', expand=False, fill='y' ) + self.graph.pack( side='right', expand=True, fill='both' ) + self.pack( expand=True, fill='both' ) + + self.running = False + + def start( self ): + print "start" + + if self.running: + return + + switch = self.controls.switch() + controller = self.controls.controller() + + self.net = Mininet( topo, switch=switch, controller=controller ) + self.hosts = self.net.hosts + self.hostCount = len( self.hosts ) + + print "*** Starting network" + self.net.start() + print "*** Starting udpbwtest on hosts" + hosts = self.hosts for host in hosts: ips = [ h.IP() for h in hosts if h != host ] host.cmdPrint( './udpbwtest ' + ' '.join( ips ) + ' &' ) print "*** Monitoring hosts" - self.output = net.monitor( hosts, timeoutms=0 ) + self.output = self.net.monitor( hosts, timeoutms=1 ) self.results = {} - self.quitTime = time() + seconds + self.running = True self.updateGraph() # Pylint isn't smart enough to understand iterator.next() @@ -205,6 +241,12 @@ class UdpBwTest( object ): def updateGraph( self ): "Graph input bandwidth." + + print "updateGraph" + + if not self.running: + return + while True: host, line = self.output.next() if host is None or len( line ) == 0: @@ -220,35 +262,51 @@ class UdpBwTest( object ): totalin = 0 for host, inbw, outbw in result: totalin += inbw - self.graph.addBar( totalin / 1000.0 ) + self.graph.addBar( totalin * 8.0/1000.0 ) print totalin - if time() < self.quitTime: - # Fileevent would be better, but for now we just poll every 500ms - self.graph.after( 10, self.updateGraph ) - else: - self.shutdown() + # Fileevent might be better, but for now we just poll every 500ms + self.graph.after( 500, self.updateGraph ) - def shutdown( self ): - "Stop udpbwtest proceses." + def stop( self ): + "Stop test." + print "*** Stopping udpbwtest processes" # We *really* don't want these things hanging around! quietRun( 'killall -9 udpbwtest' ) + + if not self.running: + return + + print "*** Stopping network" + self.running = False + self.net.stop() + + def quit( self ): + print "*** Quitting" + self.stop() + Frame.quit( self ) # pylint: enable-msg=E1101 +# Useful utilities + +def findKey( dict, value ): + "Find some key where dict[ key ] == value." + return [ key for key, val in dict.items() if val == value ][ 0 ] + +def assign( obj, **kwargs): + "Set a bunch of fields in an object." + for name, value in kwargs.items(): + setattr( obj, name, value ) + +class Object( object ): + "Generic object you can stuff junk into." + def __init__( self, **kwargs ): + assign( self, **kwargs ) + if __name__ == '__main__': setLogLevel( 'info' ) - app = Graph() - app.master.title( "Mininet Bandwidth" ) - depth, fanout = 1, 2 - net = Mininet( topo=TreeTopo( depth=depth, fanout=fanout), - switch=KernelSwitch ) - title = "Bandwidth (Mb/s), (%i hosts, %i switches, depth=%d, fanout=%d)" % ( - len( net.hosts ), len( net.switches), depth, fanout ) - app.setTitle( title ) - net.start() - test = UdpBwTest( app, net ) + topo = TreeTopo( depth=1, fanout=2 ) + app = UdpBwTest( topo ) app.mainloop() - net.stop() - test.shutdown() # just in case! \ No newline at end of file diff --git a/examples/udpbwtest.py b/examples/udpbwtest.py index 80bf601..bbeaf68 100755 --- a/examples/udpbwtest.py +++ b/examples/udpbwtest.py @@ -24,7 +24,7 @@ from time import time flush = sys.stdout.flush from mininet.log import lg -from mininet.net import init, Mininet +from mininet.net import Mininet from mininet.node import KernelSwitch from mininet.topolib import TreeTopo from mininet.util import quietRun @@ -32,7 +32,7 @@ from mininet.util import quietRun # bwtest support def parsebwtest( line, - r=re.compile( r'(\d+) s: in ([\d\.]+) Mbps, out ([\d\.]+) Mbps' ) ): + r=re.compile( r'(\d+) s: in ([\d\.]+) MB/s, out ([\d\.]+) MB/s' ) ): "Parse udpbwtest.c output, returning seconds, inbw, outbw." match = r.match( line ) if match: @@ -43,7 +43,7 @@ def parsebwtest( line, def printTotalHeader(): "Print header for bandwidth stats." print - print "time(s)\thosts\ttotal in/out (Mbps)\tavg in/out (Mbps)" + print "time(s)\thosts\ttotal in/out (MB/s)\tavg in/out (MB/s)" # Annoyingly, pylint isn't smart enough to notice # when an unused variable is an iteration tuple @@ -108,7 +108,7 @@ if __name__ == '__main__': lg.setLogLevel( 'info' ) if not os.path.exists( './udpbwtest' ): raise Exception( 'Could not find udpbwtest in current directory.' ) - network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=KernelSwitch ) + network = Mininet( TreeTopo( depth=1, fanout=8 ), switch=KernelSwitch ) network.start() udpbwtest( network, seconds=10 ) network.stop() diff --git a/mininet/cli.py b/mininet/cli.py index 6ab6e70..090419d 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -28,9 +28,8 @@ and bandwidth ('iperf'.) from subprocess import call from cmd import Cmd from os import isatty -from select import poll, select, POLLIN +from select import poll, POLLIN from sys import stdin -from tty import setcbreak from mininet.log import info, output, error from mininet.term import makeTerms diff --git a/mininet/net.py b/mininet/net.py index a6a7808..f9183cf 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -397,10 +397,12 @@ class Mininet( object ): self.stop() return result - def monitor( self, hosts=None ): + def monitor( self, hosts=None, timeoutms=-1 ): """Monitor a set of hosts (or all hosts by default), and return their output, a line at a time. - returns: host, line""" + hosts: (optional) set of hosts to monitor + timeoutms: (optional) timeout value in ms + returns: iterator which returns host, line""" if hosts is None: hosts = self.hosts poller = select.poll() @@ -408,13 +410,16 @@ class Mininet( object ): for host in hosts: poller.register( host.stdout ) while True: - ready = poller.poll() + ready = poller.poll( timeoutms ) for fd, event in ready: host = Node.fdToNode( fd ) if event & select.POLLIN: line = host.readline() - if line: + if line is not None: yield host, line + # Return if non-blocking + if not ready and timeoutms >= 0: + yield None, None @staticmethod def _parsePing( pingOutput ):