diff --git a/examples/controlnet.py b/examples/controlnet.py index 3d5dd9d1476b4a3d3e8c142328250be26bb72aa4..0b36dd7ff8ffc8507605e266047fdf22cad26c22 100755 --- a/examples/controlnet.py +++ b/examples/controlnet.py @@ -31,30 +31,43 @@ def checkListening( self ): pass -class CLI2( CLI ): - "CLI that can talk to two networks" +class MininetFacade: + "TODO: CLI that can talk to two or more networks" - def __init__( self, *args, **kwargs ): - "cnet: second network" - self.cnet = kwargs.pop( 'cnet' ) - CLI.__init__( self, *args, **kwargs ) - - def updateVars( self ): - "Update variables to include cnet" - cnet = self.cnet - nodes2 = cnet.controllers + cnet.switches + cnet.hosts - self.nodelist += nodes2 - for node in nodes2: - self.nodemap[ node.name ] = node - self.locals[ 'cnet' ] = cnet - self.locals.update( self.nodemap ) - - def cmdloop( self, *args, **kwargs ): - "Patch to add cnet if needed" - if 'cnet' not in self.locals: - self.updateVars() - CLI.cmdloop( self, *args, **kwargs ) + def __init__( self, *args ): + self.nets = args + + # default is first net + def __getattr__( self, name ): + return getattr( self.nets[ 0 ], name ) + + def __getitem__( self, key ): + for net in self.nets: + if key in net: + return net[ key ] + + def __iter__( self ): + for net in self.nets: + for node in net: + yield node + + def __len__( self ): + count = 0 + for net in self.nets: + count += len(net) + return count + + def __contains__( self, key ): + return key in self.keys() + + def keys( self ): + return list( self ) + + def values( self ): + return [ self[ key ] for key in self ] + def items( self ): + return zip( self.keys(), self.values() ) # A real control network! @@ -83,32 +96,33 @@ def __init__( self, n, dataController=DataController, **kwargs ): info( '* Creating Control Network\n' ) ctopo = ControlNetwork( n=4, dataController=DataController ) -cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', build=False ) +cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', controller=None ) info( '* Adding Control Network Controller\n') -cnet.addController( 'cc0' ) +cnet.addController( 'cc0', controller=Controller ) info( '* Starting Control Network\n') -cnet.build() cnet.start() -dataControllers = cnet.hosts[ : -1 ] # ignore 'root' node info( '* Creating Data Network\n' ) topo = TreeTopo( depth=2, fanout=2 ) # UserSwitch so we can easily test failover -net = Mininet( topo=topo, switch=UserSwitch, build=False ) +net = Mininet( topo=topo, switch=UserSwitch, controller=None ) info( '* Adding Controllers to Data Network\n' ) -net.controllers = dataControllers -net.build() +for host in cnet.hosts: + if isinstance(host, Controller): + net.addController( host ) info( '* Starting Data Network\n') net.start() -CLI2( net, cnet=cnet ) +mn = MininetFacade( net, cnet ) +mn.keys() +CLI( mn ) info( '* Stopping Data Network\n' ) net.stop() info( '* Stopping Control Network\n' ) -# dataControllers have already been stopped -cnet.hosts = list( set( cnet.hosts ) - set( dataControllers ) ) +# dataControllers have already been stopped -- now terminate is idempotent +#cnet.hosts = list( set( cnet.hosts ) - set( dataControllers ) ) cnet.stop() diff --git a/mininet/net.py b/mininet/net.py index 91ec40eabb1fa394614a88af1811adb30a025204..37b1f4fed7c0f41f766eb0f7e9d96ec92ba777ab 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -209,9 +209,16 @@ def addSwitch( self, name, cls=None, **params ): def addController( self, name='c0', controller=None, **params ): """Add controller. controller: Controller class""" + #Get controller class if not controller: controller = self.controller - controller_new = controller( name, **params ) + #Construct new controller if one is not given + if isinstance(name, Controller): + controller_new = name + name = controller_new.name + else: + controller_new = controller( name, **params ) + #Add new controller to net if controller_new: # allow controller-less setups self.controllers.append( controller_new ) self.nameToNode[ name ] = controller_new @@ -230,9 +237,9 @@ def get( self, *args ): return self.getNodeByName( *args ) # Even more convenient syntax for node lookup and iteration - def __getitem__( self, *args ): + def __getitem__( self, key ): """net [ name ] operator: Return node(s) with given name(s)""" - return self.getNodeByName( *args ) + return self.nameToNode[ key ] def __iter__( self ): "return iterator over nodes" @@ -246,15 +253,17 @@ def __len__( self ): def __contains__( self, item ): "returns True if net contains named node" - return item in self.keys() + return item in self.nameToNode def keys( self ): "return a list of all node names or net's keys" - return list( self.__iter__() ) + #TODO: fix this + return list( self ) def values( self ): "return a list of all nodes or net's values" - return [ self[name] for name in self.__iter__() ] + #TODO: fix this + return [ self[name] for name in self ] def items( self ): "return (key,value) tuple list for every node in net" @@ -307,7 +316,7 @@ def buildFromTopo( self, topo=None ): info( '*** Creating network\n' ) - if not self.controllers: + if not self.controllers and self.controller: # Add a default controller info( '*** Adding controller\n' ) classes = self.controller diff --git a/mininet/node.py b/mininet/node.py index 951b870232f6ca2659cc360e70d8855c1ec92638..895c73109281252cf7f922370f95667e7e7aa77a 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -183,7 +183,8 @@ def write( self, data ): def terminate( self ): "Send kill signal to Node and clean up after it." - os.kill( self.pid, signal.SIGKILL ) + if self.shell: + os.kill( self.pid, signal.SIGKILL ) self.cleanup() def stop( self ): @@ -1240,3 +1241,4 @@ def checkListening( self ): if 'Unable' in listening: warn( "Unable to contact the remote controller" " at %s:%d\n" % ( self.ip, self.port ) ) +