First commit
diff --git a/mininet/util.py b/mininet/util.py
new file mode 100644
index 0000000..6a3dc14
--- /dev/null
+++ b/mininet/util.py
@@ -0,0 +1,473 @@
+"Utility functions for Mininet."
+
+from mininet.log import output, info, error, warn
+
+from time import sleep
+from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
+from select import poll, POLLIN
+from subprocess import call, check_call, Popen, PIPE, STDOUT
+import re
+from fcntl import fcntl, F_GETFL, F_SETFL
+from os import O_NONBLOCK
+import os
+
+# Command execution support
+
+def run( cmd ):
+    """Simple interface to subprocess.call()
+       cmd: list of command params"""
+    return call( cmd.split( ' ' ) )
+
+def checkRun( cmd ):
+    """Simple interface to subprocess.check_call()
+       cmd: list of command params"""
+    return check_call( cmd.split( ' ' ) )
+
+# pylint doesn't understand explicit type checking
+# pylint: disable-msg=E1103
+
+def oldQuietRun( *cmd ):
+    """Run a command, routing stderr to stdout, and return the output.
+       cmd: list of command params"""
+    if len( cmd ) == 1:
+        cmd = cmd[ 0 ]
+        if isinstance( cmd, str ):
+            cmd = cmd.split( ' ' )
+    popen = Popen( cmd, stdout=PIPE, stderr=STDOUT )
+    # We can't use Popen.communicate() because it uses
+    # select(), which can't handle
+    # high file descriptor numbers! poll() can, however.
+    out = ''
+    readable = poll()
+    readable.register( popen.stdout )
+    while True:
+        while readable.poll():
+            data = popen.stdout.read( 1024 )
+            if len( data ) == 0:
+                break
+            out += data
+        popen.poll()
+        if popen.returncode is not None:
+            break
+    return out
+
+
+# This is a bit complicated, but it enables us to
+# monitor command output as it is happening
+
+def errRun( *cmd, **kwargs ):
+    """Run a command and return stdout, stderr and return code
+       cmd: string or list of command and args
+       stderr: STDOUT to merge stderr with stdout
+       shell: run command using shell
+       echo: monitor output to console"""
+    # Allow passing in a list or a string
+    if len( cmd ) == 1:
+        cmd = cmd[ 0 ]
+        if isinstance( cmd, str ):
+            cmd = cmd.split( ' ' )
+    cmd = [ str( arg ) for arg in cmd ]
+    # By default we separate stderr, don't run in a shell, and don't echo
+    stderr = kwargs.get( 'stderr', PIPE )
+    shell = kwargs.get( 'shell', False )
+    echo = kwargs.get( 'echo', False )
+    if echo:
+        # cmd goes to stderr, output goes to stdout
+        info( cmd, '\n' )
+    popen = Popen( cmd, stdout=PIPE, stderr=stderr, shell=shell )
+    # We use poll() because select() doesn't work with large fd numbers,
+    # and thus communicate() doesn't work either
+    out, err = '', ''
+    poller = poll()
+    poller.register( popen.stdout, POLLIN )
+    fdtofile = { popen.stdout.fileno(): popen.stdout }
+    outDone, errDone = False, True
+    if popen.stderr:
+        fdtofile[ popen.stderr.fileno() ] = popen.stderr
+        poller.register( popen.stderr, POLLIN )
+        errDone = False
+    while not outDone or not errDone:
+        readable = poller.poll()
+        for fd, _event in readable:
+            f = fdtofile[ fd ]
+            data = f.read( 1024 )
+            if echo:
+                output( data )
+            if f == popen.stdout:
+                out += data
+                if data == '':
+                    outDone = True
+            elif f == popen.stderr:
+                err += data
+                if data == '':
+                    errDone = True
+    returncode = popen.wait()
+    return out, err, returncode
+
+def errFail( *cmd, **kwargs ):
+    "Run a command using errRun and raise exception on nonzero exit"
+    out, err, ret = errRun( *cmd, **kwargs )
+    if ret:
+        raise Exception( "errFail: %s failed with return code %s: %s"
+                         % ( cmd, ret, err ) )
+    return out, err, ret
+
+def quietRun( cmd, **kwargs ):
+    "Run a command and return merged stdout and stderr"
+    return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ]
+
+# pylint: enable-msg=E1103
+# pylint: disable-msg=E1101
+
+def isShellBuiltin( cmd ):
+    "Return True if cmd is a bash builtin."
+    if isShellBuiltin.builtIns is None:
+        isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
+    space = cmd.find( ' ' )
+    if space > 0:
+        cmd = cmd[ :space]
+    return cmd in isShellBuiltin.builtIns
+
+isShellBuiltin.builtIns = None
+
+# pylint: enable-msg=E1101
+
+# Interface management
+#
+# Interfaces are managed as strings which are simply the
+# interface names, of the form 'nodeN-ethM'.
+#
+# To connect nodes, we create a pair of veth interfaces, and then place them
+# in the pair of nodes that we want to communicate. We then update the node's
+# list of interfaces and connectivity map.
+#
+# For the kernel datapath, switch interfaces
+# live in the root namespace and thus do not have to be
+# explicitly moved.
+
+def makeIntfPair( intf1, intf2 ):
+    """Make a veth pair connecting intf1 and intf2.
+       intf1: string, interface
+       intf2: string, interface
+       returns: success boolean"""
+    # Delete any old interfaces with the same names
+    quietRun( 'ip link del ' + intf1 )
+    quietRun( 'ip link del ' + intf2 )
+    # Create new pair
+    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
+    return quietRun( cmd )
+
+def retry( retries, delaySecs, fn, *args, **keywords ):
+    """Try something several times before giving up.
+       n: number of times to retry
+       delaySecs: wait this long between tries
+       fn: function to call
+       args: args to apply to function call"""
+    tries = 0
+    while not fn( *args, **keywords ) and tries < retries:
+        sleep( delaySecs )
+        tries += 1
+    if tries >= retries:
+        error( "*** gave up after %i retries\n" % tries )
+        exit( 1 )
+
+def moveIntfNoRetry( intf, node, printError=False ):
+    """Move interface to node, without retrying.
+       intf: string, interface
+       node: Node object
+       printError: if true, print error"""
+    cmd = 'ip link set ' + intf + ' netns ' + repr( node.pid )
+    quietRun( cmd )
+    links = node.cmd( 'ip link show' )
+    if not ( ' %s:' % intf ) in links:
+        if printError:
+            error( '*** Error: moveIntf: ' + intf +
+                   ' not successfully moved to ' + node.name + '\n' )
+        return False
+    return True
+
+def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ):
+    """Move interface to node, retrying on failure.
+       intf: string, interface
+       node: Node object
+       printError: if true, print error"""
+    retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError )
+
+# Support for dumping network
+
+def dumpNodeConnections( nodes ):
+    "Dump connections to/from nodes."
+
+    def dumpConnections( node ):
+        "Helper function: dump connections to node"
+        for intf in node.intfList():
+            output( ' %s:' % intf )
+            if intf.link:
+                intfs = [ intf.link.intf1, intf.link.intf2 ]
+                intfs.remove( intf )
+                output( intfs[ 0 ] )
+            else:
+                output( ' ' )
+
+    for node in nodes:
+        output( node.name )
+        dumpConnections( node )
+        output( '\n' )
+
+def dumpNetConnections( net ):
+    "Dump connections in network"
+    nodes = net.controllers + net.switches + net.hosts
+    dumpNodeConnections( nodes )
+
+# IP and Mac address formatting and parsing
+
+def _colonHex( val, bytecount ):
+    """Generate colon-hex string.
+       val: input as unsigned int
+       bytecount: number of bytes to convert
+       returns: chStr colon-hex string"""
+    pieces = []
+    for i in range( bytecount - 1, -1, -1 ):
+        piece = ( ( 0xff << ( i * 8 ) ) & val ) >> ( i * 8 )
+        pieces.append( '%02x' % piece )
+    chStr = ':'.join( pieces )
+    return chStr
+
+def macColonHex( mac ):
+    """Generate MAC colon-hex string from unsigned int.
+       mac: MAC address as unsigned int
+       returns: macStr MAC colon-hex string"""
+    return _colonHex( mac, 6 )
+
+def ipStr( ip ):
+    """Generate IP address string from an unsigned int.
+       ip: unsigned int of form w << 24 | x << 16 | y << 8 | z
+       returns: ip address string w.x.y.z, or 10.x.y.z if w==0"""
+    w = ( ip >> 24 ) & 0xff
+    w = 10 if w == 0 else w
+    x = ( ip >> 16 ) & 0xff
+    y = ( ip >> 8 ) & 0xff
+    z = ip & 0xff
+    return "%i.%i.%i.%i" % ( w, x, y, z )
+
+def ipNum( w, x, y, z ):
+    """Generate unsigned int from components of IP address
+       returns: w << 24 | x << 16 | y << 8 | z"""
+    return ( w << 24 ) | ( x << 16 ) | ( y << 8 ) | z
+
+def nextCCNnet(curCCNnet):
+    netNum = ipParse(curCCNnet)
+    return ipStr(netNum+4)
+
+def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ):
+    """Return IP address string from ints
+       i: int to be added to ipbase
+       prefixLen: optional IP prefix length
+       ipBaseNum: option base IP address as int
+       returns IP address as string"""
+    # Ugly but functional
+    assert i < ( 1 << ( 32 - prefixLen ) )
+    mask = 0xffffffff ^ ( ( 1 << prefixLen ) - 1 )
+    ipnum = i + ( ipBaseNum & mask )
+    return ipStr( ipnum )
+
+def ipParse( ip ):
+    "Parse an IP address and return an unsigned int."
+    args = [ int( arg ) for arg in ip.split( '.' ) ]
+    return ipNum( *args )
+
+def netParse( ipstr ):
+    """Parse an IP network specification, returning
+       address and prefix len as unsigned ints"""
+    prefixLen = 0
+    if '/' in ipstr:
+        ip, pf = ipstr.split( '/' )
+        prefixLen = int( pf )
+    return ipParse( ip ), prefixLen
+
+def checkInt( s ):
+    "Check if input string is an int"
+    try:
+        int( s )
+        return True
+    except ValueError:
+        return False
+
+def checkFloat( s ):
+    "Check if input string is a float"
+    try:
+        float( s )
+        return True
+    except ValueError:
+        return False
+
+def makeNumeric( s ):
+    "Convert string to int or float if numeric."
+    if checkInt( s ):
+        return int( s )
+    elif checkFloat( s ):
+        return float( s )
+    else:
+        return s
+
+# Popen support
+
+def pmonitor(popens, timeoutms=500, readline=True,
+             readmax=1024 ):
+    """Monitor dict of hosts to popen objects
+       a line at a time
+       timeoutms: timeout for poll()
+       readline: return single line of output
+       yields: host, line/output (if any)
+       terminates: when all EOFs received"""
+    poller = poll()
+    fdToHost = {}
+    for host, popen in popens.iteritems():
+        fd = popen.stdout.fileno()
+        fdToHost[ fd ] = host
+        poller.register( fd, POLLIN )
+        if not readline:
+            # Use non-blocking reads
+            flags = fcntl( fd, F_GETFL )
+            fcntl( fd, F_SETFL, flags | O_NONBLOCK )
+    while True:
+        fds = poller.poll( timeoutms )
+        if fds:
+            for fd, _event in fds:
+                host = fdToHost[ fd ]
+                popen = popens[ host ]
+                if readline:
+                    # Attempt to read a line of output
+                    # This blocks until we receive a newline!
+                    line = popen.stdout.readline()
+                else:
+                    line = popen.stdout.read( readmax )
+                yield host, line
+                # Check for EOF
+                if not line:
+                    popen.poll()
+                    if popen.returncode is not None:
+                        poller.unregister( fd )
+                        del popens[ host ]
+                        if not popens:
+                            return
+        else:
+            yield None, ''
+
+# Other stuff we use
+
+def fixLimits():
+    "Fix ridiculously small resource limits."
+    setrlimit( RLIMIT_NPROC, ( 8192, 8192 ) )
+    setrlimit( RLIMIT_NOFILE, ( 16384, 16384 ) )
+
+def mountCgroups():
+    "Make sure cgroups file system is mounted"
+    mounts = quietRun( 'mount' )
+    cgdir = '/sys/fs/cgroup'
+    csdir = cgdir + '/cpuset'
+    if ('cgroup on %s' % cgdir not in mounts and
+            'cgroups on %s' % cgdir not in mounts):
+        raise Exception( "cgroups not mounted on " + cgdir )
+    if 'cpuset on %s' % csdir not in mounts:
+        errRun( 'mkdir -p ' + csdir )
+        errRun( 'mount -t cgroup -ocpuset cpuset ' + csdir )
+
+def natural( text ):
+    "To sort sanely/alphabetically: sorted( l, key=natural )"
+    def num( s ):
+        "Convert text segment to int if necessary"
+        return int( s ) if s.isdigit() else s
+    return [  num( s ) for s in re.split( r'(\d+)', text ) ]
+
+def naturalSeq( t ):
+    "Natural sort key function for sequences"
+    return [ natural( x ) for x in t ]
+
+def numCores():
+    "Returns number of CPU cores based on /proc/cpuinfo"
+    if hasattr( numCores, 'ncores' ):
+        return numCores.ncores
+    try:
+        numCores.ncores = int( quietRun('grep -c processor /proc/cpuinfo') )
+    except ValueError:
+        return 0
+    return numCores.ncores
+
+def irange(start, end):
+    """Inclusive range from start to end (vs. Python insanity.)
+       irange(1,5) -> 1, 2, 3, 4, 5"""
+    return range( start, end + 1 )
+
+def custom( cls, **params ):
+    "Returns customized constructor for class cls."
+    # Note: we may wish to see if we can use functools.partial() here
+    # and in customConstructor
+    def customized( *args, **kwargs):
+        "Customized constructor"
+        kwargs = kwargs.copy()
+        kwargs.update( params )
+        return cls( *args, **kwargs )
+    customized.__name__ = 'custom(%s,%s)' % ( cls, params )
+    return customized
+
+def splitArgs( argstr ):
+    """Split argument string into usable python arguments
+       argstr: argument string with format fn,arg2,kw1=arg3...
+       returns: fn, args, kwargs"""
+    split = argstr.split( ',' )
+    fn = split[ 0 ]
+    params = split[ 1: ]
+    # Convert int and float args; removes the need for function
+    # to be flexible with input arg formats.
+    args = [ makeNumeric( s ) for s in params if '=' not in s ]
+    kwargs = {}
+    for s in [ p for p in params if '=' in p ]:
+        key, val = s.split( '=' )
+        kwargs[ key ] = makeNumeric( val )
+    return fn, args, kwargs
+
+def customConstructor( constructors, argStr ):
+    """Return custom constructor based on argStr
+    The args and key/val pairs in argsStr will be automatically applied
+    when the generated constructor is later used.
+    """
+    cname, newargs, kwargs = splitArgs( argStr )
+    constructor = constructors.get( cname, None )
+
+    if not constructor:
+        raise Exception( "error: %s is unknown - please specify one of %s" %
+                         ( cname, constructors.keys() ) )
+
+    def customized( name, *args, **params ):
+        "Customized constructor, useful for Node, Link, and other classes"
+        params = params.copy()
+        params.update( kwargs )
+        if not newargs:
+            return constructor( name, *args, **params )
+        if args:
+            warn( 'warning: %s replacing %s with %s\n' % (
+                  constructor, args, newargs ) )
+        return constructor( name, *newargs, **params )
+
+    customized.__name__ = 'customConstructor(%s)' % argStr
+    return customized
+
+def buildTopo( topos, topoStr ):
+    """Create topology from string with format (object, arg1, arg2,...).
+    input topos is a dict of topo names to constructors, possibly w/args.
+    """
+    topo, args, kwargs = splitArgs( topoStr )
+    if topo not in topos:
+        raise Exception( 'Invalid topo name %s' % topo )
+    return topos[ topo ]( *args, **kwargs )
+
+def ensureRoot():
+    """Ensure that we are running as root.
+
+    Probably we should only sudo when needed as per Big Switch's patch.
+    """
+    if os.getuid() != 0:
+        print "*** Mininet must run as root."
+        exit( 1 )
+    return