Separate kernel and user switches into separate objects
This commit is contained in:
+2
-2
@@ -11,7 +11,7 @@ from ripcord.topo import FatTreeTopo
|
|||||||
|
|
||||||
from mininet.logging_mod import lg, set_loglevel, LEVELS
|
from mininet.logging_mod import lg, set_loglevel, LEVELS
|
||||||
from mininet.net import Mininet, init
|
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
|
from mininet.topo import TreeTopo
|
||||||
|
|
||||||
# built in topologies, created only when run
|
# built in topologies, created only when run
|
||||||
@@ -24,7 +24,7 @@ TOPOS = {'minimal' : (lambda: TreeTopo(depth = 2, fanout = 2)),
|
|||||||
'fattree6' : (lambda: FatTreeTopo(k = 6))}
|
'fattree6' : (lambda: FatTreeTopo(k = 6))}
|
||||||
|
|
||||||
SWITCH_DEF = 'kernel'
|
SWITCH_DEF = 'kernel'
|
||||||
SWITCHES = {'kernel' : Switch}
|
SWITCHES = {'kernel' : KernelSwitch}
|
||||||
|
|
||||||
HOST_DEF = 'process'
|
HOST_DEF = 'process'
|
||||||
HOSTS = {'process' : Host}
|
HOSTS = {'process' : Host}
|
||||||
|
|||||||
+10
-4
@@ -377,14 +377,20 @@ class Mininet(object):
|
|||||||
return ploss
|
return ploss
|
||||||
|
|
||||||
def ping_all(self):
|
def ping_all(self):
|
||||||
'''Ping between all hosts.'''
|
'''Ping between all hosts.
|
||||||
self.ping()
|
|
||||||
|
@return ploss packet loss percentage
|
||||||
|
'''
|
||||||
|
return self.ping()
|
||||||
|
|
||||||
def ping_pair(self):
|
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_sorted = sorted(self.topo.hosts())
|
||||||
hosts = [hosts_sorted[0], hosts_sorted[1]]
|
hosts = [hosts_sorted[0], hosts_sorted[1]]
|
||||||
self.ping(hosts = hosts)
|
return self.ping(hosts = hosts)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parseIperf(iperfOutput):
|
def _parseIperf(iperfOutput):
|
||||||
|
|||||||
+103
-108
@@ -211,6 +211,102 @@ class Host(Node):
|
|||||||
pass
|
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):
|
class Controller(Node):
|
||||||
'''A Controller is a Node that is running (or has execed) an
|
'''A Controller is a Node that is running (or has execed) an
|
||||||
OpenFlow controller.'''
|
OpenFlow controller.'''
|
||||||
@@ -240,105 +336,16 @@ class Controller(Node):
|
|||||||
self.terminate()
|
self.terminate()
|
||||||
|
|
||||||
|
|
||||||
class Switch(Node):
|
class ControllerParams(object):
|
||||||
'''A Switch is a Node that is running (or has execed)
|
'''Container for controller IP parameters.'''
|
||||||
an OpenFlow switch.'''
|
def __init__(self, ip, subnet_size):
|
||||||
|
|
||||||
def __init__(self, name, datapath = None):
|
|
||||||
'''Init.
|
'''Init.
|
||||||
|
|
||||||
@param name
|
@param ip integer, controller IP
|
||||||
@param datapath string, datapath name
|
@param subnet_size integer, ex 8 for slash-8, covering 17M
|
||||||
'''
|
'''
|
||||||
self.dp = datapath
|
self.ip = ip
|
||||||
Node.__init__(self, name, inNamespace = (datapath == None))
|
self.subnet_size = subnet_size
|
||||||
|
|
||||||
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, ''
|
|
||||||
|
|
||||||
|
|
||||||
class NOX(Controller):
|
class NOX(Controller):
|
||||||
@@ -361,15 +368,3 @@ class NOX(Controller):
|
|||||||
cargs = '--libdir=/usr/local/lib -v -i ptcp: ' + \
|
cargs = '--libdir=/usr/local/lib -v -i ptcp: ' + \
|
||||||
' '.join(nox_args),
|
' '.join(nox_args),
|
||||||
cdir = nox_core_dir, **kwargs)
|
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
|
|
||||||
@@ -8,12 +8,12 @@ from time import sleep
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from mininet.net import init, Mininet #, DATAPATHS
|
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.node import Controller
|
||||||
from mininet.topo import TreeTopo
|
from mininet.topo import TreeTopo
|
||||||
|
|
||||||
# temporary, until user-space side is tested
|
# temporary, until user-space side is tested
|
||||||
DATAPATHS = ['kernel']
|
SWITCHES = {'kernel' : KernelSwitch}
|
||||||
|
|
||||||
class testMinimal(unittest.TestCase):
|
class testMinimal(unittest.TestCase):
|
||||||
'''For each datapath type, test ping with a minimal topology.
|
'''For each datapath type, test ping with a minimal topology.
|
||||||
@@ -24,15 +24,12 @@ class testMinimal(unittest.TestCase):
|
|||||||
def testMinimal(self):
|
def testMinimal(self):
|
||||||
'''Ping test with both datapaths on minimal topology'''
|
'''Ping test with both datapaths on minimal topology'''
|
||||||
init()
|
init()
|
||||||
for datapath in DATAPATHS:
|
for switch in SWITCHES.values():
|
||||||
k = datapath == 'kernel'
|
|
||||||
controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
|
controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
|
||||||
mn = Mininet(TreeTopo(), Switch, Host, Controller,
|
mn = Mininet(TreeTopo(), switch, Host, Controller,
|
||||||
controller_params)
|
controller_params)
|
||||||
mn.start()
|
dropped = mn.run('ping')
|
||||||
dropped = mn.ping_test()
|
|
||||||
self.assertEqual(dropped, 0)
|
self.assertEqual(dropped, 0)
|
||||||
mn.stop()
|
|
||||||
|
|
||||||
|
|
||||||
class testTree(unittest.TestCase):
|
class testTree(unittest.TestCase):
|
||||||
@@ -41,16 +38,13 @@ class testTree(unittest.TestCase):
|
|||||||
def testTree16(self):
|
def testTree16(self):
|
||||||
'''Ping test with both datapaths on 16-host topology'''
|
'''Ping test with both datapaths on 16-host topology'''
|
||||||
init()
|
init()
|
||||||
for datapath in DATAPATHS:
|
for switch in SWITCHES.values():
|
||||||
k = datapath == 'kernel'
|
|
||||||
controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
|
controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8
|
||||||
tree_topo = TreeTopo(depth = 3, fanout = 4)
|
tree_topo = TreeTopo(depth = 3, fanout = 4)
|
||||||
mn = Mininet(tree_topo, Switch, Host, Controller,
|
mn = Mininet(tree_topo, switch, Host, Controller,
|
||||||
controller_params)
|
controller_params)
|
||||||
mn.start()
|
dropped = mn.run('ping')
|
||||||
dropped = mn.ping_test()
|
|
||||||
self.assertEqual(dropped, 0)
|
self.assertEqual(dropped, 0)
|
||||||
mn.stop()
|
|
||||||
|
|
||||||
#class testLinear(unittest.TestCase):
|
#class testLinear(unittest.TestCase):
|
||||||
# '''For each datapath type, test all-pairs ping with LinearNet.'''
|
# '''For each datapath type, test all-pairs ping with LinearNet.'''
|
||||||
|
|||||||
Reference in New Issue
Block a user