Any code in mn is not usable by other Python code. Hence, move this code into util, so other scripts can use it.
259 lines
9.2 KiB
Python
Executable File
259 lines
9.2 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
"""
|
|
Mininet runner
|
|
author: Brandon Heller (brandonh@stanford.edu)
|
|
|
|
To see options:
|
|
sudo mn -h
|
|
|
|
Example to pull custom params (topo, switch, etc.) from a file:
|
|
sudo mn --custom ~/mininet/custom/custom_example.py
|
|
"""
|
|
|
|
from optparse import OptionParser
|
|
import os.path
|
|
import sys
|
|
import time
|
|
|
|
from mininet.clean import cleanup
|
|
from mininet.cli import CLI
|
|
from mininet.log import lg, LEVELS, info, warn
|
|
from mininet.net import Mininet, MininetWithControlNet
|
|
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
|
|
NOX, RemoteController, UserSwitch, OVSKernelSwitch,
|
|
OVSLegacyKernelSwitch )
|
|
from mininet.link import Link, TCLink
|
|
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
|
from mininet.topolib import TreeTopo
|
|
from mininet.util import makeNumeric, custom, customConstructor, splitArgs
|
|
from mininet.util import buildTopo
|
|
|
|
|
|
# built in topologies, created only when run
|
|
TOPODEF = 'minimal'
|
|
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
|
|
'linear': LinearTopo,
|
|
'reversed': SingleSwitchReversedTopo,
|
|
'single': SingleSwitchTopo,
|
|
'tree': TreeTopo }
|
|
|
|
SWITCHDEF = 'ovsk'
|
|
SWITCHES = { 'user': UserSwitch,
|
|
'ovsk': OVSKernelSwitch,
|
|
'ovsl': OVSLegacyKernelSwitch }
|
|
|
|
HOSTDEF = 'proc'
|
|
HOSTS = { 'proc': Host,
|
|
'rt': custom( CPULimitedHost, sched='rt' ),
|
|
'cfs': custom( CPULimitedHost, sched='cfs' ) }
|
|
|
|
CONTROLLERDEF = 'ref'
|
|
CONTROLLERS = { 'ref': Controller,
|
|
'ovsc': OVSController,
|
|
'nox': NOX,
|
|
'remote': RemoteController,
|
|
'none': lambda name: None }
|
|
|
|
LINKDEF = 'default'
|
|
LINKS = { 'default': Link,
|
|
'tc': TCLink }
|
|
|
|
|
|
# optional tests to run
|
|
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
|
|
'none' ]
|
|
|
|
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
|
|
'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
|
|
|
|
|
|
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
|
|
"""Convenience function to add choices dicts to OptionParser.
|
|
opts: OptionParser instance
|
|
choicesDict: dictionary of valid choices, must include default
|
|
default: default choice key
|
|
name: long option name
|
|
help: string"""
|
|
if default not in choicesDict:
|
|
raise Exception( 'Invalid default %s for choices dict: %s' %
|
|
( default, name ) )
|
|
if not helpStr:
|
|
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
|
|
'[,param=value...]' )
|
|
opts.add_option( '--' + name,
|
|
type='string',
|
|
default = default,
|
|
help = helpStr )
|
|
|
|
|
|
class MininetRunner( object ):
|
|
"Build, setup, and run Mininet."
|
|
|
|
def __init__( self ):
|
|
"Init."
|
|
self.options = None
|
|
self.args = None # May be used someday for more CLI scripts
|
|
self.validate = None
|
|
|
|
self.parseArgs()
|
|
self.setup()
|
|
self.begin()
|
|
|
|
def setCustom( self, name, value ):
|
|
"Set custom parameters for MininetRunner."
|
|
if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
|
|
# Update dictionaries
|
|
param = name.upper()
|
|
globals()[ param ].update( value )
|
|
elif name == 'validate':
|
|
# Add custom validate function
|
|
self.validate = value
|
|
else:
|
|
# Add or modify global variable or class
|
|
globals()[ name ] = value
|
|
|
|
def parseCustomFile( self, fileName ):
|
|
"Parse custom file and add params before parsing cmd-line options."
|
|
customs = {}
|
|
if os.path.isfile( fileName ):
|
|
execfile( fileName, customs, customs )
|
|
for name, val in customs.iteritems():
|
|
self.setCustom( name, val )
|
|
else:
|
|
raise Exception( 'could not find custom file: %s' % fileName )
|
|
|
|
def parseArgs( self ):
|
|
"""Parse command-line args and return options object.
|
|
returns: opts parse options dict"""
|
|
if '--custom' in sys.argv:
|
|
index = sys.argv.index( '--custom' )
|
|
if len( sys.argv ) > index + 1:
|
|
filename = sys.argv[ index + 1 ]
|
|
self.parseCustomFile( filename )
|
|
else:
|
|
raise Exception( 'Custom file name not found' )
|
|
|
|
opts = OptionParser()
|
|
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
|
|
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
|
|
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
|
|
addDictOption( opts, LINKS, LINKDEF, 'link' )
|
|
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
|
|
|
|
opts.add_option( '--clean', '-c', action='store_true',
|
|
default=False, help='clean and exit' )
|
|
opts.add_option( '--custom', type='string', default=None,
|
|
help='read custom topo and node params from .py file' )
|
|
opts.add_option( '--test', type='choice', choices=TESTS,
|
|
default=TESTS[ 0 ],
|
|
help='|'.join( TESTS ) )
|
|
opts.add_option( '--xterms', '-x', action='store_true',
|
|
default=False, help='spawn xterms for each node' )
|
|
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
|
|
help='base IP address for hosts' )
|
|
opts.add_option( '--mac', action='store_true',
|
|
default=False, help='automatically set host MACs' )
|
|
opts.add_option( '--arp', action='store_true',
|
|
default=False, help='set all-pairs ARP entries' )
|
|
opts.add_option( '--verbosity', '-v', type='choice',
|
|
choices=LEVELS.keys(), default = 'info',
|
|
help = '|'.join( LEVELS.keys() ) )
|
|
opts.add_option( '--innamespace', action='store_true',
|
|
default=False, help='sw and ctrl in namespace?' )
|
|
opts.add_option( '--listenport', type='int', default=6635,
|
|
help='base port for passive switch listening' )
|
|
opts.add_option( '--nolistenport', action='store_true',
|
|
default=False, help="don't use passive listening port")
|
|
opts.add_option( '--pre', type='string', default=None,
|
|
help='CLI script to run before tests' )
|
|
opts.add_option( '--post', type='string', default=None,
|
|
help='CLI script to run after tests' )
|
|
opts.add_option( '--prefixlen', type='int', default=8,
|
|
help='prefix length (e.g. /8) for automatic '
|
|
'network configuration' )
|
|
opts.add_option( '--pin', action='store_true',
|
|
default=False, help="pin hosts to CPU cores "
|
|
"(requires --host cfs or --host rt)" )
|
|
|
|
self.options, self.args = opts.parse_args()
|
|
|
|
def setup( self ):
|
|
"Setup and validate environment."
|
|
|
|
# set logging verbosity
|
|
if LEVELS[self.options.verbosity] > LEVELS['output']:
|
|
print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
|
|
'output!\n'
|
|
'Please restart Mininet with -v [debug, info, output].'
|
|
% self.options.verbosity )
|
|
lg.setLogLevel( self.options.verbosity )
|
|
|
|
def begin( self ):
|
|
"Create and run mininet."
|
|
|
|
if self.options.clean:
|
|
cleanup()
|
|
exit()
|
|
|
|
start = time.time()
|
|
|
|
topo = buildTopo( TOPOS, self.options.topo )
|
|
switch = customConstructor( SWITCHES, self.options.switch )
|
|
host = customConstructor( HOSTS, self.options.host )
|
|
controller = customConstructor( CONTROLLERS, self.options.controller )
|
|
link = customConstructor( LINKS, self.options.link )
|
|
|
|
if self.validate:
|
|
self.validate( self.options )
|
|
|
|
inNamespace = self.options.innamespace
|
|
Net = MininetWithControlNet if inNamespace else Mininet
|
|
ipBase = self.options.ipbase
|
|
xterms = self.options.xterms
|
|
mac = self.options.mac
|
|
arp = self.options.arp
|
|
pin = self.options.pin
|
|
listenPort = None
|
|
if not self.options.nolistenport:
|
|
listenPort = self.options.listenport
|
|
mn = Net( topo=topo,
|
|
switch=switch, host=host, controller=controller,
|
|
link=link,
|
|
ipBase=ipBase,
|
|
inNamespace=inNamespace,
|
|
xterms=xterms, autoSetMacs=mac,
|
|
autoStaticArp=arp, autoPinCpus=pin,
|
|
listenPort=listenPort )
|
|
|
|
if self.options.pre:
|
|
CLI( mn, script=self.options.pre )
|
|
|
|
test = self.options.test
|
|
test = ALTSPELLING.get( test, test )
|
|
|
|
mn.start()
|
|
|
|
if test == 'none':
|
|
pass
|
|
elif test == 'all':
|
|
mn.start()
|
|
mn.ping()
|
|
mn.iperf()
|
|
elif test == 'cli':
|
|
CLI( mn )
|
|
elif test != 'build':
|
|
getattr( mn, test )()
|
|
|
|
if self.options.post:
|
|
CLI( mn, script=self.options.post )
|
|
|
|
mn.stop()
|
|
|
|
elapsed = float( time.time() - start )
|
|
info( 'completed in %0.3f seconds\n' % elapsed )
|
|
|
|
|
|
if __name__ == "__main__":
|
|
MininetRunner()
|