From 1bb4412ff345a8c3583bbf881ae3be6679a44a3e Mon Sep 17 00:00:00 2001 From: Brandon Heller Date: Sat, 2 Jan 2010 08:51:24 -0800 Subject: [PATCH] Separate kernel and user switches into separate objects --- bin/mn_run.py | 4 +- mininet/net.py | 14 ++- mininet/node.py | 213 +++++++++++++++++++------------------- mininet/test/test_nets.py | 22 ++-- 4 files changed, 124 insertions(+), 129 deletions(-) diff --git a/bin/mn_run.py b/bin/mn_run.py index 0aa7248..2c566c4 100755 --- a/bin/mn_run.py +++ b/bin/mn_run.py @@ -11,7 +11,7 @@ from ripcord.topo import FatTreeTopo from mininet.logging_mod import lg, set_loglevel, LEVELS from mininet.net import Mininet, init -from mininet.node import Switch, Host, Controller, ControllerParams, NOX +from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX from mininet.topo import TreeTopo # built in topologies, created only when run @@ -24,7 +24,7 @@ TOPOS = {'minimal' : (lambda: TreeTopo(depth = 2, fanout = 2)), 'fattree6' : (lambda: FatTreeTopo(k = 6))} SWITCH_DEF = 'kernel' -SWITCHES = {'kernel' : Switch} +SWITCHES = {'kernel' : KernelSwitch} HOST_DEF = 'process' HOSTS = {'process' : Host} diff --git a/mininet/net.py b/mininet/net.py index 063ca23..0a72349 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -377,14 +377,20 @@ class Mininet(object): return ploss def ping_all(self): - '''Ping between all hosts.''' - self.ping() + '''Ping between all hosts. + + @return ploss packet loss percentage + ''' + return self.ping() def ping_pair(self): - '''Ping between first two hosts, useful for testing.''' + '''Ping between first two hosts, useful for testing. + + @return ploss packet loss percentage + ''' hosts_sorted = sorted(self.topo.hosts()) hosts = [hosts_sorted[0], hosts_sorted[1]] - self.ping(hosts = hosts) + return self.ping(hosts = hosts) @staticmethod def _parseIperf(iperfOutput): diff --git a/mininet/node.py b/mininet/node.py index 023d01c..dab98dd 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -211,6 +211,102 @@ class Host(Node): pass +class Switch(Node): + '''A Switch is a Node that is running (or has execed) + an OpenFlow switch.''' + + 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, '' + +class UserSwitch(Switch): + + def __init__(self, name): + '''Init. + + @param name + ''' + Node.__init__(self, name, inNamespace = True) + + def start(self, controllers): + '''Start OpenFlow reference user datapath. + + Log to /tmp/sN-{ofd,ofp}.log. + + @param controllers dict of controller names to objects + ''' + if 'c0' not in controller: + raise Exception('User datapath start() requires controller c0') + controller = controllers['c0'] + 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 stop(self): + '''Stop OpenFlow reference user datapath.''' + self.cmd('kill %ofdatapath') + self.cmd('kill %ofprotocol') + + +class KernelSwitch(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 start(self, ignore): + '''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 stop(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('.') + + class Controller(Node): '''A Controller is a Node that is running (or has execed) an OpenFlow controller.''' @@ -240,105 +336,16 @@ class Controller(Node): 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): +class ControllerParams(object): + '''Container for controller IP parameters.''' + def __init__(self, ip, subnet_size): '''Init. - @param name - @param datapath string, datapath name + @param ip integer, controller IP + @param subnet_size integer, ex 8 for slash-8, covering 17M ''' - self.dp = datapath - Node.__init__(self, name, inNamespace = (datapath == None)) - - def _startUserDatapath(self, controllers): - '''Start OpenFlow reference user datapath. - - Log to /tmp/sN-{ofd,ofp}.log. - - @param controllers dict of controller names to objects - ''' - if 'c0' not in controller: - raise Exception('User datapath start() requires controller c0') - controller = controllers['c0'] - 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, controllers): - '''Start datapath. - - @param controllers dict of controller names to objects - ''' - if self.dp is None: - self._startUserDatapath(controllers) - 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, '' + self.ip = ip + self.subnet_size = subnet_size class NOX(Controller): @@ -360,16 +367,4 @@ class NOX(Controller): 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 + cdir = nox_core_dir, **kwargs) \ No newline at end of file diff --git a/mininet/test/test_nets.py b/mininet/test/test_nets.py index ed6570d..2c65fd1 100755 --- a/mininet/test/test_nets.py +++ b/mininet/test/test_nets.py @@ -8,12 +8,12 @@ from time import sleep import unittest from mininet.net import init, Mininet #, DATAPATHS -from mininet.node import Switch, Host, NOXController, ControllerParams +from mininet.node import KernelSwitch, Host, ControllerParams from mininet.node import Controller from mininet.topo import TreeTopo # temporary, until user-space side is tested -DATAPATHS = ['kernel'] +SWITCHES = {'kernel' : KernelSwitch} class testMinimal(unittest.TestCase): '''For each datapath type, test ping with a minimal topology. @@ -24,15 +24,12 @@ class testMinimal(unittest.TestCase): def testMinimal(self): '''Ping test with both datapaths on minimal topology''' init() - for datapath in DATAPATHS: - k = datapath == 'kernel' + for switch in SWITCHES.values(): controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8 - mn = Mininet(TreeTopo(), Switch, Host, Controller, + mn = Mininet(TreeTopo(), switch, Host, Controller, controller_params) - mn.start() - dropped = mn.ping_test() + dropped = mn.run('ping') self.assertEqual(dropped, 0) - mn.stop() class testTree(unittest.TestCase): @@ -41,16 +38,13 @@ class testTree(unittest.TestCase): def testTree16(self): '''Ping test with both datapaths on 16-host topology''' init() - for datapath in DATAPATHS: - k = datapath == 'kernel' + for switch in SWITCHES.values(): controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8 tree_topo = TreeTopo(depth = 3, fanout = 4) - mn = Mininet(tree_topo, Switch, Host, Controller, + mn = Mininet(tree_topo, switch, Host, Controller, controller_params) - mn.start() - dropped = mn.ping_test() + dropped = mn.run('ping') self.assertEqual(dropped, 0) - mn.stop() #class testLinear(unittest.TestCase): # '''For each datapath type, test all-pairs ping with LinearNet.'''