Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ 27da832d

History | View | Annotate | Download (9.95 KB)

1
#!/usr/bin/env python
2

    
3
"""
4
Mininet runner
5
author: Brandon Heller (brandonh@stanford.edu)
6

    
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
"""
13

    
14
from optparse import OptionParser
15
import os
16
import sys
17
import time
18

    
19
# Fix setuptools' evil madness, and open up (more?) security holes
20
if 'PYTHONPATH' in os.environ:
21
    sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
22

    
23
from mininet.clean import cleanup
24
from mininet.cli import CLI
25
from mininet.log import lg, LEVELS, info
26
from mininet.net import Mininet, MininetWithControlNet, VERSION
27
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
28
                           NOX, RemoteController, UserSwitch, OVSKernelSwitch,
29
                           OVSLegacyKernelSwitch, IVSSwitch )
30
from mininet.link import Link, TCLink
31
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
32
from mininet.topolib import TreeTopo
33
from mininet.util import custom, customConstructor
34
from mininet.util import buildTopo
35

    
36

    
37
# built in topologies, created only when run
38
TOPODEF = 'minimal'
39
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
40
          'linear': LinearTopo,
41
          'reversed': SingleSwitchReversedTopo,
42
          'single': SingleSwitchTopo,
43
          'tree': TreeTopo }
44

    
45
SWITCHDEF = 'ovsk'
46
SWITCHES = { 'user': UserSwitch,
47
             'ovsk': OVSKernelSwitch,
48
             'ovsl': OVSLegacyKernelSwitch,
49
             'ivs': IVSSwitch }
50

    
51
HOSTDEF = 'proc'
52
HOSTS = { 'proc': Host,
53
          'rt': custom( CPULimitedHost, sched='rt' ),
54
          'cfs': custom( CPULimitedHost, sched='cfs' ) }
55

    
56
CONTROLLERDEF = 'ovsc'
57
CONTROLLERS = { 'ref': Controller,
58
                'ovsc': OVSController,
59
                'nox': NOX,
60
                'remote': RemoteController,
61
                'none': lambda name: None }
62

    
63
LINKDEF = 'default'
64
LINKS = { 'default': Link,
65
          'tc': TCLink }
66

    
67

    
68
# optional tests to run
69
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
70
          'none' ]
71

    
72
ALTSPELLING = { 'pingall': 'pingAll',
73
                'pingpair': 'pingPair',
74
                'iperfudp': 'iperfUdp',
75
                'iperfUDP': 'iperfUdp' }
76

    
77

    
78
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
79
    """Convenience function to add choices dicts to OptionParser.
80
       opts: OptionParser instance
81
       choicesDict: dictionary of valid choices, must include default
82
       default: default choice key
83
       name: long option name
84
       help: string"""
85
    if default not in choicesDict:
86
        raise Exception( 'Invalid  default %s for choices dict: %s' %
87
                         ( default, name ) )
88
    if not helpStr:
89
        helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
90
                    '[,param=value...]' )
91
    opts.add_option( '--' + name,
92
                     type='string',
93
                     default = default,
94
                     help = helpStr )
95

    
96

    
97
def version( *_args ):
98
    "Print Mininet version and exit"
99
    print "%s" % VERSION
100
    exit()
101

    
102
class MininetRunner( object ):
103
    "Build, setup, and run Mininet."
104

    
105
    def __init__( self ):
106
        "Init."
107
        self.options = None
108
        self.args = None  # May be used someday for more CLI scripts
109
        self.validate = None
110

    
111
        self.parseArgs()
112
        self.setup()
113
        self.begin()
114

    
115
    def setCustom( self, name, value ):
116
        "Set custom parameters for MininetRunner."
117
        if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
118
            # Update dictionaries
119
            param = name.upper()
120
            globals()[ param ].update( value )
121
        elif name == 'validate':
122
            # Add custom validate function
123
            self.validate = value
124
        else:
125
            # Add or modify global variable or class
126
            globals()[ name ] = value
127

    
128
    def parseCustomFile( self, fileName ):
129
        "Parse custom file and add params before parsing cmd-line options."
130
        customs = {}
131
        if os.path.isfile( fileName ):
132
            execfile( fileName, customs, customs )
133
            for name, val in customs.iteritems():
134
                self.setCustom( name, val )
135
        else:
136
            raise Exception( 'could not find custom file: %s' % fileName )
137

    
138
    def parseArgs( self ):
139
        """Parse command-line args and return options object.
140
           returns: opts parse options dict"""
141
        if '--custom' in sys.argv:
142
            index = sys.argv.index( '--custom' )
143
            if len( sys.argv ) > index + 1:
144
                filename = sys.argv[ index + 1 ]
145
                self.parseCustomFile( filename )
146
            else:
147
                raise Exception( 'Custom file name not found' )
148

    
149
        desc = ( "The %prog utility creates Mininet network from the\n"
150
                 "command line. It can create parametrized topologies,\n"
151
                 "invoke the Mininet CLI, and run tests." )
152

    
153
        usage = ( '%prog [options]\n'
154
                  '(type %prog -h for details)' )
155

    
156
        opts = OptionParser( description=desc, usage=usage )
157
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
158
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
159
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
160
        addDictOption( opts, LINKS, LINKDEF, 'link' )
161
        addDictOption( opts, TOPOS, TOPODEF, 'topo' )
162

    
163
        opts.add_option( '--clean', '-c', action='store_true',
164
                         default=False, help='clean and exit' )
165
        opts.add_option( '--custom', type='string', default=None,
166
                         help='read custom topo and node params from .py' +
167
                         'file' )
168
        opts.add_option( '--test', type='choice', choices=TESTS,
169
                         default=TESTS[ 0 ],
170
                         help='|'.join( TESTS ) )
171
        opts.add_option( '--xterms', '-x', action='store_true',
172
                         default=False, help='spawn xterms for each node' )
173
        opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
174
                         help='base IP address for hosts' )
175
        opts.add_option( '--mac', action='store_true',
176
                         default=False, help='automatically set host MACs' )
177
        opts.add_option( '--arp', action='store_true',
178
                         default=False, help='set all-pairs ARP entries' )
179
        opts.add_option( '--verbosity', '-v', type='choice',
180
                         choices=LEVELS.keys(), default = 'info',
181
                         help = '|'.join( LEVELS.keys() )  )
182
        opts.add_option( '--innamespace', action='store_true',
183
                         default=False, help='sw and ctrl in namespace?' )
184
        opts.add_option( '--listenport', type='int', default=6634,
185
                         help='base port for passive switch listening' )
186
        opts.add_option( '--nolistenport', action='store_true',
187
                         default=False, help="don't use passive listening " +
188
                         "port")
189
        opts.add_option( '--pre', type='string', default=None,
190
                         help='CLI script to run before tests' )
191
        opts.add_option( '--post', type='string', default=None,
192
                         help='CLI script to run after tests' )
193
        opts.add_option( '--pin', action='store_true',
194
                         default=False, help="pin hosts to CPU cores "
195
                         "(requires --host cfs or --host rt)" )
196
        opts.add_option( '--version', action='callback', callback=version )
197

    
198
        self.options, self.args = opts.parse_args()
199

    
200
        # We don't accept extra arguments after the options
201
        if self.args:
202
            opts.print_help()
203
            exit()
204

    
205
    def setup( self ):
206
        "Setup and validate environment."
207

    
208
        # set logging verbosity
209
        if LEVELS[self.options.verbosity] > LEVELS['output']:
210
            print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
211
                    'output!\n'
212
                    'Please restart Mininet with -v [debug, info, output].'
213
                    % self.options.verbosity )
214
        lg.setLogLevel( self.options.verbosity )
215

    
216
    def begin( self ):
217
        "Create and run mininet."
218

    
219
        if self.options.clean:
220
            cleanup()
221
            exit()
222

    
223
        start = time.time()
224

    
225
        topo = buildTopo( TOPOS, self.options.topo )
226
        switch = customConstructor( SWITCHES, self.options.switch )
227
        host = customConstructor( HOSTS, self.options.host )
228
        controller = customConstructor( CONTROLLERS, self.options.controller )
229
        link = customConstructor( LINKS, self.options.link )
230

    
231
        if self.validate:
232
            self.validate( self.options )
233

    
234
        inNamespace = self.options.innamespace
235
        Net = MininetWithControlNet if inNamespace else Mininet
236
        ipBase = self.options.ipbase
237
        xterms = self.options.xterms
238
        mac = self.options.mac
239
        arp = self.options.arp
240
        pin = self.options.pin
241
        listenPort = None
242
        if not self.options.nolistenport:
243
            listenPort = self.options.listenport
244
        mn = Net( topo=topo,
245
                  switch=switch, host=host, controller=controller,
246
                  link=link,
247
                  ipBase=ipBase,
248
                  inNamespace=inNamespace,
249
                  xterms=xterms, autoSetMacs=mac,
250
                  autoStaticArp=arp, autoPinCpus=pin,
251
                  listenPort=listenPort )
252

    
253
        if self.options.pre:
254
            CLI( mn, script=self.options.pre )
255

    
256
        test = self.options.test
257
        test = ALTSPELLING.get( test, test )
258

    
259
        mn.start()
260

    
261
        if test == 'none':
262
            pass
263
        elif test == 'all':
264
            mn.start()
265
            mn.ping()
266
            mn.iperf()
267
        elif test == 'cli':
268
            CLI( mn )
269
        elif test != 'build':
270
            getattr( mn, test )()
271

    
272
        if self.options.post:
273
            CLI( mn, script=self.options.post )
274

    
275
        mn.stop()
276

    
277
        elapsed = float( time.time() - start )
278
        info( 'completed in %0.3f seconds\n' % elapsed )
279

    
280

    
281
if __name__ == "__main__":
282
    MininetRunner()