Files
mininet/bin/mn
T
Brandon Heller befa1310df Revamp custom topology input
Defining custom topologies, switch types, controllers, and hosts is now
much easier.  Plus, all Ripcord-specific stuff has been moved out.
2010-01-30 02:46:08 -08:00

194 lines
7.0 KiB
Python

#!/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.log import lg, LEVELS
from mininet.net import Mininet, init
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
# built in topologies, created only when run
TOPODEF = 'minimal'
TOPOS = { 'minimal': ( lambda: SingleSwitchTopo( k=2 ) ),
'reversed': ( lambda: SingleSwitchReversedTopo( k=2 ) ),
'single4': ( lambda: SingleSwitchTopo( k=4 ) ),
'single100': ( lambda: SingleSwitchTopo( k=100 ) ),
'linear2': ( lambda: LinearTopo( k=2 ) ),
'linear100': ( lambda: LinearTopo( k=100 ) ) }
SWITCHDEF = 'kernel'
SWITCHES = { 'kernel': KernelSwitch,
'user': UserSwitch,
'ovsk': OVSKernelSwitch }
HOSTDEF = 'process'
HOSTS = { 'process': Host }
CONTROLLERDEF = 'ref'
# a and b are the name and inNamespace params.
CONTROLLERS = { 'ref': Controller,
'nox_dump': lambda a, b: NOX( a, b, 'packetdump' ),
'nox_pysw': lambda a, b: NOX( a, b, 'pyswitch' ),
'remote': lambda a, b: None,
'none': lambda a, b: None }
# optional tests to run
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp' ]
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( choicesDict.keys() ) + ']'
opts.add_option( '--' + name,
type='choice',
choices=choicesDict.keys(),
default = default,
help = helpStr )
class MininetRunner( object ):
"Build, setup, and run Mininet."
def __init__( self ):
"Init."
self.options = None
self.validate = None
self.parseArgs()
self.setup()
self.begin()
def parseCustomFile( self, custom ):
"Parse custom file and add params before parsing cmd-line options."
if os.path.isfile( custom ):
execfile( custom, globals(), globals() )
if 'topos' in globals(): TOPOS.update( topos )
if 'switches' in globals(): SWITCHES.update( switches )
if 'hosts' in globals(): HOSTS.update( hosts )
if 'controllers' in globals(): CONTROLLERS.update( controllers )
if 'validate' in globals(): self.validate = validate
else:
raise Exception( 'could not find custom file: %s' % custom )
def parseArgs( self ):
"""Parse command-line args and return options object.
returns: opts parse options dict"""
if '--custom' in sys.argv:
print "custom in sys.argv"
index = sys.argv.index( '--custom' )
if len( sys.argv ) > index + 1:
custom = sys.argv[ index + 1 ]
print "custom = %s" % custom
self.parseCustomFile( custom )
else:
raise Exception( 'Custom file name not found' )
opts = OptionParser()
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
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( '--mac', action='store_true',
default=False, help='set MACs equal to DPIDs' )
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( '--ip', type='string', default='127.0.0.1',
help='[ip address as a dotted decimal string for a'
'remote controller]' )
opts.add_option( '--port', type='string', default=6633,
help='[port integer for a listening remote'
' controller]' )
opts.add_option( '--inNamespace', action='store_true',
default=False, help='sw and ctrl in namespace?' )
self.options = opts.parse_args()[ 0 ]
def setup( self ):
"Setup and validate environment."
# set logging verbosity
lg.setLogLevel( self.options.verbosity )
# validate environment setup
init()
def begin( self ):
"Create and run mininet."
start = time.time()
topo = TOPOS[ self.options.topo ]() # build topology object
switch = SWITCHES[ self.options.switch ]
host = HOSTS[ self.options.host ]
controller = CONTROLLERS[ self.options.controller ]
if self.options.controller == 'remote':
controller = lambda a, b: RemoteController( a, b,
ipAddress=self.options.ip,
port=self.options.port )
if self.validate:
self.validate(self.options)
controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8
inNamespace = self.options.inNamespace
xterms = self.options.xterms
mac = self.options.mac
arp = self.options.arp
mn = Mininet( topo, switch, host, controller, controllerParams,
inNamespace=inNamespace,
xterms=xterms, autoSetMacs=mac,
autoStaticArp=arp )
test = self.options.test
if test != 'build':
if test == 'cli':
mn.interact()
elif test == 'all':
mn.start()
mn.ping()
mn.iperf()
mn.stop()
else:
mn.run( test )
elapsed = float( time.time() - start )
print ( 'completed in %0.3f seconds' % elapsed )
if __name__ == "__main__":
MininetRunner()