Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ce07884f4 | |||
| be53ac31d6 | |||
| 50bfbd0566 | |||
| a4d8049661 | |||
| da4c53b3c9 | |||
| 1b96ff3539 | |||
| 93d04123c6 | |||
| 22655cf9fd | |||
| fe82d2c04a | |||
| 0534932bf3 | |||
| 5f68be2273 | |||
| 68ae67dc58 | |||
| c4a85ab1d1 | |||
| ef3c885630 | |||
| bb35d04102 | |||
| ba05fd363b | |||
| e988b0f660 | |||
| b27cce08af | |||
| a38896c254 | |||
| 63ae13fcf9 | |||
| c5f6d0ff17 | |||
| ab8c4e9198 | |||
| 8daa4193c7 | |||
| 5c895eaad8 | |||
| 435d0d68b3 | |||
| 66e9845f05 | |||
| fe3340077c | |||
| c589660e17 | |||
| d9117c77e1 | |||
| 6cb68f26c9 | |||
| c60764c34f | |||
| ba723826b7 | |||
| 0165d7bdff | |||
| 2c916acc06 | |||
| 0a810b226c | |||
| 57c8f5934f | |||
| 7acc693277 | |||
| 889698f7bd |
@@ -29,10 +29,13 @@ Andrew Ferguson
|
||||
Eder Leao Fernandes
|
||||
Gregory Gee
|
||||
Jon Hall
|
||||
Roan Huang
|
||||
Vitaly Ivanov
|
||||
Babis Kaidos
|
||||
Rich Lane
|
||||
Rémy Léone
|
||||
Zi Shen Lim
|
||||
David Mahler
|
||||
Murphy McCauley
|
||||
José Pedro Oliveira
|
||||
James Page
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Mininet Installation/Configuration Notes
|
||||
----------------------------------------
|
||||
|
||||
Mininet 2.2.1d2
|
||||
Mininet 2.2.1
|
||||
---
|
||||
|
||||
The supported installation methods for Mininet are 1) using a
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Mininet 2.2.1d2 License
|
||||
Mininet 2.2.1 License
|
||||
|
||||
Copyright (c) 2013-2015 Open Networking Laboratory
|
||||
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
|
||||
|
||||
@@ -3,7 +3,7 @@ Mininet: Rapid Prototyping for Software Defined Networks
|
||||
|
||||
*The best way to emulate almost any network on your laptop!*
|
||||
|
||||
Mininet 2.2.1d2
|
||||
Mininet 2.2.1
|
||||
|
||||
### What is Mininet?
|
||||
|
||||
@@ -83,6 +83,8 @@ This is primarily a performance improvement and bug fix release.
|
||||
significantly better performance than veth pairs, for certain
|
||||
configurations.
|
||||
|
||||
- You can now easily install Mininet on a Raspberry Pi ;-)
|
||||
|
||||
- Additional information for this release and previous releases
|
||||
may be found in the release notes on docs.mininet.org
|
||||
|
||||
@@ -108,6 +110,8 @@ Mininet mailing list, `mininet-discuss` at:
|
||||
|
||||
### Join Us
|
||||
|
||||
Thanks again to all of the Mininet contributors!
|
||||
|
||||
Mininet is an open source project and is currently hosted
|
||||
at <https://github.com/mininet>. You are encouraged to download
|
||||
the code, examine it, modify it, and submit bug reports, bug fixes,
|
||||
@@ -121,12 +125,5 @@ hard work that Mininet continues to grow and improve.
|
||||
Best wishes, and we look forward to seeing what you can do with
|
||||
Mininet to change the networking world!
|
||||
|
||||
The Mininet Core Team:
|
||||
|
||||
* Bob Lantz
|
||||
* Brian O'Connor
|
||||
* Cody Burkard
|
||||
|
||||
Thanks again to all of the Mininet contributors, particularly Gregory
|
||||
Gee for his work on MiniEdit.
|
||||
|
||||
Bob Lantz
|
||||
Mininet Core Team
|
||||
|
||||
@@ -26,12 +26,13 @@ from mininet.log import lg, LEVELS, info, debug, warn, error
|
||||
from mininet.net import Mininet, MininetWithControlNet, VERSION
|
||||
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
|
||||
Ryu, NOX, RemoteController, findController,
|
||||
DefaultController,
|
||||
DefaultController, NullController,
|
||||
UserSwitch, OVSSwitch, OVSBridge,
|
||||
IVSSwitch )
|
||||
from mininet.nodelib import LinuxBridge
|
||||
from mininet.link import Link, TCLink, OVSLink
|
||||
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
||||
from mininet.topo import ( SingleSwitchTopo, LinearTopo,
|
||||
SingleSwitchReversedTopo, MinimalTopo )
|
||||
from mininet.topolib import TreeTopo, TorusTopo
|
||||
from mininet.util import customClass, specialClass, splitArgs
|
||||
from mininet.util import buildTopo
|
||||
@@ -49,7 +50,7 @@ PLACEMENT = { 'block': SwitchBinPlacer, 'random': RandomPlacer }
|
||||
|
||||
# built in topologies, created only when run
|
||||
TOPODEF = 'minimal'
|
||||
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
|
||||
TOPOS = { 'minimal': MinimalTopo,
|
||||
'linear': LinearTopo,
|
||||
'reversed': SingleSwitchReversedTopo,
|
||||
'single': SingleSwitchTopo,
|
||||
@@ -72,13 +73,14 @@ HOSTS = { 'proc': Host,
|
||||
'cfs': specialClass( CPULimitedHost, defaults=dict( sched='cfs' ) ) }
|
||||
|
||||
CONTROLLERDEF = 'default'
|
||||
|
||||
CONTROLLERS = { 'ref': Controller,
|
||||
'ovsc': OVSController,
|
||||
'nox': NOX,
|
||||
'remote': RemoteController,
|
||||
'ryu': Ryu,
|
||||
'default': DefaultController, # Note: replaced below
|
||||
'none': lambda name: None }
|
||||
'none': NullController }
|
||||
|
||||
LINKDEF = 'default'
|
||||
LINKS = { 'default': Link,
|
||||
@@ -96,17 +98,18 @@ ALTSPELLING = { 'pingall': 'pingAll',
|
||||
'iperfUDP': 'iperfUdp' }
|
||||
|
||||
|
||||
def addDictOption( opts, choicesDict, default, name, helpStr=None, **kwargs ):
|
||||
def addDictOption( opts, choicesDict, default, name, **kwargs ):
|
||||
"""Convenience function to add choices dicts to OptionParser.
|
||||
opts: OptionParser instance
|
||||
choicesDict: dictionary of valid choices, must include default
|
||||
default: default choice key
|
||||
name: long option name
|
||||
helpStr: help string
|
||||
kwargs: additional arguments to add_option"""
|
||||
if not helpStr:
|
||||
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
|
||||
'[,param=value...]' )
|
||||
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
|
||||
'[,param=value...]' )
|
||||
helpList = [ '%s=%s' % ( k, v.__name__ )
|
||||
for k, v in choicesDict.items() ]
|
||||
helpStr += ' ' + ( ' '.join( helpList ) )
|
||||
params = dict( type='string', default=default, help=helpStr )
|
||||
params.update( **kwargs )
|
||||
opts.add_option( '--' + name, **params )
|
||||
@@ -155,7 +158,7 @@ class MininetRunner( object ):
|
||||
|
||||
def setCustom( self, name, value ):
|
||||
"Set custom parameters for MininetRunner."
|
||||
if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
|
||||
if name in ( 'topos', 'switches', 'hosts', 'controllers', 'links' ):
|
||||
# Update dictionaries
|
||||
param = name.upper()
|
||||
globals()[ param ].update( value )
|
||||
@@ -235,7 +238,7 @@ class MininetRunner( object ):
|
||||
default=False, help="pin hosts to CPU cores "
|
||||
"(requires --host cfs or --host rt)" )
|
||||
opts.add_option( '--nat', action='callback', callback=self.setNat,
|
||||
help="adds a NAT to the topology that"
|
||||
help="[option=val...] adds a NAT to the topology that"
|
||||
" connects Mininet hosts to the physical network."
|
||||
" Warning: This may route any traffic on the machine"
|
||||
" that uses Mininet's"
|
||||
|
||||
Executable
+275
@@ -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()
|
||||
+3
-1
@@ -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.2.1d2"
|
||||
VERSION = "2.2.1"
|
||||
|
||||
class Mininet( object ):
|
||||
"Network emulation with hosts spawned in network namespaces."
|
||||
@@ -357,6 +357,8 @@ class Mininet( object ):
|
||||
options.setdefault( 'port1', port1 )
|
||||
if port2 is not None:
|
||||
options.setdefault( 'port2', port2 )
|
||||
if self.intf is not None:
|
||||
options.setdefault( 'intf', self.intf )
|
||||
# Set default MAC - this should probably be in Link
|
||||
options.setdefault( 'addr1', self.randMac() )
|
||||
options.setdefault( 'addr2', self.randMac() )
|
||||
|
||||
+13
-1
@@ -168,6 +168,8 @@ class Node( object ):
|
||||
|
||||
def mountPrivateDirs( self ):
|
||||
"mount private directories"
|
||||
# Avoid expanding a string into a list of chars
|
||||
assert not isinstance( self.privateDirs, basestring )
|
||||
for directory in self.privateDirs:
|
||||
if isinstance( directory, tuple ):
|
||||
# mount given private directory
|
||||
@@ -901,6 +903,12 @@ class Switch( Node ):
|
||||
debug( 'Assuming', repr( self ), 'is connected to a controller\n' )
|
||||
return True
|
||||
|
||||
def stop( self, deleteIntfs=True ):
|
||||
"""Stop switch
|
||||
deleteIntfs: delete interfaces? (True)"""
|
||||
if deleteIntfs:
|
||||
self.deleteIntfs()
|
||||
|
||||
def __repr__( self ):
|
||||
"More informative string representation"
|
||||
intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() )
|
||||
@@ -1137,7 +1145,7 @@ class OVSSwitch( Switch ):
|
||||
if self.protocols and not self.isOldOVS():
|
||||
opts += ' protocols=%s' % self.protocols
|
||||
if self.stp and self.failMode == 'standalone':
|
||||
opts += ' stp_enable=true' % self
|
||||
opts += ' stp_enable=true'
|
||||
return opts
|
||||
|
||||
def start( self, controllers ):
|
||||
@@ -1511,3 +1519,7 @@ def DefaultController( name, controllers=DefaultControllers, **kwargs ):
|
||||
if not controller:
|
||||
raise Exception( 'Could not find a default OpenFlow controller' )
|
||||
return controller( name, **kwargs )
|
||||
|
||||
def NullController( *_args, **_kwargs ):
|
||||
"Nonexistent controller - simply returns None"
|
||||
return None
|
||||
|
||||
+30
-20
@@ -7,6 +7,7 @@ This contains additional Node types which you may find to be useful.
|
||||
from mininet.node import Node, Switch
|
||||
from mininet.log import info, warn
|
||||
from mininet.moduledeps import pathCheck
|
||||
from mininet.util import quietRun
|
||||
|
||||
import re
|
||||
|
||||
@@ -59,23 +60,31 @@ class LinuxBridge( Switch ):
|
||||
|
||||
@classmethod
|
||||
def setup( cls ):
|
||||
"Make sure our class dependencies are available"
|
||||
"Check dependencies and warn about firewalling"
|
||||
pathCheck( 'brctl', moduleName='bridge-utils' )
|
||||
# Disable Linux bridge firewalling so that traffic can flow!
|
||||
for table in 'arp', 'ip', 'ip6':
|
||||
cmd = 'sysctl net.bridge.bridge-nf-call-%stables' % table
|
||||
out = quietRun( cmd ).strip()
|
||||
if out.endswith( '1' ):
|
||||
warn( 'Warning: Linux bridge may not work with', out, '\n' )
|
||||
|
||||
|
||||
class NAT( Node ):
|
||||
"NAT: Provides connectivity to external network"
|
||||
|
||||
def __init__( self, name, inetIntf=None, subnet='10.0/8',
|
||||
localIntf=None, **params):
|
||||
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)="""
|
||||
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
|
||||
|
||||
def config( self, **params ):
|
||||
"""Configure the NAT and iptables"""
|
||||
@@ -86,17 +95,15 @@ class NAT( Node ):
|
||||
|
||||
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
|
||||
|
||||
# Flush any currently active rules
|
||||
# TODO: is this safe?
|
||||
self.cmd( 'iptables -F' )
|
||||
self.cmd( 'iptables -t nat -F' )
|
||||
if self.flush:
|
||||
self.cmd( 'iptables -F' )
|
||||
self.cmd( 'iptables -t nat -F' )
|
||||
# Create default entries for unmatched traffic
|
||||
self.cmd( 'iptables -P INPUT ACCEPT' )
|
||||
self.cmd( 'iptables -P OUTPUT ACCEPT' )
|
||||
self.cmd( 'iptables -P FORWARD DROP' )
|
||||
|
||||
# Create default entries for unmatched traffic
|
||||
self.cmd( 'iptables -P INPUT ACCEPT' )
|
||||
self.cmd( 'iptables -P OUTPUT ACCEPT' )
|
||||
self.cmd( 'iptables -P FORWARD DROP' )
|
||||
|
||||
# Configure NAT
|
||||
# Install NAT rules
|
||||
self.cmd( 'iptables -I FORWARD',
|
||||
'-i', self.localIntf, '-d', self.subnet, '-j DROP' )
|
||||
self.cmd( 'iptables -A FORWARD',
|
||||
@@ -136,13 +143,16 @@ class NAT( Node ):
|
||||
return fallback
|
||||
|
||||
def terminate( self ):
|
||||
"""Stop NAT/forwarding between Mininet and external network"""
|
||||
# Flush any currently active rules
|
||||
# TODO: is this safe?
|
||||
self.cmd( 'iptables -F' )
|
||||
self.cmd( 'iptables -t nat -F' )
|
||||
|
||||
"Stop NAT/forwarding between Mininet and external network"
|
||||
# Remote NAT rules
|
||||
self.cmd( 'iptables -D FORWARD',
|
||||
'-i', self.localIntf, '-d', self.subnet, '-j DROP' )
|
||||
self.cmd( 'iptables -D FORWARD',
|
||||
'-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' )
|
||||
self.cmd( 'iptables -D FORWARD',
|
||||
'-i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' )
|
||||
self.cmd( 'iptables -t nat -D POSTROUTING',
|
||||
'-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()
|
||||
|
||||
@@ -318,6 +318,12 @@ class SingleSwitchReversedTopo( Topo ):
|
||||
port1=0, port2=( k - h + 1 ) )
|
||||
|
||||
|
||||
class MinimalTopo( SingleSwitchTopo ):
|
||||
"Minimal topology with two hosts and one switch"
|
||||
def build( self ):
|
||||
return SingleSwitchTopo.build( self, k=2 )
|
||||
|
||||
|
||||
class LinearTopo( Topo ):
|
||||
"Linear topology of k switches, with n hosts per switch."
|
||||
|
||||
|
||||
+13
-4
@@ -45,10 +45,18 @@ class TorusTopo( Topo ):
|
||||
without STP turned on! It can be used with STP, e.g.:
|
||||
# mn --topo torus,3,3 --switch lxbr,stp=1 --test pingall"""
|
||||
|
||||
def build( self, x, y ):
|
||||
def build( self, x, y, n=1 ):
|
||||
"""x: dimension of torus in x-direction
|
||||
y: dimension of torus in y-direction
|
||||
n: number of hosts per switch"""
|
||||
if x < 3 or y < 3:
|
||||
raise Exception( 'Please use 3x3 or greater for compatibility '
|
||||
'with 2.1' )
|
||||
if n == 1:
|
||||
genHostName = lambda loc, k: 'h%s' % ( loc )
|
||||
else:
|
||||
genHostName = lambda loc, k: 'h%sx%d' % ( loc, k )
|
||||
|
||||
hosts, switches, dpid = {}, {}, 0
|
||||
# Create and wire interior
|
||||
for i in range( 0, x ):
|
||||
@@ -57,9 +65,10 @@ class TorusTopo( Topo ):
|
||||
# dpid cannot be zero for OVS
|
||||
dpid = ( i + 1 ) * 256 + ( j + 1 )
|
||||
switch = switches[ i, j ] = self.addSwitch(
|
||||
's' + loc, dpid='%016x' % dpid )
|
||||
host = hosts[ i, j ] = self.addHost( 'h' + loc )
|
||||
self.addLink( host, switch )
|
||||
's' + loc, dpid='%x' % dpid )
|
||||
for k in range( 0, n ):
|
||||
host = hosts[ i, j, k ] = self.addHost( genHostName( loc, k + 1 ) )
|
||||
self.addLink( host, switch )
|
||||
# Connect switches
|
||||
for i in range( 0, x ):
|
||||
for j in range( 0, y ):
|
||||
|
||||
+24
-24
@@ -25,20 +25,20 @@ clean=false
|
||||
declare -a hosts=()
|
||||
user=$(whoami)
|
||||
SSHDIR=/tmp/mn/ssh
|
||||
USERDIR=/home/$user/.ssh
|
||||
usage=$'./clustersetup.sh [ -p|h|c ] [ host1 ] [ host2 ] ...\n
|
||||
USERDIR=$HOME/.ssh
|
||||
usage="./clustersetup.sh [ -p|h|c ] [ host1 ] [ host2 ] ...\n
|
||||
Authenticate yourself and other cluster nodes to each other
|
||||
via ssh for mininet cluster edition. By default, we use a
|
||||
temporary ssh setup. An ssh directory is mounted over
|
||||
/home/user/.ssh on each machine in the cluster.
|
||||
$USERDIR on each machine in the cluster.
|
||||
|
||||
-h: display this help
|
||||
-p: create a persistent ssh setup. This will add
|
||||
new ssh keys and known_hosts to each nodes
|
||||
/home/user/.ssh directory
|
||||
$USERDIR directory
|
||||
-c: method to clean up a temporary ssh setup.
|
||||
Any hosts taken as arguments will be cleaned
|
||||
'
|
||||
"
|
||||
|
||||
persistentSetup() {
|
||||
echo "***creating key pair"
|
||||
@@ -74,40 +74,40 @@ tempSetup() {
|
||||
echo "***creating temporary ssh directory"
|
||||
mkdir -p $SSHDIR
|
||||
echo "***creating key pair"
|
||||
ssh-keygen -t rsa -C "Cluster_Edition_Key" -f /tmp/mn/ssh/id_rsa -N '' &> /dev/null
|
||||
ssh-keygen -t rsa -C "Cluster_Edition_Key" -f $SSHDIR/id_rsa -N '' &> /dev/null
|
||||
|
||||
echo "***mounting temporary ssh directory"
|
||||
sudo mount --bind $SSHDIR /home/$user/.ssh
|
||||
sudo mount --bind $SSHDIR $USERDIR
|
||||
cp $SSHDIR/id_rsa.pub $SSHDIR/authorized_keys
|
||||
|
||||
for host in $hosts; do
|
||||
echo "***copying public key to $host"
|
||||
ssh-copy-id $user@$host &> /dev/null
|
||||
echo "***mounting remote temporary ssh directory for $host"
|
||||
ssh -o ForwardAgent=yes $user@$host "
|
||||
mkdir -p /tmp/mn/ssh
|
||||
cp /home/$user/.ssh/authorized_keys $SSHDIR/authorized_keys
|
||||
sudo mount --bind $SSHDIR /home/$user/.ssh"
|
||||
echo "***copying key pair to $host"
|
||||
scp $SSHDIR/{id_rsa,id_rsa.pub} $user@$host:$SSHDIR
|
||||
done
|
||||
for host in $hosts; do
|
||||
echo "***copying public key to $host"
|
||||
ssh-copy-id $user@$host &> /dev/null
|
||||
echo "***mounting remote temporary ssh directory for $host"
|
||||
ssh -o ForwardAgent=yes $user@$host "
|
||||
mkdir -p $SSHDIR
|
||||
cp $USERDIR/authorized_keys $SSHDIR/authorized_keys
|
||||
sudo mount --bind $SSHDIR $USERDIR"
|
||||
echo "***copying key pair to $host"
|
||||
scp $SSHDIR/{id_rsa,id_rsa.pub} $user@$host:$SSHDIR
|
||||
done
|
||||
|
||||
for host in $hosts; do
|
||||
echo "***copying known_hosts to $host"
|
||||
scp $SSHDIR/known_hosts $user@$host:$SSHDIR
|
||||
done
|
||||
for host in $hosts; do
|
||||
echo "***copying known_hosts to $host"
|
||||
scp $SSHDIR/known_hosts $user@$host:$SSHDIR
|
||||
done
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
|
||||
for host in $hosts; do
|
||||
echo "***cleaning up $host"
|
||||
ssh $user@$host "sudo umount /home/$user/.ssh
|
||||
ssh $user@$host "sudo umount $USERDIR
|
||||
sudo rm -rf $SSHDIR"
|
||||
done
|
||||
|
||||
echo "**unmounting local directories"
|
||||
sudo umount /home/$user/.ssh
|
||||
sudo umount $USERDIR
|
||||
echo "***removing temporary ssh directory"
|
||||
sudo rm -rf $SSHDIR
|
||||
echo "done!"
|
||||
|
||||
+11
-4
@@ -192,17 +192,24 @@ function of13 {
|
||||
fi
|
||||
|
||||
# Install netbee
|
||||
NBEESRC="nbeesrc-jan-10-2013"
|
||||
if [ "$DIST" = "Ubuntu" ] && version_ge $RELEASE 14.04; then
|
||||
NBEESRC="nbeesrc-feb-24-2015"
|
||||
NBEEDIR="netbee"
|
||||
else
|
||||
NBEESRC="nbeesrc-jan-10-2013"
|
||||
NBEEDIR="nbeesrc-jan-10-2013"
|
||||
fi
|
||||
|
||||
NBEEURL=${NBEEURL:-http://www.nbee.org/download/}
|
||||
wget -nc ${NBEEURL}${NBEESRC}.zip
|
||||
unzip ${NBEESRC}.zip
|
||||
cd ${NBEESRC}/src
|
||||
cd ${NBEEDIR}/src
|
||||
cmake .
|
||||
make
|
||||
cd $BUILD_DIR/
|
||||
sudo cp ${NBEESRC}/bin/libn*.so /usr/local/lib
|
||||
sudo cp ${NBEEDIR}/bin/libn*.so /usr/local/lib
|
||||
sudo ldconfig
|
||||
sudo cp -R ${NBEESRC}/include/ /usr/
|
||||
sudo cp -R ${NBEEDIR}/include/ /usr/
|
||||
|
||||
# Resume the install:
|
||||
cd $BUILD_DIR/ofsoftswitch13
|
||||
|
||||
+1
-1
@@ -323,7 +323,7 @@ zerombr yes
|
||||
clearpart --all --initlabel
|
||||
#Automatic partitioning
|
||||
autopart
|
||||
#System authorization infomation
|
||||
#System authorization information
|
||||
auth --useshadow --enablemd5
|
||||
#Firewall configuration
|
||||
firewall --disabled
|
||||
|
||||
Reference in New Issue
Block a user