Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ d85a58fe

History | View | Annotate | Download (9.64 KB)

1 a6b47322 Brandon Heller
#!/usr/bin/env python
2
3 8895862a Bob Lantz
"""
4
Mininet runner
5
author: Brandon Heller (brandonh@stanford.edu)
6 befa1310 Brandon Heller
7
To see options:
8
  sudo mn -h
9
10
Example to pull custom params (topo, switch, etc.) from a file:
11
  sudo mn --custom ~/mininet/custom/custom_example.py
12 8895862a Bob Lantz
"""
13 a6b47322 Brandon Heller
14
from optparse import OptionParser
15 3031d31e Brandon Heller
import os.path
16 befa1310 Brandon Heller
import sys
17 a6b47322 Brandon Heller
import time
18
19 3eb5abe6 Brandon Heller
from mininet.clean import cleanup
20 d869d820 Bob Lantz
from mininet.cli import CLI
21 2db4268b Bob Lantz
from mininet.log import lg, LEVELS, info, warn
22 39128f8c Bob Lantz
from mininet.net import Mininet, MininetWithControlNet, VERSION
23 612b21cb Bob Lantz
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
24
                           NOX, RemoteController, UserSwitch, OVSKernelSwitch,
25 335ba99b Bob Lantz
                           OVSLegacyKernelSwitch )
26 ff568819 Bob Lantz
from mininet.link import Link, TCLink
27 6d2cd77b Brandon Heller
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
28 509a852f Brandon Heller
from mininet.topolib import TreeTopo
29 928c0761 Brandon Heller
from mininet.util import makeNumeric, custom, customConstructor, splitArgs
30
from mininet.util import buildTopo
31 a6b47322 Brandon Heller
32 2db4268b Bob Lantz
33 a6b47322 Brandon Heller
# built in topologies, created only when run
34 8895862a Bob Lantz
TOPODEF = 'minimal'
35 bb941950 Brandon Heller
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
36
         'linear': LinearTopo,
37
         'reversed': SingleSwitchReversedTopo,
38 509a852f Brandon Heller
         'single': SingleSwitchTopo,
39
         'tree': TreeTopo }
40 8895862a Bob Lantz
41 0a6e5423 Brandon Heller
SWITCHDEF = 'ovsk'
42 7d557fd7 Bob Lantz
SWITCHES = { 'user': UserSwitch,
43 335ba99b Bob Lantz
            'ovsk': OVSKernelSwitch,
44
             'ovsl': OVSLegacyKernelSwitch }
45 a6b47322 Brandon Heller
46 216a4b7c Bob Lantz
HOSTDEF = 'proc'
47
HOSTS = { 'proc': Host,
48
          'rt': custom( CPULimitedHost, sched='rt' ),
49
          'cfs': custom( CPULimitedHost, sched='cfs' ) }
50 a6b47322 Brandon Heller
51 ec969b7f Bob Lantz
CONTROLLERDEF = 'ovsc'
52 8895862a Bob Lantz
CONTROLLERS = { 'ref': Controller,
53 9addfc13 Bob Lantz
                'ovsc': OVSController,
54 14ff3ad3 Bob Lantz
                'nox': NOX,
55 9addfc13 Bob Lantz
                'remote': RemoteController,
56
                'none': lambda name: None }
57 a6b47322 Brandon Heller
58 ff568819 Bob Lantz
LINKDEF = 'default'
59
LINKS = { 'default': Link,
60
          'tc': TCLink }
61 216a4b7c Bob Lantz
62
63 a6b47322 Brandon Heller
# optional tests to run
64 d869d820 Bob Lantz
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
65 dfc08a86 Brandon Heller
         'none' ]
66 8895862a Bob Lantz
67 d869d820 Bob Lantz
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
68 cc960215 Bob Lantz
    'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
69 8895862a Bob Lantz
70 216a4b7c Bob Lantz
71 8895862a Bob Lantz
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
72
    """Convenience function to add choices dicts to OptionParser.
73
       opts: OptionParser instance
74
       choicesDict: dictionary of valid choices, must include default
75
       default: default choice key
76
       name: long option name
77
       help: string"""
78
    if default not in choicesDict:
79
        raise Exception( 'Invalid  default %s for choices dict: %s' %
80
                        ( default, name ) )
81
    if not helpStr:
82 14ff3ad3 Bob Lantz
        helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
83
                   '[,param=value...]' )
84 8895862a Bob Lantz
    opts.add_option( '--' + name,
85 216a4b7c Bob Lantz
                    type='string',
86 a6b47322 Brandon Heller
                    default = default,
87 8895862a Bob Lantz
                    help = helpStr )
88 a6b47322 Brandon Heller
89
90 39128f8c Bob Lantz
def version( *_args ):
91
    "Print Mininet version and exit"
92 d85a58fe Bob Lantz
    print "%s" % VERSION
93 39128f8c Bob Lantz
    exit()
94
95 8895862a Bob Lantz
class MininetRunner( object ):
96
    "Build, setup, and run Mininet."
97 a6b47322 Brandon Heller
98 8895862a Bob Lantz
    def __init__( self ):
99
        "Init."
100 a6b47322 Brandon Heller
        self.options = None
101 d869d820 Bob Lantz
        self.args = None  # May be used someday for more CLI scripts
102 befa1310 Brandon Heller
        self.validate = None
103 723d068c Brandon Heller
104 8895862a Bob Lantz
        self.parseArgs()
105 a6b47322 Brandon Heller
        self.setup()
106
        self.begin()
107 e0cfcdd5 Bob Lantz
108 c3a44400 Bob Lantz
    def setCustom( self, name, value ):
109 e0cfcdd5 Bob Lantz
        "Set custom parameters for MininetRunner."
110 c3a44400 Bob Lantz
        if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
111
            # Update dictionaries
112
            param = name.upper()
113
            globals()[ param ].update( value )
114
        elif name == 'validate':
115
            # Add custom validate function
116
            self.validate = value
117
        else:
118
            # Add or modify global variable or class
119
            globals()[ name ] = value
120 e0cfcdd5 Bob Lantz
121 c3a44400 Bob Lantz
    def parseCustomFile( self, fileName ):
122 befa1310 Brandon Heller
        "Parse custom file and add params before parsing cmd-line options."
123 14ff3ad3 Bob Lantz
        customs = {}
124 c3a44400 Bob Lantz
        if os.path.isfile( fileName ):
125 14ff3ad3 Bob Lantz
            execfile( fileName, customs, customs )
126
            for name, val in customs.iteritems():
127
                self.setCustom( name, val )
128 befa1310 Brandon Heller
        else:
129 c3a44400 Bob Lantz
            raise Exception( 'could not find custom file: %s' % fileName )
130 e0cfcdd5 Bob Lantz
131 8895862a Bob Lantz
    def parseArgs( self ):
132
        """Parse command-line args and return options object.
133
           returns: opts parse options dict"""
134 befa1310 Brandon Heller
        if '--custom' in sys.argv:
135
            index = sys.argv.index( '--custom' )
136
            if len( sys.argv ) > index + 1:
137 14ff3ad3 Bob Lantz
                filename = sys.argv[ index + 1 ]
138
                self.parseCustomFile( filename )
139 befa1310 Brandon Heller
            else:
140
                raise Exception( 'Custom file name not found' )
141
142 f2e7884a Bob Lantz
        desc = ( "The %prog utility creates Mininet network from the\n"
143
                 "command line. It can create parametrized topologies,\n"
144
                 "invoke the Mininet CLI, and run tests." )
145
146
        opts = OptionParser( description=desc )
147 8895862a Bob Lantz
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
148
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
149
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
150 ff568819 Bob Lantz
        addDictOption( opts, LINKS, LINKDEF, 'link' )
151 216a4b7c Bob Lantz
        addDictOption( opts, TOPOS, TOPODEF, 'topo' )
152 8895862a Bob Lantz
153 3eb5abe6 Brandon Heller
        opts.add_option( '--clean', '-c', action='store_true',
154
                        default=False, help='clean and exit' )
155 8895862a Bob Lantz
        opts.add_option( '--custom', type='string', default=None,
156 befa1310 Brandon Heller
                        help='read custom topo and node params from .py file' )
157 8895862a Bob Lantz
        opts.add_option( '--test', type='choice', choices=TESTS,
158
                        default=TESTS[ 0 ],
159 216a4b7c Bob Lantz
                        help='|'.join( TESTS ) )
160 8895862a Bob Lantz
        opts.add_option( '--xterms', '-x', action='store_true',
161
                        default=False, help='spawn xterms for each node' )
162 82f483f5 Bob Lantz
        opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
163
                         help='base IP address for hosts' )
164 8895862a Bob Lantz
        opts.add_option( '--mac', action='store_true',
165 216a4b7c Bob Lantz
                        default=False, help='automatically set host MACs' )
166 8895862a Bob Lantz
        opts.add_option( '--arp', action='store_true',
167
                        default=False, help='set all-pairs ARP entries' )
168
        opts.add_option( '--verbosity', '-v', type='choice',
169
                        choices=LEVELS.keys(), default = 'info',
170 216a4b7c Bob Lantz
                        help = '|'.join( LEVELS.keys() )  )
171 d869d820 Bob Lantz
        opts.add_option( '--innamespace', action='store_true',
172 8895862a Bob Lantz
                        default=False, help='sw and ctrl in namespace?' )
173 8856d284 Bob Lantz
        opts.add_option( '--listenport', type='int', default=6635,
174 216a4b7c Bob Lantz
                         help='base port for passive switch listening' )
175 0a9358c9 Brandon Heller
        opts.add_option( '--nolistenport', action='store_true',
176
                        default=False, help="don't use passive listening port")
177 d869d820 Bob Lantz
        opts.add_option( '--pre', type='string', default=None,
178 216a4b7c Bob Lantz
                        help='CLI script to run before tests' )
179 d869d820 Bob Lantz
        opts.add_option( '--post', type='string', default=None,
180 216a4b7c Bob Lantz
                        help='CLI script to run after tests' )
181 cc960215 Bob Lantz
        opts.add_option( '--prefixlen', type='int', default=8,
182 216a4b7c Bob Lantz
                        help='prefix length (e.g. /8) for automatic '
183
                        'network configuration' )
184 197b083f Bob Lantz
        opts.add_option( '--pin', action='store_true',
185
                         default=False, help="pin hosts to CPU cores "
186
                         "(requires --host cfs or --host rt)" )
187 39128f8c Bob Lantz
        opts.add_option( '--version', action='callback', callback=version )
188 87737a70 Bob Lantz
189 d869d820 Bob Lantz
        self.options, self.args = opts.parse_args()
190 8895862a Bob Lantz
191
    def setup( self ):
192
        "Setup and validate environment."
193 a6b47322 Brandon Heller
194
        # set logging verbosity
195 cdeaca86 Brandon Heller
        if LEVELS[self.options.verbosity] > LEVELS['output']:
196 1a40cd04 Brandon Heller
            print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
197
                    'output!\n'
198 1dcc0476 Bob Lantz
                    'Please restart Mininet with -v [debug, info, output].'
199
                    % self.options.verbosity )
200 8895862a Bob Lantz
        lg.setLogLevel( self.options.verbosity )
201 a6b47322 Brandon Heller
202 8895862a Bob Lantz
    def begin( self ):
203
        "Create and run mininet."
204 a6b47322 Brandon Heller
205 3eb5abe6 Brandon Heller
        if self.options.clean:
206
            cleanup()
207
            exit()
208
209 a6b47322 Brandon Heller
        start = time.time()
210
211 928c0761 Brandon Heller
        topo = buildTopo( TOPOS, self.options.topo )
212 30b4b4e7 Brandon Heller
        switch = customConstructor( SWITCHES, self.options.switch )
213
        host = customConstructor( HOSTS, self.options.host )
214
        controller = customConstructor( CONTROLLERS, self.options.controller )
215
        link = customConstructor( LINKS, self.options.link )
216 a6b47322 Brandon Heller
217 befa1310 Brandon Heller
        if self.validate:
218 c3a44400 Bob Lantz
            self.validate( self.options )
219 befa1310 Brandon Heller
220 d869d820 Bob Lantz
        inNamespace = self.options.innamespace
221 14ff3ad3 Bob Lantz
        Net = MininetWithControlNet if inNamespace else Mininet
222 82f483f5 Bob Lantz
        ipBase = self.options.ipbase
223 8a034f4f Brandon Heller
        xterms = self.options.xterms
224 376bcba4 Brandon Heller
        mac = self.options.mac
225
        arp = self.options.arp
226 197b083f Bob Lantz
        pin = self.options.pin
227 0a9358c9 Brandon Heller
        listenPort = None
228
        if not self.options.nolistenport:
229
            listenPort = self.options.listenport
230 14ff3ad3 Bob Lantz
        mn = Net( topo=topo,
231
                  switch=switch, host=host, controller=controller,
232 ff568819 Bob Lantz
                  link=link,
233 14ff3ad3 Bob Lantz
                  ipBase=ipBase,
234
                  inNamespace=inNamespace,
235
                  xterms=xterms, autoSetMacs=mac,
236 197b083f Bob Lantz
                  autoStaticArp=arp, autoPinCpus=pin,
237
                  listenPort=listenPort )
238 87737a70 Bob Lantz
239 d869d820 Bob Lantz
        if self.options.pre:
240
            CLI( mn, script=self.options.pre )
241 a6b47322 Brandon Heller
242 eeb9cb3c Brandon Heller
        test = self.options.test
243 d869d820 Bob Lantz
        test = ALTSPELLING.get( test, test )
244 f95aebb4 Bob Lantz
245 d869d820 Bob Lantz
        mn.start()
246 f95aebb4 Bob Lantz
247 dfc08a86 Brandon Heller
        if test == 'none':
248 d869d820 Bob Lantz
            pass
249 dfc08a86 Brandon Heller
        elif test == 'all':
250
            mn.start()
251
            mn.ping()
252
            mn.iperf()
253 d869d820 Bob Lantz
        elif test == 'cli':
254
            CLI( mn )
255 dfc08a86 Brandon Heller
        elif test != 'build':
256 d869d820 Bob Lantz
            getattr( mn, test )()
257
258
        if self.options.post:
259
            CLI( mn, script=self.options.post )
260
261
        mn.stop()
262 a6b47322 Brandon Heller
263 8895862a Bob Lantz
        elapsed = float( time.time() - start )
264 4e69ae83 Brandon Heller
        info( 'completed in %0.3f seconds\n' % elapsed )
265 a6b47322 Brandon Heller
266
267
if __name__ == "__main__":
268 83086439 Brandon Heller
    MininetRunner()