Pass pylint.
This commit is contained in:
@@ -9,7 +9,7 @@ EXAMPLES = examples/*.py
|
||||
BIN = bin/mn
|
||||
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
|
||||
|
||||
P8IGN = E251,E201,E302
|
||||
P8IGN = E251,E201,E302,E202
|
||||
|
||||
codecheck: $(PYSRC)
|
||||
pyflakes $(PYSRC)
|
||||
|
||||
+34
-29
@@ -128,23 +128,28 @@ class Console( Frame ):
|
||||
cmd = cmd[ pos + len( self.prompt ): ]
|
||||
self.sendCmd( cmd )
|
||||
|
||||
# Callback ignores event
|
||||
# pylint: disable-msg=W0613
|
||||
def handleInt( self, event=None ):
|
||||
"Handle control-c."
|
||||
self.node.sendInt()
|
||||
# pylint: enable-msg=W0613
|
||||
|
||||
def sendCmd( self, cmd ):
|
||||
"Send a command to our node."
|
||||
text, node = self.text, self.node
|
||||
if not node.waiting:
|
||||
node.sendCmd( cmd )
|
||||
if not self.node.waiting:
|
||||
self.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."
|
||||
data = self.node.monitor( timeoutms )
|
||||
self.append( data )
|
||||
if not self.node.waiting:
|
||||
# Print prompt
|
||||
self.append( self.prompt )
|
||||
# pylint: enable-msg=W0613
|
||||
|
||||
def waiting( self ):
|
||||
"Are we waiting for output?"
|
||||
@@ -182,27 +187,25 @@ class Graph( Frame ):
|
||||
self.xpos = 0
|
||||
|
||||
# Create everything
|
||||
self.title = self.graph = None
|
||||
self.createWidgets()
|
||||
self.title, self.scale, self.graph = self.createWidgets()
|
||||
self.updateScrollRegions()
|
||||
self.yview( 'moveto', '1.0' )
|
||||
|
||||
|
||||
def scale( self ):
|
||||
def createScale( self ):
|
||||
"Create a and return a new canvas with scale markers."
|
||||
height = float( self.gheight )
|
||||
width = 25
|
||||
ymax = self.ymax
|
||||
scale = Canvas( self, width=width, height=height, background=self.bg )
|
||||
fill = 'red'
|
||||
scale = Canvas( self, width=width, height=height,
|
||||
background=self.bg )
|
||||
opts = { 'fill': 'red' }
|
||||
# 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
|
||||
for y in range( 0, int( ymax + 1 ) ):
|
||||
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 )
|
||||
|
||||
scale.create_line( width, ypos, width - 10, ypos, **opts )
|
||||
scale.create_text( 10, ypos, text=str( y ), **opts )
|
||||
return scale
|
||||
|
||||
def updateScrollRegions( self ):
|
||||
@@ -222,10 +225,10 @@ class Graph( Frame ):
|
||||
"Create initial widget set."
|
||||
|
||||
# Objects
|
||||
title = Label( self, text="Bandwidth (Gb/s)", bg=self.bg )
|
||||
title = Label( self, text='Bandwidth (Gb/s)', bg=self.bg )
|
||||
width = self.gwidth
|
||||
height = self.gheight
|
||||
scale = self.scale()
|
||||
scale = self.createScale()
|
||||
graph = Canvas( self, width=width, height=height, background=self.bg)
|
||||
xbar = Scrollbar( self, orient='horizontal', command=graph.xview )
|
||||
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' )
|
||||
self.rowconfigure( 1, weight=1 )
|
||||
self.columnconfigure( 1, weight=1 )
|
||||
# Save for future reference
|
||||
self.title = title
|
||||
self.scale = scale
|
||||
self.graph = graph
|
||||
return graph
|
||||
return title, scale, graph
|
||||
|
||||
def addBar( self, yval ):
|
||||
"Add a new bar to our graph."
|
||||
@@ -279,6 +278,8 @@ class Graph( Frame ):
|
||||
|
||||
class ConsoleApp( Frame ):
|
||||
|
||||
"Simple Tk consoles for Mininet."
|
||||
|
||||
menuStyle = { 'font': 'Geneva 7 bold' }
|
||||
|
||||
def __init__( self, net, parent=None, width=4 ):
|
||||
@@ -317,6 +318,8 @@ class ConsoleApp( Frame ):
|
||||
|
||||
self.pack( expand=True, fill='both' )
|
||||
|
||||
# Update callback doesn't use console arg
|
||||
# pylint: disable-msg=W0613
|
||||
def updateGraph( self, console, output ):
|
||||
"Update our graph."
|
||||
m = re.search( r'(\d+) Mbits/sec', output )
|
||||
@@ -328,8 +331,10 @@ class ConsoleApp( Frame ):
|
||||
self.graph.addBar( self.bw )
|
||||
self.bw = 0
|
||||
self.updates = 0
|
||||
# pylint: enable-msg=W0613
|
||||
|
||||
def setOutputHook( self, fn=None, consoles=None ):
|
||||
"Register fn as output hook [on specific consoles.]"
|
||||
if consoles is None:
|
||||
consoles = self.consoles[ 'hosts' ].consoles
|
||||
for console in consoles:
|
||||
@@ -342,7 +347,7 @@ class ConsoleApp( Frame ):
|
||||
consoles = []
|
||||
index = 0
|
||||
for node in nodes:
|
||||
console = Console( f, net, node, title=title )
|
||||
console = Console( f, self.net, node, title=title )
|
||||
consoles.append( console )
|
||||
row = index / width
|
||||
column = index % width
|
||||
@@ -352,11 +357,11 @@ class ConsoleApp( Frame ):
|
||||
f.columnconfigure( column, weight=1 )
|
||||
return f, consoles
|
||||
|
||||
def select( self, set ):
|
||||
"Select a set of consoles to display."
|
||||
def select( self, groupName ):
|
||||
"Select a group of consoles to display."
|
||||
if self.selected is not None:
|
||||
self.selected.frame.pack_forget()
|
||||
self.selected = self.consoles[ set ]
|
||||
self.selected = self.consoles[ groupName ]
|
||||
self.selected.frame.pack( expand=True, fill='both' )
|
||||
|
||||
def createMenuBar( self ):
|
||||
@@ -453,8 +458,8 @@ class Object( object ):
|
||||
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'info' )
|
||||
net = TreeNet( depth=2, fanout=2 )
|
||||
net.start()
|
||||
app = ConsoleApp( net, width=4 )
|
||||
network = TreeNet( depth=2, fanout=4 )
|
||||
network.start()
|
||||
app = ConsoleApp( network, width=4 )
|
||||
app.mainloop()
|
||||
net.stop()
|
||||
network.stop()
|
||||
|
||||
+139
-93
@@ -48,10 +48,10 @@ class MiniEdit( Frame ):
|
||||
self.cframe, self.canvas = self.createCanvas()
|
||||
|
||||
# Toolbar
|
||||
self.images = miniEditImages()
|
||||
self.buttons = {}
|
||||
self.active = None
|
||||
self.tools = ( 'Select', 'Host', 'Switch', 'Link' )
|
||||
self.images = self.createImages()
|
||||
self.customColors = { 'Switch': 'darkGreen', 'Host': 'blue' }
|
||||
self.toolbar = self.createToolbar()
|
||||
|
||||
@@ -83,6 +83,10 @@ class MiniEdit( Frame ):
|
||||
self.bind( '<KeyPress-BackSpace>', self.deleteSelection )
|
||||
self.focus()
|
||||
|
||||
# Event handling initalization
|
||||
self.linkx = self.linky = self.linkItem = None
|
||||
self.lastSelection = None
|
||||
|
||||
# Model initialization
|
||||
self.links = {}
|
||||
self.nodeCount = 0
|
||||
@@ -112,15 +116,13 @@ class MiniEdit( Frame ):
|
||||
appMenu.add_separator()
|
||||
appMenu.add_command( label='Quit', command=self.quit, font=font )
|
||||
|
||||
"""
|
||||
fileMenu = Menu( mbar, tearoff=False )
|
||||
mbar.add_cascade( label="File", font=font, menu=fileMenu )
|
||||
fileMenu.add_command( label="Load...", font=font )
|
||||
fileMenu.add_separator()
|
||||
fileMenu.add_command( label="Save", font=font )
|
||||
fileMenu.add_separator()
|
||||
fileMenu.add_command( label="Print", font=font )
|
||||
"""
|
||||
#fileMenu = Menu( mbar, tearoff=False )
|
||||
#mbar.add_cascade( label="File", font=font, menu=fileMenu )
|
||||
#fileMenu.add_command( label="Load...", font=font )
|
||||
#fileMenu.add_separator()
|
||||
#fileMenu.add_command( label="Save", font=font )
|
||||
#fileMenu.add_separator()
|
||||
#fileMenu.add_command( label="Print", font=font )
|
||||
|
||||
editMenu = Menu( mbar, tearoff=False )
|
||||
mbar.add_cascade( label="Edit", font=font, menu=editMenu )
|
||||
@@ -189,6 +191,7 @@ class MiniEdit( Frame ):
|
||||
# Toolbar
|
||||
|
||||
def activate( self, toolName ):
|
||||
"Activate a tool and press its button."
|
||||
# Adjust button appearance
|
||||
if self.active:
|
||||
self.buttons[ self.active ].configure( relief='raised' )
|
||||
@@ -203,7 +206,7 @@ class MiniEdit( Frame ):
|
||||
|
||||
# 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)
|
||||
if tool in self.images:
|
||||
b.config( height=35, image=self.images[ tool ] )
|
||||
@@ -217,9 +220,9 @@ class MiniEdit( Frame ):
|
||||
|
||||
# Commands
|
||||
for cmd, color in [ ( 'Stop', 'darkRed' ), ( 'Run', 'darkGreen' ) ]:
|
||||
def doCmd( f=getattr( self, 'do' + cmd ) ):
|
||||
f()
|
||||
b = Button( toolbar, text=cmd, font=self.smallFont, fg=color, command=doCmd )
|
||||
doCmd = getattr( self, 'do' + cmd )
|
||||
b = Button( toolbar, text=cmd, font=self.smallFont,
|
||||
fg=color, command=doCmd )
|
||||
b.pack( fill='x', side='bottom' )
|
||||
|
||||
return toolbar
|
||||
@@ -267,9 +270,9 @@ class MiniEdit( Frame ):
|
||||
|
||||
# Currently the only items we can select directly are
|
||||
# links. Nodes are handled by bindings in the node icon.
|
||||
# If we want to allow node deletion, we will
|
||||
|
||||
def findItem( self, x, y ):
|
||||
"Find items at a location in our canvas."
|
||||
items = self.canvas.find_overlapping( x, y, x, y )
|
||||
if len( items ) == 0:
|
||||
return None
|
||||
@@ -295,10 +298,14 @@ class MiniEdit( Frame ):
|
||||
# Delete from view
|
||||
self.canvas.delete( item )
|
||||
|
||||
# Callback ignores event
|
||||
# pylint: disable-msg=W0613
|
||||
def deleteSelection( self, event ):
|
||||
"Delete the selected item."
|
||||
if self.selection is not None:
|
||||
self.deleteItem( self.selection )
|
||||
self.selectItem( None )
|
||||
# pylint: enable-msg=W0613
|
||||
|
||||
def nodeIcon( self, node, name ):
|
||||
"Create a new node icon."
|
||||
@@ -317,7 +324,8 @@ class MiniEdit( Frame ):
|
||||
self.nodeCount += 1
|
||||
name = self.nodePrefixes[ node ] + str( self.nodeCount )
|
||||
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.itemToWidget[ item ] = icon
|
||||
self.selectItem( item )
|
||||
@@ -341,40 +349,47 @@ class MiniEdit( Frame ):
|
||||
c = self.canvas
|
||||
c.coords( self.link, self.linkx, self.linky, x, y )
|
||||
|
||||
# Callback ignores event
|
||||
# pylint: disable-msg=W0613
|
||||
def releaseLink( self, event ):
|
||||
"Give up on the current link."
|
||||
if self.link is not None:
|
||||
self.canvas.delete( self.link )
|
||||
self.linkWidget = self.linkItem = self.link = None
|
||||
# pylint: enable-msg=W0613
|
||||
|
||||
# Generic node handlers
|
||||
|
||||
def createBindings( self, bindings ):
|
||||
l = Label()
|
||||
for event, binding in bindings.items():
|
||||
l.bind( event, binding )
|
||||
return l
|
||||
|
||||
def createNodeBindings( self ):
|
||||
"Create a set of bindings for nodes."
|
||||
return self.createBindings( {
|
||||
bindings = {
|
||||
'<ButtonPress-1>': self.clickNode,
|
||||
'<B1-Motion>': self.dragNode,
|
||||
'<ButtonRelease-1>': self.releaseNode,
|
||||
'<Enter>': self.enterNode,
|
||||
'<Leave>': self.leaveNode,
|
||||
'<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 ):
|
||||
"Select an item and remember old selection."
|
||||
self.lastSelection = self.selection
|
||||
self.selection = item
|
||||
|
||||
def enterNode( self, event ):
|
||||
"Select node on entry."
|
||||
self.selectNode( event )
|
||||
|
||||
# Callback ignores event
|
||||
# pylint: disable-msg=W0613
|
||||
def leaveNode( self, event ):
|
||||
"Restore old selection on exit."
|
||||
self.selectItem( self.lastSelection )
|
||||
# pylint: enable-msg=W0613
|
||||
|
||||
def clickNode( self, event ):
|
||||
"Node click handler."
|
||||
@@ -436,14 +451,20 @@ class MiniEdit( Frame ):
|
||||
self.linkItem = item
|
||||
# Link bindings
|
||||
# Selection still needs a bit of work overall
|
||||
# Callbacks ignore event
|
||||
# pylint: disable-msg=W0613
|
||||
def select( event, link=self.link ):
|
||||
"Select item on mouse entry."
|
||||
self.selectItem( link )
|
||||
def highlight( event, link=self.link ):
|
||||
"Highlight item on mouse entry."
|
||||
# self.selectItem( link )
|
||||
self.canvas.itemconfig( link, fill='green' )
|
||||
def unhighlight( event, link=self.link ):
|
||||
"Unhighlight item on mouse exit."
|
||||
self.canvas.itemconfig( link, fill='blue' )
|
||||
# self.selectItem( None )
|
||||
# pylint: disable-msg=W0613
|
||||
self.canvas.tag_bind( self.link, '<Enter>', highlight )
|
||||
self.canvas.tag_bind( self.link, '<Leave>', unhighlight )
|
||||
self.canvas.tag_bind( self.link, '<ButtonPress-1>', select )
|
||||
@@ -471,8 +492,6 @@ class MiniEdit( Frame ):
|
||||
x, y = c.coords( target )
|
||||
c.coords( self.link, self.linkx, self.linky, x, y )
|
||||
self.addLink( source, dest )
|
||||
|
||||
|
||||
# We're done
|
||||
self.link = self.linkWidget = None
|
||||
|
||||
@@ -494,7 +513,7 @@ class MiniEdit( Frame ):
|
||||
line1.pack( padx=20, pady=10 )
|
||||
line2.pack(pady=10 )
|
||||
line3.pack(pady=10 )
|
||||
hide = lambda about=about: about.withdraw()
|
||||
hide = ( lambda about=about: about.withdraw() )
|
||||
self.aboutBox = about
|
||||
# Hide on close rather than destroying window
|
||||
Wm.wm_protocol( about, name='WM_DELETE_WINDOW', func=hide )
|
||||
@@ -566,17 +585,19 @@ class MiniEdit( Frame ):
|
||||
return net
|
||||
|
||||
def start( self ):
|
||||
"Start network."
|
||||
if self.net is None:
|
||||
self.net = self.build()
|
||||
self.net.start()
|
||||
|
||||
def stop( self ):
|
||||
"Stop network."
|
||||
if self.net is not None:
|
||||
self.net.stop()
|
||||
cleanUpScreens()
|
||||
self.net = None
|
||||
|
||||
def xterm( self, ignore=None ):
|
||||
"Make an xterm when a button is pressed."
|
||||
if ( self.selection is None or
|
||||
self.net is None or
|
||||
self.selection not in self.itemToWidget ):
|
||||
@@ -584,77 +605,102 @@ class MiniEdit( Frame ):
|
||||
name = self.itemToWidget[ self.selection ][ 'text' ]
|
||||
if name not in self.net.nameToNode:
|
||||
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 ):
|
||||
"Initialize button/icon images."
|
||||
images = {}
|
||||
def miniEditImages():
|
||||
"Create and return images for MiniEdit."
|
||||
|
||||
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"""
|
||||
R0lGODlhIAAYAPcAMf//////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
|
||||
u6qqqoiIiHd3d1VVVURERCIiIhEREQAAACH5BAEAAAAALAAAAAAgABgAAAiNAAH8G0iwoMGD
|
||||
CAcKTMiw4UBwBPXVm0ixosWLFvVBHFjPoUeC9Tb+6/jRY0iQ/8iVbHiS40CVKxG2HEkQZsyC
|
||||
M0mmvGkw50uePUV2tEnOZkyfQA8iTYpTKNOgKJ+C3AhOp9SWVaVOfWj1KdauTL9q5UgVbFKs
|
||||
EjGqXVtP40NwcBnCjXtw7tx/C8cSBBAQADs=""" )
|
||||
return {
|
||||
'Select': BitmapImage(
|
||||
file='/usr/include/X11/bitmaps/left_ptr' ),
|
||||
|
||||
images[ 'Switch' ] = PhotoImage( data=r"""
|
||||
R0lGODlhIAAYAPcAMf//////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
|
||||
u6qqqoiIiHd3d1VVVURERCIiIhEREQAAACH5BAEAAAAALAAAAAAgABgAAAhwAAEIHEiwoMGD
|
||||
CBMqXMiwocOHECNKnEixosWB3zJq3Mixo0eNAL7xG0mypMmTKPl9Cznyn8uWL/m5/AeTpsyY
|
||||
I1eKlBnO5r+eLYHy9Ck0J8ubPmPOrMmUpM6UUKMa/Ui16saLWLNq3cq1q9evYB0GBAA7
|
||||
'Host': 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
|
||||
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__':
|
||||
setLogLevel( 'info' )
|
||||
|
||||
+35
-37
@@ -41,12 +41,11 @@ class Graph( Frame ):
|
||||
self.xpos = 0
|
||||
|
||||
# Create everything
|
||||
self.title = self.graph = None
|
||||
self.createWidgets()
|
||||
self.title, self.graph, self.scale = self.createWidgets()
|
||||
self.updateScrollRegions()
|
||||
self.yview( 'moveto', '1.0' )
|
||||
|
||||
def scale( self ):
|
||||
def createScale( self ):
|
||||
"Create a and return a new canvas with scale markers."
|
||||
height = float( self.gheight )
|
||||
width = 25
|
||||
@@ -83,7 +82,7 @@ class Graph( Frame ):
|
||||
title = Label( self, text="Bandwidth (Mb/s)", bg=self.bg )
|
||||
width = self.gwidth
|
||||
height = self.gheight
|
||||
scale = self.scale()
|
||||
scale = self.createScale()
|
||||
graph = Canvas( self, width=width, height=height, background=self.bg)
|
||||
xbar = Scrollbar( self, orient='horizontal', command=graph.xview )
|
||||
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' )
|
||||
self.rowconfigure( 1, weight=1 )
|
||||
self.columnconfigure( 1, weight=1 )
|
||||
|
||||
# Save for future reference
|
||||
self.title = title
|
||||
self.scale = scale
|
||||
self.graph = graph
|
||||
return graph
|
||||
return title, graph, scale
|
||||
|
||||
def addBar( self, yval ):
|
||||
"Add a new bar to our graph."
|
||||
@@ -123,7 +117,7 @@ class Graph( Frame ):
|
||||
"Add a bar for testing purposes."
|
||||
ms = 1000
|
||||
if self.xpos < 10:
|
||||
self.addBar( self.xpos/10 * self.ymax )
|
||||
self.addBar( self.xpos / 10 * self.ymax )
|
||||
self.after( ms, self.test )
|
||||
|
||||
def setTitle( self, text ):
|
||||
@@ -146,26 +140,15 @@ class Controls( Frame ):
|
||||
'NOX': NOX
|
||||
}
|
||||
|
||||
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 ):
|
||||
def __init__( self, master, startFn, stopFn, quitFn ):
|
||||
|
||||
Frame.__init__( self, master )
|
||||
|
||||
# Option menus
|
||||
opts = { 'font': 'Geneva 7 bold' }
|
||||
self.switch = self.optionMenu( 'Switch', self.switches,
|
||||
self.switch = self.optionMenu( self.switches,
|
||||
KernelSwitch, opts )
|
||||
self.controller = self.optionMenu( 'Controller', self.controllers,
|
||||
self.controller = self.optionMenu( self.controllers,
|
||||
Controller, opts)
|
||||
|
||||
# Spacer
|
||||
@@ -173,12 +156,20 @@ class Controls( Frame ):
|
||||
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 )
|
||||
self.start = Button( self, text='Start', command=startFn, **opts )
|
||||
self.stop = Button( self, text='Stop', command=stopFn, **opts )
|
||||
self.quit = Button( self, text='Quit', command=quitFn, **opts )
|
||||
for button in ( self.start, self.stop, self.quit ):
|
||||
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,
|
||||
r=re.compile( r'(\d+) s: in ([\d\.]+) MB/s, out ([\d\.]+) MB/s' ) ):
|
||||
@@ -193,7 +184,7 @@ def parsebwtest( line,
|
||||
class UdpBwTest( Frame ):
|
||||
"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."
|
||||
|
||||
Frame.__init__( self, master )
|
||||
@@ -206,10 +197,16 @@ class UdpBwTest( Frame ):
|
||||
self.graph.pack( side='right', 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
|
||||
|
||||
def start( self ):
|
||||
print "start"
|
||||
"Start test."
|
||||
|
||||
if self.running:
|
||||
return
|
||||
@@ -217,7 +214,8 @@ class UdpBwTest( Frame ):
|
||||
switch = self.controls.switch()
|
||||
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.hostCount = len( self.hosts )
|
||||
|
||||
@@ -282,7 +280,7 @@ class UdpBwTest( Frame ):
|
||||
self.net.stop()
|
||||
|
||||
def quit( self ):
|
||||
print "*** Quitting"
|
||||
"Quit app."
|
||||
self.stop()
|
||||
Frame.quit( self )
|
||||
|
||||
@@ -290,9 +288,9 @@ class UdpBwTest( Frame ):
|
||||
|
||||
# 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 findKey( d, value ):
|
||||
"Find some key where d[ key ] == value."
|
||||
return [ key for key, val in d.items() if val == value ][ 0 ]
|
||||
|
||||
def assign( obj, **kwargs):
|
||||
"Set a bunch of fields in an object."
|
||||
@@ -306,7 +304,7 @@ class Object( object ):
|
||||
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'info' )
|
||||
topo = TreeTopo( depth=1, fanout=2 )
|
||||
app = UdpBwTest( topo )
|
||||
app = UdpBwTest( topo=TreeTopo( depth=2, fanout=2 ) )
|
||||
app.mainloop()
|
||||
|
||||
|
||||
|
||||
+20
-14
@@ -29,7 +29,7 @@ from subprocess import call
|
||||
from cmd import Cmd
|
||||
from os import isatty
|
||||
from select import poll, POLLIN
|
||||
from sys import stdin
|
||||
import sys
|
||||
|
||||
from mininet.log import info, output, error
|
||||
from mininet.term import makeTerms
|
||||
@@ -40,7 +40,7 @@ class CLI( Cmd ):
|
||||
|
||||
prompt = 'mininet> '
|
||||
|
||||
def __init__( self, mininet, stdin=stdin ):
|
||||
def __init__( self, mininet, stdin=sys.stdin ):
|
||||
self.mn = mininet
|
||||
self.nodelist = self.mn.controllers + self.mn.switches + self.mn.hosts
|
||||
self.nodemap = {} # map names to Node objects
|
||||
@@ -110,7 +110,9 @@ class CLI( Cmd ):
|
||||
for switch in self.mn.switches:
|
||||
output( switch.name, '<->' )
|
||||
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( '\n' )
|
||||
|
||||
@@ -236,20 +238,16 @@ class CLI( Cmd ):
|
||||
for arg in rest ]
|
||||
rest = ' '.join( rest )
|
||||
# Run cmd on node:
|
||||
node.sendCmd( rest )
|
||||
self.waitForNode( node, isShellBuiltin( first ) )
|
||||
builtin = isShellBuiltin( first )
|
||||
print "builtin =", builtin
|
||||
node.sendCmd( rest, printPid=( not builtin ) )
|
||||
self.waitForNode( node )
|
||||
else:
|
||||
error( '*** Unknown command: %s\n' % first )
|
||||
|
||||
# pylint: enable-msg=W0613,R0201
|
||||
|
||||
def isReadable( self, poller ):
|
||||
"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 ):
|
||||
def waitForNode( self, node ):
|
||||
"Wait for a node to finish, and print its output."
|
||||
# Pollers
|
||||
nodePoller = poll()
|
||||
@@ -264,10 +262,10 @@ class CLI( Cmd ):
|
||||
while True:
|
||||
try:
|
||||
bothPoller.poll()
|
||||
if self.isReadable( self.inPoller ):
|
||||
if isReadable( self.inPoller ):
|
||||
key = self.stdin.read( 1 )
|
||||
node.write( key )
|
||||
if self.isReadable( nodePoller ):
|
||||
if isReadable( nodePoller ):
|
||||
data = node.monitor()
|
||||
output( data )
|
||||
if not node.waiting:
|
||||
@@ -275,3 +273,11 @@ class CLI( Cmd ):
|
||||
except KeyboardInterrupt:
|
||||
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
@@ -100,26 +100,6 @@ from mininet.util import quietRun, fixLimits
|
||||
from mininet.util import createLink, macColonHex, ipStr, ipParse
|
||||
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 ):
|
||||
"Network emulation with hosts spawned in network namespaces."
|
||||
|
||||
@@ -195,13 +175,13 @@ class Mininet( object ):
|
||||
self.nameToNode[ name ] = sw
|
||||
return sw
|
||||
|
||||
def addController( self, controller ):
|
||||
def addController( self, name='c0', **kwargs ):
|
||||
"""Add controller.
|
||||
controller: Controller class"""
|
||||
controller_new = self.controller( 'c0' )
|
||||
controller_new = self.controller( name, **kwargs )
|
||||
if controller_new: # allow controller-less setups
|
||||
self.controllers.append( controller_new )
|
||||
self.nameToNode[ 'c0' ] = controller_new
|
||||
self.nameToNode[ name ] = controller_new
|
||||
|
||||
# Control network support:
|
||||
#
|
||||
@@ -558,3 +538,27 @@ class Mininet( object ):
|
||||
result = CLI( self )
|
||||
self.stop()
|
||||
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
@@ -95,6 +95,8 @@ class Node( object ):
|
||||
self.lastPid = None
|
||||
self.readbuf = ''
|
||||
self.waiting = False
|
||||
# Stash additional information as desired
|
||||
self.args = kwargs
|
||||
|
||||
@classmethod
|
||||
def fdToNode( cls, fd ):
|
||||
@@ -186,7 +188,7 @@ class Node( object ):
|
||||
if self.lastPid:
|
||||
try:
|
||||
os.kill( self.lastPid, sig )
|
||||
except Exception:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def monitor( self, timeoutms=None ):
|
||||
@@ -410,14 +412,6 @@ class Switch( Node ):
|
||||
error( '*** Error: %s has execed and cannot accept commands' %
|
||||
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 ):
|
||||
"User-space switch."
|
||||
|
||||
|
||||
+31
-19
@@ -5,7 +5,9 @@ from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
|
||||
import select
|
||||
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 ):
|
||||
"""Simple interface to subprocess.call()
|
||||
@@ -17,6 +19,9 @@ def checkRun( cmd ):
|
||||
cmd: list of command params"""
|
||||
return check_call( cmd.split( ' ' ) )
|
||||
|
||||
# pylint doesn't understand explicit type checking
|
||||
# pylint: disable-msg=E1103
|
||||
|
||||
def quietRun( *cmd ):
|
||||
"""Run a command, routing stderr to stdout, and return the output.
|
||||
cmd: list of command params"""
|
||||
@@ -42,6 +47,22 @@ def quietRun( *cmd ):
|
||||
break
|
||||
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
|
||||
#
|
||||
# Interfaces are managed as strings which are simply the
|
||||
@@ -78,7 +99,7 @@ def retry( retries, delaySecs, fn, *args, **keywords ):
|
||||
sleep( delaySecs )
|
||||
tries += 1
|
||||
if tries >= retries:
|
||||
lg.error( "*** gave up after %i retries\n" % tries )
|
||||
error( "*** gave up after %i retries\n" % tries )
|
||||
exit( 1 )
|
||||
|
||||
def moveIntfNoRetry( intf, node, printError=False ):
|
||||
@@ -91,7 +112,7 @@ def moveIntfNoRetry( intf, node, printError=False ):
|
||||
links = node.cmd( 'ip link show' )
|
||||
if not ( ' %s:' % intf ) in links:
|
||||
if printError:
|
||||
lg.error( '*** Error: moveIntf: ' + intf +
|
||||
error( '*** Error: moveIntf: ' + intf +
|
||||
' not successfully moved to ' + node.name + '\n' )
|
||||
return False
|
||||
return True
|
||||
@@ -112,10 +133,8 @@ def createLink( node1, node2, port1=None, port2=None ):
|
||||
returns: intf1 name, intf2 name"""
|
||||
return node1.linkTo( node2, port1, port2 )
|
||||
|
||||
def fixLimits():
|
||||
"Fix ridiculously small resource limits."
|
||||
setrlimit( RLIMIT_NPROC, ( 4096, 8192 ) )
|
||||
setrlimit( RLIMIT_NOFILE, ( 16384, 32768 ) )
|
||||
|
||||
# IP and Mac address formatting and parsing
|
||||
|
||||
def _colonHex( val, bytes ):
|
||||
"""Generate colon-hex string.
|
||||
@@ -181,17 +200,10 @@ def makeNumeric( s ):
|
||||
else:
|
||||
return s
|
||||
|
||||
# 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
|
||||
# Other stuff we use
|
||||
|
||||
isShellBuiltin.builtIns = None
|
||||
|
||||
# pylint: enable-msg=E1101,W0612
|
||||
def fixLimits():
|
||||
"Fix ridiculously small resource limits."
|
||||
setrlimit( RLIMIT_NPROC, ( 4096, 8192 ) )
|
||||
setrlimit( RLIMIT_NOFILE, ( 16384, 32768 ) )
|
||||
|
||||
Reference in New Issue
Block a user