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() |