216 lines
6.9 KiB
Python
Executable File
216 lines
6.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
import json
|
|
from os import linesep as eol
|
|
|
|
virtual_servers_per_physical_server = 2
|
|
physical_servers_per_rack_tower = 2
|
|
rack_tower_per_corridor = 2
|
|
corridors = 3
|
|
spines = 3
|
|
|
|
linkspd_virtual_physical = 0.1 # 100 mbps
|
|
linkspd_physicalhost_switch = 0.1 # 100 mbps
|
|
linkspd_physical_tower = 0.1 # 100 mbps
|
|
linkspd_tower_corridor = 1 # 1 gbps
|
|
linkspd_corridor_spine = 1 # 1 gbps
|
|
linkspd_spine_spine = 10 # 10 gbps
|
|
|
|
|
|
class CounterIterator:
|
|
def __init__(self):
|
|
self._c = 0
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
self._c += 1
|
|
return self._c
|
|
|
|
|
|
hosts_iter = CounterIterator()
|
|
switch_iter = CounterIterator()
|
|
|
|
|
|
def create_virtual_server():
|
|
this_hosts = []
|
|
this_switches = []
|
|
this_links = []
|
|
this_hosts.append("h%d" % next(hosts_iter))
|
|
return this_hosts, this_switches, this_links
|
|
|
|
|
|
def create_physical_server():
|
|
this_hosts = []
|
|
this_switches = []
|
|
this_links = []
|
|
serv = "h%d" % next(hosts_iter)
|
|
sw = "s%d" % next(switch_iter)
|
|
for _ in range(virtual_servers_per_physical_server):
|
|
chd_hosts, chd_switches, chd_links = create_virtual_server()
|
|
this_hosts += chd_hosts
|
|
this_switches += chd_switches
|
|
this_links += chd_links
|
|
this_links.append((chd_hosts[-1], sw, linkspd_virtual_physical))
|
|
this_hosts.append(serv)
|
|
this_switches.append(sw)
|
|
this_links.append((serv, sw, linkspd_physicalhost_switch))
|
|
return this_hosts, this_switches, this_links
|
|
|
|
|
|
def create_racktower():
|
|
this_hosts = []
|
|
this_switches = []
|
|
this_links = []
|
|
sw = "s%d" % next(switch_iter)
|
|
for _ in range(physical_servers_per_rack_tower):
|
|
chd_hosts, chd_switches, chd_links = create_physical_server()
|
|
this_hosts += chd_hosts
|
|
this_switches += chd_switches
|
|
this_links += chd_links
|
|
lsw = chd_switches[-1]
|
|
this_links.append((lsw, sw, linkspd_physical_tower))
|
|
this_switches.append(sw)
|
|
return this_hosts, this_switches, this_links
|
|
|
|
|
|
def create_corridor():
|
|
this_hosts = []
|
|
this_switches = []
|
|
this_links = []
|
|
sw1 = "s%d" % next(switch_iter)
|
|
sw2 = "s%d" % next(switch_iter)
|
|
for _ in range(rack_tower_per_corridor):
|
|
chd_hosts, chd_switches, chd_links = create_racktower()
|
|
this_hosts += chd_hosts
|
|
this_switches += chd_switches
|
|
this_links += chd_links
|
|
lsw = chd_switches[-1]
|
|
this_links.append((lsw, sw1, linkspd_tower_corridor))
|
|
this_links.append((lsw, sw2, linkspd_tower_corridor))
|
|
this_switches.append(sw1)
|
|
this_switches.append(sw2)
|
|
return this_hosts, this_switches, this_links
|
|
|
|
|
|
def create_spine():
|
|
this_hosts = []
|
|
this_switches = []
|
|
this_links = []
|
|
swsps = ["s%d" % next(switch_iter) for _ in range(spines)]
|
|
for i in range(spines-1):
|
|
chd_hosts, chd_switches, chd_links = create_corridor()
|
|
this_hosts += chd_hosts
|
|
this_switches += chd_switches
|
|
this_links += chd_links
|
|
lsw1, lsw2 = chd_switches[-2:]
|
|
this_links.append((lsw1, swsps[i], linkspd_corridor_spine))
|
|
this_links.append((lsw2, swsps[i+1], linkspd_corridor_spine))
|
|
this_switches += swsps
|
|
return this_hosts, this_switches, this_links
|
|
|
|
|
|
def create_datacenter():
|
|
this_hosts = []
|
|
this_switches = []
|
|
this_links = []
|
|
last_spined_corridor = []
|
|
for _ in range(corridors):
|
|
chd_hosts, chd_switches, chd_links = create_spine()
|
|
this_hosts += chd_hosts
|
|
this_switches += chd_switches
|
|
this_links += chd_links
|
|
spined_corridor = chd_switches[-spines:]
|
|
if len(last_spined_corridor) > 0:
|
|
for i in range(spines):
|
|
this_links.append(
|
|
(last_spined_corridor[i], spined_corridor[i], linkspd_spine_spine))
|
|
last_spined_corridor = spined_corridor
|
|
return this_hosts, this_switches, this_links
|
|
|
|
|
|
def render_topology(hosts, switches, links):
|
|
indent = ' '*4
|
|
s = ''
|
|
s += f'#!/usr/bin/env python3{eol}# -*- encoding: utf-8 -*-{eol}'+eol
|
|
s += 'from mininet.net import Mininet'+eol
|
|
s += 'from mininet.node import Controller, RemoteController, OVSController'+eol
|
|
s += 'from mininet.node import CPULimitedHost, Host, Node'+eol
|
|
s += 'from mininet.node import OVSKernelSwitch, UserSwitch'+eol
|
|
s += 'from mininet.node import IVSSwitch'+eol
|
|
s += 'from mininet.cli import CLI'+eol
|
|
s += 'from mininet.log import setLogLevel, info'+eol
|
|
s += 'from mininet.link import TCLink, Intf'+eol
|
|
s += 'from subprocess import call'+eol+eol
|
|
s += 'def myNetwork():'+eol
|
|
s += f'{indent}net = Mininet({eol}'
|
|
s += f'{indent}{indent}topo=None,{eol}'
|
|
s += f'{indent}{indent}build=False,{eol}'
|
|
s += f'{indent}{indent}ipBase="10.0.0.0/8"{eol}'
|
|
s += f'{indent}){eol}'
|
|
s += eol
|
|
# controller
|
|
s += f"{indent}info('*** Adding controller\\n'){eol}"
|
|
s += f"{indent}c0=net.addController({eol}"
|
|
s += f"{indent}{indent}name='c0',{eol}"
|
|
s += f"{indent}{indent}controller=Controller,{eol}"
|
|
s += f"{indent}{indent}protocol='tcp',{eol}"
|
|
s += f"{indent}{indent}port=6633{eol}"
|
|
s += f"{indent}){eol}"
|
|
s += eol
|
|
# switch
|
|
s += f"{indent}info('*** Adding switches\\n'){eol}"
|
|
for sw in sorted(switches, key=lambda a: int(a[1:])):
|
|
s += f"{indent}{sw} = net.addSwitch('{sw}', cls=OVSKernelSwitch){eol}"
|
|
s += eol
|
|
# hosts
|
|
s += f"{indent}info('*** Adding hosts\\n'){eol}"
|
|
for hs in sorted(hosts, key=lambda a: int(a[1:])):
|
|
ipint = int(hs[1:])
|
|
iplst = [
|
|
ipint//(256**2),
|
|
(ipint//256)%256,
|
|
ipint%256
|
|
]
|
|
ip = '.'.join(list(map(str, iplst)))
|
|
s+= f"{indent}{hs} = net.addHost('{hs}', cls=Host, ip='10.{ip}', defaultRoute=None){eol}"
|
|
s += eol
|
|
# links
|
|
s += f"{indent}info('*** Adding links\\n'){eol}"
|
|
for e1, e2, bw in links:
|
|
s += f"{indent}net.addLink({e1}, {e2}, cls=TCLink, bw={bw}){eol}"
|
|
s += eol
|
|
# rest
|
|
s += f"{indent}info('*** Starting network\\n'){eol}"
|
|
s += f"{indent}net.build(){eol}"
|
|
s += eol
|
|
s += f"{indent}info('*** Starting controllers\\n'){eol}"
|
|
s += f"{indent}for controller in net.controllers:{eol}"
|
|
s += f"{indent}{indent}controller.start(){eol}"
|
|
s += eol
|
|
s += f"{indent}info('*** Starting switches\\n'){eol}"
|
|
for sw in sorted(switches, key=lambda a: int(a[1:])):
|
|
s += f"{indent}net.get('{sw}').start([c0]){eol}"
|
|
s += eol
|
|
s += f"{indent}info('*** Post configure switches and hosts\\n'){eol}"
|
|
s += f"{indent}CLI(net){eol}"
|
|
s += f"{indent}net.stop(){eol}"
|
|
# main
|
|
s += eol
|
|
s += eol
|
|
s += f'if __name__ == "__main__":{eol}'
|
|
s += f'{indent}setLogLevel("info"){eol}'
|
|
s += f'{indent}myNetwork(){eol}'
|
|
return s
|
|
|
|
|
|
datacenter = create_datacenter()
|
|
rendered = render_topology(*datacenter)
|
|
|
|
with open('bigtopo.py', 'w') as f:
|
|
f.write(rendered)
|
|
with open('bigtopo.json', 'w') as f:
|
|
f.write(json.dumps(datacenter))
|