Statistics
| Branch: | Tag: | Revision:

mininet / mininet / util.py @ master

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

587
    Probably we should only sudo when needed as per Big Switch's patch.
588
    """
589
    if os.getuid() != 0:
590
        print "*** Mininet must run as root."
591
        exit( 1 )
592
    return
593 cf5bbd59 cody burkard
594 a565bdd5 cody burkard
def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ):
595 7c5d2771 cody burkard
    """Wait until server is listening on port.
596
       returns True if server is listening"""
597 b1ec912d Bob Lantz
    runCmd = ( client.cmd if client else
598 7a3159c9 Bob Lantz
               partial( quietRun, shell=True ) )
599 b1ec912d Bob Lantz
    if not runCmd( 'which telnet' ):
600 cf5bbd59 cody burkard
        raise Exception('Could not find telnet' )
601 18aab5b7 Bob Lantz
    # pylint: disable=maybe-no-member
602 9a8bdfd7 Bob Lantz
    serverIP = server if isinstance( server, basestring ) else server.IP()
603 b2fe0778 Bob Lantz
    cmd = ( 'echo A | telnet -e A %s %s' % ( serverIP, port ) )
604 cf5bbd59 cody burkard
    time = 0
605 b2fe0778 Bob Lantz
    result = runCmd( cmd )
606
    while 'Connected' not in result:
607
        if 'No route' in result:
608
            rtable = runCmd( 'route' )
609
            error( 'no route to %s:\n%s' % ( server, rtable ) )
610
            return False
611
        if timeout and time >= timeout:
612
            error( 'could not connect to %s on port %d\n' % ( server, port ) )
613
            return False
614
        debug( 'waiting for', server, 'to listen on port', port, '\n' )
615
        info( '.' )
616 cf5bbd59 cody burkard
        sleep( .5 )
617
        time += .5
618 b2fe0778 Bob Lantz
        result = runCmd( cmd )
619 7c5d2771 cody burkard
    return True