Compare commits

..

25 Commits

Author SHA1 Message Date
Bob Lantz dd0abe0e12 Default ipv6 action should be 'add' 2015-04-14 14:20:07 -07:00
Bob Lantz 5a7b8f9833 setIP(): allow multiple IP addresses and IPv6 addresses
This may be a useful feature, but it doesn't fit well into
the established Mininet API, which assumes a single default
IP address for each interface.
2015-04-09 17:57:52 -07:00
Bob Lantz 1df1f9a1c5 Fix sorting & remove duplicate 2015-04-09 17:56:37 -07:00
Bob Lantz 125e669723 Support multiple --controller arguments 2015-03-30 20:40:07 -07:00
Bob Lantz a2486a6d66 Allow node.setIP() to pass extra arguments to intf.setIP() 2015-03-30 19:43:51 -07:00
Bob Lantz 15f2898f26 Add a space after ipv6.disable=1 so as not to break text boot 2015-03-30 16:26:05 -07:00
Bob Lantz 1c4adde1b6 Remove redundant processing for '/' 2015-03-24 15:22:55 -07:00
Bob Lantz 4d22991245 Allow install.sh -V on debian 2015-03-23 18:48:30 -07:00
Bob Lantz 90ea6c6bd1 Usually kernel install is unnecessary, so don't quit if it fails 2015-03-23 17:42:51 -07:00
Bob Lantz 269cecd3ee openvswitch-datapath-dkms is no longer needed for 14.04+ 2015-03-23 17:15:59 -07:00
Bob Lantz c2be20f09e Rename node.RYU to node.Ryu
Perhaps it should be RyuController, but just Ryu for now.
RYU made no sense because it's not an acronym.
2015-03-18 16:00:28 -07:00
Bob Lantz df56fa2716 2.2.1d1 -> 2.2.1d2 2015-03-18 15:47:53 -07:00
Bob Lantz f49e2539b7 Minor formatting, pass code check 2015-03-18 15:32:21 -07:00
Bob Lantz 4da7b3b7f0 Fix exception for unknown class 2015-03-18 15:31:40 -07:00
Bob Lantz e5a5cd0070 customConstructor -> customClass 2015-03-18 15:18:02 -07:00
Bob Lantz c5779deeb6 Pass code check 2015-03-18 15:17:33 -07:00
Bob Lantz 79c944aef4 Remove obsolete OVSLegacyKernelSwitch 2015-03-18 15:12:09 -07:00
Bob Lantz a23c6a2871 Fix undefined constructors in customClass() 2015-03-18 15:10:20 -07:00
Bob Lantz f6f6d9282b CustomConstructor -> CustomClass, which calls specialClass
specialClass is an analog of functools.partial but for classes.
We can now use it instead of partial() in mn, so that Mininet
can introspect on the actual base class.

Fixes #488
2015-03-13 21:17:43 -07:00
lantz 5224884e5e Merge pull request #473 from joerango/master
Support for running arbitrary command when starting terminal
2015-03-13 15:09:11 -07:00
lantz f063b023bd Merge pull request #478 from rlane/fix-readline-history
cli: don't read/write readline history more than once
2015-03-02 14:22:19 -08:00
Rich Lane a1edb167b1 Merge pull request #1 from lantz/devel/fix-readline-history
Move cmdloop() wrapper into a new run() method
2015-03-02 14:20:11 -08:00
Bob Lantz 613fac4bab Move cmdloop() wrapper into a new run() method
I also added another try/catch block so that interrupting
the 'Interrupt' message should no longer occur.
2015-02-20 16:46:18 -08:00
Rich Lane e0cd11ab21 cli: don't read/write readline history more than once
Previously, when creating multiple CLI objects, each one would append the
~/.mininet_history file to readline's internal list. When writing the file back
it would be duplicated for each CLI object created. So, over a few mininet runs
the history file would grow exponentially.

This change moves the readline setup code out of the CLI constructor into a
class method and adds a flag to prevent it from being executed more than once.
2015-02-20 10:47:43 -08:00
Joseph Beshay 5b818ad75c Support for running arbitrary command when starting terminal (other than bash) 2015-02-09 12:55:25 -06:00
15 changed files with 265 additions and 292 deletions
+1 -2
View File
@@ -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
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+14 -35
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.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
+23 -28
View File
@@ -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 )
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
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.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
View File
@@ -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
View File
@@ -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 ):
+1 -8
View File
@@ -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 ):
-28
View File
@@ -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
View File
@@ -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
View File
@@ -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