kelvin-onlab | d9e23de | 2015-08-06 10:34:44 -0700 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | """ |
| 4 | Custom topology for Mininet |
| 5 | Author: kelvin@onlab.us |
| 6 | """ |
| 7 | from mininet.topo import Topo |
| 8 | from mininet.net import Mininet |
| 9 | from mininet.node import Host, RemoteController |
| 10 | from mininet.node import Node |
| 11 | from mininet.node import CPULimitedHost |
| 12 | from mininet.link import TCLink |
| 13 | from mininet.cli import CLI |
| 14 | from mininet.log import setLogLevel |
| 15 | from mininet.util import dumpNodeConnections |
| 16 | from mininet.node import ( UserSwitch, OVSSwitch, IVSSwitch ) |
| 17 | import sys |
| 18 | coreSwitches = {} |
| 19 | spineSwitches = {} |
| 20 | leafSwitches = {} |
| 21 | endSwitches = {} |
| 22 | allSwitches = {} |
| 23 | # Counters for nodes |
| 24 | totalSwitches = 0 |
| 25 | totalEndSwitches = 0 |
| 26 | totalHosts = 0 |
| 27 | endSwitchCount = 0 # total count of end switch in each row in gui |
| 28 | class spineTopo( Topo ): |
| 29 | |
| 30 | def __init__( self, **opts ): |
| 31 | "Create a topology." |
| 32 | Topo.__init__( self, **opts ) |
| 33 | |
| 34 | def build( self, s, l, c, e, h, **opts ): |
| 35 | """ |
| 36 | s = number of spine switches |
| 37 | l = number of leaf switches |
| 38 | c = number of core |
| 39 | e = number of end switch |
| 40 | h = number of end host |
| 41 | """ |
| 42 | global totalSwitches |
| 43 | global coreSwitches |
| 44 | global spineSwitches |
| 45 | global leafSwitches |
| 46 | global endSwitches |
| 47 | global totalEndSwitches |
| 48 | global totalHosts |
| 49 | global allSwitches |
| 50 | global endSwitchCount |
| 51 | endSwitchCount = e |
| 52 | |
| 53 | print "Creating topology with", s,"spine", l,"leaf", c,"core",\ |
| 54 | e,"end switches and",h,"host for each end switches" |
| 55 | |
| 56 | self.addCore( c ) |
| 57 | self.addSpine( s ) |
| 58 | self.addLeaf( l ) |
| 59 | self.linkLayer( coreSwitches, spineSwitches ) |
| 60 | self.linkLayer( spineSwitches, leafSwitches ) |
| 61 | self.linkEndSwitch( e, leafSwitches ) |
| 62 | self.linkHosts( h ) |
| 63 | |
| 64 | allSwitches = coreSwitches |
| 65 | allSwitches.update( spineSwitches ) |
| 66 | allSwitches.update( leafSwitches ) |
| 67 | allSwitches.update( endSwitches ) |
| 68 | deviceData = self.createSwitchDict() |
| 69 | self.genCfgJson( deviceData ) |
| 70 | |
| 71 | |
| 72 | def addCore( self, numSwitch ): |
| 73 | global totalSwitches |
| 74 | global coreSwitches |
| 75 | for i in range( numSwitch ): |
| 76 | coreSwitches[ 'core' + str( i + 1 ) ] = self.addSwitch( |
| 77 | 's' + str( totalSwitches + 1 ) ) |
| 78 | totalSwitches += 1 |
| 79 | |
| 80 | def addSpine( self, numSwitch ): |
| 81 | global totalSwitches |
| 82 | global spineSwitches |
| 83 | for i in range( numSwitch ): |
| 84 | spineSwitches[ 'spine' + str( i + 1 ) ] = self.addSwitch( |
| 85 | 's' + str( totalSwitches + 1 ) ) |
| 86 | totalSwitches += 1 |
| 87 | |
| 88 | def addLeaf( self, numSwitch ): |
| 89 | global totalSwitches |
| 90 | global leafSwitches |
| 91 | for i in range( numSwitch ): |
| 92 | leafSwitches[ 'leaf' + str( i + 1 ) ] = self.addSwitch( |
| 93 | 's' + str( totalSwitches + 1 ) ) |
| 94 | totalSwitches += 1 |
| 95 | |
| 96 | def addEnd( self ): |
| 97 | global totalSwitches |
| 98 | global totalEndSwitches |
| 99 | global endSwitches |
| 100 | |
| 101 | endSwitches[ 'end' + str( totalEndSwitches + 1 ) ] = self.addSwitch( |
| 102 | 's' + str( totalSwitches + 1 ) ) |
| 103 | totalSwitches += 1 |
| 104 | totalEndSwitches += 1 |
| 105 | |
| 106 | return endSwitches[ 'end' + str( totalEndSwitches ) ] |
| 107 | |
| 108 | def addEndHosts( self ): |
| 109 | global totalHosts |
| 110 | |
| 111 | totalHosts += 1 |
| 112 | host = self.addHost( 'h' + str( totalHosts ) ) |
| 113 | |
| 114 | return host |
| 115 | |
| 116 | |
| 117 | def linkHosts( self, numHosts ): |
| 118 | global endSwitches |
| 119 | switches = sorted( endSwitches.values() ) |
| 120 | |
| 121 | for sw in switches: |
| 122 | for i in xrange( numHosts ): |
| 123 | self.addLink( sw, self.addEndHosts() ) |
| 124 | |
| 125 | |
| 126 | def linkLayer( self, topLayer, botLayer ): |
| 127 | """ |
| 128 | Description: |
| 129 | The top layer is the upper layer in the spine topology eg. top layer |
| 130 | can be the spine and the bottom layer is the leaf, another is the |
| 131 | core layer is the top layer and the spine is the bottom layer and |
| 132 | so on. |
| 133 | Required: |
| 134 | topLayer - Upper layer in the spine topology to be linked in the |
| 135 | layer below |
| 136 | botLater - Layer that is below the upper layer to be linked at |
| 137 | """ |
| 138 | |
| 139 | topSwitches = sorted( topLayer.keys() ) |
| 140 | botSwitches = sorted( botLayer.keys() ) |
| 141 | |
| 142 | for topSw in topSwitches: |
| 143 | for botSw in botSwitches: |
| 144 | self.addLink( topLayer.get( topSw ), botLayer.get( botSw ) ) |
| 145 | |
| 146 | |
| 147 | def linkEndSwitch( self, numSwitch, leafLayer ): |
| 148 | global totalSwitches |
| 149 | global totalEndSwitches |
| 150 | |
| 151 | leaf = sorted( leafLayer.values() ) |
| 152 | |
| 153 | for i in xrange( len( leafSwitches ) ): |
| 154 | if len( leafSwitches ) == 1: |
| 155 | for j in xrange( numSwitch ): |
| 156 | self.addLink( leaf[ 0 ], self.addEnd() ) |
| 157 | break |
| 158 | if len( leafSwitches ) == 2: |
| 159 | for j in xrange( numSwitch ): |
| 160 | endSw = self.addEnd() |
| 161 | self.addLink( leaf[ i ], endSw ) |
| 162 | self.addLink( leaf[ i + 1 ], endSw ) |
| 163 | break |
| 164 | if i == ( len( leafSwitches ) - 1 ) and len( leafSwitches )%2: |
| 165 | for j in xrange( numSwitch ): |
| 166 | self.addLink( leaf[ i ], self.addEnd() ) |
| 167 | break |
| 168 | if i == 0: |
| 169 | for j in xrange( numSwitch ): |
| 170 | endSw = self.addEnd() |
| 171 | self.addLink( leaf[ i ], endSw ) |
| 172 | self.addLink( leaf[ i + 1 ], endSw ) |
| 173 | continue |
| 174 | if i == 1: |
| 175 | continue |
| 176 | if i%2 == 0: |
| 177 | for j in xrange( numSwitch ): |
| 178 | endSw = self.addEnd() |
| 179 | self.addLink( leaf[ i ], endSw ) |
| 180 | self.addLink( leaf[ i + 1 ], endSw ) |
| 181 | |
| 182 | def genCfgJson( self, deviceData ): |
| 183 | import json |
| 184 | configJson = {} |
| 185 | configJson[ "devices" ] = deviceData |
| 186 | with open( 'spine.json', 'w+' ) as outfile: |
| 187 | json.dump( configJson, outfile ) |
| 188 | #cfgFile = open( "spine.json" , 'w+' ) |
| 189 | #cfgFile.write( configJson ) |
| 190 | #cfgFile.close() |
| 191 | |
| 192 | |
| 193 | |
| 194 | def createSwitchDict( self ): |
| 195 | global allSwitches |
| 196 | global endSwitchCount |
| 197 | |
| 198 | latitude = 0 |
| 199 | longitude = 0 |
| 200 | coreLong = -70 |
| 201 | spineLong = -80 |
| 202 | leafLong = -90 |
| 203 | endLat = 30 |
| 204 | rowCount = 0 # count of end switches or rows |
| 205 | colOffSet = 0 # off set for end switches; longitude |
| 206 | |
| 207 | #for i in xrange( len( allSwitches ) ): |
| 208 | deviceList = [] |
| 209 | deviceDict = {} |
| 210 | for sw in allSwitches: |
| 211 | tempSw = allSwitches.get( sw ) |
| 212 | uri = str( "{0:0>16}".format( str( hex( int( tempSw[ 1: ] ) )\ |
| 213 | ).split( "x" )[ 1 ] ) ) |
| 214 | mac = str( "{0:0>12}".format( str( hex( int( tempSw[ 1: ] ) )\ |
| 215 | ).split( "x" )[ 1 ] ) ) |
| 216 | |
| 217 | if "core" in sw: |
| 218 | latitude = 45 |
| 219 | longitude = coreLong |
| 220 | coreLong += 2.5 |
| 221 | elif "spine" in sw: |
| 222 | latitude = 40 |
| 223 | longitude = spineLong |
| 224 | spineLong += 1.5 |
| 225 | elif "leaf" in sw: |
| 226 | latitude = 35 |
| 227 | longitude = leafLong |
| 228 | leafLong += 1.5 |
| 229 | elif "end" in sw: |
| 230 | # Reset position and move to the right once every |
| 231 | # number of end switches |
| 232 | if rowCount == endSwitchCount: |
| 233 | colOffSet += 2.5 |
| 234 | rowCount = 0 |
| 235 | endLat = 30 |
| 236 | longitude = -80 + colOffSet |
| 237 | latitude = endLat |
| 238 | endLat -= 1 |
| 239 | rowCount += 1 |
| 240 | |
| 241 | tempItem = { "alias": allSwitches.get( sw ) , |
| 242 | "uri": "of:" + uri, |
| 243 | "mac": mac, |
| 244 | "annotations": { "name": sw, |
| 245 | "latitude": latitude, |
| 246 | "longitude": longitude }, |
| 247 | "type": "SWITCH" } |
| 248 | deviceList.append( tempItem ) |
| 249 | |
| 250 | return deviceList |
| 251 | #def createHostsJson( hostDict ): |
| 252 | |
| 253 | topos = { 'spine': ( lambda s=2, l=3, c=1, e=5, h=1: spineTopo( s=s, |
| 254 | l=l, |
| 255 | c=c, |
| 256 | e=e, |
| 257 | h=h) ) } |
| 258 | |
| 259 | # HERE THE CODE DEFINITION OF THE TOPOLOGY ENDS |
| 260 | |
| 261 | def setupNetwork(): |
| 262 | "Create network" |
| 263 | topo = spineTopo() |
| 264 | #if controller_ip == '': |
| 265 | #controller_ip = '10.0.2.2'; |
| 266 | # controller_ip = '127.0.0.1'; |
| 267 | network = Mininet( topo=topo, |
| 268 | autoSetMacs=True, |
| 269 | controller=None ) |
| 270 | network.start() |
| 271 | CLI( network ) |
| 272 | network.stop() |
| 273 | |
| 274 | if __name__ == '__main__': |
| 275 | setLogLevel( 'info' ) |
| 276 | #setLogLevel('debug') |
| 277 | setupNetwork() |