Compare commits

...
4 Commits
Author SHA1 Message Date
Bob Lantz 511d71a110 Add net.delNode(), net.delLink() and associated methods
This makes the mid-level net.add*() API symmetric.
You can now delete hosts, switches, controllers and links using
a new net.del*() API, as well as del net[ 'nodename' ].
2016-06-03 23:59:27 -07:00
Bob Lantz 57abd9baef Use correct command name in OVSController 2016-05-24 17:40:00 -07:00
Bob Lantz e6b0430a87 Enable TESTS={'mytest':test} in --custom files 2016-05-11 19:30:18 -07:00
Bob Lantz 475bb4d911 2.3.0d1 2016-04-26 15:13:14 -07:00
7 changed files with 114 additions and 44 deletions

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@
Mininet Installation/Configuration Notes
----------------------------------------
Mininet 2.2.2b1
Mininet 2.3.0d1
---
The supported installation methods for Mininet are 1) using a
+1 -1
View File
@@ -1,4 +1,4 @@
Mininet 2.2.2b1 License
Mininet 2.3.0d1 License
Copyright (c) 2013-2016 Open Networking Laboratory
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
+1 -1
View File
@@ -3,7 +3,7 @@ Mininet: Rapid Prototyping for Software Defined Networks
*The best way to emulate almost any network on your laptop!*
Mininet 2.2.2b1
Mininet 2.3.0d1
### What is Mininet?
+31 -26
View File
@@ -88,14 +88,15 @@ LINKS = { 'default': Link,
'ovs': OVSLink }
# optional tests to run
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
'none' ]
# Names of tests that are Mininet() methods
TESTNAMES = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
'none' ]
ALTSPELLING = { 'pingall': 'pingAll',
'pingpair': 'pingPair',
'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp' }
# Map to alternate functions and/or spellings of Mininet() methods
TESTS = { 'pingall': 'pingAll',
'pingpair': 'pingPair',
'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp' }
def addDictOption( opts, choicesDict, default, name, **kwargs ):
@@ -158,7 +159,8 @@ class MininetRunner( object ):
def setCustom( self, name, value ):
"Set custom parameters for MininetRunner."
if name in ( 'topos', 'switches', 'hosts', 'controllers', 'links' ):
if name in ( 'topos', 'switches', 'hosts', 'controllers', 'links'
'testnames', 'tests' ):
# Update dictionaries
param = name.upper()
globals()[ param ].update( value )
@@ -208,10 +210,9 @@ class MininetRunner( object ):
type='string',
help='read custom classes or params from .py file(s)'
)
opts.add_option( '--test', type='choice', choices=TESTS,
default=TESTS[ 0 ],
help='|'.join( TESTS ) )
testList = TESTNAMES + TESTS.keys()
opts.add_option( '--test', default=[], action='append',
dest='tests', help='|'.join( testList ) )
opts.add_option( '--xterms', '-x', action='store_true',
default=False, help='spawn xterms for each node' )
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
@@ -358,23 +359,27 @@ class MininetRunner( object ):
if self.options.pre:
cli( mn, script=self.options.pre )
test = self.options.test
test = ALTSPELLING.get( test, test )
mn.start()
if test == 'none':
pass
elif test == 'all':
mn.waitConnected()
mn.start()
mn.ping()
mn.iperf()
elif test == 'cli':
if not self.options.tests:
cli( mn )
elif test != 'build':
mn.waitConnected()
getattr( mn, test )()
for test in self.options.tests:
test = TESTS.get( test, test )
if callable( test ): # user added TESTMAP={'mytest': testfn}
test( mn )
elif test == 'none':
pass
elif test == 'all':
mn.waitConnected()
mn.start()
mn.ping()
mn.iperf()
elif test == 'cli':
cli( mn )
elif test != 'build':
mn.waitConnected()
getattr( mn, test )()
if self.options.post:
cli( mn, script=self.options.post )
+6 -4
View File
@@ -202,6 +202,8 @@ class Intf( object ):
# if self.node.inNamespace:
# Link may have been dumped into root NS
# quietRun( 'ip link del ' + self.name )
self.node.delIntf( self )
self.link = None
def status( self ):
"Return intf status as a string"
@@ -471,10 +473,10 @@ class Link( object ):
def delete( self ):
"Delete this link"
self.intf1.delete()
# We only need to delete one side, though this doesn't seem to
# cost us much and might help subclasses.
# self.intf2.delete()
self.intf1 = None
self.intf2.delete()
self.intf2 = None
def stop( self ):
"Override to stop and clean up link as needed"
self.delete()
+60 -6
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.2b1"
VERSION = "2.3.0d1"
class Mininet( object ):
"Network emulation with hosts spawned in network namespaces."
@@ -226,6 +226,24 @@ class Mininet( object ):
self.nameToNode[ name ] = h
return h
def delNode( self, node, nodes=None):
"""Delete node
node: node to delete
nodes: optional list to delete from (e.g. self.hosts)"""
if nodes is None:
nodes = ( self.hosts if node in self.hosts else
( self.switches if node in self.switches else
( self.controllers if node in self.controllers else
[] ) ) )
node.stop( deleteIntfs=True )
node.terminate()
nodes.remove( node )
del self.nameToNode[ node.name ]
def delHost( self, host ):
"Delete a host"
self.delNode( host, nodes=self.hosts )
def addSwitch( self, name, cls=None, **params ):
"""Add switch.
name: name of switch to add
@@ -244,6 +262,10 @@ class Mininet( object ):
self.nameToNode[ name ] = sw
return sw
def delSwitch( self, switch ):
"Delete a switch"
self.delNode( switch, nodes=self.switches )
def addController( self, name='c0', controller=None, **params ):
"""Add controller.
controller: Controller class"""
@@ -265,6 +287,12 @@ class Mininet( object ):
self.nameToNode[ name ] = controller_new
return controller_new
def delController( self, controller ):
"""Delete a controller
Warning - does not reconfigure switches, so they
may still attempt to connect to it!"""
self.delNode( controller )
def addNAT( self, name='nat0', connect=True, inNamespace=False,
**params):
"""Add a NAT to the Mininet network
@@ -303,9 +331,13 @@ class Mininet( object ):
# Even more convenient syntax for node lookup and iteration
def __getitem__( self, key ):
"""net [ name ] operator: Return node(s) with given name(s)"""
"net[ name ] operator: Return node with given name"
return self.nameToNode[ key ]
def __delitem__( self, key ):
"del net[ name ] operator - delete node with given name"
self.delNode( self.nameToNode[ key ] )
def __iter__( self ):
"return iterator over node names"
for node in chain( self.hosts, self.switches, self.controllers ):
@@ -367,6 +399,30 @@ class Mininet( object ):
self.links.append( link )
return link
def delLink( self, link ):
"Remove a link from this network"
link.delete()
self.links.remove( link )
def linksBetween( self, node1, node2 ):
"Return Links between node1 and node2"
return [ link for link in self.links
if ( node1, node2 ) in (
( link.intf1.node, link.intf2.node ),
( link.intf2.node, link.intf1.node ) ) ]
def delLinkBetween( self, node1, node2, index=0, allLinks=False ):
"""Delete link(s) between node1 and node2
index: index of link to delete if multiple links (0)
allLinks: ignore index and delete all such links (False)
returns: deleted link(s)"""
links = self.linksBetween( node1, node2 )
if not allLinks:
links = [ links[ index ] ]
for link in links:
self.delLink( link )
return links
def configHosts( self ):
"Configure a set of hosts."
for host in self.hosts:
@@ -840,10 +896,8 @@ class Mininet( object ):
elif dst not in self.nameToNode:
error( 'dst not in network: %s\n' % dst )
else:
if isinstance( src, basestring ):
src = self.nameToNode[ src ]
if isinstance( dst, basestring ):
dst = self.nameToNode[ dst ]
src = self.nameToNode[ src ]
dst = self.nameToNode[ dst ]
connections = src.connectionsTo( dst )
if len( connections ) == 0:
error( 'src and dst not connected: %s %s\n' % ( src, dst) )
+14 -5
View File
@@ -431,6 +431,15 @@ class Node( object ):
debug( 'moving', intf, 'into namespace for', self.name, '\n' )
moveIntfFn( intf.name, self )
def delIntf( self, intf ):
"""Remove interface from Node's known interfaces
Note: to fully delete interface, call intf.delete() instead"""
port = self.ports.get( intf )
if port is not None:
del self.intfs[ port ]
del self.ports[ intf ]
del self.nameToIntf[ intf.name ]
def defaultIntf( self ):
"Return interface for lowest port"
ports = self.intfs.keys()
@@ -1423,16 +1432,16 @@ class Controller( Node ):
class OVSController( Controller ):
"Open vSwitch controller"
def __init__( self, name, command='ovs-controller', **kwargs ):
if quietRun( 'which test-controller' ):
command = 'test-controller'
Controller.__init__( self, name, command=command, **kwargs )
def __init__( self, name, **kwargs ):
kwargs.setdefault( 'command', self.isAvailable() or
'ovs-controller' )
Controller.__init__( self, name, **kwargs )
@classmethod
def isAvailable( cls ):
return ( quietRun( 'which ovs-controller' ) or
quietRun( 'which test-controller' ) or
quietRun( 'which ovs-testcontroller' ) )
quietRun( 'which ovs-testcontroller' ) ).strip()
class NOX( Controller ):
"Controller to run a NOX application."