From b055728fd5662b49990bb903edfa279c3e9b86e9 Mon Sep 17 00:00:00 2001 From: Brandon Heller Date: Sun, 14 Mar 2010 03:51:11 -0700 Subject: [PATCH] Automatically load kernel module dependencies Before this commit, you'd have to manually insert the kernel module for OVS or OF kernel modules, and you couldn't run one regression test with all 3. Now, these are kmod insert/remove is handled automatically. --- INSTALL | 9 +++---- mininet/moduledeps.py | 54 +++++++++++++++++++++++++++++++++++++++ mininet/net.py | 2 ++ mininet/node.py | 16 ++++++++++++ mininet/test/test_nets.py | 5 +++- util/modprobe_setup.sh | 20 +++++++++++++++ 6 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 mininet/moduledeps.py create mode 100755 util/modprobe_setup.sh diff --git a/INSTALL b/INSTALL index a99ea17..a434f8c 100644 --- a/INSTALL +++ b/INSTALL @@ -47,12 +47,11 @@ Preliminary Mininet Installation/Configuration Notes To compile for Linux 2.6.33, you may need to apply the patch included below. - If you want to automatically load the kernel modules required - for OpenFlow, you could add something like the following to - /etc/rc.local: +- 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. - insmod /home/openflow/openflow/datapath/linux-2.6/ofdatapath.ko - modprobe tun + See ~/mininet/util/modprobe_setup.sh for an example. - The reference OpenFlow controller (controller(8)) only supports 16 switches by default! If you wish to run a network with more than 16 diff --git a/mininet/moduledeps.py b/mininet/moduledeps.py new file mode 100644 index 0000000..7cfe8e8 --- /dev/null +++ b/mininet/moduledeps.py @@ -0,0 +1,54 @@ +"Module dependency utility functions for Mininet." + +from mininet.util import quietRun +from mininet.log import info, error, debug + +def lsmod(): + "Return output of lsmod." + return quietRun( 'lsmod' ) + +def rmmod( mod ): + """Return output of lsmod. + mod: module string""" + return quietRun( [ 'rmmod', mod ] ) + +def modprobe( mod ): + """Return output of modprobe + mod: module string""" + return quietRun( [ 'modprobe', mod ] ) + +OF_KMOD = 'ofdatapath' +OVS_KMOD = 'openvswitch_mod' +TUN = 'tun' + +def moduleDeps( subtract = [], add = [] ): + """Handle module dependencies. + subtract: string or list of module names to remove, if already loaded + add: string or list of module names to add, if not already loaded""" + if type( subtract ) is str: + subtract = [ subtract ] + if type( add ) is str: + add = [ add ] + for mod in subtract: + if mod in lsmod(): + info( '*** Removing ' + mod + '\n' ) + rmmodOutput = rmmod( mod ) + if rmmodOutput: + error( 'Error removing ' + mod + '\n%s' % rmmodOutput ) + exit( 1 ) + if mod in lsmod(): + error( 'Failed to remove ' + mod + '; still there!\n' ) + exit( 1 ) + for mod in add: + if mod not in lsmod(): + info( '*** Loading ' + mod + '\n' ) + modprobeOutput = modprobe( mod ) + if modprobeOutput: + error( 'Error inserting ' + mod + ';\n See INSTALL.\n%s' % + modprobeOutput ) + exit( 1 ) + if mod not in lsmod(): + error( 'Failed to insert ' + mod + '\n' ) + exit( 1 ) + else: + debug( '*** ' + mod + ' already loaded\n' ) \ No newline at end of file diff --git a/mininet/net.py b/mininet/net.py index 0f37133..f732c36 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -151,6 +151,8 @@ class Mininet( object ): self.dps = 0 # number of created kernel datapaths self.terms = [] # list of spawned xterm processes + switch.setup() + if build: self.build() diff --git a/mininet/node.py b/mininet/node.py index 44c5faa..a3126cf 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -50,6 +50,7 @@ from time import sleep from mininet.log import info, error, debug from mininet.util import quietRun, makeIntfPair, moveIntf, isShellBuiltin +from mininet.moduledeps import moduleDeps, OVS_KMOD, OF_KMOD, TUN class Node( object ): """A virtual network node is simply a shell in a network namespace. @@ -397,6 +398,11 @@ class UserSwitch( Switch ): name: name for the switch""" Switch.__init__( self, name, **kwargs ) + @staticmethod + def setup(): + "Ensure any dependencies are loaded; if not, try to load them." + moduleDeps( add = TUN ) + def start( self, controllers ): """Start OpenFlow reference user datapath. Log to /tmp/sN-{ofd,ofp}.log. @@ -448,6 +454,11 @@ class KernelSwitch( Switch ): " in the root namespace." ) exit( 1 ) + @staticmethod + def setup(): + "Ensure any dependencies are loaded; if not, try to load them." + moduleDeps( subtract = OVS_KMOD, add = OF_KMOD ) + def start( self, controllers ): "Start up reference kernel datapath." ofplog = '/tmp/' + self.name + '-ofp.log' @@ -508,6 +519,11 @@ class OVSKernelSwitch( Switch ): " in the root namespace." ) exit( 1 ) + @staticmethod + def setup(): + "Ensure any dependencies are loaded; if not, try to load them." + moduleDeps( subtract = OF_KMOD, add = OVS_KMOD ) + def start( self, controllers ): "Start up kernel datapath." ofplog = '/tmp/' + self.name + '-ofp.log' diff --git a/mininet/test/test_nets.py b/mininet/test/test_nets.py index b5e32a3..e114e3c 100755 --- a/mininet/test/test_nets.py +++ b/mininet/test/test_nets.py @@ -7,10 +7,13 @@ import unittest from mininet.net import init, Mininet from mininet.node import KernelSwitch, Host, Controller, ControllerParams +from mininet.node import UserSwitch, OVSKernelSwitch from mininet.topo import SingleSwitchTopo, LinearTopo # temporary, until user-space side is tested -SWITCHES = { 'kernel': KernelSwitch } +SWITCHES = { 'kernel': KernelSwitch, + 'user': UserSwitch, + 'ovsk': OVSKernelSwitch } class testSingleSwitch( unittest.TestCase ): diff --git a/util/modprobe_setup.sh b/util/modprobe_setup.sh new file mode 100755 index 0000000..fec0a36 --- /dev/null +++ b/util/modprobe_setup.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Script to copy built OVS and OF kernel modules to where modprobe will +# find them automatically. Removes the need to keep an environment variable +# for each, and works nicely with multiple kernel versions. +# +# The downside is that after each recompilation of OVS or OF you'll need to +# re-run this script. If you're using only one kernel version, then it may be +# a good idea to use a symbolic link in place of the copy below. +DRIVERS_DIR=/lib/modules/`uname -r`/kernel/drivers + +OVS_DIR=~/openvswitch +OVS_KMOD=openvswitch_mod.ko +cp $OVS_DIR/datapath/linux-2.6/$OVS_KMOD $DRIVERS_DIR + +OF_DIR=~/openflow +OF_KMOD=ofdatapath.ko +cp $OF_DIR/datapath/linux-2.6/$OF_KMOD $DRIVERS_DIR + +# Update for modprobe +sudo depmod -a