blob: 568760bb702c8bf2458109db0f7f510799584f4a [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
You Wang91befd72018-02-28 16:41:23 -0800262 # Note: Change "fpm connection ip" to $OC1 in zebradbgp1.conf and zebradbgp2.conf to make quagga work correctly
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800263 if routers:
264 last_ls = self.leafs[4]
You Wang91befd72018-02-28 16:41:23 -0800265 last_paired_ls = self.leafs[3]
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800266
267 # Control plane switch (for quagga fpm)
268 cs0 = self.addSwitch('cs0', cls=OVSBridge)
269
270 # Control plane NAT (for quagga fpm)
271 nat = self.addHost('nat', cls=NAT,
272 ip='172.16.0.1/12',
273 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
274 self.addLink(cs0, nat)
275
276 # Internal Quagga bgp1
277 intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
278 {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}],
279 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}}
280 bgp1 = self.addHost('bgp1', cls=BgpRouter,
281 interfaces=intfs,
282 quaggaConfFile='./bgpdbgp1.conf',
283 zebraConfFile='./zebradbgp1.conf')
284 self.addLink(bgp1, last_paired_ls)
285 self.addLink(bgp1, cs0)
286
287 # Internal Quagga bgp2
288 intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
289 {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
290 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
291 bgp2 = self.addHost('bgp2', cls=BgpRouter,
292 interfaces=intfs,
293 quaggaConfFile='./bgpdbgp2.conf',
294 zebraConfFile='./zebradbgp2.conf')
295 self.addLink(bgp2, last_ls)
296 self.addLink(bgp2, cs0)
297
298 # External Quagga r1
299 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
300 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
301 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']},
302 'r1-eth3': {'ipAddrs': ['2000::9901/120']},
303 'r1-eth4': {'ipAddrs': ['2000::7701/120']}}
304 r1 = self.addHost('r1', cls=BgpRouter,
305 interfaces=intfs,
306 quaggaConfFile='./bgpdr1.conf')
307 self.addLink(r1, last_paired_ls)
308 self.addLink(r1, last_ls)
309
310 # External IPv4 Host behind r1
You Wang91befd72018-02-28 16:41:23 -0800311 rh1v4 = self.addHost('rh1v4', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
312 self.addLink(r1, rh1v4)
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800313
314 # External IPv6 Host behind r1
315 rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
316 self.addLink(r1, rh1v6)
317
318 # Another external IPv6 Host behind r1
319 rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701')
320 self.addLink(r1, rh11v6)
321
322 # External Quagga r2
323 intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
324 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
325 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']},
326 'r2-eth3': {'ipAddrs': ['2000::9901/120']},
327 'r2-eth4': {'ipAddrs': ['2000::8801/120']}}
328 r2 = self.addHost('r2', cls=BgpRouter,
329 interfaces=intfs,
330 quaggaConfFile='./bgpdr2.conf')
331 self.addLink(r2, last_ls)
332 self.addLink(r2, last_paired_ls)
333
334 # External IPv4 Host behind r2
You Wang91befd72018-02-28 16:41:23 -0800335 rh2v4 = self.addHost('rh2v4', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
336 self.addLink(r2, rh2v4)
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800337
338 # External IPv6 Host behind r2
You Wang91befd72018-02-28 16:41:23 -0800339 rh2v6 = self.addHost('rh2v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800340 self.addLink(r2, rh2v6)
341
342 # Another external IPv6 Host behind r1
343 rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801')
344 self.addLink(r2, rh22v6)
345
You Wang79577812018-02-27 16:39:50 -0800346 # create dhcp servers
347 if dhcp:
348 cs1 = self.addSwitch('cs1', cls=OVSBridge)
349 self.addLink(cs1, self.leafs[4])
350 if ipv4:
351 dhcp4 = self.addHost( 'dhcp', cls=TrellisHost,
You Wang91befd72018-02-28 16:41:23 -0800352 mac="00:cc:00:00:00:01", ips=["10.0.3.253/24"],
You Wang79577812018-02-27 16:39:50 -0800353 gateway="10.0.3.254", dhcpServer=True)
354 self.addLink(dhcp4, cs1, **linkopts)
355 if ipv6:
356 dhcp6 = self.addHost( 'dhcp6', cls=TrellisHost,
You Wang91befd72018-02-28 16:41:23 -0800357 mac="00:dd:00:00:00:01", ips=["2000::3fd/120"],
You Wang79577812018-02-27 16:39:50 -0800358 gateway="2000::3ff", dhcpServer=True, ipv6=True)
359 self.addLink(dhcp6, cs1, **linkopts)
360
Andreas Pantelopoulos971c91d2018-02-12 11:28:10 -0800361
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800362def config( opts ):
363
364 dhcp = bool(opts.dhcp)
365 routers = bool(opts.routers)
366 ipv6 = bool(opts.ipv6)
367 ipv4 = bool(opts.ipv4)
368
369 if opts.onosIp != '':
370 controllers = opts.onosIp.split( ',' )
371 else:
372 controllers = ['127.0.0.1']
373 topo = ComcastLeafSpineFabric(dhcp=dhcp, routers=routers, ipv6=ipv6,
374 ipv4=ipv4)
375
376 net = Mininet( topo=topo, link=TCLink, build=False,
377 controller=None, autoSetMacs=True )
378 i = 0
379 for ip in controllers:
380 net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
381 i += 1
382
383 net.build()
384 net.start()
385 CLI( net )
386 net.stop()
387
388
389if __name__ == '__main__':
390 setLogLevel('info')
391 config(opts)
392 os.system('sudo mn -c')
393