diff --git a/bin/mn b/bin/mn
index 71c76ecf51293615daeaa2ab562cd7213dc863eb..edd4d98423263ae1e8ca4955504ba83a180bac11 100755
--- a/bin/mn
+++ b/bin/mn
@@ -25,11 +25,13 @@ from mininet.cli import CLI
 from mininet.log import lg, LEVELS, info, debug, error
 from mininet.net import Mininet, MininetWithControlNet, VERSION
 from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
-                           NOX, RemoteController, UserSwitch, OVSKernelSwitch,
+                           NOX, RemoteController, DefaultController,
+                           UserSwitch, OVSSwitch,
                            OVSLegacyKernelSwitch, IVSSwitch )
+from mininet.nodelib import LinuxBridge
 from mininet.link import Link, TCLink
 from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
-from mininet.topolib import TreeTopo
+from mininet.topolib import TreeTopo, TorusTopo
 from mininet.util import custom, customConstructor
 from mininet.util import buildTopo
 
@@ -40,24 +42,29 @@ TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
           'linear': LinearTopo,
           'reversed': SingleSwitchReversedTopo,
           'single': SingleSwitchTopo,
-          'tree': TreeTopo }
+          'tree': TreeTopo,
+          'torus': TorusTopo }
 
 SWITCHDEF = 'ovsk'
 SWITCHES = { 'user': UserSwitch,
-             'ovsk': OVSKernelSwitch,
+             'ovs':  OVSSwitch,
+             # Keep ovsk for compatibility with 2.0
+             'ovsk': OVSSwitch,
              'ovsl': OVSLegacyKernelSwitch,
-             'ivs': IVSSwitch }
+             'ivs': IVSSwitch,
+             'lxbr': LinuxBridge }
 
 HOSTDEF = 'proc'
 HOSTS = { 'proc': Host,
           'rt': custom( CPULimitedHost, sched='rt' ),
           'cfs': custom( CPULimitedHost, sched='cfs' ) }
 
-CONTROLLERDEF = 'ovsc'
+CONTROLLERDEF = 'default'
 CONTROLLERS = { 'ref': Controller,
                 'ovsc': OVSController,
                 'nox': NOX,
                 'remote': RemoteController,
+                'default': DefaultController,
                 'none': lambda name: None }
 
 LINKDEF = 'default'
@@ -261,12 +268,14 @@ class MininetRunner( object ):
         if test == 'none':
             pass
         elif test == 'all':
+            mn.waitConnected()
             mn.start()
             mn.ping()
             mn.iperf()
         elif test == 'cli':
             CLI( mn )
         elif test != 'build':
+            mn.waitConnected()
             getattr( mn, test )()
 
         if self.options.post:
diff --git a/examples/bind.py b/examples/bind.py
index 2c317cf19543e8a151325762aca0e2e061f16995..287c97abfff8a03e726891acf2e420ddb0ea417e 100755
--- a/examples/bind.py
+++ b/examples/bind.py
@@ -1,197 +1,72 @@
 #!/usr/bin/python
 
 """
-bind.py: Bind mount prototype
+bind.py: Bind mount example
 
-This creates hosts with private directories as desired.
+This creates hosts with private directories that the user specifies.
+These hosts may have persistent directories that will be available
+across multiple mininet session, or temporary directories that will
+only last for one mininet session. To specify a persistent
+directory, add a tuple to a list of private directories:
+
+    [ ( 'directory to be mounted on', 'directory to be mounted' ) ]
+
+String expansion may be used to create a directory template for
+each host. To do this, add a %(name)s in place of the host name
+when creating your list of directories:
+
+    [ ( '/var/run', '/tmp/%(name)s/var/run' ) ]
+
+If no persistent directory is specified, the directories will default
+to temporary private directories. To do this, simply create a list of
+directories to be made private. A tmpfs will then be mounted on them.
+
+You may use both temporary and persistent directories at the same
+time. In the following privateDirs string, each host will have a 
+persistent directory in the root filesystem at
+"/tmp/(hostname)/var/run" mounted on "/var/run". Each host will also
+have a temporary private directory mounted on "/var/log".
+
+    [ ( '/var/run', '/tmp/%(name)s/var/run' ), '/var/log' ]
+
+This example has both persistent directories mounted on '/var/log'
+and '/var/run'. It also has a temporary private directory mounted
+on '/var/mn'
 """
 
 from mininet.net import Mininet
-from mininet.node import Host
+from mininet.node import Host, HostWithPrivateDirs
 from mininet.cli import CLI
-from mininet.util import errFail, quietRun, errRun
 from mininet.topo import SingleSwitchTopo
 from mininet.log import setLogLevel, info, debug
 
-from os.path import realpath
 from functools import partial
 
 
-# Utility functions for unmounting a tree
-
-MNRUNDIR = realpath( '/var/run/mn' )
-
-def mountPoints():
-    "Return list of mounted file systems"
-    mtab, _err, _ret = errFail( 'cat /proc/mounts' )
-    lines = mtab.split( '\n' )
-    mounts = []
-    for line in lines:
-        if not line:
-            continue
-        fields = line.split( ' ')
-        mount = fields[ 1 ]
-        mounts.append( mount )
-    return mounts
-
-def unmountAll( rootdir=MNRUNDIR ):
-    "Unmount all mounts under a directory tree"
-    rootdir = realpath( rootdir )
-    # Find all mounts below rootdir
-    # This is subtle because /foo is not
-    # a parent of /foot
-    dirslash = rootdir + '/'
-    mounts = [ m for m in mountPoints()
-              if m == dir or m.find( dirslash ) == 0 ]
-    # Unmount them from bottom to top
-    mounts.sort( reverse=True )
-    for mount in mounts:
-        debug( 'Unmounting', mount, '\n' )
-        _out, err, code = errRun( 'umount', mount )
-        if code != 0:
-            info( '*** Warning: failed to umount', mount, '\n' )
-            info( err )
-
-
-class HostWithPrivateDirs( Host ):
-    "Host with private directories"
-
-    mnRunDir = MNRUNDIR
-
-    def __init__(self, name, *args, **kwargs ):
-        """privateDirs: list of private directories
-           remounts: dirs to remount
-           unmount: unmount dirs in cleanup? (True)
-           Note: if unmount is False, you must call unmountAll()
-           manually."""
-        self.privateDirs = kwargs.pop( 'privateDirs', [] )
-        self.remounts = kwargs.pop( 'remounts', [] )
-        self.unmount = kwargs.pop( 'unmount', True )
-        Host.__init__( self, name, *args, **kwargs )
-        self.rundir = '%s/%s' % ( self.mnRunDir, name )
-        self.root, self.private = None, None  # set in createBindMounts
-        if self.privateDirs:
-            self.privateDirs = [ realpath( d ) for d in self.privateDirs ]
-            self.createBindMounts()
-        # These should run in the namespace before we chroot,
-        # in order to put the right entries in /etc/mtab
-        # Eventually this will allow a local pid space
-        # Now we chroot and cd to wherever we were before.
-        pwd = self.cmd( 'pwd' ).strip()
-        self.sendCmd( 'exec chroot', self.root, 'bash -ms mininet:'
-                       + self.name )
-        self.waiting = False
-        self.cmd( 'cd', pwd )
-        # In order for many utilities to work,
-        # we need to remount /proc and /sys
-        self.cmd( 'mount /proc' )
-        self.cmd( 'mount /sys' )
-
-    def mountPrivateDirs( self ):
-        "Create and bind mount private dirs"
-        for dir_ in self.privateDirs:
-            privateDir = self.private + dir_
-            errFail( 'mkdir -p ' + privateDir )
-            mountPoint = self.root + dir_
-            errFail( 'mount -B %s %s' %
-                           ( privateDir, mountPoint) )
-
-    def mountDirs( self, dirs ):
-        "Mount a list of directories"
-        for dir_ in dirs:
-            mountpoint = self.root + dir_
-            errFail( 'mount -B %s %s' %
-                     ( dir_, mountpoint ) )
-
-    @classmethod
-    def findRemounts( cls, fstypes=None ):
-        """Identify mount points in /proc/mounts to remount
-           fstypes: file system types to match"""
-        if fstypes is None:
-            fstypes = [ 'nfs' ]
-        dirs = quietRun( 'cat /proc/mounts' ).strip().split( '\n' )
-        remounts = []
-        for dir_ in dirs:
-            line = dir_.split()
-            mountpoint, fstype = line[ 1 ], line[ 2 ]
-            # Don't re-remount directories!!!
-            if mountpoint.find( cls.mnRunDir ) == 0:
-                continue
-            if fstype in fstypes:
-                remounts.append( mountpoint )
-        return remounts
-
-    def createBindMounts( self ):
-        """Create a chroot directory structure,
-           with self.privateDirs as private dirs"""
-        errFail( 'mkdir -p '+ self.rundir )
-        unmountAll( self.rundir )
-        # Create /root and /private directories
-        self.root = self.rundir + '/root'
-        self.private = self.rundir + '/private'
-        errFail( 'mkdir -p ' + self.root )
-        errFail( 'mkdir -p ' + self.private )
-        # Recursively mount / in private doort
-        # note we'll remount /sys and /proc later
-        errFail( 'mount -B / ' + self.root )
-        self.mountDirs( self.remounts )
-        self.mountPrivateDirs()
-
-    def unmountBindMounts( self ):
-        "Unmount all of our bind mounts"
-        unmountAll( self.rundir )
-
-    def popen( self, *args, **kwargs ):
-        "Popen with chroot support"
-        chroot = kwargs.pop( 'chroot', True )
-        mncmd = kwargs.get( 'mncmd',
-                           [ 'mnexec', '-a', str( self.pid ) ] )
-        if chroot:
-            mncmd = [ 'chroot', self.root ] + mncmd
-            kwargs[ 'mncmd' ] = mncmd
-        return Host.popen( self, *args, **kwargs )
-
-    def cleanup( self ):
-        """Clean up, then unmount bind mounts
-           unmount: actually unmount bind mounts?"""
-        # Wait for process to actually terminate
-        self.shell.wait()
-        Host.cleanup( self )
-        if self.unmount:
-            self.unmountBindMounts()
-            errFail( 'rmdir ' + self.root )
-
-
-# Convenience aliases
-
-findRemounts = HostWithPrivateDirs.findRemounts
-
-
 # Sample usage
 
 def testHostWithPrivateDirs():
     "Test bind mounts"
     topo = SingleSwitchTopo( 10 )
-    remounts = findRemounts( fstypes=[ 'nfs' ] )
-    privateDirs = [ '/var/log', '/var/run' ]
-    host = partial( HostWithPrivateDirs, remounts=remounts,
-                    privateDirs=privateDirs, unmount=False )
+    privateDirs = [ ( '/var/log', '/tmp/%(name)s/var/log' ), 
+                    ( '/var/run', '/tmp/%(name)s/var/run' ), 
+                      '/var/mn' ]
+    host = partial( HostWithPrivateDirs,
+                    privateDirs=privateDirs )
     net = Mininet( topo=topo, host=host )
     net.start()
-    info( 'Private Directories:', privateDirs, '\n' )
+    directories = []
+    for directory in privateDirs:
+        directories.append( directory[ 0 ]
+                            if isinstance( directory, tuple )
+                            else directory )
+    info( 'Private Directories:',  directories, '\n' )
     CLI( net )
     net.stop()
-    # We do this all at once to save a bit of time
-    info( 'Unmounting host bind mounts...\n' )
-    unmountAll()
-
 
 if __name__ == '__main__':
-    unmountAll()
     setLogLevel( 'info' )
     testHostWithPrivateDirs()
     info( 'Done.\n')
 
 
-
-
diff --git a/examples/linearbandwidth.py b/examples/linearbandwidth.py
index 3fd06c757db8730d10ccee8345ebd9de458f0ce9..dee5490cf28a34376a7cc93bb8a92be181badc36 100755
--- a/examples/linearbandwidth.py
+++ b/examples/linearbandwidth.py
@@ -24,7 +24,7 @@
 """
 
 from mininet.net import Mininet
-from mininet.node import UserSwitch, OVSKernelSwitch
+from mininet.node import UserSwitch, OVSKernelSwitch, Controller
 from mininet.topo import Topo
 from mininet.log import lg
 from mininet.util import irange
@@ -76,7 +76,7 @@ def linearBandwidthTest( lengths ):
         print "*** testing", datapath, "datapath"
         Switch = switches[ datapath ]
         results[ datapath ] = []
-        net = Mininet( topo=topo, switch=Switch )
+        net = Mininet( topo=topo, switch=Switch, controller=Controller, waitConnected=True )
         net.start()
         print "*** testing basic connectivity"
         for n in lengths:
diff --git a/mininet/clean.py b/mininet/clean.py
index 675c7d7e6e82069d11b1a1b2be32bc0f642a1724..49e32eaf24bd267e0bd889f6564e6dfe6e00f5fc 100755
--- a/mininet/clean.py
+++ b/mininet/clean.py
@@ -10,7 +10,7 @@
 nothing irreplaceable!
 """
 
-from subprocess import Popen, PIPE
+from subprocess import Popen, PIPE, check_output as co
 import time
 
 from mininet.log import info
@@ -69,4 +69,18 @@ def cleanup():
         if link:
             sh( "ip link del " + link )
 
+    info( "*** Killing stale mininet node processes\n" )
+    sh( 'pkill -9 -f mininet:' )
+    # Make sure they are gone
+    while True:
+        try:
+            pids = co( 'pgrep -f mininet:'.split() )
+        except:
+            pids = ''
+        if pids:
+            sh( 'pkill -f 9 mininet:' )
+            sleep( .5 )
+        else:
+            break
+
     info( "*** Cleanup complete.\n" )
diff --git a/mininet/net.py b/mininet/net.py
index 8edaee3d7072e75eb20ed16cee3f20e5a6ee180b..80654f5c37583cd341da02fb25375e6bb3c23f45 100755
--- a/mininet/net.py
+++ b/mininet/net.py
@@ -90,12 +90,13 @@
 import re
 import select
 import signal
+import copy
 from time import sleep
 from itertools import chain, groupby
 
 from mininet.cli import CLI
-from mininet.log import info, error, debug, output
-from mininet.node import Host, OVSKernelSwitch, Controller
+from mininet.log import info, error, debug, output, warn
+from mininet.node import Host, OVSKernelSwitch, DefaultController, Controller
 from mininet.link import Link, Intf
 from mininet.util import quietRun, fixLimits, numCores, ensureRoot
 from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
@@ -108,11 +109,11 @@ class Mininet( object ):
     "Network emulation with hosts spawned in network namespaces."
 
     def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
-                  controller=Controller, link=Link, intf=Intf,
+                  controller=DefaultController, link=Link, intf=Intf,
                   build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
                   inNamespace=False,
                   autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
-                  listenPort=None ):
+                  listenPort=None, waitConnected=False ):
         """Create Mininet object.
            topo: Topo (topology) object or None
            switch: default Switch class
@@ -148,6 +149,7 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
         self.numCores = numCores()
         self.nextCore = 0  # next core for pinning hosts to CPUs
         self.listenPort = listenPort
+        self.waitConn = waitConnected
 
         self.hosts = []
         self.switches = []
@@ -163,6 +165,37 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
         if topo and build:
             self.build()
 
+
+    def waitConnected( self, timeout=None, delay=.5 ):
+        """wait for each switch to connect to a controller,
+           up to 5 seconds
+           timeout: time to wait, or None to wait indefinitely
+           delay: seconds to sleep per iteration
+           returns: True if all switches are connected"""
+        info( '*** Waiting for switches to connect\n' )
+        time = 0
+        remaining = list( self.switches )
+        while True:
+            for switch in tuple( remaining ):
+                if switch.connected():
+                    info( '%s ' % switch )
+                    remaining.remove( switch )
+            if not remaining:
+                info( '\n' )
+                return True
+            if time > timeout and timeout is not None:
+                break
+            sleep( delay )
+            time += delay
+        warn( 'Timed out after %d seconds\n' % time )
+        for switch in remaining:
+            if not switch.connected():
+                warn( 'Warning: %s is not connected to a controller\n'
+                      % switch.name )
+            else:
+                remaining.remove( switch )
+        return not remaining
+
     def addHost( self, name, cls=None, **params ):
         """Add host.
            name: name of host to add
@@ -213,7 +246,7 @@ def addController( self, name='c0', controller=None, **params ):
         if not controller:
             controller = self.controller
         # Construct new controller if one is not given
-        if isinstance(name, Controller):
+        if isinstance( name, Controller ):
             controller_new = name
             # Pylint thinks controller is a str()
             # pylint: disable=E1103
@@ -222,7 +255,7 @@ def addController( self, name='c0', controller=None, **params ):
         else:
             controller_new = controller( name, **params )
         # Add new controller to net
-        if controller_new:  # allow controller-less setups
+        if controller_new: # allow controller-less setups
             self.controllers.append( controller_new )
             self.nameToNode[ name ] = controller_new
         return controller_new
@@ -324,7 +357,11 @@ def buildFromTopo( self, topo=None ):
             if type( classes ) is not list:
                 classes = [ classes ]
             for i, cls in enumerate( classes ):
-                self.addController( 'c%d' % i, cls )
+                # Allow Controller objects because nobody understands currying
+                if isinstance( cls, Controller ):
+                    self.addController( cls )
+                else:
+                    self.addController( 'c%d' % i, cls )
 
         info( '*** Adding hosts:\n' )
         for hostName in topo.hosts():
@@ -401,9 +438,16 @@ def start( self ):
             info( switch.name + ' ')
             switch.start( self.controllers )
         info( '\n' )
+        if self.waitConn:
+            self.waitConnected()
 
     def stop( self ):
         "Stop the controller(s), switches and hosts"
+        info( '*** Stopping %i controllers\n' % len( self.controllers ) )
+        for controller in self.controllers:
+            info( controller.name + ' ' )
+            controller.stop()
+        info( '\n' )
         if self.terms:
             info( '*** Stopping %i terms\n' % len( self.terms ) )
             self.stopXterms()
@@ -419,11 +463,6 @@ def stop( self ):
         for host in self.hosts:
             info( host.name + ' ' )
             host.terminate()
-        info( '\n' )
-        info( '*** Stopping %i controllers\n' % len( self.controllers ) )
-        for controller in self.controllers:
-            info( controller.name + ' ' )
-            controller.stop()
         info( '\n*** Done\n' )
 
     def run( self, test, *args, **kwargs ):
@@ -616,7 +655,7 @@ def _parseIperf( iperfOutput ):
 
     # XXX This should be cleaned up
 
-    def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
+    def iperf( self, hosts=None, l4Type='TCP', udpBw='10M', format=None ):
         """Run iperf between two hosts.
            hosts: list of hosts; if None, uses opposite hosts
            l4Type: string, one of [ TCP, UDP ]
@@ -639,6 +678,8 @@ def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
             bwArgs = '-b ' + udpBw + ' '
         elif l4Type != 'TCP':
             raise Exception( 'Unexpected l4 type: %s' % l4Type )
+        if format:
+          iperfArgs += '-f %s ' %format
         server.sendCmd( iperfArgs + '-s', printPid=True )
         servout = ''
         while server.lastPid is None:
@@ -646,7 +687,7 @@ def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
         if l4Type == 'TCP':
             while 'Connected' not in client.cmd(
                     'sh -c "echo A | telnet -e A %s 5001"' % server.IP()):
-                output('waiting for iperf to start up...')
+                info( 'Waiting for iperf to start up...' )
                 sleep(.5)
         cliout = client.cmd( iperfArgs + '-t 5 -c ' + server.IP() + ' ' +
                              bwArgs )
diff --git a/mininet/node.py b/mininet/node.py
index 7bb80ba5b9b460aecd186aa784344b55a93c98fe..3950d95762f5733edadb71e1ee669dcbba465d06 100644
--- a/mininet/node.py
+++ b/mininet/node.py
@@ -16,6 +16,11 @@
 CPULimitedHost: a virtual host whose CPU bandwidth is limited by
     RT or CFS bandwidth limiting.
 
+HostWithPrivateDirs: a virtual host that has user-specified private
+    directories. These may be temporary directories stored as a tmpfs,
+    or persistent directories that are mounted from another directory in
+    the root filesystem.
+
 Switch: superclass for switch nodes.
 
 UserSwitch: a switch using the user-space switch from the OpenFlow
@@ -735,6 +740,33 @@ def init( cls ):
         mountCgroups()
         cls.inited = True
 
+class HostWithPrivateDirs( Host ):
+    "Host with private directories"
+
+    def __init__( self, name, *args, **kwargs ):
+        "privateDirs: list of private directory strings or tuples"
+        self.name = name
+        self.privateDirs = kwargs.pop( 'privateDirs', [] )
+        Host.__init__( self, name, *args, **kwargs )
+        self.mountPrivateDirs()
+
+    def mountPrivateDirs( self ):
+        "mount private directories"
+        for directory in self.privateDirs:
+            if isinstance( directory, tuple ):
+                # mount given private directory
+                privateDir = directory[ 1 ] % self.__dict__ 
+                mountPoint = directory[ 0 ]
+                self.cmd( 'mkdir -p %s' % privateDir )
+                self.cmd( 'mkdir -p %s' % mountPoint )
+                self.cmd( 'mount --bind %s %s' %
+                               ( privateDir, mountPoint ) )
+            else:
+                # mount temporary filesystem on directory
+                self.cmd( 'mkdir -p %s' % directory ) 
+                self.cmd( 'mount -n -t tmpfs tmpfs %s' % directory )
+
+
 
 # Some important things to note:
 #
@@ -834,6 +866,8 @@ def __init__( self, name, dpopts='--no-slicing', **kwargs ):
                               '(openflow.org)' )
         if self.listenPort:
             self.opts += ' --listen=ptcp:%i ' % self.listenPort
+        else:
+            self.opts += ' --listen=punix:/tmp/%s.listen' % self.name
         self.dpopts = dpopts
 
     @classmethod
@@ -846,7 +880,7 @@ def dpctl( self, *args ):
         "Run dpctl command"
         listenAddr = None
         if not self.listenPort:
-            listenAddr = 'unix:/tmp/' + self.name
+            listenAddr = 'unix:/tmp/%s.listen' % self.name
         else:
             listenAddr = 'tcp:127.0.0.1:%i' % self.listenPort
         return self.cmd( 'dpctl ' + ' '.join( args ) +
@@ -1253,13 +1287,19 @@ def __repr__( self ):
         return '<%s %s: %s:%s pid=%s> ' % (
             self.__class__.__name__, self.name,
             self.IP(), self.port, self.pid )
-
+    @classmethod
+    def isAvailable( self ):
+        return quietRun( 'which controller' )
 
 class OVSController( Controller ):
     "Open vSwitch controller"
     def __init__( self, name, command='ovs-controller', **kwargs ):
+        if quietRun( 'which test-controller' ):
+            command = 'test-controller'
         Controller.__init__( self, name, command=command, **kwargs )
-
+    @classmethod
+    def isAvailable( self ):
+        return quietRun( 'which ovs-controller' ) or quietRun( 'which test-controller' )
 
 class NOX( Controller ):
     "Controller to run a NOX application."
@@ -1314,3 +1354,10 @@ def checkListening( self ):
         if 'Connected' not in listening:
             warn( "Unable to contact the remote controller"
                   " at %s:%d\n" % ( self.ip, self.port ) )
+
+
+def DefaultController( name, order=[ Controller, OVSController ], **kwargs ):
+    "find any controller that is available and run it"
+    for controller in order:
+        if controller.isAvailable():
+            return controller( name, **kwargs )
diff --git a/mininet/nodelib.py b/mininet/nodelib.py
new file mode 100644
index 0000000000000000000000000000000000000000..2eb80465cd005c28c9a2aaa86aa920b2cc04c02a
--- /dev/null
+++ b/mininet/nodelib.py
@@ -0,0 +1,51 @@
+"""
+Node Library for Mininet
+
+This contains additional Node types which you may find to be useful
+"""
+
+from mininet.net import Mininet
+from mininet.topo import Topo
+from mininet.node import Switch
+from mininet.log import setLogLevel, info
+
+
+class LinuxBridge( Switch ):
+    "Linux Bridge (with optional spanning tree)"
+
+    nextPrio = 100  # next bridge priority for spanning tree
+
+    def __init__( self, name, stp=False, prio=None, **kwargs ):
+        """stp: use spanning tree protocol? (default False)
+           prio: optional explicit bridge priority for STP"""
+        self.stp = stp
+        if prio:
+            self.prio = prio
+        else:
+            self.prio = LinuxBridge.nextPrio
+            LinuxBridge.nextPrio += 1
+        Switch.__init__( self, name, **kwargs )
+
+    def connected( self ):
+        "Are we forwarding yet?"
+        if self.stp:
+            return 'forwarding' in self.cmd( 'brctl showstp', self )
+        else:
+            return True
+    
+    def start( self, controllers ):
+        self.cmd( 'ifconfig', self, 'down' )
+        self.cmd( 'brctl delbr', self )
+        self.cmd( 'brctl addbr', self )
+        if self.stp:
+            self.cmd( 'brctl setbridgeprio', self.prio )
+            self.cmd( 'brctl stp', self, 'on' )
+        for i in self.intfList():
+            if self.name in i.name:
+                self.cmd( 'brctl addif', self, i )
+        self.cmd( 'ifconfig', self, 'up' )
+
+    def stop( self ):
+        self.cmd( 'ifconfig', self, 'down' )
+        self.cmd( 'brctl delbr', self )
+
diff --git a/mininet/test/test_hifi.py b/mininet/test/test_hifi.py
index 20ee03167b648f59f7ea94b8f37400ee0d375670..c888e29620a4edfd4aea6468feff43be11c44ba8 100755
--- a/mininet/test/test_hifi.py
+++ b/mininet/test/test_hifi.py
@@ -55,6 +55,9 @@ def assertWithinTolerance(self, measured, expected, tolerance_frac):
         """
         self.assertGreaterEqual( float(measured),
                                  float(expected) * tolerance_frac )
+        self.assertLessEqual( float( measured ),
+                                 float(expected) + (1-tolerance_frac)
+                                 * float( expected ) )
 
     def testCPULimits( self ):
         "Verify topology creation with CPU limits set for both schedulers."
@@ -68,19 +71,20 @@ def testCPULimits( self ):
         mn.start()
         results = mn.runCpuLimitTest( cpu=CPU_FRACTION )
         mn.stop()
-        for cpu in results:
-            self.assertWithinTolerance( cpu, CPU_FRACTION, CPU_TOLERANCE )
+        for pct in results:
+            #divide cpu by 100 to convert from percentage to fraction
+            self.assertWithinTolerance( pct/100, CPU_FRACTION, CPU_TOLERANCE )
 
     def testLinkBandwidth( self ):
         "Verify that link bandwidths are accurate within a bound."
-        BW = 5  # Mbps
+        BW = .5  # Mbps
         BW_TOLERANCE = 0.8  # BW fraction below which test should fail
         # Verify ability to create limited-link topo first;
         lopts = { 'bw': BW, 'use_htb': True }
         # Also verify correctness of limit limitng within a bound.
         mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
                       link=TCLink, switch=self.switchClass )
-        bw_strs = mn.run( mn.iperf )
+        bw_strs = mn.run( mn.iperf, format='m' )
         for bw_str in bw_strs:
             bw = float( bw_str.split(' ')[0] )
             self.assertWithinTolerance( bw, BW, BW_TOLERANCE )
@@ -91,7 +95,7 @@ def testLinkDelay( self ):
         DELAY_TOLERANCE = 0.8  # Delay fraction below which test should fail
         lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True }
         mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
-                      link=TCLink, switch=self.switchClass )
+                      link=TCLink, switch=self.switchClass, autoStaticArp=True )
         ping_delays = mn.run( mn.pingFull )
         test_outputs = ping_delays[0]
         # Ignore unused variables below
@@ -102,9 +106,10 @@ def testLinkDelay( self ):
         # pylint: enable-msg=W0612
         for rttval in [rttmin, rttavg, rttmax]:
             # Multiply delay by 4 to cover there & back on two links
-            self.assertWithinTolerance( rttval, DELAY_MS * 4.0,
+            self.assertWithinTolerance( rttval, DELAY_MS * 4.0, 
                                         DELAY_TOLERANCE)
 
+
     def testLinkLoss( self ):
         "Verify that we see packet drops with a high configured loss rate."
         LOSS_PERCENT = 99
diff --git a/mininet/test/test_nets.py b/mininet/test/test_nets.py
index 159ba348c46831fe4e48f020f07bbd79d40d4744..330e9a88a6c69e336f95467bf99e2b9bb9b31e69 100755
--- a/mininet/test/test_nets.py
+++ b/mininet/test/test_nets.py
@@ -66,7 +66,7 @@ class testLinearCommon( object ):
 
     def testLinear5( self ):
         "Ping test on a 5-switch topology"
-        mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host, Controller )
+        mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host, Controller, waitConnected=True )
         dropped = mn.run( mn.ping )
         self.assertEqual( dropped, 0 )
 
diff --git a/mininet/topo.py b/mininet/topo.py
index f9c421fbc8f57dc72e0850ae72ebd9cab99ee41c..de5ba8a7a37d63cfd5795aec907f32cfb33420bf 100644
--- a/mininet/topo.py
+++ b/mininet/topo.py
@@ -48,18 +48,25 @@ def __getitem__( self, node ):
 class Topo(object):
     "Data center network representation for structured multi-trees."
 
-    def __init__(self, hopts=None, sopts=None, lopts=None):
-        """Topo object:
+    def __init__(self, *args, **params):
+        """Topo object. 
+           Optional named parameters:
            hinfo: default host options
            sopts: default switch options
-           lopts: default link options"""
+           lopts: default link options
+           calls build()"""
         self.g = MultiGraph()
         self.node_info = {}
         self.link_info = {}  # (src, dst) tuples hash to EdgeInfo objects
-        self.hopts = {} if hopts is None else hopts
-        self.sopts = {} if sopts is None else sopts
-        self.lopts = {} if lopts is None else lopts
+        self.hopts = params.pop( 'hopts', {} )
+        self.sopts = params.pop( 'sopts', {} )
+        self.lopts = params.pop( 'lopts', {} )
         self.ports = {}  # ports[src][dst] is port on src that connects to dst
+        self.build( *args, **params )
+
+    def build( self, *args, **params ):
+        "Override this method to build your topology."
+        pass
 
     def addNode(self, name, **opts):
         """Add Node to graph.
diff --git a/mininet/topolib.py b/mininet/topolib.py
index 63ba36deb3d51e5a246545e7bfe8782ed4a3848e..8e3b3a4b6a33caabebaba7ddcfde5e581ea9197e 100644
--- a/mininet/topolib.py
+++ b/mininet/topolib.py
@@ -34,3 +34,37 @@ def TreeNet( depth=1, fanout=2, **kwargs ):
     "Convenience function for creating tree networks."
     topo = TreeTopo( depth, fanout )
     return Mininet( topo, **kwargs )
+
+
+class TorusTopo( Topo ):
+    """2-D Torus topology
+       WARNING: this topology has LOOPS and WILL NOT WORK
+       with the default controller or any Ethernet bridge
+       without STP turned on! It can be used with STP, e.g.:
+       # mn --topo torus,3,3 --switch lxbr,stp=1 --test pingall"""
+    def __init__( self, x, y, *args, **kwargs ):
+        Topo.__init__( self, *args, **kwargs )
+        if x < 3 or y < 3:
+            raise Exception( 'Please use 3x3 or greater for compatibility '
+                            'with 2.1' )
+        hosts, switches, dpid = {}, {}, 0
+        # Create and wire interior
+        for i in range( 0, x ):
+            for j in range( 0, y ):
+                loc = '%dx%d' % ( i + 1, j + 1 )
+                # dpid cannot be zero for OVS
+                dpid = ( i + 1 ) * 256 + ( j + 1 )
+                switch = switches[ i, j ] = self.addSwitch( 's' + loc, dpid='%016x' % dpid )
+                host = hosts[ i, j ] = self.addHost( 'h' + loc )
+                self.addLink( host, switch )
+        # Connect switches
+        for i in range( 0, x ):
+            for j in range( 0, y ):
+                sw1 = switches[ i, j ]
+                sw2 = switches[ i, ( j + 1 ) % y ]
+                sw3 = switches[ ( i + 1 ) % x, j ]
+                self.addLink( sw1, sw2 )
+                self.addLink( sw1, sw3 )
+
+    
+
diff --git a/mnexec.c b/mnexec.c
index fee3d2506e620f7cebfb9a7de15a674915823e09..c7103d4670d72e82364d8eef349cd1bc89f0b556 100644
--- a/mnexec.c
+++ b/mnexec.c
@@ -140,7 +140,7 @@ int main(int argc, char *argv[])
             fflush(stdout);
             break;
         case 'a':
-            /* Attach to pid's network namespace */
+            /* Attach to pid's network namespace and mount namespace*/
             pid = atoi(optarg);
             sprintf(path, "/proc/%d/ns/net", pid );
             nsid = open(path, O_RDONLY);
@@ -152,6 +152,16 @@ int main(int argc, char *argv[])
                 perror("setns");
                 return 1;
             }
+            sprintf(path, "/proc/%d/ns/mnt", pid );
+            nsid = open(path, O_RDONLY);
+            if (nsid < 0) {
+                perror(path);
+                return 1;
+            }
+            if (setns(nsid, 0) != 0) {
+                perror("setns");
+                return 1;
+            }
             break;
         case 'g':
             /* Attach to cgroup */
diff --git a/util/vm/build.py b/util/vm/build.py
index be809eced8ef4c2982e048ef8526a3cef16ba462..ad454f0ddfbd3df163202cd352ebad1f480a3abc 100755
--- a/util/vm/build.py
+++ b/util/vm/build.py
@@ -89,6 +89,12 @@
     'trusty64server':
     'http://mirrors.kernel.org/ubuntu-releases/14.04/'
     'ubuntu-14.04-server-amd64.iso',
+    'utopic32server':
+    'http://mirrors.kernel.org/ubuntu-releases/14.10/'
+    'ubuntu-14.10-server-i386.iso',
+    'utopic64server':
+    'http://mirrors.kernel.org/ubuntu-releases/14.10/'
+    'ubuntu-14.10-server-amd64.iso',
 }