Files
mininet/bin/mn
T
2012-07-03 22:08:33 -07:00

269 lines
9.7 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, VERSION
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 = 'ovsc'
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 )
def version( *_args ):
"Print Mininet version and exit"
print "mn (Mininet %s)" % VERSION
exit()
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' )
desc = ( "The %prog utility creates Mininet network from the\n"
"command line. It can create parametrized topologies,\n"
"invoke the Mininet CLI, and run tests." )
opts = OptionParser( description=desc )
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)" )
opts.add_option( '--version', action='callback', callback=version )
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()