Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd0abe0e12 | |||
| 5a7b8f9833 | |||
| 1df1f9a1c5 | |||
| 125e669723 | |||
| a2486a6d66 | |||
| 15f2898f26 | |||
| 1c4adde1b6 | |||
| 4d22991245 | |||
| 90ea6c6bd1 | |||
| 269cecd3ee | |||
| c2be20f09e | |||
| df56fa2716 | |||
| f49e2539b7 | |||
| 4da7b3b7f0 | |||
| e5a5cd0070 | |||
| c5779deeb6 | |||
| 79c944aef4 | |||
| a23c6a2871 | |||
| f6f6d9282b | |||
| 5224884e5e | |||
| f063b023bd | |||
| a1edb167b1 | |||
| 613fac4bab | |||
| e0cd11ab21 | |||
| 5b818ad75c |
+1
-2
@@ -31,12 +31,11 @@ Gregory Gee
|
||||
Jon Hall
|
||||
Vitaly Ivanov
|
||||
Rich Lane
|
||||
Rémy Léone
|
||||
Zi Shen Lim
|
||||
Murphy McCauley
|
||||
José Pedro Oliveira
|
||||
James Page
|
||||
Rich Lane
|
||||
Rémy Léone
|
||||
Angad Singh
|
||||
Piyush Srivastava
|
||||
Ed Swierk
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Mininet Installation/Configuration Notes
|
||||
----------------------------------------
|
||||
|
||||
Mininet 2.2.1d1
|
||||
Mininet 2.2.1d2
|
||||
---
|
||||
|
||||
The supported installation methods for Mininet are 1) using a
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Mininet 2.2.1d1 License
|
||||
Mininet 2.2.1d2 License
|
||||
|
||||
Copyright (c) 2013-2014 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
|
||||
|
||||
|
||||
@@ -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.1d1
|
||||
Mininet 2.2.1d2
|
||||
|
||||
### What is Mininet?
|
||||
|
||||
@@ -68,44 +68,23 @@ Mininet includes:
|
||||
|
||||
### New features in this release
|
||||
|
||||
This release provides a number of bug fixes as well as
|
||||
several new features, including:
|
||||
This is primarily a performance improvement and bug fix release.
|
||||
|
||||
* Improved OpenFlow 1.3 support
|
||||
- Batch startup has been implemented for Open vSwitch, improving
|
||||
startup performance.
|
||||
|
||||
- `mn --switch ovs,protocols=openflow13` starts OVS in 1.3 mode
|
||||
- `install.sh -w` installs a 1.3-compatible Wireshark dissector using
|
||||
Loxigen
|
||||
- `install.sh -y` installs the Ryu 1.3-compatible controller
|
||||
- OVS patch links have been implemented via OVSLink and --link ovs
|
||||
|
||||
* A new `nodelib.py` node library, and new `Node` types including
|
||||
`LinuxBridge`, `OVSBridge`, `LinuxRouter` (see `examples/`)
|
||||
and `NAT`
|
||||
Warning! These links have *serious limitations* compared to
|
||||
virtual Ethernet pairs: they are not attached to real Linux
|
||||
interfaces so you cannot use tcpdump or wireshark with them;
|
||||
they also cannot be used in long chains - we don't recommend more
|
||||
than 64 OVSLinks, for example --linear,64. However, they can offer
|
||||
significantly better performance than veth pairs, for certain
|
||||
configurations.
|
||||
|
||||
* A `--nat` option which connects a Mininet network to your LAN using NAT
|
||||
(For this to work correctly, Mininet's `--ipbase` subnet should not
|
||||
overlap with any external or internet IP addresses you wish to use)
|
||||
|
||||
* An improved MiniEdit GUI (`examples/miniedit.py`) - thanks to
|
||||
Gregory Gee
|
||||
|
||||
* Support for multiple `--custom` arguments to `mn`
|
||||
|
||||
* Experimental cluster support - consult the
|
||||
[documentation](http://docs.mininet.org) for details -
|
||||
as well as `examples/cluster.py` and an experimental `--cluster`
|
||||
option for topologies built with the default `Host` and `OVSSwitch`
|
||||
classes:
|
||||
|
||||
`mn --cluster localhost,server1,server2`
|
||||
|
||||
Note that examples contain experimental features which might
|
||||
"graduate" into mainline Mininet in the future, but they should
|
||||
not be considered a stable part of the Mininet API!
|
||||
|
||||
A number of bugs have also been fixed, most notably multiple link
|
||||
support in `Topo()`. See github issues and the release notes on
|
||||
the Mininet wiki for additional information.
|
||||
- Additional information for this release and previous releases
|
||||
may be found in the release notes on docs.mininet.org
|
||||
|
||||
### Installation
|
||||
|
||||
|
||||
@@ -25,15 +25,15 @@ from mininet.cli import CLI
|
||||
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,
|
||||
Ryu, NOX, RemoteController, findController,
|
||||
DefaultController,
|
||||
UserSwitch, OVSSwitch, OVSBridge,
|
||||
OVSLegacyKernelSwitch, IVSSwitch )
|
||||
IVSSwitch )
|
||||
from mininet.nodelib import LinuxBridge
|
||||
from mininet.link import Link, TCLink, OVSLink
|
||||
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
||||
from mininet.topolib import TreeTopo, TorusTopo
|
||||
from mininet.util import customConstructor, splitArgs
|
||||
from mininet.util import customClass, specialClass, splitArgs
|
||||
from mininet.util import buildTopo
|
||||
|
||||
from functools import partial
|
||||
@@ -62,22 +62,21 @@ SWITCHES = { 'user': UserSwitch,
|
||||
'ovsbr' : OVSBridge,
|
||||
# Keep ovsk for compatibility with 2.0
|
||||
'ovsk': OVSSwitch,
|
||||
'ovsl': OVSLegacyKernelSwitch,
|
||||
'ivs': IVSSwitch,
|
||||
'lxbr': LinuxBridge,
|
||||
'default': OVSSwitch }
|
||||
|
||||
HOSTDEF = 'proc'
|
||||
HOSTS = { 'proc': Host,
|
||||
'rt': partial( CPULimitedHost, sched='rt' ),
|
||||
'cfs': partial( CPULimitedHost, sched='cfs' ) }
|
||||
'rt': specialClass( CPULimitedHost, defaults=dict( sched='rt' ) ),
|
||||
'cfs': specialClass( CPULimitedHost, defaults=dict( sched='cfs' ) ) }
|
||||
|
||||
CONTROLLERDEF = 'default'
|
||||
CONTROLLERS = { 'ref': Controller,
|
||||
'ovsc': OVSController,
|
||||
'nox': NOX,
|
||||
'remote': RemoteController,
|
||||
'ryu': RYU,
|
||||
'ryu': Ryu,
|
||||
'default': DefaultController, # Note: replaced below
|
||||
'none': lambda name: None }
|
||||
|
||||
@@ -97,24 +96,20 @@ ALTSPELLING = { 'pingall': 'pingAll',
|
||||
'iperfUDP': 'iperfUdp' }
|
||||
|
||||
|
||||
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
|
||||
def addDictOption( opts, choicesDict, default, name, helpStr=None, **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
|
||||
help: string"""
|
||||
if default not in choicesDict:
|
||||
raise Exception( 'Invalid default %s for choices dict: %s' %
|
||||
( default, name ) )
|
||||
helpStr: help string
|
||||
kwargs: additional arguments to add_option"""
|
||||
if not helpStr:
|
||||
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
|
||||
'[,param=value...]' )
|
||||
opts.add_option( '--' + name,
|
||||
type='string',
|
||||
default = default,
|
||||
help = helpStr )
|
||||
|
||||
params = dict( type='string', default=default, help=helpStr )
|
||||
params.update( **kwargs )
|
||||
opts.add_option( '--' + name, **params )
|
||||
|
||||
def version( *_args ):
|
||||
"Print Mininet version and exit"
|
||||
@@ -199,7 +194,7 @@ class MininetRunner( object ):
|
||||
opts = OptionParser( description=desc, usage=usage )
|
||||
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
|
||||
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
|
||||
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
|
||||
addDictOption( opts, CONTROLLERS, [], 'controller', action='append' )
|
||||
addDictOption( opts, LINKS, LINKDEF, 'link' )
|
||||
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
|
||||
|
||||
@@ -293,28 +288,28 @@ class MininetRunner( object ):
|
||||
|
||||
start = time.time()
|
||||
|
||||
if self.options.controller == 'default':
|
||||
if not self.options.controller:
|
||||
# Update default based on available controllers
|
||||
CONTROLLERS[ 'default' ] = findController()
|
||||
if CONTROLLERS[ 'default' ] is None:
|
||||
self.options.controller = [ 'default' ]
|
||||
if not CONTROLLERS[ 'default' ]:
|
||||
self.options.controller = [ 'none' ]
|
||||
if self.options.switch == 'default':
|
||||
info( '*** No default OpenFlow controller found '
|
||||
'for default switch!\n' )
|
||||
info( '*** Falling back to OVS Bridge\n' )
|
||||
self.options.switch = 'ovsbr'
|
||||
self.options.controller = 'none'
|
||||
elif self.options.switch in ( 'ovsbr', 'lxbr' ):
|
||||
self.options.controller = 'none'
|
||||
else:
|
||||
elif self.options.switch not in ( 'ovsbr', 'lxbr' ):
|
||||
raise Exception( "Could not find a default controller "
|
||||
"for switch %s" %
|
||||
self.options.switch )
|
||||
|
||||
topo = buildTopo( TOPOS, self.options.topo )
|
||||
switch = customConstructor( SWITCHES, self.options.switch )
|
||||
host = customConstructor( HOSTS, self.options.host )
|
||||
controller = customConstructor( CONTROLLERS, self.options.controller )
|
||||
link = customConstructor( LINKS, self.options.link )
|
||||
switch = customClass( SWITCHES, self.options.switch )
|
||||
host = customClass( HOSTS, self.options.host )
|
||||
controller = [ customClass( CONTROLLERS, c )
|
||||
for c in self.options.controller ]
|
||||
link = customClass( LINKS, self.options.link )
|
||||
|
||||
if self.validate:
|
||||
self.validate( self.options )
|
||||
|
||||
@@ -49,7 +49,7 @@ from mininet.log import info, setLogLevel
|
||||
from mininet.net import Mininet, VERSION
|
||||
from mininet.util import netParse, ipAdd, quietRun
|
||||
from mininet.util import buildTopo
|
||||
from mininet.util import custom, customConstructor
|
||||
from mininet.util import custom, customClass
|
||||
from mininet.term import makeTerm, cleanUpScreens
|
||||
from mininet.node import Controller, RemoteController, NOX, OVSController
|
||||
from mininet.node import CPULimitedHost, Host, Node
|
||||
@@ -3222,7 +3222,7 @@ class MiniEdit( Frame ):
|
||||
return
|
||||
self.newTopology()
|
||||
topo = buildTopo( TOPOS, self.options.topo )
|
||||
link = customConstructor( LINKS, self.options.link )
|
||||
link = customClass( LINKS, self.options.link )
|
||||
importNet = Mininet(topo=topo, build=False, link=link)
|
||||
importNet.build()
|
||||
|
||||
|
||||
+38
-13
@@ -45,6 +45,10 @@ class CLI( Cmd ):
|
||||
prompt = 'mininet> '
|
||||
|
||||
def __init__( self, mininet, stdin=sys.stdin, script=None ):
|
||||
"""Start and run interactive or batch mode CLI
|
||||
mininet: Mininet network object
|
||||
stdin: standard input for CLI
|
||||
script: script to run in batch mode"""
|
||||
self.mn = mininet
|
||||
# Local variable bindings for py command
|
||||
self.locals = { 'net': mininet }
|
||||
@@ -56,33 +60,54 @@ class CLI( Cmd ):
|
||||
Cmd.__init__( self )
|
||||
info( '*** Starting CLI:\n' )
|
||||
|
||||
# Set up history if readline is available
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
history_path = os.path.expanduser('~/.mininet_history')
|
||||
if os.path.isfile(history_path):
|
||||
readline.read_history_file(history_path)
|
||||
atexit.register(lambda: readline.write_history_file(history_path))
|
||||
|
||||
if self.inputFile:
|
||||
self.do_source( self.inputFile )
|
||||
return
|
||||
|
||||
self.initReadline()
|
||||
self.run()
|
||||
|
||||
readlineInited = False
|
||||
|
||||
@classmethod
|
||||
def initReadline( cls ):
|
||||
"Set up history if readline is available"
|
||||
# Only set up readline once to prevent multiplying the history file
|
||||
if cls.readlineInited:
|
||||
return
|
||||
cls.readlineInited = True
|
||||
try:
|
||||
from readline import read_history_file, write_history_file
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
history_path = os.path.expanduser( '~/.mininet_history' )
|
||||
if os.path.isfile( history_path ):
|
||||
read_history_file( history_path )
|
||||
atexit.register( lambda: write_history_file( history_path ) )
|
||||
|
||||
def run( self ):
|
||||
"Run our cmdloop(), catching KeyboardInterrupt"
|
||||
while True:
|
||||
try:
|
||||
# Make sure no nodes are still waiting
|
||||
for node in self.mn.values():
|
||||
while node.waiting:
|
||||
info( 'stopping', node, '\n' )
|
||||
node.sendInt()
|
||||
node.waitOutput()
|
||||
if self.isatty():
|
||||
quietRun( 'stty echo sane intr "^C"' )
|
||||
quietRun( 'stty echo sane intr ^C' )
|
||||
self.cmdloop()
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
output( '\nInterrupt\n' )
|
||||
# Output a message - unless it's also interrupted
|
||||
# pylint: disable=broad-except
|
||||
try:
|
||||
output( '\nInterrupt\n' )
|
||||
except Exception:
|
||||
pass
|
||||
# pylint: enable=broad-except
|
||||
|
||||
def emptyline( self ):
|
||||
"Don't repeat last command when you hit return."
|
||||
|
||||
+44
-21
@@ -67,19 +67,36 @@ class Intf( object ):
|
||||
"Configure ourselves using ifconfig"
|
||||
return self.cmd( 'ifconfig', self.name, *args )
|
||||
|
||||
def setIP( self, ipstr, prefixLen=None ):
|
||||
"""Set our IP address"""
|
||||
def setIP( self, ip, prefixLen=8, action='add' ):
|
||||
"""Set our IP address(es) and bring interface up
|
||||
ip: IP address string or list
|
||||
prefixLen: optional default prefix length if '/' not in addr (8)
|
||||
action: optional action for IPv6 addrs (default 'add')"""
|
||||
if isinstance( ip, basestring ):
|
||||
ip = ( ip, )
|
||||
ipstr = ip[ 0 ]
|
||||
# This is a sign that we should perhaps rethink our prefix
|
||||
# mechanism and/or the way we specify IP addresses
|
||||
if '/' in ipstr:
|
||||
self.ip, self.prefixLen = ipstr.split( '/' )
|
||||
return self.ifconfig( ipstr, 'up' )
|
||||
else:
|
||||
if prefixLen is None:
|
||||
raise Exception( 'No prefix length set for IP address %s'
|
||||
% ( ipstr, ) )
|
||||
self.ip, self.prefixLen = ipstr, prefixLen
|
||||
return self.ifconfig( '%s/%s' % ( ipstr, prefixLen ) )
|
||||
result = ''
|
||||
self.ips = []
|
||||
for index, ipstr in enumerate( ip ):
|
||||
if '/' in ipstr:
|
||||
ip, prefixLen = ipstr.split( '/' )
|
||||
else:
|
||||
ipstr = '%s/%s' % ( ipstr, prefixLen )
|
||||
if index == 0:
|
||||
dev = self.name
|
||||
self.ip, self.prefixLen = ip, prefixLen
|
||||
else:
|
||||
dev = '%s:%d' % ( self, index )
|
||||
if ':' not in ipstr:
|
||||
result += self.cmd( 'ifconfig', dev, ipstr, 'up' )
|
||||
else:
|
||||
# IPv6
|
||||
result += self.cmd( 'ifconfig', dev, 'inet6', action, ipstr,
|
||||
'up' )
|
||||
self.ips += [ ipstr ]
|
||||
return result
|
||||
|
||||
def setMAC( self, macstr ):
|
||||
"""Set the MAC address for an interface.
|
||||
@@ -89,18 +106,23 @@ class Intf( object ):
|
||||
self.ifconfig( 'hw', 'ether', macstr ) +
|
||||
self.ifconfig( 'up' ) )
|
||||
|
||||
_ipMatchRegex = re.compile( r'\d+\.\d+\.\d+\.\d+' )
|
||||
_ipMatchRegex = re.compile( r'inet.? (.*)/' )
|
||||
_macMatchRegex = re.compile( r'..:..:..:..:..:..' )
|
||||
|
||||
def updateIP( self ):
|
||||
"Return updated IP address based on ifconfig"
|
||||
def updateIP( self, all=False ):
|
||||
"""Return updated IP address based on ifconfig
|
||||
all: return list of all IP addresses for this interface"""
|
||||
# use pexec instead of node.cmd so that we dont read
|
||||
# backgrounded output from the cli.
|
||||
ifconfig, _err, _exitCode = self.node.pexec(
|
||||
'ifconfig %s' % self.name )
|
||||
ips = self._ipMatchRegex.findall( ifconfig )
|
||||
ipaddr, _err, _exitCode = self.node.pexec(
|
||||
'ip', 'addr', 'show', self.name )
|
||||
ips = self._ipMatchRegex.findall( ipaddr )
|
||||
self.ip = ips[ 0 ] if ips else None
|
||||
return self.ip
|
||||
self.ips = ips
|
||||
if all:
|
||||
return self.ips
|
||||
else:
|
||||
return self.ip
|
||||
|
||||
def updateMAC( self ):
|
||||
"Return updated MAC address based on ifconfig"
|
||||
@@ -122,9 +144,10 @@ class Intf( object ):
|
||||
self.mac = macs[ 0 ] if macs else None
|
||||
return self.ip, self.mac
|
||||
|
||||
def IP( self ):
|
||||
"Return IP address"
|
||||
return self.ip
|
||||
def IP( self, all=False):
|
||||
"""Return IP address
|
||||
all: return list of IP addresses for this interface (False)"""
|
||||
return self.ips if all else self.ip
|
||||
|
||||
def MAC( self ):
|
||||
"Return MAC address"
|
||||
|
||||
+2
-2
@@ -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.1d1"
|
||||
VERSION = "2.2.1d2"
|
||||
|
||||
class Mininet( object ):
|
||||
"Network emulation with hosts spawned in network namespaces."
|
||||
@@ -402,7 +402,7 @@ class Mininet( object ):
|
||||
if not isinstance( classes, list ):
|
||||
classes = [ classes ]
|
||||
for i, cls in enumerate( classes ):
|
||||
# Allow Controller objects because nobody understands currying
|
||||
# Allow Controller objects because nobody understands partial()
|
||||
if isinstance( cls, Controller ):
|
||||
self.addController( cls )
|
||||
else:
|
||||
|
||||
+23
-65
@@ -23,20 +23,26 @@ Switch: superclass for switch nodes.
|
||||
UserSwitch: a switch using the user-space switch from the OpenFlow
|
||||
reference implementation.
|
||||
|
||||
KernelSwitch: a switch using the kernel switch from the OpenFlow reference
|
||||
implementation.
|
||||
|
||||
OVSSwitch: a switch using the OpenVSwitch OpenFlow-compatible switch
|
||||
OVSSwitch: a switch using the Open vSwitch OpenFlow-compatible switch
|
||||
implementation (openvswitch.org).
|
||||
|
||||
OVSBridge: an Ethernet bridge implemented using Open vSwitch.
|
||||
Supports STP.
|
||||
|
||||
IVSSwitch: OpenFlow switch using the Indigo Virtual Switch.
|
||||
|
||||
Controller: superclass for OpenFlow controllers. The default controller
|
||||
is controller(8) from the reference implementation.
|
||||
|
||||
OVSController: The test controller from Open vSwitch.
|
||||
|
||||
NOXController: a controller node using NOX (noxrepo.org).
|
||||
|
||||
Ryu: The Ryu controller (https://osrg.github.io/ryu/)
|
||||
|
||||
RemoteController: a remote controller node, which may use any
|
||||
arbitrary OpenFlow-compatible controller, and which is not
|
||||
created or managed by mininet.
|
||||
created or managed by Mininet.
|
||||
|
||||
Future enhancements:
|
||||
|
||||
@@ -57,7 +63,7 @@ from time import sleep
|
||||
from mininet.log import info, error, warn, debug
|
||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||
numCores, retry, mountCgroups )
|
||||
from mininet.moduledeps import moduleDeps, pathCheck, OVS_KMOD, OF_KMOD, TUN
|
||||
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
||||
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
||||
from re import findall
|
||||
from distutils.version import StrictVersion
|
||||
@@ -507,15 +513,13 @@ class Node( object ):
|
||||
mac: MAC address as string"""
|
||||
return self.intf( intf ).setMAC( mac )
|
||||
|
||||
def setIP( self, ip, prefixLen=8, intf=None ):
|
||||
def setIP( self, ip, prefixLen=8, intf=None, **kwargs ):
|
||||
"""Set the IP address for an interface.
|
||||
intf: intf or intf name
|
||||
ip: IP address as a string
|
||||
prefixLen: prefix length, e.g. 8 for /8 or 16M addrs"""
|
||||
# This should probably be rethought
|
||||
if '/' not in ip:
|
||||
ip = '%s/%s' % ( ip, prefixLen )
|
||||
return self.intf( intf ).setIP( ip )
|
||||
prefixLen: prefix length, e.g. 8 for /8 or 16M addrs
|
||||
kwargs: any additional arguments for intf.setIP"""
|
||||
return self.intf( intf ).setIP( ip, prefixLen, **kwargs )
|
||||
|
||||
def IP( self, intf=None ):
|
||||
"Return IP address of a node or specific interface."
|
||||
@@ -1003,56 +1007,6 @@ class UserSwitch( Switch ):
|
||||
self.cmd( 'kill %ofprotocol' )
|
||||
super( UserSwitch, self ).stop( deleteIntfs )
|
||||
|
||||
class OVSLegacyKernelSwitch( Switch ):
|
||||
"""Open VSwitch legacy kernel-space switch using ovs-openflowd.
|
||||
Currently only works in the root namespace."""
|
||||
|
||||
def __init__( self, name, dp=None, **kwargs ):
|
||||
"""Init.
|
||||
name: name for switch
|
||||
dp: netlink id (0, 1, 2, ...)
|
||||
defaultMAC: default MAC as unsigned int; random value if None"""
|
||||
Switch.__init__( self, name, **kwargs )
|
||||
self.dp = dp if dp else self.name
|
||||
self.intf = self.dp
|
||||
if self.inNamespace:
|
||||
error( "OVSKernelSwitch currently only works"
|
||||
" in the root namespace.\n" )
|
||||
exit( 1 )
|
||||
|
||||
@classmethod
|
||||
def setup( cls ):
|
||||
"Ensure any dependencies are loaded; if not, try to load them."
|
||||
pathCheck( 'ovs-dpctl', 'ovs-openflowd',
|
||||
moduleName='Open vSwitch (openvswitch.org)')
|
||||
moduleDeps( subtract=OF_KMOD, add=OVS_KMOD )
|
||||
|
||||
def start( self, controllers ):
|
||||
"Start up kernel datapath."
|
||||
ofplog = '/tmp/' + self.name + '-ofp.log'
|
||||
# Delete local datapath if it exists;
|
||||
# then create a new one monitoring the given interfaces
|
||||
self.cmd( 'ovs-dpctl del-dp ' + self.dp )
|
||||
self.cmd( 'ovs-dpctl add-dp ' + self.dp )
|
||||
intfs = [ str( i ) for i in self.intfList() if not i.IP() ]
|
||||
self.cmd( 'ovs-dpctl', 'add-if', self.dp, ' '.join( intfs ) )
|
||||
# Run protocol daemon
|
||||
clist = ','.join( [ 'tcp:%s:%d' % ( c.IP(), c.port )
|
||||
for c in controllers ] )
|
||||
self.cmd( 'ovs-openflowd ' + self.dp +
|
||||
' ' + clist +
|
||||
' --fail=secure ' + self.opts +
|
||||
' --datapath-id=' + self.dpid +
|
||||
' 1>' + ofplog + ' 2>' + ofplog + '&' )
|
||||
self.execed = False
|
||||
|
||||
def stop( self, deleteIntfs=True ):
|
||||
"""Terminate kernel datapath."
|
||||
deleteIntfs: delete interfaces? (True)"""
|
||||
quietRun( 'ovs-dpctl del-dp ' + self.dp )
|
||||
self.cmd( 'kill %ovs-openflowd' )
|
||||
super( OVSLegacyKernelSwitch, self ).stop( deleteIntfs )
|
||||
|
||||
|
||||
class OVSSwitch( Switch ):
|
||||
"Open vSwitch switch. Depends on ovs-vsctl."
|
||||
@@ -1289,11 +1243,14 @@ OVSKernelSwitch = OVSSwitch
|
||||
class OVSBridge( OVSSwitch ):
|
||||
"OVSBridge is an OVSSwitch in standalone/bridge mode"
|
||||
|
||||
def __init__( self, args, **kwargs ):
|
||||
def __init__( self, *args, **kwargs ):
|
||||
"""stp: enable Spanning Tree Protocol (False)
|
||||
see OVSSwitch for other options"""
|
||||
kwargs.update( failMode='standalone' )
|
||||
OVSSwitch.__init__( self, args, **kwargs )
|
||||
OVSSwitch.__init__( self, *args, **kwargs )
|
||||
|
||||
def start( self, controllers ):
|
||||
"Start bridge, ignoring controllers argument"
|
||||
OVSSwitch.start( self, controllers=[] )
|
||||
|
||||
def connected( self ):
|
||||
@@ -1488,7 +1445,7 @@ class NOX( Controller ):
|
||||
cdir=noxCoreDir,
|
||||
**kwargs )
|
||||
|
||||
class RYU( Controller ):
|
||||
class Ryu( Controller ):
|
||||
"Controller to run Ryu application"
|
||||
def __init__( self, name, *ryuArgs, **kwargs ):
|
||||
"""Init.
|
||||
@@ -1510,6 +1467,7 @@ class RYU( Controller ):
|
||||
cdir=ryuCoreDir,
|
||||
**kwargs )
|
||||
|
||||
|
||||
class RemoteController( Controller ):
|
||||
"Controller running outside of Mininet's control."
|
||||
|
||||
|
||||
+3
-2
@@ -35,7 +35,7 @@ def tunnelX11( node, display=None):
|
||||
"EXEC:'mnexec -a 1 socat STDIO %s'" % connection ]
|
||||
return 'localhost:' + screen, node.popen( cmd )
|
||||
|
||||
def makeTerm( node, title='Node', term='xterm', display=None ):
|
||||
def makeTerm( node, title='Node', term='xterm', display=None, cmd='bash'):
|
||||
"""Create an X11 tunnel to the node and start up a terminal.
|
||||
node: Node object
|
||||
title: base title
|
||||
@@ -54,7 +54,8 @@ def makeTerm( node, title='Node', term='xterm', display=None ):
|
||||
display, tunnel = tunnelX11( node, display )
|
||||
if display is None:
|
||||
return []
|
||||
term = node.popen( cmds[ term ] + [ display, '-e', 'env TERM=ansi bash'] )
|
||||
term = node.popen( cmds[ term ] +
|
||||
[ display, '-e', 'env TERM=ansi %s' % cmd ] )
|
||||
return [ tunnel, term ] if tunnel else [ term ]
|
||||
|
||||
def runX11( node, cmd ):
|
||||
|
||||
@@ -8,8 +8,7 @@ import sys
|
||||
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import Host, Controller
|
||||
from mininet.node import ( UserSwitch, OVSSwitch, OVSLegacyKernelSwitch,
|
||||
IVSSwitch )
|
||||
from mininet.node import ( UserSwitch, OVSSwitch, IVSSwitch )
|
||||
from mininet.topo import Topo
|
||||
from mininet.log import setLogLevel
|
||||
from mininet.util import quietRun
|
||||
@@ -81,12 +80,6 @@ class testSwitchOVSUser( TestSwitchDpidAssignmentOVS ):
|
||||
"Test dpid assignnment of OVS User Switch."
|
||||
switchClass = OVSUser
|
||||
|
||||
@unittest.skipUnless( quietRun( 'which ovs-openflowd' ),
|
||||
'OVS Legacy Kernel switch is not installed' )
|
||||
class testSwitchOVSLegacyKernel( TestSwitchDpidAssignmentOVS ):
|
||||
"Test dpid assignnment of OVS Legacy Kernel Switch."
|
||||
switchClass = OVSLegacyKernelSwitch
|
||||
|
||||
@unittest.skipUnless( quietRun( 'which ivs-ctl' ),
|
||||
'IVS switch is not installed' )
|
||||
class testSwitchIVS( TestSwitchDpidAssignmentOVS ):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"Library of potentially useful topologies for Mininet"
|
||||
|
||||
from mininet.topo import Topo
|
||||
from mininet.nodelib import NAT
|
||||
from mininet.net import Mininet
|
||||
|
||||
# The build() method is expected to do this:
|
||||
@@ -70,31 +69,4 @@ class TorusTopo( Topo ):
|
||||
self.addLink( sw1, sw2 )
|
||||
self.addLink( sw1, sw3 )
|
||||
|
||||
def Natted( topoClass ):
|
||||
"Return a natted Topo class based on topoClass"
|
||||
class NattedTopo( topoClass ):
|
||||
"Customized topology with attached NAT"
|
||||
def build( self, *args, **kwargs ):
|
||||
"""Build topo with NAT attachment
|
||||
natIP: local IP address of NAT node for routing ('10.0.0.254')
|
||||
connect: switch to connect NAT node to ('s1')"""
|
||||
self.natIP = kwargs.pop( 'natIP', '10.0.0.254')
|
||||
self.connect = kwargs.pop( 'connect', 's1' )
|
||||
self.hopts.update( defaultRoute='via ' + self.natIP )
|
||||
super( NattedTopo, self ).build( *args, **kwargs )
|
||||
nat1 = self.addNode( 'nat1', cls=NAT, ip=self.natIP,
|
||||
inNamespace=False )
|
||||
self.addLink( self.connect, nat1 )
|
||||
return NattedTopo
|
||||
|
||||
|
||||
def natted( topoClass, *args, **kwargs ):
|
||||
"""Create and invoke natted version of topoClass
|
||||
natIP: local IP address of NAT node for routing ('10.0.0.254')
|
||||
connect: switch to connect NAT node to ('s1')
|
||||
usage: topo = natted( TreeTopo, depth=2, fanout=2 )"""
|
||||
topoClass = Natted( topoClass )
|
||||
return topoClass( *args, **kwargs )
|
||||
|
||||
|
||||
# pylint: enable=arguments-differ
|
||||
|
||||
+39
-27
@@ -523,43 +523,55 @@ def splitArgs( argstr ):
|
||||
kwargs[ key ] = makeNumeric( val )
|
||||
return fn, args, kwargs
|
||||
|
||||
def customConstructor( constructors, argStr ):
|
||||
"""Return custom constructor based on argStr
|
||||
The args and key/val pairs in argsStr will be automatically applied
|
||||
when the generated constructor is later used.
|
||||
def customClass( classes, argStr ):
|
||||
"""Return customized class based on argStr
|
||||
The args and key/val pairs in argStr will be automatically applied
|
||||
when the generated class is later used.
|
||||
"""
|
||||
cname, newargs, kwargs = splitArgs( argStr )
|
||||
constructor = constructors.get( cname, None )
|
||||
|
||||
if not constructor:
|
||||
cname, args, kwargs = splitArgs( argStr )
|
||||
cls = classes.get( cname, None )
|
||||
if not cls:
|
||||
raise Exception( "error: %s is unknown - please specify one of %s" %
|
||||
( cname, constructors.keys() ) )
|
||||
( cname, classes.keys() ) )
|
||||
if not args and not kwargs:
|
||||
return cls
|
||||
|
||||
if not newargs and not kwargs:
|
||||
return constructor
|
||||
return specialClass( cls, append=args, defaults=kwargs )
|
||||
|
||||
if not isinstance( constructor, type ):
|
||||
raise Exception( "error: invalid arguments %s" % argStr )
|
||||
def specialClass( cls, prepend=None, append=None,
|
||||
defaults=None, override=None ):
|
||||
"""Like functools.partial, but it returns a class
|
||||
prepend: arguments to prepend to argument list
|
||||
append: arguments to append to argument list
|
||||
defaults: default values for keyword arguments
|
||||
override: keyword arguments to override"""
|
||||
|
||||
# Return a customized subclass
|
||||
cls = constructor
|
||||
if prepend is None:
|
||||
prepend = []
|
||||
|
||||
if append is None:
|
||||
append = []
|
||||
|
||||
if defaults is None:
|
||||
defaults = {}
|
||||
|
||||
if override is None:
|
||||
override = {}
|
||||
|
||||
class CustomClass( cls ):
|
||||
"Customized subclass, useful for Node, Link, and other classes"
|
||||
def __init__( self, name, *args, **params ):
|
||||
params = params.copy()
|
||||
params.update( kwargs )
|
||||
if not newargs:
|
||||
cls.__init__( self, name, *args, **params )
|
||||
return
|
||||
if args:
|
||||
warn( 'warning: %s replacing %s with %s\n' %
|
||||
( constructor, args, newargs ) )
|
||||
cls.__init__( self, name, *newargs, **params )
|
||||
"Customized subclass with preset args/params"
|
||||
def __init__( self, *args, **params ):
|
||||
newparams = defaults.copy()
|
||||
newparams.update( params )
|
||||
newparams.update( override )
|
||||
cls.__init__( self, *( list( prepend ) + list( args ) +
|
||||
list( append ) ),
|
||||
**newparams )
|
||||
|
||||
CustomClass.__name__ = '%s%s' % ( cls.__name__, kwargs )
|
||||
CustomClass.__name__ = '%s%s' % ( cls.__name__, defaults )
|
||||
return CustomClass
|
||||
|
||||
|
||||
def buildTopo( topos, topoStr ):
|
||||
"""Create topology from string with format (object, arg1, arg2,...).
|
||||
input topos is a dict of topo names to constructors, possibly w/args.
|
||||
|
||||
+72
-56
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Mininet install script for Ubuntu (and Debian Lenny)
|
||||
# Mininet install script for Ubuntu (and Debian Wheezy+)
|
||||
# Brandon Heller (brandonh@stanford.edu)
|
||||
|
||||
# Fail on error
|
||||
@@ -102,7 +102,10 @@ OF13_SWITCH_REV=${OF13_SWITCH_REV:-""}
|
||||
function kernel {
|
||||
echo "Install Mininet-compatible kernel if necessary"
|
||||
sudo apt-get update
|
||||
$install linux-image-$KERNEL_NAME
|
||||
if ! $install linux-image-$KERNEL_NAME; then
|
||||
echo "Could not install linux-image-$KERNEL_NAME"
|
||||
echo "Skipping - assuming installed kernel is OK."
|
||||
fi
|
||||
}
|
||||
|
||||
function kernel_clean {
|
||||
@@ -258,53 +261,63 @@ function ubuntuOvs {
|
||||
OVS_SRC=$BUILD_DIR/openvswitch
|
||||
OVS_TARBALL_LOC=http://openvswitch.org/releases
|
||||
|
||||
if [ "$DIST" = "Ubuntu" ] && version_ge $RELEASE 12.04; then
|
||||
rm -rf $OVS_SRC
|
||||
mkdir -p $OVS_SRC
|
||||
cd $OVS_SRC
|
||||
if ! echo "$DIST" | egrep "Ubuntu|Debian" > /dev/null; then
|
||||
echo "OS must be Ubuntu or Debian"
|
||||
$cd BUILD_DIR
|
||||
return
|
||||
fi
|
||||
if [ "$DIST" = "Ubuntu" ] && ! version_ge $RELEASE 12.04; then
|
||||
echo "Ubuntu version must be >= 12.04"
|
||||
cd $BUILD_DIR
|
||||
return
|
||||
fi
|
||||
if [ "$DIST" = "Debian" ] && ! version_ge $RELEASE 7.0; then
|
||||
echo "Debian version must be >= 7.0"
|
||||
cd $BUILD_DIR
|
||||
return
|
||||
fi
|
||||
|
||||
if wget $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz 2> /dev/null; then
|
||||
tar xzf openvswitch-$OVS_RELEASE.tar.gz
|
||||
else
|
||||
echo "Failed to find OVS at $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz"
|
||||
cd $BUILD_DIR
|
||||
return
|
||||
fi
|
||||
rm -rf $OVS_SRC
|
||||
mkdir -p $OVS_SRC
|
||||
cd $OVS_SRC
|
||||
|
||||
# Remove any old packages
|
||||
$remove openvswitch-common openvswitch-datapath-dkms openvswitch-controller \
|
||||
openvswitch-pki openvswitch-switch
|
||||
|
||||
# Get build deps
|
||||
$install build-essential fakeroot debhelper autoconf automake libssl-dev \
|
||||
pkg-config bzip2 openssl python-all procps python-qt4 \
|
||||
python-zopeinterface python-twisted-conch dkms
|
||||
|
||||
# Build OVS
|
||||
cd $BUILD_DIR/openvswitch/openvswitch-$OVS_RELEASE
|
||||
DEB_BUILD_OPTIONS='parallel=2 nocheck' fakeroot debian/rules binary
|
||||
cd ..
|
||||
$pkginst openvswitch-common_$OVS_RELEASE*.deb openvswitch-datapath-dkms_$OVS_RELEASE*.deb \
|
||||
openvswitch-pki_$OVS_RELEASE*.deb openvswitch-switch_$OVS_RELEASE*.deb
|
||||
if $pkginst openvswitch-controller_$OVS_RELEASE*.deb; then
|
||||
echo "Ignoring error installing openvswitch-controller"
|
||||
fi
|
||||
|
||||
modinfo openvswitch
|
||||
sudo ovs-vsctl show
|
||||
# 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 openvswitch-controller stop; then
|
||||
echo "Stopped running controller"
|
||||
fi
|
||||
if [ -e /etc/init.d/openvswitch-controller ]; then
|
||||
sudo update-rc.d openvswitch-controller disable
|
||||
fi
|
||||
if wget $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz 2> /dev/null; then
|
||||
tar xzf openvswitch-$OVS_RELEASE.tar.gz
|
||||
else
|
||||
echo "Failed to install Open vSwitch. OS must be Ubuntu >= 12.04"
|
||||
cd $BUILD_DIR
|
||||
return
|
||||
echo "Failed to find OVS at $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz"
|
||||
cd $BUILD_DIR
|
||||
return
|
||||
fi
|
||||
|
||||
# Remove any old packages
|
||||
$remove openvswitch-common openvswitch-datapath-dkms openvswitch-controller \
|
||||
openvswitch-pki openvswitch-switch
|
||||
|
||||
# Get build deps
|
||||
$install build-essential fakeroot debhelper autoconf automake libssl-dev \
|
||||
pkg-config bzip2 openssl python-all procps python-qt4 \
|
||||
python-zopeinterface python-twisted-conch dkms
|
||||
|
||||
# Build OVS
|
||||
cd $BUILD_DIR/openvswitch/openvswitch-$OVS_RELEASE
|
||||
DEB_BUILD_OPTIONS='parallel=2 nocheck' fakeroot debian/rules binary
|
||||
cd ..
|
||||
$pkginst openvswitch-common_$OVS_RELEASE*.deb openvswitch-datapath-dkms_$OVS_RELEASE*.deb \
|
||||
openvswitch-pki_$OVS_RELEASE*.deb openvswitch-switch_$OVS_RELEASE*.deb
|
||||
if $pkginst openvswitch-controller_$OVS_RELEASE*.deb; then
|
||||
echo "Ignoring error installing openvswitch-controller"
|
||||
fi
|
||||
|
||||
modinfo openvswitch
|
||||
sudo ovs-vsctl show
|
||||
# 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 openvswitch-controller stop; then
|
||||
echo "Stopped running controller"
|
||||
fi
|
||||
if [ -e /etc/init.d/openvswitch-controller ]; then
|
||||
sudo update-rc.d openvswitch-controller disable
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -319,14 +332,17 @@ function ovs {
|
||||
return
|
||||
fi
|
||||
|
||||
# Manually installing openvswitch-datapath may be necessary
|
||||
# for manually built kernel .debs using Debian's defective kernel
|
||||
# packaging, which doesn't yield usable headers.
|
||||
if ! dpkg --get-selections | grep openvswitch-datapath; then
|
||||
# If you've already installed a datapath, assume you
|
||||
# know what you're doing and don't need dkms datapath.
|
||||
# Otherwise, install it.
|
||||
$install openvswitch-datapath-dkms
|
||||
if [ "$DIST" = "Ubuntu" ] && ! version_ge $RELEASE 14.04; then
|
||||
# Older Ubuntu versions need openvswitch-datapath/-dkms
|
||||
# Manually installing openvswitch-datapath may be necessary
|
||||
# for manually built kernel .debs using Debian's defective kernel
|
||||
# packaging, which doesn't yield usable headers.
|
||||
if ! dpkg --get-selections | grep openvswitch-datapath; then
|
||||
# If you've already installed a datapath, assume you
|
||||
# know what you're doing and don't need dkms datapath.
|
||||
# Otherwise, install it.
|
||||
$install openvswitch-datapath-dkms
|
||||
fi
|
||||
fi
|
||||
|
||||
$install openvswitch-switch
|
||||
@@ -343,7 +359,7 @@ function ovs {
|
||||
else
|
||||
echo "Attempting to install openvswitch-testcontroller"
|
||||
if ! $install openvswitch-testcontroller; then
|
||||
echo "Failed - giving up"
|
||||
echo "Failed - skipping openvswitch-testcontroller"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -567,7 +583,7 @@ net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee -a /etc/sysctl.conf > /dev/null
|
||||
# Since the above doesn't disable neighbor discovery, also do this:
|
||||
if ! grep 'ipv6.disable' /etc/default/grub; then
|
||||
sudo sed -i -e \
|
||||
's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1/' \
|
||||
's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 /' \
|
||||
/etc/default/grub
|
||||
sudo update-grub
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user