Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ e0cfcdd5

History | View | Annotate | Download (7.25 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.log import lg, LEVELS
20
from mininet.net import Mininet, init
21
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
22
from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
23
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
24

    
25
# built in topologies, created only when run
26
TOPODEF = 'minimal'
27
TOPOS = { 'minimal': ( lambda: SingleSwitchTopo( k=2 ) ),
28
         'reversed': ( lambda: SingleSwitchReversedTopo( k=2 ) ),
29
         'single4': ( lambda: SingleSwitchTopo( k=4 ) ),
30
         'single100': ( lambda: SingleSwitchTopo( k=100 ) ),
31
         'linear2': ( lambda: LinearTopo( k=2 ) ),
32
         'linear100': ( lambda: LinearTopo( k=100 ) ) }
33

    
34
SWITCHDEF = 'kernel'
35
SWITCHES = { 'kernel': KernelSwitch,
36
            'user': UserSwitch,
37
            'ovsk': OVSKernelSwitch }
38

    
39
HOSTDEF = 'process'
40
HOSTS = { 'process': Host }
41

    
42
CONTROLLERDEF = 'ref'
43
# a and b are the name and inNamespace params.
44
CONTROLLERS = { 'ref': Controller,
45
               'nox_dump': lambda a, b: NOX( a, b, 'packetdump' ),
46
               'nox_pysw': lambda a, b: NOX( a, b, 'pyswitch' ),
47
               'remote': lambda a, b: None,
48
               'none': lambda a, b: None }
49

    
50
# optional tests to run
51
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp' ]
52

    
53

    
54
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
55
    """Convenience function to add choices dicts to OptionParser.
56
       opts: OptionParser instance
57
       choicesDict: dictionary of valid choices, must include default
58
       default: default choice key
59
       name: long option name
60
       help: string"""
61
    if default not in choicesDict:
62
        raise Exception( 'Invalid  default %s for choices dict: %s' %
63
                        ( default, name ) )
64
    if not helpStr:
65
        helpStr = '[' + ' '.join( choicesDict.keys() ) + ']'
66
    opts.add_option( '--' + name,
67
                    type='choice',
68
                    choices=choicesDict.keys(),
69
                    default = default,
70
                    help = helpStr )
71

    
72

    
73
class MininetRunner( object ):
74
    "Build, setup, and run Mininet."
75

    
76
    def __init__( self ):
77
        "Init."
78
        self.options = None
79
        self.validate = None
80

    
81
        self.parseArgs()
82
        self.setup()
83
        self.begin()
84

    
85
    def setCustom( self, name, value ):
86
        "Set custom parameters for MininetRunner."
87
        if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
88
            # Update dictionaries
89
            param = name.upper()
90
            globals()[ param ].update( value )
91
        elif name == 'validate':
92
            # Add custom validate function
93
            self.validate = value
94
        else:
95
            # Add or modify global variable or class
96
            globals()[ name ] = value
97

    
98
    def parseCustomFile( self, fileName ):
99
        "Parse custom file and add params before parsing cmd-line options."
100
        custom = {}
101
        if os.path.isfile( fileName ):
102
            execfile( fileName, custom, custom )
103
            for name in custom:
104
                self.setCustom( name, custom[ name ] )
105
        else:
106
            raise Exception( 'could not find custom file: %s' % fileName )
107

    
108
    def parseArgs( self ):
109
        """Parse command-line args and return options object.
110
           returns: opts parse options dict"""
111
        if '--custom' in sys.argv:
112
            print "custom in sys.argv"
113
            index = sys.argv.index( '--custom' )
114
            if len( sys.argv ) > index + 1:
115
                custom = sys.argv[ index + 1 ]
116
                self.parseCustomFile( custom )
117
            else:
118
                raise Exception( 'Custom file name not found' )
119

    
120
        opts = OptionParser()
121
        addDictOption( opts, TOPOS, TOPODEF, 'topo' )
122
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
123
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
124
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
125

    
126
        opts.add_option( '--custom', type='string', default=None,
127
                        help='read custom topo and node params from .py file' )
128
        opts.add_option( '--test', type='choice', choices=TESTS,
129
                        default=TESTS[ 0 ],
130
                        help='[' + ' '.join( TESTS ) + ']' )
131
        opts.add_option( '--xterms', '-x', action='store_true',
132
                        default=False, help='spawn xterms for each node' )
133
        opts.add_option( '--mac', action='store_true',
134
                        default=False, help='set MACs equal to DPIDs' )
135
        opts.add_option( '--arp', action='store_true',
136
                        default=False, help='set all-pairs ARP entries' )
137
        opts.add_option( '--verbosity', '-v', type='choice',
138
                        choices=LEVELS.keys(), default = 'info',
139
                        help = '[' + ' '.join( LEVELS.keys() ) + ']' )
140
        opts.add_option( '--ip', type='string', default='127.0.0.1',
141
                        help='[ip address as a dotted decimal string for a'
142
                        'remote controller]' )
143
        opts.add_option( '--port', type='string', default=6633,
144
                        help='[port integer for a listening remote'
145
                        ' controller]' )
146
        opts.add_option( '--inNamespace', action='store_true',
147
                        default=False, help='sw and ctrl in namespace?' )
148
        self.options = opts.parse_args()[ 0 ]
149

    
150
    def setup( self ):
151
        "Setup and validate environment."
152

    
153
        # set logging verbosity
154
        lg.setLogLevel( self.options.verbosity )
155

    
156
        # validate environment setup
157
        init()
158

    
159
    def begin( self ):
160
        "Create and run mininet."
161

    
162
        start = time.time()
163

    
164
        topo = TOPOS[ self.options.topo ]() # build topology object
165
        switch = SWITCHES[ self.options.switch ]
166
        host = HOSTS[ self.options.host ]
167
        controller = CONTROLLERS[ self.options.controller ]
168
        if self.options.controller == 'remote':
169
            controller = lambda a, b: RemoteController( a, b,
170
                             ipAddress=self.options.ip,
171
                             port=self.options.port )
172

    
173
        if self.validate:
174
            self.validate( self.options )
175

    
176
        controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8
177
        inNamespace = self.options.inNamespace
178
        xterms = self.options.xterms
179
        mac = self.options.mac
180
        arp = self.options.arp
181
        mn = Mininet( topo, switch, host, controller, controllerParams,
182
                     inNamespace=inNamespace,
183
                     xterms=xterms, autoSetMacs=mac,
184
                     autoStaticArp=arp )
185

    
186
        test = self.options.test
187
        if test != 'build':
188
            if test == 'cli':
189
                mn.interact()
190
            elif test == 'all':
191
                mn.start()
192
                mn.ping()
193
                mn.iperf()
194
                mn.stop()
195
            else:
196
                mn.run( test )
197

    
198
        elapsed = float( time.time() - start )
199
        print ( 'completed in %0.3f seconds' % elapsed )
200

    
201

    
202
if __name__ == "__main__":
203
    MininetRunner()