Pass pylint.

This commit is contained in:
Bob Lantz
2010-05-06 16:24:15 -07:00
parent 259d713315
commit 82b7207295
11 changed files with 465 additions and 400 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ EXAMPLES = examples/*.py
BIN = bin/mn BIN = bin/mn
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN) PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
P8IGN = E251,E201,E302 P8IGN = E251,E201,E302,E202
codecheck: $(PYSRC) codecheck: $(PYSRC)
pyflakes $(PYSRC) pyflakes $(PYSRC)
+34 -29
View File
@@ -128,23 +128,28 @@ class Console( Frame ):
cmd = cmd[ pos + len( self.prompt ): ] cmd = cmd[ pos + len( self.prompt ): ]
self.sendCmd( cmd ) self.sendCmd( cmd )
# Callback ignores event
# pylint: disable-msg=W0613
def handleInt( self, event=None ): def handleInt( self, event=None ):
"Handle control-c." "Handle control-c."
self.node.sendInt() self.node.sendInt()
# pylint: enable-msg=W0613
def sendCmd( self, cmd ): def sendCmd( self, cmd ):
"Send a command to our node." "Send a command to our node."
text, node = self.text, self.node if not self.node.waiting:
if not node.waiting: self.node.sendCmd( cmd )
node.sendCmd( cmd )
def handleReadable( self, file=None, mask=None, timeoutms=None ): # Callback ignores fds
# pylint: disable-msg=W0613
def handleReadable( self, fds, timeoutms=None ):
"Handle file readable event." "Handle file readable event."
data = self.node.monitor( timeoutms ) data = self.node.monitor( timeoutms )
self.append( data ) self.append( data )
if not self.node.waiting: if not self.node.waiting:
# Print prompt # Print prompt
self.append( self.prompt ) self.append( self.prompt )
# pylint: enable-msg=W0613
def waiting( self ): def waiting( self ):
"Are we waiting for output?" "Are we waiting for output?"
@@ -182,27 +187,25 @@ class Graph( Frame ):
self.xpos = 0 self.xpos = 0
# Create everything # Create everything
self.title = self.graph = None self.title, self.scale, self.graph = self.createWidgets()
self.createWidgets()
self.updateScrollRegions() self.updateScrollRegions()
self.yview( 'moveto', '1.0' ) self.yview( 'moveto', '1.0' )
def createScale( self ):
def scale( self ):
"Create a and return a new canvas with scale markers." "Create a and return a new canvas with scale markers."
height = float( self.gheight ) height = float( self.gheight )
width = 25 width = 25
ymax = self.ymax ymax = self.ymax
scale = Canvas( self, width=width, height=height, background=self.bg ) scale = Canvas( self, width=width, height=height,
fill = 'red' background=self.bg )
opts = { 'fill': 'red' }
# Draw scale line # Draw scale line
scale.create_line( width - 1, height, width - 1, 0, fill=fill ) scale.create_line( width - 1, height, width - 1, 0, **opts )
# Draw ticks and numbers # Draw ticks and numbers
for y in range( 0, int( ymax + 1 ) ): 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_line( width, ypos, width - 10, ypos, **opts )
scale.create_text( 10, ypos, text=str( y ), fill=fill ) scale.create_text( 10, ypos, text=str( y ), **opts )
return scale return scale
def updateScrollRegions( self ): def updateScrollRegions( self ):
@@ -222,10 +225,10 @@ class Graph( Frame ):
"Create initial widget set." "Create initial widget set."
# Objects # Objects
title = Label( self, text="Bandwidth (Gb/s)", bg=self.bg ) title = Label( self, text='Bandwidth (Gb/s)', bg=self.bg )
width = self.gwidth width = self.gwidth
height = self.gheight height = self.gheight
scale = self.scale() scale = self.createScale()
graph = Canvas( self, width=width, height=height, background=self.bg) graph = Canvas( self, width=width, height=height, background=self.bg)
xbar = Scrollbar( self, orient='horizontal', command=graph.xview ) xbar = Scrollbar( self, orient='horizontal', command=graph.xview )
ybar = Scrollbar( self, orient='vertical', command=self.yview ) ybar = Scrollbar( self, orient='vertical', command=self.yview )
@@ -241,11 +244,7 @@ class Graph( Frame ):
xbar.grid( row=2, column=0, columnspan=2, sticky='ew' ) xbar.grid( row=2, column=0, columnspan=2, sticky='ew' )
self.rowconfigure( 1, weight=1 ) self.rowconfigure( 1, weight=1 )
self.columnconfigure( 1, weight=1 ) self.columnconfigure( 1, weight=1 )
# Save for future reference return title, scale, graph
self.title = title
self.scale = scale
self.graph = graph
return graph
def addBar( self, yval ): def addBar( self, yval ):
"Add a new bar to our graph." "Add a new bar to our graph."
@@ -279,6 +278,8 @@ class Graph( Frame ):
class ConsoleApp( Frame ): class ConsoleApp( Frame ):
"Simple Tk consoles for Mininet."
menuStyle = { 'font': 'Geneva 7 bold' } menuStyle = { 'font': 'Geneva 7 bold' }
def __init__( self, net, parent=None, width=4 ): def __init__( self, net, parent=None, width=4 ):
@@ -317,6 +318,8 @@ class ConsoleApp( Frame ):
self.pack( expand=True, fill='both' ) self.pack( expand=True, fill='both' )
# Update callback doesn't use console arg
# pylint: disable-msg=W0613
def updateGraph( self, console, output ): def updateGraph( self, console, output ):
"Update our graph." "Update our graph."
m = re.search( r'(\d+) Mbits/sec', output ) m = re.search( r'(\d+) Mbits/sec', output )
@@ -328,8 +331,10 @@ class ConsoleApp( Frame ):
self.graph.addBar( self.bw ) self.graph.addBar( self.bw )
self.bw = 0 self.bw = 0
self.updates = 0 self.updates = 0
# pylint: enable-msg=W0613
def setOutputHook( self, fn=None, consoles=None ): def setOutputHook( self, fn=None, consoles=None ):
"Register fn as output hook [on specific consoles.]"
if consoles is None: if consoles is None:
consoles = self.consoles[ 'hosts' ].consoles consoles = self.consoles[ 'hosts' ].consoles
for console in consoles: for console in consoles:
@@ -342,7 +347,7 @@ class ConsoleApp( Frame ):
consoles = [] consoles = []
index = 0 index = 0
for node in nodes: for node in nodes:
console = Console( f, net, node, title=title ) console = Console( f, self.net, node, title=title )
consoles.append( console ) consoles.append( console )
row = index / width row = index / width
column = index % width column = index % width
@@ -352,11 +357,11 @@ class ConsoleApp( Frame ):
f.columnconfigure( column, weight=1 ) f.columnconfigure( column, weight=1 )
return f, consoles return f, consoles
def select( self, set ): def select( self, groupName ):
"Select a set of consoles to display." "Select a group of consoles to display."
if self.selected is not None: if self.selected is not None:
self.selected.frame.pack_forget() self.selected.frame.pack_forget()
self.selected = self.consoles[ set ] self.selected = self.consoles[ groupName ]
self.selected.frame.pack( expand=True, fill='both' ) self.selected.frame.pack( expand=True, fill='both' )
def createMenuBar( self ): def createMenuBar( self ):
@@ -453,8 +458,8 @@ class Object( object ):
if __name__ == '__main__': if __name__ == '__main__':
setLogLevel( 'info' ) setLogLevel( 'info' )
net = TreeNet( depth=2, fanout=2 ) network = TreeNet( depth=2, fanout=4 )
net.start() network.start()
app = ConsoleApp( net, width=4 ) app = ConsoleApp( network, width=4 )
app.mainloop() app.mainloop()
net.stop() network.stop()
+139 -93
View File
@@ -48,10 +48,10 @@ class MiniEdit( Frame ):
self.cframe, self.canvas = self.createCanvas() self.cframe, self.canvas = self.createCanvas()
# Toolbar # Toolbar
self.images = miniEditImages()
self.buttons = {} self.buttons = {}
self.active = None self.active = None
self.tools = ( 'Select', 'Host', 'Switch', 'Link' ) self.tools = ( 'Select', 'Host', 'Switch', 'Link' )
self.images = self.createImages()
self.customColors = { 'Switch': 'darkGreen', 'Host': 'blue' } self.customColors = { 'Switch': 'darkGreen', 'Host': 'blue' }
self.toolbar = self.createToolbar() self.toolbar = self.createToolbar()
@@ -83,6 +83,10 @@ class MiniEdit( Frame ):
self.bind( '<KeyPress-BackSpace>', self.deleteSelection ) self.bind( '<KeyPress-BackSpace>', self.deleteSelection )
self.focus() self.focus()
# Event handling initalization
self.linkx = self.linky = self.linkItem = None
self.lastSelection = None
# Model initialization # Model initialization
self.links = {} self.links = {}
self.nodeCount = 0 self.nodeCount = 0
@@ -112,15 +116,13 @@ class MiniEdit( Frame ):
appMenu.add_separator() appMenu.add_separator()
appMenu.add_command( label='Quit', command=self.quit, font=font ) appMenu.add_command( label='Quit', command=self.quit, font=font )
""" #fileMenu = Menu( mbar, tearoff=False )
fileMenu = Menu( mbar, tearoff=False ) #mbar.add_cascade( label="File", font=font, menu=fileMenu )
mbar.add_cascade( label="File", font=font, menu=fileMenu ) #fileMenu.add_command( label="Load...", font=font )
fileMenu.add_command( label="Load...", font=font ) #fileMenu.add_separator()
fileMenu.add_separator() #fileMenu.add_command( label="Save", font=font )
fileMenu.add_command( label="Save", font=font ) #fileMenu.add_separator()
fileMenu.add_separator() #fileMenu.add_command( label="Print", font=font )
fileMenu.add_command( label="Print", font=font )
"""
editMenu = Menu( mbar, tearoff=False ) editMenu = Menu( mbar, tearoff=False )
mbar.add_cascade( label="Edit", font=font, menu=editMenu ) mbar.add_cascade( label="Edit", font=font, menu=editMenu )
@@ -189,6 +191,7 @@ class MiniEdit( Frame ):
# Toolbar # Toolbar
def activate( self, toolName ): def activate( self, toolName ):
"Activate a tool and press its button."
# Adjust button appearance # Adjust button appearance
if self.active: if self.active:
self.buttons[ self.active ].configure( relief='raised' ) self.buttons[ self.active ].configure( relief='raised' )
@@ -203,7 +206,7 @@ class MiniEdit( Frame ):
# Tools # Tools
for tool in self.tools: for tool in self.tools:
cmd = lambda t=tool: self.activate( t ) cmd = ( lambda t=tool: self.activate( t ) )
b = Button( toolbar, text=tool, font=self.smallFont, command=cmd) b = Button( toolbar, text=tool, font=self.smallFont, command=cmd)
if tool in self.images: if tool in self.images:
b.config( height=35, image=self.images[ tool ] ) b.config( height=35, image=self.images[ tool ] )
@@ -217,9 +220,9 @@ class MiniEdit( Frame ):
# Commands # Commands
for cmd, color in [ ( 'Stop', 'darkRed' ), ( 'Run', 'darkGreen' ) ]: for cmd, color in [ ( 'Stop', 'darkRed' ), ( 'Run', 'darkGreen' ) ]:
def doCmd( f=getattr( self, 'do' + cmd ) ): doCmd = getattr( self, 'do' + cmd )
f() b = Button( toolbar, text=cmd, font=self.smallFont,
b = Button( toolbar, text=cmd, font=self.smallFont, fg=color, command=doCmd ) fg=color, command=doCmd )
b.pack( fill='x', side='bottom' ) b.pack( fill='x', side='bottom' )
return toolbar return toolbar
@@ -267,9 +270,9 @@ class MiniEdit( Frame ):
# Currently the only items we can select directly are # Currently the only items we can select directly are
# links. Nodes are handled by bindings in the node icon. # links. Nodes are handled by bindings in the node icon.
# If we want to allow node deletion, we will
def findItem( self, x, y ): def findItem( self, x, y ):
"Find items at a location in our canvas."
items = self.canvas.find_overlapping( x, y, x, y ) items = self.canvas.find_overlapping( x, y, x, y )
if len( items ) == 0: if len( items ) == 0:
return None return None
@@ -295,10 +298,14 @@ class MiniEdit( Frame ):
# Delete from view # Delete from view
self.canvas.delete( item ) self.canvas.delete( item )
# Callback ignores event
# pylint: disable-msg=W0613
def deleteSelection( self, event ): def deleteSelection( self, event ):
"Delete the selected item."
if self.selection is not None: if self.selection is not None:
self.deleteItem( self.selection ) self.deleteItem( self.selection )
self.selectItem( None ) self.selectItem( None )
# pylint: enable-msg=W0613
def nodeIcon( self, node, name ): def nodeIcon( self, node, name ):
"Create a new node icon." "Create a new node icon."
@@ -317,7 +324,8 @@ class MiniEdit( Frame ):
self.nodeCount += 1 self.nodeCount += 1
name = self.nodePrefixes[ node ] + str( self.nodeCount ) name = self.nodePrefixes[ node ] + str( self.nodeCount )
icon = self.nodeIcon( node, name ) icon = self.nodeIcon( node, name )
item = self.canvas.create_window( x, y, anchor='c', window=icon, tags=node ) item = self.canvas.create_window( x, y, anchor='c',
window=icon, tags=node )
self.widgetToItem[ icon ] = item self.widgetToItem[ icon ] = item
self.itemToWidget[ item ] = icon self.itemToWidget[ item ] = icon
self.selectItem( item ) self.selectItem( item )
@@ -341,40 +349,47 @@ class MiniEdit( Frame ):
c = self.canvas c = self.canvas
c.coords( self.link, self.linkx, self.linky, x, y ) c.coords( self.link, self.linkx, self.linky, x, y )
# Callback ignores event
# pylint: disable-msg=W0613
def releaseLink( self, event ): def releaseLink( self, event ):
"Give up on the current link." "Give up on the current link."
if self.link is not None: if self.link is not None:
self.canvas.delete( self.link ) self.canvas.delete( self.link )
self.linkWidget = self.linkItem = self.link = None self.linkWidget = self.linkItem = self.link = None
# pylint: enable-msg=W0613
# Generic node handlers # Generic node handlers
def createBindings( self, bindings ):
l = Label()
for event, binding in bindings.items():
l.bind( event, binding )
return l
def createNodeBindings( self ): def createNodeBindings( self ):
"Create a set of bindings for nodes." "Create a set of bindings for nodes."
return self.createBindings( { bindings = {
'<ButtonPress-1>': self.clickNode, '<ButtonPress-1>': self.clickNode,
'<B1-Motion>': self.dragNode, '<B1-Motion>': self.dragNode,
'<ButtonRelease-1>': self.releaseNode, '<ButtonRelease-1>': self.releaseNode,
'<Enter>': self.enterNode, '<Enter>': self.enterNode,
'<Leave>': self.leaveNode, '<Leave>': self.leaveNode,
'<Double-ButtonPress-1>': self.xterm '<Double-ButtonPress-1>': self.xterm
} ) }
l = Label() # lightweight-ish owner for bindings
for event, binding in bindings.items():
l.bind( event, binding )
return l
def selectItem( self, item ): def selectItem( self, item ):
"Select an item and remember old selection."
self.lastSelection = self.selection self.lastSelection = self.selection
self.selection = item self.selection = item
def enterNode( self, event ): def enterNode( self, event ):
"Select node on entry."
self.selectNode( event ) self.selectNode( event )
# Callback ignores event
# pylint: disable-msg=W0613
def leaveNode( self, event ): def leaveNode( self, event ):
"Restore old selection on exit."
self.selectItem( self.lastSelection ) self.selectItem( self.lastSelection )
# pylint: enable-msg=W0613
def clickNode( self, event ): def clickNode( self, event ):
"Node click handler." "Node click handler."
@@ -436,14 +451,20 @@ class MiniEdit( Frame ):
self.linkItem = item self.linkItem = item
# Link bindings # Link bindings
# Selection still needs a bit of work overall # Selection still needs a bit of work overall
# Callbacks ignore event
# pylint: disable-msg=W0613
def select( event, link=self.link ): def select( event, link=self.link ):
"Select item on mouse entry."
self.selectItem( link ) self.selectItem( link )
def highlight( event, link=self.link ): def highlight( event, link=self.link ):
"Highlight item on mouse entry."
# self.selectItem( link ) # self.selectItem( link )
self.canvas.itemconfig( link, fill='green' ) self.canvas.itemconfig( link, fill='green' )
def unhighlight( event, link=self.link ): def unhighlight( event, link=self.link ):
"Unhighlight item on mouse exit."
self.canvas.itemconfig( link, fill='blue' ) self.canvas.itemconfig( link, fill='blue' )
# self.selectItem( None ) # self.selectItem( None )
# pylint: disable-msg=W0613
self.canvas.tag_bind( self.link, '<Enter>', highlight ) self.canvas.tag_bind( self.link, '<Enter>', highlight )
self.canvas.tag_bind( self.link, '<Leave>', unhighlight ) self.canvas.tag_bind( self.link, '<Leave>', unhighlight )
self.canvas.tag_bind( self.link, '<ButtonPress-1>', select ) self.canvas.tag_bind( self.link, '<ButtonPress-1>', select )
@@ -471,8 +492,6 @@ class MiniEdit( Frame ):
x, y = c.coords( target ) x, y = c.coords( target )
c.coords( self.link, self.linkx, self.linky, x, y ) c.coords( self.link, self.linkx, self.linky, x, y )
self.addLink( source, dest ) self.addLink( source, dest )
# We're done # We're done
self.link = self.linkWidget = None self.link = self.linkWidget = None
@@ -494,7 +513,7 @@ class MiniEdit( Frame ):
line1.pack( padx=20, pady=10 ) line1.pack( padx=20, pady=10 )
line2.pack(pady=10 ) line2.pack(pady=10 )
line3.pack(pady=10 ) line3.pack(pady=10 )
hide = lambda about=about: about.withdraw() hide = ( lambda about=about: about.withdraw() )
self.aboutBox = about self.aboutBox = about
# Hide on close rather than destroying window # Hide on close rather than destroying window
Wm.wm_protocol( about, name='WM_DELETE_WINDOW', func=hide ) Wm.wm_protocol( about, name='WM_DELETE_WINDOW', func=hide )
@@ -566,17 +585,19 @@ class MiniEdit( Frame ):
return net return net
def start( self ): def start( self ):
"Start network."
if self.net is None: if self.net is None:
self.net = self.build()
self.net.start() self.net.start()
def stop( self ): def stop( self ):
"Stop network."
if self.net is not None: if self.net is not None:
self.net.stop() self.net.stop()
cleanUpScreens() cleanUpScreens()
self.net = None self.net = None
def xterm( self, ignore=None ): def xterm( self, ignore=None ):
"Make an xterm when a button is pressed."
if ( self.selection is None or if ( self.selection is None or
self.net is None or self.net is None or
self.selection not in self.itemToWidget ): self.selection not in self.itemToWidget ):
@@ -584,77 +605,102 @@ class MiniEdit( Frame ):
name = self.itemToWidget[ self.selection ][ 'text' ] name = self.itemToWidget[ self.selection ][ 'text' ]
if name not in self.net.nameToNode: if name not in self.net.nameToNode:
return return
self.net.terms.append( makeTerm( self.net.nameToNode[ name ], 'Host' ) ) term = makeTerm( self.net.nameToNode[ name ], 'Host' )
self.net.terms.append( term )
# Image data. Git will be unhappy.
def createImages( self ): def miniEditImages():
"Initialize button/icon images." "Create and return images for MiniEdit."
images = {}
images[ 'Select' ] = BitmapImage( file='/usr/include/X11/bitmaps/left_ptr' ) # Image data. Git will be unhappy. However, the alternative
# is to keep track of separate binary files, which is also
# unappealing.
images[ 'Host' ] = PhotoImage( data=r""" return {
R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/Mmf/MZv/MM//MAP+Z//+Z 'Select': BitmapImage(
zP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9mZv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8A file='/usr/include/X11/bitmaps/left_ptr' ),
zP8Amf8AZv8AM/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zMAMyZ/8yZ
zMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz/8wzzMwzmcwzZswzM8wzAMwA/8wA
zMwAmcwAZswAM8wAAJn//5n/zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZ
zJmZmZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkzZpkzM5kzAJkA/5kA
zJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZ
zGaZmWaZZmaZM2aZAGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA/2YA
zGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPMzDPMmTPMZjPMMzPMADOZ/zOZ
zDOZmTOZZjOZMzOZADNm/zNmzDNmmTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMA
zDMAmTMAZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDMMwDMAACZ/wCZ
zACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBmAAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAA
zAAAmQAAZgAAM+4AAN0AALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAARAAAIgAAEe7u7t3d3bu7
u6qqqoiIiHd3d1VVVURERCIiIhEREQAAACH5BAEAAAAALAAAAAAgABgAAAiNAAH8G0iwoMGD
CAcKTMiw4UBwBPXVm0ixosWLFvVBHFjPoUeC9Tb+6/jRY0iQ/8iVbHiS40CVKxG2HEkQZsyC
M0mmvGkw50uePUV2tEnOZkyfQA8iTYpTKNOgKJ+C3AhOp9SWVaVOfWj1KdauTL9q5UgVbFKs
EjGqXVtP40NwcBnCjXtw7tx/C8cSBBAQADs=""" )
images[ 'Switch' ] = PhotoImage( data=r""" 'Host': PhotoImage( data=r"""
R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/Mmf/MZv/MM//MAP+Z//+Z R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
zP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9mZv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8A mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
zP8Amf8AZv8AM/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zMAMyZ/8yZ Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
zMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz/8wzzMwzmcwzZswzM8wzAMwA/8wA M/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zM
zMwAmcwAZswAM8wAAJn//5n/zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZ AMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz
zJmZmZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkzZpkzM5kzAJkA/5kA /8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswAM8wAAJn//5n/
zJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZ zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZzJmZ
zGaZmWaZZmaZM2aZAGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA/2YA mZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkz
zGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPMzDPMmTPMZjPMMzPMADOZ/zOZ ZpkzM5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/
zDOZmTOZZjOZMzOZADNm/zNmzDNmmTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMA M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZ
zDMAmTMAZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDMMwDMAACZ/wCZ AGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA
zACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBmAAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAA /2YAzGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPM
zAAAmQAAZgAAM+4AAN0AALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI zDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZMzOZADNm/zNmzDNm
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAARAAAIgAAEe7u7t3d3bu7 mTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMAzDMAmTMA
u6qqqoiIiHd3d1VVVURERCIiIhEREQAAACH5BAEAAAAALAAAAAAgABgAAAhwAAEIHEiwoMGD ZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
CBMqXMiwocOHECNKnEixosWB3zJq3Mixo0eNAL7xG0mypMmTKPl9Cznyn8uWL/m5/AeTpsyY MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBm
I1eKlBnO5r+eLYHy9Ck0J8ubPmPOrMmUpM6UUKMa/Ui16saLWLNq3cq1q9evYB0GBAA7 AAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0A
ALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAA
RAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3d1VVVURERCIiIhEREQAA
ACH5BAEAAAAALAAAAAAgABgAAAiNAAH8G0iwoMGDCAcKTMiw4UBw
BPXVm0ixosWLFvVBHFjPoUeC9Tb+6/jRY0iQ/8iVbHiS40CVKxG2
HEkQZsyCM0mmvGkw50uePUV2tEnOZkyfQA8iTYpTKNOgKJ+C3AhO
p9SWVaVOfWj1KdauTL9q5UgVbFKsEjGqXVtP40NwcBnCjXtw7tx/
C8cSBBAQADs=
""" ),
'Switch': PhotoImage( data=r"""
R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
M/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zM
AMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz
/8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswAM8wAAJn//5n/
zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZzJmZ
mZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkz
ZpkzM5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/
M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZ
AGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA
/2YAzGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPM
zDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZMzOZADNm/zNmzDNm
mTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMAzDMAmTMA
ZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBm
AAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0A
ALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAA
RAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3d1VVVURERCIiIhEREQAA
ACH5BAEAAAAALAAAAAAgABgAAAhwAAEIHEiwoMGDCBMqXMiwocOH
ECNKnEixosWB3zJq3Mixo0eNAL7xG0mypMmTKPl9Cznyn8uWL/m5
/AeTpsyYI1eKlBnO5r+eLYHy9Ck0J8ubPmPOrMmUpM6UUKMa/Ui1
6saLWLNq3cq1q9evYB0GBAA7
""" ),
'Link': PhotoImage( data=r"""
R0lGODlhFgAWAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
M/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zM
AMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz
/8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswAM8wAAJn//5n/
zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZzJmZ
mZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkz
ZpkzM5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/
M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZ
AGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA
/2YAzGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPM
zDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZMzOZADNm/zNmzDNm
mTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMAzDMAmTMA
ZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBm
AAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0A
ALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAA
RAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3d1VVVURERCIiIhEREQAA
ACH5BAEAAAAALAAAAAAWABYAAAhIAAEIHEiwoEGBrhIeXEgwoUKG
Cx0+hGhQoiuKBy1irChxY0GNHgeCDAlgZEiTHlFuVImRJUWXEGEy
lBmxI8mSNknm1Dnx5sCAADs=
""" ) """ )
}
images[ 'Link' ] = PhotoImage( data=r"""
R0lGODlhFgAWAPcAMf//////zP//mf//Zv//M///AP/M///MzP/Mmf/MZv/MM//MAP+Z//+Z
zP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9mZv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8A
zP8Amf8AZv8AM/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zMAMyZ/8yZ
zMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz/8wzzMwzmcwzZswzM8wzAMwA/8wA
zMwAmcwAZswAM8wAAJn//5n/zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZ
zJmZmZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkzZpkzM5kzAJkA/5kA
zJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZ
zGaZmWaZZmaZM2aZAGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA/2YA
zGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPMzDPMmTPMZjPMMzPMADOZ/zOZ
zDOZmTOZZjOZMzOZADNm/zNmzDNmmTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMA
zDMAmTMAZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDMMwDMAACZ/wCZ
zACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBmAAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAA
zAAAmQAAZgAAM+4AAN0AALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAARAAAIgAAEe7u7t3d3bu7
u6qqqoiIiHd3d1VVVURERCIiIhEREQAAACH5BAEAAAAALAAAAAAWABYAAAhIAAEIHEiwoEGB
rhIeXEgwoUKGCx0+hGhQoiuKBy1irChxY0GNHgeCDAlgZEiTHlFuVImRJUWXEGEylBmxI8mS
Nknm1Dnx5sCAADs=
""" )
return images
if __name__ == '__main__': if __name__ == '__main__':
setLogLevel( 'info' ) setLogLevel( 'info' )
+35 -37
View File
@@ -41,12 +41,11 @@ class Graph( Frame ):
self.xpos = 0 self.xpos = 0
# Create everything # Create everything
self.title = self.graph = None self.title, self.graph, self.scale = self.createWidgets()
self.createWidgets()
self.updateScrollRegions() self.updateScrollRegions()
self.yview( 'moveto', '1.0' ) self.yview( 'moveto', '1.0' )
def scale( self ): def createScale( self ):
"Create a and return a new canvas with scale markers." "Create a and return a new canvas with scale markers."
height = float( self.gheight ) height = float( self.gheight )
width = 25 width = 25
@@ -83,7 +82,7 @@ class Graph( Frame ):
title = Label( self, text="Bandwidth (Mb/s)", bg=self.bg ) title = Label( self, text="Bandwidth (Mb/s)", bg=self.bg )
width = self.gwidth width = self.gwidth
height = self.gheight height = self.gheight
scale = self.scale() scale = self.createScale()
graph = Canvas( self, width=width, height=height, background=self.bg) graph = Canvas( self, width=width, height=height, background=self.bg)
xbar = Scrollbar( self, orient='horizontal', command=graph.xview ) xbar = Scrollbar( self, orient='horizontal', command=graph.xview )
ybar = Scrollbar( self, orient='vertical', command=self.yview ) ybar = Scrollbar( self, orient='vertical', command=self.yview )
@@ -99,12 +98,7 @@ class Graph( Frame ):
xbar.grid( row=2, column=0, columnspan=2, sticky='ew' ) xbar.grid( row=2, column=0, columnspan=2, sticky='ew' )
self.rowconfigure( 1, weight=1 ) self.rowconfigure( 1, weight=1 )
self.columnconfigure( 1, weight=1 ) self.columnconfigure( 1, weight=1 )
return title, graph, scale
# Save for future reference
self.title = title
self.scale = scale
self.graph = graph
return graph
def addBar( self, yval ): def addBar( self, yval ):
"Add a new bar to our graph." "Add a new bar to our graph."
@@ -123,7 +117,7 @@ class Graph( Frame ):
"Add a bar for testing purposes." "Add a bar for testing purposes."
ms = 1000 ms = 1000
if self.xpos < 10: if self.xpos < 10:
self.addBar( self.xpos/10 * self.ymax ) self.addBar( self.xpos / 10 * self.ymax )
self.after( ms, self.test ) self.after( ms, self.test )
def setTitle( self, text ): def setTitle( self, text ):
@@ -146,26 +140,15 @@ class Controls( Frame ):
'NOX': NOX 'NOX': NOX
} }
def optionMenu( self, name, dict, initval, opts ): def __init__( self, master, startFn, stopFn, quitFn ):
"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 ) Frame.__init__( self, master )
# Option menus # Option menus
opts = { 'font': 'Geneva 7 bold' } opts = { 'font': 'Geneva 7 bold' }
self.switch = self.optionMenu( 'Switch', self.switches, self.switch = self.optionMenu( self.switches,
KernelSwitch, opts ) KernelSwitch, opts )
self.controller = self.optionMenu( 'Controller', self.controllers, self.controller = self.optionMenu( self.controllers,
Controller, opts) Controller, opts)
# Spacer # Spacer
@@ -173,12 +156,20 @@ class Controls( Frame ):
Label( self, **opts ).pack( **pk ) Label( self, **opts ).pack( **pk )
# Buttons # Buttons
self.start = Button( self, text='Start', command=start, **opts ) self.start = Button( self, text='Start', command=startFn, **opts )
self.stop = Button( self, text='Stop', command=stop, **opts ) self.stop = Button( self, text='Stop', command=stopFn, **opts )
self.quit = Button( self, text='Quit', command=quit, **opts ) self.quit = Button( self, text='Quit', command=quitFn, **opts )
for button in ( self.start, self.stop, self.quit ): for button in ( self.start, self.stop, self.quit ):
button.pack( **pk ) button.pack( **pk )
def optionMenu( self, menuItems, initval, opts ):
"Add a new option menu. Returns function to get value."
var = StringVar()
var.set( findKey( menuItems, initval ) )
menu = OptionMenu( self, var, *menuItems )
menu.config( **opts )
menu.pack( fill='x' )
return lambda: menuItems[ var.get() ]
def parsebwtest( line, def parsebwtest( line,
r=re.compile( r'(\d+) s: in ([\d\.]+) MB/s, out ([\d\.]+) MB/s' ) ): r=re.compile( r'(\d+) s: in ([\d\.]+) MB/s, out ([\d\.]+) MB/s' ) ):
@@ -193,7 +184,7 @@ def parsebwtest( line,
class UdpBwTest( Frame ): class UdpBwTest( Frame ):
"Test and plot UDP bandwidth over time" "Test and plot UDP bandwidth over time"
def __init__( self, topo, seconds=60, master=None ): def __init__( self, topo, master=None ):
"Start up and monitor udpbwtest on each of our hosts." "Start up and monitor udpbwtest on each of our hosts."
Frame.__init__( self, master ) Frame.__init__( self, master )
@@ -206,10 +197,16 @@ class UdpBwTest( Frame ):
self.graph.pack( side='right', expand=True, fill='both' ) self.graph.pack( side='right', expand=True, fill='both' )
self.pack( expand=True, fill='both' ) self.pack( expand=True, fill='both' )
self.topo = topo
self.net = None
self.hosts = []
self.hostCount = 0
self.output = None
self.results = {}
self.running = False self.running = False
def start( self ): def start( self ):
print "start" "Start test."
if self.running: if self.running:
return return
@@ -217,7 +214,8 @@ class UdpBwTest( Frame ):
switch = self.controls.switch() switch = self.controls.switch()
controller = self.controls.controller() controller = self.controls.controller()
self.net = Mininet( topo, switch=switch, controller=controller ) self.net = Mininet( self.topo, switch=switch,
controller=controller )
self.hosts = self.net.hosts self.hosts = self.net.hosts
self.hostCount = len( self.hosts ) self.hostCount = len( self.hosts )
@@ -282,7 +280,7 @@ class UdpBwTest( Frame ):
self.net.stop() self.net.stop()
def quit( self ): def quit( self ):
print "*** Quitting" "Quit app."
self.stop() self.stop()
Frame.quit( self ) Frame.quit( self )
@@ -290,9 +288,9 @@ class UdpBwTest( Frame ):
# Useful utilities # Useful utilities
def findKey( dict, value ): def findKey( d, value ):
"Find some key where dict[ key ] == value." "Find some key where d[ key ] == value."
return [ key for key, val in dict.items() if val == value ][ 0 ] return [ key for key, val in d.items() if val == value ][ 0 ]
def assign( obj, **kwargs): def assign( obj, **kwargs):
"Set a bunch of fields in an object." "Set a bunch of fields in an object."
@@ -306,7 +304,7 @@ class Object( object ):
if __name__ == '__main__': if __name__ == '__main__':
setLogLevel( 'info' ) setLogLevel( 'info' )
topo = TreeTopo( depth=1, fanout=2 ) app = UdpBwTest( topo=TreeTopo( depth=2, fanout=2 ) )
app = UdpBwTest( topo )
app.mainloop() app.mainloop()
+20 -14
View File
@@ -29,7 +29,7 @@ from subprocess import call
from cmd import Cmd from cmd import Cmd
from os import isatty from os import isatty
from select import poll, POLLIN from select import poll, POLLIN
from sys import stdin import sys
from mininet.log import info, output, error from mininet.log import info, output, error
from mininet.term import makeTerms from mininet.term import makeTerms
@@ -40,7 +40,7 @@ class CLI( Cmd ):
prompt = 'mininet> ' prompt = 'mininet> '
def __init__( self, mininet, stdin=stdin ): def __init__( self, mininet, stdin=sys.stdin ):
self.mn = mininet self.mn = mininet
self.nodelist = self.mn.controllers + self.mn.switches + self.mn.hosts self.nodelist = self.mn.controllers + self.mn.switches + self.mn.hosts
self.nodemap = {} # map names to Node objects self.nodemap = {} # map names to Node objects
@@ -110,7 +110,9 @@ class CLI( Cmd ):
for switch in self.mn.switches: for switch in self.mn.switches:
output( switch.name, '<->' ) output( switch.name, '<->' )
for intf in switch.intfs.values(): for intf in switch.intfs.values():
node, name = switch.connection.get( intf, ( None, 'Unknown ' ) ) # Ugly, but pylint wants it
name = switch.connection.get( intf,
( None, 'Unknown ' ) )[ 1 ]
output( ' %s' % name ) output( ' %s' % name )
output( '\n' ) output( '\n' )
@@ -236,20 +238,16 @@ class CLI( Cmd ):
for arg in rest ] for arg in rest ]
rest = ' '.join( rest ) rest = ' '.join( rest )
# Run cmd on node: # Run cmd on node:
node.sendCmd( rest ) builtin = isShellBuiltin( first )
self.waitForNode( node, isShellBuiltin( first ) ) print "builtin =", builtin
node.sendCmd( rest, printPid=( not builtin ) )
self.waitForNode( node )
else: else:
error( '*** Unknown command: %s\n' % first ) error( '*** Unknown command: %s\n' % first )
# pylint: enable-msg=W0613,R0201 # pylint: enable-msg=W0613,R0201
def isReadable( self, poller ): def waitForNode( self, node ):
"Check whether a single polled object is readable."
for fd, mask in poller.poll( 0 ):
if mask & POLLIN:
return True
def waitForNode( self, node, isShellBuiltin=False ):
"Wait for a node to finish, and print its output." "Wait for a node to finish, and print its output."
# Pollers # Pollers
nodePoller = poll() nodePoller = poll()
@@ -264,10 +262,10 @@ class CLI( Cmd ):
while True: while True:
try: try:
bothPoller.poll() bothPoller.poll()
if self.isReadable( self.inPoller ): if isReadable( self.inPoller ):
key = self.stdin.read( 1 ) key = self.stdin.read( 1 )
node.write( key ) node.write( key )
if self.isReadable( nodePoller ): if isReadable( nodePoller ):
data = node.monitor() data = node.monitor()
output( data ) output( data )
if not node.waiting: if not node.waiting:
@@ -275,3 +273,11 @@ class CLI( Cmd ):
except KeyboardInterrupt: except KeyboardInterrupt:
node.sendInt() node.sendInt()
# Helper functions
def isReadable( poller ):
"Check whether a Poll object has a readable fd."
for fdmask in poller.poll( 0 ):
mask = fdmask[ 1 ]
if mask & POLLIN:
return True
+27 -23
View File
@@ -100,26 +100,6 @@ from mininet.util import quietRun, fixLimits
from mininet.util import createLink, macColonHex, ipStr, ipParse from mininet.util import createLink, macColonHex, ipStr, ipParse
from mininet.term import cleanUpScreens, makeTerms from mininet.term import cleanUpScreens, makeTerms
DATAPATHS = [ 'kernel' ] # [ 'user', 'kernel' ]
def init():
"Initialize Mininet."
if init.inited:
return
if os.getuid() != 0:
# Note: this script must be run as root
# Perhaps we should do so automatically!
print "*** Mininet must run as root."
exit( 1 )
# If which produces no output, then mnexec is not in the path.
# May want to loosen this to handle mnexec in the current dir.
if not quietRun( 'which mnexec' ):
raise Exception( "Could not find mnexec - check $PATH" )
fixLimits()
init.inited = False
class Mininet( object ): class Mininet( object ):
"Network emulation with hosts spawned in network namespaces." "Network emulation with hosts spawned in network namespaces."
@@ -195,13 +175,13 @@ class Mininet( object ):
self.nameToNode[ name ] = sw self.nameToNode[ name ] = sw
return sw return sw
def addController( self, controller ): def addController( self, name='c0', **kwargs ):
"""Add controller. """Add controller.
controller: Controller class""" controller: Controller class"""
controller_new = self.controller( 'c0' ) controller_new = self.controller( name, **kwargs )
if controller_new: # allow controller-less setups if controller_new: # allow controller-less setups
self.controllers.append( controller_new ) self.controllers.append( controller_new )
self.nameToNode[ 'c0' ] = controller_new self.nameToNode[ name ] = controller_new
# Control network support: # Control network support:
# #
@@ -558,3 +538,27 @@ class Mininet( object ):
result = CLI( self ) result = CLI( self )
self.stop() self.stop()
return result return result
# pylint thinks inited is unused
# pylint: disable-msg=W0612
def init():
"Initialize Mininet."
if init.inited:
return
if os.getuid() != 0:
# Note: this script must be run as root
# Perhaps we should do so automatically!
print "*** Mininet must run as root."
exit( 1 )
# If which produces no output, then mnexec is not in the path.
# May want to loosen this to handle mnexec in the current dir.
if not quietRun( 'which mnexec' ):
raise Exception( "Could not find mnexec - check $PATH" )
fixLimits()
init.inited = True
init.inited = False
# pylint: enable-msg=W0612
+3 -9
View File
@@ -95,6 +95,8 @@ class Node( object ):
self.lastPid = None self.lastPid = None
self.readbuf = '' self.readbuf = ''
self.waiting = False self.waiting = False
# Stash additional information as desired
self.args = kwargs
@classmethod @classmethod
def fdToNode( cls, fd ): def fdToNode( cls, fd ):
@@ -186,7 +188,7 @@ class Node( object ):
if self.lastPid: if self.lastPid:
try: try:
os.kill( self.lastPid, sig ) os.kill( self.lastPid, sig )
except Exception: except OSError:
pass pass
def monitor( self, timeoutms=None ): def monitor( self, timeoutms=None ):
@@ -410,14 +412,6 @@ class Switch( Node ):
error( '*** Error: %s has execed and cannot accept commands' % error( '*** Error: %s has execed and cannot accept commands' %
self.name ) self.name )
def monitor( self, *args, **kwargs ):
"Monitor a switch."
if not self.execed:
return Node.monitor( self, *args, **kwargs )
else:
return True, ''
class UserSwitch( Switch ): class UserSwitch( Switch ):
"User-space switch." "User-space switch."
+31 -19
View File
@@ -5,7 +5,9 @@ from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
import select import select
from subprocess import call, check_call, Popen, PIPE, STDOUT from subprocess import call, check_call, Popen, PIPE, STDOUT
from mininet.log import lg from mininet.log import error
# Command execution support
def run( cmd ): def run( cmd ):
"""Simple interface to subprocess.call() """Simple interface to subprocess.call()
@@ -17,6 +19,9 @@ def checkRun( cmd ):
cmd: list of command params""" cmd: list of command params"""
return check_call( cmd.split( ' ' ) ) return check_call( cmd.split( ' ' ) )
# pylint doesn't understand explicit type checking
# pylint: disable-msg=E1103
def quietRun( *cmd ): def quietRun( *cmd ):
"""Run a command, routing stderr to stdout, and return the output. """Run a command, routing stderr to stdout, and return the output.
cmd: list of command params""" cmd: list of command params"""
@@ -42,6 +47,22 @@ def quietRun( *cmd ):
break break
return output return output
# pylint: enable-msg=E1103
# pylint: disable-msg=E1101,W0612
def isShellBuiltin( cmd ):
"Return True if cmd is a bash builtin."
if isShellBuiltin.builtIns is None:
isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
space = cmd.find( ' ' )
if space > 0:
cmd = cmd[ :space]
return cmd in isShellBuiltin.builtIns
isShellBuiltin.builtIns = None
# pylint: enable-msg=E1101,W0612
# Interface management # Interface management
# #
# Interfaces are managed as strings which are simply the # Interfaces are managed as strings which are simply the
@@ -78,7 +99,7 @@ def retry( retries, delaySecs, fn, *args, **keywords ):
sleep( delaySecs ) sleep( delaySecs )
tries += 1 tries += 1
if tries >= retries: if tries >= retries:
lg.error( "*** gave up after %i retries\n" % tries ) error( "*** gave up after %i retries\n" % tries )
exit( 1 ) exit( 1 )
def moveIntfNoRetry( intf, node, printError=False ): def moveIntfNoRetry( intf, node, printError=False ):
@@ -91,7 +112,7 @@ def moveIntfNoRetry( intf, node, printError=False ):
links = node.cmd( 'ip link show' ) links = node.cmd( 'ip link show' )
if not ( ' %s:' % intf ) in links: if not ( ' %s:' % intf ) in links:
if printError: if printError:
lg.error( '*** Error: moveIntf: ' + intf + error( '*** Error: moveIntf: ' + intf +
' not successfully moved to ' + node.name + '\n' ) ' not successfully moved to ' + node.name + '\n' )
return False return False
return True return True
@@ -112,10 +133,8 @@ def createLink( node1, node2, port1=None, port2=None ):
returns: intf1 name, intf2 name""" returns: intf1 name, intf2 name"""
return node1.linkTo( node2, port1, port2 ) return node1.linkTo( node2, port1, port2 )
def fixLimits():
"Fix ridiculously small resource limits." # IP and Mac address formatting and parsing
setrlimit( RLIMIT_NPROC, ( 4096, 8192 ) )
setrlimit( RLIMIT_NOFILE, ( 16384, 32768 ) )
def _colonHex( val, bytes ): def _colonHex( val, bytes ):
"""Generate colon-hex string. """Generate colon-hex string.
@@ -181,17 +200,10 @@ def makeNumeric( s ):
else: else:
return s return s
# pylint: disable-msg=E1101,W0612
def isShellBuiltin( cmd ): # Other stuff we use
"Return True if cmd is a bash builtin."
if isShellBuiltin.builtIns is None:
isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
space = cmd.find( ' ' )
if space > 0:
cmd = cmd[ :space]
return cmd in isShellBuiltin.builtIns
isShellBuiltin.builtIns = None def fixLimits():
"Fix ridiculously small resource limits."
# pylint: enable-msg=E1101,W0612 setrlimit( RLIMIT_NPROC, ( 4096, 8192 ) )
setrlimit( RLIMIT_NOFILE, ( 16384, 32768 ) )