diff --git a/INSTALL b/INSTALL index dd735cd..57046f2 100644 --- a/INSTALL +++ b/INSTALL @@ -1,31 +1,71 @@ Preliminary Mininet Installation/Configuration Notes -Alpha release, March 2010 - +Pre-Beta version, August 2010 --- -(Disclaimer: this is an early alpha release; things may be broken!) +(Disclaimer: we're still pre-beta - things may be broken!) -The easiest way to get Mininet running is to start with one of our pre-built virtual machine images from: +The supported installation methods for Mininet Pre-Beta are 1) using +a pre-built VM image, and 2) native installation on Ubuntu or Debian. +(Other distributions may be supported in the future - if you would +like to contribute an installation script, we would welcome it!) -http://www.openflowswitch.org/foswiki/bin/view/OpenFlow/MininetGettingStarted +1. Easiest "install" - use our pre-built VM image! -Once you have booted up the VM image, all you need to do to install -Mininet into it is: +The easiest way to get Mininet running is to start with one of our pre-built +virtual machine images from: - git clone git://yuba.stanford.edu/mininet.git - cd mininet - sudo make install + http://openflow.org/foswiki/bin/view/OpenFlow/MininetGettingStarted -At this point, it should be possible to run a simple Mininet configuration -from the command line: +Boot up the VM image, log in, and follow the instructions on the wiki page. - sudo mn +An additional advantage of using the VM image is that it doesn't mess with +your native OS install or damage it in any way. -As an alternative, if you are Linux-savvy, do not wish to use the VM -image, and wish to take on the challenge of installing Mininet and its -dependencies from scratch, the requirements are described below. +2. Native installation for Ubuntu and Debian 5 (NEW for pre-beta!) + +If you are running Ubuntu or Debian 5, you may be able to use our handy +install.sh script, which is in mininet/util. + +WARNING: install.sh is a bit intrusive and may possibly damage your OS +and/or home directory. Although we hope it won't do anything completely +terrible, you may want to look at the script before you run it, and you +should make sure your system and home directory are backed up just in case! + +To install ALL of the software which we use for OpenFlow tutorials, you may +use + +$ mininet/util/install.sh + +This takes about 20-30 minutes. + +Alternately, you can install just the pieces you need. + +We recommend the following steps, in order: + +a) On Debian 5, first install a Mininet-compatible kernel: + $ mininet/util/install.sh -k + Reboot and run 'uname -r' to make sure you're running the new kernel. + +b) Install mininet and its dependencies: + $ mininet/util/install.sh -n + +c) Install OpenFlow 1.0 and associated useful software + $ mininet/util/install.sh -f + +d) Install Open vSwitch and its kernel module + $ mininet/util/install.sh -vm + +e) If you wish to install the version of NOX we use in the tutorial: + $ mininet/util/install.sh -x + +Good luck! Some additional installation notes are provided below, for +the brave and/or Linux-savvy, or those who are trying to understand what +is installed and why. + +p.s. Note that only one instance of Mininet is currently supported on a single +machine - that's one reason we recommend using a VM to run it. --- @@ -36,47 +76,94 @@ compile kernels, apply patches, configure networks, write code, etc.. If this is unfamiliar territory, or if you run into trouble, we recommend using one of our pre-built virtual machine images (see above.) +If you wish to try to create a VM to run Mininet, you may also wish +to look at the Wiki page: + +http://openflow.org/foswiki/bin/view/OpenFlow/MininetVMCreationNotes + +0. Obtaining Mininet + + If you're reading this, you've already done it, but the command to + download mininet is: + + git clone git://openflow.org/mininet.git + 1. Core Mininet installation The core Mininet installation requires gcc, make, python, - and setuptools. + and setuptools. On Ubuntu and Debian you may install them with: + + # aptitude install gcc make python setuptools To install Mininet itself, with root privileges: - + + # cd mininet # make install - This places the mininet package in /usr/lib/python-2.5/site-packages/, + This places the mininet package in /usr/lib/python-*/site-packages/, so that 'import mininet' will work, and installs the primary mn script (mn) as well as its helper utility (mnexec.) + + On Ubuntu and Debian, Mininet's dependencies and core files may also be + installed using mininet/util/install.sh -n -2. Script-based kernel and OpenFlow installation for Debian +2. Installation script for Ubuntu/Debian Lenny - If you are running debian-stable, you may be able to use the + If you are running Ubuntu 10.04 or Debian Lenny, you may be able to use the util/install.sh script to install a compatible Linux kernel as well as other software including the OpenFlow reference implementation, the Open - vSwitch switch implementation, and the NOX OpenFlow controller. Assuming - the mininet source tree is installed in ~/mininet, the steps to run - install.sh are as follows: + vSwitch switch implementation, and the NOX OpenFlow controller. + Many different installation options are possible by passing different + options to install.sh; install.sh -h lists them all. + + Assuming the mininet source tree is installed in ~/mininet, the steps to run + install.sh to install EVERYTHING we use for OpenFlow tutorials are: + % cd - % time ~/mininet/util/install.sh + % time ~/mininet/util/install.sh # installs tons of stuff % sudo reboot # to load new kernel % ~/mininet/util/install.sh -c # to clean out unneeded kernel stuff - If install.sh cannot be used for some reason, the kernel and - OpenFlow software requirements are descibed in steps [3] and [4], + This installs a lot of useful software, but it will take a while (30 + minutes or more, depending on your network connection, computer, etc..) + + Probably the minimal semi-useful configuration would be to install + Mininet itself, kernel support if necessary, and either the + reference OpenFlow switch or Open vSwitch. This could be installed + as follows: + + % sudo ~/mininet/util/install.sh -knvm + + Respectively, this installs kernel support, core mininet dependencies, + Open vSwitch, and the Open vSwitch kernel module. If a new kernel was + installed, then a reboot may be required. + + If install.sh cannot be used for some reason (e.g. you're on Fedora + or some other Linux - please don't say CentOS) or if you don't want to + install all of these components (they're useful!), the kernel and + OpenFlow software requirements are described in steps [3] and [4], which follow. - If you successfully used install.sh, proceed to step [5]. - + If you successfully used install.sh, congratulations! You're basically + done. Proceed to step [6] for additional advice. + 3. Linux Kernel requirements Mininet requires a kernel built with network namespace support enabled, - i.e. with CONFIG_NET_NS=Y + i.e. with CONFIG_NET_NS=Y, such as the kernel shipped with + Ubuntu 10.04 LTS, currently 2.6.32. On Ubuntu 10.04, you should not need + to install or build a custom kernel, although 2.6.33+ is faster at + tearing down virtual ethernet pairs. + + For Ubuntu and Debian, we provide a 2.6.33 kernel package which you may be + able to install using "util/install.sh -k". Note our kernel package + requires an ext2 or ext3 root file system, so it won't work if you have + a default Ubuntu install, which uses ext4. - If your kernel doesn't support it, you will need to build and install a - kernel that does! >= 2.6.33 works better, but may be harder to get - working, depending on your Linux distribution. + If your kernel wasn't compiled with CONFIG_NET_NS=Y, you will need to + build and install a kernel that does! >= 2.6.33 works better, but may + be harder to get working, depending on your Linux distribution. A script for building Debian packages for 2.6.33.1 is provided in mininet/util/kbuild. You may wish to read it, as it applies patches @@ -102,23 +189,19 @@ using one of our pre-built virtual machine images (see above.) Mininet requires either the reference OpenFlow switch implementation (from openflowswitch.org) or Open vSwitch (openvswitch.org) to be - installed. "make test" requires the reference user and kernel space - implementations as well as Open vSwitch. Note the kernel implementation - is not currently included in OpenFlow 1.0. - - To switch to the most recent OpenFlow 0.8.9 release branch (the most - recent one with full NOX support and kernel datapath support) in your - OpenFlow git tree: - - git checkout -b release/0.8.9 remotes/origin/release/0.8.9 + installed. "make test" requires the reference user space + implementations as well as Open vSwitch. Note the reference kernel + implementation is not currently included in OpenFlow 1.0. - A patch to enable datapath.c to compile with recent kernels - is included in util/openflow-patches/datapath.patch. + On Ubuntu and Debian, the install.sh script may be used with the '-f' + option to install the OpenFlow reference implementation, the '-v' option + to build Open vSwitch, and the '-m' option to install the Open vSwitch + kernel module into /lib/modules (note: you must build Open vSwitch first!) Mininet will automatically load and remove kernel module dependencies for supported switch types, using modprobe and rmmod - but these - modules must be in a location where modprobe can find them (i.e. - /lib/modules/...) + modules must be in a location where modprobe can find them (e.g. + something like /lib/modules/`uname -r`/kernel/drivers/net/) The reference OpenFlow controller (controller(8)) only supports 16 switches by default! If you wish to run a network with more than 16 @@ -128,6 +211,9 @@ using one of our pre-built virtual machine images (see above.) 5. Other software dependencies + On Ubuntu and Debian, other Mininet dependencies may be installed using + the '-n' option of the install.sh script. + To run the iperf test, you need to install iperf: sudo aptitude/yum install iperf @@ -141,8 +227,14 @@ using one of our pre-built virtual machine images (see above.) Some examples may have additional requirements - consult the specific example file for details. + The install.sh script has an '-x' option to install the version of + NOX from the OpenFlow tutorial. + 6. Other notes and recommendations + If you did not install certain useful packages and you wish to later, + it may be possible to install them using install.sh. + Mininet should be run either on a machine with no other important processes, or on a virtual machine (recommended!) @@ -151,3 +243,26 @@ using one of our pre-built virtual machine images (see above.) Good luck! --- + +Historical information on OpenFlow 0.8.9 and the reference kernel module: + + The kernel reference implementation has been deprecated, but it may + be possible to get it work with Mininet. + + To switch to the most recent OpenFlow 0.8.9 release branch (the most + recent one with full NOX support and kernel datapath support) in your + OpenFlow git tree: + + git checkout -b release/0.8.9 remotes/origin/release/0.8.9 + + A patch to enable datapath.c to compile with recent kernels + is included in util/openflow-patches/datapath.patch. + + In OpenFlow 1.0, switch port numbering starts at 1 (for better or for worse.) + To run with previous versions of OpenFlow, it may be necessary + to change SWITCH_PORT_BASE from 1 to 0 in node.py. + + + + + diff --git a/bin/mn b/bin/mn index 9e50cbf..98d4a83 100755 --- a/bin/mn +++ b/bin/mn @@ -55,7 +55,7 @@ TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp', 'none' ] ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair', - 'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp' } + 'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' } def buildTopo( topo ): "Create topology from string with format (object, arg1, arg2,...)." @@ -176,11 +176,25 @@ class MininetRunner( object ): ' controller]' ) opts.add_option( '--innamespace', action='store_true', default=False, help='sw and ctrl in namespace?' ) +<<<<<<< HEAD:bin/mn +======= + opts.add_option( '--listenport', type='int', default=6634, + help='[base port for passive switch listening' + ' controller]' ) + opts.add_option( '--nolistenport', action='store_true', + default=False, help="don't use passive listening port") +>>>>>>> of1.0:bin/mn opts.add_option( '--pre', type='string', default=None, help='[CLI script to run before tests]' ) opts.add_option( '--post', type='string', default=None, help='[CLI script to run after tests]' ) +<<<<<<< HEAD:bin/mn +======= + opts.add_option( '--prefixlen', type='int', default=8, + help='[prefix length (e.g. /8) for automatic ' + 'network configuration]' ) +>>>>>>> of1.0:bin/mn self.options, self.args = opts.parse_args() def setup( self ): @@ -217,15 +231,31 @@ class MininetRunner( object ): if self.validate: self.validate( self.options ) +<<<<<<< HEAD:bin/mn controllerParams = ControllerParams( '10.0.0.0', 8 ) +======= + # We should clarify what this is actually for... + # It seems like it should be default values for the + # *data* network, so it may be misnamed. + controllerParams = ControllerParams( '10.0.0.0', + self.options.prefixlen) + +>>>>>>> of1.0:bin/mn inNamespace = self.options.innamespace xterms = self.options.xterms mac = self.options.mac arp = self.options.arp + listenPort = None + if not self.options.nolistenport: + listenPort = self.options.listenport mn = Mininet( topo, switch, host, controller, controllerParams, inNamespace=inNamespace, xterms=xterms, autoSetMacs=mac, +<<<<<<< HEAD:bin/mn autoStaticArp=arp ) +======= + autoStaticArp=arp, listenPort=listenPort ) +>>>>>>> of1.0:bin/mn if self.options.pre: CLI( mn, script=self.options.pre ) diff --git a/examples/baresshd.py b/examples/baresshd.py new file mode 100755 index 0000000..841454a --- /dev/null +++ b/examples/baresshd.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +"This example doesn't use OpenFlow, but attempts to run sshd in a namespace." + +from mininet.node import Host + +print "*** Creating nodes" +h1 = Host( 'h1' ) +root = Host( 'root', inNamespace=False ) + +print "*** Creating links" +h1.linkTo( root ) + +print "*** Configuring nodes" +h1.setIP( h1.intfs[ 0 ], '10.0.0.1', 8 ) +root.setIP( root.intfs[ 0 ], '10.0.0.2', 8 ) + +print "*** Creating banner file" +f = open( '/tmp/%s.banner' % h1.name, 'w' ) +f.write( 'Welcome to %s at %s\n' % ( h1.name, h1.IP() ) ) +f.close() + +print "*** Running sshd" +h1.cmd( '/usr/sbin/sshd -o "Banner /tmp/%s.banner"' % h1.name ) + +print "*** You may now ssh into", h1.name, "at", h1.IP() diff --git a/examples/consoles.py b/examples/consoles.py index 54fb32c..607163d 100755 --- a/examples/consoles.py +++ b/examples/consoles.py @@ -448,8 +448,7 @@ class ConsoleApp( Frame ): def assign( obj, **kwargs ): "Set a bunch of fields in an object." - for name, value in kwargs.items(): - setattr( obj, name, value ) + obj.__dict__.update( kwargs ) class Object( object ): "Generic object you can stuff junk into." diff --git a/examples/controllers.py b/examples/controllers.py new file mode 100755 index 0000000..6eeef0e --- /dev/null +++ b/examples/controllers.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +""" +This example creates a multi-controller network from +semi-scratch; note a topo object could also be used and +would be passed into the Mininet() constructor. +""" + +from mininet.net import Mininet +from mininet.node import Controller, OVSKernelSwitch +from mininet.cli import CLI +from mininet.log import setLogLevel + +Switch = OVSKernelSwitch + +def addHost( net, N ): + "Create host hN and add to net." + name = 'h%d' % N + ip = '10.0.0.%d' % N + return net.addHost( name, ip=ip ) + +def multiControllerNet(): + "Create a network with multiple controllers." + + net = Mininet( controller=Controller, switch=Switch) + + print "*** Creating controllers" + c1 = net.addController( 'c1', port=6633 ) + c2 = net.addController( 'c2', port=6634 ) + + print "*** Creating switches" + s1 = net.addSwitch( 's1' ) + s2 = net.addSwitch( 's2' ) + + print "*** Creating hosts" + hosts1 = [ addHost( net, n ) for n in 3, 4 ] + hosts2 = [ addHost( net, n ) for n in 5, 6 ] + + print "*** Creating links" + for h in hosts1: + s1.linkTo( h ) + for h in hosts2: + s2.linkTo( h ) + s1.linkTo( s2 ) + + print "*** Starting network" + net.build() + c1.start() + c2.start() + s1.start( [ c1 ] ) + s2.start( [ c2 ] ) + + print "*** Testing network" + net.pingAll() + + print "*** Running CLI" + CLI( net ) + + print "*** Stopping network" + net.stop() + +if __name__ == '__main__': + setLogLevel( 'info' ) # for CLI output + multiControllerNet() diff --git a/mininet/cli.py b/mininet/cli.py index a884316..3fbedd1 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -272,6 +272,20 @@ class CLI( Cmd ): error( 'error reading file %s\n' % args[ 0 ] ) self.inputFile = None + def do_dpctl( self, line ): + "Run dpctl command on all switches." + args = line.split() + if len(args) == 0: + error( 'usage: dpctl command [arg1] [arg2] ...\n' ) + return + if not self.mn.listenPort: + error( "can't run dpctl w/no passive listening port\n") + return + for sw in self.mn.switches: + output( '*** ' + sw.name + ' ' + ('-' * 72) + '\n' ) + output( sw.cmd( 'dpctl ' + ' '.join(args) + + ' tcp:127.0.0.1:%i' % sw.listenPort ) ) + def default( self, line ): """Called on an input line when the command prefix is not recognized. Overridden to run shell commands when a node is the first CLI argument. @@ -314,7 +328,8 @@ class CLI( Cmd ): while True: try: bothPoller.poll() - if self.inputFile: + # XXX BL: this doesn't quite do what we want. + if False and self.inputFile: key = self.inputFile.read( 1 ) if key is not '': node.write(key) diff --git a/mininet/moduledeps.py b/mininet/moduledeps.py index f954e03..15b575d 100644 --- a/mininet/moduledeps.py +++ b/mininet/moduledeps.py @@ -37,7 +37,7 @@ def moduleDeps( subtract=None, add=None ): info( '*** Removing ' + mod + '\n' ) rmmodOutput = rmmod( mod ) if rmmodOutput: - error( 'Error removing ' + mod + '\n%s' % rmmodOutput ) + error( 'Error removing ' + mod + ': "%s">\n' % rmmodOutput ) exit( 1 ) if mod in lsmod(): error( 'Failed to remove ' + mod + '; still there!\n' ) @@ -47,20 +47,22 @@ def moduleDeps( subtract=None, add=None ): info( '*** Loading ' + mod + '\n' ) modprobeOutput = modprobe( mod ) if modprobeOutput: - error( 'Error inserting ' + mod + ';\n See INSTALL.\n%s' % - modprobeOutput ) - exit( 1 ) + error( 'Error inserting ' + mod + + ' - is it installed and available via modprobe?\n' + + 'Error was: "%s"\n' % modprobeOutput ) if mod not in lsmod(): - error( 'Failed to insert ' + mod + '\n' ) + error( 'Failed to insert ' + mod + ' - quitting.\n' ) exit( 1 ) else: debug( '*** ' + mod + ' already loaded\n' ) -def pathCheck( *args ): + +def pathCheck( *args, **kwargs ): "Make sure each program in *args can be found in $PATH." + moduleName = kwargs.get( 'moduleName', 'it' ) for arg in args: if not quietRun( 'which ' + arg ): - error( 'Cannot find required executable %s -' - ' is it installed somewhere in your $PATH?\n(%s)\n' % - ( arg, environ[ 'PATH' ] ) ) + error( 'Cannot find required executable %s.\n' % arg + + 'Please make sure that %s is installed ' % moduleName + + 'and available in your $PATH:\n(%s)\n' % environ[ 'PATH' ] ) exit( 1 ) diff --git a/mininet/net.py b/mininet/net.py index 5f1bb44..bf25330 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -94,7 +94,7 @@ from time import sleep from mininet.cli import CLI from mininet.log import info, error, debug, output -from mininet.node import Host, UserSwitch, KernelSwitch, Controller +from mininet.node import Host, UserSwitch, OVSKernelSwitch, Controller from mininet.node import ControllerParams from mininet.util import quietRun, fixLimits from mininet.util import createLink, macColonHex, ipStr, ipParse @@ -103,12 +103,12 @@ from mininet.term import cleanUpScreens, makeTerms class Mininet( object ): "Network emulation with hosts spawned in network namespaces." - def __init__( self, topo=None, switch=KernelSwitch, host=Host, + def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host, controller=Controller, cparams=ControllerParams( '10.0.0.0', 8 ), build=True, xterms=False, cleanup=False, inNamespace=False, - autoSetMacs=False, autoStaticArp=False ): + autoSetMacs=False, autoStaticArp=False, listenPort=None ): """Create Mininet object. topo: Topo (topology) object or None switch: Switch class @@ -120,7 +120,9 @@ class Mininet( object ): cleanup: if build now, cleanup before creating? inNamespace: spawn switches and controller in net namespaces? autoSetMacs: set MAC addrs from topo? - autoStaticArp: set all-pairs static MAC addrs?""" + autoStaticArp: set all-pairs static MAC addrs? + listenPort: base listening port to open; will be incremented for + each additional switch in the net if inNamespace=False""" self.switch = switch self.host = host self.controller = controller @@ -131,6 +133,7 @@ class Mininet( object ): self.cleanup = cleanup self.autoSetMacs = autoSetMacs self.autoStaticArp = autoStaticArp + self.listenPort = listenPort self.hosts = [] self.switches = [] @@ -162,25 +165,32 @@ class Mininet( object ): """Add switch. name: name of switch to add mac: default MAC address for kernel/OVS switch intf 0 - returns: added switch""" + returns: added switch + side effect: increments the listenPort member variable.""" if self.switch == UserSwitch: - sw = self.switch( name, defaultMAC=mac, defaultIP=ip, - inNamespace=self.inNamespace ) + sw = self.switch( name, listenPort=self.listenPort, + defaultMAC=mac, defaultIP=ip, inNamespace=self.inNamespace ) else: - sw = self.switch( name, defaultMAC=mac, defaultIP=ip, dp=self.dps, + sw = self.switch( name, listenPort=self.listenPort, + defaultMAC=mac, defaultIP=ip, dp=self.dps, inNamespace=self.inNamespace ) + if not self.inNamespace and self.listenPort: + self.listenPort += 1 self.dps += 1 self.switches.append( sw ) self.nameToNode[ name ] = sw return sw - def addController( self, name='c0', **kwargs ): + def addController( self, name='c0', controller=None, **kwargs ): """Add controller. controller: Controller class""" - controller_new = self.controller( name, **kwargs ) + if not controller: + controller = self.controller + controller_new = controller( name, **kwargs ) if controller_new: # allow controller-less setups self.controllers.append( controller_new ) self.nameToNode[ name ] = controller_new + return controller_new # Control network support: # diff --git a/mininet/node.py b/mininet/node.py index ad94ad6..6a69119 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -200,7 +200,6 @@ class Node( object ): """Monitor and return the output of a command. Set self.waiting to False if command has completed. timeoutms: timeout in ms or None to wait indefinitely.""" - assert self.waiting self.waitReadable( timeoutms ) data = self.read( 1024 ) # Look for PID @@ -434,9 +433,19 @@ class Switch( Node ): portBase = SWITCH_PORT_BASE # 0 for OF < 1.0, 1 for OF >= 1.0 - def __init__( self, name, opts='', **kwargs): + def __init__( self, name, opts='', listenPort=None, **kwargs): Node.__init__( self, name, **kwargs ) self.opts = opts + self.listenPort = listenPort + if self.listenPort: + self.opts += ' --listen=ptcp:%i ' % self.listenPort + + def defaultIntf( self ): + "Return interface for HIGHEST port" + ports = self.intfs.keys() + if ports: + intf = self.intfs[ max( ports ) ] + return intf def sendCmd( self, *cmd, **kwargs ): """Send command to Node. @@ -455,12 +464,15 @@ class UserSwitch( Switch ): """Init. name: name for the switch""" Switch.__init__( self, name, **kwargs ) - pathCheck( 'ofdatapath', 'ofprotocol' ) + pathCheck( 'ofdatapath', 'ofprotocol', + moduleName='the OpenFlow reference user switch (openflow.org)' ) + @staticmethod def setup(): "Ensure any dependencies are loaded; if not, try to load them." - moduleDeps( add=TUN ) + if not os.path.exists( '/dev/net/tun' ): + moduleDeps( add=TUN ) def start( self, controllers ): """Start OpenFlow reference user datapath. @@ -478,7 +490,7 @@ class UserSwitch( Switch ): if self.inNamespace: intfs = intfs[ :-1 ] self.cmd( 'ofdatapath -i ' + ','.join( intfs ) + - ' punix:/tmp/' + self.name + mac_str + + ' punix:/tmp/' + self.name + mac_str + ' --no-slicing ' + ' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' ) self.cmd( 'ofprotocol unix:/tmp/' + self.name + ' tcp:%s:%d' % ( controller.IP(), controller.port ) + @@ -511,8 +523,10 @@ class KernelSwitch( Switch ): @staticmethod def setup(): "Ensure any dependencies are loaded; if not, try to load them." - moduleDeps( subtract = OVS_KMOD, add = OF_KMOD ) - pathCheck( 'ofprotocol' ) + pathCheck( 'ofprotocol', + moduleName='the OpenFlow reference kernel switch' + ' (openflow.org) (NOTE: not available in OpenFlow 1.0!)' ) + moduleDeps( subtract=OVS_KMOD, add=OF_KMOD ) def start( self, controllers ): "Start up reference kernel datapath." @@ -559,14 +573,15 @@ class OVSKernelSwitch( Switch ): self.intf = self.dp if self.inNamespace: error( "OVSKernelSwitch currently only works" - " in the root namespace." ) + " in the root namespace.\n" ) exit( 1 ) @staticmethod def setup(): "Ensure any dependencies are loaded; if not, try to load them." - moduleDeps( subtract = OF_KMOD, add = OVS_KMOD ) - pathCheck( 'ovs-dpctl', 'ovs-openflowd' ) + pathCheck( 'ovs-dpctl', 'ovs-openflowd', + moduleName='Open vSwitch (openvswitch.org)') + moduleDeps( subtract=OF_KMOD, add=OVS_KMOD ) def start( self, controllers ): "Start up kernel datapath." @@ -607,10 +622,10 @@ class Controller( Node ): """A Controller is a Node that is running (or has execed?) an OpenFlow controller.""" - def __init__( self, name, inNamespace=False, controller='controller', - cargs='-v ptcp:', cdir=None, defaultIP="127.0.0.1", + def __init__( self, name, inNamespace=False, command='controller', + cargs='-v ptcp:%d', cdir=None, defaultIP="127.0.0.1", port=6633 ): - self.controller = controller + self.command = command self.cargs = cargs self.cdir = cdir self.port = port @@ -620,17 +635,17 @@ class Controller( Node ): def start( self ): """Start on controller. Log to /tmp/cN.log""" - pathCheck( self.controller ) + pathCheck( self.command ) cout = '/tmp/' + self.name + '.log' if self.cdir is not None: self.cmd( 'cd ' + self.cdir ) - self.cmd( self.controller + ' ' + self.cargs + + self.cmd( self.command + ' ' + self.cargs % self.port + ' 1>' + cout + ' 2>' + cout + '&' ) self.execed = False def stop( self ): "Stop controller." - self.cmd( 'kill %' + self.controller ) + self.cmd( 'kill %' + self.command ) self.terminate() def IP( self, intf=None ): @@ -668,8 +683,8 @@ class NOX( Controller ): noxCoreDir = os.environ[ 'NOX_CORE_DIR' ] Controller.__init__( self, name, - controller=noxCoreDir + '/nox_core', - cargs='--libdir=/usr/local/lib -v -i ptcp: ' + + command=noxCoreDir + '/nox_core', + cargs='--libdir=/usr/local/lib -v -i ptcp:%s ' % self.port + ' '.join( noxArgs ), cdir=noxCoreDir, **kwargs ) diff --git a/util/install.sh b/util/install.sh index dd84f84..b2a85de 100755 --- a/util/install.sh +++ b/util/install.sh @@ -4,24 +4,43 @@ # Fail on error set -e - + # Fail on unset var usage set -o nounset # Location of CONFIG_NET_NS-enabled kernel(s) -KERNEL_LOC=http://www.stanford.edu/~brandonh +KERNEL_LOC=http://www.openflow.org/downloads/mininet + +test -e /etc/debian_version && DIST="Debian" +grep Ubuntu /etc/lsb-release &> /dev/null && DIST="Ubuntu" # Kernel params # These kernels have been tried: +<<<<<<< HEAD:util/install.sh KERNEL_NAME=2.6.33.1-mininet #KERNEL_NAME=`uname -r` KERNEL_HEADERS=linux-headers-${KERNEL_NAME}_${KERNEL_NAME}-10.00.Custom_i386.deb KERNEL_IMAGE=linux-image-${KERNEL_NAME}_${KERNEL_NAME}-10.00.Custom_i386.deb +======= +if [ "$DIST" = "Debian" ]; then + KERNEL_NAME=2.6.33.1-mininet + KERNEL_HEADERS=linux-headers-${KERNEL_NAME}_${KERNEL_NAME}-10.00.Custom_i386.deb + KERNEL_IMAGE=linux-image-${KERNEL_NAME}_${KERNEL_NAME}-10.00.Custom_i386.deb +elif [ "$DIST" = "Ubuntu" ]; then + KERNEL_NAME=`uname -r` + KERNEL_HEADERS=linux-headers-${KERNEL_NAME} +else + echo "Install.sh currently only supports Ubuntu and Debian." + exit 1 +fi + +echo "Detected Linux distribution: $DIST" +>>>>>>> of1.0:util/install.sh # Kernel Deb pkg to be removed: KERNEL_IMAGE_OLD=linux-image-2.6.26-2-686 -DRIVERS_DIR=/lib/modules/${KERNEL_NAME}/kernel/drivers +DRIVERS_DIR=/lib/modules/${KERNEL_NAME}/kernel/drivers/net #OVS_RELEASE=openvswitch-1.0.1 OVS_RELEASE=openvswitch # release 1.0.1 doesn't work with veth pairs. @@ -29,12 +48,14 @@ OVS_DIR=~/$OVS_RELEASE OVS_KMOD=openvswitch_mod.ko function kernel { - echo "Install new kernel..." + echo "Install Mininet-compatible kernel" sudo apt-get update - + + if [ "$DIST" = "Debian" ]; then + # The easy approach: download pre-built linux-image and linux-headers packages: - wget $KERNEL_LOC/$KERNEL_HEADERS - wget $KERNEL_LOC/$KERNEL_IMAGE + wget -c $KERNEL_LOC/$KERNEL_HEADERS + wget -c $KERNEL_LOC/$KERNEL_IMAGE #Install custom linux headers and image: sudo dpkg -i $KERNEL_IMAGE $KERNEL_HEADERS @@ -51,6 +72,8 @@ function kernel { sudo update-grub # The default should be the new kernel. Otherwise, you may need to modify /boot/grub/menu.lst to set the default to the entry corresponding to the kernel you just installed. + fi + } function kernel_clean { @@ -65,14 +88,20 @@ function kernel_clean { # Install Mininet deps function mn_deps { - #Install dependencies: - sudo apt-get install -y screen psmisc xterm ssh iperf iproute python-setuptools + echo "Installing Mininet dependencies" + sudo aptitude install -y gcc make screen psmisc xterm ssh iperf iproute \ + python-setuptools python-networkx #Add sysctl parameters as noted in the INSTALL file to increase kernel limits to support larger setups: - sudo su -c "cat /home/mininet/mininet/util/sysctl_addon >> /etc/sysctl.conf" + sudo su -c "cat $HOME/mininet/util/sysctl_addon >> /etc/sysctl.conf" #Load new sysctl settings: sudo sysctl -p + + echo "Installing Mininet core" + pushd ~/mininet + sudo make install + popd } # The following will cause a full OF install, covering: @@ -109,7 +138,12 @@ function of { sudo apt-get remove -y avahi-daemon # Disable IPv6. Add to /etc/modprobe.d/blacklist: - sudo sh -c "echo -e 'blacklist net-pf-10\nblacklist ipv6' >> /etc/modprobe.d/blacklist" + if [ "$DIST" = "Ubuntu" ]; then + BLACKLIST=/etc/modprobe.d/blacklist.conf + else + BLACKLIST=/etc/modprobe.d/blacklist + fi + sudo sh -c "echo 'blacklist net-pf-10\nblacklist ipv6' >> $BLACKLIST" } # Install OpenVSwitch @@ -117,13 +151,23 @@ function of { function ovs { echo "Installing OpenVSwitch..." - #Install Autoconf 2.63+ backport from Debian Backports repo: - #Instructions from http://backports.org/dokuwiki/doku.php?id=instructions - sudo su -c "echo 'deb http://www.backports.org/debian lenny-backports main contrib non-free' >> /etc/apt/sources.list" - sudo apt-get update - sudo apt-get -y --force-yes install debian-backports-keyring - sudo apt-get -y --force-yes -t lenny-backports install autoconf + if [ "$DIST" = "Debian" ]; then + sudo aptitude -y install pkg-config gcc make git-core python-dev libssl-dev + #Install Autoconf 2.63+ backport from Debian Backports repo: + #Instructions from http://backports.org/dokuwiki/doku.php?id=instructions + sudo su -c "echo 'deb http://www.backports.org/debian lenny-backports main contrib non-free' >> /etc/apt/sources.list" + sudo apt-get update + sudo apt-get -y --force-yes install debian-backports-keyring + sudo apt-get -y --force-yes -t lenny-backports install autoconf + fi +<<<<<<< HEAD:util/install.sh +======= + if [ "$DIST" = "Ubuntu" ]; then + sudo apt-get -y install $KERNEL_HEADERS + fi + +>>>>>>> of1.0:util/install.sh #Install OVS from release cd ~/ #wget http://openvswitch.org/releases/${OVS_RELEASE}.tar.gz @@ -132,7 +176,17 @@ function ovs { git clone git://openvswitch.org/openvswitch cd $OVS_RELEASE ./boot.sh +<<<<<<< HEAD:util/install.sh ./configure --with-l26=/lib/modules/${KERNEL_NAME}/build +======= + BUILDDIR=/lib/modules/${KERNEL_NAME}/build + if [ ! -e $BUILDDIR ]; then + echo "Creating build directory $BUILDDIR" + sudo mkdir -p $BUILDDIR + fi + opts="--with-l26=$BUILDDIR" + ./configure $opts +>>>>>>> of1.0:util/install.sh make sudo make install } @@ -142,8 +196,14 @@ function nox { echo "Installing NOX w/tutorial files..." #Install NOX deps: - sudo apt-get -y install autoconf automake g++ libtool python python-twisted swig libboost1.35-dev libxerces-c2-dev libssl-dev make - + sudo apt-get -y install autoconf automake g++ libtool python python-twisted swig libxerces-c2-dev libssl-dev make + if [ "$DIST" = "Debian" ]; then + sudo apt-get -y install libboost1.35-dev + elif [ "$DIST" = "Ubuntu" ]; then + sudo apt-get -y install python-dev libboost-dev + sudo apt-get -y install libboost-filesystem-dev + sudo apt-get -y install libboost-test-dev + fi #Install NOX optional deps: sudo apt-get install -y libsqlite3-dev python-simplejson @@ -154,12 +214,19 @@ function nox { # With later autoconf versions this doesn't quite work: ./boot.sh --apps-core || true +<<<<<<< HEAD:util/install.sh # So use this instead: autoreconf --install --force +======= + if [ "$DIST" = "Debian" ]; then + # So use this instead: + autoreconf --install --force + fi +>>>>>>> of1.0:util/install.sh mkdir build cd build ../configure --with-python=yes - make + make #make check # Add NOX_CORE_DIR env var: @@ -194,7 +261,11 @@ function cbench { git clone git://www.openflow.org/oflops.git cd oflops sh boot.sh +<<<<<<< HEAD:util/install.sh ./configure --with-openflow-src-dir=/home/mininet/openflow +======= + ./configure --with-openflow-src-dir=$HOME/openflow +>>>>>>> of1.0:util/install.sh make sudo make install || true # make install fails; force past this } @@ -221,12 +292,23 @@ function other { git config --global color.branch auto #Reduce boot screen opt-out delay. Modify timeout in /boot/grub/menu.lst to 1: +<<<<<<< HEAD:util/install.sh sudo sed -i -e 's/^timeout.*$/timeout 1/' /boot/grub/menu.lst # Clean unneeded debs: rm -f ~/linux-headers-* ~/linux-image-* } +======= + if [ "$DIST" = "Debian" ]; then + sudo sed -i -e 's/^timeout.*$/timeout 1/' /boot/grub/menu.lst + fi + + # Clean unneeded debs: + rm -f ~/linux-headers-* ~/linux-image-* +} + +>>>>>>> of1.0:util/install.sh # Script to copy built OVS kernel module to where modprobe will # find them automatically. Removes the need to keep an environment variable # for insmod usage, and works nicely with multiple kernel versions. @@ -243,11 +325,14 @@ function modprobe { function all { echo "Running all commands..." - kernel + if [ "$DIST" != "Ubuntu" ]; then + # Ubuntu ships with Mininet-compatible kernel + kernel + fi mn_deps of ovs - modprobe + modprobe nox oftest cbench @@ -264,27 +349,58 @@ function vm_clean { sudo rm -rf openvswitch*.tar.gz # Remove sensistive files +<<<<<<< HEAD:util/install.sh history -c rm ~/.bash_history # history -c doesn't seem to work for some reason +======= + history -c # note this won't work if you have multiple bash sessions + rm -f ~/.bash_history # need to clear in memory and remove on disk +>>>>>>> of1.0:util/install.sh rm -f ~/.ssh/id_rsa* ~/.ssh/known_hosts - sudo rm ~/.ssh/authorized_keys2 + sudo rm -f ~/.ssh/authorized_keys2 # Remove Mininet files #sudo rm -f /lib/modules/python2.5/site-packages/mininet* #sudo rm -f /usr/bin/mnexec # Clear optional dev script for SSH keychain load on boot +<<<<<<< HEAD:util/install.sh rm ~/.bash_profile +======= + rm -f ~/.bash_profile +>>>>>>> of1.0:util/install.sh # Clear git changes git config --global user.name "None" git config --global user.email "None" - #sudo rm -rf ~/mininet + # Remove mininet install script + rm -f install-mininet.sh } function usage { - printf "Usage: %s: [-acdfhkmntvxy] args\n" $(basename $0) >&2 + printf 'Usage: %s [-acdfhkmntvxy]\n\n' $(basename $0) >&2 + + printf 'This install script attempts to install useful packages\n' >&2 + printf 'for Mininet. It should (hopefully) work on Ubuntu 10.04 and\n' >&2 + printf 'Debian 5.0 (Lenny). If you run into trouble, try\n' >&2 + printf 'installing one thing at a time, and looking at the \n' >&2 + printf 'specific installation function in this script.\n\n' >&2 + + printf 'options:\n' >&2 + printf -- ' -a: (default) install (A)ll packages - good luck!\n' >&2 + printf -- ' -c: (C)lean up after kernel install\n' >&2 + printf -- ' -d: (D)elete some sensitive files from a VM image\n' >&2 + printf -- ' -f: install open(F)low\n' >&2 + printf -- ' -h: print this (H)elp message\n' >&2 + printf -- ' -k: install new (K)ernel\n' >&2 + printf -- ' -m: install Open vSwitch kernel (M)odule\n' >&2 + printf -- ' -n: install mini(N)et dependencies + core files\n' >&2 + printf -- ' -t: install o(T)her stuff\n' >&2 + printf -- ' -v: install open (V)switch\n' >&2 + printf -- ' -x: install NO(X) OpenFlow controller\n' >&2 + printf -- ' -y: install (A)ll packages\n' >&2 + exit 2 } @@ -295,7 +411,7 @@ else while getopts 'acdfhkmntvx' OPTION do case $OPTION in - a) all;; + a) all;; c) kernel_clean;; d) vm_clean;; f) of;;