Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ d85a58fe

History | View | Annotate | Download (9.64 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.path
16
import sys
17
import time
18

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

    
32

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

    
41
SWITCHDEF = 'ovsk'
42
SWITCHES = { 'user': UserSwitch,
43
            'ovsk': OVSKernelSwitch,
44
             'ovsl': OVSLegacyKernelSwitch }
45

    
46
HOSTDEF = 'proc'
47
HOSTS = { 'proc': Host,
48
          'rt': custom( CPULimitedHost, sched='rt' ),
49
          'cfs': custom( CPULimitedHost, sched='cfs' ) }
50

    
51
CONTROLLERDEF = 'ovsc'
52
CONTROLLERS = { 'ref': Controller,
53
                'ovsc': OVSController,
54
                'nox': NOX,
55
                'remote': RemoteController,
56
                'none': lambda name: None }
57

    
58
LINKDEF = 'default'
59
LINKS = { 'default': Link,
60
          'tc': TCLink }
61

    
62

    
63
# optional tests to run
64
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
65
         'none' ]
66

    
67
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
68
    'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
69

    
70

    
71
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
        helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
83
                   '[,param=value...]' )
84
    opts.add_option( '--' + name,
85
                    type='string',
86
                    default = default,
87
                    help = helpStr )
88

    
89

    
90
def version( *_args ):
91
    "Print Mininet version and exit"
92
    print "%s" % VERSION
93
    exit()
94

    
95
class MininetRunner( object ):
96
    "Build, setup, and run Mininet."
97

    
98
    def __init__( self ):
99
        "Init."
100
        self.options = None
101
        self.args = None  # May be used someday for more CLI scripts
102
        self.validate = None
103

    
104
        self.parseArgs()
105
        self.setup()
106
        self.begin()
107

    
108
    def setCustom( self, name, value ):
109
        "Set custom parameters for MininetRunner."
110
        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

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

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

    
142
        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
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
148
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
149
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
150
        addDictOption( opts, LINKS, LINKDEF, 'link' )
151
        addDictOption( opts, TOPOS, TOPODEF, 'topo' )
152

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

    
189
        self.options, self.args = opts.parse_args()
190

    
191
    def setup( self ):
192
        "Setup and validate environment."
193

    
194
        # set logging verbosity
195
        if LEVELS[self.options.verbosity] > LEVELS['output']:
196
            print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
197
                    'output!\n'
198
                    'Please restart Mininet with -v [debug, info, output].'
199
                    % self.options.verbosity )
200
        lg.setLogLevel( self.options.verbosity )
201

    
202
    def begin( self ):
203
        "Create and run mininet."
204

    
205
        if self.options.clean:
206
            cleanup()
207
            exit()
208

    
209
        start = time.time()
210

    
211
        topo = buildTopo( TOPOS, self.options.topo )
212
        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

    
217
        if self.validate:
218
            self.validate( self.options )
219

    
220
        inNamespace = self.options.innamespace
221
        Net = MininetWithControlNet if inNamespace else Mininet
222
        ipBase = self.options.ipbase
223
        xterms = self.options.xterms
224
        mac = self.options.mac
225
        arp = self.options.arp
226
        pin = self.options.pin
227
        listenPort = None
228
        if not self.options.nolistenport:
229
            listenPort = self.options.listenport
230
        mn = Net( topo=topo,
231
                  switch=switch, host=host, controller=controller,
232
                  link=link,
233
                  ipBase=ipBase,
234
                  inNamespace=inNamespace,
235
                  xterms=xterms, autoSetMacs=mac,
236
                  autoStaticArp=arp, autoPinCpus=pin,
237
                  listenPort=listenPort )
238

    
239
        if self.options.pre:
240
            CLI( mn, script=self.options.pre )
241

    
242
        test = self.options.test
243
        test = ALTSPELLING.get( test, test )
244

    
245
        mn.start()
246

    
247
        if test == 'none':
248
            pass
249
        elif test == 'all':
250
            mn.start()
251
            mn.ping()
252
            mn.iperf()
253
        elif test == 'cli':
254
            CLI( mn )
255
        elif test != 'build':
256
            getattr( mn, test )()
257

    
258
        if self.options.post:
259
            CLI( mn, script=self.options.post )
260

    
261
        mn.stop()
262

    
263
        elapsed = float( time.time() - start )
264
        info( 'completed in %0.3f seconds\n' % elapsed )
265

    
266

    
267
if __name__ == "__main__":
268
    MininetRunner()