mininet / mininet / util.py @ 7c5d2771
History | View | Annotate | Download (19 KB)
1 | 80a8fa62 | Bob Lantz | "Utility functions for Mininet."
|
---|---|---|---|
2 | 220890a0 | Brandon Heller | |
3 | 4ea0c093 | Brian O'Connor | from mininet.log import output, info, error, warn, debug |
4 | 50cebe67 | Bob Lantz | |
5 | 867a6d67 | Brian O'Connor | from time import sleep |
6 | b20c9470 | Brian O'Connor | from resource import getrlimit, setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE |
7 | 31fe4f1b | Bob Lantz | from select import poll, POLLIN, POLLHUP |
8 | 220890a0 | Brandon Heller | from subprocess import call, check_call, Popen, PIPE, STDOUT |
9 | 134a75ef | Bob Lantz | import re |
10 | 50cebe67 | Bob Lantz | from fcntl import fcntl, F_GETFL, F_SETFL |
11 | from os import O_NONBLOCK |
||
12 | bcfb3009 | Brandon Heller | import os |
13 | a565bdd5 | cody burkard | from functools import partial |
14 | 82b72072 | Bob Lantz | |
15 | # Command execution support
|
||
16 | 220890a0 | Brandon Heller | |
17 | 80a8fa62 | Bob Lantz | def run( cmd ): |
18 | """Simple interface to subprocess.call()
|
||
19 | cmd: list of command params"""
|
||
20 | return call( cmd.split( ' ' ) ) |
||
21 | |||
22 | def checkRun( cmd ): |
||
23 | """Simple interface to subprocess.check_call()
|
||
24 | cmd: list of command params"""
|
||
25 | efc9a01c | Bob Lantz | return check_call( cmd.split( ' ' ) ) |
26 | 80a8fa62 | Bob Lantz | |
27 | 82b72072 | Bob Lantz | # pylint doesn't understand explicit type checking
|
28 | # pylint: disable-msg=E1103
|
||
29 | |||
30 | daa576c4 | Bob Lantz | def oldQuietRun( *cmd ): |
31 | 80a8fa62 | Bob Lantz | """Run a command, routing stderr to stdout, and return the output.
|
32 | cmd: list of command params"""
|
||
33 | 8bc00379 | Bob Lantz | if len( cmd ) == 1: |
34 | cmd = cmd[ 0 ]
|
||
35 | 82b72072 | Bob Lantz | if isinstance( cmd, str ): |
36 | cmd = cmd.split( ' ' )
|
||
37 | 80a8fa62 | Bob Lantz | popen = Popen( cmd, stdout=PIPE, stderr=STDOUT ) |
38 | 220890a0 | Brandon Heller | # We can't use Popen.communicate() because it uses
|
39 | # select(), which can't handle
|
||
40 | # high file descriptor numbers! poll() can, however.
|
||
41 | 134a75ef | Bob Lantz | out = ''
|
42 | daa576c4 | Bob Lantz | readable = poll() |
43 | 80a8fa62 | Bob Lantz | readable.register( popen.stdout ) |
44 | 220890a0 | Brandon Heller | while True: |
45 | while readable.poll():
|
||
46 | 80a8fa62 | Bob Lantz | data = popen.stdout.read( 1024 )
|
47 | if len( data ) == 0: |
||
48 | 220890a0 | Brandon Heller | break
|
49 | 134a75ef | Bob Lantz | out += data |
50 | 220890a0 | Brandon Heller | popen.poll() |
51 | 7a506047 | Brandon Heller | if popen.returncode is not None: |
52 | 220890a0 | Brandon Heller | break
|
53 | 134a75ef | Bob Lantz | return out
|
54 | 220890a0 | Brandon Heller | |
55 | 14ff3ad3 | Bob Lantz | |
56 | daa576c4 | Bob Lantz | # This is a bit complicated, but it enables us to
|
57 | 6e64deec | Bob Lantz | # monitor command output as it is happening
|
58 | daa576c4 | Bob Lantz | |
59 | 14ff3ad3 | Bob Lantz | def errRun( *cmd, **kwargs ): |
60 | daa576c4 | Bob Lantz | """Run a command and return stdout, stderr and return code
|
61 | cmd: string or list of command and args
|
||
62 | stderr: STDOUT to merge stderr with stdout
|
||
63 | shell: run command using shell
|
||
64 | echo: monitor output to console"""
|
||
65 | # By default we separate stderr, don't run in a shell, and don't echo
|
||
66 | stderr = kwargs.get( 'stderr', PIPE )
|
||
67 | shell = kwargs.get( 'shell', False ) |
||
68 | echo = kwargs.get( 'echo', False ) |
||
69 | 551a3666 | Bob Lantz | if echo:
|
70 | # cmd goes to stderr, output goes to stdout
|
||
71 | info( cmd, '\n' )
|
||
72 | a565bdd5 | cody burkard | if len( cmd ) == 1: |
73 | cmd = cmd[ 0 ]
|
||
74 | # Allow passing in a list or a string
|
||
75 | if isinstance( cmd, str ) and not shell: |
||
76 | cmd = cmd.split( ' ' )
|
||
77 | cmd = [ str( arg ) for arg in cmd ] |
||
78 | elif isinstance( cmd, list ) and shell: |
||
79 | cmd = " ".join( arg for arg in cmd ) |
||
80 | daa576c4 | Bob Lantz | popen = Popen( cmd, stdout=PIPE, stderr=stderr, shell=shell ) |
81 | cfd38113 | Bob Lantz | # We use poll() because select() doesn't work with large fd numbers,
|
82 | # and thus communicate() doesn't work either
|
||
83 | daa576c4 | Bob Lantz | out, err = '', '' |
84 | poller = poll() |
||
85 | poller.register( popen.stdout, POLLIN ) |
||
86 | fdtofile = { popen.stdout.fileno(): popen.stdout } |
||
87 | cfd38113 | Bob Lantz | outDone, errDone = False, True |
88 | daa576c4 | Bob Lantz | if popen.stderr:
|
89 | fdtofile[ popen.stderr.fileno() ] = popen.stderr |
||
90 | poller.register( popen.stderr, POLLIN ) |
||
91 | cfd38113 | Bob Lantz | errDone = False
|
92 | while not outDone or not errDone: |
||
93 | daa576c4 | Bob Lantz | readable = poller.poll() |
94 | e8d60e0f | Bob Lantz | for fd, _event in readable: |
95 | daa576c4 | Bob Lantz | f = fdtofile[ fd ] |
96 | data = f.read( 1024 )
|
||
97 | if echo:
|
||
98 | output( data ) |
||
99 | if f == popen.stdout:
|
||
100 | out += data |
||
101 | cfd38113 | Bob Lantz | if data == '': |
102 | outDone = True
|
||
103 | daa576c4 | Bob Lantz | elif f == popen.stderr:
|
104 | err += data |
||
105 | cfd38113 | Bob Lantz | if data == '': |
106 | errDone = True
|
||
107 | returncode = popen.wait() |
||
108 | daa576c4 | Bob Lantz | return out, err, returncode
|
109 | |||
110 | 551a3666 | Bob Lantz | def errFail( *cmd, **kwargs ): |
111 | "Run a command using errRun and raise exception on nonzero exit"
|
||
112 | out, err, ret = errRun( *cmd, **kwargs ) |
||
113 | if ret:
|
||
114 | a5af91d0 | Bob Lantz | raise Exception( "errFail: %s failed with return code %s: %s" |
115 | % ( cmd, ret, err ) ) |
||
116 | 551a3666 | Bob Lantz | return out, err, ret
|
117 | |||
118 | daa576c4 | Bob Lantz | def quietRun( cmd, **kwargs ): |
119 | "Run a command and return merged stdout and stderr"
|
||
120 | return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ] |
||
121 | 220890a0 | Brandon Heller | |
122 | 82b72072 | Bob Lantz | # pylint: enable-msg=E1103
|
123 | e8d60e0f | Bob Lantz | # pylint: disable-msg=E1101
|
124 | 82b72072 | Bob Lantz | |
125 | def isShellBuiltin( cmd ): |
||
126 | "Return True if cmd is a bash builtin."
|
||
127 | if isShellBuiltin.builtIns is None: |
||
128 | isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
|
||
129 | space = cmd.find( ' ' )
|
||
130 | if space > 0: |
||
131 | cmd = cmd[ :space] |
||
132 | return cmd in isShellBuiltin.builtIns |
||
133 | |||
134 | isShellBuiltin.builtIns = None
|
||
135 | |||
136 | e8d60e0f | Bob Lantz | # pylint: enable-msg=E1101
|
137 | 82b72072 | Bob Lantz | |
138 | 220890a0 | Brandon Heller | # Interface management
|
139 | #
|
||
140 | # Interfaces are managed as strings which are simply the
|
||
141 | # interface names, of the form 'nodeN-ethM'.
|
||
142 | #
|
||
143 | # To connect nodes, we create a pair of veth interfaces, and then place them
|
||
144 | # in the pair of nodes that we want to communicate. We then update the node's
|
||
145 | # list of interfaces and connectivity map.
|
||
146 | #
|
||
147 | # For the kernel datapath, switch interfaces
|
||
148 | # live in the root namespace and thus do not have to be
|
||
149 | # explicitly moved.
|
||
150 | |||
151 | c265deed | Bob Lantz | def makeIntfPair( intf1, intf2, addr1=None, addr2=None, run=quietRun ): |
152 | 80a8fa62 | Bob Lantz | """Make a veth pair connecting intf1 and intf2.
|
153 | intf1: string, interface
|
||
154 | intf2: string, interface
|
||
155 | c265deed | Bob Lantz | node: node to run on or None (default)
|
156 | returns: ip link add result"""
|
||
157 | 220890a0 | Brandon Heller | # Delete any old interfaces with the same names
|
158 | c265deed | Bob Lantz | run( 'ip link del ' + intf1 )
|
159 | run( 'ip link del ' + intf2 )
|
||
160 | 220890a0 | Brandon Heller | # Create new pair
|
161 | eba13f0c | cody burkard | if addr1 is None and addr2 is None: |
162 | cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2 |
||
163 | else:
|
||
164 | cmd = ( 'ip link add name ' + intf1 + ' address ' + addr1 + |
||
165 | ' type veth peer name ' + intf2 + ' address ' + addr2 ) |
||
166 | c265deed | Bob Lantz | cmdOutput = run( cmd ) |
167 | 2e704f99 | Andrew Ferguson | if cmdOutput == '': |
168 | return True |
||
169 | else:
|
||
170 | error( "Error creating interface pair: %s " % cmdOutput )
|
||
171 | return False |
||
172 | 80a8fa62 | Bob Lantz | |
173 | def retry( retries, delaySecs, fn, *args, **keywords ): |
||
174 | """Try something several times before giving up.
|
||
175 | n: number of times to retry
|
||
176 | delaySecs: wait this long between tries
|
||
177 | fn: function to call
|
||
178 | args: args to apply to function call"""
|
||
179 | tries = 0
|
||
180 | while not fn( *args, **keywords ) and tries < retries: |
||
181 | sleep( delaySecs ) |
||
182 | tries += 1
|
||
183 | if tries >= retries:
|
||
184 | 82b72072 | Bob Lantz | error( "*** gave up after %i retries\n" % tries )
|
185 | 80a8fa62 | Bob Lantz | exit( 1 ) |
186 | |||
187 | c265deed | Bob Lantz | def moveIntfNoRetry( intf, dstNode, printError=False ): |
188 | 80a8fa62 | Bob Lantz | """Move interface to node, without retrying.
|
189 | intf: string, interface
|
||
190 | c771b2d7 | Bob Lantz | dstNode: destination Node
|
191 | printError: if true, print error"""
|
||
192 | intf = str( intf )
|
||
193 | cmd = 'ip link set %s netns %s' % ( intf, dstNode.pid )
|
||
194 | c265deed | Bob Lantz | cmdOutput = quietRun( cmd ) |
195 | 41a54f05 | cody burkard | # If ip link set does not produce any output, then we can assume
|
196 | # that the link has been moved successfully.
|
||
197 | a3d51b77 | cody burkard | if cmdOutput:
|
198 | 80a8fa62 | Bob Lantz | if printError:
|
199 | 82b72072 | Bob Lantz | error( '*** Error: moveIntf: ' + intf +
|
200 | c265deed | Bob Lantz | ' not successfully moved to ' + dstNode.name + ':\n', |
201 | cmdOutput ) |
||
202 | 220890a0 | Brandon Heller | return False |
203 | return True |
||
204 | |||
205 | c265deed | Bob Lantz | def moveIntf( intf, dstNode, srcNode=None, printError=True, |
206 | c771b2d7 | Bob Lantz | retries=3, delaySecs=0.001 ): |
207 | 80a8fa62 | Bob Lantz | """Move interface to node, retrying on failure.
|
208 | intf: string, interface
|
||
209 | c771b2d7 | Bob Lantz | dstNode: destination Node
|
210 | 80a8fa62 | Bob Lantz | printError: if true, print error"""
|
211 | c771b2d7 | Bob Lantz | retry( retries, delaySecs, moveIntfNoRetry, intf, dstNode, |
212 | c265deed | Bob Lantz | printError=printError ) |
213 | 80a8fa62 | Bob Lantz | |
214 | beb05a71 | Bob Lantz | # Support for dumping network
|
215 | |||
216 | def dumpNodeConnections( nodes ): |
||
217 | "Dump connections to/from nodes."
|
||
218 | |||
219 | def dumpConnections( node ): |
||
220 | "Helper function: dump connections to node"
|
||
221 | for intf in node.intfList(): |
||
222 | output( ' %s:' % intf )
|
||
223 | if intf.link:
|
||
224 | intfs = [ intf.link.intf1, intf.link.intf2 ] |
||
225 | intfs.remove( intf ) |
||
226 | output( intfs[ 0 ] )
|
||
227 | else:
|
||
228 | output( ' ' )
|
||
229 | |||
230 | for node in nodes: |
||
231 | output( node.name ) |
||
232 | dumpConnections( node ) |
||
233 | output( '\n' )
|
||
234 | e3621eb0 | Brandon Heller | |
235 | beb05a71 | Bob Lantz | def dumpNetConnections( net ): |
236 | "Dump connections in network"
|
||
237 | nodes = net.controllers + net.switches + net.hosts |
||
238 | dumpNodeConnections( nodes ) |
||
239 | 82b72072 | Bob Lantz | |
240 | 08643fe6 | cody burkard | def dumpPorts( switches ): |
241 | "dump interface to openflow port mappings for each switch"
|
||
242 | for switch in switches: |
||
243 | output( '%s ' % switch.name )
|
||
244 | for intf in switch.intfList(): |
||
245 | port = switch.ports[ intf ] |
||
246 | output( '%s:%d ' % ( intf, port ) )
|
||
247 | output( '\n' )
|
||
248 | |||
249 | 82b72072 | Bob Lantz | # IP and Mac address formatting and parsing
|
250 | 80a8fa62 | Bob Lantz | |
251 | 14ff3ad3 | Bob Lantz | def _colonHex( val, bytecount ): |
252 | 80a8fa62 | Bob Lantz | """Generate colon-hex string.
|
253 | val: input as unsigned int
|
||
254 | ab594b6a | Bob Lantz | bytecount: number of bytes to convert
|
255 | 80a8fa62 | Bob Lantz | returns: chStr colon-hex string"""
|
256 | 54037995 | Brandon Heller | pieces = [] |
257 | 14ff3ad3 | Bob Lantz | for i in range( bytecount - 1, -1, -1 ): |
258 | 80a8fa62 | Bob Lantz | piece = ( ( 0xff << ( i * 8 ) ) & val ) >> ( i * 8 ) |
259 | pieces.append( '%02x' % piece )
|
||
260 | chStr = ':'.join( pieces )
|
||
261 | return chStr
|
||
262 | |||
263 | def macColonHex( mac ): |
||
264 | """Generate MAC colon-hex string from unsigned int.
|
||
265 | mac: MAC address as unsigned int
|
||
266 | returns: macStr MAC colon-hex string"""
|
||
267 | 891a9e8b | cody burkard | return _colonHex( mac, 6 ) |
268 | 80a8fa62 | Bob Lantz | |
269 | def ipStr( ip ): |
||
270 | d44a5843 | Bob Lantz | """Generate IP address string from an unsigned int.
|
271 | ip: unsigned int of form w << 24 | x << 16 | y << 8 | z
|
||
272 | 8204a1b6 | Bob Lantz | returns: ip address string w.x.y.z"""
|
273 | 82f483f5 | Bob Lantz | w = ( ip >> 24 ) & 0xff |
274 | 14ff3ad3 | Bob Lantz | x = ( ip >> 16 ) & 0xff |
275 | y = ( ip >> 8 ) & 0xff |
||
276 | d44a5843 | Bob Lantz | z = ip & 0xff
|
277 | return "%i.%i.%i.%i" % ( w, x, y, z ) |
||
278 | |||
279 | def ipNum( w, x, y, z ): |
||
280 | 82f483f5 | Bob Lantz | """Generate unsigned int from components of IP address
|
281 | d44a5843 | Bob Lantz | returns: w << 24 | x << 16 | y << 8 | z"""
|
282 | 1052f8a0 | Brandon Heller | return ( w << 24 ) | ( x << 16 ) | ( y << 8 ) | z |
283 | d44a5843 | Bob Lantz | |
284 | 5a8bb489 | Bob Lantz | def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ): |
285 | """Return IP address string from ints
|
||
286 | i: int to be added to ipbase
|
||
287 | prefixLen: optional IP prefix length
|
||
288 | ipBaseNum: option base IP address as int
|
||
289 | returns IP address as string"""
|
||
290 | 8204a1b6 | Bob Lantz | imax = 0xffffffff >> prefixLen
|
291 | 68e2e45f | Brian O'Connor | assert i <= imax, 'Not enough IP addresses in the subnet' |
292 | 8204a1b6 | Bob Lantz | mask = 0xffffffff ^ imax
|
293 | ipnum = ( ipBaseNum & mask ) + i |
||
294 | 5a8bb489 | Bob Lantz | return ipStr( ipnum )
|
295 | d44a5843 | Bob Lantz | |
296 | def ipParse( ip ): |
||
297 | "Parse an IP address and return an unsigned int."
|
||
298 | args = [ int( arg ) for arg in ip.split( '.' ) ] |
||
299 | b3055067 | Cody Burkard | while ( len(args) < 4 ): |
300 | args.append( 0 )
|
||
301 | d44a5843 | Bob Lantz | return ipNum( *args )
|
302 | bb941950 | Brandon Heller | |
303 | 82f483f5 | Bob Lantz | def netParse( ipstr ): |
304 | """Parse an IP network specification, returning
|
||
305 | address and prefix len as unsigned ints"""
|
||
306 | prefixLen = 0
|
||
307 | if '/' in ipstr: |
||
308 | ip, pf = ipstr.split( '/' )
|
||
309 | prefixLen = int( pf )
|
||
310 | b3055067 | Cody Burkard | #if no prefix is specified, set the prefix to 24
|
311 | else:
|
||
312 | ip = ipstr |
||
313 | prefixLen = 24
|
||
314 | 82f483f5 | Bob Lantz | return ipParse( ip ), prefixLen
|
315 | |||
316 | bb941950 | Brandon Heller | def checkInt( s ): |
317 | "Check if input string is an int"
|
||
318 | try:
|
||
319 | int( s )
|
||
320 | return True |
||
321 | except ValueError: |
||
322 | return False |
||
323 | |||
324 | def checkFloat( s ): |
||
325 | "Check if input string is a float"
|
||
326 | try:
|
||
327 | float( s )
|
||
328 | return True |
||
329 | except ValueError: |
||
330 | return False |
||
331 | |||
332 | def makeNumeric( s ): |
||
333 | "Convert string to int or float if numeric."
|
||
334 | if checkInt( s ):
|
||
335 | return int( s ) |
||
336 | elif checkFloat( s ):
|
||
337 | return float( s ) |
||
338 | else:
|
||
339 | 740d7ce3 | Bob Lantz | return s
|
340 | bcacfc05 | Bob Lantz | |
341 | 50cebe67 | Bob Lantz | # Popen support
|
342 | |||
343 | def pmonitor(popens, timeoutms=500, readline=True, |
||
344 | readmax=1024 ):
|
||
345 | """Monitor dict of hosts to popen objects
|
||
346 | a line at a time
|
||
347 | timeoutms: timeout for poll()
|
||
348 | readline: return single line of output
|
||
349 | yields: host, line/output (if any)
|
||
350 | terminates: when all EOFs received"""
|
||
351 | poller = poll() |
||
352 | fdToHost = {} |
||
353 | for host, popen in popens.iteritems(): |
||
354 | fd = popen.stdout.fileno() |
||
355 | fdToHost[ fd ] = host |
||
356 | poller.register( fd, POLLIN ) |
||
357 | if not readline: |
||
358 | # Use non-blocking reads
|
||
359 | flags = fcntl( fd, F_GETFL ) |
||
360 | fcntl( fd, F_SETFL, flags | O_NONBLOCK ) |
||
361 | 31fe4f1b | Bob Lantz | while popens:
|
362 | 50cebe67 | Bob Lantz | fds = poller.poll( timeoutms ) |
363 | if fds:
|
||
364 | 31fe4f1b | Bob Lantz | for fd, event in fds: |
365 | 50cebe67 | Bob Lantz | host = fdToHost[ fd ] |
366 | popen = popens[ host ] |
||
367 | 31fe4f1b | Bob Lantz | if event & POLLIN:
|
368 | if readline:
|
||
369 | # Attempt to read a line of output
|
||
370 | # This blocks until we receive a newline!
|
||
371 | line = popen.stdout.readline() |
||
372 | else:
|
||
373 | line = popen.stdout.read( readmax ) |
||
374 | yield host, line
|
||
375 | 50cebe67 | Bob Lantz | # Check for EOF
|
376 | 31fe4f1b | Bob Lantz | elif event & POLLHUP:
|
377 | poller.unregister( fd ) |
||
378 | del popens[ host ]
|
||
379 | 50cebe67 | Bob Lantz | else:
|
380 | yield None, '' |
||
381 | bcacfc05 | Bob Lantz | |
382 | 82b72072 | Bob Lantz | # Other stuff we use
|
383 | b20c9470 | Brian O'Connor | def sysctlTestAndSet( name, limit ): |
384 | 867a6d67 | Brian O'Connor | "Helper function to set sysctl limits"
|
385 | #convert non-directory names into directory names
|
||
386 | if '/' not in name: |
||
387 | b635fd9e | Brian O'Connor | name = '/proc/sys/' + name.replace( '.', '/' ) |
388 | b20c9470 | Brian O'Connor | #read limit
|
389 | 4ea0c093 | Brian O'Connor | with open( name, 'r' ) as readFile: |
390 | oldLimit = readFile.readline() |
||
391 | if type( limit ) is int: |
||
392 | #compare integer limits before overriding
|
||
393 | if int( oldLimit ) < limit: |
||
394 | with open( name, 'w' ) as writeFile: |
||
395 | writeFile.write( "%d" % limit )
|
||
396 | else:
|
||
397 | #overwrite non-integer limits
|
||
398 | with open( name, 'w' ) as writeFile: |
||
399 | writeFile.write( limit ) |
||
400 | b20c9470 | Brian O'Connor | |
401 | def rlimitTestAndSet( name, limit ): |
||
402 | 867a6d67 | Brian O'Connor | "Helper function to set rlimits"
|
403 | b20c9470 | Brian O'Connor | soft, hard = getrlimit( name ) |
404 | if soft < limit:
|
||
405 | hardLimit = hard if limit < hard else limit |
||
406 | setrlimit( name, ( limit, hardLimit ) ) |
||
407 | bcacfc05 | Bob Lantz | |
408 | 82b72072 | Bob Lantz | def fixLimits(): |
409 | "Fix ridiculously small resource limits."
|
||
410 | 4ea0c093 | Brian O'Connor | debug( "*** Setting resource limits\n" )
|
411 | try:
|
||
412 | rlimitTestAndSet( RLIMIT_NPROC, 8192 )
|
||
413 | rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
|
||
414 | #Increase open file limit
|
||
415 | sysctlTestAndSet( 'fs.file-max', 10000 ) |
||
416 | #Increase network buffer space
|
||
417 | sysctlTestAndSet( 'net.core.wmem_max', 16777216 ) |
||
418 | sysctlTestAndSet( 'net.core.rmem_max', 16777216 ) |
||
419 | sysctlTestAndSet( 'net.ipv4.tcp_rmem', '10240 87380 16777216' ) |
||
420 | sysctlTestAndSet( 'net.ipv4.tcp_wmem', '10240 87380 16777216' ) |
||
421 | sysctlTestAndSet( 'net.core.netdev_max_backlog', 5000 ) |
||
422 | #Increase arp cache size
|
||
423 | sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh1', 4096 ) |
||
424 | sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh2', 8192 ) |
||
425 | sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh3', 16384 ) |
||
426 | #Increase routing table size
|
||
427 | sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 ) |
||
428 | #Increase number of PTYs for nodes
|
||
429 | sysctlTestAndSet( 'kernel.pty.max', 20000 ) |
||
430 | except:
|
||
431 | warn( "*** Error setting resource limits. "
|
||
432 | "Mininet's performance may be affected.\n" )
|
||
433 | a7648e78 | Bob Lantz | |
434 | def mountCgroups(): |
||
435 | "Make sure cgroups file system is mounted"
|
||
436 | 433ca2ec | Piyush Srivastava | mounts = quietRun( 'cat /proc/mounts' )
|
437 | a7648e78 | Bob Lantz | cgdir = '/sys/fs/cgroup'
|
438 | csdir = cgdir + '/cpuset'
|
||
439 | 433ca2ec | Piyush Srivastava | if ('cgroup %s' % cgdir not in mounts and |
440 | 'cgroups %s' % cgdir not in mounts): |
||
441 | a7648e78 | Bob Lantz | raise Exception( "cgroups not mounted on " + cgdir ) |
442 | 433ca2ec | Piyush Srivastava | if 'cpuset %s' % csdir not in mounts: |
443 | 149a1f56 | Bob Lantz | errRun( 'mkdir -p ' + csdir )
|
444 | errRun( 'mount -t cgroup -ocpuset cpuset ' + csdir )
|
||
445 | 134a75ef | Bob Lantz | |
446 | def natural( text ): |
||
447 | "To sort sanely/alphabetically: sorted( l, key=natural )"
|
||
448 | def num( s ): |
||
449 | 14ff3ad3 | Bob Lantz | "Convert text segment to int if necessary"
|
450 | 5a8bb489 | Bob Lantz | return int( s ) if s.isdigit() else s |
451 | 134a75ef | Bob Lantz | return [ num( s ) for s in re.split( r'(\d+)', text ) ] |
452 | 551a3666 | Bob Lantz | |
453 | 5a8bb489 | Bob Lantz | def naturalSeq( t ): |
454 | "Natural sort key function for sequences"
|
||
455 | return [ natural( x ) for x in t ] |
||
456 | |||
457 | 551a3666 | Bob Lantz | def numCores(): |
458 | "Returns number of CPU cores based on /proc/cpuinfo"
|
||
459 | if hasattr( numCores, 'ncores' ): |
||
460 | return numCores.ncores
|
||
461 | try:
|
||
462 | numCores.ncores = int( quietRun('grep -c processor /proc/cpuinfo') ) |
||
463 | except ValueError: |
||
464 | return 0 |
||
465 | return numCores.ncores
|
||
466 | d8c88bed | Bob Lantz | |
467 | 5a8bb489 | Bob Lantz | def irange(start, end): |
468 | """Inclusive range from start to end (vs. Python insanity.)
|
||
469 | irange(1,5) -> 1, 2, 3, 4, 5"""
|
||
470 | return range( start, end + 1 ) |
||
471 | |||
472 | d8c88bed | Bob Lantz | def custom( cls, **params ): |
473 | "Returns customized constructor for class cls."
|
||
474 | 4b1dc93b | Bob Lantz | # Note: we may wish to see if we can use functools.partial() here
|
475 | # and in customConstructor
|
||
476 | d8c88bed | Bob Lantz | def customized( *args, **kwargs): |
477 | 14ff3ad3 | Bob Lantz | "Customized constructor"
|
478 | 4b1dc93b | Bob Lantz | kwargs = kwargs.copy() |
479 | d8c88bed | Bob Lantz | kwargs.update( params ) |
480 | return cls( *args, **kwargs )
|
||
481 | 22b8e5e4 | Bob Lantz | customized.__name__ = 'custom(%s,%s)' % ( cls, params )
|
482 | d8c88bed | Bob Lantz | return customized
|
483 | 928c0761 | Brandon Heller | |
484 | def splitArgs( argstr ): |
||
485 | """Split argument string into usable python arguments
|
||
486 | argstr: argument string with format fn,arg2,kw1=arg3...
|
||
487 | returns: fn, args, kwargs"""
|
||
488 | split = argstr.split( ',' )
|
||
489 | fn = split[ 0 ]
|
||
490 | params = split[ 1: ]
|
||
491 | # Convert int and float args; removes the need for function
|
||
492 | # to be flexible with input arg formats.
|
||
493 | args = [ makeNumeric( s ) for s in params if '=' not in s ] |
||
494 | kwargs = {} |
||
495 | for s in [ p for p in params if '=' in p ]: |
||
496 | 5fae96eb | Bob Lantz | key, val = s.split( '=', 1 ) |
497 | 928c0761 | Brandon Heller | kwargs[ key ] = makeNumeric( val ) |
498 | return fn, args, kwargs
|
||
499 | |||
500 | def customConstructor( constructors, argStr ): |
||
501 | """Return custom constructor based on argStr
|
||
502 | The args and key/val pairs in argsStr will be automatically applied
|
||
503 | when the generated constructor is later used.
|
||
504 | """
|
||
505 | cname, newargs, kwargs = splitArgs( argStr ) |
||
506 | constructor = constructors.get( cname, None )
|
||
507 | |||
508 | if not constructor: |
||
509 | raise Exception( "error: %s is unknown - please specify one of %s" % |
||
510 | edf60032 | Brandon Heller | ( cname, constructors.keys() ) ) |
511 | 928c0761 | Brandon Heller | |
512 | def customized( name, *args, **params ): |
||
513 | "Customized constructor, useful for Node, Link, and other classes"
|
||
514 | 4b1dc93b | Bob Lantz | params = params.copy() |
515 | 928c0761 | Brandon Heller | params.update( kwargs ) |
516 | if not newargs: |
||
517 | return constructor( name, *args, **params )
|
||
518 | if args:
|
||
519 | warn( 'warning: %s replacing %s with %s\n' % (
|
||
520 | constructor, args, newargs ) ) |
||
521 | return constructor( name, *newargs, **params )
|
||
522 | |||
523 | 22b8e5e4 | Bob Lantz | customized.__name__ = 'customConstructor(%s)' % argStr
|
524 | 928c0761 | Brandon Heller | return customized
|
525 | |||
526 | def buildTopo( topos, topoStr ): |
||
527 | """Create topology from string with format (object, arg1, arg2,...).
|
||
528 | input topos is a dict of topo names to constructors, possibly w/args.
|
||
529 | """
|
||
530 | topo, args, kwargs = splitArgs( topoStr ) |
||
531 | if topo not in topos: |
||
532 | raise Exception( 'Invalid topo name %s' % topo ) |
||
533 | return topos[ topo ]( *args, **kwargs )
|
||
534 | bcfb3009 | Brandon Heller | |
535 | def ensureRoot(): |
||
536 | """Ensure that we are running as root.
|
||
537 |
|
||
538 | Probably we should only sudo when needed as per Big Switch's patch.
|
||
539 | """
|
||
540 | if os.getuid() != 0: |
||
541 | print "*** Mininet must run as root." |
||
542 | exit( 1 ) |
||
543 | return
|
||
544 | cf5bbd59 | cody burkard | |
545 | a565bdd5 | cody burkard | def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ): |
546 | 7c5d2771 | cody burkard | """Wait until server is listening on port.
|
547 | returns True if server is listening"""
|
||
548 | a565bdd5 | cody burkard | run = ( client.cmd if client else |
549 | partial( quietRun, shell=True ) )
|
||
550 | if not run( 'which telnet' ): |
||
551 | cf5bbd59 | cody burkard | raise Exception('Could not find telnet' ) |
552 | f8e98d6a | Bob Lantz | serverIP = server if type( server ) is str else server.IP() |
553 | cf5bbd59 | cody burkard | cmd = ( 'sh -c "echo A | telnet -e A %s %s"' %
|
554 | f8e98d6a | Bob Lantz | ( serverIP, port ) ) |
555 | cf5bbd59 | cody burkard | time = 0
|
556 | a565bdd5 | cody burkard | while 'Connected' not in run( cmd ): |
557 | cf5bbd59 | cody burkard | if timeout:
|
558 | 7c5d2771 | cody burkard | print time
|
559 | cf5bbd59 | cody burkard | if time >= timeout:
|
560 | error( 'could not connect to %s on port %d\n'
|
||
561 | a565bdd5 | cody burkard | % ( server, port ) ) |
562 | 7c5d2771 | cody burkard | return False |
563 | cf5bbd59 | cody burkard | output('waiting for', server,
|
564 | 'to listen on port', port, '\n') |
||
565 | sleep( .5 )
|
||
566 | time += .5
|
||
567 | 7c5d2771 | cody burkard | return True |