Compare commits

..
Author SHA1 Message Date
Bob Lantz 7ce07884f4 Install cleanup callback on load. 2015-06-12 13:06:51 -07:00
Bob Lantz be53ac31d6 Fix CLI for switches, and rename cleanup (in superclass!!) 2015-06-11 00:17:19 -07:00
Bob Lantz 50bfbd0566 Add cleanup callback 2015-06-11 00:17:19 -07:00
Bob Lantz a4d8049661 Rename pid files to make them more distinctive and to facilitate pkill
If there are leftover ovsdb/vswitchd processes, you can kill them with
sudo pkill -9 -f mn.pid
2015-06-11 00:17:19 -07:00
Bob Lantz da4c53b3c9 Add OVSLinkNSh and share shell by default
Note: this changes the semantics somewhat, but it drastically reduces
the number of bash processes that we start up.
2015-06-11 00:17:19 -07:00
Bob Lantz 1b96ff3539 Use 172.123.123.0/24 for control network so we can ping data network 2015-06-11 00:17:19 -07:00
Bob Lantz 93d04123c6 Rename group option to n (number of OVS instances per ovsdb) 2015-06-11 00:17:19 -07:00
Bob Lantz 22655cf9fd We can now use --nat flush=0 2015-06-11 00:17:19 -07:00
Bob Lantz fe82d2c04a Minor changes + allow --switch ovsm,group=16 2015-06-11 00:17:18 -07:00
Bob Lantz 0534932bf3 First version of OVS in shared namespaces 2015-06-11 00:17:18 -07:00
25 changed files with 564 additions and 333 deletions

No files matched your search

+6 -6
View File
@@ -2,7 +2,7 @@
Mininet Installation/Configuration Notes
----------------------------------------
Mininet 2.3.0d1
Mininet 2.2.1
---
The supported installation methods for Mininet are 1) using a
@@ -65,7 +65,7 @@ like to contribute an installation script, we would welcome it!)
where <release tag> is the release you want to check out.
If you are running Ubuntu, Debian, or Fedora, you may be able to use
our handy `install.sh` script, which is in `util/`.
our handy `install.sh` script, which is in `mininet/util`.
*WARNING: USE AT YOUR OWN RISK!*
@@ -81,7 +81,7 @@ like to contribute an installation script, we would welcome it!)
To install Mininet itself, the OpenFlow reference implementation, and
Open vSwitch, you may use:
util/install.sh -fnv
mininet/util/install.sh -fnv
This should be reasonably quick, and the following command should
work after the installation:
@@ -92,14 +92,14 @@ like to contribute an installation script, we would welcome it!)
including POX, the OpenFlow WireShark dissector, the `oftest`
framework, and other potentially useful software, you may use:
util/install.sh -a
mininet/util/install.sh -a
This takes about 4 minutes on our test system.
You can change the directory where the dependencies are installed using
the -s <directory> flag.
util/install.sh -s <directory> -a
mininet/util/install.sh -s <directory> -a
3.2. Native installation from source on Fedora 18+.
@@ -128,7 +128,7 @@ like to contribute an installation script, we would welcome it!)
* install Mininet, the OpenFlow reference implementation, and
Open vSwitch
util/install.sh -fnv
mininet/util/install.sh -fnv
* enable and start openvswitch
+2 -2
View File
@@ -1,6 +1,6 @@
Mininet 2.3.0d1 License
Mininet 2.2.1 License
Copyright (c) 2013-2016 Open Networking Laboratory
Copyright (c) 2013-2015 Open Networking Laboratory
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
The Leland Stanford Junior University
+2 -3
View File
@@ -2,7 +2,6 @@ MININET = mininet/*.py
TEST = mininet/test/*.py
EXAMPLES = mininet/examples/*.py
MN = bin/mn
PYMN = python -B bin/mn
BIN = $(MN)
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
MNEXEC = mnexec
@@ -44,7 +43,7 @@ slowtest: $(MININET)
mininet/examples/test/runner.py -v
mnexec: mnexec.c $(MN) mininet/net.py
cc $(CFLAGS) $(LDFLAGS) -DVERSION=\"`PYTHONPATH=. $(PYMN) --version`\" $< -o $@
cc $(CFLAGS) $(LDFLAGS) -DVERSION=\"`PYTHONPATH=. $(MN) --version`\" $< -o $@
install: $(MNEXEC) $(MANPAGES)
install $(MNEXEC) $(BINDIR)
@@ -61,7 +60,7 @@ man: $(MANPAGES)
mn.1: $(MN)
PYTHONPATH=. help2man -N -n "create a Mininet network." \
--no-discard-stderr "$(PYMN)" -o $@
--no-discard-stderr $< -o $@
mnexec.1: mnexec
help2man -N -n "execution utility for Mininet." \
+1 -1
View File
@@ -3,7 +3,7 @@ Mininet: Rapid Prototyping for Software Defined Networks
*The best way to emulate almost any network on your laptop!*
Mininet 2.3.0d1
Mininet 2.2.1
### What is Mininet?
+26 -31
View File
@@ -88,15 +88,14 @@ LINKS = { 'default': Link,
'ovs': OVSLink }
# Names of tests that are Mininet() methods
TESTNAMES = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
'none' ]
# optional tests to run
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
'none' ]
# Map to alternate functions and/or spellings of Mininet() methods
TESTS = { 'pingall': 'pingAll',
'pingpair': 'pingPair',
'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp' }
ALTSPELLING = { 'pingall': 'pingAll',
'pingpair': 'pingPair',
'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp' }
def addDictOption( opts, choicesDict, default, name, **kwargs ):
@@ -159,8 +158,7 @@ class MininetRunner( object ):
def setCustom( self, name, value ):
"Set custom parameters for MininetRunner."
if name in ( 'topos', 'switches', 'hosts', 'controllers', 'links'
'testnames', 'tests' ):
if name in ( 'topos', 'switches', 'hosts', 'controllers', 'links' ):
# Update dictionaries
param = name.upper()
globals()[ param ].update( value )
@@ -210,9 +208,10 @@ class MininetRunner( object ):
type='string',
help='read custom classes or params from .py file(s)'
)
testList = TESTNAMES + TESTS.keys()
opts.add_option( '--test', default=[], action='append',
dest='tests', help='|'.join( testList ) )
opts.add_option( '--test', type='choice', choices=TESTS,
default=TESTS[ 0 ],
help='|'.join( TESTS ) )
opts.add_option( '--xterms', '-x', action='store_true',
default=False, help='spawn xterms for each node' )
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
@@ -359,27 +358,23 @@ class MininetRunner( object ):
if self.options.pre:
cli( mn, script=self.options.pre )
test = self.options.test
test = ALTSPELLING.get( test, test )
mn.start()
if not self.options.tests:
if test == 'none':
pass
elif test == 'all':
mn.waitConnected()
mn.start()
mn.ping()
mn.iperf()
elif test == 'cli':
cli( mn )
for test in self.options.tests:
test = TESTS.get( test, test )
if callable( test ): # user added TESTMAP={'mytest': testfn}
test( mn )
elif test == 'none':
pass
elif test == 'all':
mn.waitConnected()
mn.start()
mn.ping()
mn.iperf()
elif test == 'cli':
cli( mn )
elif test != 'build':
mn.waitConnected()
getattr( mn, test )()
elif test != 'build':
mn.waitConnected()
getattr( mn, test )()
if self.options.post:
cli( mn, script=self.options.post )
+1 -1
View File
@@ -103,7 +103,7 @@ def findUser():
# Logged-in user (if we have a tty)
( quietRun( 'who am i' ).split() or [ False ] )[ 0 ] or
# Give up and return effective user
quietRun( 'whoami' ).strip() )
quietRun( 'whoami' ) )
class ClusterCleanup( object ):
+1 -1
View File
@@ -17,7 +17,7 @@ setLogLevel( 'info' )
# Ignore the warning message that the remote isn't (yet) running
c0 = Controller( 'c0', port=6633 )
c1 = Controller( 'c1', port=6634 )
c2 = RemoteController( 'c2', ip='127.0.0.1', port=6633 )
c2 = RemoteController( 'c2', ip='127.0.0.1' )
cmap = { 's1': c0, 's2': c1, 's3': c2 }
+2 -3
View File
@@ -17,11 +17,10 @@ from mininet.util import quietRun
def checkIntf( intf ):
"Make sure intf exists and is not configured."
config = quietRun( 'ifconfig %s 2>/dev/null' % intf, shell=True )
if not config:
if ( ' %s:' % intf ) not in quietRun( 'ip link show' ):
error( 'Error:', intf, 'does not exist!\n' )
exit( 1 )
ips = re.findall( r'\d+\.\d+\.\d+\.\d+', config )
ips = re.findall( r'\d+\.\d+\.\d+\.\d+', quietRun( 'ifconfig ' + intf ) )
if ips:
error( 'Error:', intf, 'has an IP address,'
'and is probably in use!\n' )
+1 -1
View File
@@ -121,6 +121,6 @@ def linearBandwidthTest( lengths ):
if __name__ == '__main__':
lg.setLogLevel( 'info' )
sizes = [ 1, 10, 20, 40, 60, 80 ]
sizes = [ 1, 10, 20, 40, 60, 80, 100 ]
print "*** Running linearBandwidthTest", sizes
linearBandwidthTest( sizes )
+275
View File
@@ -0,0 +1,275 @@
#!/usr/bin/python
"""
Multiple ovsdb OVS!!
We scale up by creating multiple ovsdb instances,
each of which is shared by several OVS switches
The shell may also be shared among switch instances,
which causes switch.cmd() and switch.popen() to be
delegated to the ovsdb instance.
"""
from mininet.net import Mininet
from mininet.node import Node, OVSSwitch
from mininet.node import OVSBridge
from mininet.link import Link, OVSIntf
from mininet.topo import LinearTopo, SingleSwitchTopo
from mininet.topolib import TreeTopo
from mininet.log import setLogLevel, info
from mininet.cli import CLI
from mininet.clean import Cleanup, sh
from itertools import groupby
from operator import attrgetter
class OVSDB( Node ):
"Namespace for an OVSDB instance"
privateDirs = [ '/etc/openvswitch',
'/var/run/openvswitch',
'/var/log/openvswitch' ]
# Control network
ipBase = '172.123.123.0/24'
cnet = None
nat = None
@classmethod
def startControlNet( cls ):
"Start control net if necessary and return it"
cnet = cls.cnet
if not cnet:
info( '### Starting control network\n' )
cnet = Mininet( ipBase=cls.ipBase )
cswitch = cnet.addSwitch( 'ovsbr0', cls=OVSBridge )
# Add NAT - note this can conflict with data network NAT
info( '### Adding NAT for control and data networks'
' (use --nat flush=0 for data network)\n' )
cls.cnet = cnet
cls.nat = cnet.addNAT( 'ovsdbnat0')
cnet.start()
info( '### Control network started\n' )
return cnet
def stopControlNet( self ):
info( '\n### Stopping control network\n' )
cls = self.__class__
cls.cnet.stop()
info( '### Control network stopped\n' )
def addSwitch( self, switch ):
"Add a switch to our namespace"
# Attach first switch to cswitch!
self.switches.append( switch )
def delSwitch( self, switch ):
"Delete a switch from our namespace, and terminate if none left"
self.switches.remove( switch )
if not self.switches:
self.stopOVS()
ovsdbCount = 0
def startOVS( self ):
"Start new OVS instance"
self.cmd( 'ovsdb-tool create /etc/openvswitch/conf.db' )
self.cmd( 'ovsdb-server /etc/openvswitch/conf.db'
' -vfile:emer -vfile:err -vfile:info'
' --remote=punix:/var/run/openvswitch/db.sock '
' --log-file=/var/log/openvswitch/ovsdb-server.log'
' --pidfile=/var/run/openvswitch/ovsdb-server-mn.pid'
' --no-chdir'
' --detach' )
self.cmd( 'ovs-vswitchd unix:/var/run/openvswitch/db.sock'
' -vfile:emer -vfile:err -vfile:info'
' --mlockall --log-file=/var/log/openvswitch/ovs-vswitchd.log'
' --pidfile=/var/run/openvswitch/ovs-vswitchd-mn.pid'
' --no-chdir'
' --detach' )
def stopOVS( self ):
self.cmd( 'kill',
'`cat /var/run/openvswitch/ovs-vswitchd-mn.pid`',
'`cat /var/run/openvswitch/ovsdb-server-mn.pid`' )
self.cmd( 'wait' )
self.__class__.ovsdbCount -= 1
if self.__class__.ovsdbCount <= 0:
self.stopControlNet()
@classmethod
def cleanUpOVS( cls ):
"Clean up leftover ovsdb-server/ovs-vswitchd processes"
info( '*** Shutting down extra ovsdb-server/ovs-vswitchd processes\n' )
sh( 'pkill -f mn.pid' )
def self( self, *args, **kwargs ):
"A fake constructor that sets params and returns self"
self.params = kwargs
return self
def __init__( self, **kwargs ):
cls = self.__class__
cls.ovsdbCount += 1
cnet = self.startControlNet()
# Create a new ovsdb namespace
self.switches = []
name = 'ovsdb%d' % cls.ovsdbCount
kwargs.update( inNamespace=True )
kwargs.setdefault( 'privateDirs', self.privateDirs )
super( OVSDB, self ).__init__( name, **kwargs )
ovsdb = cnet.addHost( name, cls=self.self, **kwargs )
link = cnet.addLink( ovsdb, cnet.switches[ 0 ] )
cnet.switches[ 0 ].attach( link.intf2 )
ovsdb.configDefault()
ovsdb.setDefaultRoute( 'via %s' % self.nat.intfs[ 0 ].IP() )
ovsdb.startOVS()
# Install cleanup callback
Cleanup.addCleanupCallback( OVSDB.cleanUpOVS )
class OVSSwitchNS( OVSSwitch ):
"OVS Switch in shared OVSNS namespace"
isSetup = False
@classmethod
def batchStartup( cls, switches ):
result = []
for ovsdb, switchGroup in groupby( switches, attrgetter( 'ovsdb') ):
switchGroup = list( switchGroup )
info( '(%s)' % ovsdb )
result += OVSSwitch.batchStartup( switchGroup, run=ovsdb.cmd )
return result
@classmethod
def batchShutdown( cls, switches ):
result = []
for ovsdb, switchGroup in groupby( switches, attrgetter( 'ovsdb') ):
switchGroup = list( switchGroup )
info( '(%s)' % ovsdb )
for switch in switches:
if switch.pid == ovsdb.pid:
switch.pid = None
switch.shell = None
result += OVSSwitch.batchShutdown( switchGroup, run=ovsdb.cmd )
for switch in switchGroup:
switch.ovsdbFree()
return result
# OVSDB allocation
groupSize = 64
switchCount = 0
lastOvsdb = None
@classmethod
def ovsdbAlloc( cls, switch ):
"Allocate (possibly new) OVSDB instance for switch"
if cls.switchCount % switch.groupSize == 0:
cls.lastOvsdb = OVSDB()
cls.switchCount += 1
cls.lastOvsdb.addSwitch( switch )
return cls.lastOvsdb
def ovsdbFree( self ):
"Deallocate OVSDB instance for switch"
self.ovsdb.delSwitch( self )
def startShell( self, *args, **kwargs ):
"Start shell in shared OVSDB namespace"
ovsdb = self.ovsdbAlloc( self )
kwargs.update( mnopts='-da %d ' % ovsdb.pid )
self.ns = [ 'net' ]
self.ovsdb = ovsdb
self._waiting = False
if self.privateShell:
super( OVSSwitchNS, self ).startShell( *args, **kwargs )
else:
# Delegate methods and initialize local vars
attrs = ( 'cmd', 'cmdPrint', 'sendCmd', 'waitOutput',
'monitor', 'write', 'read',
'pid', 'shell', 'stdout',)
for attr in attrs:
setattr( self, attr, getattr( ovsdb, attr ) )
self.defaultIntf().updateIP()
@property
def waiting( self ):
"Optionally delegated to ovsdb"
return self._waiting if self.privateShell else self.ovsdb.waiting
@waiting.setter
def waiting( self, value ):
"Optionally delegated to ovsdb (read only!)"
if self.privateShell:
_waiting = value
def start( self, controllers ):
"Update controller IP addresses if necessary"
for controller in controllers:
if controller.IP() == '127.0.0.1' and not controller.intfs:
controller.intfs[ 0 ] = self.ovsdb.nat.intfs[ 0 ]
super( OVSSwitchNS, self ).start( controllers )
def stop( self, *args, **kwargs ):
"Stop and free OVSDB namespace if necessary"
self.ovsdbFree()
def terminate( self, *args, **kwargs ):
if self.privateShell:
super( OVSSwitchNS, self ).terminate( *args, **kwargs )
else:
self.pid = None
self.shell= None
def defaultIntf( self ):
return self.ovsdb.defaultIntf()
def __init__( self, *args, **kwargs ):
"""n: number of OVS instances per OVSDB
shell: run private shell/bash process? (False)
If shell is shared/not private, cmd() and popen() are
delegated to the OVSDB instance, which is different than
regular OVSSwitch semantics!!"""
self.groupSize = kwargs.pop( 'n', self.groupSize )
self.privateShell = kwargs.pop( 'shell', False )
super( OVSSwitchNS, self ).__init__( *args, **kwargs )
class OVSLinkNS( Link ):
"OVSLink that supports OVSSwitchNS"
def __init__( self, node1, node2, **kwargs ):
"See Link.__init__() for options"
self.isPatchLink = False
if ( isinstance( node1, OVSSwitch ) and
isinstance( node2, OVSSwitch ) and
getattr( node1, 'ovsdb', None ) ==
getattr( node2, 'ovsdb', None ) ):
self.isPatchLink = True
kwargs.update( cls1=OVSIntf, cls2=OVSIntf )
Link.__init__( self, node1, node2, **kwargs )
switches = { 'ovsns': OVSSwitchNS, 'ovsm': OVSSwitchNS }
links = { 'ovs': OVSLinkNS }
def test():
"Test OVSNS switch"
setLogLevel( 'info' )
topo = TreeTopo( depth=4, fanout=2 )
net = Mininet( topo=topo, switch=OVSSwitchNS )
# Add connectivity to controller which is on LAN or in root NS
# net.addNAT().configDefault()
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
test()
+94 -3
View File
@@ -2,20 +2,111 @@
"""
Example to create a Mininet topology and connect it to the internet via NAT
through eth0 on the host.
Glen Gibb, February 2011
(slight modifications by BL, 5/13)
"""
from mininet.cli import CLI
from mininet.log import lg
from mininet.node import Node
from mininet.topolib import TreeNet
#################################
def startNAT( root, inetIntf='eth0', subnet='10.0/8' ):
"""Start NAT/forwarding between Mininet and external network
root: node to access iptables from
inetIntf: interface for internet access
subnet: Mininet subnet (default 10.0/8)="""
# Identify the interface connecting to the mininet network
localIntf = root.defaultIntf()
# Flush any currently active rules
root.cmd( 'iptables -F' )
root.cmd( 'iptables -t nat -F' )
# Create default entries for unmatched traffic
root.cmd( 'iptables -P INPUT ACCEPT' )
root.cmd( 'iptables -P OUTPUT ACCEPT' )
root.cmd( 'iptables -P FORWARD DROP' )
# Configure NAT
root.cmd( 'iptables -I FORWARD -i', localIntf, '-d', subnet, '-j DROP' )
root.cmd( 'iptables -A FORWARD -i', localIntf, '-s', subnet, '-j ACCEPT' )
root.cmd( 'iptables -A FORWARD -i', inetIntf, '-d', subnet, '-j ACCEPT' )
root.cmd( 'iptables -t nat -A POSTROUTING -o ', inetIntf, '-j MASQUERADE' )
# Instruct the kernel to perform forwarding
root.cmd( 'sysctl net.ipv4.ip_forward=1' )
def stopNAT( root ):
"""Stop NAT/forwarding between Mininet and external network"""
# Flush any currently active rules
root.cmd( 'iptables -F' )
root.cmd( 'iptables -t nat -F' )
# Instruct the kernel to stop forwarding
root.cmd( 'sysctl net.ipv4.ip_forward=0' )
def fixNetworkManager( root, intf ):
"""Prevent network-manager from messing with our interface,
by specifying manual configuration in /etc/network/interfaces
root: a node in the root namespace (for running commands)
intf: interface name"""
cfile = '/etc/network/interfaces'
line = '\niface %s inet manual\n' % intf
config = open( cfile ).read()
if line not in config:
print '*** Adding', line.strip(), 'to', cfile
with open( cfile, 'a' ) as f:
f.write( line )
# Probably need to restart network-manager to be safe -
# hopefully this won't disconnect you
root.cmd( 'service network-manager restart' )
def connectToInternet( network, switch='s1', rootip='10.254', subnet='10.0/8'):
"""Connect the network to the internet
switch: switch to connect to root namespace
rootip: address for interface in root namespace
subnet: Mininet subnet"""
switch = network.get( switch )
prefixLen = subnet.split( '/' )[ 1 ]
# Create a node in root namespace
root = Node( 'root', inNamespace=False )
# Prevent network-manager from interfering with our interface
fixNetworkManager( root, 'root-eth0' )
# Create link between root NS and switch
link = network.addLink( root, switch )
link.intf1.setIP( rootip, prefixLen )
# Start network that now includes link to root namespace
network.start()
# Start NAT and establish forwarding
startNAT( root )
# Establish routes from end hosts
for host in network.hosts:
host.cmd( 'ip route flush root 0/0' )
host.cmd( 'route add -net', subnet, 'dev', host.defaultIntf() )
host.cmd( 'route add default gw', rootip )
return root
if __name__ == '__main__':
lg.setLogLevel( 'info')
net = TreeNet( depth=1, fanout=4 )
# Add NAT connectivity
net.addNAT().configDefault()
net.start()
# Configure and start NATted connectivity
rootnode = connectToInternet( net )
print "*** Hosts are running and should have internet connectivity"
print "*** Type 'exit' or control-D to shut down network"
CLI( net )
# Shut down NAT
stopNAT( rootnode )
net.stop()
+8 -17
View File
@@ -16,30 +16,22 @@ from mininet.link import TCLink
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
from sys import argv
class SingleSwitchTopo(Topo):
"Single switch connected to n hosts."
def __init__(self, n=2, lossy=True, **opts):
def __init__(self, n=2, **opts):
Topo.__init__(self, **opts)
switch = self.addSwitch('s1')
for h in range(n):
# Each host gets 50%/n of system CPU
host = self.addHost('h%s' % (h + 1),
cpu=.5 / n)
if lossy:
# 10 Mbps, 5ms delay, 10% packet loss
self.addLink(host, switch,
bw=10, delay='5ms', loss=10, use_htb=True)
else:
# 10 Mbps, 5ms delay, no packet loss
self.addLink(host, switch,
bw=10, delay='5ms', loss=0, use_htb=True)
# 10 Mbps, 5ms delay, 10% loss
self.addLink(host, switch,
bw=10, delay='5ms', loss=10, use_htb=True)
def perfTest( lossy=True ):
def perfTest():
"Create network and run simple performance test"
topo = SingleSwitchTopo( n=4, lossy=lossy )
topo = SingleSwitchTopo( n=4 )
net = Mininet( topo=topo,
host=CPULimitedHost, link=TCLink,
autoStaticArp=True )
@@ -52,6 +44,5 @@ def perfTest( lossy=True ):
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
# Prevent test_simpleperf from failing due to packet loss
perfTest( lossy=( 'testmode' not in argv ) )
setLogLevel('info')
perfTest()
+1 -3
View File
@@ -40,9 +40,7 @@ class testCPU( unittest.TestCase ):
if sched not in scheds:
scheds.append( sched )
else:
self.assertTrue( bw < previous_bw,
"%f should be less than %f\n" %
( bw, previous_bw ) )
self.assertTrue( bw < previous_bw )
previous_bw = bw
else:
break
+8 -10
View File
@@ -13,29 +13,27 @@ class testIntfOptions( unittest.TestCase ):
def testIntfOptions( self ):
"verify that intf.config is correctly limiting traffic"
p = pexpect.spawn( 'python -m mininet.examples.intfoptions ' )
tolerance = .2 # plus or minus 20%
tolerance = .8
opts = [ "Results: \['([\d\.]+) .bits/sec",
"Results: \['10M', '([\d\.]+) .bits/sec",
"h(\d+)->h(\d+): (\d)/(\d),"
"rtt min/avg/max/mdev ([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms",
"h(\d+)->h(\d+): (\d)/(\d), rtt min/avg/max/mdev ([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms",
pexpect.EOF ]
while True:
index = p.expect( opts, timeout=600 )
if index == 0:
BW = 5
bw = float( p.match.group( 1 ) )
self.assertGreaterEqual( bw, BW * ( 1 - tolerance ) )
self.assertLessEqual( bw, BW * ( 1 + tolerance ) )
self.assertGreaterEqual( bw, float( 5 * tolerance ) )
self.assertLessEqual( bw, float( 5 + 5 * ( 1 - tolerance ) ) )
elif index == 1:
BW = 10
measuredBw = float( p.match.group( 1 ) )
loss = ( measuredBw / BW ) * 100
self.assertGreaterEqual( loss, 50 * ( 1 - tolerance ) )
self.assertLessEqual( loss, 50 * ( 1 + tolerance ) )
self.assertGreaterEqual( loss, 50 * tolerance )
self.assertLessEqual( loss, 50 + 50 * ( 1 - tolerance ) )
elif index == 2:
delay = float( p.match.group( 6 ) )
self.assertGreaterEqual( delay, 15 * ( 1 - tolerance ) )
self.assertLessEqual( delay, 15 * ( 1 + tolerance ) )
self.assertGreaterEqual( delay, 15 * tolerance )
self.assertLessEqual( delay, 15 + 15 * ( 1 - tolerance ) )
else:
break
+5 -5
View File
@@ -16,15 +16,15 @@ class testSimplePerf( unittest.TestCase ):
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testE2E( self ):
"Run the example and verify iperf results"
# 10 Mb/s, plus or minus 20% tolerance
BW = 10
TOLERANCE = .2
p = pexpect.spawn( 'python -m mininet.examples.simpleperf testmode' )
TOLERANCE = .8
expectedBw = BW * TOLERANCE
p = pexpect.spawn( 'python -m mininet.examples.simpleperf' )
# check iperf results
p.expect( "Results: \['10M', '([\d\.]+) .bits/sec", timeout=480 )
measuredBw = float( p.match.group( 1 ) )
lowerBound = BW * ( 1 - TOLERANCE )
upperBound = BW + ( 1 + TOLERANCE )
lowerBound = expectedBw * TOLERANCE
upperBound = expectedBw + expectedBw * ( 1 - TOLERANCE )
self.assertGreaterEqual( measuredBw, lowerBound )
self.assertLessEqual( measuredBw, upperBound )
p.wait()
+3 -5
View File
@@ -17,15 +17,13 @@ class testTree1024( unittest.TestCase ):
"Run the example and do a simple ping test from h1 to h1024"
p = pexpect.spawn( 'python -m mininet.examples.tree1024' )
p.expect( self.prompt, timeout=6000 ) # it takes awhile to set up
p.sendline( 'h1 ping -c 20 h1024' )
p.sendline( 'h1 ping -c 1 h1024' )
p.expect ( '(\d+)% packet loss' )
packetLossPercent = int( p.match.group( 1 ) ) if p.match else -1
percent = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
# Tolerate slow startup on some systems - we should revisit this
# and determine the root cause.
self.assertLess( packetLossPercent, 60 )
self.assertEqual( percent, 0 )
if __name__ == '__main__':
unittest.main()
+4 -7
View File
@@ -49,7 +49,6 @@ class Intf( object ):
# This saves an ifconfig command per node
if self.name == 'lo':
self.ip = '127.0.0.1'
self.prefixLen = 8
# Add to node (and move ourselves if necessary )
moveIntfFn = params.pop( 'moveIntfFn', None )
if moveIntfFn:
@@ -202,8 +201,6 @@ class Intf( object ):
# if self.node.inNamespace:
# Link may have been dumped into root NS
# quietRun( 'ip link del ' + self.name )
self.node.delIntf( self )
self.link = None
def status( self ):
"Return intf status as a string"
@@ -473,10 +470,10 @@ class Link( object ):
def delete( self ):
"Delete this link"
self.intf1.delete()
self.intf1 = None
self.intf2.delete()
self.intf2 = None
# We only need to delete one side, though this doesn't seem to
# cost us much and might help subclasses.
# self.intf2.delete()
def stop( self ):
"Override to stop and clean up link as needed"
self.delete()
+8 -68
View File
@@ -108,7 +108,7 @@ from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
from mininet.term import cleanUpScreens, makeTerms
# Mininet version: should be consistent with README and LICENSE
VERSION = "2.3.0d1"
VERSION = "2.2.1"
class Mininet( object ):
"Network emulation with hosts spawned in network namespaces."
@@ -226,24 +226,6 @@ class Mininet( object ):
self.nameToNode[ name ] = h
return h
def delNode( self, node, nodes=None):
"""Delete node
node: node to delete
nodes: optional list to delete from (e.g. self.hosts)"""
if nodes is None:
nodes = ( self.hosts if node in self.hosts else
( self.switches if node in self.switches else
( self.controllers if node in self.controllers else
[] ) ) )
node.stop( deleteIntfs=True )
node.terminate()
nodes.remove( node )
del self.nameToNode[ node.name ]
def delHost( self, host ):
"Delete a host"
self.delNode( host, nodes=self.hosts )
def addSwitch( self, name, cls=None, **params ):
"""Add switch.
name: name of switch to add
@@ -262,10 +244,6 @@ class Mininet( object ):
self.nameToNode[ name ] = sw
return sw
def delSwitch( self, switch ):
"Delete a switch"
self.delNode( switch, nodes=self.switches )
def addController( self, name='c0', controller=None, **params ):
"""Add controller.
controller: Controller class"""
@@ -287,12 +265,6 @@ class Mininet( object ):
self.nameToNode[ name ] = controller_new
return controller_new
def delController( self, controller ):
"""Delete a controller
Warning - does not reconfigure switches, so they
may still attempt to connect to it!"""
self.delNode( controller )
def addNAT( self, name='nat0', connect=True, inNamespace=False,
**params):
"""Add a NAT to the Mininet network
@@ -309,7 +281,7 @@ class Mininet( object ):
# Use first switch if not specified
connect = self.switches[ 0 ]
# Connect the nat to the switch
self.addLink( nat, connect )
self.addLink( nat, self.switches[ 0 ] )
# Set the default route on hosts
natIP = nat.params[ 'ip' ].split('/')[ 0 ]
for host in self.hosts:
@@ -331,13 +303,9 @@ class Mininet( object ):
# Even more convenient syntax for node lookup and iteration
def __getitem__( self, key ):
"net[ name ] operator: Return node with given name"
"""net [ name ] operator: Return node(s) with given name(s)"""
return self.nameToNode[ key ]
def __delitem__( self, key ):
"del net[ name ] operator - delete node with given name"
self.delNode( self.nameToNode[ key ] )
def __iter__( self ):
"return iterator over node names"
for node in chain( self.hosts, self.switches, self.controllers ):
@@ -399,30 +367,6 @@ class Mininet( object ):
self.links.append( link )
return link
def delLink( self, link ):
"Remove a link from this network"
link.delete()
self.links.remove( link )
def linksBetween( self, node1, node2 ):
"Return Links between node1 and node2"
return [ link for link in self.links
if ( node1, node2 ) in (
( link.intf1.node, link.intf2.node ),
( link.intf2.node, link.intf1.node ) ) ]
def delLinkBetween( self, node1, node2, index=0, allLinks=False ):
"""Delete link(s) between node1 and node2
index: index of link to delete if multiple links (0)
allLinks: ignore index and delete all such links (False)
returns: deleted link(s)"""
links = self.linksBetween( node1, node2 )
if not allLinks:
links = [ links[ index ] ]
for link in links:
self.delLink( link )
return links
def configHosts( self ):
"Configure a set of hosts."
for host in self.hosts:
@@ -823,14 +767,8 @@ class Mininet( object ):
cliout = client.cmd( iperfArgs + '-t %d -c ' % seconds +
server.IP() + ' ' + bwArgs )
debug( 'Client output: %s\n' % cliout )
servout = ''
# We want the last *b/sec from the iperf server output
# for TCP, there are two fo them because of waitListening
count = 2 if l4Type == 'TCP' else 1
while len( re.findall( '/sec', servout ) ) < count:
servout += server.monitor( timeoutms=5000 )
server.sendInt()
servout += server.waitOutput()
servout = server.waitOutput()
debug( 'Server output: %s\n' % servout )
result = [ self._parseIperf( servout ), self._parseIperf( cliout ) ]
if l4Type == 'UDP':
@@ -896,8 +834,10 @@ class Mininet( object ):
elif dst not in self.nameToNode:
error( 'dst not in network: %s\n' % dst )
else:
src = self.nameToNode[ src ]
dst = self.nameToNode[ dst ]
if isinstance( src, basestring ):
src = self.nameToNode[ src ]
if isinstance( dst, basestring ):
dst = self.nameToNode[ dst ]
connections = src.connectionsTo( dst )
if len( connections ) == 0:
error( 'src and dst not connected: %s %s\n' % ( src, dst) )
+19 -52
View File
@@ -212,7 +212,7 @@ class Node( object ):
# Subshell I/O, commands and control
def read( self, maxbytes=1024 ):
"""Buffered read from node, potentially blocking.
"""Buffered read from node, non-blocking.
maxbytes: maximum number of bytes to return"""
count = len( self.readbuf )
if count < maxbytes:
@@ -227,7 +227,7 @@ class Node( object ):
return result
def readline( self ):
"""Buffered readline from node, potentially blocking.
"""Buffered readline from node, non-blocking.
returns: line (minus newline) or None"""
self.readbuf += self.read( 1024 )
if '\n' not in self.readbuf:
@@ -259,10 +259,9 @@ class Node( object ):
def waitReadable( self, timeoutms=None ):
"""Wait until node's output is readable.
timeoutms: timeout in ms or None to wait indefinitely.
returns: result of poll()"""
timeoutms: timeout in ms or None to wait indefinitely."""
if len( self.readbuf ) == 0:
return self.pollOut.poll( timeoutms )
self.pollOut.poll( timeoutms )
def sendCmd( self, *args, **kwargs ):
"""Send a command, followed by a command to echo a sentinel,
@@ -304,9 +303,7 @@ class Node( object ):
Set self.waiting to False if command has completed.
timeoutms: timeout in ms or None to wait indefinitely
findPid: look for PID from mnexec -p"""
ready = self.waitReadable( timeoutms )
if not ready:
return ''
self.waitReadable( timeoutms )
data = self.read( 1024 )
pidre = r'\[\d+\] \d+\r\n'
# Look for PID
@@ -431,15 +428,6 @@ class Node( object ):
debug( 'moving', intf, 'into namespace for', self.name, '\n' )
moveIntfFn( intf.name, self )
def delIntf( self, intf ):
"""Remove interface from Node's known interfaces
Note: to fully delete interface, call intf.delete() instead"""
port = self.ports.get( intf )
if port is not None:
del self.intfs[ port ]
del self.ports[ intf ]
del self.nameToIntf[ intf.name ]
def defaultIntf( self ):
"Return interface for lowest port"
ports = self.intfs.keys()
@@ -693,9 +681,7 @@ class CPULimitedHost( Host ):
"Clean up our cgroup"
# info( '*** deleting cgroup', self.cgroup, '\n' )
_out, _err, exitcode = errRun( 'cgdelete -r ' + self.cgroup )
# Sometimes cgdelete returns a resource busy error but still
# deletes the group; next attempt will give "no such file"
return exitcode == 0 or ( 'no such file' in _err.lower() )
return exitcode == 0 # success condition
def popen( self, *args, **kwargs ):
"""Return a Popen() object in node's namespace
@@ -717,7 +703,7 @@ class CPULimitedHost( Host ):
def cleanup( self ):
"Clean up Node, then clean up our cgroup"
super( CPULimitedHost, self ).cleanup()
retry( retries=3, delaySecs=.1, fn=self.cgroupDel )
retry( retries=3, delaySecs=1, fn=self.cgroupDel )
_rtGroupSched = False # internal class var: Is CONFIG_RT_GROUP_SCHED set?
@@ -1037,7 +1023,7 @@ class OVSSwitch( Switch ):
inband=False, protocols=None,
reconnectms=1000, stp=False, batch=False, **params ):
"""name: name for switch
failMode: controller loss behavior (secure|standalone)
failMode: controller loss behavior (secure|open)
datapath: userspace or kernel mode (kernel|user)
inband: use in-band control (False)
protocols: use specific OpenFlow version(s) (e.g. OpenFlow13)
@@ -1360,7 +1346,7 @@ class Controller( Node ):
def __init__( self, name, inNamespace=False, command='controller',
cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1",
port=6653, protocol='tcp', **params ):
port=6633, protocol='tcp', **params ):
self.command = command
self.cargs = cargs
self.cdir = cdir
@@ -1432,16 +1418,15 @@ class Controller( Node ):
class OVSController( Controller ):
"Open vSwitch controller"
def __init__( self, name, **kwargs ):
kwargs.setdefault( 'command', self.isAvailable() or
'ovs-controller' )
Controller.__init__( self, name, **kwargs )
def __init__( self, name, command='ovs-controller', **kwargs ):
if quietRun( 'which test-controller' ):
command = 'test-controller'
Controller.__init__( self, name, command=command, **kwargs )
@classmethod
def isAvailable( cls ):
return ( quietRun( 'which ovs-controller' ) or
quietRun( 'which test-controller' ) or
quietRun( 'which ovs-testcontroller' ) ).strip()
quietRun( 'which test-controller' ) )
class NOX( Controller ):
"Controller to run a NOX application."
@@ -1495,7 +1480,7 @@ class RemoteController( Controller ):
"Controller running outside of Mininet's control."
def __init__( self, name, ip='127.0.0.1',
port=None, **kwargs):
port=6633, **kwargs):
"""Init.
name: name to give controller
ip: the IP address where the remote controller is
@@ -1513,30 +1498,12 @@ class RemoteController( Controller ):
def checkListening( self ):
"Warn if remote controller is not accessible"
if self.port is not None:
self.isListening( self.ip, self.port )
else:
for port in 6653, 6633:
if self.isListening( self.ip, port ):
self.port = port
info( "Connecting to remote controller"
" at %s:%d\n" % ( self.ip, self.port ))
break
if self.port is None:
self.port = 6653
warn( "Setting remote controller"
" to %s:%d\n" % ( self.ip, self.port ))
def isListening( self, ip, port ):
"Check if a remote controller is listening at a specific ip and port"
listening = self.cmd( "echo A | telnet -e A %s %d" % ( ip, port ) )
listening = self.cmd( "echo A | telnet -e A %s %d" %
( self.ip, self.port ) )
if 'Connected' not in listening:
warn( "Unable to contact the remote controller"
" at %s:%d\n" % ( ip, port ) )
return False
else:
return True
" at %s:%d\n" % ( self.ip, self.port ) )
DefaultControllers = ( Controller, OVSController )
+24 -10
View File
@@ -9,6 +9,7 @@ from mininet.log import info, warn
from mininet.moduledeps import pathCheck
from mininet.util import quietRun
import re
class LinuxBridge( Switch ):
"Linux Bridge (with optional spanning tree)"
@@ -72,17 +73,18 @@ class LinuxBridge( Switch ):
class NAT( Node ):
"NAT: Provides connectivity to external network"
def __init__( self, name, subnet='10.0/8',
def __init__( self, name, inetIntf=None, subnet='10.0/8',
localIntf=None, flush=False, **params):
"""Start NAT/forwarding between Mininet and external network
inetIntf: interface for internet access
subnet: Mininet subnet (default 10.0/8)
flush: flush iptables before installing NAT rules"""
super( NAT, self ).__init__( name, **params )
self.inetIntf = inetIntf if inetIntf else self.getGatewayIntf()
self.subnet = subnet
self.localIntf = localIntf
self.flush = flush
self.forwardState = self.cmd( 'sysctl -n net.ipv4.ip_forward' ).strip()
def config( self, **params ):
"""Configure the NAT and iptables"""
@@ -91,8 +93,9 @@ class NAT( Node ):
if not self.localIntf:
self.localIntf = self.defaultIntf()
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
if self.flush:
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
self.cmd( 'iptables -F' )
self.cmd( 'iptables -t nat -F' )
# Create default entries for unmatched traffic
@@ -106,9 +109,9 @@ class NAT( Node ):
self.cmd( 'iptables -A FORWARD',
'-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -A FORWARD',
'-o', self.localIntf, '-d', self.subnet,'-j ACCEPT' )
'-i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -t nat -A POSTROUTING',
'-s', self.subnet, "'!'", '-d', self.subnet, '-j MASQUERADE' )
'-o', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' )
# Instruct the kernel to perform forwarding
self.cmd( 'sysctl net.ipv4.ip_forward=1' )
@@ -127,6 +130,18 @@ class NAT( Node ):
# hopefully this won't disconnect you
self.cmd( 'service network-manager restart' )
def getGatewayIntf( self, fallback='eth0' ):
"""Return gateway interface name
fallback: default device to fall back to"""
routes = self.cmd( 'ip route show' )
match = re.search( r'default via \S+ dev (\S+)', routes )
if match:
return match.group( 1 )
else:
warn( 'There is no default route set.',
'Using', fallback, 'as gateway interface...\n' )
return fallback
def terminate( self ):
"Stop NAT/forwarding between Mininet and external network"
# Remote NAT rules
@@ -135,10 +150,9 @@ class NAT( Node ):
self.cmd( 'iptables -D FORWARD',
'-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -D FORWARD',
'-o', self.localIntf, '-d', self.subnet,'-j ACCEPT' )
'-i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -t nat -D POSTROUTING',
'-s', self.subnet, '\'!\'', '-d', self.subnet,
'-j MASQUERADE' )
# Put the forwarding state back to what it was
self.cmd( 'sysctl net.ipv4.ip_forward=%s' % self.forwardState )
'-o', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' )
# Instruct the kernel to stop forwarding
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
super( NAT, self ).terminate()
+1 -2
View File
@@ -67,8 +67,7 @@ class TorusTopo( Topo ):
switch = switches[ i, j ] = self.addSwitch(
's' + loc, dpid='%x' % dpid )
for k in range( 0, n ):
host = hosts[ i, j, k ] = self.addHost(
genHostName( loc, k + 1 ) )
host = hosts[ i, j, k ] = self.addHost( genHostName( loc, k + 1 ) )
self.addLink( host, switch )
# Connect switches
for i in range( 0, x ):
-10
View File
@@ -130,16 +130,6 @@ int main(int argc, char *argv[])
perror("unshare");
return 1;
}
/* Mark our whole hierarchy recursively as private, so that our
* mounts do not propagate to other processes.
*/
if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) == -1) {
perror("remount");
return 1;
}
/* mount sysfs to pick up the new network namespace */
if (mount("sysfs", "/sys", "sysfs", MS_MGC_VAL, NULL) == -1) {
perror("mount");
+31 -54
View File
@@ -13,7 +13,7 @@ set -o nounset
MININET_DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd -P )"
# Set up build directory, which by default is the working directory
# unless the working directory is a subdirectory of mininet,
# unless the working directory is a subdirectory of mininet,
# in which case we use the directory containing mininet
BUILD_DIR="$(pwd -P)"
case $BUILD_DIR in
@@ -36,9 +36,8 @@ if [ "$ARCH" = "i686" ]; then ARCH="i386"; fi
test -e /etc/debian_version && DIST="Debian"
grep Ubuntu /etc/lsb-release &> /dev/null && DIST="Ubuntu"
if [ "$DIST" = "Ubuntu" ] || [ "$DIST" = "Debian" ]; then
# Truly non-interactive apt-get installation
install='sudo DEBIAN_FRONTEND=noninteractive apt-get -y -q install'
remove='sudo DEBIAN_FRONTEND=noninteractive apt-get -y -q remove'
install='sudo apt-get -y install'
remove='sudo apt-get -y remove'
pkginst='sudo dpkg -i'
# Prereqs for this script
if ! which lsb_release &> /dev/null; then
@@ -46,8 +45,7 @@ if [ "$DIST" = "Ubuntu" ] || [ "$DIST" = "Debian" ]; then
fi
fi
test -e /etc/fedora-release && DIST="Fedora"
test -e /etc/redhat-release && DIST="RedHatEnterpriseServer"
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
if [ "$DIST" = "Fedora" ]; then
install='sudo yum -y install'
remove='sudo yum -y erase'
pkginst='sudo rpm -ivh'
@@ -68,8 +66,8 @@ echo "Detected Linux distribution: $DIST $RELEASE $CODENAME $ARCH"
KERNEL_NAME=`uname -r`
KERNEL_HEADERS=kernel-headers-${KERNEL_NAME}
if ! echo $DIST | egrep 'Ubuntu|Debian|Fedora|RedHatEnterpriseServer'; then
echo "Install.sh currently only supports Ubuntu, Debian, RedHat and Fedora."
if ! echo $DIST | egrep 'Ubuntu|Debian|Fedora'; then
echo "Install.sh currently only supports Ubuntu, Debian and Fedora."
exit 1
fi
@@ -125,14 +123,14 @@ function kernel_clean {
# Install Mininet deps
function mn_deps {
echo "Installing Mininet dependencies"
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
if [ "$DIST" = "Fedora" ]; then
$install gcc make socat psmisc xterm openssh-clients iperf \
iproute telnet python-setuptools libcgroup-tools \
ethtool help2man pyflakes pylint python-pep8 python-pexpect
ethtool help2man pyflakes pylint python-pep8
else
$install gcc make socat psmisc xterm ssh iperf iproute telnet \
python-setuptools cgroup-bin ethtool help2man \
pyflakes pylint pep8 python-pexpect
pyflakes pylint pep8
fi
echo "Installing Mininet core"
@@ -158,14 +156,12 @@ function of {
echo "Installing OpenFlow reference implementation..."
cd $BUILD_DIR
$install autoconf automake libtool make gcc
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
if [ "$DIST" = "Fedora" ]; then
$install git pkgconfig glibc-devel
else
$install git-core autotools-dev pkg-config libc6-dev
fi
# was: git clone git://openflowswitch.org/openflow.git
# Use our own fork on github for now:
git clone git://github.com/mininet/openflow
git clone git://openflowswitch.org/openflow.git
cd $BUILD_DIR/openflow
# Patch controller to handle more than 16 switches
@@ -228,7 +224,7 @@ function of13 {
function install_wireshark {
if ! which wireshark; then
echo "Installing Wireshark"
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
if [ "$DIST" = "Fedora" ]; then
$install wireshark wireshark-gnome
else
$install wireshark tshark
@@ -338,7 +334,7 @@ function ubuntuOvs {
function ovs {
echo "Installing Open vSwitch..."
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
if [ "$DIST" == "Fedora" ]; then
$install openvswitch openvswitch-controller
return
fi
@@ -357,28 +353,23 @@ function ovs {
fi
$install openvswitch-switch
OVSC=""
if $install openvswitch-controller; then
OVSC="openvswitch-controller"
else
echo "Attempting to install openvswitch-testcontroller"
if $install openvswitch-testcontroller; then
OVSC="openvswitch-testcontroller"
else
echo "Failed - skipping openvswitch-testcontroller"
fi
fi
if [ "$OVSC" ]; then
# Switch can run on its own, but
# Mininet should control the controller
# This appears to only be an issue on Ubuntu/Debian
if sudo service $OVSC stop; then
if sudo service openvswitch-controller stop; then
echo "Stopped running controller"
fi
if [ -e /etc/init.d/$OVSC ]; then
sudo update-rc.d $OVSC disable
if [ -e /etc/init.d/openvswitch-controller ]; then
sudo update-rc.d openvswitch-controller disable
fi
else
echo "Attempting to install openvswitch-testcontroller"
if ! $install openvswitch-testcontroller; then
echo "Failed - skipping openvswitch-testcontroller"
fi
fi
}
function remove_ovs {
@@ -424,10 +415,12 @@ function ryu {
# install Ryu dependencies"
$install autoconf automake g++ libtool python make
if [ "$DIST" = "Ubuntu" -o "$DIST" = "Debian" ]; then
if [ "$DIST" = "Ubuntu" ]; then
$install libxml2 libxslt-dev python-pip python-dev
sudo pip install --upgrade gevent pbr webob routes paramiko \\
oslo.config
sudo pip install gevent
elif [ "$DIST" = "Debian" ]; then
$install libxml2 libxslt-dev python-pip python-dev
sudo pip install gevent
fi
# if needed, update python-six
@@ -553,15 +546,13 @@ function oftest {
function cbench {
echo "Installing cbench..."
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
if [ "$DIST" = "Fedora" ]; then
$install net-snmp-devel libpcap-devel libconfig-devel
else
$install libsnmp-dev libpcap-dev libconfig-dev
fi
cd $BUILD_DIR/
# was: git clone git://gitosis.stanford.edu/oflops.git
# Use our own fork on github for now:
git clone git://github.com/mininet/oflops
git clone git://gitosis.stanford.edu/oflops.git
cd oflops
sh boot.sh || true # possible error in autoreconf, so run twice
sh boot.sh
@@ -625,7 +616,7 @@ net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee -a /etc/sysctl.conf > /dev/null
$install ntp
# Install vconfig for VLAN example
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
if [ "$DIST" = "Fedora" ]; then
$install vconfig
else
$install vlan
@@ -706,20 +697,6 @@ function vm_clean {
rm -f ~/.ssh/id_rsa* ~/.ssh/known_hosts
sudo rm -f ~/.ssh/authorized_keys*
# Remove SSH keys and regenerate on boot
echo 'Removing SSH keys from /etc/ssh/'
sudo rm -f /etc/ssh/*key*
if ! grep mininet /etc/rc.local >& /dev/null; then
sudo sed -i -e "s/exit 0//" /etc/rc.local
echo '
# mininet: regenerate ssh keys if we deleted them
if ! stat -t /etc/ssh/*key* >/dev/null 2>&1; then
/usr/sbin/dpkg-reconfigure openssh-server
fi
exit 0
' | sudo tee -a /etc/rc.local > /dev/null
fi
# Remove Mininet files
#sudo rm -f /lib/modules/python2.5/site-packages/mininet*
#sudo rm -f /usr/bin/mnexec
@@ -734,7 +711,7 @@ exit 0
# Note: you can shrink the .vmdk in vmware using
# vmware-vdiskmanager -k *.vmdk
echo "Zeroing out disk blocks for efficient compaction..."
time sudo dd if=/dev/zero of=/tmp/zero bs=1M || true
time sudo dd if=/dev/zero of=/tmp/zero bs=1M
sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero
}
+40 -37
View File
@@ -54,7 +54,6 @@ NoKVM = False # Don't use kvm and use emulation instead
Branch = None # Branch to update and check out before testing
Zip = False # Archive .ovf and .vmdk into a .zip file
Forward = [] # VM port forwarding options (-redir)
Chown = '' # Build directory owner
VMImageDir = os.environ[ 'HOME' ] + '/vm-images'
@@ -67,18 +66,36 @@ isoURLs = {
'precise64server':
'http://mirrors.kernel.org/ubuntu-releases/12.04/'
'ubuntu-12.04.5-server-amd64.iso',
'quantal32server':
'http://mirrors.kernel.org/ubuntu-releases/12.10/'
'ubuntu-12.10-server-i386.iso',
'quantal64server':
'http://mirrors.kernel.org/ubuntu-releases/12.10/'
'ubuntu-12.10-server-amd64.iso',
'raring32server':
'http://mirrors.kernel.org/ubuntu-releases/13.04/'
'ubuntu-13.04-server-i386.iso',
'raring64server':
'http://mirrors.kernel.org/ubuntu-releases/13.04/'
'ubuntu-13.04-server-amd64.iso',
'saucy32server':
'http://mirrors.kernel.org/ubuntu-releases/13.10/'
'ubuntu-13.10-server-i386.iso',
'saucy64server':
'http://mirrors.kernel.org/ubuntu-releases/13.10/'
'ubuntu-13.10-server-amd64.iso',
'trusty32server':
'http://mirrors.kernel.org/ubuntu-releases/14.04/'
'ubuntu-14.04.3-server-i386.iso',
'ubuntu-14.04-server-i386.iso',
'trusty64server':
'http://mirrors.kernel.org/ubuntu-releases/14.04/'
'ubuntu-14.04.3-server-amd64.iso',
'wily32server':
'http://mirrors.kernel.org/ubuntu-releases/15.10/'
'ubuntu-15.10-server-i386.iso',
'wily64server':
'http://mirrors.kernel.org/ubuntu-releases/15.10/'
'ubuntu-15.10-server-amd64.iso',
'ubuntu-14.04-server-amd64.iso',
'utopic32server':
'http://mirrors.kernel.org/ubuntu-releases/14.10/'
'ubuntu-14.10-server-i386.iso',
'utopic64server':
'http://mirrors.kernel.org/ubuntu-releases/14.10/'
'ubuntu-14.10-server-amd64.iso',
}
@@ -418,13 +435,12 @@ def installUbuntu( iso, image, logfilename='install.log', memory=1024 ):
log( '* Ubuntu installation completed in %.2f seconds' % elapsed )
def boot( cow, kernel, initrd, logfile, memory=1024, cpuCores=1 ):
def boot( cow, kernel, initrd, logfile, memory=1024 ):
"""Boot qemu/kvm with a COW disk and local/user data store
cow: COW disk path
kernel: kernel path
logfile: log file for pexpect object
memory: memory size in MB
cpuCores: number of CPU cores to use
returns: pexpect object to qemu process"""
# pexpect might not be installed until after depend() is called
global pexpect
@@ -453,8 +469,6 @@ def boot( cow, kernel, initrd, logfile, memory=1024, cpuCores=1 ):
'-append "root=/dev/vda1 init=/sbin/init console=ttyS0" ' ]
if Forward:
cmd += sum( [ [ '-redir', f ] for f in Forward ], [] )
if cpuCores > 1:
cmd += [ '-smp cores=%s' % cpuCores ]
cmd = ' '.join( cmd )
log( '* BOOTING VM FROM', cow )
log( cmd )
@@ -566,9 +580,6 @@ def useTest( vm, prompt=Prompt ):
log( '* Restoring logging to stdout' )
vm.logfile = stdout
# A convenient alias for use - 'run'; we might want to allow
# 'run' to take a parameter
runTest = useTest
def checkOutBranch( vm, branch, prompt=Prompt ):
# This is a bit subtle; it will check out an existing branch (e.g. master)
@@ -778,20 +789,18 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ):
post: command line to run in VM after tests
prompt: shell prompt (default '$ ')
memory: memory size in MB"""
global LogFile, Zip, Chown
global LogFile, Zip
start = time()
lstart = localtime()
date = strftime( '%y%m%d-%H-%M-%S', lstart)
ovfdate = strftime( '%y%m%d', lstart )
dir = 'mn-%s-%s' % ( flavor, date )
if Branch:
dirname = 'mn-%s-%s-%s' % ( Branch, flavor, date )
dir = 'mn-%s-%s-%s' % ( Branch, flavor, date )
try:
os.mkdir( dir)
os.mkdir( dir )
except:
raise Exception( "Failed to create build directory %s" % dir )
if Chown:
run( 'chown %s %s' % ( Chown, dir ) )
os.chdir( dir )
LogFile = open( 'build.log', 'w' )
log( '* Logging to', abspath( LogFile.name ) )
@@ -872,15 +881,14 @@ def getMininetVersion( vm ):
return version
def bootAndRun( image, prompt=Prompt, memory=1024, cpuCores=1, outputFile=None,
def bootAndRun( image, prompt=Prompt, memory=1024, outputFile=None,
runFunction=None, **runArgs ):
"""Boot and test VM
tests: list of tests to run
pre: command line to run in VM before tests
post: command line to run in VM after tests
prompt: shell prompt (default '$ ')
memory: VM memory size in MB
cpuCores: number of CPU cores to use"""
memory: VM memory size in MB"""
bootTestStart = time()
basename = path.basename( image )
image = abspath( image )
@@ -898,7 +906,7 @@ def bootAndRun( image, prompt=Prompt, memory=1024, cpuCores=1, outputFile=None,
suffix='.testlog', delete=False )
log( '* Logging VM output to', logfile.name )
vm = boot( cow=cow, kernel=kernel, initrd=initrd, logfile=logfile,
memory=memory, cpuCores=cpuCores )
memory=memory )
login( vm )
log( '* Waiting for prompt after login' )
vm.expect( prompt )
@@ -920,7 +928,7 @@ def bootAndRun( image, prompt=Prompt, memory=1024, cpuCores=1, outputFile=None,
def buildFlavorString():
"Return string listing valid build flavors"
return 'valid build flavors: %s' % ' '.join( sorted( isoURLs ) )
return 'valid build flavors: ( %s )' % ' '.join( sorted( isoURLs ) )
def testDict():
@@ -936,16 +944,15 @@ def testDict():
def testString():
"Return string listing valid tests"
tests = [ '%s <%s>' % ( name, func.__doc__ )
for name, func in testDict().iteritems() ]
return 'valid tests: %s' % ', '.join( tests )
return 'valid tests: ( %s )' % ' '.join( testDict().keys() )
def parseArgs():
"Parse command line arguments and run"
global LogToConsole, NoKVM, Branch, Zip, TIMEOUT, Forward, Chown
global LogToConsole, NoKVM, Branch, Zip, TIMEOUT, Forward
parser = argparse.ArgumentParser( description='Mininet VM build script',
epilog='' )
epilog=buildFlavorString() + ' ' +
testString() )
parser.add_argument( '-v', '--verbose', action='store_true',
help='send VM output to console rather than log file' )
parser.add_argument( '-d', '--depend', action='store_true',
@@ -965,7 +972,7 @@ def parseArgs():
help='Boot and test an existing VM image' )
parser.add_argument( '-t', '--test', metavar='test', default=[],
action='append',
help='specify a test to run; ' + testString() )
help='specify a test to run' )
parser.add_argument( '-w', '--timeout', metavar='timeout', type=int,
default=0, help='set expect timeout' )
parser.add_argument( '-r', '--run', metavar='cmd', default='',
@@ -975,15 +982,13 @@ def parseArgs():
parser.add_argument( '-b', '--branch', metavar='branch',
help='branch to install and/or check out and test' )
parser.add_argument( 'flavor', nargs='*',
help='VM flavor(s) to build; ' + buildFlavorString() )
help='VM flavor(s) to build (e.g. raring32server)' )
parser.add_argument( '-z', '--zip', action='store_true',
help='archive .ovf and .vmdk into .zip file' )
parser.add_argument( '-o', '--out',
help='output file for test image (vmdk)' )
parser.add_argument( '-f', '--forward', default=[], action='append',
help='forward VM ports to local server, e.g. tcp:5555::22' )
parser.add_argument( '-u', '--chown', metavar='user',
help='specify an owner for build directory' )
args = parser.parse_args()
if args.depend:
depend()
@@ -1005,8 +1010,6 @@ def parseArgs():
Forward = args.forward
if not args.test and not args.run and not args.post:
args.test = [ 'sanity', 'core' ]
if args.chown:
Chown = args.chown
for flavor in args.flavor:
if flavor not in isoURLs:
print "Unknown build flavor:", flavor
+1 -1
View File
@@ -43,7 +43,7 @@ fi
# Install Mininet
time mininet/util/install.sh
# Finalize VM
time mininet/util/install.sh -tcd
time mininet/util/install.sh -tc
# Ignoring this since NOX classic is deprecated
#if ! grep NOX_CORE_DIR .bashrc; then
# echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc