blob: 7b4c19e7b3ce614828ef3fe62cfb718927503574 [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
15from trellislib import DhcpServer, TaggedRoutedHost, DualHomedRoutedHost, DualHomedTaggedRoutedHost, DhcpClient, Dhcp6Client, DhcpServer, Dhcp6Server
16
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
37class DualHomedTaggedHostWithIpv4(Host):
38
39 def __init__(self, name, ip, gateway, dhcp, vlan, *args, **kwargs):
40 super(DualHomedTaggedHostWithIpv4, self).__init__(name, **kwargs)
Andreas Pantelopoulosb7904ce2018-02-07 16:24:49 -080041 self.vlanBond0 = None
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080042 self.bond0 = None
43 self.ip = ip
44 self.gateway = gateway
45 self.dhcp = dhcp
46 self.vlan = vlan
47
48 def config(self, **kwargs):
49 super(DualHomedTaggedHostWithIpv4, self).config(**kwargs)
50 intf0 = self.intfs[0].name
51 intf1 = self.intfs[1].name
52
53 self.bond0 = "%s-bond0" % self.name
54 self.vlanBondIntf = "%s.%s" % (self.bond0, self.vlan)
55
56 self.cmd('modprobe bonding')
57 self.cmd('ip link add %s type bond' % self.bond0)
58 self.cmd('ip link set %s down' % intf0)
59 self.cmd('ip link set %s down' % intf1)
60 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
61 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
62 self.cmd('ip addr flush dev %s' % intf0)
63 self.cmd('ip addr flush dev %s' % intf1)
64 self.cmd('ip link set %s up' % self.bond0)
65
66 self.cmd('ip link add link %s name %s type vlan id %s' % (self.bond0,
67 self.vlanBondIntf, self.vlan))
68
69 self.cmd('ip link set up %s' % self.vlanBondIntf)
70 self.cmd('ip addr add %s/24 dev %s' % (self.ip, self.vlanBondIntf))
71 self.cmd('ip route add default via %s' % self.gateway)
72
73 default_intf = self.defaultIntf()
Andreas Pantelopoulosb7904ce2018-02-07 16:24:49 -080074 default_intf.name = self.vlanBondIntf
75 self.nameToIntf[self.vlanBond0] = default_intf
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080076
77 def terminate(self, **kwargs):
78 self.cmd('ip link set %s down' % self.bond0)
79 self.cmd('ip link delete %s' % self.bond0)
80 super(DualHomedTaggedHostWithIpv4, self).terminate()
81
82class DualHomedUntaggedHostWithIpv4(Host):
83
84 def __init__(self, name, ip, gateway, dhcp, *args, **kwargs):
85 super(DualHomedUntaggedHostWithIpv4, self).__init__(name, **kwargs)
86 self.bond0 = None
87 self.ip = ip
88 self.gateway = gateway
89 self.dhcp = dhcp
90
91 def config(self, **kwargs):
92 super(DualHomedUntaggedHostWithIpv4, self).config(**kwargs)
93 intf0 = self.intfs[0].name
94 intf1 = self.intfs[1].name
95
96 self.bond0 = "%s-bond0" % self.name
97 self.cmd('modprobe bonding')
98 self.cmd('ip link add %s type bond' % self.bond0)
99 self.cmd('ip link set %s down' % intf0)
100 self.cmd('ip link set %s down' % intf1)
101 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
102 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
103 self.cmd('ip addr flush dev %s' % intf0)
104 self.cmd('ip addr flush dev %s' % intf1)
105 self.cmd('ip link set %s up' % self.bond0)
106 self.cmd('ip addr add %s/24 dev %s' % (self.ip, self.bond0))
107 self.cmd('ip route add default via %s' % self.gateway)
108
109 default_intf = self.defaultIntf()
110 default_intf.name = self.bond0
111 self.nameToIntf[self.bond0] = default_intf
112
113 def terminate(self, **kwargs):
114 self.cmd('ip link set %s down' % self.bond0)
115 self.cmd('ip link delete %s' % self.bond0)
116 super(DualHomedUntaggedHostWithIpv4, self).terminate()
117
118class TaggedHostWithIpv4(Host):
119 '''
120 Tagged host configured with a static ip address.
121 '''
122 def __init__(self, name, ip, gateway, dhcp, vlan, *args, **kwargs):
123 super(TaggedHostWithIpv4, self).__init__(name, *args, **kwargs)
124 self.ip = ip
125 self.gateway = gateway
126 self.vlan = vlan
127 self.vlanIntf = None
128 self.dhcp = dhcp
129
130 def config(self, **kwargs):
131 Host.config(self, **kwargs)
132
133 intf = self.defaultIntf()
134 self.vlanIntf = "%s.%s" % (intf, self.vlan)
135 self.cmd('ip -4 addr flush dev %s' % intf)
136 self.cmd('ip link add link %s name %s type vlan id %s' % (intf, self.vlanIntf, self.vlan))
137 self.cmd('ip link set up %s' % self.vlanIntf)
138 self.cmd('ip addr add %s/24 dev %s' % (self.ip, self.vlanIntf))
139 self.cmd('ip route add default via %s' % self.gateway)
140 intf.name = self.vlanIntf
141 self.nameToIntf[self.vlanIntf] = intf
142
143 def terminate(self, **kwargs):
144 self.cmd('ip link remove link %s' % self.vlanIntf)
145 super(TaggedHostWithIpv4, self).terminate()
146
147
148class UnTaggedHostWithIpv4(Host):
149 '''
150 Untagged host configured with a static ip address.
151 '''
152 def __init__(self, name, ip, gateway, dhcp, *args, **kwargs):
153 super(UnTaggedHostWithIpv4, self).__init__(name, *args, **kwargs)
154 self.ip = ip
155 self.gateway = gateway
156 self.dhcp = dhcp
157
158 def config(self, **kwargs):
159 Host.config(self, **kwargs)
160
161 intf = self.defaultIntf()
162 self.cmd('ip -4 addr flush dev %s' % intf)
163 self.cmd('ip addr add %s/24 dev %s' % (self.ip, intf))
164 self.cmd('ip route add default via %s' % self.gateway)
165
166 def terminate(self, **kwargs):
167 super(UnTaggedHostWithIpv4, self).terminate()
168
169class ComcastLeafSpineFabric(Topo):
170
171 spines = dict()
172 leafs = dict()
173 hosts_dict = dict()
174
175 def createIpv4Hosts(self, dhcp):
176
177 h1 = self.addHost('h1v4', cls=UnTaggedHostWithIpv4,
178 mac='00:aa:00:00:00:01', ip='10.1.0.1',
179 gateway='10.1.0.254', dhcp=dhcp)
180 self.addLink(h1, self.leafs[0])
181 self.hosts_dict['h1v4'] = h1
182
183 h2 = self.addHost('h2v4', cls=UnTaggedHostWithIpv4,
184 mac='00:aa:00:00:01:01', ip='10.1.10.1',
185 gateway='10.1.10.254', dhcp=dhcp)
186 self.addLink(h2, self.leafs[0])
187 self.hosts_dict['h2v4'] = h2
188
189 h3 = self.addHost('h3v4', cls=UnTaggedHostWithIpv4,
190 mac='00:aa:00:00:00:02', ip='10.2.0.1',
191 gateway='10.2.0.254', dhcp=dhcp)
192 self.addLink(h3, self.leafs[1])
193 self.hosts_dict['h3v4'] = h3
194
195 h4 = self.addHost('h4v4', cls=DualHomedUntaggedHostWithIpv4,
196 mac='00:aa:00:00:00:03', ip='10.2.30.1',
197 gateway='10.2.30.254', dhcp=dhcp)
198 self.addLink(h4, self.leafs[1])
199 self.addLink(h4, self.leafs[2])
200 self.hosts_dict['h4v4'] = h4
201
202 h5 = self.addHost('h5v4', cls=DualHomedTaggedHostWithIpv4,
203 mac='00:aa:00:00:00:04', ip='10.2.20.1',
204 gateway='10.2.20.254', dhcp=dhcp, vlan=30)
205 self.addLink(h5, self.leafs[1])
206 self.addLink(h5, self.leafs[2])
207 self.hosts_dict['h5v4'] = h5
208
209 h6 = self.addHost('h6v4', cls=TaggedHostWithIpv4,
210 mac='00:aa:00:00:00:05', ip='10.2.10.1',
211 gateway='10.2.10.254', dhcp=dhcp, vlan=20)
212 self.addLink(h6, self.leafs[2])
213 self.hosts_dict['h6v4'] = h6
214
215 h7 = self.addHost('h7v4', cls=TaggedHostWithIpv4,
216 mac='00:aa:00:00:01:05', ip='10.2.40.1',
217 gateway='10.2.40.254', dhcp=dhcp, vlan=40)
218 self.addLink(h7, self.leafs[2])
219 self.hosts_dict['h7v4'] = h7
220
221 h8 = self.addHost('h8v4', cls=TaggedHostWithIpv4,
222 mac='00:aa:00:00:00:06', ip='10.3.0.1',
223 gateway='10.3.0.254', dhcp=dhcp, vlan=30)
224 self.addLink(h8, self.leafs[3])
225 self.hosts_dict['h8v4'] = h8
226
227 h9 = self.addHost('h9v4', cls=DualHomedTaggedHostWithIpv4,
228 mac='00:aa:00:00:00:07', ip='10.3.10.1',
229 gateway='10.3.10.254', dhcp=dhcp, vlan=40)
230 self.addLink(h9, self.leafs[3])
231 self.addLink(h9, self.leafs[4])
232 self.hosts_dict['h9v4'] = h9
233
234 h10 = self.addHost('h10v4', cls=DualHomedTaggedHostWithIpv4,
235 mac='00:aa:00:00:00:08', ip='10.3.30.1',
236 gateway='10.3.30.254', dhcp=dhcp, vlan=40)
237 self.addLink(h10, self.leafs[3])
238 self.addLink(h10, self.leafs[4])
239 self.hosts_dict['h10v4'] = h10
240
241 h11 = self.addHost('h11v4', cls=TaggedHostWithIpv4,
242 mac='00:aa:00:00:00:0a', ip='10.3.20.1',
243 gateway='10.3.20.254', dhcp=dhcp, vlan=40)
244 self.addLink(h11, self.leafs[4])
245 self.hosts_dict['h11v4'] = h11
246
247 return
248
249 def createIpv6Hosts(self, dhcp):
250 print("NYI")
251 return
252
253 '''
254 Creates the topology employed by Comcast which is a 2x5
255 leaf spine traffic.
256
257 S1 S2
258
259 L1 L2 L3 L4 L5
260
261 Where L2/L3 and L4/L5 are paired switches.
262 Parameters for this topology :
263 dhcp = True/False : set up dhcp servers
264 routers = True/False : set up external routers
265 '''
266 def __init__(self, dhcp=False, routers=False, ipv4=False, ipv6=False, **opts):
267 Topo.__init__(self, **opts)
268
269 # TODO: support IPv6 hosts
270 linkopts = dict( bw=10 )
271
272 spine = 2
273 leaf = 5
274
275 # Create spine switches
276 for s in range(spine):
277 self.spines[s] = self.addSwitch('spine10%s' % (s + 1), dpid = "00000000010%s" % (s + 1) )
278
279 # Create leaf switches
280 for ls in range(leaf):
281 self.leafs[ls] = self.addSwitch('leaf%s' % (ls + 1), dpid = "00000000000%s" % ( ls + 1) )
282
283 # connecting leaf and spines, leafs 1-5 have double links
284 for s in range( spine ):
285 spine_switch = self.spines[s]
286
287 for ls in range( leaf ):
288 leaf_switch = self.leafs[ls]
289
290 self.addLink( spine_switch, leaf_switch, **linkopts )
291 if ls > 0:
292 self.addLink( spine_switch, leaf_switch, **linkopts )
293
294 # connect paired leafs
295 self.addLink(self.leafs[1], self.leafs[2], **linkopts)
296 self.addLink(self.leafs[3], self.leafs[4], **linkopts)
297
298 # create hosts
299 if ipv6:
300 self.createIpv6Hosts(dhcp)
301
302 if ipv4:
303 self.createIpv4Hosts(dhcp)
304
305 if not ipv4 and not ipv6:
306 print("No hosts were created!")
307
308def config( opts ):
309
310 dhcp = bool(opts.dhcp)
311 routers = bool(opts.routers)
312 ipv6 = bool(opts.ipv6)
313 ipv4 = bool(opts.ipv4)
314
315 if opts.onosIp != '':
316 controllers = opts.onosIp.split( ',' )
317 else:
318 controllers = ['127.0.0.1']
319 topo = ComcastLeafSpineFabric(dhcp=dhcp, routers=routers, ipv6=ipv6,
320 ipv4=ipv4)
321
322 net = Mininet( topo=topo, link=TCLink, build=False,
323 controller=None, autoSetMacs=True )
324 i = 0
325 for ip in controllers:
326 net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
327 i += 1
328
329 net.build()
330 net.start()
331 CLI( net )
332 net.stop()
333
334
335if __name__ == '__main__':
336 setLogLevel('info')
337 config(opts)
338 os.system('sudo mn -c')
339