blob: 431301408bc2350c3aa450b0b49dd422b6f43cce [file] [log] [blame]
Naoki Shiota2322a2f2014-05-21 19:47:40 -07001#!/usr/bin/env python
2
3"""
4start_topo.py : Mininet topology builder for multiple controller.
5
6This script reads config file and creates a Mininet topology.
7
8Usage:
9
10 $ sudo -E start_topo.py [filename]
11
12 filename: Config filename to specify topology.
13 If omitted, "topo.`hostname`.py" or "topo.py" in current
14 directory will be used.
15"""
16
17import platform
18import time
19import os.path
20import getpass
21from sys import argv
22from time import sleep
23
24from mininet.node import Controller, OVSSwitch, RemoteController
25from mininet.net import Mininet
26from mininet.cli import CLI
27from mininet.topo import Topo
28from mininet.log import setLogLevel, info, warn
29
30usage = """
31Usage: Create Mininet topology.
32 $ sudo -E %s [filename]
33 filename: config file (topo.`hostname`.py by default)
34""" % os.path.basename( argv[0] )
35
36# Mininet must be run by root user
37if ( getpass.getuser() != 'root' ):
38 print usage
39 exit( 0 )
40
41argc = len( argv )
42if ( argc > 2 ):
43 print usage
44 exit( 0 )
45
46if ( argc == 2 and ( argv[ 1 ] == "-h" or argv[ 1 ] == "--help" ) ):
47 print usage
48 exit( 0 )
49
50if ( argc == 2 ):
51 topofile = argv[1]
52else:
53 hostname = platform.node()
54 default_topo = 'topo.%s.py' % hostname
55 fallback_topo = 'topo.py'
Naoki Shiota801875c2014-05-29 17:06:06 -070056 if os.path.exists(default_topo):
57 topofile = default_topo
58 else:
59 topofile = fallback_topo
Naoki Shiota2322a2f2014-05-21 19:47:40 -070060
61if not os.path.exists( topofile ):
Naoki Shiota801875c2014-05-29 17:06:06 -070062 print( 'Config file %s not found' % topofile )
Naoki Shiota2322a2f2014-05-21 19:47:40 -070063 exit( 1 )
64
65execfile( topofile )
66conf = createTopo()
Naoki Shiota2322a2f2014-05-21 19:47:40 -070067
68class ConfigTopo( Topo ):
69 "Topology created from config."
70
71 def __init__( self, *args, **kwargs ):
72 "Create custom topo."
73
74 Topo.__init__( self, *args, **kwargs )
75
76 # Add hosts and switches
77 nmap = {}
78 for s, prop in conf[ 'switches' ].iteritems():
Naoki Shiota801875c2014-05-29 17:06:06 -070079 s = s.strip()
80 dpid = None
81 if 'dpid' in prop:
82 dpid = prop[ 'dpid' ].strip()
Naoki Shiota2322a2f2014-05-21 19:47:40 -070083 nmap[ s ] = self.addSwitch( s, dpid=dpid )
84
85 for h, prop in conf[ 'hosts' ].iteritems():
Naoki Shiota801875c2014-05-29 17:06:06 -070086 h = h.strip()
87 params = {}
88 if 'mac' in prop:
89 mac = prop[ 'mac' ].strip()
90 params[ 'mac' ] = mac
91 if 'ip' in prop:
92 ip = prop[ 'ip' ].strip()
93 params[ 'ip' ] = ip
94 nmap[ h ] = self.addHost( h, **params )
Naoki Shiota2322a2f2014-05-21 19:47:40 -070095
96 # Add links
97 for l in conf[ 'links' ]:
Naoki Shiota801875c2014-05-29 17:06:06 -070098 node1 = nmap[ l[ 'node1' ] ].strip()
99 node2 = nmap[ l[ 'node2' ] ].strip()
Naoki Shiota2322a2f2014-05-21 19:47:40 -0700100 self.addLink( node1, node2 )
101
102class ClusterConnectedSwitch( OVSSwitch ):
103 "OVSSwitch connected to controller cluster."
104
105 def start( self, controllers ):
106 # make sure controllers contains only a ControllerCluster
107 assert len( controllers ) == 1
108 ccluster = controllers[ 0 ]
109 assert type( ccluster ) == ControllerCluster
110
111 controller_list = ccluster.clist( self.name )
112 # TODO: manage order of controllers to control mastership
113 OVSSwitch.start( self, controllers=controller_list )
114
115class ControllerCluster( Controller ):
116 "Cluster of controllers. Relationship between controllers and switches is defined by config file"
117
118 def __init__( self, name, **params ):
119 self.sw_clist_map = {}
120 self.cmap = {}
121
122 Controller.__init__( self, name, **params )
123
124 for cname, addr in conf[ 'controllers' ].iteritems():
Naoki Shiota801875c2014-05-29 17:06:06 -0700125 cname = cname.strip()
126 addr = addr.strip()
Naoki Shiota2322a2f2014-05-21 19:47:40 -0700127 ip, port = addr.split( ':' )
128 self.cmap[ cname ] = RemoteController( cname, ip=ip, port=int( port ) )
129
130 for sw, params in conf[ 'switches' ].iteritems():
131 clist = []
132 for c in params[ 'controllers' ]:
133 assert not self.cmap[ c ] is None
134 clist.append( self.cmap[ c ] )
135 self.sw_clist_map[ sw ] = clist
136
137 def start( self ):
138 # do nothing
139 return
140
141 def stop( self ):
142 # do nothing
143 return
144
145 def checkListening( self ):
146 for c in self.cmap.values():
147 c.checkListening()
148
149 def clist( self, sw ):
150 return self.sw_clist_map[ sw ]
151
152if __name__ == '__main__':
153 setLogLevel( 'info' )
Naoki Shiota801875c2014-05-29 17:06:06 -0700154 info( "Topology file : %s\n" % topofile )
Naoki Shiota2322a2f2014-05-21 19:47:40 -0700155 net = Mininet( topo=ConfigTopo(),
156 controller=ControllerCluster,
157 switch=ClusterConnectedSwitch )
158 net.start()
159 CLI( net )
160 net.stop()