4 controlnet.py: Mininet with a custom control network
6 We create two Mininet() networks, a control network
7 and a data network, running four DataControllers on the
8 control network to control the data network.
10 Since we're using UserSwitch on the data network,
11 it should correctly fail over to a backup controller.
13 We also use a Mininet Facade to talk to both the
14 control and data networks from a single CLI.
17 from functools import partial
19 from mininet.net import Mininet
20 from mininet.node import Controller, UserSwitch
21 from mininet.cli import CLI
22 from mininet.topo import Topo
23 from mininet.topolib import TreeTopo
24 from mininet.log import setLogLevel, info
28 class DataController( Controller ):
29 """Data Network Controller.
30 patched to avoid checkListening error and to delete intfs"""
32 def checkListening( self ):
33 "Ignore spurious error"
36 def stop( self, *args, **kwargs ):
37 "Make sure intfs are deleted"
38 kwargs.update( deleteIntfs=True )
39 super( DataController, self ).stop( *args, **kwargs )
42 class MininetFacade( object ):
43 """Mininet object facade that allows a single CLI to
44 talk to one or more networks"""
46 def __init__( self, net, *args, **kwargs ):
47 """Create MininetFacade object.
48 net: Primary Mininet object
49 args: unnamed networks passed as arguments
50 kwargs: named networks passed as arguments"""
52 self.nets = [ net ] + list( args ) + list( kwargs.values() )
53 self.nameToNet = kwargs
54 self.nameToNet['net'] = net
56 def __getattr__( self, name ):
57 "returns attribute from Primary Mininet object"
58 return getattr( self.net, name )
60 def __getitem__( self, key ):
61 "returns primary/named networks or node from any net"
62 #search kwargs for net named key
63 if key in self.nameToNet:
64 return self.nameToNet[ key ]
65 #search each net for node named key
71 "Iterate through all nodes in all Mininet objects"
77 "returns aggregate number of nodes in all nets"
83 def __contains__( self, key ):
84 "returns True if node is a member of any net"
85 return key in self.keys()
88 "returns a list of all node names in all networks"
92 "returns a list of all nodes in all networks"
93 return [ self[ key ] for key in self ]
96 "returns (key,value) tuple list for every node in all networks"
97 return zip( self.keys(), self.values() )
99 # A real control network!
101 class ControlNetwork( Topo ):
102 "Control Network Topology"
103 def build( self, n, dataController=DataController, **_kwargs ):
104 """n: number of data network controller nodes
105 dataController: class for data network controllers"""
106 # Connect everything to a single switch
107 cs0 = self.addSwitch( 'cs0' )
108 # Add hosts which will serve as data network controllers
109 for i in range( 0, n ):
110 c = self.addHost( 'c%s' % i, cls=dataController,
112 self.addLink( c, cs0 )
113 # Connect switch to root namespace so that data network
114 # switches will be able to talk to us
115 root = self.addHost( 'root', inNamespace=False )
116 self.addLink( root, cs0 )
122 "Create control and data networks, and invoke the CLI"
124 info( '* Creating Control Network\n' )
125 ctopo = ControlNetwork( n=4, dataController=DataController )
126 cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', controller=None )
127 info( '* Adding Control Network Controller\n')
128 cnet.addController( 'cc0', controller=Controller )
129 info( '* Starting Control Network\n')
132 info( '* Creating Data Network\n' )
133 topo = TreeTopo( depth=2, fanout=2 )
134 # UserSwitch so we can easily test failover
135 sw = partial( UserSwitch, opts='--inactivity-probe=1 --max-backoff=1' )
136 net = Mininet( topo=topo, switch=sw, controller=None )
137 info( '* Adding Controllers to Data Network\n' )
138 for host in cnet.hosts:
139 if isinstance(host, Controller):
140 net.addController( host )
141 info( '* Starting Data Network\n')
144 mn = MininetFacade( net, cnet=cnet )
148 info( '* Stopping Data Network\n' )
151 info( '* Stopping Control Network\n' )
155 if __name__ == '__main__':
156 setLogLevel( 'info' )