Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ e2b799b8

History | View | Annotate | Download (9.86 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 )
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

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

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

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

    
66

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

    
71
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
72
    'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
73

    
74

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

    
93

    
94
def version( *_args ):
95
    "Print Mininet version and exit"
96
    print "%s" % VERSION
97
    exit()
98

    
99
class MininetRunner( object ):
100
    "Build, setup, and run Mininet."
101

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

    
108
        self.parseArgs()
109
        self.setup()
110
        self.begin()
111

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

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

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

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

    
150
        usage = ( '%prog [options]\n'
151
                  '(type %prog -h for details)' )
152

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

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

    
196
        self.options, self.args = opts.parse_args()
197

    
198
    def setup( self ):
199
        "Setup and validate environment."
200

    
201
        # set logging verbosity
202
        if LEVELS[self.options.verbosity] > LEVELS['output']:
203
            print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
204
                    'output!\n'
205
                    'Please restart Mininet with -v [debug, info, output].'
206
                    % self.options.verbosity )
207
        lg.setLogLevel( self.options.verbosity )
208

    
209
    def begin( self ):
210
        "Create and run mininet."
211

    
212
        if self.options.clean:
213
            cleanup()
214
            exit()
215

    
216
        start = time.time()
217

    
218
        topo = buildTopo( TOPOS, self.options.topo )
219
        switch = customConstructor( SWITCHES, self.options.switch )
220
        host = customConstructor( HOSTS, self.options.host )
221
        controller = customConstructor( CONTROLLERS, self.options.controller )
222
        link = customConstructor( LINKS, self.options.link )
223

    
224
        if self.validate:
225
            self.validate( self.options )
226

    
227
        inNamespace = self.options.innamespace
228
        Net = MininetWithControlNet if inNamespace else Mininet
229
        ipBase = self.options.ipbase
230
        xterms = self.options.xterms
231
        mac = self.options.mac
232
        arp = self.options.arp
233
        pin = self.options.pin
234
        listenPort = None
235
        if not self.options.nolistenport:
236
            listenPort = self.options.listenport
237
        mn = Net( topo=topo,
238
                  switch=switch, host=host, controller=controller,
239
                  link=link,
240
                  ipBase=ipBase,
241
                  inNamespace=inNamespace,
242
                  xterms=xterms, autoSetMacs=mac,
243
                  autoStaticArp=arp, autoPinCpus=pin,
244
                  listenPort=listenPort )
245

    
246
        if self.options.pre:
247
            CLI( mn, script=self.options.pre )
248

    
249
        test = self.options.test
250
        test = ALTSPELLING.get( test, test )
251

    
252
        mn.start()
253

    
254
        if test == 'none':
255
            pass
256
        elif test == 'all':
257
            mn.start()
258
            mn.ping()
259
            mn.iperf()
260
        elif test == 'cli':
261
            CLI( mn )
262
        elif test != 'build':
263
            getattr( mn, test )()
264

    
265
        if self.options.post:
266
            CLI( mn, script=self.options.post )
267

    
268
        mn.stop()
269

    
270
        elapsed = float( time.time() - start )
271
        info( 'completed in %0.3f seconds\n' % elapsed )
272

    
273

    
274
if __name__ == "__main__":
275
    MininetRunner()