Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ e2b799b8

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