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.
This commit is contained in:
Brandon Heller
2010-01-30 02:46:08 -08:00
parent 3774f234f0
commit befa1310df
3 changed files with 81 additions and 65 deletions
+39 -45
View File
@@ -3,18 +3,19 @@
""" """
Mininet runner Mininet runner
author: Brandon Heller (brandonh@stanford.edu) 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 from optparse import OptionParser
import os.path import os.path
import sys
import time import time
try:
from ripcord.dctopo import TreeTopo, FatTreeTopo, VL2Topo
USERIPCORD = True
except ImportError:
USERIPCORD = False
from mininet.log import lg, LEVELS from mininet.log import lg, LEVELS
from mininet.net import Mininet, init from mininet.net import Mininet, init
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
@@ -29,16 +30,6 @@ TOPOS = { 'minimal': ( lambda: SingleSwitchTopo( k=2 ) ),
'single100': ( lambda: SingleSwitchTopo( k=100 ) ), 'single100': ( lambda: SingleSwitchTopo( k=100 ) ),
'linear2': ( lambda: LinearTopo( k=2 ) ), 'linear2': ( lambda: LinearTopo( k=2 ) ),
'linear100': ( lambda: LinearTopo( k=100 ) ) } 'linear100': ( lambda: LinearTopo( k=100 ) ) }
if USERIPCORD:
TOPOSRIPCORD = {
'tree16': ( lambda: TreeTopo( depth=3, fanout=4 ) ),
'tree64': ( lambda: TreeTopo( depth=4, fanout=4 ) ),
'tree1024': ( lambda: TreeTopo( depth=3, fanout=32 ) ),
'fattree4': ( lambda: FatTreeTopo( k=4 ) ),
'fattree6': ( lambda: FatTreeTopo( k=6 ) ),
'vl2': ( lambda: VL2Topo( da=4, di=4 ) ),
'vl2reduced': ( lambda: VL2Topo( da=4, di=4, edgeDown=1 ) ) }
TOPOS.update( TOPOSRIPCORD )
SWITCHDEF = 'kernel' SWITCHDEF = 'kernel'
SWITCHES = { 'kernel': KernelSwitch, SWITCHES = { 'kernel': KernelSwitch,
@@ -57,8 +48,7 @@ CONTROLLERS = { 'ref': Controller,
'none': lambda a, b: None } 'none': lambda a, b: None }
# optional tests to run # optional tests to run
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp' ]
'iperfUdp' ]
def addDictOption( opts, choicesDict, default, name, helpStr=None ): def addDictOption( opts, choicesDict, default, name, helpStr=None ):
@@ -86,14 +76,37 @@ class MininetRunner( object ):
def __init__( self ): def __init__( self ):
"Init." "Init."
self.options = None self.options = None
self.validate = None
self.parseArgs() self.parseArgs()
self.setup() self.setup()
self.begin() 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 ): def parseArgs( self ):
"""Parse command-line args and return options object. """Parse command-line args and return options object.
returns: opts parse options dict""" 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() opts = OptionParser()
addDictOption( opts, TOPOS, TOPODEF, 'topo' ) addDictOption( opts, TOPOS, TOPODEF, 'topo' )
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' ) addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
@@ -101,7 +114,7 @@ class MininetRunner( object ):
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' ) addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
opts.add_option( '--custom', type='string', default=None, opts.add_option( '--custom', type='string', default=None,
help='read custom mininet from current dir' ) 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,
default=TESTS[ 0 ], default=TESTS[ 0 ],
help='[' + ' '.join( TESTS ) + ']' ) help='[' + ' '.join( TESTS ) + ']' )
@@ -133,18 +146,6 @@ class MininetRunner( object ):
# validate environment setup # validate environment setup
init() init()
# check for invalid combinations
if ( self.options.controller == 'ref' and
( ( 'fattree' in self.options.topo ) or
( 'vl2' in self.options.topo ) ) ):
raise Exception( 'multipath topos require multipath-capable '
'controller.' )
if self.options.custom:
if not os.path.isfile( self.options.custom ):
raise Exception( 'could not find custom file: %s' %
self.options.custom )
def begin( self ): def begin( self ):
"Create and run mininet." "Create and run mininet."
@@ -159,25 +160,18 @@ class MininetRunner( object ):
ipAddress=self.options.ip, ipAddress=self.options.ip,
port=self.options.port ) port=self.options.port )
if self.validate:
self.validate(self.options)
controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8 controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8
inNamespace = self.options.inNamespace inNamespace = self.options.inNamespace
xterms = self.options.xterms xterms = self.options.xterms
mac = self.options.mac mac = self.options.mac
arp = self.options.arp arp = self.options.arp
mn = None mn = Mininet( topo, switch, host, controller, controllerParams,
if not self.options.custom: inNamespace=inNamespace,
mn = Mininet( topo, switch, host, controller, controllerParams, xterms=xterms, autoSetMacs=mac,
inNamespace=inNamespace, autoStaticArp=arp )
xterms=xterms, autoSetMacs=mac,
autoStaticArp=arp )
else:
globals_ = {}
locals_ = {}
execfile( self.options.custom, globals_, locals_ )
if 'mn' not in locals_:
raise Exception( 'could not find mn var in custom file' )
else:
mn = locals_[ 'mn' ]
test = self.options.test test = self.options.test
if test != 'build': if test != 'build':
+39 -19
View File
@@ -1,25 +1,45 @@
'''Example of custom topo """Custom topology example
@author Brandon Heller (brandonh@stanford.edu) author: Brandon Heller (brandonh@stanford.edu)
''' Two directly connected switches plus a host for each switch:
from mininet.topo import SingleSwitchTopo host --- switch --- switch --- host
from mininet.net import Mininet
from mininet.node import KernelSwitch, Host, Controller, ControllerParams
topo = SingleSwitchTopo(k = 2) # build topology object Adding the 'topos' dict with a key/value pair to generate our newly defined
switch = KernelSwitch topology enables one to pass in '--topo=mytopo' from the command line.
host = Host """
controller = Controller
controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
in_namespace = False
xterms = False
mac = True
arp = True
mn = Mininet(topo, switch, host, controller, controller_params, from mininet.topo import Topo, Node
in_namespace = in_namespace,
xterms = xterms, auto_set_macs = mac,
auto_static_arp = arp)
class MyTopo( Topo ):
"""Simple topology example."""
def __init__( self, enable_all = True ):
"""Create custom topo."""
# Add default members to class.
super( MyTopo, self ).__init__()
# Set Node IDs for hosts and switches
leftHost = 1
leftSwitch = 2
rightSwitch = 3
rightHost = 4
# Add nodes
self._add_node( leftSwitch, Node( is_switch=True ) )
self._add_node( rightSwitch, Node( is_switch=True ) )
self._add_node( leftHost, Node( is_switch=False ) )
self._add_node( rightHost, Node( is_switch=False ) )
# Add edges
self._add_edge( leftHost, leftSwitch )
self._add_edge( leftSwitch, rightSwitch )
self._add_edge( rightSwitch, rightHost )
# Consider all switches and hosts 'on'
self.enable_all()
topos = { 'mytopo': ( lambda: MyTopo() ) }
+3 -1
View File
@@ -107,7 +107,7 @@ class Topo(object):
self.g.add_node(dpid) self.g.add_node(dpid)
self.node_info[dpid] = node self.node_info[dpid] = node
def _add_edge(self, src, dst, edge): def _add_edge(self, src, dst, edge = None):
'''Add edge (Node, Node) to graph. '''Add edge (Node, Node) to graph.
@param src src dpid @param src src dpid
@@ -116,6 +116,8 @@ class Topo(object):
''' '''
src, dst = tuple(sorted([src, dst])) src, dst = tuple(sorted([src, dst]))
self.g.add_edge(src, dst) self.g.add_edge(src, dst)
if not edge:
edge = Edge()
self.edge_info[(src, dst)] = edge self.edge_info[(src, dst)] = edge
self._add_port(src, dst) self._add_port(src, dst)