blob: 9e2812d8c9f5428d256bba1eb81c9b462e90dc61 [file] [log] [blame]
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -08001#!/usr/bin/python
2import os
3import re
4from optparse import OptionParser
5from ipaddress import ip_network
6from mininet.node import RemoteController, OVSBridge, Host
7from mininet.link import TCLink
8from mininet.log import setLogLevel
9from mininet.net import Mininet
10from mininet.topo import Topo
11from mininet.nodelib import NAT
12from mininet.cli import CLI
13
14from routinglib import BgpRouter, RoutedHost
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080015from trellislib import DhcpServer, TaggedRoutedHost, DualHomedRoutedHost, DualHomedTaggedRoutedHost, DhcpClient, Dhcp6Client, DhcpServer, Dhcp6Server, TrellisHost
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080016
17# Parse command line options and dump results
18def parseOptions():
19 "Parse command line options"
20 parser = OptionParser()
21 parser.add_option( '--dhcp', dest='dhcp', type='int', default=0,
22 help='Configure hosts with dhcp or not' )
23 parser.add_option( '--routers', dest='routers', type='int', default=0,
24 help='Configure external routers or not in the topology' )
25 parser.add_option( '--ipv6', dest='ipv6', type='int', default=0,
26 help='Configure hosts with ipv6 or not' )
27 parser.add_option( '--ipv4', dest='ipv4', type='int', default=1,
28 help='Configure hosts with ipv4 or not' )
29 parser.add_option( '--onos-ip', dest='onosIp', type='str', default='',
30 help='IP address list of ONOS instances, separated by comma(,). Overrides --onos option' )
31
32 ( options, args ) = parser.parse_args()
33 return options, args
34
35opts, args = parseOptions()
36
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080037class ComcastLeafSpineFabric(Topo):
38
39 spines = dict()
40 leafs = dict()
41 hosts_dict = dict()
42
43 def createIpv4Hosts(self, dhcp):
44
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080045 h1 = self.addHost('h1v4', cls=TrellisHost,
46 mac='00:aa:00:00:00:01', ips=['10.1.0.1/24'],
47 gateway='10.1.0.254', dhcpClient=dhcp)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080048 self.addLink(h1, self.leafs[0])
49 self.hosts_dict['h1v4'] = h1
50
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080051 h2 = self.addHost('h2v4', cls=TrellisHost,
52 mac='00:aa:00:00:01:01', ips=['10.1.10.1/24'],
53 gateway='10.1.10.254', dhcpClient=dhcp)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080054 self.addLink(h2, self.leafs[0])
55 self.hosts_dict['h2v4'] = h2
56
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080057 h3 = self.addHost('h3v4', cls=TrellisHost,
58 mac='00:aa:00:00:00:02', ips=['10.2.0.1/24'],
59 gateway='10.2.0.254', dhcpClient=dhcp)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080060 self.addLink(h3, self.leafs[1])
61 self.hosts_dict['h3v4'] = h3
62
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080063 h4 = self.addHost('h4v4', cls=TrellisHost,
64 mac='00:aa:00:00:00:03', ips=['10.2.30.1/24'],
65 gateway='10.2.30.254', dhcpClient=dhcp,
66 dualHomed=True)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080067 self.addLink(h4, self.leafs[1])
68 self.addLink(h4, self.leafs[2])
69 self.hosts_dict['h4v4'] = h4
70
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080071 h5 = self.addHost('h5v4', cls=TrellisHost,
72 mac='00:aa:00:00:00:04', ips=['10.2.20.1/24'],
73 gateway='10.2.20.254', dhcpClient=dhcp, vlan=30,
74 dualHomed=True)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080075 self.addLink(h5, self.leafs[1])
76 self.addLink(h5, self.leafs[2])
77 self.hosts_dict['h5v4'] = h5
78
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080079 h6 = self.addHost('h6v4', cls=TrellisHost,
80 mac='00:aa:00:00:00:05', ips=['10.2.10.1/24'],
81 gateway='10.2.10.254', dhcpClient=dhcp, vlan=20)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080082 self.addLink(h6, self.leafs[2])
83 self.hosts_dict['h6v4'] = h6
84
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080085 h7 = self.addHost('h7v4', cls=TrellisHost,
86 mac='00:aa:00:00:01:05', ips=['10.2.40.1/24'],
87 gateway='10.2.40.254', dhcpClient=dhcp, vlan=40)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080088 self.addLink(h7, self.leafs[2])
89 self.hosts_dict['h7v4'] = h7
90
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080091 h8 = self.addHost('h8v4', cls=TrellisHost,
92 mac='00:aa:00:00:00:06', ips=['10.3.0.1/24'],
93 gateway='10.3.0.254', dhcpClient=dhcp, vlan=30)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080094 self.addLink(h8, self.leafs[3])
95 self.hosts_dict['h8v4'] = h8
96
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -080097 h9 = self.addHost('h9v4', cls=TrellisHost,
98 mac='00:aa:00:00:00:07', ips=['10.3.10.1/24'],
99 gateway='10.3.10.254', dhcpClient=dhcp, vlan=40,
100 dualHomed=True)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800101 self.addLink(h9, self.leafs[3])
102 self.addLink(h9, self.leafs[4])
103 self.hosts_dict['h9v4'] = h9
104
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800105 h10 = self.addHost('h10v4', cls=TrellisHost,
106 mac='00:aa:00:00:00:08', ips=['10.3.30.1/24'],
107 gateway='10.3.30.254', dhcpClient=dhcp, vlan=40,
108 dualHomed=True)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800109 self.addLink(h10, self.leafs[3])
110 self.addLink(h10, self.leafs[4])
111 self.hosts_dict['h10v4'] = h10
112
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800113 h11 = self.addHost('h11v4', cls=TrellisHost,
114 mac='00:aa:00:00:00:0a', ips=['10.3.20.1/24'],
115 gateway='10.3.20.254', dhcpClient=dhcp, vlan=40)
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800116 self.addLink(h11, self.leafs[4])
117 self.hosts_dict['h11v4'] = h11
118
119 return
120
121 def createIpv6Hosts(self, dhcp):
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800122
123 h1 = self.addHost('h1v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800124 mac='00:bb:00:00:00:01', ips=["1000::3fe/120"],
125 gateway='1000::3ff', dhcpClient=dhcp, ipv6=1)
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800126 self.addLink(h1, self.leafs[0])
127 self.hosts_dict['h1v6'] = h1
128
129 h2 = self.addHost('h2v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800130 mac='00:bb:00:00:01:01', ips=['1001::3fe/120'],
131 gateway='1001::3ff', dhcpClient=dhcp, ipv6=1)
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800132 self.addLink(h2, self.leafs[0])
133 self.hosts_dict['h2v6'] = h2
134
135 h3 = self.addHost('h3v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800136 mac='00:bb:00:00:00:02', ips=['1002::3fe/120'],
137 gateway='1002::3ff', dhcpClient=dhcp, ipv6=1)
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800138 self.addLink(h3, self.leafs[1])
139 self.hosts_dict['h3v6'] = h3
140
141 h4 = self.addHost('h4v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800142 mac='00:bb:00:00:00:03', ips=['1003::3fe/120'],
143 gateway='1003::3ff', dhcpClient=dhcp, ipv6=1,
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800144 dualHomed=True)
145 self.addLink(h4, self.leafs[1])
146 self.addLink(h4, self.leafs[2])
147 self.hosts_dict['h4v6'] = h4
148
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800149 # TODO: Remove this line when we
150 # find WHY dhcpv6 with tagged clients
151 # does not work.
152 dhcp = False
153
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800154 h5 = self.addHost('h5v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800155 mac='00:bb:00:00:00:04', ips=['1004::3fe/120'],
156 gateway='1004::3ff', dhcpClient=dhcp, ipv6=1,
157 vlan=30,
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800158 dualHomed=True)
159 self.addLink(h5, self.leafs[1])
160 self.addLink(h5, self.leafs[2])
161 self.hosts_dict['h5v6'] = h5
162
163 h6 = self.addHost('h6v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800164 mac='00:bb:00:00:00:05', ips=['1005::3fe/120'],
165 gateway='1005::3ff', dhcpClient=dhcp, vlan=20,
166 ipv6=1)
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800167 self.addLink(h6, self.leafs[2])
168 self.hosts_dict['h6v6'] = h6
169
170 h7 = self.addHost('h7v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800171 mac='00:bb:00:00:01:05', ips=['1006::3fe/120'],
172 gateway='1006::3ff', dhcpClient=dhcp, ipv6=1,
173 vlan=40)
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800174 self.addLink(h7, self.leafs[2])
175 self.hosts_dict['h7v6'] = h7
176
177 h8 = self.addHost('h8v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800178 mac='00:bb:00:00:00:06', ips=['1007::3fe/120'],
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800179 gateway='1007::3ff', dhcpClient=dhcp, vlan=30)
180 self.addLink(h8, self.leafs[3])
181 self.hosts_dict['h8v6'] = h8
182
183 h9 = self.addHost('h9v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800184 mac='00:bb:00:00:00:07', ips=['1008::3fe/120'],
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800185 gateway='1008::3ff', dhcpClient=dhcp, vlan=40,
186 dualHomed=True)
187 self.addLink(h9, self.leafs[3])
188 self.addLink(h9, self.leafs[4])
189 self.hosts_dict['h9v6'] = h9
190
191 h10 = self.addHost('h10v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800192 mac='00:bb:00:00:00:08', ips=['1009::3fe/120'],
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800193 gateway='1009::3ff', dhcpClient=dhcp, vlan=40,
194 dualHomed=True)
195 self.addLink(h10, self.leafs[3])
196 self.addLink(h10, self.leafs[4])
197 self.hosts_dict['h10v6'] = h10
198
199 h11 = self.addHost('h11v6', cls=TrellisHost,
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800200 mac='00:bb:00:00:00:0a', ips=['1010::3fe/120'],
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800201 gateway='1010::3ff', dhcpClient=dhcp, vlan=40)
202 self.addLink(h11, self.leafs[4])
203 self.hosts_dict['h11v6'] = h11
204
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800205 return
206
207 '''
208 Creates the topology employed by Comcast which is a 2x5
209 leaf spine traffic.
210
211 S1 S2
212
213 L1 L2 L3 L4 L5
214
215 Where L2/L3 and L4/L5 are paired switches.
216 Parameters for this topology :
217 dhcp = True/False : set up dhcp servers
218 routers = True/False : set up external routers
219 '''
220 def __init__(self, dhcp=False, routers=False, ipv4=False, ipv6=False, **opts):
221 Topo.__init__(self, **opts)
222
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800223 linkopts = dict( bw=10 )
224
225 spine = 2
226 leaf = 5
227
228 # Create spine switches
229 for s in range(spine):
230 self.spines[s] = self.addSwitch('spine10%s' % (s + 1), dpid = "00000000010%s" % (s + 1) )
231
232 # Create leaf switches
233 for ls in range(leaf):
234 self.leafs[ls] = self.addSwitch('leaf%s' % (ls + 1), dpid = "00000000000%s" % ( ls + 1) )
235
236 # connecting leaf and spines, leafs 1-5 have double links
237 for s in range( spine ):
238 spine_switch = self.spines[s]
239
240 for ls in range( leaf ):
241 leaf_switch = self.leafs[ls]
242
243 self.addLink( spine_switch, leaf_switch, **linkopts )
244 if ls > 0:
245 self.addLink( spine_switch, leaf_switch, **linkopts )
246
247 # connect paired leafs
248 self.addLink(self.leafs[1], self.leafs[2], **linkopts)
249 self.addLink(self.leafs[3], self.leafs[4], **linkopts)
250
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800251 # create hosts
252 if ipv6:
253 self.createIpv6Hosts(dhcp)
254
255 if ipv4:
256 self.createIpv4Hosts(dhcp)
257
258 if not ipv4 and not ipv6:
259 print("No hosts were created!")
260
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800261 # create quagga routers
262 if routers:
263 last_ls = self.leafs[4]
264 last_paired_ls = self. leafs[3]
265
266 # Control plane switch (for quagga fpm)
267 cs0 = self.addSwitch('cs0', cls=OVSBridge)
268
269 # Control plane NAT (for quagga fpm)
270 nat = self.addHost('nat', cls=NAT,
271 ip='172.16.0.1/12',
272 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
273 self.addLink(cs0, nat)
274
275 # Internal Quagga bgp1
276 intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
277 {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}],
278 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}}
279 bgp1 = self.addHost('bgp1', cls=BgpRouter,
280 interfaces=intfs,
281 quaggaConfFile='./bgpdbgp1.conf',
282 zebraConfFile='./zebradbgp1.conf')
283 self.addLink(bgp1, last_paired_ls)
284 self.addLink(bgp1, cs0)
285
286 # Internal Quagga bgp2
287 intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
288 {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
289 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
290 bgp2 = self.addHost('bgp2', cls=BgpRouter,
291 interfaces=intfs,
292 quaggaConfFile='./bgpdbgp2.conf',
293 zebraConfFile='./zebradbgp2.conf')
294 self.addLink(bgp2, last_ls)
295 self.addLink(bgp2, cs0)
296
297 # External Quagga r1
298 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
299 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
300 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']},
301 'r1-eth3': {'ipAddrs': ['2000::9901/120']},
302 'r1-eth4': {'ipAddrs': ['2000::7701/120']}}
303 r1 = self.addHost('r1', cls=BgpRouter,
304 interfaces=intfs,
305 quaggaConfFile='./bgpdr1.conf')
306 self.addLink(r1, last_paired_ls)
307 self.addLink(r1, last_ls)
308
309 # External IPv4 Host behind r1
310 rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
311 self.addLink(r1, rh1)
312
313 # External IPv6 Host behind r1
314 rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
315 self.addLink(r1, rh1v6)
316
317 # Another external IPv6 Host behind r1
318 rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701')
319 self.addLink(r1, rh11v6)
320
321 # External Quagga r2
322 intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
323 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
324 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']},
325 'r2-eth3': {'ipAddrs': ['2000::9901/120']},
326 'r2-eth4': {'ipAddrs': ['2000::8801/120']}}
327 r2 = self.addHost('r2', cls=BgpRouter,
328 interfaces=intfs,
329 quaggaConfFile='./bgpdr2.conf')
330 self.addLink(r2, last_ls)
331 self.addLink(r2, last_paired_ls)
332
333 # External IPv4 Host behind r2
334 rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
335 self.addLink(r2, rh2)
336
337 # External IPv6 Host behind r2
338 rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
339 self.addLink(r2, rh2v6)
340
341 # Another external IPv6 Host behind r1
342 rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801')
343 self.addLink(r2, rh22v6)
344
You Wang79577812018-02-27 16:39:50 -0800345 # create dhcp servers
346 if dhcp:
347 cs1 = self.addSwitch('cs1', cls=OVSBridge)
348 self.addLink(cs1, self.leafs[4])
349 if ipv4:
350 dhcp4 = self.addHost( 'dhcp', cls=TrellisHost,
351 mac="00:bb:00:00:00:01", ips=["10.0.3.253/24"],
352 gateway="10.0.3.254", dhcpServer=True)
353 self.addLink(dhcp4, cs1, **linkopts)
354 if ipv6:
355 dhcp6 = self.addHost( 'dhcp6', cls=TrellisHost,
356 mac="00:cc:00:00:00:01", ips=["2000::3fd/120"],
357 gateway="2000::3ff", dhcpServer=True, ipv6=True)
358 self.addLink(dhcp6, cs1, **linkopts)
359
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800360
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800361def config( opts ):
362
363 dhcp = bool(opts.dhcp)
364 routers = bool(opts.routers)
365 ipv6 = bool(opts.ipv6)
366 ipv4 = bool(opts.ipv4)
367
368 if opts.onosIp != '':
369 controllers = opts.onosIp.split( ',' )
370 else:
371 controllers = ['127.0.0.1']
372 topo = ComcastLeafSpineFabric(dhcp=dhcp, routers=routers, ipv6=ipv6,
373 ipv4=ipv4)
374
375 net = Mininet( topo=topo, link=TCLink, build=False,
376 controller=None, autoSetMacs=True )
377 i = 0
378 for ip in controllers:
379 net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
380 i += 1
381
382 net.build()
383 net.start()
384 CLI( net )
385 net.stop()
386
387
388if __name__ == '__main__':
389 setLogLevel('info')
390 config(opts)
391 os.system('sudo mn -c')
392