From 2f5349134304141d68b4ad365100c1d7e9cbe336 Mon Sep 17 00:00:00 2001
From: Bob Lantz <rlantz@cs.stanford.edu>
Date: Mon, 14 Dec 2009 20:14:44 -0800
Subject: [PATCH] First crack at allowing Controller to be customized. Network
 may now be used with custom controllers. An example of doing this is in
 nox.py, which instantiates at TreeNet using a custom Controller,
 NoxController, that runs nox_core rather than the reference controller.

---
 INSTALL                 |  2 ++
 cleanup                 |  3 +++
 examples/nox.py         | 42 ++++++++----------------------
 examples/sshd.py        |  1 +
 examples/treenet1024.py | 15 -----------
 examples/treeping64.py  |  4 +--
 mininet.py              | 57 ++++++++++++++++++++++++++---------------
 7 files changed, 54 insertions(+), 70 deletions(-)
 delete mode 100755 examples/treenet1024.py

diff --git a/INSTALL b/INSTALL
index 2f2ce4d7..c8b99309 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,6 +1,8 @@
 Preliminary Mininet Installation/Configuration Notes
 ---
 
+- This is not (yet) a 'release'; things may be broken.
+
 - Mininet is not currently 'installed.' If you want to install it,
   so that you can 'import mininet', place it somewhere in your
   python path.
diff --git a/cleanup b/cleanup
index 75b0577f..a93a208d 100755
--- a/cleanup
+++ b/cleanup
@@ -24,6 +24,9 @@ ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/' | xargs -l1 echo dpctl deldp
 echo "Removing junk in /tmp"
 rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log
 
+echo "Killing nox"
+killall lt-nox_core
+
 echo "Removing old screen sessions"
 screen -ls | egrep -o '[0-9]+\.[hsc][0-9]+' | sed 's/\.[hsc][0-9]*//g' | kill -9
 
diff --git a/examples/nox.py b/examples/nox.py
index 493714b6..84a34960 100755
--- a/examples/nox.py
+++ b/examples/nox.py
@@ -1,39 +1,17 @@
 #!/usr/bin/python
 
-"Create a network from scratch and use NOX as the controller."
+"Instantiate a Tree network and use NOX as the controller."
 
-from mininet import init, Controller, Switch, Host, createLink
+import time
+from mininet import init, Controller, TreeNet, Cli
 
-def scratchNet( cname='controller', cargs='ptcp:'):
-   # Create Network
-   controller = Node( 'c0', inNamespace=False )
-   switch = Node( 's0', inNamespace=False )
-   h0 = Node( 'h0' )
-   h1 = Node( 'h1' )
-   createLink( h0, switch )
-   createLink( h1, switch )
-   # Configure hosts
-   h0.setIP( h0.intfs[ 0 ], '192.168.123.1', '/24' )
-   h1.setIP( h1.intfs[ 0 ], '192.168.123.2', '/24' )
-   # Start network using kernel datapath
-   controller.cmdPrint( cname + ' ' + cargs + '&' )
-   switch.cmdPrint( 'dpctl deldp nl:0' )
-   switch.cmdPrint( 'dpctl adddp nl:0' )
-   for intf in switch.intfs:
-      switch.cmdPrint( 'dpctl addif nl:0 ' + intf )
-   switch.cmdPrint( 'ofprotocol nl:0 tcp:localhost &')
-   # Run test
-   h0.cmdPrint( 'ping -c1 ' + h1.IP() )
-   # Stop network
-   controller.cmdPrint( 'kill %' + cname)
-   switch.cmdPrint( 'dpctl deldp nl:0' )
-   switch.cmdPrint( 'kill %ofprotocol' )
-   switch.stop()
-   controller.stop()
+class NoxController( Controller ):
+   def __init__( self, name, **kwargs ):
+      Controller.__init__( self, name, 
+         controller='nox_core', cargs='-i ptcp pyswitch', 
+         cdir='/usr/local/bin', **kwargs)
    
 if __name__ == '__main__':
    init()   
-   scratchNet( cname='nox_core', cargs='-i ptcp:' )
-
-
-
+   network = TreeNet( depth=2, fanout=4, kernel=True, Controller=NoxController)
+   network.run( Cli )
diff --git a/examples/sshd.py b/examples/sshd.py
index 0df92314..af455f2f 100755
--- a/examples/sshd.py
+++ b/examples/sshd.py
@@ -7,6 +7,7 @@
 (and perfectly adequate on an in-machine network)
 the advantage of running sshd is that scripts can work
 unchanged on mininet and hardware.
+
 """
 
 import sys ; readline = sys.stdin.readline
diff --git a/examples/treenet1024.py b/examples/treenet1024.py
deleted file mode 100755
index 3c96770e..00000000
--- a/examples/treenet1024.py
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/python
-
-"""
-Create a 1024-host network, and run the CLI on it.
-If this fails because of kernel limits, you may have
-to adjust them, e.g. by adding entries to /etc/sysctl.conf
-and running sysctl -p.
-"""
-   
-from mininet import init, TreeNet
-
-if __name__ == '__main__':
-   init()
-   network = TreeNet( depth=2, fanout=32, kernel=True )
-   network.run( Cli )
diff --git a/examples/treeping64.py b/examples/treeping64.py
index e8062b22..5405ef1a 100755
--- a/examples/treeping64.py
+++ b/examples/treeping64.py
@@ -6,9 +6,9 @@
 
 def treePing64():
    results = {}
-   datapaths = [ 'kernel', 'user' ]
+   datapaths = [ 'user', 'kernel' ]
    
-   print "*** Testing Mininet with kernel and user datapaths"
+   print "*** Testing Mininet with user and kernel datapaths"
    
    for datapath in datapaths:
       k = datapath == 'kernel'
diff --git a/mininet.py b/mininet.py
index 2921eed3..31d6c200 100755
--- a/mininet.py
+++ b/mininet.py
@@ -242,12 +242,18 @@ class Host( Node ):
 class Controller( Node ):
    """A Controller is a Node that is running (or has execed) an 
       OpenFlow controller."""
-   def __init__( self, name, kernel=True ):
+   def __init__( self, name, kernel=True, controller='controller',
+      cargs='ptcp:', cdir=None ):
+      self.controller = controller
+      self.cargs = cargs
+      self.cdir = cdir
       Node.__init__( self, name, inNamespace=( not kernel ) )
-   def start( self, controller='controller', args='ptcp:' ):
+   def start( self ):
       "Start <controller> <args> on controller, logging to /tmp/cN.log"
       cout = '/tmp/' + self.name + '.log'
-      self.cmdPrint( controller + ' ' + args + 
+      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' ):
@@ -394,10 +400,10 @@ def nameGen( prefix ):
 # Note: Instead of routing, we could bridge or use "in-band" control
    
 def configRoutedControlNetwork( controller, switches, 
-   startAddr=( 10, 123, 0, 1 ) ):
+   ipGen=ipGen, ipStart=( 10, 123, 0, 1 ) ):
    """Configure a routed control network on controller and switches,
       for use with the user datapath."""
-   ips = apply( ipGen, startAddr )
+   ips = ipGen( ipStart )
    cip = ips.next()
    print controller.name, '<->',
    for switch in switches:
@@ -426,9 +432,8 @@ def configRoutedControlNetwork( controller, switches,
       print "*** Error: control network test failed"
       exit( 1 )
 
-def configHosts( hosts, ( a, b, c, d ) ):
+def configHosts( hosts, ips ):
    "Configure a set of hosts, starting at IP address a.b.c.d"
-   ips = ipGen( a, b, c, d )
    for host in hosts:
       hintf = host.intfs[ 0 ]
       host.setIP( hintf, ips.next(), '/24' )
@@ -442,8 +447,15 @@ def configHosts( hosts, ( a, b, c, d ) ):
 
 class Network( object ):
    "Network topology (and test driver) base class."
-   def __init__( self, kernel=True, startAddr=( 192, 168, 123, 1) ):
-      self.kernel, self.startAddr = kernel, startAddr
+   def __init__( self,
+      kernel=True, 
+      Controller=Controller, Switch=Switch, 
+      hostIpGen=ipGen, hostIpStart=( 192, 168, 123, 1 ) ):
+      print "NETWORK: Controller=", Controller
+      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:
@@ -456,6 +468,11 @@ def __init__( self, kernel=True, startAddr=( 192, 168, 123, 1) ):
          exit( 1 )
       # Create network, but don't start things up yet!
       self.prepareNet()
+   def configureControlNetwork( self ):
+      configureRoutedControlNetwork( self.controllers[ 0 ],
+         self.switches)
+   def configHosts( self ):
+      configHosts( self.hosts, self.hostIps )
    def prepareNet( self ):
       """Create a network by calling makeNet as follows: 
          (switches, hosts ) = makeNet()
@@ -464,21 +481,19 @@ def prepareNet( self ):
       if kernel: print "*** Using kernel datapath"
       else: print "*** Using user datapath"
       print "*** Creating controller"
-      controller = Controller( 'c0', kernel )
+      self.controller = self.Controller( 'c0', kernel=kernel )
+      self.controllers = [ self.controller ]
       print "*** Creating network"
-      switches, hosts = self.makeNet( controller )
+      self.switches, self.hosts = self.makeNet( self.controller )
       print
       if not kernel:
          print "*** Configuring control network"
-         configRoutedControlNetwork( controller, switches )
+         self.configureControlNetwork()
       print "*** Configuring hosts"
-      configHosts( hosts, self.startAddr )
-      self.controllers = [ controller ]
-      self.switches = switches
-      self.hosts = hosts
+      self.configHosts()
    def start( self ):
       "Start controller and switches"
-      print "*** Starting reference controller"
+      print "*** Starting controller"
       for controller in self.controllers:
          controller.start()
       print "*** Starting", len( self.switches ), "switches"
@@ -524,9 +539,9 @@ def defaultNames( snames=None, hnames=None, dpnames=None ):
 
 class TreeNet( Network ):
    "A tree-structured network with the specified depth and fanout"
-   def __init__( self, depth, fanout, kernel=True):
+   def __init__( self, depth, fanout, **kwargs):
       self.depth, self.fanout = depth, fanout
-      Network.__init__( self, kernel )
+      Network.__init__( self, **kwargs )
    def treeNet( self, controller, depth, fanout, kernel=True, snames=None,
       hnames=None, dpnames=None ):
       """Return a tree network of the given depth and fanout as a triple:
@@ -563,9 +578,9 @@ 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, kernel=True, linear=False ):
+   def __init__( self, n, m, kernel=True, linear=False, **kwargs ):
       self.n, self.m, self.linear = n, m, linear and m == 1
-      Network.__init__( self, kernel )
+      Network.__init__( self, kernel, **kwargs )
    def makeNet( self, controller ):
       snames, hnames, dpnames = defaultNames()
       n, m = self.n, self.m
-- 
GitLab