blob: e02a675b4ca116fa61bb8134ecdb87a4a4d49eb8 [file] [log] [blame]
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -07001#!/usr/bin/python
2import os
3import re
4from optparse import OptionParser
5
6from ipaddress import ip_network
You Wang53dba1e2018-02-02 17:45:44 -08007from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -07008from mininet.link import TCLink
9from mininet.log import setLogLevel
10from mininet.net import Mininet
11from mininet.topo import Topo
12from mininet.nodelib import NAT
13from mininet.cli import CLI
14
You Wang5102af12018-02-08 12:30:12 -080015from routinglib import BgpRouter
You Wang53dba1e2018-02-02 17:45:44 -080016from trellislib import TrellisHost, DhcpRelay
17from functools import partial
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070018
You Wang68568b12019-03-04 11:49:57 -080019from bmv2 import ONOSBmv2Switch
20
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070021# Parse command line options and dump results
22def parseOptions():
23 "Parse command line options"
24 parser = OptionParser()
25 parser.add_option( '--spine', dest='spine', type='int', default=2,
26 help='number of spine switches, default=2' )
27 parser.add_option( '--leaf', dest='leaf', type='int', default=2,
28 help='number of leaf switches, default=2' )
29 parser.add_option( '--fanout', dest='fanout', type='int', default=2,
30 help='number of hosts per leaf switch, default=2' )
31 parser.add_option( '--onos-ip', dest='onosIp', type='str', default='',
32 help='IP address list of ONOS instances, separated by comma(,). Overrides --onos option' )
33 parser.add_option( '--ipv6', action="store_true", dest='ipv6',
34 help='hosts are capable to use also ipv6' )
35 parser.add_option( '--dual-homed', action="store_true", dest='dualhomed', default=False,
36 help='True if the topology is dual-homed, default=False' )
37 parser.add_option( '--vlan', dest='vlan', type='str', default='',
38 help='list of vlan id for hosts, separated by comma(,).'
39 'Empty or id with 0 will be unconfigured.' )
You Wang53dba1e2018-02-02 17:45:44 -080040 parser.add_option( '--dhcp-client', action="store_true", dest='dhcpClient', default=False,
41 help='Set hosts as DhcpClient if True' )
42 parser.add_option( '--dhcp-relay', action="store_true", dest='dhcpRelay', default=False,
43 help='Connect half of the hosts to switch indirectly (via DHCP relay) if True' )
44 parser.add_option( '--multiple-dhcp-server', action="store_true", dest='multipleServer', default=False,
45 help='Use another DHCP server for indirectly connected DHCP clients if True' )
46 parser.add_option( '--remote-dhcp-server', action="store_true", dest='remoteServer', default=False,
47 help='Connect DHCP server indirectly (via gateway) if True' )
You Wang68568b12019-03-04 11:49:57 -080048 parser.add_option( '--switch', dest='switch', type='str', default='ovs',
49 help='Switch type: ovs, bmv2 (with fabric.p4)' )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070050 ( options, args ) = parser.parse_args()
51 return options, args
52
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070053opts, args = parseOptions()
54
55IP6_SUBNET_CLASS = 120
56IP4_SUBNET_CLASS = 24
You Wang68568b12019-03-04 11:49:57 -080057FABRIC_PIPECONF = "org.onosproject.pipelines.fabric"
58
59SWITCH_TO_PARAMS_DICT = {
60 "ovs": dict(cls=OVSSwitch),
61 "bmv2": dict(cls=ONOSBmv2Switch, pipeconf=FABRIC_PIPECONF)
62}
63if opts.switch not in SWITCH_TO_PARAMS_DICT:
64 raise Exception("Unknown switch type '%s'" % opts.switch)
65SWITCH_PARAMS = SWITCH_TO_PARAMS_DICT[opts.switch]
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070066
67# TODO: DHCP support
68class IpHost( Host ):
69
70 def __init__( self, name, *args, **kwargs ):
71 super( IpHost, self ).__init__( name, *args, **kwargs )
72 gateway = re.split( '\.|/', kwargs[ 'ip' ] )
73 gateway[ 3 ] = '254'
74 self.gateway = '.'.join( gateway[ 0:4 ] )
75
76 def config( self, **kwargs ):
77 Host.config( self, **kwargs )
78 mtu = "ifconfig " + self.name + "-eth0 mtu 1490"
79 self.cmd( mtu )
80 self.cmd( 'ip route add default via %s' % self.gateway )
81
82class DualHomedIpHost(IpHost):
83 def __init__(self, name, *args, **kwargs):
84 super(DualHomedIpHost, self).__init__(name, **kwargs)
85 self.bond0 = None
86
87 def config(self, **kwargs):
88 super(DualHomedIpHost, self).config(**kwargs)
89 intf0 = self.intfs[0].name
90 intf1 = self.intfs[1].name
91 self.bond0 = "%s-bond0" % self.name
92 self.cmd('modprobe bonding')
93 self.cmd('ip link add %s type bond' % self.bond0)
94 self.cmd('ip link set %s down' % intf0)
95 self.cmd('ip link set %s down' % intf1)
96 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
97 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
98 self.cmd('ip addr flush dev %s' % intf0)
99 self.cmd('ip addr flush dev %s' % intf1)
100 self.cmd('ip link set %s up' % self.bond0)
101
102 def terminate(self, **kwargs):
103 self.cmd('ip link set %s down' % self.bond0)
104 self.cmd('ip link delete %s' % self.bond0)
105 self.cmd('kill -9 `cat %s`' % self.pidFile)
106 self.cmd('rm -rf %s' % self.pidFile)
107 super(DualHomedIpHost, self).terminate()
108
109
110# TODO: Implement IPv6 support
111class DualHomedLeafSpineFabric (Topo) :
You Wang53dba1e2018-02-02 17:45:44 -0800112 def __init__(self, spine = 2, leaf = 2, fanout = 2, vlan_id = [], ipv6 = False,
113 dhcp_client = False, dhcp_relay = False,
114 multiple_server = False, remote_server = False, **opts):
115 # TODO: add support to dhcp_relay, multiple_server and remote_server
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700116 Topo.__init__(self, **opts)
117 spines = dict()
118 leafs = dict()
119
120 # leaf should be 2 or 4
121
122 # calculate the subnets to use and set options
123 linkopts = dict( bw=100 )
124 # Create spine switches
125 for s in range(spine):
You Wang68568b12019-03-04 11:49:57 -0800126 spines[s] = self.addSwitch( 'spine10%s' % (s + 1),
127 dpid="00000000010%s" % (s + 1),
128 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700129
130 # Create leaf switches
131 for ls in range(leaf):
You Wang68568b12019-03-04 11:49:57 -0800132 leafs[ls] = self.addSwitch( 'leaf%s' % (ls + 1),
133 dpid="00000000000%s" % (ls + 1),
134 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700135
136 # Connect leaf to all spines with dual link
137 for s in range( spine ):
138 switch = spines[ s ]
139 self.addLink(leafs[ls], switch, **linkopts)
140 self.addLink(leafs[ls], switch, **linkopts)
141
142 # Add hosts after paired ToR switches are added.
143 if ls % 2 == 0:
144 continue
145
146 # Add leaf-leaf link
147 self.addLink(leafs[ls], leafs[ls-1])
148
149 dual_ls = ls / 2
150 # Add hosts
151 for f in range(fanout):
You Wang53dba1e2018-02-02 17:45:44 -0800152 name = 'h%s%s' % (dual_ls * fanout + f + 1, "v6" if ipv6 else "")
153 if ipv6:
154 ips = ['2000::%d0%d/%d' % (dual_ls+2, f+1, IP6_SUBNET_CLASS)]
155 gateway = '2000::%dff' % (dual_ls+2)
156 mac = '00:bb:00:00:00:%02x' % (dual_ls * fanout + f + 1)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700157 else:
You Wang53dba1e2018-02-02 17:45:44 -0800158 ips = ['10.0.%d.%d/%d' % (dual_ls+2, f+1, IP4_SUBNET_CLASS)]
159 gateway = '10.0.%d.254' % (dual_ls+2)
160 mac = '00:aa:00:00:00:%02x' % (dual_ls * fanout + f + 1)
161 host = self.addHost( name=name, cls=TrellisHost, ips=ips, gateway=gateway, mac=mac,
162 vlan=vlan_id[ dual_ls*fanout + f ] if vlan_id[dual_ls * fanout + f] != 0 else None,
163 dhcpClient=dhcp_client, ipv6=ipv6, dualHomed=True )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700164 self.addLink(host, leafs[ls], **linkopts)
165 self.addLink(host, leafs[ls-1], **linkopts)
166
167 last_ls = leafs[leaf-2]
168 last_paired_ls = leafs[leaf-1]
169 # Create common components
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700170 # Control plane switch (for DHCP servers)
171 cs1 = self.addSwitch('cs1', cls=OVSBridge)
172 self.addLink(cs1, last_ls)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700173
174 # Control plane switch (for quagga fpm)
175 cs0 = self.addSwitch('cs0', cls=OVSBridge)
176
177 # Control plane NAT (for quagga fpm)
178 nat = self.addHost('nat', cls=NAT,
179 ip='172.16.0.1/12',
180 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
181 self.addLink(cs0, nat)
182
183 # Internal Quagga bgp1
You Wang051b55f2018-06-04 15:24:51 -0700184 intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03'},
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700185 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
186 bgp1 = self.addHost('bgp1', cls=BgpRouter,
187 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800188 quaggaConfFile='./bgpdbgp1.conf',
189 zebraConfFile='./zebradbgp1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700190 self.addLink(bgp1, last_ls)
191 self.addLink(bgp1, cs0)
192
193 # Internal Quagga bgp2
194 intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
195 {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
196 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
197 bgp2 = self.addHost('bgp2', cls=BgpRouter,
198 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800199 quaggaConfFile='./bgpdbgp2.conf',
200 zebraConfFile='./zebradbgp2.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700201 self.addLink(bgp2, last_paired_ls)
202 self.addLink(bgp2, cs0)
203
204 # External Quagga r1
205 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
206 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
207 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']}}
208 r1 = self.addHost('r1', cls=BgpRouter,
209 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800210 quaggaConfFile='./bgpdr1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700211 self.addLink(r1, last_ls)
212 self.addLink(r1, last_paired_ls)
213
214 # External IPv4 Host behind r1
You Wang5102af12018-02-08 12:30:12 -0800215 rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700216 self.addLink(r1, rh1)
217
218 # External Quagga r2
219 intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
220 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
221 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']}}
222 r2 = self.addHost('r2', cls=BgpRouter,
223 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800224 quaggaConfFile='./bgpdr2.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700225 self.addLink(r2, last_ls)
226 self.addLink(r2, last_paired_ls)
227
228 # External IPv4 Host behind r2
You Wang5102af12018-02-08 12:30:12 -0800229 rh2 = self.addHost('rh2', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700230 self.addLink(r2, rh2)
231
You Wang53dba1e2018-02-02 17:45:44 -0800232 # DHCP server
233 if ipv6:
234 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
235 ips=['2000::3fd/120'], gateway='2000::3ff',
236 dhcpServer=True, ipv6=True)
237 self.addLink(dhcp, cs1)
238 else:
239 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
240 ips=['10.0.3.253/24'], gateway='10.0.3.254',
241 dhcpServer=True)
242 self.addLink(dhcp, cs1)
243
244
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700245class LeafSpineFabric (Topo) :
You Wang53dba1e2018-02-02 17:45:44 -0800246 def __init__(self, spine = 2, leaf = 2, fanout = 2, vlan_id = [], ipv6 = False,
247 dhcp_client = False, dhcp_relay = False,
248 multiple_server = False, remote_server = False, **opts):
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700249 Topo.__init__(self, **opts)
250 spines = dict()
251 leafs = dict()
252
253 # TODO: support IPv6 hosts
254 linkopts = dict( bw=100 )
255
256 # Create spine switches
257 for s in range(spine):
You Wang68568b12019-03-04 11:49:57 -0800258 spines[s] = self.addSwitch( 'spine10%s' % (s + 1),
259 dpid="00000000010%s" % (s + 1),
260 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700261
262 # Create leaf switches
263 for ls in range(leaf):
You Wang68568b12019-03-04 11:49:57 -0800264 leafs[ls] = self.addSwitch( 'leaf%s' % (ls + 1),
265 dpid="00000000000%s" % (ls + 1),
266 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700267
268 # Connect leaf to all spines
269 for s in range( spine ):
270 switch = spines[ s ]
271 self.addLink( leafs[ ls ], switch, **linkopts )
272
273 # If dual-homed ToR, add hosts only when adding second switch at each edge-pair
274 # When the number of leaf switches is odd, leave the last switch as a single ToR
275
276 # Add hosts
277 for f in range(fanout):
You Wang53dba1e2018-02-02 17:45:44 -0800278 name = 'h%s%s' % (ls * fanout + f + 1, "v6" if ipv6 else "")
279 if ipv6:
280 ips = ['2000::%d0%d/%d' % (ls+2, f+1, IP6_SUBNET_CLASS)]
281 gateway = '2000::%dff' % (ls+2)
282 mac = '00:bb:00:00:00:%02x' % (ls * fanout + f + 1)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700283 else:
You Wang53dba1e2018-02-02 17:45:44 -0800284 ips = ['10.0.%d.%d/%d' % (ls+2, f+1, IP4_SUBNET_CLASS)]
285 gateway = '10.0.%d.254' % (ls+2)
286 mac = '00:aa:00:00:00:%02x' % (ls * fanout + f + 1)
287 host = self.addHost( name=name, cls=TrellisHost, ips=ips, gateway=gateway, mac=mac,
288 vlan=vlan_id[ ls*fanout + f ] if vlan_id[ls * fanout + f] != 0 else None,
289 dhcpClient=dhcp_client, ipv6=ipv6 )
290 if dhcp_relay and f % 2:
291 relayIndex = ls * fanout + f + 1
292 if ipv6:
293 intfs = {
294 'relay%s-eth0' % relayIndex: { 'ipAddrs': ['2000::%dff/%d' % (leaf + ls + 2, IP6_SUBNET_CLASS)] },
295 'relay%s-eth1' % relayIndex: { 'ipAddrs': ['2000::%d5%d/%d' % (ls + 2, f, IP6_SUBNET_CLASS)] }
296 }
297 if remote_server:
298 serverIp = '2000::99fd'
299 elif multiple_server:
300 serverIp = '2000::3fc'
301 else:
302 serverIp = '2000::3fd'
303 dhcpRelay = self.addHost(name='relay%s' % relayIndex, cls=DhcpRelay, serverIp=serverIp,
304 gateway='2000::%dff' % (ls+2), interfaces=intfs)
305 else:
306 intfs = {
307 'relay%s-eth0' % relayIndex: { 'ipAddrs': ['10.0.%d.254/%d' % (leaf + ls + 2, IP4_SUBNET_CLASS)] },
308 'relay%s-eth1' % relayIndex: { 'ipAddrs': ['10.0.%d.%d/%d' % (ls + 2, f + 99, IP4_SUBNET_CLASS)] }
309 }
310 if remote_server:
311 serverIp = '10.0.99.3'
312 elif multiple_server:
313 serverIp = '10.0.3.252'
314 else:
315 serverIp = '10.0.3.253'
316 dhcpRelay = self.addHost(name='relay%s' % relayIndex, cls=DhcpRelay, serverIp=serverIp,
317 gateway='10.0.%d.254' % (ls+2), interfaces=intfs)
318 self.addLink(host, dhcpRelay, **linkopts)
319 self.addLink(dhcpRelay, leafs[ls], **linkopts)
320 else:
321 self.addLink(host, leafs[ls], **linkopts)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700322
323 last_ls = leafs[leaf-1]
324 # Create common components
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700325 # Control plane switch (for DHCP servers)
326 cs1 = self.addSwitch('cs1', cls=OVSBridge)
327 self.addLink(cs1, last_ls)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700328
329 # Control plane switch (for quagga fpm)
330 cs0 = self.addSwitch('cs0', cls=OVSBridge)
331
332 # Control plane NAT (for quagga fpm)
333 nat = self.addHost('nat', cls=NAT,
334 ip='172.16.0.1/12',
335 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
336 self.addLink(cs0, nat)
337
338 # Internal Quagga bgp1
339 intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'},
340 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
341 bgp1 = self.addHost('bgp1', cls=BgpRouter,
342 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800343 quaggaConfFile='./bgpdbgp1.conf',
344 zebraConfFile='./zebradbgp1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700345 self.addLink(bgp1, last_ls)
346 self.addLink(bgp1, cs0)
347
348 # External Quagga r1
349 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
350 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']},
351 'r1-eth2': {'ipAddrs': ['2000::9901/120']}}
352 r1 = self.addHost('r1', cls=BgpRouter,
353 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800354 quaggaConfFile='./bgpdr1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700355 self.addLink(r1, last_ls)
356
You Wang53dba1e2018-02-02 17:45:44 -0800357 # External switch behind r1
358 rs0 = self.addSwitch('rs0', cls=OVSBridge)
359 self.addLink(r1, rs0)
360
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700361 # External IPv4 Host behind r1
You Wang5102af12018-02-08 12:30:12 -0800362 rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700363 self.addLink(r1, rh1)
364
You Wang53dba1e2018-02-02 17:45:44 -0800365 # External IPv6 Host behind r1
366 rh1v6 = self.addHost('rh1v6', cls=TrellisHost, ips=['2000::9902/120'], gateway='2000::9901')
367 self.addLink(r1, rh1v6)
368
369 # DHCP server
370 if ipv6:
371 if remote_server:
372 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
373 ips=['2000::99fd/120'], gateway='2000::9901',
374 dhcpServer=True, ipv6=True)
375 self.addLink(rs0, dhcp)
376 else:
377 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
378 ips=['2000::3fd/120'], gateway='2000::3ff',
379 dhcpServer=True, ipv6=True)
380 self.addLink(dhcp, cs1)
381 if multiple_server:
382 dhcp2 = self.addHost('dhcp2', cls=TrellisHost, mac='00:99:00:00:00:02',
383 ips=['2000::3fc/120'], gateway='2000::3ff',
384 dhcpServer=True, ipv6=True)
385 self.addLink(dhcp2, cs1)
386 else:
387 if remote_server:
388 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
389 ips=['10.0.99.3/24'], gateway='10.0.99.1',
390 dhcpServer=True)
391 self.addLink(rs0, dhcp)
392 else:
393 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
394 ips=['10.0.3.253/24'], gateway='10.0.3.254',
395 dhcpServer=True)
396 self.addLink(dhcp, cs1)
397 if multiple_server:
398 dhcp2 = self.addHost('dhcp2', cls=TrellisHost, mac='00:99:00:00:00:02',
399 ips=['10.0.3.252/24'], gateway='10.0.3.254',
400 dhcpServer=True)
401 self.addLink(dhcp2, cs1)
402
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700403def config( opts ):
404 spine = opts.spine
405 leaf = opts.leaf
406 fanout = opts.fanout
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700407 dualhomed = opts.dualhomed
408 if opts.vlan == '':
409 vlan = [0] * (((leaf / 2) if dualhomed else leaf) * fanout)
410 else:
411 vlan = [int(vlan_id) if vlan_id != '' else 0 for vlan_id in opts.vlan.split(',')]
412
413 if opts.onosIp != '':
414 controllers = opts.onosIp.split( ',' )
415 else:
416 controllers = ['127.0.0.1']
417
418 if len(vlan) != ((leaf / 2) if dualhomed else leaf ) * fanout:
419 print "Invalid vlan configuration is given."
420 return
421
You Wang53dba1e2018-02-02 17:45:44 -0800422 if dualhomed:
423 if leaf % 2 == 1 or leaf == 0:
424 print "Even number of leaf switches (at least two) are needed to build dual-homed topology."
425 return
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700426 else:
You Wang53dba1e2018-02-02 17:45:44 -0800427 topo = DualHomedLeafSpineFabric(spine=spine, leaf=leaf, fanout=fanout, vlan_id=vlan,
428 ipv6=opts.ipv6,
429 dhcp_client=opts.dhcpClient,
430 dhcp_relay=opts.dhcpRelay,
431 multiple_server=opts.multipleServer,
432 remote_server=opts.remoteServer)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700433 else:
You Wang53dba1e2018-02-02 17:45:44 -0800434 topo = LeafSpineFabric(spine=spine, leaf=leaf, fanout=fanout, vlan_id=vlan, ipv6=opts.ipv6,
435 dhcp_client=opts.dhcpClient,
436 dhcp_relay=opts.dhcpRelay,
437 multiple_server=opts.multipleServer,
438 remote_server=opts.remoteServer)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700439
440 net = Mininet( topo=topo, link=TCLink, build=False,
441 controller=None, autoSetMacs=True )
442 i = 0
443 for ip in controllers:
444 net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
445 i += 1
446 net.build()
447 net.start()
448 CLI( net )
449 net.stop()
450
451if __name__ == '__main__':
452 setLogLevel('info')
453 config(opts)
454 os.system('sudo mn -c')