Add flexible topology input parsing
Now you can pass a topology name followed by params. For example, to create a switch with 3 hosts: sudo mn --topo single,3
This commit is contained in:
@@ -21,15 +21,14 @@ from mininet.net import Mininet, init
|
|||||||
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
|
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
|
||||||
from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
|
from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
|
||||||
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
||||||
|
from mininet.util import makeNumeric
|
||||||
|
|
||||||
# built in topologies, created only when run
|
# built in topologies, created only when run
|
||||||
TOPODEF = 'minimal'
|
TOPODEF = 'minimal'
|
||||||
TOPOS = { 'minimal': ( lambda: SingleSwitchTopo( k=2 ) ),
|
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
|
||||||
'reversed': ( lambda: SingleSwitchReversedTopo( k=2 ) ),
|
'linear': LinearTopo,
|
||||||
'single4': ( lambda: SingleSwitchTopo( k=4 ) ),
|
'reversed': SingleSwitchReversedTopo,
|
||||||
'single100': ( lambda: SingleSwitchTopo( k=100 ) ),
|
'single': SingleSwitchTopo }
|
||||||
'linear2': ( lambda: LinearTopo( k=2 ) ),
|
|
||||||
'linear100': ( lambda: LinearTopo( k=100 ) ) }
|
|
||||||
|
|
||||||
SWITCHDEF = 'kernel'
|
SWITCHDEF = 'kernel'
|
||||||
SWITCHES = { 'kernel': KernelSwitch,
|
SWITCHES = { 'kernel': KernelSwitch,
|
||||||
@@ -51,6 +50,26 @@ CONTROLLERS = { 'ref': Controller,
|
|||||||
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp' ]
|
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp' ]
|
||||||
|
|
||||||
|
|
||||||
|
def buildTopo( topo ):
|
||||||
|
"Create topology from string with format (object, arg1, arg2,...)."
|
||||||
|
topo_split = topo.split( ',' )
|
||||||
|
topo_name = topo_split[ 0 ]
|
||||||
|
topo_params = topo_split[ 1: ]
|
||||||
|
|
||||||
|
# Convert int and float args; removes the need for every topology to
|
||||||
|
# be flexible with input arg formats.
|
||||||
|
topo_seq_params = [ s for s in topo_params if '=' not in s ]
|
||||||
|
topo_seq_params = [ makeNumeric( s ) for s in topo_seq_params ]
|
||||||
|
topo_kw_params = {}
|
||||||
|
for s in [ s for s in topo_params if '=' in s ]:
|
||||||
|
key, val = s.split( '=' )
|
||||||
|
topo_kw_params[ key ] = makeNumeric( val )
|
||||||
|
|
||||||
|
if topo_name not in TOPOS.keys():
|
||||||
|
raise Exception( 'Invalid topo_name %s' % topo_name )
|
||||||
|
return TOPOS[ topo_name ]( *topo_seq_params, **topo_kw_params )
|
||||||
|
|
||||||
|
|
||||||
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
|
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
|
||||||
"""Convenience function to add choices dicts to OptionParser.
|
"""Convenience function to add choices dicts to OptionParser.
|
||||||
opts: OptionParser instance
|
opts: OptionParser instance
|
||||||
@@ -118,11 +137,13 @@ class MininetRunner( object ):
|
|||||||
raise Exception( 'Custom file name not found' )
|
raise Exception( 'Custom file name not found' )
|
||||||
|
|
||||||
opts = OptionParser()
|
opts = OptionParser()
|
||||||
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
|
|
||||||
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
|
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
|
||||||
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
|
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
|
||||||
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
|
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
|
||||||
|
|
||||||
|
opts.add_option( '--topo', type='string', default=TOPODEF,
|
||||||
|
help='[' + ' '.join( TOPOS.keys() ) + '],arg1,arg2,'
|
||||||
|
'...argN')
|
||||||
opts.add_option( '--custom', type='string', default=None,
|
opts.add_option( '--custom', type='string', default=None,
|
||||||
help='read custom topo and node params from .py file' )
|
help='read custom topo and node params from .py file' )
|
||||||
opts.add_option( '--test', type='choice', choices=TESTS,
|
opts.add_option( '--test', type='choice', choices=TESTS,
|
||||||
@@ -165,7 +186,7 @@ class MininetRunner( object ):
|
|||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
topo = TOPOS[ self.options.topo ]() # build topology object
|
topo = buildTopo( self.options.topo )
|
||||||
switch = SWITCHES[ self.options.switch ]
|
switch = SWITCHES[ self.options.switch ]
|
||||||
host = HOSTS[ self.options.host ]
|
host = HOSTS[ self.options.host ]
|
||||||
controller = CONTROLLERS[ self.options.controller ]
|
controller = CONTROLLERS[ self.options.controller ]
|
||||||
|
|||||||
@@ -153,3 +153,28 @@ def ipParse( ip ):
|
|||||||
"Parse an IP address and return an unsigned int."
|
"Parse an IP address and return an unsigned int."
|
||||||
args = [ int( arg ) for arg in ip.split( '.' ) ]
|
args = [ int( arg ) for arg in ip.split( '.' ) ]
|
||||||
return ipNum( *args )
|
return ipNum( *args )
|
||||||
|
|
||||||
|
def checkInt( s ):
|
||||||
|
"Check if input string is an int"
|
||||||
|
try:
|
||||||
|
int( s )
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def checkFloat( s ):
|
||||||
|
"Check if input string is a float"
|
||||||
|
try:
|
||||||
|
float( s )
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def makeNumeric( s ):
|
||||||
|
"Convert string to int or float if numeric."
|
||||||
|
if checkInt( s ):
|
||||||
|
return int( s )
|
||||||
|
elif checkFloat( s ):
|
||||||
|
return float( s )
|
||||||
|
else:
|
||||||
|
return s
|
||||||
Reference in New Issue
Block a user