Added updbwgraph, a demo of how to graphically monitor node output.
This commit is contained in:
Executable
+254
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
udpbwgraph: Plot network bandwidth over time
|
||||
|
||||
Bob Lantz
|
||||
3/27/10
|
||||
"""
|
||||
|
||||
from time import sleep
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from time import time
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
from mininet.log import setLogLevel
|
||||
from mininet.net import init, Mininet
|
||||
from mininet.node import KernelSwitch, UserSwitch, OVSKernelSwitch
|
||||
from mininet.node import Controller, NOX
|
||||
from mininet.topolib import TreeTopo
|
||||
from mininet.util import quietRun
|
||||
|
||||
# bwtest support
|
||||
|
||||
class Graph( Frame ):
|
||||
|
||||
"Graph that we can add bars to over time."
|
||||
|
||||
def __init__( self, master=None,
|
||||
bg = 'white',
|
||||
gheight=200, gwidth=500,
|
||||
barwidth=10,
|
||||
ymax=3.5,):
|
||||
|
||||
Frame.__init__( self, master )
|
||||
|
||||
self.bg = bg
|
||||
self.gheight = gheight
|
||||
self.gwidth = gwidth
|
||||
self.barwidth = barwidth
|
||||
self.ymax = float( ymax )
|
||||
self.xpos = 0
|
||||
|
||||
# Create everything
|
||||
self.title = self.graph = None
|
||||
self.createWidgets()
|
||||
self.updateScrollRegions()
|
||||
self.yview( 'moveto', '1.0' )
|
||||
|
||||
def scale( self ):
|
||||
"Create a and return a new canvas with scale markers."
|
||||
height = float( self.gheight )
|
||||
width = 25
|
||||
ymax = self.ymax
|
||||
scale = Canvas( self, width=width, height=height, background=self.bg )
|
||||
fill = 'red'
|
||||
# Draw scale line
|
||||
scale.create_line( width - 1, height, width - 1, 0, fill=fill )
|
||||
# Draw ticks and numbers
|
||||
for y in range( 0, int( ymax + 1 ) ):
|
||||
ypos = height * (1 - float( y ) / ymax )
|
||||
scale.create_line( width, ypos, width - 10, ypos, fill=fill )
|
||||
scale.create_text( 10, ypos, text=str( y ), fill=fill )
|
||||
|
||||
return scale
|
||||
|
||||
def updateScrollRegions( self ):
|
||||
"Update graph and scale scroll regions."
|
||||
ofs = 20
|
||||
height = self.gheight + ofs
|
||||
self.graph.configure( scrollregion=( 0, -ofs,
|
||||
self.xpos * self.barwidth, height ) )
|
||||
self.scale.configure( scrollregion=( 0, -ofs, 0, height ) )
|
||||
|
||||
def yview( self, *args ):
|
||||
"Scroll both scale and graph."
|
||||
self.graph.yview( *args )
|
||||
self.scale.yview( *args )
|
||||
|
||||
def createWidgets( self ):
|
||||
"Create initial widget set."
|
||||
|
||||
# Objects
|
||||
title = Label( self, text="Bandwidth (Mb/s)", bg=self.bg )
|
||||
width = self.gwidth
|
||||
height = self.gheight
|
||||
scale = self.scale()
|
||||
graph = Canvas( self, width=width, height=height, background=self.bg)
|
||||
xbar = Scrollbar( self, orient='horizontal', command=graph.xview )
|
||||
ybar = Scrollbar( self, orient='vertical', command=self.yview )
|
||||
graph.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set,
|
||||
scrollregion=(0, 0, width, height ) )
|
||||
scale.configure( yscrollcommand=ybar.set )
|
||||
|
||||
# Layout
|
||||
title.grid( row=0, columnspan=3, sticky=N+E+W)
|
||||
scale.grid( row=1, column=0, sticky=N+S+E+W )
|
||||
graph.grid( row=1, column=1, sticky=N+S+E+W )
|
||||
ybar.grid( row=1, column=2, sticky=N+S )
|
||||
xbar.grid( row=2, column=0, columnspan=2, sticky=E+W )
|
||||
self.rowconfigure( 1, weight=1 )
|
||||
self.columnconfigure( 1, weight=1 )
|
||||
|
||||
# Save for future reference
|
||||
self.title = title
|
||||
self.scale = scale
|
||||
self.graph = graph
|
||||
return graph
|
||||
|
||||
def addBar( self, yval ):
|
||||
"Add a new bar to our graph."
|
||||
percent = yval / self.ymax
|
||||
height = percent * self.gheight
|
||||
c = self.graph
|
||||
x0 = self.xpos * self.barwidth
|
||||
x1 = x0 + self.barwidth
|
||||
y0 = self.gheight
|
||||
y1 = ( 1 - percent ) * self.gheight
|
||||
c.create_rectangle( x0 , y0, x1, y1, fill='green' )
|
||||
self.xpos += 1
|
||||
self.updateScrollRegions()
|
||||
self.graph.xview( 'moveto', '1.0' )
|
||||
|
||||
def test( self ):
|
||||
"Add a bar for testing purposes."
|
||||
ms = 1000
|
||||
if self.xpos < 10:
|
||||
self.addBar( self.xpos/10 * self.ymax )
|
||||
self.after( ms, self.test )
|
||||
|
||||
def setTitle( self, text ):
|
||||
"Set graph title"
|
||||
self.title.configure( text=text, font='Helvetica 9 bold' )
|
||||
|
||||
|
||||
class Controls( Frame ):
|
||||
|
||||
"Handy controls for configuring test."
|
||||
|
||||
switches = {
|
||||
'Kernel Switch': KernelSwitch,
|
||||
'User Switch': UserSwitch,
|
||||
'Open vSwitch': OVSKernelSwitch
|
||||
}
|
||||
|
||||
controllers = {
|
||||
'Reference Controller': Controller,
|
||||
'NOX': NOX
|
||||
}
|
||||
|
||||
|
||||
def __init__( self, master=None ):
|
||||
|
||||
Frame.__init__( self, master )
|
||||
|
||||
self.switch = StringVar()
|
||||
self.switch.set( 'Kernel Switch' )
|
||||
self.switchMenu = OptionMenu( self, self.switch,
|
||||
*( switches.keys() ) )
|
||||
|
||||
self.controller = StringVar()
|
||||
self.controller.set( 'Reference Controller' )
|
||||
self.controllerMenu = OpetionMenu( self, self.controller,
|
||||
*( controllers.keys() ) )
|
||||
|
||||
def App( Frame ):
|
||||
|
||||
|
||||
def parsebwtest( line,
|
||||
r=re.compile( r'(\d+) s: in ([\d\.]+) Mbps, out ([\d\.]+) Mbps' ) ):
|
||||
"Parse udpbwtest.c output, returning seconds, inbw, outbw."
|
||||
match = r.match( line )
|
||||
if match:
|
||||
seconds, inbw, outbw = match.group( 1, 2, 3 )
|
||||
return int( seconds ), float( inbw ), float( outbw )
|
||||
return None, None, None
|
||||
|
||||
|
||||
class UdpBwTest( object ):
|
||||
"Test and plot UDP bandwidth over time"
|
||||
|
||||
def __init__( self, graph, net, seconds=60 ):
|
||||
"Start up and monitor udpbwtest on each of our hosts."
|
||||
|
||||
hosts = net.hosts
|
||||
self.graph = graph
|
||||
self.hostCount = len( hosts )
|
||||
|
||||
print "*** Starting udpbwtest on hosts"
|
||||
for host in hosts:
|
||||
ips = [ h.IP() for h in hosts if h != host ]
|
||||
host.cmdPrint( './udpbwtest ' + ' '.join( ips ) + ' &' )
|
||||
|
||||
print "*** Monitoring hosts"
|
||||
self.output = net.monitor( hosts, timeoutms=0 )
|
||||
self.results = {}
|
||||
self.quitTime = time() + seconds
|
||||
self.updateGraph()
|
||||
|
||||
# Pylint isn't smart enough to understand iterator.next()
|
||||
# pylint: disable-msg=E1101
|
||||
|
||||
def updateGraph( self ):
|
||||
"Graph input bandwidth."
|
||||
while True:
|
||||
host, line = self.output.next()
|
||||
if host is None or len( line ) == 0:
|
||||
break
|
||||
seconds, inbw, outbw = parsebwtest( line )
|
||||
if seconds is None:
|
||||
break
|
||||
result = self.results.get( seconds, [] ) + [ ( host, inbw, outbw ) ]
|
||||
self.results[ seconds ] = result
|
||||
if len( result ) == self.hostCount:
|
||||
# Calculate total and update graph
|
||||
# We report input bandwidth, i.e. packets that made it
|
||||
totalin = 0
|
||||
for host, inbw, outbw in result:
|
||||
totalin += inbw
|
||||
self.graph.addBar( totalin / 1000.0 )
|
||||
print totalin
|
||||
if time() < self.quitTime:
|
||||
# Fileevent would be better, but for now we just poll every 500ms
|
||||
self.graph.after( 10, self.updateGraph )
|
||||
else:
|
||||
self.shutdown()
|
||||
|
||||
def shutdown( self ):
|
||||
"Stop udpbwtest proceses."
|
||||
print "*** Stopping udpbwtest processes"
|
||||
# We *really* don't want these things hanging around!
|
||||
quietRun( 'killall -9 udpbwtest' )
|
||||
|
||||
# pylint: enable-msg=E1101
|
||||
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'info' )
|
||||
app = Graph()
|
||||
app.master.title( "Mininet Bandwidth" )
|
||||
depth, fanout = 1, 2
|
||||
net = Mininet( topo=TreeTopo( depth=depth, fanout=fanout),
|
||||
switch=KernelSwitch )
|
||||
title = "Bandwidth (Mb/s), (%i hosts, %i switches, depth=%d, fanout=%d)" % (
|
||||
len( net.hosts ), len( net.switches), depth, fanout )
|
||||
app.setTitle( title )
|
||||
net.start()
|
||||
test = UdpBwTest( app, net )
|
||||
app.mainloop()
|
||||
net.stop()
|
||||
test.shutdown() # just in case!
|
||||
|
||||
Reference in New Issue
Block a user