From 511d71a110b29c6d01dfa8d75de90f5d9db8089d Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 2 Apr 2015 16:21:27 -0700 Subject: [PATCH] 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' ]. --- mininet/link.py | 10 ++++---- mininet/net.py | 64 +++++++++++++++++++++++++++++++++++++++++++++---- mininet/node.py | 9 +++++++ 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/mininet/link.py b/mininet/link.py index edb072b..cf1d534 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -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() diff --git a/mininet/net.py b/mininet/net.py index 96affb1..8acba20 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -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) ) diff --git a/mininet/node.py b/mininet/node.py index 1e50b51..184fa75 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -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()