blob: 32c84194a6bf2c78591e5e22989ca5c4ee611b71 [file] [log] [blame]
kelvin-onlabd9e23de2015-08-06 10:34:44 -07001#!/usr/bin/python
2
3"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07004Copyright 2015 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07005
6Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
7the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
8or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
9
10 TestON is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070013 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070014
15 TestON is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with TestON. If not, see <http://www.gnu.org/licenses/>.
22"""
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070023"""
kelvin-onlabd9e23de2015-08-06 10:34:44 -070024Custom topology for Mininet
25Author: kelvin@onlab.us
26"""
27from mininet.topo import Topo
28from mininet.net import Mininet
29from mininet.node import Host, RemoteController
30from mininet.node import Node
31from mininet.node import CPULimitedHost
32from mininet.link import TCLink
33from mininet.cli import CLI
34from mininet.log import setLogLevel
35from mininet.util import dumpNodeConnections
36from mininet.node import ( UserSwitch, OVSSwitch, IVSSwitch )
37import sys
38coreSwitches = {}
39spineSwitches = {}
40leafSwitches = {}
41endSwitches = {}
42allSwitches = {}
43# Counters for nodes
44totalSwitches = 0
45totalEndSwitches = 0
46totalHosts = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070047endSwitchCount = 0 # total count of end switch in each row in gui
48
49
kelvin-onlabd9e23de2015-08-06 10:34:44 -070050class spineTopo( Topo ):
51
52 def __init__( self, **opts ):
53 "Create a topology."
54 Topo.__init__( self, **opts )
55
56 def build( self, s, l, c, e, h, **opts ):
57 """
58 s = number of spine switches
59 l = number of leaf switches
60 c = number of core
61 e = number of end switch
62 h = number of end host
63 """
64 global totalSwitches
65 global coreSwitches
66 global spineSwitches
67 global leafSwitches
68 global endSwitches
69 global totalEndSwitches
70 global totalHosts
71 global allSwitches
72 global endSwitchCount
73 endSwitchCount = e
74
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070075 print "Creating topology with", s, "spine", l, "leaf", c, "core",\
76 e, "end switches and", h, "host for each end switches"
kelvin-onlabd9e23de2015-08-06 10:34:44 -070077
78 self.addCore( c )
79 self.addSpine( s )
80 self.addLeaf( l )
81 self.linkLayer( coreSwitches, spineSwitches )
82 self.linkLayer( spineSwitches, leafSwitches )
83 self.linkEndSwitch( e, leafSwitches )
84 self.linkHosts( h )
85
86 allSwitches = coreSwitches
87 allSwitches.update( spineSwitches )
88 allSwitches.update( leafSwitches )
89 allSwitches.update( endSwitches )
90 deviceData = self.createSwitchDict()
91 self.genCfgJson( deviceData )
92
kelvin-onlabd9e23de2015-08-06 10:34:44 -070093 def addCore( self, numSwitch ):
94 global totalSwitches
95 global coreSwitches
96 for i in range( numSwitch ):
97 coreSwitches[ 'core' + str( i + 1 ) ] = self.addSwitch(
98 's' + str( totalSwitches + 1 ) )
99 totalSwitches += 1
100
101 def addSpine( self, numSwitch ):
102 global totalSwitches
103 global spineSwitches
104 for i in range( numSwitch ):
105 spineSwitches[ 'spine' + str( i + 1 ) ] = self.addSwitch(
106 's' + str( totalSwitches + 1 ) )
107 totalSwitches += 1
108
109 def addLeaf( self, numSwitch ):
110 global totalSwitches
111 global leafSwitches
112 for i in range( numSwitch ):
113 leafSwitches[ 'leaf' + str( i + 1 ) ] = self.addSwitch(
114 's' + str( totalSwitches + 1 ) )
115 totalSwitches += 1
116
117 def addEnd( self ):
118 global totalSwitches
119 global totalEndSwitches
120 global endSwitches
121
122 endSwitches[ 'end' + str( totalEndSwitches + 1 ) ] = self.addSwitch(
123 's' + str( totalSwitches + 1 ) )
124 totalSwitches += 1
125 totalEndSwitches += 1
126
127 return endSwitches[ 'end' + str( totalEndSwitches ) ]
128
129 def addEndHosts( self ):
130 global totalHosts
131
132 totalHosts += 1
133 host = self.addHost( 'h' + str( totalHosts ) )
134
135 return host
136
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700137 def linkHosts( self, numHosts ):
138 global endSwitches
139 switches = sorted( endSwitches.values() )
140
141 for sw in switches:
142 for i in xrange( numHosts ):
143 self.addLink( sw, self.addEndHosts() )
144
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700145 def linkLayer( self, topLayer, botLayer ):
146 """
147 Description:
148 The top layer is the upper layer in the spine topology eg. top layer
149 can be the spine and the bottom layer is the leaf, another is the
150 core layer is the top layer and the spine is the bottom layer and
151 so on.
152 Required:
153 topLayer - Upper layer in the spine topology to be linked in the
154 layer below
155 botLater - Layer that is below the upper layer to be linked at
156 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700157 topSwitches = sorted( topLayer.keys() )
158 botSwitches = sorted( botLayer.keys() )
159
160 for topSw in topSwitches:
161 for botSw in botSwitches:
162 self.addLink( topLayer.get( topSw ), botLayer.get( botSw ) )
163
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700164 def linkEndSwitch( self, numSwitch, leafLayer ):
165 global totalSwitches
166 global totalEndSwitches
167
168 leaf = sorted( leafLayer.values() )
169
170 for i in xrange( len( leafSwitches ) ):
171 if len( leafSwitches ) == 1:
172 for j in xrange( numSwitch ):
173 self.addLink( leaf[ 0 ], self.addEnd() )
174 break
175 if len( leafSwitches ) == 2:
176 for j in xrange( numSwitch ):
177 endSw = self.addEnd()
178 self.addLink( leaf[ i ], endSw )
179 self.addLink( leaf[ i + 1 ], endSw )
180 break
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700181 if i == ( len( leafSwitches ) - 1 ) and len( leafSwitches ) % 2:
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700182 for j in xrange( numSwitch ):
183 self.addLink( leaf[ i ], self.addEnd() )
184 break
185 if i == 0:
186 for j in xrange( numSwitch ):
187 endSw = self.addEnd()
188 self.addLink( leaf[ i ], endSw )
189 self.addLink( leaf[ i + 1 ], endSw )
190 continue
191 if i == 1:
192 continue
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700193 if i % 2 == 0:
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700194 for j in xrange( numSwitch ):
195 endSw = self.addEnd()
196 self.addLink( leaf[ i ], endSw )
197 self.addLink( leaf[ i + 1 ], endSw )
198
199 def genCfgJson( self, deviceData ):
200 import json
201 configJson = {}
202 configJson[ "devices" ] = deviceData
203 with open( 'spine.json', 'w+' ) as outfile:
204 json.dump( configJson, outfile )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700205 # cfgFile = open( "spine.json" , 'w+' )
206 # cfgFile.write( configJson )
207 # cfgFile.close()
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700208
209 def createSwitchDict( self ):
210 global allSwitches
211 global endSwitchCount
212
213 latitude = 0
214 longitude = 0
215 coreLong = -70
216 spineLong = -80
217 leafLong = -90
218 endLat = 30
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700219 rowCount = 0 # count of end switches or rows
220 colOffSet = 0 # off set for end switches; longitude
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700221
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700222 # for i in xrange( len( allSwitches ) ):
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700223 deviceList = []
224 deviceDict = {}
225 for sw in allSwitches:
226 tempSw = allSwitches.get( sw )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700227 uri = str( "{0:0>16}".format( str( hex( int( tempSw[ 1: ] ) )
228 ).split( "x" )[ 1 ] ) )
229 mac = str( "{0:0>12}".format( str( hex( int( tempSw[ 1: ] ) )
230 ).split( "x" )[ 1 ] ) )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700231
232 if "core" in sw:
233 latitude = 45
234 longitude = coreLong
235 coreLong += 2.5
236 elif "spine" in sw:
237 latitude = 40
238 longitude = spineLong
239 spineLong += 1.5
240 elif "leaf" in sw:
241 latitude = 35
242 longitude = leafLong
243 leafLong += 1.5
244 elif "end" in sw:
245 # Reset position and move to the right once every
246 # number of end switches
247 if rowCount == endSwitchCount:
248 colOffSet += 2.5
249 rowCount = 0
250 endLat = 30
251 longitude = -80 + colOffSet
252 latitude = endLat
253 endLat -= 1
254 rowCount += 1
255
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700256 tempItem = { "alias": allSwitches.get( sw ),
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700257 "uri": "of:" + uri,
258 "mac": mac,
259 "annotations": { "name": sw,
260 "latitude": latitude,
261 "longitude": longitude },
262 "type": "SWITCH" }
263 deviceList.append( tempItem )
264
265 return deviceList
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700266 # def createHostsJson( hostDict ):
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700267
268topos = { 'spine': ( lambda s=2, l=3, c=1, e=5, h=1: spineTopo( s=s,
269 l=l,
270 c=c,
271 e=e,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700272 h=h ) ) }
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700273
274# HERE THE CODE DEFINITION OF THE TOPOLOGY ENDS
275
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700276
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700277def setupNetwork():
278 "Create network"
279 topo = spineTopo()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700280 # if controller_ip == '':
281 # controller_ip = '10.0.2.2';
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700282 # controller_ip = '127.0.0.1';
283 network = Mininet( topo=topo,
284 autoSetMacs=True,
285 controller=None )
286 network.start()
287 CLI( network )
288 network.stop()
289
290if __name__ == '__main__':
291 setLogLevel( 'info' )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700292 # setLogLevel( 'debug' )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700293 setupNetwork()