diff --git a/examples/ripcordtest.py b/examples/ripcordtest.py
index 3491851c313d4720167a44fd472f2976219791a6..7ac257819aa427fdaba5c8e931262e1563862e31 100755
--- a/examples/ripcordtest.py
+++ b/examples/ripcordtest.py
@@ -1,483 +1,16 @@
 #!/usr/bin/python
-
-'''Run a FatTree network from the Ripcord project.
-
-For verbose printout, set LOG_LEVEL_DEFAULT in mininet.py to logging.INFO.
-'''
-
-import os
-import re
-from subprocess import call
-import sys
-from time import sleep
+'''Run a FatTree network from the Ripcord project.'''
 
 from ripcord.topo import FatTreeTopo
 
-from mininet.net import init
-from mininet.node import Switch, Controller, Host
-from mininet.logging_mod import lg, set_loglevel
-from mininet.util import make_veth_pair, move_intf, retry, quietRun
-from mininet.util import MOVEINTF_DELAY
-
-
-class Mininet(object):
-    '''Network emulation with hosts spawned in network namespaces.'''
-
-    def __init__(self, topo, switch, host, controller, cparams,
-                 build = True, xterms = False, cleanup = False,
-                 in_namespace = False, switch_is_kernel = True):
-        '''Create Mininet object.
-
-        @param topo Topo object
-        @param switch Switch class
-        @param host Host class
-        @param controller Controller class
-        @param cparams ControllerParams object
-        @param now build now?
-        @param xterms if build now, spawn xterms?
-        @param cleanup if build now, cleanup before creating?
-        @param in_namespace spawn switches and hosts in their own namespace?
-        '''
-        self.topo = topo
-        self.switch = switch
-        self.host = host
-        self.controller = controller
-        self.cparams = cparams
-        self.nodes = {} # dpid to Node{Host, Switch} objects
-        self.controllers = {} # controller name to Controller objects
-        self.dps = 0 # number of created kernel datapaths
-        self.in_namespace = in_namespace
-        self.switch_is_kernel = switch_is_kernel
-
-        self.kernel = True #temporary!
-
-        if build:
-            self.build(xterms, cleanup)
-
-    def _add_host(self, dpid):
-        '''Add host.
-
-        @param dpid DPID of host to add
-        '''
-        host = self.host('h_' + self.topo.name(dpid))
-        # for now, assume one interface per host.
-        host.intfs.append('h_' + self.topo.name(dpid) + '-eth0')
-        self.nodes[dpid] = host
-        #lg.info('%s ' % host.name)
-
-    def _add_switch(self, dpid):
-        '''
-        @param dpid DPID of switch to add
-        '''
-        sw = None
-        if self.switch_is_kernel:
-            sw = self.switch('s_' + self.topo.name(dpid), 'nl:' + str(self.dps))
-            self.dps += 1
-        else:
-            sw = self.switch('s_' + self.topo.name(dpid))
-        self.nodes[dpid] = sw
-
-    def _add_link(self, src, dst):
-        '''Add link.
-
-        @param src source DPID
-        @param dst destination DPID
-        '''
-        src_port, dst_port = self.topo.port(src, dst)
-        src_node = self.nodes[src]
-        dst_node = self.nodes[dst]
-        src_intf = src_node.intfName(src_port)
-        dst_intf = dst_node.intfName(dst_port)
-        make_veth_pair(src_intf, dst_intf)
-        src_node.intfs.append(src_intf)
-        dst_node.intfs.append(dst_intf)
-        #lg.info('\n')
-        #lg.info('added intf %s to src node %x\n' % (src_intf, src))
-        #lg.info('added intf %s to dst node %x\n' % (dst_intf, dst))
-        if src_node.inNamespace:
-            #lg.info('moving src w/inNamespace set\n')
-            retry(3, MOVEINTF_DELAY, move_intf, src_intf, src_node)
-        if dst_node.inNamespace:
-            #lg.info('moving dst w/inNamespace set\n')
-            retry(3, MOVEINTF_DELAY, move_intf, dst_intf, dst_node)
-        src_node.connection[src_intf] = (dst_node, dst_intf)
-        dst_node.connection[dst_intf] = (src_node, src_intf)
-
-    def _add_controller(self, controller):
-        '''Add controller.
-
-        @param controller Controller class
-        '''
-        controller = self.controller('c0', kernel = self.kernel)
-        self.controllers['c0'] = controller
-
-    # Control network support:
-    #
-    # Create an explicit control network. Currently this is only
-    # used by the user datapath configuration.
-    #
-    # Notes:
-    #
-    # 1. If the controller and switches are in the same (e.g. root)
-    #    namespace, they can just use the loopback connection.
-    #    We may wish to do this for the user datapath as well as the
-    #    kernel datapath.
-    #
-    # 2. If we can get unix domain sockets to work, we can use them
-    #    instead of an explicit control network.
-    #
-    # 3. Instead of routing, we could bridge or use 'in-band' control.
-    #
-    # 4. Even if we dispense with this in general, it could still be
-    #    useful for people who wish to simulate a separate control
-    #    network (since real networks may need one!)
-
-    def _configureControlNetwork(self):
-        '''Configure control network.'''
-        self._configureRoutedControlNetwork()
-
-    def _configureRoutedControlNetwork(self):
-        '''Configure a routed control network on controller and switches.
-
-        For use with the user datapath only right now.
-
-        @todo(brandonh) Test this code and verify that user-space works!
-        '''
-        # params were: controller, switches, ips
-
-        controller = self.controllers['c0']
-        lg.info('%s <-> ' % controller.name)
-        for switch_dpid in self.topo.switches():
-            switch = self.nodes[switch_dpid]
-            lg.info('%s ' % switch.name)
-            sip = self.topo.ip(switch_dpid)#ips.next()
-            sintf = switch.intfs[0]
-            node, cintf = switch.connection[sintf]
-            if node != controller:
-                lg.error('*** Error: switch %s not connected to correct'
-                         'controller' %
-                         switch.name)
-                exit(1)
-            controller.setIP(cintf, self.cparams.ip, '/' +
-                             self.cparams.subnet_size)
-            switch.setIP(sintf, sip, '/' + self.cparams.subnet_size)
-            controller.setHostRoute(sip, cintf)
-            switch.setHostRoute(self.cparams.ip, sintf)
-        lg.info('\n')
-        lg.info('*** Testing control network\n')
-        while not controller.intfIsUp(controller.intfs[0]):
-            lg.info('*** Waiting for %s to come up\n', controller.intfs[0])
-            sleep(1)
-        for switch_dpid in self.topo.switches():
-            switch = self.nodes[switch_dpid]
-            while not switch.intfIsUp(switch.intfs[0]):
-                lg.info('*** Waiting for %s to come up\n' % switch.intfs[0])
-                sleep(1)
-            if self.ping_test(hosts=[switch, controller]) != 0:
-                lg.error('*** Error: control network test failed\n')
-                exit(1)
-        lg.info('\n')
-
-    def _config_hosts( self ):
-        '''Configure a set of hosts.'''
-        # params were: hosts, ips
-        for host_dpid in self.topo.hosts():
-            host = self.nodes[host_dpid]
-            hintf = host.intfs[0]
-            host.setIP(hintf, self.topo.ip(host_dpid),
-                       '/' + str(self.cparams.subnet_size))
-            host.setDefaultRoute(hintf)
-            # You're low priority, dude!
-            quietRun('renice +18 -p ' + repr(host.pid))
-            lg.info('%s ', host.name)
-        lg.info('\n')
-
-    def build(self, xterms, cleanup):
-        '''Build mininet.
-
-        At the end of this function, everything should be connected and up.
-
-        @param xterms spawn xterms on build?
-        @param cleanup cleanup before creating?
-        '''
-        if cleanup:
-            pass # cleanup
-        # validate topo?
-        kernel = self.kernel
-        if kernel:
-            lg.info('*** Using kernel datapath\n')
-        else:
-            lg.info('*** Using user datapath\n')
-        lg.info('*** Adding controller\n')
-        self._add_controller(self.controller)
-        lg.info('*** Creating network\n')
-        lg.info('*** Adding hosts:\n')
-        for host in sorted(self.topo.hosts()):
-            self._add_host(host)
-            lg.info('0x%x ' % host)
-        lg.info('\n*** Adding switches:\n')
-        for switch in sorted(self.topo.switches()):
-            self._add_switch(switch)
-            lg.info('0x%x ' % switch)
-        lg.info('\n*** Adding edges: ')
-        for src, dst in sorted(self.topo.edges()):
-            self._add_link(src, dst)
-            lg.info('(0x%x, 0x%x) ' % (src, dst))
-        lg.info('\n')
-
-        if not kernel:
-            lg.info('*** Configuring control network\n')
-            self._configureControlNetwork()
-
-        lg.info('*** Configuring hosts\n')
-        self._config_hosts()
-
-        if xterms:
-            pass # build xterms
-
-    def start(self):
-        '''Start controller and switches\n'''
-        lg.info('*** Starting controller\n')
-        self.controllers['c0'].start()
-        #for controller in self.controllers:
-        #    controller.start()
-        lg.info('*** Starting %s switches\n' % len(self.topo.switches()))
-        for switch_dpid in self.topo.switches():
-            switch = self.nodes[switch_dpid]
-            #lg.info('switch = %s' % switch)
-            lg.info('0x%x ' % switch_dpid)
-            switch.start(self.controllers['c0'])
-        lg.info('\n')
-
-    def stop(self):
-        '''Stop the controller(s), switches and hosts\n'''
-        lg.info('*** Stopping %i hosts\n' % len(self.topo.hosts()))
-        for host_dpid in self.topo.hosts():
-            host = self.nodes[host_dpid]
-            lg.info('%s ' % host.name)
-            host.terminate()
-        lg.info('\n')
-        lg.info('*** Stopping %i switches\n' % len(self.topo.switches()))
-        for switch_dpid in self.topo.switches():
-            switch = self.nodes[switch_dpid]
-            lg.info('%s' % switch.name)
-            switch.stop()
-        lg.info('\n')
-        lg.info('*** Stopping controller\n')
-        #for controller in self.controllers.iteriterms():
-        self.controllers['c0'].stop()
-        lg.info('*** Test complete\n')
-
-    def run(self, test, **params):
-        '''Perform a complete start/test/stop cycle.'''
-        self.start()
-        lg.info('*** Running test\n')
-        result = test(self, **params)
-        self.stop()
-        return result
-
-    @staticmethod
-    def _parse_ping(pingOutput):
-        '''Parse ping output and return packets sent, received.'''
-        r = r'(\d+) packets transmitted, (\d+) received'
-        m = re.search( r, pingOutput )
-        if m == None:
-            lg.error('*** Error: could not parse ping output: %s\n' %
-                     pingOutput)
-            exit(1)
-        sent, received = int(m.group(1)), int(m.group(2))
-        return sent, received
-
-    def ping_test(self, hosts = None, verbose = False):
-        '''Ping between all specified hosts.
-
-        @param hosts list of host DPIDs
-        @param verbose verbose printing
-        @return ploss packet loss percentage
-        '''
-        #self.start()
-        # check if running - only then, start?
-        packets = 0
-        lost = 0
-        if not hosts:
-            hosts = self.topo.hosts()
-        for node_dpid in hosts:
-            node = self.nodes[node_dpid]
-            if verbose:
-                lg.info('%s -> ' % node.name)
-            for dest_dpid in hosts:
-                dest = self.nodes[dest_dpid]
-                if node != dest:
-                    result = node.cmd('ping -c1 ' + dest.IP())
-                    sent, received = self._parse_ping(result)
-                    packets += sent
-                    if received > sent:
-                        lg.error('*** Error: received too many packets')
-                        lg.error('%s' % result)
-                        node.cmdPrint('route')
-                        exit( 1 )
-                    lost += sent - received
-                    if verbose:
-                        lg.info(('%s ' % dest.name) if received else 'X ')
-            if verbose:
-                lg.info('\n')
-            ploss = 100 * lost/packets
-        if verbose:
-            lg.info('%d%% packet loss (%d/%d lost)\n' % (ploss, lost, packets))
-            #flush()
-        #self.stop()
-        return ploss
-
-    def interact(self):
-        '''Start network and run our simple CLI.'''
-        self.run(Cli)
-
-
-class Cli(object):
-    '''Simple command-line interface to talk to nodes.'''
-    cmds = ['?', 'help', 'nodes', 'net', 'sh', 'ping_all', 'exit', \
-            'ping_pair'] #'iperf'
-
-    def __init__(self, mininet):
-        self.mn = mininet
-        self.nodemap = {} # map names to Node objects
-        for node in self.mn.nodes.values():
-            self.nodemap[node.name] = node
-        self.nodemap['c0'] = self.mn.controllers['c0']
-        self.nodelist = self.nodemap.values()
-        self.run()
-
-    # Commands
-    def help(self, args):
-        '''Semi-useful help for CLI.'''
-        help_str = 'Available commands are:' + str(self.cmds) + '\n' + \
-                   'You may also send a command to a node using:\n' + \
-                   '  <node> command {args}\n' + \
-                   'For example:\n' + \
-                   '  mininet> h0 ifconfig\n' + \
-                   '\n' + \
-                   'The interpreter automatically substitutes IP ' + \
-                   'addresses\n' + \
-                   'for node names, so commands like\n' + \
-                   '  mininet> h0 ping -c1 h1\n' + \
-                   'should work.\n' + \
-                   '\n\n' + \
-                   'Interactive commands are not really supported yet,\n' + \
-                   'so please limit commands to ones that do not\n' + \
-                   'require user interaction and will terminate\n' + \
-                   'after a reasonable amount of time.\n'
-        print(help_str)
-
-    def nodes(self, args):
-        '''List all nodes.'''
-        lg.info('available nodes are: \n%s\n',
-                ' '.join([node.name for node in sorted(self.nodelist)]))
-
-    def net(self, args):
-        '''List network connection.'''
-        for switch_dpid in self.mn.topo.switches():
-            switch = self.mn.nodes[switch_dpid]
-            lg.info('%s <->', switch.name)
-            for intf in switch.intfs:
-                node, remoteIntf = switch.connection[intf]
-                lg.info(' %s' % node.name)
-            lg.info('\n')
-
-    def sh(self, args):
-        '''Run an external shell command'''
-        call( [ 'sh', '-c' ] + args )
-
-    def ping_all(self, args):
-        '''Ping between all hosts.'''
-        self.mn.ping_test(verbose = True)
-
-    def ping_pair(self, args):
-        '''Ping between first two hosts, useful for testing.'''
-        hosts_unsorted = sorted(self.mn.topo.hosts())
-        hosts = [hosts_unsorted[0], hosts_unsorted[1]]
-        self.mn.ping_test(hosts = hosts, verbose = True)
-
-    def run(self):
-        '''Read and execute commands.'''
-        lg.warn('*** Starting CLI:\n')
-        while True:
-            lg.warn('mininet> ')
-            input = sys.stdin.readline()
-            if input == '':
-                break
-            if input[-1] == '\n':
-                input = input[:-1]
-            cmd = input.split(' ')
-            first = cmd[0]
-            rest = cmd[1:]
-            if first in self.cmds and hasattr(self, first):
-                getattr(self, first)(rest)
-            elif first in self.nodemap and rest != []:
-                node = self.nodemap[first]
-                # Substitute IP addresses for node names in command
-                rest = [self.nodemap[arg].IP() if arg in self.nodemap else arg
-                        for arg in rest]
-                rest = ' '.join(rest)
-                # Interactive commands don't work yet, and
-                # there are still issues with control-c
-                lg.warn('*** %s: running %s\n' % (node.name, rest))
-                node.sendCmd( rest )
-                while True:
-                    try:
-                        done, data = node.monitor()
-                        lg.info('%s\n' % data)
-                        if done:
-                            break
-                    except KeyboardInterrupt:
-                        node.sendInt()
-            elif first == '':
-                pass
-            elif first in ['exit', 'quit']:
-                break
-            elif first == '?':
-                self.help( rest )
-            else:
-                lg.error('CLI: unknown node or command: < %s >\n' % first)
-            #lg.info('*** CLI: command complete\n')
-        return 'exited by user command'
-
-
-class NOXController(Controller):
-    '''Controller to run a NOX application.'''
-    def __init__(self, name, nox_args = None, **kwargs):
-        '''Init.
-
-        @param name name to give controller
-        @param nox_args list of args to use with NOX
-        '''
-        if not nox_args:
-            nox_args = ['packetdump']
-        nox_core_dir = os.environ['NOX_CORE_DIR']
-        if not nox_core_dir:
-            raise Exception('please set NOX_CORE_DIR env var\n')
-        Controller.__init__(self, name,
-            controller = nox_core_dir + '/nox_core',
-            cargs = '--libdir=/usr/local/lib -v -i ptcp: ' + \
-                    ' '.join(nox_args),
-            cdir = nox_core_dir, **kwargs)
-
-
-class ControllerParams(object):
-    '''Container for controller IP parameters.'''
-    def __init__(self, ip, subnet_size):
-        '''Init.
-
-        @param ip integer, controller IP
-        @param subnet_size integer, ex 8 for slash-8, covering 17M
-        '''
-        self.ip = ip
-        self.subnet_size = subnet_size
-
+from mininet.logging_mod import set_loglevel
+from mininet.net import init, Mininet
+from mininet.node import Switch, Host, NOXController, ControllerParams
 
 if __name__ == '__main__':
     set_loglevel('info')
     init()
     controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
     mn = Mininet(FatTreeTopo(4), Switch, Host, NOXController,
-                      controller_params)
+                 controller_params)
     mn.interact()
\ No newline at end of file
diff --git a/mininet/net.py b/mininet/net.py
index 47f94562e8c4b7ab20a74784cd9ab600285064f4..0b25e88ab86bac5b3eaa5ebbf7a339eb5b5a725b 100755
--- a/mininet/net.py
+++ b/mininet/net.py
@@ -66,499 +66,479 @@
 12/12/09 Added subdivided network driver workflow
 12/13/09 Added support for custom controller and switch classes
 """
-
-from subprocess import call, Popen, PIPE, STDOUT
+import os
+import re
+from subprocess import call
+import sys
 from time import sleep
-import os, re, signal, sys, select
-flush = sys.stdout.flush
+#flush = sys.stdout.flush
+#import os, re, signal, sys, select
 
 from mininet.logging_mod import lg, set_loglevel
-from mininet.node import Node, Host, Controller, Switch
-from mininet.util import run, checkRun, quietRun, makeIntfPair, moveIntf
-from mininet.util import createLink, setLimits
-
-DATAPATHS = ['user', 'kernel']
-
-# Handy utilities
-     
-def dumpNodes( nodes ):
-   "Dump ifconfig of each node."
-   for node in nodes:
-      lg.info("*** Dumping node %s\n" % node.name)
-      lg.info("%s\n" % node.cmd( 'ip link show' ))
-      lg.info("%s\n" % node.cmd( 'route' ))
-
-def ipGen( A, B, c, d ):
-   "Generate next IP class B IP address, starting at A.B.c.d"
-   while True:
-      yield '%d.%d.%d.%d' % ( A, B, c, d )
-      d += 1
-      if d > 254:
-         d = 1
-         c += 1
-         if c > 254: break
-
-def nameGen( prefix ):
-   "Generate names starting with prefix."
-   i = 0
-   while True: yield prefix + `i`; i += 1
-      
-# Control network support:
-#
-# Create an explicit control network. Currently this is only
-# used by the user datapath configuration.
-#
-# Notes:
-#
-# 1. If the controller and switches are in the same (e.g. root)
-#    namespace, they can just use the loopback connection.
-#    We may wish to do this for the user datapath as well as the
-#    kernel datapath.
-#
-# 2. If we can get unix domain sockets to work, we can use them
-#    instead of an explicit control network.
-#
-# 3. Instead of routing, we could bridge or use "in-band" control.
-#
-# 4. Even if we dispense with this in general, it could still be
-#    useful for people who wish to simulate a separate control
-#    network (since real networks may need one!)
-
-def configureRoutedControlNetwork( controller, switches, ips):
-   """Configure a routed control network on controller and switches,
-      for use with the user datapath."""
-   cip = ips.next()
-   lg.info("%s <-> " % controller.name)
-   for switch in switches:
-      lg.info("%s " % switch.name)
-      sip = ips.next()
-      sintf = switch.intfs[ 0 ]
-      node, cintf = switch.connection[ sintf ]
-      if node != controller:
-         lg.error("*** Error: switch %s not connected to correct controller" %
-                  switch.name)
-         exit( 1 )
-      controller.setIP( cintf, cip,  '/24' )
-      switch.setIP( sintf, sip, '/24' )
-      controller.setHostRoute( sip, cintf )
-      switch.setHostRoute( cip, sintf )
-   lg.info("\n")
-   lg.info("*** Testing control network\n")
-   while not controller.intfIsUp():
-      lg.info("*** Waiting for %s to come up\n", controller.intfs[ 0 ])
-      sleep( 1 )
-   for switch in switches:
-      while not switch.intfIsUp():
-         lg.info("*** Waiting for %s to come up\n" % switch.intfs[ 0 ])
-         sleep( 1 )
-      if pingTest( hosts=[ switch, controller ] ) != 0:
-         lg.error("*** Error: control network test failed\n")
-         exit( 1 )
-
-def configHosts( hosts, ips ):
-   """Configure a set of hosts, starting at IP address a.b.c.d"""
-   for host in hosts:
-      hintf = host.intfs[ 0 ]
-      host.setIP( hintf, ips.next(), '/24' )
-      host.setDefaultRoute( hintf )
-      # You're low priority, dude!
-      quietRun( 'renice +18 -p ' + `host.pid` )
-      lg.info("%s ", host.name)
-   lg.info("\n")
-
-# Test driver and topologies
-
-class Network( object ):
-   """Network topology (and test driver) base class."""
-   def __init__( self,
-      kernel=True, 
-      Controller=Controller, Switch=Switch, 
-      hostIpGen=ipGen, hostIpStart=( 192, 168, 123, 1 ) ):
-      self.kernel = kernel
-      self.Controller = Controller
-      self.Switch = Switch
-      self.hostIps = apply( hostIpGen, hostIpStart )
-      # Check for kernel modules
-      modules = quietRun( 'lsmod' )
-      if not kernel and 'tun' not in modules:
-         lg.error("*** Error: kernel module tun not loaded:\n")
-         lg.error(" user datapath not supported\n")
-         exit( 1 )
-      if kernel and 'ofdatapath' not in modules:
-         lg.error("*** Error: kernel module ofdatapath not loaded:\n")
-         lg.error(" kernel datapath not supported\n")
-         exit( 1 )
-      # Create network, but don't start things up yet!
-      self.prepareNet()
-   def configureControlNetwork( self,
-      ipGen=ipGen, ipStart = (10, 0, 123, 1 ) ):
-      ips = apply( ipGen, ipStart )
-      configureRoutedControlNetwork( self.controllers[ 0 ],
-         self.switches, ips = ips)
-   def configHosts( self ):
-      configHosts( self.hosts, self.hostIps )
-   def prepareNet( self ):
-      """Create a network by calling makeNet as follows: 
-         (switches, hosts ) = makeNet()
-         Create a controller here as well."""
-      kernel = self.kernel
-      if kernel:
-          lg.info("*** Using kernel datapath\n")
-      else:
-          lg.info("*** Using user datapath\n")
-      lg.info("*** Creating controller\n")
-      self.controller = self.Controller( 'c0', kernel=kernel )
-      self.controllers = [ self.controller ]
-      lg.info("*** Creating network\n")
-      self.switches, self.hosts = self.makeNet( self.controller )
-      lg.info("\n")
-      if not kernel:
-         lg.info("*** Configuring control network\n")
-         self.configureControlNetwork()
-      lg.info("*** Configuring hosts\n")
-      self.configHosts()
-   def start( self ):
-      """Start controller and switches\n"""
-      lg.info("*** Starting controller\n")
-      for controller in self.controllers:
-         controller.start()
-      lg.info("*** Starting %s switches" % len(self.switches))
-      for switch in self.switches:
-         switch.start( self.controllers[ 0 ] )
-      lg.info("\n")
-   def stop( self ):
-      """Stop the controller(s), switches and hosts\n"""
-      lg.info("*** Stopping hosts\n")
-      for host in self.hosts: 
-         host.terminate()
-      lg.info("*** Stopping switches\n")
-      for switch in self.switches:
-         lg.info("%s" % switch.name)
-         switch.stop()
-      lg.info("\n")
-      lg.info("*** Stopping controller\n")
-      for controller in self.controllers:
-         controller.stop();
-      lg.info("*** Test complete\n")
-   def runTest( self, test ):
-      """Run a given test, called as test( controllers, switches, hosts)"""
-      return test( self.controllers, self.switches, self.hosts )
-   def run( self, test ):
-      """Perform a complete start/test/stop cycle; test is of the form
-         test( controllers, switches, hosts )"""
-      self.start()
-      lg.info("*** Running test\n")
-      result = self.runTest( test )
-      self.stop()
-      return result
-   def interact( self ):
-      "Create a network and run our simple CLI."
-      self.run( self, Cli )
-   
-def defaultNames( snames=None, hnames=None, dpnames=None ):
-   "Reinitialize default names from generators, if necessary."
-   if snames is None: snames = nameGen( 's' )
-   if hnames is None: hnames = nameGen( 'h' )
-   if dpnames is None: dpnames = nameGen( 'nl:' )
-   return snames, hnames, dpnames
-
-# Tree network
-
-class TreeNet( Network ):
-   "A tree-structured network with the specified depth and fanout"
-   def __init__( self, depth, fanout, **kwargs):
-      self.depth, self.fanout = depth, fanout
-      Network.__init__( self, **kwargs )
-   def treeNet( self, controller, depth, fanout, snames=None,
-      hnames=None, dpnames=None ):
-      """Return a tree network of the given depth and fanout as a triple:
-         ( root, switches, hosts ), using the given switch, host and
-         datapath name generators, with the switches connected to the given
-         controller. If kernel=True, use the kernel datapath; otherwise the
-         user datapath will be used."""
-      # Ugly, but necessary (?) since defaults are only evaluated once
-      snames, hnames, dpnames = defaultNames( snames, hnames, dpnames )
-      if ( depth == 0 ):
-         host = Host( hnames.next() )
-         lg.info("%s " % host.name)
-         return host, [], [ host ]
-      dp = dpnames.next() if self.kernel else None
-      switch = Switch( snames.next(), dp )
-      if not self.kernel: createLink( switch, controller )
-      lg.info("%s " % switch.name)
-      switches, hosts = [ switch ], []
-      for i in range( 0, fanout ):
-         child, slist, hlist = self.treeNet( controller, 
-            depth - 1, fanout, snames, hnames, dpnames )
-         createLink( switch, child )
-         switches += slist
-         hosts += hlist
-      return switch, switches, hosts
-   def makeNet( self, controller ):
-      root, switches, hosts = self.treeNet( controller,
-         self.depth, self.fanout )
-      return switches, hosts
-   
-# Grid network
-
-class GridNet( Network ):
-   """An N x M grid/mesh network of switches, with hosts at the edges.
-      This class also demonstrates creating a somewhat complicated
-      topology."""
-   def __init__( self, n, m, linear=False, **kwargs ):
-      self.n, self.m, self.linear = n, m, linear and m == 1
-      Network.__init__( self, **kwargs )
-   def makeNet( self, controller ):
-      snames, hnames, dpnames = defaultNames()
-      n, m = self.n, self.m
-      hosts = []
-      switches = []
-      kernel = self.kernel
-      rows = []
-      if not self.linear:
-         lg.info("*** gridNet: creating", n, "x", m, "grid of switches")
-      for y in range( 0, m ):
-         row = []
-         for x in range( 0, n ):
-            dp = dpnames.next() if kernel else None
-            switch = Switch( snames.next(), dp )
-            if not kernel: createLink( switch, controller )
-            row.append( switch )
-            switches += [ switch ]
-            lg.info("%s " % switch.name)
-         rows += [ row ]
-      # Hook up rows
-      for row in rows:
-         previous = None
-         for switch in row:
-            if previous is not None:
-               createLink( switch, previous )
-            previous = switch
-         h1, h2 = Host( hnames.next() ), Host( hnames.next() )
-         createLink( h1, row[ 0 ] )
-         createLink( h2, row[ -1 ] )
-         hosts += [ h1, h2 ]
-         lg.info("%s %s" % (h1.name, h2.name))
-      # Return here if we're using this to make a linear network
-      if self.linear: return switches, hosts
-      # Hook up columns
-      for x in range( 0, n ):
-         previous = None
-         for y in range( 0, m ):
-            switch = rows[ y ][ x ]
-            if previous is not None:
-               createLink( switch, previous )
-            previous = switch
-         h1, h2 = Host( hnames.next() ), Host( hnames.next() )
-         createLink( h1, rows[ 0 ][ x ] )
-         createLink( h2, rows[ -1 ][ x ] )
-         hosts += [ h1, h2 ]
-         lg.info("%s %s" % (h1.name, h2.name))
-      return switches, hosts
-
-class LinearNet( GridNet ):
-   "A network consisting of two hosts connected by a string of switches."
-   def __init__( self, switchCount, **kwargs ):
-      self.switchCount = switchCount
-      GridNet.__init__( self, switchCount, 1, linear=True, **kwargs )
-      
-# Tests
-
-def parsePing( pingOutput ):
-   "Parse ping output and return packets sent, received."
-   r = r'(\d+) packets transmitted, (\d+) received'
-   m = re.search( r, pingOutput )
-   if m == None:
-      lg.error("*** Error: could not parse ping output: %s\n" % pingOutput)
-      exit( 1 )
-   sent, received  = int( m.group( 1 ) ), int( m.group( 2 ) )
-   return sent, received
-   
-def pingTest( controllers=[], switches=[], hosts=[], verbose=False ):
-   "Test that each host can reach every other host."
-   packets = 0 ; lost = 0
-   for node in hosts:
-      if verbose:
-         lg.info("%s -> " % node.name)
-      for dest in hosts: 
-         if node != dest:
-            result = node.cmd( 'ping -c1 ' + dest.IP() )
-            sent, received = parsePing( result )
-            packets += sent
-            if received > sent:
-               lg.error("*** Error: received too many packets")
-               lg.error("%s" % result)
-               node.cmdPrint( 'route' )
-               exit( 1 )
-            lost += sent - received
-            if verbose: 
-               lg.info(("%s " % dest.name) if received else "X ")
-      if verbose:
-          lg.info("\n")
-   ploss = 100 * lost/packets
-   if verbose:
-      lg.info("%d%% packet loss (%d/%d lost)\n" % ( ploss, lost, packets ))
-      flush()
-   return ploss
-
-def pingTestVerbose( controllers, switches, hosts ):
-   return "%d %% packet loss" % \
-      pingTest( controllers, switches, hosts, verbose=True )
- 
-def parseIperf( iperfOutput ):
-   "Parse iperf output and return bandwidth."
-   r = r'([\d\.]+ \w+/sec)'
-   m = re.search( r, iperfOutput )
-   return m.group( 1 ) if m is not None else "could not parse iperf output"
-    
-def iperf( hosts, verbose=False ):
-   "Run iperf between two hosts."
-   assert len( hosts ) == 2
-   host1, host2 = hosts[ 0 ], hosts[ 1 ]
-   host1.cmd( 'killall -9 iperf') # XXX shouldn't be global killall
-   server = host1.cmd( 'iperf -s &' )
-   if verbose:
-       lg.info("%s" % server)
-   client = host2.cmd( 'iperf -t 5 -c ' + host1.IP() )
-   if verbose:
-       lg.info("%s" % client)
-   server = host1.cmd( 'kill -9 %iperf' )
-   if verbose:
-       lg.info("%s" % server)
-   return [ parseIperf( server ), parseIperf( client ) ]
-   
-def iperfTest( controllers, switches, hosts, verbose=False ):
-   "Simple iperf test between two hosts."
-   if verbose: 
-       lg.info("*** Starting ping test\n")
-   h0, hN = hosts[ 0 ], hosts[ -1 ]
-   lg.info("*** iperfTest: Testing bandwidth between")
-   lg.info("%s and %s\n" % (h0.name, hN.name))
-   result = iperf( [ h0, hN], verbose )
-   lg.info("*** result: %s\n" % result)
-   return result
-
-# Simple CLI
-
-class Cli( object ):
-   "Simple command-line interface to talk to nodes."
-   cmds = [ '?', 'help', 'nodes', 'sh', 'pingtest', 'iperf', 'net', 'exit' ]
-   def __init__( self, controllers, switches, hosts ):
-      self.controllers = controllers
-      self.switches = switches
-      self.hosts = hosts
-      self.nodemap = {}
-      self.nodelist = controllers + switches + hosts
-      for node in self.nodelist:
-         self.nodemap[ node.name ] = node
-      self.run()
-   # Commands
-   def help( self, args ):
-      "Semi-useful help for CLI"
-      help_str = "Available commands are:" + str(self.cmds) + "\n" + \
-                 "You may also send a command to a node using:" + \
-                 "  <node> command {args}" + \
-                 "For example:" + \
-                 "  mininet> h0 ifconfig" + \
-                 "\n" + \
-                 "The interpreter automatically substitutes IP addresses" + \
-                 "for node names, so commands like" + \
-                 "  mininet> h0 ping -c1 h1" + \
-                 "should work." + \
-                 "\n" + \
-                 "Interactive commands are not really supported yet," + \
-                 "so please limit commands to ones that do not" + \
-                 "require user interaction and will terminate" + \
-                 "after a reasonable amount of time."
-      print(help_str)
-
-   def nodes( self, args ):
-      "List available nodes"
-      lg.info("available nodes are:\n", [ node.name for node in self.nodelist])
-   def sh( self, args ):
-      "Run an external shell command"
-      call( [ 'sh', '-c' ] + args )
-   def pingtest( self, args ):
-      pingTest( self.controllers, self.switches, self.hosts, verbose=True )
-   def net( self, args ):
-      for switch in self.switches:
-         lg.info("%s <-> ", switch.name)
-         for intf in switch.intfs:
-            node, remoteIntf = switch.connection[ intf ]
-            lg.info("%s" % node.name)
-   def iperf( self, args ):
-      if len( args ) != 2:
-         lg.error("usage: iperf <h1> <h2>")
-         return
-      for host in args:
-         if host not in self.nodemap:
-            lg.error("iperf: cannot find host: %s" % host)
-            return
-      iperf( [ self.nodemap[ h ] for h in args ], verbose=True )
-   # Interpreter
-   def run( self ):
-      "Read and execute commands."
-      lg.info("*** cli: starting\n")
-      while True:
-         lg.info("mininet> ")
-         input = sys.stdin.readline()
-         if input == '': break
-         if input[ -1 ] == '\n': input = input[ : -1 ]
-         cmd = input.split( ' ' )
-         first = cmd[ 0 ]
-         rest = cmd[ 1: ]
-         if first in self.cmds and hasattr( self, first ):
-            getattr( self, first )( rest )
-         elif first in self.nodemap and rest != []:
-            node = self.nodemap[ first ]
-            # Substitute IP addresses for node names in command
-            rest = [ self.nodemap[ arg ].IP() if arg in self.nodemap else arg
-               for arg in rest ]
-            rest = ' '.join( rest )
-            # Interactive commands don't work yet, and
-            # there are still issues with control-c
-            lg.error("*** %s: running %s\n" % (node.name, rest))
-            node.sendCmd( rest )
-            while True:
-               try:
-                  done, data = node.monitor()
-                  lg.info("%s\n" % data)
-                  if done: break
-               except KeyboardInterrupt: node.sendInt()
-         elif first == '': pass
-         elif first in [ 'exit', 'quit' ]: break
-         elif first == '?': self.help( rest )
-         else:
-            lg.error("cli: unknown node or command: < %s >\n" % first)
-      lg.info("*** cli: exiting\n")
+from mininet.node import Host, Controller, Switch, ControllerParams
+from mininet.topo import TreeTopo
+from mininet.util import quietRun, fixLimits
+from mininet.util import make_veth_pair, move_intf, retry, MOVEINTF_DELAY
+
+DATAPATHS = ['kernel'] #['user', 'kernel']
 
 
 def init():
-   "Initialize Mininet."
-   if os.getuid() != 0: 
-      # Note: this script must be run as root 
-      # Perhaps we should do so automatically!
-      print "*** Mininet must run as root."; exit( 1 )
-   # If which produces no output, then netns is not in the path.
-   # May want to loosen this to handle netns in the current dir.
-   if not quietRun( [ 'which', 'netns' ] ):
-       raise Exception( "Could not find netns; see INSTALL" )
-   fixLimits()
+    "Initialize Mininet."
+    if os.getuid() != 0:
+        # Note: this script must be run as root
+        # Perhaps we should do so automatically!
+        print "*** Mininet must run as root."
+        exit(1)
+    # If which produces no output, then netns is not in the path.
+    # May want to loosen this to handle netns in the current dir.
+    if not quietRun(['which', 'netns']):
+        raise Exception("Could not find netns; see INSTALL")
+    fixLimits()
+
+
+class Mininet(object):
+    '''Network emulation with hosts spawned in network namespaces.'''
+
+    def __init__(self, topo, switch, host, controller, cparams,
+                 build = True, xterms = False, cleanup = False,
+                 in_namespace = False, switch_is_kernel = True):
+        '''Create Mininet object.
+
+        @param topo Topo object
+        @param switch Switch class
+        @param host Host class
+        @param controller Controller class
+        @param cparams ControllerParams object
+        @param now build now?
+        @param xterms if build now, spawn xterms?
+        @param cleanup if build now, cleanup before creating?
+        @param in_namespace spawn switches and hosts in their own namespace?
+        '''
+        self.topo = topo
+        self.switch = switch
+        self.host = host
+        self.controller = controller
+        self.cparams = cparams
+        self.nodes = {} # dpid to Node{Host, Switch} objects
+        self.controllers = {} # controller name to Controller objects
+        self.dps = 0 # number of created kernel datapaths
+        self.in_namespace = in_namespace
+        self.switch_is_kernel = switch_is_kernel
+
+        self.kernel = True #temporary!
+
+        if build:
+            self.build(xterms, cleanup)
+
+    def _add_host(self, dpid):
+        '''Add host.
+
+        @param dpid DPID of host to add
+        '''
+        host = self.host('h_' + self.topo.name(dpid))
+        # for now, assume one interface per host.
+        host.intfs.append('h_' + self.topo.name(dpid) + '-eth0')
+        self.nodes[dpid] = host
+        #lg.info('%s ' % host.name)
+
+    def _add_switch(self, dpid):
+        '''
+        @param dpid DPID of switch to add
+        '''
+        sw = None
+        if self.switch_is_kernel:
+            sw = self.switch('s_' + self.topo.name(dpid), 'nl:' + str(self.dps))
+            self.dps += 1
+        else:
+            sw = self.switch('s_' + self.topo.name(dpid))
+        self.nodes[dpid] = sw
+
+    def _add_link(self, src, dst):
+        '''Add link.
+
+        @param src source DPID
+        @param dst destination DPID
+        '''
+        src_port, dst_port = self.topo.port(src, dst)
+        src_node = self.nodes[src]
+        dst_node = self.nodes[dst]
+        src_intf = src_node.intfName(src_port)
+        dst_intf = dst_node.intfName(dst_port)
+        make_veth_pair(src_intf, dst_intf)
+        src_node.intfs.append(src_intf)
+        dst_node.intfs.append(dst_intf)
+        #lg.info('\n')
+        #lg.info('added intf %s to src node %x\n' % (src_intf, src))
+        #lg.info('added intf %s to dst node %x\n' % (dst_intf, dst))
+        if src_node.inNamespace:
+            #lg.info('moving src w/inNamespace set\n')
+            retry(3, MOVEINTF_DELAY, move_intf, src_intf, src_node)
+        if dst_node.inNamespace:
+            #lg.info('moving dst w/inNamespace set\n')
+            retry(3, MOVEINTF_DELAY, move_intf, dst_intf, dst_node)
+        src_node.connection[src_intf] = (dst_node, dst_intf)
+        dst_node.connection[dst_intf] = (src_node, src_intf)
+
+    def _add_controller(self, controller):
+        '''Add controller.
+
+        @param controller Controller class
+        '''
+        controller = self.controller('c0', kernel = self.kernel)
+        self.controllers['c0'] = controller
+
+    # Control network support:
+    #
+    # Create an explicit control network. Currently this is only
+    # used by the user datapath configuration.
+    #
+    # Notes:
+    #
+    # 1. If the controller and switches are in the same (e.g. root)
+    #    namespace, they can just use the loopback connection.
+    #    We may wish to do this for the user datapath as well as the
+    #    kernel datapath.
+    #
+    # 2. If we can get unix domain sockets to work, we can use them
+    #    instead of an explicit control network.
+    #
+    # 3. Instead of routing, we could bridge or use 'in-band' control.
+    #
+    # 4. Even if we dispense with this in general, it could still be
+    #    useful for people who wish to simulate a separate control
+    #    network (since real networks may need one!)
+
+    def _configureControlNetwork(self):
+        '''Configure control network.'''
+        self._configureRoutedControlNetwork()
+
+    def _configureRoutedControlNetwork(self):
+        '''Configure a routed control network on controller and switches.
+
+        For use with the user datapath only right now.
+
+        @todo(brandonh) Test this code and verify that user-space works!
+        '''
+        # params were: controller, switches, ips
+
+        controller = self.controllers['c0']
+        lg.info('%s <-> ' % controller.name)
+        for switch_dpid in self.topo.switches():
+            switch = self.nodes[switch_dpid]
+            lg.info('%s ' % switch.name)
+            sip = self.topo.ip(switch_dpid)#ips.next()
+            sintf = switch.intfs[0]
+            node, cintf = switch.connection[sintf]
+            if node != controller:
+                lg.error('*** Error: switch %s not connected to correct'
+                         'controller' %
+                         switch.name)
+                exit(1)
+            controller.setIP(cintf, self.cparams.ip, '/' +
+                             self.cparams.subnet_size)
+            switch.setIP(sintf, sip, '/' + self.cparams.subnet_size)
+            controller.setHostRoute(sip, cintf)
+            switch.setHostRoute(self.cparams.ip, sintf)
+        lg.info('\n')
+        lg.info('*** Testing control network\n')
+        while not controller.intfIsUp(controller.intfs[0]):
+            lg.info('*** Waiting for %s to come up\n', controller.intfs[0])
+            sleep(1)
+        for switch_dpid in self.topo.switches():
+            switch = self.nodes[switch_dpid]
+            while not switch.intfIsUp(switch.intfs[0]):
+                lg.info('*** Waiting for %s to come up\n' % switch.intfs[0])
+                sleep(1)
+            if self.ping_test(hosts=[switch, controller]) != 0:
+                lg.error('*** Error: control network test failed\n')
+                exit(1)
+        lg.info('\n')
+
+    def _config_hosts( self ):
+        '''Configure a set of hosts.'''
+        # params were: hosts, ips
+        for host_dpid in self.topo.hosts():
+            host = self.nodes[host_dpid]
+            hintf = host.intfs[0]
+            host.setIP(hintf, self.topo.ip(host_dpid),
+                       '/' + str(self.cparams.subnet_size))
+            host.setDefaultRoute(hintf)
+            # You're low priority, dude!
+            quietRun('renice +18 -p ' + repr(host.pid))
+            lg.info('%s ', host.name)
+        lg.info('\n')
+
+    def build(self, xterms, cleanup):
+        '''Build mininet.
+
+        At the end of this function, everything should be connected and up.
+
+        @param xterms spawn xterms on build?
+        @param cleanup cleanup before creating?
+        '''
+        if cleanup:
+            pass # cleanup
+        # validate topo?
+        kernel = self.kernel
+        if kernel:
+            lg.info('*** Using kernel datapath\n')
+        else:
+            lg.info('*** Using user datapath\n')
+        lg.info('*** Adding controller\n')
+        self._add_controller(self.controller)
+        lg.info('*** Creating network\n')
+        lg.info('*** Adding hosts:\n')
+        for host in sorted(self.topo.hosts()):
+            self._add_host(host)
+            lg.info('0x%x ' % host)
+        lg.info('\n*** Adding switches:\n')
+        for switch in sorted(self.topo.switches()):
+            self._add_switch(switch)
+            lg.info('0x%x ' % switch)
+        lg.info('\n*** Adding edges: ')
+        for src, dst in sorted(self.topo.edges()):
+            self._add_link(src, dst)
+            lg.info('(0x%x, 0x%x) ' % (src, dst))
+        lg.info('\n')
+
+        if not kernel:
+            lg.info('*** Configuring control network\n')
+            self._configureControlNetwork()
+
+        lg.info('*** Configuring hosts\n')
+        self._config_hosts()
+
+        if xterms:
+            pass # build xterms
+
+    def start(self):
+        '''Start controller and switches\n'''
+        lg.info('*** Starting controller\n')
+        self.controllers['c0'].start()
+        #for controller in self.controllers:
+        #    controller.start()
+        lg.info('*** Starting %s switches\n' % len(self.topo.switches()))
+        for switch_dpid in self.topo.switches():
+            switch = self.nodes[switch_dpid]
+            #lg.info('switch = %s' % switch)
+            lg.info('0x%x ' % switch_dpid)
+            switch.start(self.controllers['c0'])
+        lg.info('\n')
+
+    def stop(self):
+        '''Stop the controller(s), switches and hosts\n'''
+        lg.info('*** Stopping %i hosts\n' % len(self.topo.hosts()))
+        for host_dpid in self.topo.hosts():
+            host = self.nodes[host_dpid]
+            lg.info('%s ' % host.name)
+            host.terminate()
+        lg.info('\n')
+        lg.info('*** Stopping %i switches\n' % len(self.topo.switches()))
+        for switch_dpid in self.topo.switches():
+            switch = self.nodes[switch_dpid]
+            lg.info('%s' % switch.name)
+            switch.stop()
+        lg.info('\n')
+        lg.info('*** Stopping controller\n')
+        #for controller in self.controllers.iteriterms():
+        self.controllers['c0'].stop()
+        lg.info('*** Test complete\n')
+
+    def run(self, test, **params):
+        '''Perform a complete start/test/stop cycle.'''
+        self.start()
+        lg.info('*** Running test\n')
+        result = test(self, **params)
+        self.stop()
+        return result
+
+    @staticmethod
+    def _parse_ping(pingOutput):
+        '''Parse ping output and return packets sent, received.'''
+        r = r'(\d+) packets transmitted, (\d+) received'
+        m = re.search( r, pingOutput )
+        if m == None:
+            lg.error('*** Error: could not parse ping output: %s\n' %
+                     pingOutput)
+            exit(1)
+        sent, received = int(m.group(1)), int(m.group(2))
+        return sent, received
+
+    def ping_test(self, hosts = None, verbose = False):
+        '''Ping between all specified hosts.
+
+        @param hosts list of host DPIDs
+        @param verbose verbose printing
+        @return ploss packet loss percentage
+        '''
+        #self.start()
+        # check if running - only then, start?
+        packets = 0
+        lost = 0
+        ploss = None
+        if not hosts:
+            hosts = self.topo.hosts()
+        for node_dpid in hosts:
+            node = self.nodes[node_dpid]
+            if verbose:
+                lg.info('%s -> ' % node.name)
+            for dest_dpid in hosts:
+                dest = self.nodes[dest_dpid]
+                if node != dest:
+                    result = node.cmd('ping -c1 ' + dest.IP())
+                    sent, received = self._parse_ping(result)
+                    packets += sent
+                    if received > sent:
+                        lg.error('*** Error: received too many packets')
+                        lg.error('%s' % result)
+                        node.cmdPrint('route')
+                        exit( 1 )
+                    lost += sent - received
+                    if verbose:
+                        lg.info(('%s ' % dest.name) if received else 'X ')
+            if verbose:
+                lg.info('\n')
+            ploss = 100 * lost / packets
+        if verbose:
+            lg.info('%d%% packet loss (%d/%d lost)\n' % (ploss, lost, packets))
+            #flush()
+        #self.stop()
+        return ploss
+
+    def interact(self):
+        '''Start network and run our simple CLI.'''
+        self.run(MininetCLI)
+
+
+class MininetCLI(object):
+    '''Simple command-line interface to talk to nodes.'''
+    cmds = ['?', 'help', 'nodes', 'net', 'sh', 'ping_all', 'exit', \
+            'ping_pair'] #'iperf'
+
+    def __init__(self, mininet):
+        self.mn = mininet
+        self.nodemap = {} # map names to Node objects
+        for node in self.mn.nodes.values():
+            self.nodemap[node.name] = node
+        self.nodemap['c0'] = self.mn.controllers['c0']
+        self.nodelist = self.nodemap.values()
+        self.run()
+
+    # Commands
+    def help(self, args):
+        '''Semi-useful help for CLI.'''
+        help_str = 'Available commands are:' + str(self.cmds) + '\n' + \
+                   'You may also send a command to a node using:\n' + \
+                   '  <node> command {args}\n' + \
+                   'For example:\n' + \
+                   '  mininet> h0 ifconfig\n' + \
+                   '\n' + \
+                   'The interpreter automatically substitutes IP ' + \
+                   'addresses\n' + \
+                   'for node names, so commands like\n' + \
+                   '  mininet> h0 ping -c1 h1\n' + \
+                   'should work.\n' + \
+                   '\n\n' + \
+                   'Interactive commands are not really supported yet,\n' + \
+                   'so please limit commands to ones that do not\n' + \
+                   'require user interaction and will terminate\n' + \
+                   'after a reasonable amount of time.\n'
+        print(help_str)
+
+    def nodes(self, args):
+        '''List all nodes.'''
+        lg.info('available nodes are: \n%s\n',
+                ' '.join([node.name for node in sorted(self.nodelist)]))
+
+    def net(self, args):
+        '''List network connection.'''
+        for switch_dpid in self.mn.topo.switches():
+            switch = self.mn.nodes[switch_dpid]
+            lg.info('%s <->', switch.name)
+            for intf in switch.intfs:
+                node, remoteIntf = switch.connection[intf]
+                lg.info(' %s' % node.name)
+            lg.info('\n')
+
+    def sh(self, args):
+        '''Run an external shell command'''
+        call( [ 'sh', '-c' ] + args )
+
+    def ping_all(self, args):
+        '''Ping between all hosts.'''
+        self.mn.ping_test(verbose = True)
+
+    def ping_pair(self, args):
+        '''Ping between first two hosts, useful for testing.'''
+        hosts_unsorted = sorted(self.mn.topo.hosts())
+        hosts = [hosts_unsorted[0], hosts_unsorted[1]]
+        self.mn.ping_test(hosts = hosts, verbose = True)
+
+    def run(self):
+        '''Read and execute commands.'''
+        lg.warn('*** Starting CLI:\n')
+        while True:
+            lg.warn('mininet> ')
+            input = sys.stdin.readline()
+            if input == '':
+                break
+            if input[-1] == '\n':
+                input = input[:-1]
+            cmd = input.split(' ')
+            first = cmd[0]
+            rest = cmd[1:]
+            if first in self.cmds and hasattr(self, first):
+                getattr(self, first)(rest)
+            elif first in self.nodemap and rest != []:
+                node = self.nodemap[first]
+                # Substitute IP addresses for node names in command
+                rest = [self.nodemap[arg].IP() if arg in self.nodemap else arg
+                        for arg in rest]
+                rest = ' '.join(rest)
+                # Interactive commands don't work yet, and
+                # there are still issues with control-c
+                lg.warn('*** %s: running %s\n' % (node.name, rest))
+                node.sendCmd(rest)
+                while True:
+                    try:
+                        done, data = node.monitor()
+                        lg.info('%s\n' % data)
+                        if done:
+                            break
+                    except KeyboardInterrupt:
+                        node.sendInt()
+            elif first == '':
+                pass
+            elif first in ['exit', 'quit']:
+                break
+            elif first == '?':
+                self.help( rest )
+            else:
+                lg.error('CLI: unknown node or command: < %s >\n' % first)
+            #lg.info('*** CLI: command complete\n')
+        return 'exited by user command'
+
 
 if __name__ == '__main__':
-   if len(sys.argv) > 1:
-      set_loglevel(sys.argv[1])
-   else:
-      set_loglevel('info')
-
-   init()
-   results = {}
-   lg.info("*** Welcome to Mininet!\n")
-   lg.info("*** Look in examples/ for more examples\n\n")
-   lg.info("*** Testing Mininet with kernel and user datapath\n")
-   for datapath in [ 'kernel', 'user' ]:
-      k = datapath == 'kernel'
-      network = TreeNet( depth=2, fanout=4, kernel=k)
-      result = network.run( pingTestVerbose )
-      results[ datapath ] = result
-   lg.info("*** Test results: %s\n", results)
\ No newline at end of file
+    if len(sys.argv) > 1:
+        set_loglevel(sys.argv[1])
+    else:
+        set_loglevel('info')
+
+    init()
+    results = {}
+    lg.info("*** Welcome to Mininet!\n")
+    lg.info("*** Look in examples/ for more examples\n\n")
+    lg.info("*** Testing Mininet with kernel and user datapath\n")
+    for datapath in DATAPATHS:
+        k = datapath == 'kernel'
+        controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
+        mn = Mininet(TreeTopo(), Switch, Host, Controller,
+                         controller_params)
+        mn.start()
+        dropped = mn.ping_test()
+        results[datapath] = "%i%% dropped" % dropped
+        mn.stop()
+
+    lg.info("*** Test results: %s\n", results)
\ No newline at end of file
diff --git a/mininet/node.py b/mininet/node.py
index 16f43bdb3cb7c3eb1c8105746fafee1c3196be23..d882f0613280f2fe7191a2a7e349dd0cd082ca17 100644
--- a/mininet/node.py
+++ b/mininet/node.py
@@ -335,4 +335,36 @@ def monitor(self):
         if not self.execed:
             return Node.monitor(self)
         else:
-            return True, ''
\ No newline at end of file
+            return True, ''
+
+
+class NOXController(Controller):
+    '''Controller to run a NOX application.'''
+    def __init__(self, name, nox_args = None, **kwargs):
+        '''Init.
+
+        @param name name to give controller
+        @param nox_args list of args to use with NOX
+        '''
+        if not nox_args:
+            nox_args = ['packetdump']
+        nox_core_dir = os.environ['NOX_CORE_DIR']
+        if not nox_core_dir:
+            raise Exception('please set NOX_CORE_DIR env var\n')
+        Controller.__init__(self, name,
+            controller = nox_core_dir + '/nox_core',
+            cargs = '--libdir=/usr/local/lib -v -i ptcp: ' + \
+                    ' '.join(nox_args),
+            cdir = nox_core_dir, **kwargs)
+
+
+class ControllerParams(object):
+    '''Container for controller IP parameters.'''
+    def __init__(self, ip, subnet_size):
+        '''Init.
+
+        @param ip integer, controller IP
+        @param subnet_size integer, ex 8 for slash-8, covering 17M
+        '''
+        self.ip = ip
+        self.subnet_size = subnet_size
\ No newline at end of file
diff --git a/mininet/test/test_nets.py b/mininet/test/test_nets.py
index 1696106128de3fc994bea6327059433e0ec1dec7..ed6570df08c582d6ef148a1f562300f1318cc5d3 100755
--- a/mininet/test/test_nets.py
+++ b/mininet/test/test_nets.py
@@ -7,7 +7,13 @@
 from time import sleep
 import unittest
 
-from mininet.net import init, TreeNet, LinearNet, pingTest, DATAPATHS
+from mininet.net import init, Mininet #, DATAPATHS
+from mininet.node import Switch, Host, NOXController, ControllerParams
+from mininet.node import Controller
+from mininet.topo import TreeTopo
+
+# temporary, until user-space side is tested
+DATAPATHS = ['kernel']
 
 class testMinimal(unittest.TestCase):
     '''For each datapath type, test ping with a minimal topology.
@@ -20,9 +26,13 @@ def testMinimal(self):
         init()
         for datapath in DATAPATHS:
             k = datapath == 'kernel'
-            network = TreeNet(depth = 1, fanout = 2, kernel = k)
-            dropped = network.run(pingTest)
+            controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
+            mn = Mininet(TreeTopo(), Switch, Host, Controller,
+                         controller_params)
+            mn.start()
+            dropped = mn.ping_test()
             self.assertEqual(dropped, 0)
+            mn.stop()
 
 
 class testTree(unittest.TestCase):
@@ -33,22 +43,26 @@ def testTree16(self):
         init()
         for datapath in DATAPATHS:
             k = datapath == 'kernel'
-            network = TreeNet(depth = 2, fanout = 4, kernel = k)
-            dropped = network.run(pingTest)
+            controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
+            tree_topo = TreeTopo(depth = 3, fanout = 4)
+            mn = Mininet(tree_topo, Switch, Host, Controller,
+                         controller_params)
+            mn.start()
+            dropped = mn.ping_test()
             self.assertEqual(dropped, 0)
+            mn.stop()
 
-
-class testLinear(unittest.TestCase):
-    '''For each datapath type, test all-pairs ping with LinearNet.'''
-
-    def testLinear10(self):
-        '''Ping test  with both datapaths on 10-switch topology'''
-        init()
-        for datapath in DATAPATHS:
-             k = datapath == 'kernel'
-             network = network = LinearNet(10, kernel=k)
-             dropped = network.run(pingTest)
-             self.assertEqual(dropped, 0)
+#class testLinear(unittest.TestCase):
+#    '''For each datapath type, test all-pairs ping with LinearNet.'''
+#
+#    def testLinear10(self):
+#        '''Ping test  with both datapaths on 10-switch topology'''
+#        init()
+#        for datapath in DATAPATHS:
+#             k = datapath == 'kernel'
+#             network = network = LinearNet(10, kernel=k)
+#             dropped = network.run(pingTest)
+#             self.assertEqual(dropped, 0)
 
 
 if __name__ == '__main__':
diff --git a/mininet/topo.py b/mininet/topo.py
new file mode 100644
index 0000000000000000000000000000000000000000..9417c6a261bb95b095c1a9bc13b76ca9f1e88543
--- /dev/null
+++ b/mininet/topo.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+'''Starter topologies for Mininet.'''
+
+from ripcord.topo import Topo, StructuredNodeSpec, StructuredNode, Edge
+from ripcord.topo import StructuredTopo, StructuredEdgeSpec, NodeID
+
+class TreeTopo(StructuredTopo):
+    '''Tree-structured network.'''
+
+    class TreeNodeID(NodeID):
+        '''Tree-specific node.'''
+
+        def __init__(self, layer = 0, index = 0, dpid = None):
+            '''Create TreeNodeID object from custom params.
+
+            Either (layer, index) or dpid must be passed in.
+
+            @param layer layer
+            @param index index within layer
+            @param dpid optional dpid
+            '''
+            if dpid:
+                self.layer = (dpid & 0xff0000) >> 16
+                self.index = (dpid & 0xffff)
+                self.dpid = dpid
+            else:
+                self.layer = layer
+                self.index = index
+                self.dpid = (layer << 16) + index
+
+        def __str__(self):
+            return "(%i_%i)" % (self.layer, self.index)
+
+        def name_str(self):
+            return "%i_%i" % (self.layer, self.index)
+
+        def ip_str(self):
+            # add 1; can't have IP addr ending in 0
+            index_hi = (self.index & 0xff00) >> 8
+            index_lo = self.index & 0xff
+            return "10.%i.%i.%i" % (self.layer, index_hi, index_lo)
+
+    def __init__(self, depth = 2, fanout = 2, speed = 1.0, enable_all = True):
+        '''Init.
+
+        @param depth number of levels, including host level
+        @param fanout
+        '''
+        node_specs = []
+        core = StructuredNodeSpec(0, fanout, None, speed, type_str = 'core')
+        node_specs.append(core)
+        for i in range(1, depth - 1):
+            node = StructuredNodeSpec(1, fanout, speed, speed,
+                                      type_str = 'layer' + str(i))
+            node_specs.append(node)
+        host = StructuredNodeSpec(1, 0, speed, None, type_str = 'host')
+        node_specs.append(host)
+        edge_specs = [StructuredEdgeSpec(speed)] * (depth - 1)
+        super(TreeTopo, self).__init__(node_specs, edge_specs)
+
+        self.depth = depth
+        self.fanout = fanout
+        self.id_gen = TreeTopo.TreeNodeID
+
+        # create root
+        root_id = self.id_gen(0, 0).dpid
+        self._add_node(root_id, StructuredNode(0))
+        last_layer_ids = [root_id]
+
+        # create lower layers
+        for i in range(1, depth):
+            current_layer_ids = []
+            # start index at 1, as we can't have IP addresses ending in 0
+            index = 1
+            for last_id in last_layer_ids:
+                for j in range(fanout):
+                    is_switch = (i < depth - 1)
+                    node = StructuredNode(i, is_switch = is_switch)
+                    node_id = self.id_gen(i, index).dpid
+                    current_layer_ids.append(node_id)
+                    self._add_node(node_id, node)
+                    self._add_edge(last_id, node_id, Edge())
+                    index += 1
+            last_layer_ids = current_layer_ids
+
+        if enable_all:
+            self.enable_all()
+
+    def port(self, src, dst):
+        '''Get port number (optional)
+
+        Note that the topological significance of DPIDs in FatTreeTopo enables
+        this function to be implemented statelessly.
+
+        @param src source switch DPID
+        @param dst destination switch DPID
+        @return tuple (src_port, dst_port):
+            src_port: port on source switch leading to the destination switch
+            dst_port: port on destination switch leading to the source switch
+        '''
+
+        src_layer = self.node_info[src].layer
+        dst_layer = self.node_info[dst].layer
+
+        src_id = self.id_gen(dpid = src)
+        dst_id = self.id_gen(dpid = dst)
+
+        lower = None
+        higher = None
+        if src_layer == dst_layer - 1: # src is higher
+            src_port = ((dst_id.index - 1) % self.fanout) + 1
+            dst_port = 0
+        elif dst_layer == src_layer - 1:
+            src_port = 0
+            dst_port = ((src_id.index - 1) % self.fanout) + 1
+        else:
+            raise Exception("Could not find port leading to given dst switch")
+
+        return (src_port, dst_port)
+
+    def name(self, dpid):
+        '''Get string name of node ID.
+
+        @param dpid DPID of host or switch
+        @return name_str string name with no dashes
+        '''
+        return self.id_gen(dpid = dpid).name_str()
+
+    def ip(self, dpid):
+        '''Get IP dotted-decimal string of node ID.
+
+        @param dpid DPID of host or switch
+        @return ip_str
+        '''
+        return self.id_gen(dpid = dpid).ip_str()
\ No newline at end of file