Pass pylint.
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
+70
-65
@@ -10,7 +10,7 @@ We monitor nodes in a couple of ways:
|
|||||||
|
|
||||||
- First, each individual node is monitored, and its output is added
|
- First, each individual node is monitored, and its output is added
|
||||||
to its console window
|
to its console window
|
||||||
|
|
||||||
- Second, each time a console window gets iperf output, it is parsed
|
- Second, each time a console window gets iperf output, it is parsed
|
||||||
and accumulated. Once we have output for all consoles, a bar is
|
and accumulated. Once we have output for all consoles, a bar is
|
||||||
added to the bandwidth graph.
|
added to the bandwidth graph.
|
||||||
@@ -36,7 +36,7 @@ from mininet.util import quietRun
|
|||||||
|
|
||||||
class Console( Frame ):
|
class Console( Frame ):
|
||||||
"A simple console on a host."
|
"A simple console on a host."
|
||||||
|
|
||||||
def __init__( self, parent, net, node, height=10, width=32, title='Node' ):
|
def __init__( self, parent, net, node, height=10, width=32, title='Node' ):
|
||||||
Frame.__init__( self, parent )
|
Frame.__init__( self, parent )
|
||||||
|
|
||||||
@@ -44,10 +44,10 @@ class Console( Frame ):
|
|||||||
self.node = node
|
self.node = node
|
||||||
self.prompt = node.name + '# '
|
self.prompt = node.name + '# '
|
||||||
self.height, self.width, self.title = height, width, title
|
self.height, self.width, self.title = height, width, title
|
||||||
|
|
||||||
# Initialize widget styles
|
# Initialize widget styles
|
||||||
self.buttonStyle = { 'font': 'Monaco 7' }
|
self.buttonStyle = { 'font': 'Monaco 7' }
|
||||||
self.textStyle = {
|
self.textStyle = {
|
||||||
'font': 'Monaco 7',
|
'font': 'Monaco 7',
|
||||||
'bg': 'black',
|
'bg': 'black',
|
||||||
'fg': 'green',
|
'fg': 'green',
|
||||||
@@ -58,22 +58,22 @@ class Console( Frame ):
|
|||||||
'highlightcolor': 'green',
|
'highlightcolor': 'green',
|
||||||
'selectforeground': 'black',
|
'selectforeground': 'black',
|
||||||
'selectbackground': 'green'
|
'selectbackground': 'green'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set up widgets
|
# Set up widgets
|
||||||
self.text = self.makeWidgets( )
|
self.text = self.makeWidgets( )
|
||||||
self.bindEvents()
|
self.bindEvents()
|
||||||
self.sendCmd( 'export TERM=dumb' )
|
self.sendCmd( 'export TERM=dumb' )
|
||||||
|
|
||||||
self.outputHook = None
|
self.outputHook = None
|
||||||
|
|
||||||
def makeWidgets( self ):
|
def makeWidgets( self ):
|
||||||
"Make a label, a text area, and a scroll bar."
|
"Make a label, a text area, and a scroll bar."
|
||||||
|
|
||||||
def newTerm( net=self.net, node=self.node, title=self.title ):
|
def newTerm( net=self.net, node=self.node, title=self.title ):
|
||||||
"Pop up a new terminal window for a node."
|
"Pop up a new terminal window for a node."
|
||||||
net.terms += makeTerms( [ node ], title )
|
net.terms += makeTerms( [ node ], title )
|
||||||
label = Button( self, text=self.node.name, command=newTerm,
|
label = Button( self, text=self.node.name, command=newTerm,
|
||||||
**self.buttonStyle )
|
**self.buttonStyle )
|
||||||
label.pack( side='top', fill='x' )
|
label.pack( side='top', fill='x' )
|
||||||
text = Text( self, wrap='word', **self.textStyle )
|
text = Text( self, wrap='word', **self.textStyle )
|
||||||
@@ -99,7 +99,7 @@ class Console( Frame ):
|
|||||||
# We're not a terminal (yet?), so we ignore the following
|
# We're not a terminal (yet?), so we ignore the following
|
||||||
# control characters other than [\b\n\r]
|
# control characters other than [\b\n\r]
|
||||||
ignoreChars = re.compile( r'[\x00-\x07\x09\x0b\x0c\x0e-\x1f]+' )
|
ignoreChars = re.compile( r'[\x00-\x07\x09\x0b\x0c\x0e-\x1f]+' )
|
||||||
|
|
||||||
def append( self, text ):
|
def append( self, text ):
|
||||||
"Append something to our text frame."
|
"Append something to our text frame."
|
||||||
text = self.ignoreChars.sub( '', text )
|
text = self.ignoreChars.sub( '', text )
|
||||||
@@ -114,7 +114,7 @@ class Console( Frame ):
|
|||||||
char = event.char
|
char = event.char
|
||||||
if self.node.waiting:
|
if self.node.waiting:
|
||||||
self.node.write( char )
|
self.node.write( char )
|
||||||
|
|
||||||
def handleReturn( self, event ):
|
def handleReturn( self, event ):
|
||||||
"Handle a carriage return."
|
"Handle a carriage return."
|
||||||
cmd = self.text.get( 'insert linestart', 'insert lineend' )
|
cmd = self.text.get( 'insert linestart', 'insert lineend' )
|
||||||
@@ -127,24 +127,29 @@ class Console( Frame ):
|
|||||||
if pos >= 0:
|
if pos >= 0:
|
||||||
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?"
|
||||||
@@ -161,17 +166,17 @@ class Console( Frame ):
|
|||||||
"Clear all of our text."
|
"Clear all of our text."
|
||||||
self.text.delete( '1.0', 'end' )
|
self.text.delete( '1.0', 'end' )
|
||||||
|
|
||||||
|
|
||||||
class Graph( Frame ):
|
class Graph( Frame ):
|
||||||
|
|
||||||
"Graph that we can add bars to over time."
|
"Graph that we can add bars to over time."
|
||||||
|
|
||||||
def __init__( self, parent=None,
|
def __init__( self, parent=None,
|
||||||
bg = 'white',
|
bg = 'white',
|
||||||
gheight=200, gwidth=500,
|
gheight=200, gwidth=500,
|
||||||
barwidth=10,
|
barwidth=10,
|
||||||
ymax=3.5,):
|
ymax=3.5,):
|
||||||
|
|
||||||
Frame.__init__( self, parent )
|
Frame.__init__( self, parent )
|
||||||
|
|
||||||
self.bg = bg
|
self.bg = bg
|
||||||
@@ -182,57 +187,55 @@ 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 ):
|
||||||
"Update graph and scale scroll regions."
|
"Update graph and scale scroll regions."
|
||||||
ofs = 20
|
ofs = 20
|
||||||
height = self.gheight + ofs
|
height = self.gheight + ofs
|
||||||
self.graph.configure( scrollregion=( 0, -ofs,
|
self.graph.configure( scrollregion=( 0, -ofs,
|
||||||
self.xpos * self.barwidth, height ) )
|
self.xpos * self.barwidth, height ) )
|
||||||
self.scale.configure( scrollregion=( 0, -ofs, 0, height ) )
|
self.scale.configure( scrollregion=( 0, -ofs, 0, height ) )
|
||||||
|
|
||||||
def yview( self, *args ):
|
def yview( self, *args ):
|
||||||
"Scroll both scale and graph."
|
"Scroll both scale and graph."
|
||||||
self.graph.yview( *args )
|
self.graph.yview( *args )
|
||||||
self.scale.yview( *args )
|
self.scale.yview( *args )
|
||||||
|
|
||||||
def createWidgets( self ):
|
def createWidgets( self ):
|
||||||
"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 )
|
||||||
graph.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set,
|
graph.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set,
|
||||||
scrollregion=(0, 0, width, height ) )
|
scrollregion=(0, 0, width, height ) )
|
||||||
scale.configure( yscrollcommand=ybar.set )
|
scale.configure( yscrollcommand=ybar.set )
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
title.grid( row=0, columnspan=3, sticky='new')
|
title.grid( row=0, columnspan=3, sticky='new')
|
||||||
scale.grid( row=1, column=0, sticky='nsew' )
|
scale.grid( row=1, column=0, sticky='nsew' )
|
||||||
@@ -241,12 +244,8 @@ 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."
|
||||||
percent = yval / self.ymax
|
percent = yval / self.ymax
|
||||||
@@ -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 ):
|
||||||
@@ -289,14 +290,14 @@ class ConsoleApp( Frame ):
|
|||||||
self.menubar = self.createMenuBar()
|
self.menubar = self.createMenuBar()
|
||||||
cframe = self.cframe = Frame( self )
|
cframe = self.cframe = Frame( self )
|
||||||
self.consoles = {} # consoles themselves
|
self.consoles = {} # consoles themselves
|
||||||
titles = {
|
titles = {
|
||||||
'hosts': 'Host',
|
'hosts': 'Host',
|
||||||
'switches': 'Switch',
|
'switches': 'Switch',
|
||||||
'controllers': 'Controller'
|
'controllers': 'Controller'
|
||||||
}
|
}
|
||||||
for name in titles:
|
for name in titles:
|
||||||
nodes = getattr( net, name )
|
nodes = getattr( net, name )
|
||||||
frame, consoles = self.createConsoles(
|
frame, consoles = self.createConsoles(
|
||||||
cframe, nodes, width, titles[ name ] )
|
cframe, nodes, width, titles[ name ] )
|
||||||
self.consoles[ name ] = Object( frame=frame, consoles=consoles )
|
self.consoles[ name ] = Object( frame=frame, consoles=consoles )
|
||||||
self.selected = None
|
self.selected = None
|
||||||
@@ -305,7 +306,7 @@ class ConsoleApp( Frame ):
|
|||||||
cleanUpScreens()
|
cleanUpScreens()
|
||||||
# Close window gracefully
|
# Close window gracefully
|
||||||
Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
|
Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
|
||||||
|
|
||||||
# Initialize graph
|
# Initialize graph
|
||||||
graph = Graph( cframe )
|
graph = Graph( cframe )
|
||||||
self.consoles[ 'graph' ] = Object( frame=graph, consoles=[ graph ] )
|
self.consoles[ 'graph' ] = Object( frame=graph, consoles=[ graph ] )
|
||||||
@@ -316,7 +317,9 @@ class ConsoleApp( Frame ):
|
|||||||
self.bw = 0
|
self.bw = 0
|
||||||
|
|
||||||
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,13 +331,15 @@ 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:
|
||||||
console.outputHook = fn
|
console.outputHook = fn
|
||||||
|
|
||||||
def createConsoles( self, parent, nodes, width, title ):
|
def createConsoles( self, parent, nodes, width, title ):
|
||||||
"Create a grid of consoles in a frame."
|
"Create a grid of consoles in a frame."
|
||||||
f = Frame( parent )
|
f = Frame( parent )
|
||||||
@@ -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
|
||||||
@@ -351,12 +356,12 @@ class ConsoleApp( Frame ):
|
|||||||
f.rowconfigure( row, weight=1 )
|
f.rowconfigure( row, weight=1 )
|
||||||
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 ):
|
||||||
@@ -365,8 +370,8 @@ class ConsoleApp( Frame ):
|
|||||||
buttons = [
|
buttons = [
|
||||||
( 'Hosts', lambda: self.select( 'hosts' ) ),
|
( 'Hosts', lambda: self.select( 'hosts' ) ),
|
||||||
( 'Switches', lambda: self.select( 'switches' ) ),
|
( 'Switches', lambda: self.select( 'switches' ) ),
|
||||||
( 'Controllers', lambda: self.select( 'controllers' ) ),
|
( 'Controllers', lambda: self.select( 'controllers' ) ),
|
||||||
( 'Graph', lambda: self.select( 'graph' ) ),
|
( 'Graph', lambda: self.select( 'graph' ) ),
|
||||||
( 'Ping', self.ping ),
|
( 'Ping', self.ping ),
|
||||||
( 'Iperf', self.iperf ),
|
( 'Iperf', self.iperf ),
|
||||||
( 'Interrupt', self.stop ),
|
( 'Interrupt', self.stop ),
|
||||||
@@ -378,12 +383,12 @@ class ConsoleApp( Frame ):
|
|||||||
b.pack( side='left' )
|
b.pack( side='left' )
|
||||||
f.pack( padx=4, pady=4, fill='x' )
|
f.pack( padx=4, pady=4, fill='x' )
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def clear( self ):
|
def clear( self ):
|
||||||
"Clear selection."
|
"Clear selection."
|
||||||
for console in self.selected.consoles:
|
for console in self.selected.consoles:
|
||||||
console.clear()
|
console.clear()
|
||||||
|
|
||||||
def waiting( self, consoles=None ):
|
def waiting( self, consoles=None ):
|
||||||
"Are any of our hosts waiting for output?"
|
"Are any of our hosts waiting for output?"
|
||||||
if consoles is None:
|
if consoles is None:
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This example shows how to create an empty Mininet object
|
This example shows how to create an empty Mininet object
|
||||||
(without a topology object) and add nodes to it manually.
|
(without a topology object) and add nodes to it manually.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -13,32 +13,32 @@ from mininet.log import setLogLevel, info
|
|||||||
def emptyNet():
|
def emptyNet():
|
||||||
|
|
||||||
"Create an empty network and add nodes to it."
|
"Create an empty network and add nodes to it."
|
||||||
|
|
||||||
net = Mininet( controller=Controller )
|
net = Mininet( controller=Controller )
|
||||||
|
|
||||||
info( '*** Adding controller\n' )
|
info( '*** Adding controller\n' )
|
||||||
net.addController( 'c0' )
|
net.addController( 'c0' )
|
||||||
|
|
||||||
info( '*** Adding hosts\n' )
|
info( '*** Adding hosts\n' )
|
||||||
h1 = net.addHost( 'h1', ip='10.0.0.1' )
|
h1 = net.addHost( 'h1', ip='10.0.0.1' )
|
||||||
h2 = net.addHost( 'h2', ip='10.0.0.2' )
|
h2 = net.addHost( 'h2', ip='10.0.0.2' )
|
||||||
|
|
||||||
info( '*** Adding switch\n' )
|
info( '*** Adding switch\n' )
|
||||||
s3 = net.addSwitch( 's3' )
|
s3 = net.addSwitch( 's3' )
|
||||||
|
|
||||||
info( '*** Creating links\n' )
|
info( '*** Creating links\n' )
|
||||||
h1.linkTo( s3 )
|
h1.linkTo( s3 )
|
||||||
h2.linkTo( s3 )
|
h2.linkTo( s3 )
|
||||||
|
|
||||||
info( '*** Starting network\n')
|
info( '*** Starting network\n')
|
||||||
net.start()
|
net.start()
|
||||||
|
|
||||||
info( '*** Running CLI\n' )
|
info( '*** Running CLI\n' )
|
||||||
CLI( net )
|
CLI( net )
|
||||||
|
|
||||||
info( '*** Stopping network' )
|
info( '*** Stopping network' )
|
||||||
net.stop()
|
net.stop()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
setLogLevel( 'info' )
|
setLogLevel( 'info' )
|
||||||
emptyNet()
|
emptyNet()
|
||||||
|
|||||||
+223
-177
@@ -24,9 +24,9 @@ from mininet.term import makeTerm, cleanUpScreens
|
|||||||
class MiniEdit( Frame ):
|
class MiniEdit( Frame ):
|
||||||
|
|
||||||
"A simple network editor for Mininet."
|
"A simple network editor for Mininet."
|
||||||
|
|
||||||
def __init__( self, parent=None, cheight=200, cwidth=500 ):
|
def __init__( self, parent=None, cheight=200, cwidth=500 ):
|
||||||
|
|
||||||
Frame.__init__( self, parent )
|
Frame.__init__( self, parent )
|
||||||
self.action = None
|
self.action = None
|
||||||
self.appName = 'MiniEdit'
|
self.appName = 'MiniEdit'
|
||||||
@@ -39,19 +39,19 @@ class MiniEdit( Frame ):
|
|||||||
# Title
|
# Title
|
||||||
self.top = self.winfo_toplevel()
|
self.top = self.winfo_toplevel()
|
||||||
self.top.title( self.appName )
|
self.top.title( self.appName )
|
||||||
|
|
||||||
# Menu bar
|
# Menu bar
|
||||||
self.createMenubar()
|
self.createMenubar()
|
||||||
|
|
||||||
# Editing canvas
|
# Editing canvas
|
||||||
self.cheight, self.cwidth = cheight, cwidth
|
self.cheight, self.cwidth = cheight, cwidth
|
||||||
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()
|
||||||
|
|
||||||
@@ -61,49 +61,53 @@ class MiniEdit( Frame ):
|
|||||||
self.columnconfigure( 1, weight=1 )
|
self.columnconfigure( 1, weight=1 )
|
||||||
self.rowconfigure( 0, weight=1 )
|
self.rowconfigure( 0, weight=1 )
|
||||||
self.pack( expand=True, fill='both' )
|
self.pack( expand=True, fill='both' )
|
||||||
|
|
||||||
# About box
|
# About box
|
||||||
self.aboutBox = None
|
self.aboutBox = None
|
||||||
|
|
||||||
# Initialize node data
|
# Initialize node data
|
||||||
self.nodeBindings = self.createNodeBindings()
|
self.nodeBindings = self.createNodeBindings()
|
||||||
self.nodePrefixes = { 'Switch': 's', 'Host': 'h' }
|
self.nodePrefixes = { 'Switch': 's', 'Host': 'h' }
|
||||||
self.widgetToItem = {}
|
self.widgetToItem = {}
|
||||||
self.itemToWidget = {}
|
self.itemToWidget = {}
|
||||||
|
|
||||||
# Initialize link tool
|
# Initialize link tool
|
||||||
self.link = self.linkWidget = None
|
self.link = self.linkWidget = None
|
||||||
|
|
||||||
# Selection support
|
# Selection support
|
||||||
self.selection = None
|
self.selection = None
|
||||||
|
|
||||||
# Keyboard bindings
|
# Keyboard bindings
|
||||||
self.bind( '<Control-q>', lambda event: self.quit() )
|
self.bind( '<Control-q>', lambda event: self.quit() )
|
||||||
self.bind( '<KeyPress-Delete>', self.deleteSelection )
|
self.bind( '<KeyPress-Delete>', self.deleteSelection )
|
||||||
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
|
||||||
self.net = None
|
self.net = None
|
||||||
|
|
||||||
# Close window gracefully
|
# Close window gracefully
|
||||||
Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
|
Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
|
||||||
|
|
||||||
def quit( self ):
|
def quit( self ):
|
||||||
"Stop our network, if any, then quit."
|
"Stop our network, if any, then quit."
|
||||||
self.stop()
|
self.stop()
|
||||||
Frame.quit( self )
|
Frame.quit( self )
|
||||||
|
|
||||||
def createMenubar( self ):
|
def createMenubar( self ):
|
||||||
"Create our menu bar."
|
"Create our menu bar."
|
||||||
|
|
||||||
font = self.font
|
font = self.font
|
||||||
|
|
||||||
mbar = Menu( self.top, font=font )
|
mbar = Menu( self.top, font=font )
|
||||||
self.top.configure( menu=mbar )
|
self.top.configure( menu=mbar )
|
||||||
|
|
||||||
# Application menu
|
# Application menu
|
||||||
appMenu = Menu( mbar, tearoff=False )
|
appMenu = Menu( mbar, tearoff=False )
|
||||||
mbar.add_cascade( label=self.appName, font=font, menu=appMenu )
|
mbar.add_cascade( label=self.appName, font=font, menu=appMenu )
|
||||||
@@ -111,20 +115,18 @@ class MiniEdit( Frame ):
|
|||||||
font=font)
|
font=font)
|
||||||
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 )
|
||||||
editMenu.add_command( label="Cut", font=font,
|
editMenu.add_command( label="Cut", font=font,
|
||||||
command=lambda: self.deleteSelection( None ) )
|
command=lambda: self.deleteSelection( None ) )
|
||||||
|
|
||||||
runMenu = Menu( mbar, tearoff=False )
|
runMenu = Menu( mbar, tearoff=False )
|
||||||
@@ -135,28 +137,28 @@ class MiniEdit( Frame ):
|
|||||||
runMenu.add_command( label='Xterm', font=font, command=self.xterm )
|
runMenu.add_command( label='Xterm', font=font, command=self.xterm )
|
||||||
|
|
||||||
# Canvas
|
# Canvas
|
||||||
|
|
||||||
def createCanvas( self ):
|
def createCanvas( self ):
|
||||||
"Create and return our scrolling canvas frame."
|
"Create and return our scrolling canvas frame."
|
||||||
f = Frame( self )
|
f = Frame( self )
|
||||||
|
|
||||||
canvas = Canvas( f, width=self.cwidth, height=self.cheight,
|
canvas = Canvas( f, width=self.cwidth, height=self.cheight,
|
||||||
bg=self.bg )
|
bg=self.bg )
|
||||||
|
|
||||||
# Scroll bars
|
# Scroll bars
|
||||||
xbar = Scrollbar( f, orient='horizontal', command=canvas.xview )
|
xbar = Scrollbar( f, orient='horizontal', command=canvas.xview )
|
||||||
ybar = Scrollbar( f, orient='vertical', command=canvas.yview )
|
ybar = Scrollbar( f, orient='vertical', command=canvas.yview )
|
||||||
canvas.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set )
|
canvas.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set )
|
||||||
|
|
||||||
# Resize box
|
# Resize box
|
||||||
resize = Label( f, bg='white' )
|
resize = Label( f, bg='white' )
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
canvas.grid( row=0, column=1, sticky='nsew')
|
canvas.grid( row=0, column=1, sticky='nsew')
|
||||||
ybar.grid( row=0, column=2, sticky='ns')
|
ybar.grid( row=0, column=2, sticky='ns')
|
||||||
xbar.grid( row=1, column=1, sticky='ew' )
|
xbar.grid( row=1, column=1, sticky='ew' )
|
||||||
resize.grid( row=1, column=2, sticky='nsew' )
|
resize.grid( row=1, column=2, sticky='nsew' )
|
||||||
|
|
||||||
# Resize behavior
|
# Resize behavior
|
||||||
f.rowconfigure( 0, weight=1 )
|
f.rowconfigure( 0, weight=1 )
|
||||||
f.columnconfigure( 1, weight=1 )
|
f.columnconfigure( 1, weight=1 )
|
||||||
@@ -167,7 +169,7 @@ class MiniEdit( Frame ):
|
|||||||
canvas.bind( '<ButtonPress-1>', self.clickCanvas )
|
canvas.bind( '<ButtonPress-1>', self.clickCanvas )
|
||||||
canvas.bind( '<B1-Motion>', self.dragCanvas )
|
canvas.bind( '<B1-Motion>', self.dragCanvas )
|
||||||
canvas.bind( '<ButtonRelease-1>', self.releaseCanvas )
|
canvas.bind( '<ButtonRelease-1>', self.releaseCanvas )
|
||||||
|
|
||||||
return f, canvas
|
return f, canvas
|
||||||
|
|
||||||
def updateScrollRegion( self ):
|
def updateScrollRegion( self ):
|
||||||
@@ -175,75 +177,76 @@ class MiniEdit( Frame ):
|
|||||||
bbox = self.canvas.bbox( 'all' )
|
bbox = self.canvas.bbox( 'all' )
|
||||||
if bbox is not None:
|
if bbox is not None:
|
||||||
self.canvas.configure( scrollregion=( 0, 0, bbox[ 2 ], bbox[ 3 ] ) )
|
self.canvas.configure( scrollregion=( 0, 0, bbox[ 2 ], bbox[ 3 ] ) )
|
||||||
|
|
||||||
def canvasx( self, x_root ):
|
def canvasx( self, x_root ):
|
||||||
"Convert root x coordinate to canvas coordinate."
|
"Convert root x coordinate to canvas coordinate."
|
||||||
c = self.canvas
|
c = self.canvas
|
||||||
return c.canvasx( x_root ) - c.winfo_rootx()
|
return c.canvasx( x_root ) - c.winfo_rootx()
|
||||||
|
|
||||||
def canvasy( self, y_root ):
|
def canvasy( self, y_root ):
|
||||||
"Convert root y coordinate to canvas coordinate."
|
"Convert root y coordinate to canvas coordinate."
|
||||||
c = self.canvas
|
c = self.canvas
|
||||||
return c.canvasy( y_root ) - c.winfo_rooty()
|
return c.canvasy( y_root ) - c.winfo_rooty()
|
||||||
|
|
||||||
# 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' )
|
||||||
self.buttons[ toolName ].configure( relief='sunken' )
|
self.buttons[ toolName ].configure( relief='sunken' )
|
||||||
# Activate dynamic bindings
|
# Activate dynamic bindings
|
||||||
self.active = toolName
|
self.active = toolName
|
||||||
|
|
||||||
def createToolbar( self ):
|
def createToolbar( self ):
|
||||||
"Create and return our toolbar frame."
|
"Create and return our toolbar frame."
|
||||||
|
|
||||||
toolbar = Frame( self )
|
toolbar = Frame( self )
|
||||||
|
|
||||||
# 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 ] )
|
||||||
# b.config( compound='top' )
|
# b.config( compound='top' )
|
||||||
b.pack( fill='x' )
|
b.pack( fill='x' )
|
||||||
self.buttons[ tool ] = b
|
self.buttons[ tool ] = b
|
||||||
self.activate( self.tools[ 0 ] )
|
self.activate( self.tools[ 0 ] )
|
||||||
|
|
||||||
# Spacer
|
# Spacer
|
||||||
Label( toolbar, text='' ).pack()
|
Label( toolbar, text='' ).pack()
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
def doRun( self ):
|
def doRun( self ):
|
||||||
"Run command."
|
"Run command."
|
||||||
self.activate( 'Select' )
|
self.activate( 'Select' )
|
||||||
for tool in self.tools:
|
for tool in self.tools:
|
||||||
self.buttons[ tool ].config( state='disabled' )
|
self.buttons[ tool ].config( state='disabled' )
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def doStop( self ):
|
def doStop( self ):
|
||||||
"Stop command."
|
"Stop command."
|
||||||
self.stop()
|
self.stop()
|
||||||
for tool in self.tools:
|
for tool in self.tools:
|
||||||
self.buttons[ tool ].config( state='normal' )
|
self.buttons[ tool ].config( state='normal' )
|
||||||
|
|
||||||
# Generic canvas handler
|
# Generic canvas handler
|
||||||
#
|
#
|
||||||
# We could have used bindtags, as in nodeIcon, but
|
# We could have used bindtags, as in nodeIcon, but
|
||||||
# the dynamic approach used here
|
# the dynamic approach used here
|
||||||
# may actually require less code. In any case, it's an
|
# may actually require less code. In any case, it's an
|
||||||
# interesting introspection-based alternative to bindtags.
|
# interesting introspection-based alternative to bindtags.
|
||||||
|
|
||||||
def canvasHandle( self, eventName, event ):
|
def canvasHandle( self, eventName, event ):
|
||||||
"Generic canvas event handler"
|
"Generic canvas event handler"
|
||||||
if self.active is None:
|
if self.active is None:
|
||||||
@@ -252,36 +255,36 @@ class MiniEdit( Frame ):
|
|||||||
handler = getattr( self, eventName + toolName, None )
|
handler = getattr( self, eventName + toolName, None )
|
||||||
if handler is not None:
|
if handler is not None:
|
||||||
handler( event )
|
handler( event )
|
||||||
|
|
||||||
def clickCanvas( self, event ):
|
def clickCanvas( self, event ):
|
||||||
"Canvas click handler."
|
"Canvas click handler."
|
||||||
self.canvasHandle( 'click', event )
|
self.canvasHandle( 'click', event )
|
||||||
|
|
||||||
def dragCanvas( self, event ):
|
def dragCanvas( self, event ):
|
||||||
"Canvas drag handler."
|
"Canvas drag handler."
|
||||||
self.canvasHandle( 'drag', event )
|
self.canvasHandle( 'drag', event )
|
||||||
|
|
||||||
def releaseCanvas( self, event ):
|
def releaseCanvas( self, event ):
|
||||||
"Canvas mouse up handler."
|
"Canvas mouse up handler."
|
||||||
self.canvasHandle( 'release', event )
|
self.canvasHandle( 'release', event )
|
||||||
|
|
||||||
# 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
|
||||||
else:
|
else:
|
||||||
return items[ 0 ]
|
return items[ 0 ]
|
||||||
|
|
||||||
# Canvas bindings for Select, Host, Switch and Link tools
|
# Canvas bindings for Select, Host, Switch and Link tools
|
||||||
|
|
||||||
def clickSelect( self, event ):
|
def clickSelect( self, event ):
|
||||||
"Select an item."
|
"Select an item."
|
||||||
self.selectItem( self.findItem( event.x, event.y ) )
|
self.selectItem( self.findItem( event.x, event.y ) )
|
||||||
|
|
||||||
def deleteItem( self, item ):
|
def deleteItem( self, item ):
|
||||||
"Delete an item."
|
"Delete an item."
|
||||||
# Don't delete while network is running
|
# Don't delete while network is running
|
||||||
@@ -293,23 +296,27 @@ class MiniEdit( Frame ):
|
|||||||
if item in self.itemToWidget:
|
if item in self.itemToWidget:
|
||||||
self.deleteNode( item )
|
self.deleteNode( item )
|
||||||
# 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."
|
||||||
icon = Button( self.canvas, image=self.images[ node ],
|
icon = Button( self.canvas, image=self.images[ node ],
|
||||||
text=name, compound='top' )
|
text=name, compound='top' )
|
||||||
# Unfortunately bindtags wants a tuple
|
# Unfortunately bindtags wants a tuple
|
||||||
bindtags = [ str( self.nodeBindings ) ]
|
bindtags = [ str( self.nodeBindings ) ]
|
||||||
bindtags += list( icon.bindtags() )
|
bindtags += list( icon.bindtags() )
|
||||||
icon.bindtags( tuple( bindtags ) )
|
icon.bindtags( tuple( bindtags ) )
|
||||||
return icon
|
return icon
|
||||||
|
|
||||||
def newNode( self, node, event ):
|
def newNode( self, node, event ):
|
||||||
"Add a new node to our canvas."
|
"Add a new node to our canvas."
|
||||||
c = self.canvas
|
c = self.canvas
|
||||||
@@ -317,12 +324,13 @@ 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 )
|
||||||
icon.links = {}
|
icon.links = {}
|
||||||
|
|
||||||
def clickHost( self, event ):
|
def clickHost( self, event ):
|
||||||
"Add a new host to our canvas."
|
"Add a new host to our canvas."
|
||||||
self.newNode( 'Host', event )
|
self.newNode( 'Host', event )
|
||||||
@@ -330,7 +338,7 @@ class MiniEdit( Frame ):
|
|||||||
def clickSwitch( self, event ):
|
def clickSwitch( self, event ):
|
||||||
"Add a new switch to our canvas."
|
"Add a new switch to our canvas."
|
||||||
self.newNode( 'Switch', event )
|
self.newNode( 'Switch', event )
|
||||||
|
|
||||||
def dragLink( self, event ):
|
def dragLink( self, event ):
|
||||||
"Drag a link's endpoint to another node."
|
"Drag a link's endpoint to another node."
|
||||||
if self.link is None:
|
if self.link is None:
|
||||||
@@ -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."
|
||||||
@@ -383,26 +398,26 @@ class MiniEdit( Frame ):
|
|||||||
else:
|
else:
|
||||||
self.selectNode( event )
|
self.selectNode( event )
|
||||||
return 'break'
|
return 'break'
|
||||||
|
|
||||||
def dragNode( self, event ):
|
def dragNode( self, event ):
|
||||||
"Node drag handler."
|
"Node drag handler."
|
||||||
if self.active is 'Link':
|
if self.active is 'Link':
|
||||||
self.dragLink( event )
|
self.dragLink( event )
|
||||||
else:
|
else:
|
||||||
self.dragNodeAround( event )
|
self.dragNodeAround( event )
|
||||||
|
|
||||||
def releaseNode( self, event ):
|
def releaseNode( self, event ):
|
||||||
"Node release handler."
|
"Node release handler."
|
||||||
if self.active is 'Link':
|
if self.active is 'Link':
|
||||||
self.finishLink( event )
|
self.finishLink( event )
|
||||||
|
|
||||||
# Specific node handlers
|
# Specific node handlers
|
||||||
|
|
||||||
def selectNode( self, event ):
|
def selectNode( self, event ):
|
||||||
"Select the node that was clicked on."
|
"Select the node that was clicked on."
|
||||||
item = self.widgetToItem.get( event.widget, None )
|
item = self.widgetToItem.get( event.widget, None )
|
||||||
self.selectItem( item )
|
self.selectItem( item )
|
||||||
|
|
||||||
def dragNodeAround( self, event ):
|
def dragNodeAround( self, event ):
|
||||||
"Drag a node around on the canvas."
|
"Drag a node around on the canvas."
|
||||||
c = self.canvas
|
c = self.canvas
|
||||||
@@ -429,25 +444,31 @@ class MiniEdit( Frame ):
|
|||||||
w = event.widget
|
w = event.widget
|
||||||
item = self.widgetToItem[ w ]
|
item = self.widgetToItem[ w ]
|
||||||
x, y = self.canvas.coords( item )
|
x, y = self.canvas.coords( item )
|
||||||
self.link = self.canvas.create_line( x, y, x, y, width=4,
|
self.link = self.canvas.create_line( x, y, x, y, width=4,
|
||||||
fill='blue', tag='link' )
|
fill='blue', tag='link' )
|
||||||
self.linkx, self.linky = x, y
|
self.linkx, self.linky = x, y
|
||||||
self.linkWidget = w
|
self.linkWidget = w
|
||||||
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 )
|
||||||
|
|
||||||
def finishLink( self, event ):
|
def finishLink( self, event ):
|
||||||
"Finish creating a link"
|
"Finish creating a link"
|
||||||
if self.link is None:
|
if self.link is None:
|
||||||
@@ -471,13 +492,11 @@ 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
|
||||||
|
|
||||||
# Menu handlers
|
# Menu handlers
|
||||||
|
|
||||||
def about( self ):
|
def about( self ):
|
||||||
"Display about box."
|
"Display about box."
|
||||||
about = self.aboutBox
|
about = self.aboutBox
|
||||||
@@ -494,28 +513,28 @@ 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 )
|
||||||
# Show (existing) window
|
# Show (existing) window
|
||||||
about.deiconify()
|
about.deiconify()
|
||||||
|
|
||||||
|
|
||||||
def createToolImages( self ):
|
def createToolImages( self ):
|
||||||
"Create toolbar (and icon) images."
|
"Create toolbar (and icon) images."
|
||||||
|
|
||||||
# Model interface
|
# Model interface
|
||||||
#
|
#
|
||||||
# Ultimately we will either want to use a topo or
|
# Ultimately we will either want to use a topo or
|
||||||
# mininet object here, probably.
|
# mininet object here, probably.
|
||||||
|
|
||||||
def addLink( self, source, dest ):
|
def addLink( self, source, dest ):
|
||||||
"Add link to model."
|
"Add link to model."
|
||||||
source.links[ dest ] = self.link
|
source.links[ dest ] = self.link
|
||||||
dest.links[ source ] = self.link
|
dest.links[ source ] = self.link
|
||||||
self.links[ self.link ] = ( source, dest )
|
self.links[ self.link ] = ( source, dest )
|
||||||
|
|
||||||
def deleteLink( self, link ):
|
def deleteLink( self, link ):
|
||||||
"Delete link from model."
|
"Delete link from model."
|
||||||
pair = self.links.get( link, None )
|
pair = self.links.get( link, None )
|
||||||
@@ -539,7 +558,7 @@ class MiniEdit( Frame ):
|
|||||||
"Build network based on our topology."
|
"Build network based on our topology."
|
||||||
|
|
||||||
net = Mininet( topo=None )
|
net = Mininet( topo=None )
|
||||||
|
|
||||||
# Make controller
|
# Make controller
|
||||||
net.addController( 'c0' )
|
net.addController( 'c0' )
|
||||||
# Make nodes
|
# Make nodes
|
||||||
@@ -559,24 +578,26 @@ class MiniEdit( Frame ):
|
|||||||
srcName, dstName = src[ 'text' ], dst[ 'text' ]
|
srcName, dstName = src[ 'text' ], dst[ 'text' ]
|
||||||
src, dst = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
|
src, dst = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
|
||||||
src.linkTo( dst )
|
src.linkTo( dst )
|
||||||
|
|
||||||
# Build network (we have to do this separately at the moment )
|
# Build network (we have to do this separately at the moment )
|
||||||
net.build()
|
net.build()
|
||||||
|
|
||||||
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,83 +605,108 @@ 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 ):
|
|
||||||
"Initialize button/icon images."
|
def miniEditImages():
|
||||||
images = {}
|
"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
|
||||||
images[ 'Host' ] = PhotoImage( data=r"""
|
# unappealing.
|
||||||
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=""" )
|
|
||||||
|
|
||||||
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
|
|
||||||
""" )
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
'Select': BitmapImage(
|
||||||
|
file='/usr/include/X11/bitmaps/left_ptr' ),
|
||||||
|
|
||||||
|
'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=
|
||||||
|
""" )
|
||||||
|
}
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
setLogLevel( 'info' )
|
setLogLevel( 'info' )
|
||||||
app = MiniEdit()
|
app = MiniEdit()
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+66
-68
@@ -20,17 +20,17 @@ from mininet.topolib import TreeTopo
|
|||||||
from mininet.util import quietRun
|
from mininet.util import quietRun
|
||||||
|
|
||||||
# bwtest support
|
# bwtest support
|
||||||
|
|
||||||
class Graph( Frame ):
|
class Graph( Frame ):
|
||||||
|
|
||||||
"Graph that we can add bars to over time."
|
"Graph that we can add bars to over time."
|
||||||
|
|
||||||
def __init__( self, master=None,
|
def __init__( self, master=None,
|
||||||
bg = 'white',
|
bg = 'white',
|
||||||
gheight=200, gwidth=500,
|
gheight=200, gwidth=500,
|
||||||
barwidth=10,
|
barwidth=10,
|
||||||
ymax=3.5,):
|
ymax=3.5,):
|
||||||
|
|
||||||
Frame.__init__( self, master )
|
Frame.__init__( self, master )
|
||||||
|
|
||||||
self.bg = bg
|
self.bg = bg
|
||||||
@@ -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
|
||||||
@@ -60,22 +59,22 @@ class Graph( Frame ):
|
|||||||
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, fill=fill )
|
||||||
scale.create_text( 10, ypos, text=str( y ), fill=fill )
|
scale.create_text( 10, ypos, text=str( y ), fill=fill )
|
||||||
|
|
||||||
return scale
|
return scale
|
||||||
|
|
||||||
def updateScrollRegions( self ):
|
def updateScrollRegions( self ):
|
||||||
"Update graph and scale scroll regions."
|
"Update graph and scale scroll regions."
|
||||||
ofs = 20
|
ofs = 20
|
||||||
height = self.gheight + ofs
|
height = self.gheight + ofs
|
||||||
self.graph.configure( scrollregion=( 0, -ofs,
|
self.graph.configure( scrollregion=( 0, -ofs,
|
||||||
self.xpos * self.barwidth, height ) )
|
self.xpos * self.barwidth, height ) )
|
||||||
self.scale.configure( scrollregion=( 0, -ofs, 0, height ) )
|
self.scale.configure( scrollregion=( 0, -ofs, 0, height ) )
|
||||||
|
|
||||||
def yview( self, *args ):
|
def yview( self, *args ):
|
||||||
"Scroll both scale and graph."
|
"Scroll both scale and graph."
|
||||||
self.graph.yview( *args )
|
self.graph.yview( *args )
|
||||||
self.scale.yview( *args )
|
self.scale.yview( *args )
|
||||||
|
|
||||||
def createWidgets( self ):
|
def createWidgets( self ):
|
||||||
"Create initial widget set."
|
"Create initial widget set."
|
||||||
|
|
||||||
@@ -83,14 +82,14 @@ 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 )
|
||||||
graph.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set,
|
graph.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set,
|
||||||
scrollregion=(0, 0, width, height ) )
|
scrollregion=(0, 0, width, height ) )
|
||||||
scale.configure( yscrollcommand=ybar.set )
|
scale.configure( yscrollcommand=ybar.set )
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
title.grid( row=0, columnspan=3, sticky='new')
|
title.grid( row=0, columnspan=3, sticky='new')
|
||||||
scale.grid( row=1, column=0, sticky='nsew' )
|
scale.grid( row=1, column=0, sticky='nsew' )
|
||||||
@@ -99,13 +98,8 @@ 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."
|
||||||
percent = yval / self.ymax
|
percent = yval / self.ymax
|
||||||
@@ -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 ):
|
||||||
@@ -134,52 +128,49 @@ class Graph( Frame ):
|
|||||||
class Controls( Frame ):
|
class Controls( Frame ):
|
||||||
|
|
||||||
"Handy controls for configuring test."
|
"Handy controls for configuring test."
|
||||||
|
|
||||||
switches = {
|
switches = {
|
||||||
'Kernel Switch': KernelSwitch,
|
'Kernel Switch': KernelSwitch,
|
||||||
'User Switch': UserSwitch,
|
'User Switch': UserSwitch,
|
||||||
'Open vSwitch': OVSKernelSwitch
|
'Open vSwitch': OVSKernelSwitch
|
||||||
}
|
}
|
||||||
|
|
||||||
controllers = {
|
controllers = {
|
||||||
'Reference Controller': Controller,
|
'Reference Controller': Controller,
|
||||||
'NOX': NOX
|
'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 )
|
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
|
||||||
pk = { 'fill': 'x' }
|
pk = { 'fill': 'x' }
|
||||||
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' ) ):
|
||||||
"Parse udpbwtest.c output, returning seconds, inbw, outbw."
|
"Parse udpbwtest.c output, returning seconds, inbw, outbw."
|
||||||
@@ -193,34 +184,41 @@ 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 )
|
||||||
|
|
||||||
self.controls = Controls( self, self.start, self.stop, self.quit )
|
self.controls = Controls( self, self.start, self.stop, self.quit )
|
||||||
self.graph = Graph( self )
|
self.graph = Graph( self )
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
self.controls.pack( side='left', expand=False, fill='y' )
|
self.controls.pack( side='left', expand=False, fill='y' )
|
||||||
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
|
||||||
|
|
||||||
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 )
|
||||||
|
|
||||||
print "*** Starting network"
|
print "*** Starting network"
|
||||||
self.net.start()
|
self.net.start()
|
||||||
|
|
||||||
@@ -229,7 +227,7 @@ class UdpBwTest( Frame ):
|
|||||||
for host in hosts:
|
for host in hosts:
|
||||||
ips = [ h.IP() for h in hosts if h != host ]
|
ips = [ h.IP() for h in hosts if h != host ]
|
||||||
host.cmdPrint( './udpbwtest ' + ' '.join( ips ) + ' &' )
|
host.cmdPrint( './udpbwtest ' + ' '.join( ips ) + ' &' )
|
||||||
|
|
||||||
print "*** Monitoring hosts"
|
print "*** Monitoring hosts"
|
||||||
self.output = self.net.monitor( hosts, timeoutms=1 )
|
self.output = self.net.monitor( hosts, timeoutms=1 )
|
||||||
self.results = {}
|
self.results = {}
|
||||||
@@ -238,12 +236,12 @@ class UdpBwTest( Frame ):
|
|||||||
|
|
||||||
# Pylint isn't smart enough to understand iterator.next()
|
# Pylint isn't smart enough to understand iterator.next()
|
||||||
# pylint: disable-msg=E1101
|
# pylint: disable-msg=E1101
|
||||||
|
|
||||||
def updateGraph( self ):
|
def updateGraph( self ):
|
||||||
"Graph input bandwidth."
|
"Graph input bandwidth."
|
||||||
|
|
||||||
print "updateGraph"
|
print "updateGraph"
|
||||||
|
|
||||||
if not self.running:
|
if not self.running:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -269,20 +267,20 @@ class UdpBwTest( Frame ):
|
|||||||
|
|
||||||
def stop( self ):
|
def stop( self ):
|
||||||
"Stop test."
|
"Stop test."
|
||||||
|
|
||||||
print "*** Stopping udpbwtest processes"
|
print "*** Stopping udpbwtest processes"
|
||||||
# We *really* don't want these things hanging around!
|
# We *really* don't want these things hanging around!
|
||||||
quietRun( 'killall -9 udpbwtest' )
|
quietRun( 'killall -9 udpbwtest' )
|
||||||
|
|
||||||
if not self.running:
|
if not self.running:
|
||||||
return
|
return
|
||||||
|
|
||||||
print "*** Stopping network"
|
print "*** Stopping network"
|
||||||
self.running = False
|
self.running = False
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ def sh( cmd ):
|
|||||||
def cleanup():
|
def cleanup():
|
||||||
"""Clean up junk which might be left over from old runs;
|
"""Clean up junk which might be left over from old runs;
|
||||||
do fast stuff before slow dp and link removal!"""
|
do fast stuff before slow dp and link removal!"""
|
||||||
|
|
||||||
info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
|
info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
|
||||||
"\n")
|
"\n")
|
||||||
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
|
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
|
||||||
|
|||||||
+23
-17
@@ -29,18 +29,18 @@ 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
|
||||||
from mininet.util import quietRun, isShellBuiltin
|
from mininet.util import quietRun, isShellBuiltin
|
||||||
|
|
||||||
class CLI( Cmd ):
|
class CLI( Cmd ):
|
||||||
"Simple command-line interface to talk to nodes."
|
"Simple command-line interface to talk to nodes."
|
||||||
|
|
||||||
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
|
||||||
@@ -75,7 +75,7 @@ class CLI( Cmd ):
|
|||||||
# must have the same interface
|
# must have the same interface
|
||||||
# pylint: disable-msg=W0613,R0201
|
# pylint: disable-msg=W0613,R0201
|
||||||
|
|
||||||
helpStr = (
|
helpStr = (
|
||||||
'You may also send a command to a node using:\n'
|
'You may also send a command to a node using:\n'
|
||||||
' <node> command {args}\n'
|
' <node> command {args}\n'
|
||||||
'For example:\n'
|
'For example:\n'
|
||||||
@@ -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' )
|
||||||
|
|
||||||
@@ -209,7 +211,7 @@ class CLI( Cmd ):
|
|||||||
def isatty( self ):
|
def isatty( self ):
|
||||||
"Is our standard input a tty?"
|
"Is our standard input a tty?"
|
||||||
return isatty( self.stdin.fileno() )
|
return isatty( self.stdin.fileno() )
|
||||||
|
|
||||||
def do_noecho( self, line ):
|
def do_noecho( self, line ):
|
||||||
"Run an interactive command with echoing turned off."
|
"Run an interactive command with echoing turned off."
|
||||||
if self.isatty():
|
if self.isatty():
|
||||||
@@ -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
|
||||||
|
|||||||
+28
-24
@@ -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."
|
||||||
|
|
||||||
@@ -167,7 +147,7 @@ class Mininet( object ):
|
|||||||
if topo and build:
|
if topo and build:
|
||||||
self.build()
|
self.build()
|
||||||
|
|
||||||
|
|
||||||
def addHost( self, name, mac=None, ip=None ):
|
def addHost( self, name, mac=None, ip=None ):
|
||||||
"""Add host.
|
"""Add host.
|
||||||
name: name of host to add
|
name: name of host to add
|
||||||
@@ -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
|
||||||
|
|||||||
+8
-14
@@ -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 ):
|
||||||
@@ -301,7 +303,7 @@ class Node( object ):
|
|||||||
if port1 is None:
|
if port1 is None:
|
||||||
port1 = node1.newPort()
|
port1 = node1.newPort()
|
||||||
if port2 is None:
|
if port2 is None:
|
||||||
port2 = node2.newPort()
|
port2 = node2.newPort()
|
||||||
intf1 = node1.intfName( port1 )
|
intf1 = node1.intfName( port1 )
|
||||||
intf2 = node2.intfName( port2 )
|
intf2 = node2.intfName( port2 )
|
||||||
makeIntfPair( intf1, intf2 )
|
makeIntfPair( intf1, intf2 )
|
||||||
@@ -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."
|
||||||
|
|
||||||
@@ -458,7 +452,7 @@ class UserSwitch( Switch ):
|
|||||||
class KernelSwitch( Switch ):
|
class KernelSwitch( Switch ):
|
||||||
"""Kernel-space switch.
|
"""Kernel-space switch.
|
||||||
Currently only works in root namespace."""
|
Currently only works in root namespace."""
|
||||||
|
|
||||||
def __init__( self, name, dp=None, **kwargs ):
|
def __init__( self, name, dp=None, **kwargs ):
|
||||||
"""Init.
|
"""Init.
|
||||||
name: name for switch
|
name: name for switch
|
||||||
@@ -496,7 +490,7 @@ class KernelSwitch( Switch ):
|
|||||||
# Run protocol daemon
|
# Run protocol daemon
|
||||||
controller = controllers[ 0 ]
|
controller = controllers[ 0 ]
|
||||||
self.cmd( 'ofprotocol ' + self.dp +
|
self.cmd( 'ofprotocol ' + self.dp +
|
||||||
' tcp:%s:%d' % ( controller.IP(), controller.port ) +
|
' tcp:%s:%d' % ( controller.IP(), controller.port ) +
|
||||||
' --fail=closed ' + self.opts +
|
' --fail=closed ' + self.opts +
|
||||||
' 1> ' + ofplog + ' 2>' + ofplog + ' &' )
|
' 1> ' + ofplog + ' 2>' + ofplog + ' &' )
|
||||||
self.execed = False
|
self.execed = False
|
||||||
@@ -550,8 +544,8 @@ class OVSKernelSwitch( Switch ):
|
|||||||
# Run protocol daemon
|
# Run protocol daemon
|
||||||
controller = controllers[ 0 ]
|
controller = controllers[ 0 ]
|
||||||
self.cmd( 'ovs-openflowd ' + self.dp +
|
self.cmd( 'ovs-openflowd ' + self.dp +
|
||||||
' tcp:%s:%i' % ( controller.IP(), controller.port ) +
|
' tcp:%s:%i' % ( controller.IP(), controller.port ) +
|
||||||
' --fail=closed ' + self.opts +
|
' --fail=closed ' + self.opts +
|
||||||
' 1>' + ofplog + ' 2>' + ofplog + '&' )
|
' 1>' + ofplog + ' 2>' + ofplog + '&' )
|
||||||
self.execed = False
|
self.execed = False
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -15,7 +15,7 @@ from mininet.util import quietRun
|
|||||||
def quoteArg( arg ):
|
def quoteArg( arg ):
|
||||||
"Quote an argument if it contains spaces."
|
"Quote an argument if it contains spaces."
|
||||||
return repr( arg ) if ' ' in arg else arg
|
return repr( arg ) if ' ' in arg else arg
|
||||||
|
|
||||||
def makeTerm( node, title='Node', term='xterm' ):
|
def makeTerm( node, title='Node', term='xterm' ):
|
||||||
"""Run screen on a node, and hook up a terminal.
|
"""Run screen on a node, and hook up a terminal.
|
||||||
node: Node object
|
node: Node object
|
||||||
@@ -38,9 +38,9 @@ def makeTerm( node, title='Node', term='xterm' ):
|
|||||||
else:
|
else:
|
||||||
args = [ 'sh', '-c', 'exec tail -f /tmp/' + node.name + '*.log' ]
|
args = [ 'sh', '-c', 'exec tail -f /tmp/' + node.name + '*.log' ]
|
||||||
if term == 'gterm':
|
if term == 'gterm':
|
||||||
# Compress these for gnome-terminal, which expects one token
|
# Compress these for gnome-terminal, which expects one token
|
||||||
# to follow the -e option
|
# to follow the -e option
|
||||||
args = [ ' '.join( [ quoteArg( arg ) for arg in args ] ) ]
|
args = [ ' '.join( [ quoteArg( arg ) for arg in args ] ) ]
|
||||||
return Popen( cmds[ term ] + args )
|
return Popen( cmds[ term ] + args )
|
||||||
|
|
||||||
def cleanUpScreens():
|
def cleanUpScreens():
|
||||||
|
|||||||
+33
-21
@@ -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,13 +19,16 @@ 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"""
|
||||||
if len( cmd ) == 1:
|
if len( cmd ) == 1:
|
||||||
cmd = cmd[ 0 ]
|
cmd = cmd[ 0 ]
|
||||||
if isinstance( cmd, str ):
|
if isinstance( cmd, str ):
|
||||||
cmd = cmd.split( ' ' )
|
cmd = cmd.split( ' ' )
|
||||||
popen = Popen( cmd, stdout=PIPE, stderr=STDOUT )
|
popen = Popen( cmd, stdout=PIPE, stderr=STDOUT )
|
||||||
# We can't use Popen.communicate() because it uses
|
# We can't use Popen.communicate() because it uses
|
||||||
# select(), which can't handle
|
# select(), which can't handle
|
||||||
@@ -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 ) )
|
||||||
|
|||||||
Reference in New Issue
Block a user