diff --git a/examples/ripcordtest.py b/examples/ripcordtest.py
index 41853b9a152a32da48e2dc7698aa3a788b41c105..3491851c313d4720167a44fd472f2976219791a6 100755
--- a/examples/ripcordtest.py
+++ b/examples/ripcordtest.py
@@ -13,7 +13,8 @@
 
 from ripcord.topo import FatTreeTopo
 
-from mininet.net import Switch, Controller, Host, init
+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
diff --git a/mininet/net.py b/mininet/net.py
index 4766a9bc52d58f5ab2ea7df1b7c8c7688a29ac84..c9f525e5be9c0ec450a3ed96f69a9abe4b7d4635 100755
--- a/mininet/net.py
+++ b/mininet/net.py
@@ -74,234 +74,12 @@
 from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
 
 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
 
 DATAPATHS = ['user', 'kernel']
 
-
-class Node( object ):
-   """A virtual network node is simply a shell in a network namespace.
-      We communicate with it using pipes."""
-   inToNode = {}
-   outToNode = {}
-   def __init__( self, name, inNamespace=True ):
-      self.name = name
-      closeFds = False # speed vs. memory use
-      # xpg_echo is needed so we can echo our sentinel in sendCmd
-      cmd = [ '/bin/bash', '-O', 'xpg_echo' ]
-      self.inNamespace = inNamespace
-      if self.inNamespace: cmd = [ 'netns' ] + cmd
-      self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
-         close_fds=closeFds )
-      self.stdin = self.shell.stdin
-      self.stdout = self.shell.stdout
-      self.pollOut = select.poll() 
-      self.pollOut.register( self.stdout )
-      # Maintain mapping between file descriptors and nodes
-      # This could be useful for monitoring multiple nodes
-      # using select.poll()
-      self.outToNode[ self.stdout.fileno() ] = self
-      self.inToNode[ self.stdin.fileno() ] = self
-      self.pid = self.shell.pid
-      self.intfCount = 0
-      self.intfs = [] # list of interface names, as strings
-      self.ips = {}
-      self.connection = {}
-      self.waiting = False
-      self.execed = False
-   def fdToNode( self, f ):
-      node = self.outToNode.get( f )
-      return node or self.inToNode.get( f )
-   def cleanup( self ):
-      # Help python collect its garbage
-      self.shell = None
-   # Subshell I/O, commands and control
-   def read( self, max ): return os.read( self.stdout.fileno(), max )
-   def write( self, data ): os.write( self.stdin.fileno(), data )
-   def terminate( self ):
-      os.kill( self.pid, signal.SIGKILL )
-      self.cleanup()
-   def stop( self ): self.terminate()
-   def waitReadable( self ): self.pollOut.poll()
-   def sendCmd( self, cmd ):
-      """Send a command, followed by a command to echo a sentinel,
-         and return without waiting for the command to complete."""
-      assert not self.waiting
-      if cmd[ -1 ] == '&':
-         separator = '&'
-         cmd = cmd[ : -1 ]
-      else: separator = ';'
-      if isinstance( cmd, list): cmd = ' '.join( cmd )
-      self.write( cmd + separator + " echo -n '\\0177' \n")
-      self.waiting = True
-   def monitor( self ):
-      "Monitor a command's output, returning (done, data)."
-      assert self.waiting
-      self.waitReadable()
-      data = self.read( 1024 )
-      if len( data ) > 0 and data[ -1 ] == chr( 0177 ):
-         self.waiting = False
-         return True, data[ : -1 ]
-      else:
-         return False, data
-   def sendInt( self ):
-      "Send ^C, hopefully interrupting a running subprocess."
-      self.write( chr( 3 ) )
-   def waitOutput( self ):
-      """Wait for a command to complete (signaled by a sentinel
-      character, ASCII(127) appearing in the output stream) and return
-      the output, including trailing newline."""
-      assert self.waiting
-      output = ""
-      while True:
-         self.waitReadable()
-         data = self.read( 1024 )
-         if len(data) > 0  and data[ -1 ] == chr( 0177 ): 
-            output += data[ : -1 ]
-            break
-         else: output += data
-      self.waiting = False
-      return output
-   def cmd( self, cmd ):
-      "Send a command, wait for output, and return it."
-      self.sendCmd( cmd )
-      return self.waitOutput()
-   def cmdPrint( self, cmd ):
-      "Call cmd, printing the command and output"
-      #lg.info("*** %s : %s", self.name, cmd)
-      result = self.cmd( cmd )
-      #lg.info("%s\n", result)
-      return result
-   # Interface management, configuration, and routing
-   def intfName( self, n):
-      "Construct a canonical interface name node-intf for interface N."
-      return self.name + '-eth' + `n`
-   def newIntf( self ):
-      "Reserve and return a new interface name for this node."
-      intfName = self.intfName( self.intfCount)
-      self.intfCount += 1
-      self.intfs += [ intfName ]
-      return intfName
-   def setIP( self, intf, ip, bits ):
-      "Set an interface's IP address."
-      result = self.cmd( [ 'ifconfig', intf, ip + bits, 'up' ] )
-      self.ips[ intf ] = ip
-      return result
-   def setHostRoute( self, ip, intf ):
-      "Add a route to the given IP address via intf."
-      return self.cmd( 'route add -host ' + ip + ' dev ' + intf )
-   def setDefaultRoute( self, intf ):
-      "Set the default route to go through intf."
-      self.cmd( 'ip route flush' )
-      return self.cmd( 'route add default ' + intf )
-   def IP( self ):
-      "Return IP address of first interface"
-      if len( self.intfs ) > 0:
-         return self.ips.get( self.intfs[ 0 ], None )
-   def intfIsUp( self, intf ):
-      "Check if one of our interfaces is up."
-      return 'UP' in self.cmd( 'ifconfig ' + self.intfs[ 0 ] )
-   # Other methods  
-   def __str__( self ): 
-      result = self.name + ":"
-      if self.IP():
-          result += " IP=" + self.IP()
-      result += " intfs=" + ','.join( self.intfs )
-      result += " waiting=" +  `self.waiting`
-      return result
-
-
-
-class Host( Node ):
-   """A host is simply a Node."""
-   pass
-      
-class Controller( Node ):
-   """A Controller is a Node that is running (or has execed) an 
-      OpenFlow controller."""
-   def __init__( self, name, kernel=True, controller='controller',
-      cargs='-v ptcp:', cdir=None ):
-      self.controller = controller
-      self.cargs = cargs
-      self.cdir = cdir
-      Node.__init__( self, name, inNamespace=( not kernel ) )
-   def start( self ):
-      "Start <controller> <args> on controller, logging to /tmp/cN.log"
-      cout = '/tmp/' + self.name + '.log'
-      if self.cdir is not None:
-         self.cmdPrint( 'cd ' + self.cdir )
-      self.cmdPrint( self.controller + ' ' + self.cargs + 
-         ' 1> ' + cout + ' 2> ' + cout + ' &' )
-      self.execed = False # XXX Until I fix it
-   def stop( self, controller='controller' ):
-      "Stop controller cprog on controller"
-      self.cmd( "kill %" + controller )  
-      self.terminate()
-         
-class Switch( Node ):
-   """A Switch is a Node that is running (or has execed)
-      an OpenFlow switch."""
-   def __init__( self, name, datapath=None ):
-      self.dp = datapath
-      Node.__init__( self, name, inNamespace=( datapath == None ) )
-   def startUserDatapath( self, controller ):
-      """Start OpenFlow reference user datapath, 
-         logging to /tmp/sN-{ofd,ofp}.log"""
-      ofdlog = '/tmp/' + self.name + '-ofd.log'
-      ofplog = '/tmp/' + self.name + '-ofp.log'
-      self.cmd( 'ifconfig lo up' )
-      intfs = self.intfs[ 1 : ] # 0 is mgmt interface
-      self.cmdPrint( 'ofdatapath -i ' + ','.join( intfs ) +
-       ' ptcp: 1> ' + ofdlog + ' 2> '+ ofdlog + ' &' )
-      self.cmdPrint( 'ofprotocol tcp:' + controller.IP() +
-         ' tcp:localhost --fail=closed 1> ' + ofplog + ' 2>' + ofplog + ' &' )
-   def stopUserDatapath( self ):
-      "Stop OpenFlow reference user datapath."
-      self.cmd( "kill %ofdatapath" )
-      self.cmd( "kill %ofprotocol" )
-   def startKernelDatapath( self, controller):
-      "Start up switch using OpenFlow reference kernel datapath."
-      ofplog = '/tmp/' + self.name + '-ofp.log'
-      quietRun( 'ifconfig lo up' )
-      # Delete local datapath if it exists;
-      # then create a new one monitoring the given interfaces
-      quietRun( 'dpctl deldp ' + self.dp )
-      self.cmdPrint( 'dpctl adddp ' + self.dp )
-      self.cmdPrint( 'dpctl addif ' + self.dp + ' ' + ' '.join( self.intfs ) )
-      # Run protocol daemon
-      self.cmdPrint( 'ofprotocol' +
-         ' ' + self.dp + ' tcp:127.0.0.1 ' + 
-         ' --fail=closed 1> ' + ofplog + ' 2>' + ofplog + ' &' )
-      self.execed = False # XXX until I fix it
-   def stopKernelDatapath( self ):
-      "Terminate a switch using OpenFlow reference kernel datapath."
-      quietRun( 'dpctl deldp ' + self.dp )
-      # In theory the interfaces should go away after we shut down.
-      # However, this takes time, so we're better off to remove them
-      # explicitly so that we won't get errors if we run before they
-      # have been removed by the kernel. Unfortunately this is very slow.
-      self.cmd( 'kill %ofprotocol')
-      for intf in self.intfs:
-         quietRun( 'ip link del ' + intf )
-         lg.info('.')
-   def start( self, controller ): 
-      if self.dp is None: self.startUserDatapath( controller )
-      else: self.startKernelDatapath( controller )
-   def stop( self ):
-      if self.dp is None: self.stopUserDatapath()
-      else: self.stopKernelDatapath()
-   def sendCmd( self, cmd ):
-      if not self.execed:
-          return Node.sendCmd( self, cmd )
-      else:
-          lg.error("*** Error: %s has execed and cannot accept commands" %
-                 self.name)
-   def monitor( self ):
-      if not self.execed: return Node.monitor( self )
-      else: return True, ''
-
-
 # Handy utilities
      
 def dumpNodes( nodes ):
@@ -367,11 +145,11 @@ def configureRoutedControlNetwork( controller, switches, ips):
       switch.setHostRoute( cip, sintf )
    lg.info("\n")
    lg.info("*** Testing control network\n")
-   while not controller.intfIsUp( controller.intfs[ 0 ] ):
+   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( switch.intfs[ 0 ] ):
+      while not switch.intfIsUp():
          lg.info("*** Waiting for %s to come up\n" % switch.intfs[ 0 ])
          sleep( 1 )
       if pingTest( hosts=[ switch, controller ] ) != 0:
diff --git a/mininet/node.py b/mininet/node.py
new file mode 100644
index 0000000000000000000000000000000000000000..16f43bdb3cb7c3eb1c8105746fafee1c3196be23
--- /dev/null
+++ b/mininet/node.py
@@ -0,0 +1,338 @@
+#!/usr/bin/env python
+'''Node objects for Mininet.'''
+
+from subprocess import Popen, PIPE, STDOUT
+import os, signal, sys, select
+flush = sys.stdout.flush
+
+from mininet.logging_mod import lg
+from mininet.util import quietRun
+
+class Node(object):
+    '''A virtual network node is simply a shell in a network namespace.
+       We communicate with it using pipes.'''
+    inToNode = {}
+    outToNode = {}
+
+    def __init__(self, name, inNamespace = True):
+        self.name = name
+        closeFds = False # speed vs. memory use
+        # xpg_echo is needed so we can echo our sentinel in sendCmd
+        cmd = ['/bin/bash', '-O', 'xpg_echo']
+        self.inNamespace = inNamespace
+        if self.inNamespace:
+            cmd = ['netns'] + cmd
+        self.shell = Popen(cmd, stdin = PIPE, stdout = PIPE, stderr = STDOUT,
+            close_fds = closeFds)
+        self.stdin = self.shell.stdin
+        self.stdout = self.shell.stdout
+        self.pollOut = select.poll()
+        self.pollOut.register(self.stdout)
+        # Maintain mapping between file descriptors and nodes
+        # This could be useful for monitoring multiple nodes
+        # using select.poll()
+        self.outToNode[self.stdout.fileno()] = self
+        self.inToNode[self.stdin.fileno()] = self
+        self.pid = self.shell.pid
+        self.intfCount = 0
+        self.intfs = [] # list of interface names, as strings
+        self.ips = {}
+        self.connection = {}
+        self.waiting = False
+        self.execed = False
+
+    def fdToNode(self, f):
+        '''Insert docstring.
+
+        @param f unknown
+        @return bool unknown
+        '''
+        node = self.outToNode.get(f)
+        return node or self.inToNode.get(f)
+
+    def cleanup(self):
+        '''Help python collect its garbage.'''
+        self.shell = None
+
+    # Subshell I/O, commands and control
+    def read(self, fileno_max):
+        '''Insert docstring.
+
+        @param fileno_max unknown
+        '''
+        return os.read(self.stdout.fileno(), fileno_max)
+
+    def write(self, data):
+        '''Write data to node.
+
+        @param data string
+        '''
+        os.write(self.stdin.fileno(), data)
+
+    def terminate(self):
+        '''Send kill signal to Node and cleanup after it.'''
+        os.kill(self.pid, signal.SIGKILL)
+        self.cleanup()
+
+    def stop(self):
+        '''Stop node.'''
+        self.terminate()
+
+    def waitReadable(self):
+        '''Poll on node.'''
+        self.pollOut.poll()
+
+    def sendCmd(self, cmd):
+        '''Send a command, followed by a command to echo a sentinel,
+           and return without waiting for the command to complete.'''
+        assert not self.waiting
+        if cmd[-1] == '&':
+            separator = '&'
+            cmd = cmd[:-1]
+        else:
+            separator = ';'
+        if isinstance(cmd, list):
+            cmd = ' '.join(cmd)
+        self.write(cmd + separator + ' echo -n "\\0177" \n')
+        self.waiting = True
+
+    def monitor(self):
+        '''Monitor the output of a command, returning (done, data).'''
+        assert self.waiting
+        self.waitReadable()
+        data = self.read(1024)
+        if len(data) > 0 and data[-1] == chr(0177):
+            self.waiting = False
+            return True, data[:-1]
+        else:
+            return False, data
+
+    def sendInt(self):
+        '''Send ^C, hopefully interrupting a running subprocess.'''
+        self.write(chr(3))
+
+    def waitOutput(self):
+        '''Wait for a command to complete.
+        
+        Completion is signaled by a sentinel character, ASCII(127) appearing in
+        the output stream.  Wait for the sentinel and return the output,
+        including trailing newline.
+        '''
+        assert self.waiting
+        output = ''
+        while True:
+            self.waitReadable()
+            data = self.read(1024)
+            if len(data) > 0  and data[-1] == chr(0177):
+                output += data[:-1]
+                break
+            else: output += data
+        self.waiting = False
+        return output
+
+    def cmd(self, cmd):
+        '''Send a command, wait for output, and return it.
+
+        @param cmd string
+        '''
+        self.sendCmd(cmd)
+        return self.waitOutput()
+
+    def cmdPrint(self, cmd):
+        '''Call cmd and printing its output
+        
+        @param cmd string
+        '''
+        #lg.info('*** %s : %s', self.name, cmd)
+        result = self.cmd(cmd)
+        #lg.info('%s\n', result)
+        return result
+
+    # Interface management, configuration, and routing
+    def intfName(self, n):
+        '''Construct a canonical interface name node-intf for interface N.'''
+        return self.name + '-eth' + repr(n)
+
+    def newIntf(self):
+        '''Reserve and return a new interface name.'''
+        intfName = self.intfName(self.intfCount)
+        self.intfCount += 1
+        self.intfs += [intfName]
+        return intfName
+
+    def setIP(self, intf, ip, bits):
+        '''Set the IP address for an interface.
+
+        @param intf string, interface name
+        @param ip IP address as integer
+        @param bits
+        '''
+        result = self.cmd(['ifconfig', intf, ip + bits, 'up'])
+        self.ips[intf] = ip
+        return result
+
+    def setHostRoute(self, ip, intf):
+        '''Add route to host.
+
+        @param ip IP address as dotted decimal
+        @param intf string, interface name
+        '''
+        return self.cmd('route add -host ' + ip + ' dev ' + intf)
+
+    def setDefaultRoute(self, intf):
+        '''Set the default route to go through intf.
+
+        @param intf string, interface name
+        '''
+        self.cmd('ip route flush')
+        return self.cmd('route add default ' + intf)
+
+    def IP(self):
+        '''Return IP address of first interface'''
+        if len(self.intfs) > 0:
+            return self.ips.get(self.intfs[ 0 ], None)
+
+    def intfIsUp(self):
+        '''Check if one of our interfaces is up.'''
+        return 'UP' in self.cmd('ifconfig ' + self.intfs[0])
+
+    # Other methods
+    def __str__(self):
+        result = self.name + ':'
+        if self.IP():
+            result += ' IP=' + self.IP()
+        result += ' intfs=' + ','.join(self.intfs)
+        result += ' waiting=' + repr(self.waiting)
+        return result
+
+
+class Host(Node):
+    '''A host is simply a Node.'''
+    pass
+
+
+class Controller(Node):
+    '''A Controller is a Node that is running (or has execed) an
+      OpenFlow controller.'''
+
+    def __init__(self, name, kernel=True, controller='controller',
+                 cargs='-v ptcp:', cdir=None):
+        self.controller = controller
+        self.cargs = cargs
+        self.cdir = cdir
+        Node.__init__(self, name, inNamespace=(not kernel))
+
+    def start(self):
+        '''Start <controller> <args> on controller.
+
+        Log to /tmp/cN.log
+        '''
+        cout = '/tmp/' + self.name + '.log'
+        if self.cdir is not None:
+            self.cmdPrint('cd ' + self.cdir)
+        self.cmdPrint(self.controller + ' ' + self.cargs +
+            ' 1> ' + cout + ' 2> ' + cout + ' &')
+        self.execed = False # XXX Until I fix it
+
+    def stop(self):
+        '''Stop controller.'''
+        self.cmd('kill %' + self.controller)
+        self.terminate()
+
+
+class Switch(Node):
+    '''A Switch is a Node that is running (or has execed)
+       an OpenFlow switch.'''
+
+    def __init__(self, name, datapath = None):
+        '''Init.
+
+        @param name
+        @param datapath string, datapath name
+        '''
+        self.dp = datapath
+        Node.__init__(self, name, inNamespace = (datapath == None))
+
+    def _startUserDatapath(self, controller):
+        '''Start OpenFlow reference user datapath.
+
+        Log to /tmp/sN-{ofd,ofp}.log.
+
+        @param controller Controller object.
+        '''
+        ofdlog = '/tmp/' + self.name + '-ofd.log'
+        ofplog = '/tmp/' + self.name + '-ofp.log'
+        self.cmd('ifconfig lo up')
+        intfs = self.intfs[1:] # 0 is mgmt interface
+        self.cmdPrint('ofdatapath -i ' + ','.join(intfs) +
+                      ' ptcp: 1> ' + ofdlog + ' 2> ' + ofdlog + ' &')
+        self.cmdPrint('ofprotocol tcp:' + controller.IP() +
+                      ' tcp:localhost --fail=closed 1> ' + ofplog + ' 2>' +
+                      ofplog + ' &')
+
+    def _stopUserDatapath(self):
+        '''Stop OpenFlow reference user datapath.'''
+        self.cmd('kill %ofdatapath')
+        self.cmd('kill %ofprotocol')
+
+    def _startKernelDatapath(self):
+        '''Start up reference kernel datapath.'''
+        ofplog = '/tmp/' + self.name + '-ofp.log'
+        quietRun('ifconfig lo up')
+        # Delete local datapath if it exists;
+        # then create a new one monitoring the given interfaces
+        quietRun('dpctl deldp ' + self.dp)
+        self.cmdPrint('dpctl adddp ' + self.dp)
+        self.cmdPrint('dpctl addif ' + self.dp + ' ' + ' '.join(self.intfs))
+        # Run protocol daemon
+        self.cmdPrint('ofprotocol' +
+                      ' ' + self.dp + ' tcp:127.0.0.1 ' +
+                      ' --fail=closed 1> ' + ofplog + ' 2>' + ofplog + ' &')
+        self.execed = False # XXX until I fix it
+
+    def _stopKernelDatapath(self):
+        '''Terminate reference kernel datapath.'''
+        quietRun('dpctl deldp ' + self.dp)
+        # In theory the interfaces should go away after we shut down.
+        # However, this takes time, so we're better off to remove them
+        # explicitly so that we won't get errors if we run before they
+        # have been removed by the kernel. Unfortunately this is very slow.
+        self.cmd('kill %ofprotocol')
+        for intf in self.intfs:
+            quietRun('ip link del ' + intf)
+            lg.info('.')
+
+    def start(self, controller):
+        '''Start datapath.
+
+        @param controller Controller object
+        '''
+        if self.dp is None:
+            self._startUserDatapath(controller)
+        else:
+            self._startKernelDatapath()
+
+    def stop(self):
+        '''Stop datapath.'''
+        if self.dp is None:
+            self._stopUserDatapath()
+        else:
+            self._stopKernelDatapath()
+
+    def sendCmd(self, cmd):
+        '''Send command to Node.
+
+        @param cmd string
+        '''
+        if not self.execed:
+            return Node.sendCmd(self, cmd)
+        else:
+            lg.error('*** Error: %s has execed and cannot accept commands' %
+                     self.name)
+
+    def monitor(self):
+        '''Monitor node.'''
+        if not self.execed:
+            return Node.monitor(self)
+        else:
+            return True, ''
\ No newline at end of file