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