Merge branch 'master' into nat
Conflicts: mininet/net.py mininet/node.py
This commit is contained in:
@@ -117,3 +117,8 @@ memory and `sysctl` configuration (see `INSTALL`.)
|
||||
|
||||
This example creates a 64-host tree network, and attempts to check full
|
||||
connectivity using `ping`, for different switch/datapath types.
|
||||
|
||||
#### numberedports.py
|
||||
|
||||
This example verifies the mininet ofport numbers match up to the ovs port numbers.
|
||||
It also verifies that the port numbers match up to the interface numbers
|
||||
|
||||
+42
-167
@@ -1,197 +1,72 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
bind.py: Bind mount prototype
|
||||
bind.py: Bind mount example
|
||||
|
||||
This creates hosts with private directories as desired.
|
||||
This creates hosts with private directories that the user specifies.
|
||||
These hosts may have persistent directories that will be available
|
||||
across multiple mininet session, or temporary directories that will
|
||||
only last for one mininet session. To specify a persistent
|
||||
directory, add a tuple to a list of private directories:
|
||||
|
||||
[ ( 'directory to be mounted on', 'directory to be mounted' ) ]
|
||||
|
||||
String expansion may be used to create a directory template for
|
||||
each host. To do this, add a %(name)s in place of the host name
|
||||
when creating your list of directories:
|
||||
|
||||
[ ( '/var/run', '/tmp/%(name)s/var/run' ) ]
|
||||
|
||||
If no persistent directory is specified, the directories will default
|
||||
to temporary private directories. To do this, simply create a list of
|
||||
directories to be made private. A tmpfs will then be mounted on them.
|
||||
|
||||
You may use both temporary and persistent directories at the same
|
||||
time. In the following privateDirs string, each host will have a
|
||||
persistent directory in the root filesystem at
|
||||
"/tmp/(hostname)/var/run" mounted on "/var/run". Each host will also
|
||||
have a temporary private directory mounted on "/var/log".
|
||||
|
||||
[ ( '/var/run', '/tmp/%(name)s/var/run' ), '/var/log' ]
|
||||
|
||||
This example has both persistent directories mounted on '/var/log'
|
||||
and '/var/run'. It also has a temporary private directory mounted
|
||||
on '/var/mn'
|
||||
"""
|
||||
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import Host
|
||||
from mininet.node import Host, HostWithPrivateDirs
|
||||
from mininet.cli import CLI
|
||||
from mininet.util import errFail, quietRun, errRun
|
||||
from mininet.topo import SingleSwitchTopo
|
||||
from mininet.log import setLogLevel, info, debug
|
||||
|
||||
from os.path import realpath
|
||||
from functools import partial
|
||||
|
||||
|
||||
# Utility functions for unmounting a tree
|
||||
|
||||
MNRUNDIR = realpath( '/var/run/mn' )
|
||||
|
||||
def mountPoints():
|
||||
"Return list of mounted file systems"
|
||||
mtab, _err, _ret = errFail( 'cat /proc/mounts' )
|
||||
lines = mtab.split( '\n' )
|
||||
mounts = []
|
||||
for line in lines:
|
||||
if not line:
|
||||
continue
|
||||
fields = line.split( ' ')
|
||||
mount = fields[ 1 ]
|
||||
mounts.append( mount )
|
||||
return mounts
|
||||
|
||||
def unmountAll( rootdir=MNRUNDIR ):
|
||||
"Unmount all mounts under a directory tree"
|
||||
rootdir = realpath( rootdir )
|
||||
# Find all mounts below rootdir
|
||||
# This is subtle because /foo is not
|
||||
# a parent of /foot
|
||||
dirslash = rootdir + '/'
|
||||
mounts = [ m for m in mountPoints()
|
||||
if m == dir or m.find( dirslash ) == 0 ]
|
||||
# Unmount them from bottom to top
|
||||
mounts.sort( reverse=True )
|
||||
for mount in mounts:
|
||||
debug( 'Unmounting', mount, '\n' )
|
||||
_out, err, code = errRun( 'umount', mount )
|
||||
if code != 0:
|
||||
info( '*** Warning: failed to umount', mount, '\n' )
|
||||
info( err )
|
||||
|
||||
|
||||
class HostWithPrivateDirs( Host ):
|
||||
"Host with private directories"
|
||||
|
||||
mnRunDir = MNRUNDIR
|
||||
|
||||
def __init__(self, name, *args, **kwargs ):
|
||||
"""privateDirs: list of private directories
|
||||
remounts: dirs to remount
|
||||
unmount: unmount dirs in cleanup? (True)
|
||||
Note: if unmount is False, you must call unmountAll()
|
||||
manually."""
|
||||
self.privateDirs = kwargs.pop( 'privateDirs', [] )
|
||||
self.remounts = kwargs.pop( 'remounts', [] )
|
||||
self.unmount = kwargs.pop( 'unmount', True )
|
||||
Host.__init__( self, name, *args, **kwargs )
|
||||
self.rundir = '%s/%s' % ( self.mnRunDir, name )
|
||||
self.root, self.private = None, None # set in createBindMounts
|
||||
if self.privateDirs:
|
||||
self.privateDirs = [ realpath( d ) for d in self.privateDirs ]
|
||||
self.createBindMounts()
|
||||
# These should run in the namespace before we chroot,
|
||||
# in order to put the right entries in /etc/mtab
|
||||
# Eventually this will allow a local pid space
|
||||
# Now we chroot and cd to wherever we were before.
|
||||
pwd = self.cmd( 'pwd' ).strip()
|
||||
self.sendCmd( 'exec chroot', self.root, 'bash -ms mininet:'
|
||||
+ self.name )
|
||||
self.waiting = False
|
||||
self.cmd( 'cd', pwd )
|
||||
# In order for many utilities to work,
|
||||
# we need to remount /proc and /sys
|
||||
self.cmd( 'mount /proc' )
|
||||
self.cmd( 'mount /sys' )
|
||||
|
||||
def mountPrivateDirs( self ):
|
||||
"Create and bind mount private dirs"
|
||||
for dir_ in self.privateDirs:
|
||||
privateDir = self.private + dir_
|
||||
errFail( 'mkdir -p ' + privateDir )
|
||||
mountPoint = self.root + dir_
|
||||
errFail( 'mount -B %s %s' %
|
||||
( privateDir, mountPoint) )
|
||||
|
||||
def mountDirs( self, dirs ):
|
||||
"Mount a list of directories"
|
||||
for dir_ in dirs:
|
||||
mountpoint = self.root + dir_
|
||||
errFail( 'mount -B %s %s' %
|
||||
( dir_, mountpoint ) )
|
||||
|
||||
@classmethod
|
||||
def findRemounts( cls, fstypes=None ):
|
||||
"""Identify mount points in /proc/mounts to remount
|
||||
fstypes: file system types to match"""
|
||||
if fstypes is None:
|
||||
fstypes = [ 'nfs' ]
|
||||
dirs = quietRun( 'cat /proc/mounts' ).strip().split( '\n' )
|
||||
remounts = []
|
||||
for dir_ in dirs:
|
||||
line = dir_.split()
|
||||
mountpoint, fstype = line[ 1 ], line[ 2 ]
|
||||
# Don't re-remount directories!!!
|
||||
if mountpoint.find( cls.mnRunDir ) == 0:
|
||||
continue
|
||||
if fstype in fstypes:
|
||||
remounts.append( mountpoint )
|
||||
return remounts
|
||||
|
||||
def createBindMounts( self ):
|
||||
"""Create a chroot directory structure,
|
||||
with self.privateDirs as private dirs"""
|
||||
errFail( 'mkdir -p '+ self.rundir )
|
||||
unmountAll( self.rundir )
|
||||
# Create /root and /private directories
|
||||
self.root = self.rundir + '/root'
|
||||
self.private = self.rundir + '/private'
|
||||
errFail( 'mkdir -p ' + self.root )
|
||||
errFail( 'mkdir -p ' + self.private )
|
||||
# Recursively mount / in private doort
|
||||
# note we'll remount /sys and /proc later
|
||||
errFail( 'mount -B / ' + self.root )
|
||||
self.mountDirs( self.remounts )
|
||||
self.mountPrivateDirs()
|
||||
|
||||
def unmountBindMounts( self ):
|
||||
"Unmount all of our bind mounts"
|
||||
unmountAll( self.rundir )
|
||||
|
||||
def popen( self, *args, **kwargs ):
|
||||
"Popen with chroot support"
|
||||
chroot = kwargs.pop( 'chroot', True )
|
||||
mncmd = kwargs.get( 'mncmd',
|
||||
[ 'mnexec', '-a', str( self.pid ) ] )
|
||||
if chroot:
|
||||
mncmd = [ 'chroot', self.root ] + mncmd
|
||||
kwargs[ 'mncmd' ] = mncmd
|
||||
return Host.popen( self, *args, **kwargs )
|
||||
|
||||
def cleanup( self ):
|
||||
"""Clean up, then unmount bind mounts
|
||||
unmount: actually unmount bind mounts?"""
|
||||
# Wait for process to actually terminate
|
||||
self.shell.wait()
|
||||
Host.cleanup( self )
|
||||
if self.unmount:
|
||||
self.unmountBindMounts()
|
||||
errFail( 'rmdir ' + self.root )
|
||||
|
||||
|
||||
# Convenience aliases
|
||||
|
||||
findRemounts = HostWithPrivateDirs.findRemounts
|
||||
|
||||
|
||||
# Sample usage
|
||||
|
||||
def testHostWithPrivateDirs():
|
||||
"Test bind mounts"
|
||||
topo = SingleSwitchTopo( 10 )
|
||||
remounts = findRemounts( fstypes=[ 'nfs' ] )
|
||||
privateDirs = [ '/var/log', '/var/run' ]
|
||||
host = partial( HostWithPrivateDirs, remounts=remounts,
|
||||
privateDirs=privateDirs, unmount=False )
|
||||
privateDirs = [ ( '/var/log', '/tmp/%(name)s/var/log' ),
|
||||
( '/var/run', '/tmp/%(name)s/var/run' ),
|
||||
'/var/mn' ]
|
||||
host = partial( HostWithPrivateDirs,
|
||||
privateDirs=privateDirs )
|
||||
net = Mininet( topo=topo, host=host )
|
||||
net.start()
|
||||
info( 'Private Directories:', privateDirs, '\n' )
|
||||
directories = []
|
||||
for directory in privateDirs:
|
||||
directories.append( directory[ 0 ]
|
||||
if isinstance( directory, tuple )
|
||||
else directory )
|
||||
info( 'Private Directories:', directories, '\n' )
|
||||
CLI( net )
|
||||
net.stop()
|
||||
# We do this all at once to save a bit of time
|
||||
info( 'Unmounting host bind mounts...\n' )
|
||||
unmountAll()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unmountAll()
|
||||
setLogLevel( 'info' )
|
||||
testHostWithPrivateDirs()
|
||||
info( 'Done.\n')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ from mininet.log import setLogLevel
|
||||
def multiControllerNet():
|
||||
"Create a network from semi-scratch with multiple controllers."
|
||||
|
||||
net = Mininet( controller=Controller, switch=OVSSwitch, build=False )
|
||||
net = Mininet( controller=Controller, switch=OVSSwitch )
|
||||
|
||||
print "*** Creating (reference) controllers"
|
||||
c1 = net.addController( 'c1', port=6633 )
|
||||
|
||||
@@ -24,7 +24,7 @@ of switches, this example demonstrates:
|
||||
"""
|
||||
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import UserSwitch, OVSKernelSwitch
|
||||
from mininet.node import UserSwitch, OVSKernelSwitch, Controller
|
||||
from mininet.topo import Topo
|
||||
from mininet.log import lg
|
||||
from mininet.util import irange
|
||||
@@ -76,7 +76,7 @@ def linearBandwidthTest( lengths ):
|
||||
print "*** testing", datapath, "datapath"
|
||||
Switch = switches[ datapath ]
|
||||
results[ datapath ] = []
|
||||
net = Mininet( topo=topo, switch=Switch )
|
||||
net = Mininet( topo=topo, switch=Switch, controller=Controller, waitConnected=True )
|
||||
net.start()
|
||||
print "*** testing basic connectivity"
|
||||
for n in lengths:
|
||||
|
||||
+2684
-85
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -59,13 +59,13 @@ def fixNetworkManager( root, intf ):
|
||||
cfile = '/etc/network/interfaces'
|
||||
line = '\niface %s inet manual\n' % intf
|
||||
config = open( cfile ).read()
|
||||
if ( line ) not in config:
|
||||
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' )
|
||||
# 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
|
||||
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
Create a network with 5 hosts, numbered 1-4 and 9.
|
||||
Validate that the port numbers match to the interface name,
|
||||
and that the ovs ports match the mininet ports.
|
||||
"""
|
||||
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import Controller
|
||||
from mininet.log import setLogLevel, info, warn
|
||||
from mininet.node import Node
|
||||
|
||||
def validatePort( switch, intf ):
|
||||
"Validate intf's OF port number"
|
||||
ofport = int( switch.cmd( 'ovs-vsctl get Interface', intf,
|
||||
'ofport' ) )
|
||||
if ofport != switch.ports[ intf ]:
|
||||
warn( 'WARNING: ofport for', intf, 'is actually', ofport, '\n' )
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
def net():
|
||||
|
||||
"Create a network with 5 hosts."
|
||||
|
||||
net = Mininet( controller=Controller )
|
||||
|
||||
info( '*** Adding controller\n' )
|
||||
net.addController( 'c0' )
|
||||
|
||||
info( '*** Adding hosts\n' )
|
||||
h1 = net.addHost( 'h1', ip='10.0.0.1' )
|
||||
h2 = net.addHost( 'h2', ip='10.0.0.2' )
|
||||
h3 = net.addHost( 'h3', ip='10.0.0.3' )
|
||||
h4 = net.addHost( 'h4', ip='10.0.0.4' )
|
||||
h5 = net.addHost( 'h5', ip='10.0.0.5' )
|
||||
|
||||
info( '*** Adding switch\n' )
|
||||
s1 = net.addSwitch( 's1' )
|
||||
|
||||
info( '*** Creating links\n' )
|
||||
# host 1-4 connect to ports 1-4 on the switch
|
||||
net.addLink( h1, s1 )
|
||||
net.addLink( h2, s1 )
|
||||
net.addLink( h3, s1 )
|
||||
net.addLink( h4, s1 )
|
||||
net.addLink( h5, s1, port1 = 1, port2 = 9 ) # specify a different port to connect host 5 to on the switch.
|
||||
|
||||
root = Node( 'root', inNamespace=False )
|
||||
info( '*** Starting network\n' )
|
||||
net.start()
|
||||
|
||||
# print the interfaces and their port numbers
|
||||
info( '\n*** printing and validating the ports running on each interface\n' )
|
||||
for intfs in s1.intfList():
|
||||
if not intfs.name == "lo":
|
||||
info( intfs, ': ', s1.ports[intfs],
|
||||
'\n' )
|
||||
info ( 'Validating that', intfs, 'is actually on port', s1.ports[intfs], '... ' )
|
||||
if validatePort( s1, intfs ):
|
||||
info( 'Validated.\n' )
|
||||
print '\n'
|
||||
|
||||
# test the network with pingall
|
||||
net.pingAll()
|
||||
print '\n'
|
||||
|
||||
info( '*** Stopping network' )
|
||||
net.stop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'info' )
|
||||
net()
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ def sshd( network, cmd='/usr/sbin/sshd', opts='-D',
|
||||
if not switch:
|
||||
switch = network[ 's1' ] # switch to use
|
||||
if not routes:
|
||||
routes = [ '10.0.0.0/24' ]
|
||||
routes = [ '10.0.0.0/24' ]
|
||||
connectToRootNS( network, switch, ip, routes )
|
||||
for host in network.hosts:
|
||||
host.cmd( cmd + ' ' + opts + '&' )
|
||||
|
||||
@@ -5,12 +5,14 @@ Test for hwintf.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
import re
|
||||
|
||||
import pexpect
|
||||
|
||||
from mininet.log import setLogLevel
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import Node
|
||||
from mininet.link import Link, Intf
|
||||
from mininet.link import Link
|
||||
|
||||
|
||||
class testHwintf( unittest.TestCase ):
|
||||
|
||||
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test for numberedports.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from collections import defaultdict
|
||||
from mininet.node import OVSSwitch
|
||||
|
||||
class testNumberedports( unittest.TestCase ):
|
||||
|
||||
@unittest.skipIf( OVSSwitch.setup() or OVSSwitch.isOldOVS(), "old version of OVS" )
|
||||
def testConsistency( self ):
|
||||
"""verify consistency between mininet and ovs ports"""
|
||||
p = pexpect.spawn( 'python -m mininet.examples.numberedports' )
|
||||
opts = [ 'Validating that s1-eth\d is actually on port \d ... Validated.',
|
||||
'Validating that s1-eth\d is actually on port \d ... WARNING',
|
||||
pexpect.EOF ]
|
||||
correct_ports = True
|
||||
count = 0
|
||||
while True:
|
||||
index = p.expect( opts )
|
||||
if index == 0:
|
||||
count += 1
|
||||
elif index == 1:
|
||||
correct_ports = False
|
||||
elif index == 2:
|
||||
self.assertNotEqual( 0, count )
|
||||
break
|
||||
self.assertTrue( correct_ports )
|
||||
|
||||
def testNumbering( self ):
|
||||
"""verify that all of the port numbers are printed correctly and consistent with their interface"""
|
||||
p = pexpect.spawn( 'python -m mininet.examples.numberedports' )
|
||||
opts = [ 's1-eth(\d+) : (\d+)',
|
||||
pexpect.EOF ]
|
||||
count_intfs = 0
|
||||
while True:
|
||||
index = p.expect( opts )
|
||||
if index == 0:
|
||||
count_intfs += 1
|
||||
intfport = p.match.group( 1 )
|
||||
ofport = p.match.group( 2 )
|
||||
self.assertEqual( intfport, ofport )
|
||||
elif index == 1:
|
||||
break
|
||||
self.assertNotEqual( 0, count_intfs )
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -24,7 +24,7 @@ class testSimplePerf( unittest.TestCase ):
|
||||
# check ping results
|
||||
p.expect( "Results: (\d+)% dropped", timeout=120 )
|
||||
loss = int( p.match.group( 1 ) )
|
||||
self.assertTrue( loss > 0 and loss < 100 )
|
||||
self.assertTrue( 0 < loss < 100 )
|
||||
# check iperf results
|
||||
p.expect( "Results: \['([\d\.]+) .bits/sec", timeout=480 )
|
||||
bw = float( p.match.group( 1 ) )
|
||||
@@ -46,7 +46,7 @@ class testSimplePerf( unittest.TestCase ):
|
||||
m = re.search( expectStr, output )
|
||||
loss = int( m.group( 3 ) )
|
||||
net.stop()
|
||||
self.assertTrue( loss > 0 and loss < 100 )
|
||||
self.assertTrue( 0 < loss < 100 )
|
||||
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'warning' )
|
||||
|
||||
@@ -6,7 +6,6 @@ Test for sshd.py
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from time import sleep
|
||||
from mininet.clean import sh
|
||||
|
||||
class testSSHD( unittest.TestCase ):
|
||||
|
||||
Reference in New Issue
Block a user