blob: 8668f83d9f5678894ed8368cc6ad1304fb33239c [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
Jon Halldac3eae2020-06-05 12:04:06 -070020from stratum import StratumBmv2Switch
You Wang68568b12019-03-04 11:49:57 -080021
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070022# Parse command line options and dump results
23def parseOptions():
24 "Parse command line options"
25 parser = OptionParser()
26 parser.add_option( '--spine', dest='spine', type='int', default=2,
27 help='number of spine switches, default=2' )
28 parser.add_option( '--leaf', dest='leaf', type='int', default=2,
29 help='number of leaf switches, default=2' )
30 parser.add_option( '--fanout', dest='fanout', type='int', default=2,
31 help='number of hosts per leaf switch, default=2' )
32 parser.add_option( '--onos-ip', dest='onosIp', type='str', default='',
33 help='IP address list of ONOS instances, separated by comma(,). Overrides --onos option' )
34 parser.add_option( '--ipv6', action="store_true", dest='ipv6',
35 help='hosts are capable to use also ipv6' )
36 parser.add_option( '--dual-homed', action="store_true", dest='dualhomed', default=False,
37 help='True if the topology is dual-homed, default=False' )
38 parser.add_option( '--vlan', dest='vlan', type='str', default='',
39 help='list of vlan id for hosts, separated by comma(,).'
40 'Empty or id with 0 will be unconfigured.' )
You Wang53dba1e2018-02-02 17:45:44 -080041 parser.add_option( '--dhcp-client', action="store_true", dest='dhcpClient', default=False,
42 help='Set hosts as DhcpClient if True' )
43 parser.add_option( '--dhcp-relay', action="store_true", dest='dhcpRelay', default=False,
44 help='Connect half of the hosts to switch indirectly (via DHCP relay) if True' )
45 parser.add_option( '--multiple-dhcp-server', action="store_true", dest='multipleServer', default=False,
46 help='Use another DHCP server for indirectly connected DHCP clients if True' )
47 parser.add_option( '--remote-dhcp-server', action="store_true", dest='remoteServer', default=False,
48 help='Connect DHCP server indirectly (via gateway) if True' )
You Wang68568b12019-03-04 11:49:57 -080049 parser.add_option( '--switch', dest='switch', type='str', default='ovs',
Jon Halldac3eae2020-06-05 12:04:06 -070050 help='Switch type: ovs, bmv2 (with fabric.p4), stratum' )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070051 ( options, args ) = parser.parse_args()
52 return options, args
53
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070054opts, args = parseOptions()
55
56IP6_SUBNET_CLASS = 120
57IP4_SUBNET_CLASS = 24
You Wang68568b12019-03-04 11:49:57 -080058FABRIC_PIPECONF = "org.onosproject.pipelines.fabric"
59
60SWITCH_TO_PARAMS_DICT = {
61 "ovs": dict(cls=OVSSwitch),
Jon Halldac3eae2020-06-05 12:04:06 -070062 "bmv2": dict(cls=ONOSBmv2Switch, pipeconf=FABRIC_PIPECONF),
63 "stratum": dict(cls=StratumBmv2Switch, pipeconf=FABRIC_PIPECONF, loglevel='debug')
You Wang68568b12019-03-04 11:49:57 -080064}
65if opts.switch not in SWITCH_TO_PARAMS_DICT:
66 raise Exception("Unknown switch type '%s'" % opts.switch)
67SWITCH_PARAMS = SWITCH_TO_PARAMS_DICT[opts.switch]
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070068
69# TODO: DHCP support
70class IpHost( Host ):
71
72 def __init__( self, name, *args, **kwargs ):
73 super( IpHost, self ).__init__( name, *args, **kwargs )
74 gateway = re.split( '\.|/', kwargs[ 'ip' ] )
75 gateway[ 3 ] = '254'
76 self.gateway = '.'.join( gateway[ 0:4 ] )
77
78 def config( self, **kwargs ):
79 Host.config( self, **kwargs )
80 mtu = "ifconfig " + self.name + "-eth0 mtu 1490"
81 self.cmd( mtu )
82 self.cmd( 'ip route add default via %s' % self.gateway )
83
84class DualHomedIpHost(IpHost):
85 def __init__(self, name, *args, **kwargs):
86 super(DualHomedIpHost, self).__init__(name, **kwargs)
87 self.bond0 = None
88
89 def config(self, **kwargs):
90 super(DualHomedIpHost, self).config(**kwargs)
91 intf0 = self.intfs[0].name
92 intf1 = self.intfs[1].name
93 self.bond0 = "%s-bond0" % self.name
94 self.cmd('modprobe bonding')
95 self.cmd('ip link add %s type bond' % self.bond0)
96 self.cmd('ip link set %s down' % intf0)
97 self.cmd('ip link set %s down' % intf1)
98 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
99 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
100 self.cmd('ip addr flush dev %s' % intf0)
101 self.cmd('ip addr flush dev %s' % intf1)
102 self.cmd('ip link set %s up' % self.bond0)
103
104 def terminate(self, **kwargs):
105 self.cmd('ip link set %s down' % self.bond0)
106 self.cmd('ip link delete %s' % self.bond0)
107 self.cmd('kill -9 `cat %s`' % self.pidFile)
108 self.cmd('rm -rf %s' % self.pidFile)
109 super(DualHomedIpHost, self).terminate()
110
111
112# TODO: Implement IPv6 support
113class DualHomedLeafSpineFabric (Topo) :
You Wang53dba1e2018-02-02 17:45:44 -0800114 def __init__(self, spine = 2, leaf = 2, fanout = 2, vlan_id = [], ipv6 = False,
115 dhcp_client = False, dhcp_relay = False,
116 multiple_server = False, remote_server = False, **opts):
117 # TODO: add support to dhcp_relay, multiple_server and remote_server
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700118 Topo.__init__(self, **opts)
119 spines = dict()
120 leafs = dict()
121
122 # leaf should be 2 or 4
123
124 # calculate the subnets to use and set options
125 linkopts = dict( bw=100 )
126 # Create spine switches
127 for s in range(spine):
You Wang68568b12019-03-04 11:49:57 -0800128 spines[s] = self.addSwitch( 'spine10%s' % (s + 1),
129 dpid="00000000010%s" % (s + 1),
130 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700131
132 # Create leaf switches
133 for ls in range(leaf):
You Wang68568b12019-03-04 11:49:57 -0800134 leafs[ls] = self.addSwitch( 'leaf%s' % (ls + 1),
135 dpid="00000000000%s" % (ls + 1),
136 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700137
138 # Connect leaf to all spines with dual link
139 for s in range( spine ):
140 switch = spines[ s ]
141 self.addLink(leafs[ls], switch, **linkopts)
142 self.addLink(leafs[ls], switch, **linkopts)
143
144 # Add hosts after paired ToR switches are added.
145 if ls % 2 == 0:
146 continue
147
148 # Add leaf-leaf link
149 self.addLink(leafs[ls], leafs[ls-1])
150
151 dual_ls = ls / 2
152 # Add hosts
153 for f in range(fanout):
You Wang53dba1e2018-02-02 17:45:44 -0800154 name = 'h%s%s' % (dual_ls * fanout + f + 1, "v6" if ipv6 else "")
155 if ipv6:
156 ips = ['2000::%d0%d/%d' % (dual_ls+2, f+1, IP6_SUBNET_CLASS)]
157 gateway = '2000::%dff' % (dual_ls+2)
158 mac = '00:bb:00:00:00:%02x' % (dual_ls * fanout + f + 1)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700159 else:
You Wang53dba1e2018-02-02 17:45:44 -0800160 ips = ['10.0.%d.%d/%d' % (dual_ls+2, f+1, IP4_SUBNET_CLASS)]
161 gateway = '10.0.%d.254' % (dual_ls+2)
162 mac = '00:aa:00:00:00:%02x' % (dual_ls * fanout + f + 1)
163 host = self.addHost( name=name, cls=TrellisHost, ips=ips, gateway=gateway, mac=mac,
164 vlan=vlan_id[ dual_ls*fanout + f ] if vlan_id[dual_ls * fanout + f] != 0 else None,
165 dhcpClient=dhcp_client, ipv6=ipv6, dualHomed=True )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700166 self.addLink(host, leafs[ls], **linkopts)
167 self.addLink(host, leafs[ls-1], **linkopts)
168
169 last_ls = leafs[leaf-2]
170 last_paired_ls = leafs[leaf-1]
171 # Create common components
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700172 # Control plane switch (for DHCP servers)
173 cs1 = self.addSwitch('cs1', cls=OVSBridge)
174 self.addLink(cs1, last_ls)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700175
176 # Control plane switch (for quagga fpm)
177 cs0 = self.addSwitch('cs0', cls=OVSBridge)
178
179 # Control plane NAT (for quagga fpm)
180 nat = self.addHost('nat', cls=NAT,
181 ip='172.16.0.1/12',
182 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
183 self.addLink(cs0, nat)
184
185 # Internal Quagga bgp1
You Wang051b55f2018-06-04 15:24:51 -0700186 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 -0700187 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
188 bgp1 = self.addHost('bgp1', cls=BgpRouter,
189 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800190 quaggaConfFile='./bgpdbgp1.conf',
191 zebraConfFile='./zebradbgp1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700192 self.addLink(bgp1, last_ls)
193 self.addLink(bgp1, cs0)
194
195 # Internal Quagga bgp2
196 intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
197 {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
198 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
199 bgp2 = self.addHost('bgp2', cls=BgpRouter,
200 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800201 quaggaConfFile='./bgpdbgp2.conf',
202 zebraConfFile='./zebradbgp2.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700203 self.addLink(bgp2, last_paired_ls)
204 self.addLink(bgp2, cs0)
205
206 # External Quagga r1
207 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
208 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
209 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']}}
210 r1 = self.addHost('r1', cls=BgpRouter,
211 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800212 quaggaConfFile='./bgpdr1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700213 self.addLink(r1, last_ls)
214 self.addLink(r1, last_paired_ls)
215
216 # External IPv4 Host behind r1
You Wang5102af12018-02-08 12:30:12 -0800217 rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700218 self.addLink(r1, rh1)
219
220 # External Quagga r2
221 intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
222 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
223 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']}}
224 r2 = self.addHost('r2', cls=BgpRouter,
225 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800226 quaggaConfFile='./bgpdr2.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700227 self.addLink(r2, last_ls)
228 self.addLink(r2, last_paired_ls)
229
230 # External IPv4 Host behind r2
You Wang5102af12018-02-08 12:30:12 -0800231 rh2 = self.addHost('rh2', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700232 self.addLink(r2, rh2)
233
You Wang53dba1e2018-02-02 17:45:44 -0800234 # DHCP server
235 if ipv6:
236 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
237 ips=['2000::3fd/120'], gateway='2000::3ff',
238 dhcpServer=True, ipv6=True)
239 self.addLink(dhcp, cs1)
240 else:
241 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
242 ips=['10.0.3.253/24'], gateway='10.0.3.254',
243 dhcpServer=True)
244 self.addLink(dhcp, cs1)
245
246
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700247class LeafSpineFabric (Topo) :
You Wang53dba1e2018-02-02 17:45:44 -0800248 def __init__(self, spine = 2, leaf = 2, fanout = 2, vlan_id = [], ipv6 = False,
249 dhcp_client = False, dhcp_relay = False,
250 multiple_server = False, remote_server = False, **opts):
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700251 Topo.__init__(self, **opts)
252 spines = dict()
253 leafs = dict()
254
255 # TODO: support IPv6 hosts
256 linkopts = dict( bw=100 )
257
258 # Create spine switches
259 for s in range(spine):
You Wang68568b12019-03-04 11:49:57 -0800260 spines[s] = self.addSwitch( 'spine10%s' % (s + 1),
261 dpid="00000000010%s" % (s + 1),
262 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700263
264 # Create leaf switches
265 for ls in range(leaf):
You Wang68568b12019-03-04 11:49:57 -0800266 leafs[ls] = self.addSwitch( 'leaf%s' % (ls + 1),
267 dpid="00000000000%s" % (ls + 1),
268 **SWITCH_PARAMS )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700269
270 # Connect leaf to all spines
271 for s in range( spine ):
272 switch = spines[ s ]
273 self.addLink( leafs[ ls ], switch, **linkopts )
274
275 # If dual-homed ToR, add hosts only when adding second switch at each edge-pair
276 # When the number of leaf switches is odd, leave the last switch as a single ToR
277
278 # Add hosts
279 for f in range(fanout):
You Wang53dba1e2018-02-02 17:45:44 -0800280 name = 'h%s%s' % (ls * fanout + f + 1, "v6" if ipv6 else "")
281 if ipv6:
282 ips = ['2000::%d0%d/%d' % (ls+2, f+1, IP6_SUBNET_CLASS)]
283 gateway = '2000::%dff' % (ls+2)
284 mac = '00:bb:00:00:00:%02x' % (ls * fanout + f + 1)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700285 else:
You Wang53dba1e2018-02-02 17:45:44 -0800286 ips = ['10.0.%d.%d/%d' % (ls+2, f+1, IP4_SUBNET_CLASS)]
287 gateway = '10.0.%d.254' % (ls+2)
288 mac = '00:aa:00:00:00:%02x' % (ls * fanout + f + 1)
289 host = self.addHost( name=name, cls=TrellisHost, ips=ips, gateway=gateway, mac=mac,
290 vlan=vlan_id[ ls*fanout + f ] if vlan_id[ls * fanout + f] != 0 else None,
291 dhcpClient=dhcp_client, ipv6=ipv6 )
292 if dhcp_relay and f % 2:
293 relayIndex = ls * fanout + f + 1
294 if ipv6:
295 intfs = {
296 'relay%s-eth0' % relayIndex: { 'ipAddrs': ['2000::%dff/%d' % (leaf + ls + 2, IP6_SUBNET_CLASS)] },
297 'relay%s-eth1' % relayIndex: { 'ipAddrs': ['2000::%d5%d/%d' % (ls + 2, f, IP6_SUBNET_CLASS)] }
298 }
299 if remote_server:
300 serverIp = '2000::99fd'
301 elif multiple_server:
302 serverIp = '2000::3fc'
303 else:
304 serverIp = '2000::3fd'
305 dhcpRelay = self.addHost(name='relay%s' % relayIndex, cls=DhcpRelay, serverIp=serverIp,
306 gateway='2000::%dff' % (ls+2), interfaces=intfs)
307 else:
308 intfs = {
309 'relay%s-eth0' % relayIndex: { 'ipAddrs': ['10.0.%d.254/%d' % (leaf + ls + 2, IP4_SUBNET_CLASS)] },
310 'relay%s-eth1' % relayIndex: { 'ipAddrs': ['10.0.%d.%d/%d' % (ls + 2, f + 99, IP4_SUBNET_CLASS)] }
311 }
312 if remote_server:
313 serverIp = '10.0.99.3'
314 elif multiple_server:
315 serverIp = '10.0.3.252'
316 else:
317 serverIp = '10.0.3.253'
318 dhcpRelay = self.addHost(name='relay%s' % relayIndex, cls=DhcpRelay, serverIp=serverIp,
319 gateway='10.0.%d.254' % (ls+2), interfaces=intfs)
320 self.addLink(host, dhcpRelay, **linkopts)
321 self.addLink(dhcpRelay, leafs[ls], **linkopts)
322 else:
323 self.addLink(host, leafs[ls], **linkopts)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700324
325 last_ls = leafs[leaf-1]
326 # Create common components
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700327 # Control plane switch (for DHCP servers)
328 cs1 = self.addSwitch('cs1', cls=OVSBridge)
329 self.addLink(cs1, last_ls)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700330
331 # Control plane switch (for quagga fpm)
332 cs0 = self.addSwitch('cs0', cls=OVSBridge)
333
334 # Control plane NAT (for quagga fpm)
335 nat = self.addHost('nat', cls=NAT,
336 ip='172.16.0.1/12',
337 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
338 self.addLink(cs0, nat)
339
340 # Internal Quagga bgp1
341 intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'},
342 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
343 bgp1 = self.addHost('bgp1', cls=BgpRouter,
344 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800345 quaggaConfFile='./bgpdbgp1.conf',
346 zebraConfFile='./zebradbgp1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700347 self.addLink(bgp1, last_ls)
348 self.addLink(bgp1, cs0)
349
350 # External Quagga r1
351 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
352 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']},
353 'r1-eth2': {'ipAddrs': ['2000::9901/120']}}
354 r1 = self.addHost('r1', cls=BgpRouter,
355 interfaces=intfs,
You Wang53dba1e2018-02-02 17:45:44 -0800356 quaggaConfFile='./bgpdr1.conf')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700357 self.addLink(r1, last_ls)
358
You Wang53dba1e2018-02-02 17:45:44 -0800359 # External switch behind r1
360 rs0 = self.addSwitch('rs0', cls=OVSBridge)
361 self.addLink(r1, rs0)
362
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700363 # External IPv4 Host behind r1
You Wang5102af12018-02-08 12:30:12 -0800364 rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700365 self.addLink(r1, rh1)
366
You Wang53dba1e2018-02-02 17:45:44 -0800367 # External IPv6 Host behind r1
368 rh1v6 = self.addHost('rh1v6', cls=TrellisHost, ips=['2000::9902/120'], gateway='2000::9901')
369 self.addLink(r1, rh1v6)
370
371 # DHCP server
372 if ipv6:
373 if remote_server:
374 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
375 ips=['2000::99fd/120'], gateway='2000::9901',
376 dhcpServer=True, ipv6=True)
377 self.addLink(rs0, dhcp)
378 else:
379 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
380 ips=['2000::3fd/120'], gateway='2000::3ff',
381 dhcpServer=True, ipv6=True)
382 self.addLink(dhcp, cs1)
383 if multiple_server:
384 dhcp2 = self.addHost('dhcp2', cls=TrellisHost, mac='00:99:00:00:00:02',
385 ips=['2000::3fc/120'], gateway='2000::3ff',
386 dhcpServer=True, ipv6=True)
387 self.addLink(dhcp2, cs1)
388 else:
389 if remote_server:
390 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
391 ips=['10.0.99.3/24'], gateway='10.0.99.1',
392 dhcpServer=True)
393 self.addLink(rs0, dhcp)
394 else:
395 dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01',
396 ips=['10.0.3.253/24'], gateway='10.0.3.254',
397 dhcpServer=True)
398 self.addLink(dhcp, cs1)
399 if multiple_server:
400 dhcp2 = self.addHost('dhcp2', cls=TrellisHost, mac='00:99:00:00:00:02',
401 ips=['10.0.3.252/24'], gateway='10.0.3.254',
402 dhcpServer=True)
403 self.addLink(dhcp2, cs1)
404
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700405def config( opts ):
406 spine = opts.spine
407 leaf = opts.leaf
408 fanout = opts.fanout
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700409 dualhomed = opts.dualhomed
410 if opts.vlan == '':
411 vlan = [0] * (((leaf / 2) if dualhomed else leaf) * fanout)
412 else:
413 vlan = [int(vlan_id) if vlan_id != '' else 0 for vlan_id in opts.vlan.split(',')]
414
415 if opts.onosIp != '':
416 controllers = opts.onosIp.split( ',' )
417 else:
418 controllers = ['127.0.0.1']
419
420 if len(vlan) != ((leaf / 2) if dualhomed else leaf ) * fanout:
421 print "Invalid vlan configuration is given."
422 return
423
You Wang53dba1e2018-02-02 17:45:44 -0800424 if dualhomed:
425 if leaf % 2 == 1 or leaf == 0:
426 print "Even number of leaf switches (at least two) are needed to build dual-homed topology."
427 return
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700428 else:
You Wang53dba1e2018-02-02 17:45:44 -0800429 topo = DualHomedLeafSpineFabric(spine=spine, leaf=leaf, fanout=fanout, vlan_id=vlan,
430 ipv6=opts.ipv6,
431 dhcp_client=opts.dhcpClient,
432 dhcp_relay=opts.dhcpRelay,
433 multiple_server=opts.multipleServer,
434 remote_server=opts.remoteServer)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700435 else:
You Wang53dba1e2018-02-02 17:45:44 -0800436 topo = LeafSpineFabric(spine=spine, leaf=leaf, fanout=fanout, vlan_id=vlan, ipv6=opts.ipv6,
437 dhcp_client=opts.dhcpClient,
438 dhcp_relay=opts.dhcpRelay,
439 multiple_server=opts.multipleServer,
440 remote_server=opts.remoteServer)
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700441
442 net = Mininet( topo=topo, link=TCLink, build=False,
443 controller=None, autoSetMacs=True )
444 i = 0
445 for ip in controllers:
446 net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
447 i += 1
448 net.build()
449 net.start()
450 CLI( net )
451 net.stop()
452
453if __name__ == '__main__':
454 setLogLevel('info')
455 config(opts)
456 os.system('sudo mn -c')