blob: 6e5626e149a57b05c3317a09c9ec632bd1ae1119 [file] [log] [blame]
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -07001#!/usr/bin/python
2import os
3import re
4from optparse import OptionParser
5from ipaddress import ip_network
You Wang68568b12019-03-04 11:49:57 -08006from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -07007from 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, TrellisHost
16
You Wang68568b12019-03-04 11:49:57 -080017from bmv2 import ONOSBmv2Switch
Jon Hall43060f62020-06-23 13:13:33 -070018from stratum import StratumBmv2Switch
You Wang68568b12019-03-04 11:49:57 -080019
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -070020# Parse command line options and dump results
21def parseOptions():
22 "Parse command line options"
23 parser = OptionParser()
24 parser.add_option( '--dhcp', dest='dhcp', type='int', default=0,
25 help='Configure hosts with dhcp or not' )
26 parser.add_option( '--routers', dest='routers', type='int', default=0,
27 help='Configure external routers or not in the topology' )
28 parser.add_option( '--ipv6', dest='ipv6', type='int', default=0,
29 help='Configure hosts with ipv6 or not' )
30 parser.add_option( '--ipv4', dest='ipv4', type='int', default=1,
31 help='Configure hosts with ipv4 or not' )
32 parser.add_option( '--onos-ip', dest='onosIp', type='str', default='',
You Wang68568b12019-03-04 11:49:57 -080033 help='IP address list of ONOS instances, separated by comma(,). Overrides --onos option' )
34 parser.add_option( '--switch', dest='switch', type='str', default='ovs',
Jon Hall43060f62020-06-23 13:13:33 -070035 help='Switch type: ovs, bmv2 (with fabric.p4), stratum' )
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -070036
37 ( options, args ) = parser.parse_args()
38 return options, args
39
40opts, args = parseOptions()
41
You Wang68568b12019-03-04 11:49:57 -080042FABRIC_PIPECONF = "org.onosproject.pipelines.fabric"
43
44SWITCH_TO_PARAMS_DICT = {
45 "ovs": dict(cls=OVSSwitch),
Jon Hall43060f62020-06-23 13:13:33 -070046 "bmv2": dict(cls=ONOSBmv2Switch, pipeconf=FABRIC_PIPECONF),
47 "stratum": dict(cls=StratumBmv2Switch, pipeconf=FABRIC_PIPECONF, loglevel='debug')
You Wang68568b12019-03-04 11:49:57 -080048}
49if opts.switch not in SWITCH_TO_PARAMS_DICT:
50 raise Exception("Unknown switch type '%s'" % opts.switch)
51SWITCH_PARAMS = SWITCH_TO_PARAMS_DICT[opts.switch]
52
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -070053class ComcastLeafSpineFabric(Topo):
54
55 spines = dict()
56 leafs = dict()
57 hosts_dict = dict()
58
59 def createIpv4Hosts(self, dhcp):
60
61 h1 = self.addHost('h1v4', cls=TrellisHost,
62 mac='00:aa:00:00:00:01', ips=['10.1.0.1/24'],
63 gateway='10.1.0.254', dhcpClient=dhcp)
64 self.addLink(h1, self.leafs[0])
65 self.hosts_dict['h1v4'] = h1
66
67 h2 = self.addHost('h2v4', cls=TrellisHost,
68 mac='00:aa:00:00:01:01', ips=['10.1.10.1/24'],
69 gateway='10.1.10.254', dhcpClient=dhcp)
70 self.addLink(h2, self.leafs[0])
71 self.hosts_dict['h2v4'] = h2
72
73 h3 = self.addHost('h3v4', cls=TrellisHost,
74 mac='00:aa:00:00:00:02', ips=['10.2.0.1/24'],
75 gateway='10.2.0.254', dhcpClient=dhcp)
76 self.addLink(h3, self.leafs[1])
77 self.hosts_dict['h3v4'] = h3
78
79 h4 = self.addHost('h4v4', cls=TrellisHost,
80 mac='00:aa:00:00:00:03', ips=['10.2.30.1/24'],
81 gateway='10.2.30.254', dhcpClient=dhcp,
82 dualHomed=True)
83 self.addLink(h4, self.leafs[1])
84 self.addLink(h4, self.leafs[2])
85 self.hosts_dict['h4v4'] = h4
86
87 h5 = self.addHost('h5v4', cls=TrellisHost,
88 mac='00:aa:00:00:00:04', ips=['10.2.20.1/24'],
89 gateway='10.2.20.254', dhcpClient=dhcp, vlan=30,
90 dualHomed=True)
91 self.addLink(h5, self.leafs[1])
92 self.addLink(h5, self.leafs[2])
93 self.hosts_dict['h5v4'] = h5
94
95 h6 = self.addHost('h6v4', cls=TrellisHost,
96 mac='00:aa:00:00:00:05', ips=['10.2.10.1/24'],
97 gateway='10.2.10.254', dhcpClient=dhcp, vlan=20)
98 self.addLink(h6, self.leafs[2])
99 self.hosts_dict['h6v4'] = h6
100
101 h7 = self.addHost('h7v4', cls=TrellisHost,
102 mac='00:aa:00:00:01:05', ips=['10.2.40.1/24'],
103 gateway='10.2.40.254', dhcpClient=dhcp, vlan=40)
104 self.addLink(h7, self.leafs[2])
105 self.hosts_dict['h7v4'] = h7
106
107 h8 = self.addHost('h8v4', cls=TrellisHost,
108 mac='00:aa:00:00:00:06', ips=['10.3.0.1/24'],
109 gateway='10.3.0.254', dhcpClient=dhcp)
110 self.addLink(h8, self.leafs[3])
111 self.hosts_dict['h8v4'] = h8
112
113 h9 = self.addHost('h9v4', cls=TrellisHost,
114 mac='00:aa:00:00:00:07', ips=['10.3.10.1/24'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700115 gateway='10.3.10.254', dhcpClient=dhcp, vlan=50,
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700116 dualHomed=True)
117 self.addLink(h9, self.leafs[3])
118 self.addLink(h9, self.leafs[4])
119 self.hosts_dict['h9v4'] = h9
120
121 h10 = self.addHost('h10v4', cls=TrellisHost,
122 mac='00:aa:00:00:00:08', ips=['10.3.30.1/24'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700123 gateway='10.3.30.254', dhcpClient=dhcp, vlan=60,
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700124 dualHomed=True)
125 self.addLink(h10, self.leafs[3])
126 self.addLink(h10, self.leafs[4])
127 self.hosts_dict['h10v4'] = h10
128
129 h11 = self.addHost('h11v4', cls=TrellisHost,
130 mac='00:aa:00:00:00:0a', ips=['10.3.20.1/24'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700131 gateway='10.3.20.254', dhcpClient=dhcp, vlan=70)
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700132 self.addLink(h11, self.leafs[4])
133 self.hosts_dict['h11v4'] = h11
134
135 h12 = self.addHost('h12v4', cls=TrellisHost,
136 mac='00:aa:00:00:02:01', ips=['10.5.10.1/24'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700137 gateway='10.5.10.254', dhcpClient=dhcp, vlan=80)
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700138 self.addLink(h12, self.leafs[5])
139 self.hosts_dict['h12v4'] = h12
140
141 h13 = self.addHost('h13v4', cls=TrellisHost,
142 mac='00:aa:00:00:02:02', ips=['10.5.20.1/24'],
143 gateway='10.5.20.254', dhcpClient=dhcp)
144 self.addLink(h13, self.leafs[5])
145 self.hosts_dict['h13v4'] = h13
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700146 return
147
148 def createIpv6Hosts(self, dhcp):
149
150 h1 = self.addHost('h1v6', cls=TrellisHost,
151 mac='00:bb:00:00:00:01', ips=["1000::3fe/120"],
152 gateway='1000::3ff', dhcpClient=dhcp, ipv6=1)
153 self.addLink(h1, self.leafs[0])
154 self.hosts_dict['h1v6'] = h1
155
156 h2 = self.addHost('h2v6', cls=TrellisHost,
157 mac='00:bb:00:00:01:01', ips=['1001::3fe/120'],
158 gateway='1001::3ff', dhcpClient=dhcp, ipv6=1)
159 self.addLink(h2, self.leafs[0])
160 self.hosts_dict['h2v6'] = h2
161
162 h3 = self.addHost('h3v6', cls=TrellisHost,
163 mac='00:bb:00:00:00:02', ips=['1002::3fe/120'],
164 gateway='1002::3ff', dhcpClient=dhcp, ipv6=1)
165 self.addLink(h3, self.leafs[1])
166 self.hosts_dict['h3v6'] = h3
167
168 h4 = self.addHost('h4v6', cls=TrellisHost,
169 mac='00:bb:00:00:00:03', ips=['1003::3fe/120'],
170 gateway='1003::3ff', dhcpClient=dhcp, ipv6=1,
171 dualHomed=True)
172 self.addLink(h4, self.leafs[1])
173 self.addLink(h4, self.leafs[2])
174 self.hosts_dict['h4v6'] = h4
175
176 h5 = self.addHost('h5v6', cls=TrellisHost,
177 mac='00:bb:00:00:00:04', ips=['1004::3fe/120'],
178 gateway='1004::3ff', dhcpClient=False, ipv6=1,
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700179 vlan=121,
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700180 dualHomed=True)
181 self.addLink(h5, self.leafs[1])
182 self.addLink(h5, self.leafs[2])
183 self.hosts_dict['h5v6'] = h5
184
185 h6 = self.addHost('h6v6', cls=TrellisHost,
186 mac='00:bb:00:00:00:05', ips=['1005::3fe/120'],
187 gateway='1005::3ff', dhcpClient=False, ipv6=1,
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700188 vlan=122)
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700189 self.addLink(h6, self.leafs[2])
190 self.hosts_dict['h6v6'] = h6
191
192 h7 = self.addHost('h7v6', cls=TrellisHost,
193 mac='00:bb:00:00:01:05', ips=['1006::3fe/120'],
194 gateway='1006::3ff', dhcpClient=False, ipv6=1,
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700195 vlan=123)
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700196 self.addLink(h7, self.leafs[2])
197 self.hosts_dict['h7v6'] = h7
198
199 h8 = self.addHost('h8v6', cls=TrellisHost,
200 mac='00:bb:00:00:00:06', ips=['1007::3fe/120'],
201 gateway='1007::3ff', dhcpClient=dhcp, ipv6=1)
202 self.addLink(h8, self.leafs[3])
203 self.hosts_dict['h8v6'] = h8
204
205 h9 = self.addHost('h9v6', cls=TrellisHost,
206 mac='00:bb:00:00:00:07', ips=['1008::3fe/120'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700207 gateway='1008::3ff', dhcpClient=False, vlan=124,
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700208 dualHomed=True, ipv6=1)
209 self.addLink(h9, self.leafs[3])
210 self.addLink(h9, self.leafs[4])
211 self.hosts_dict['h9v6'] = h9
212
213 h10 = self.addHost('h10v6', cls=TrellisHost,
214 mac='00:bb:00:00:00:08', ips=['1009::3fe/120'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700215 gateway='1009::3ff', dhcpClient=False, vlan=125,
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700216 dualHomed=True, ipv6=1)
217 self.addLink(h10, self.leafs[3])
218 self.addLink(h10, self.leafs[4])
219 self.hosts_dict['h10v6'] = h10
220
221 h11 = self.addHost('h11v6', cls=TrellisHost,
222 mac='00:bb:00:00:00:0a', ips=['1010::3fe/120'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700223 gateway='1010::3ff', dhcpClient=False, vlan=126,
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700224 ipv6=1)
225 self.addLink(h11, self.leafs[4])
226 self.hosts_dict['h11v6'] = h11
227
228 h12 = self.addHost('h12v6', cls=TrellisHost,
229 mac='00:bb:00:00:01:0a', ips=['1011::3fe/120'],
Andreas Pantelopoulos1e0665a2018-06-05 13:34:59 -0700230 gateway='1011::3ff', dhcpClient=False, vlan=127,
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700231 ipv6=1)
232 self.addLink(h12, self.leafs[5])
233 self.hosts_dict['h12v6'] = h12
234
235 h13 = self.addHost('h13v6', cls=TrellisHost,
236 mac='00:bb:00:00:02:0a', ips=['1012::3fe/120'],
237 gateway='1012::3ff', dhcpClient=dhcp, ipv6=1)
238 self.addLink(h13, self.leafs[5])
239 self.hosts_dict['h13v6'] = h13
240
241 return
242
243 '''
244 Creates the HAGG topology employed by Comcast.
245 '''
246 def __init__(self, dhcp=False, routers=False, ipv4=False, ipv6=False, **opts):
247 Topo.__init__(self, **opts)
248
249 linkopts = dict( bw=10 )
250
251 spine = 4
252 leaf = 6
253
254 # Create spine switches
255 for s in range(spine):
You Wang68568b12019-03-04 11:49:57 -0800256 self.spines[s] = self.addSwitch( 'spine10%s' % (s + 1),
257 dpid = "00000000010%s" % (s + 1),
258 **SWITCH_PARAMS )
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700259
260 # Create leaf switches
261 for ls in range(leaf):
You Wang68568b12019-03-04 11:49:57 -0800262 self.leafs[ls] = self.addSwitch( 'leaf%s' % (ls + 1),
263 dpid = "00000000000%s" % (ls + 1),
264 **SWITCH_PARAMS )
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700265
Jon Hall43060f62020-06-23 13:13:33 -0700266 # connecting leafs 2-5 and spines 101 and 102 with double links
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700267 for s in range(2):
268 spine_switch = self.spines[s]
269
270 for ls in range(1, 5):
271 leaf_switch = self.leafs[ls]
272
273 self.addLink( spine_switch, leaf_switch, **linkopts )
274 self.addLink( spine_switch, leaf_switch, **linkopts )
275
276 # connect paired leafs
277 self.addLink(self.leafs[1], self.leafs[2], **linkopts)
278 self.addLink(self.leafs[3], self.leafs[4], **linkopts)
279
Jon Hall43060f62020-06-23 13:13:33 -0700280 # build second fabric with single links, spines 103 and 104 and leafs 1 and 6
Andreas Pantelopoulosd5d470f2018-03-23 18:02:47 -0700281 for s in range(2, 4):
282 spine_switch = self.spines[s]
283
284 for ls in [0, 5]:
285 leaf_switch = self.leafs[ls]
286 self.addLink( spine_switch, leaf_switch, **linkopts )
287
288 # connect spines together
289 self.addLink(self.spines[2], self.spines[0], **linkopts)
290 self.addLink(self.spines[3], self.spines[1], **linkopts)
291
292 # create hosts
293 if ipv6:
294 self.createIpv6Hosts(dhcp)
295
296 if ipv4:
297 self.createIpv4Hosts(dhcp)
298
299 if not ipv4 and not ipv6:
300 print("No hosts were created!")
301
302 # create quagga routers
303 # Note: Change "fpm connection ip" to $OC1 in zebradbgp1.conf and zebradbgp2.conf to make quagga work correctly
304 if routers:
305 last_ls = self.leafs[4]
306 last_paired_ls = self.leafs[3]
307
308 # Control plane switch (for quagga fpm)
309 cs0 = self.addSwitch('cs0', cls=OVSBridge)
310
311 # Control plane NAT (for quagga fpm)
312 nat = self.addHost('nat', cls=NAT,
313 ip='172.16.0.1/12',
314 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
315 self.addLink(cs0, nat)
316
317 # Internal Quagga bgp1
318 intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
319 {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}],
320 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}}
321 bgp1 = self.addHost('bgp1', cls=BgpRouter,
322 interfaces=intfs,
323 quaggaConfFile='./bgpdbgp1.conf',
324 zebraConfFile='./zebradbgp1.conf')
325 self.addLink(bgp1, last_paired_ls)
326 self.addLink(bgp1, cs0)
327
328 # Internal Quagga bgp2
329 intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
330 {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
331 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
332 bgp2 = self.addHost('bgp2', cls=BgpRouter,
333 interfaces=intfs,
334 quaggaConfFile='./bgpdbgp2.conf',
335 zebraConfFile='./zebradbgp2.conf')
336 self.addLink(bgp2, last_ls)
337 self.addLink(bgp2, cs0)
338
339 # External Quagga r1
340 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
341 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
342 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']},
343 'r1-eth3': {'ipAddrs': ['2000::9901/120']},
344 'r1-eth4': {'ipAddrs': ['2000::7701/120']},
345 'r1-eth5': {'ipAddrs': ['10.0.88.1/24']},
346 'r1-eth6': {'ipAddrs': ['2000::8701/120']}}
347 r1 = self.addHost('r1', cls=BgpRouter,
348 interfaces=intfs,
349 quaggaConfFile='./bgpdr1.conf')
350 self.addLink(r1, last_paired_ls)
351 self.addLink(r1, last_ls)
352
353 # External IPv4 Host behind r1
354 rh1v4 = self.addHost('rh1v4', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
355 self.addLink(r1, rh1v4)
356
357 # External IPv6 Host behind r1
358 rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
359 self.addLink(r1, rh1v6)
360
361 # Another external IPv6 Host behind r1
362 rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701')
363 self.addLink(r1, rh11v6)
364
365 # Add an external ipv4 hosts that is not configured in the bgp conf
366 # files
367 rh5v4 = self.addHost('rh5v4', cls=RoutedHost, ips=['10.0.88.2/24'], gateway='10.0.88.1')
368 self.addLink(r1, rh5v4)
369
370 # Add an external ipv6 hosts that is not configured in the bgp conf
371 # files
372 rh5v6 = self.addHost('rh5v6', cls=RoutedHost, ips=['2000::8702/120'], gateway='2000::8701')
373 self.addLink(r1, rh5v6)
374
375 # External Quagga r2
376 intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
377 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
378 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']},
379 'r2-eth3': {'ipAddrs': ['2000::9901/120']},
380 'r2-eth4': {'ipAddrs': ['2000::8801/120']}}
381 r2 = self.addHost('r2', cls=BgpRouter,
382 interfaces=intfs,
383 quaggaConfFile='./bgpdr2.conf')
384 self.addLink(r2, last_ls)
385 self.addLink(r2, last_paired_ls)
386
387 # External IPv4 Host behind r2
388 rh2v4 = self.addHost('rh2v4', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
389 self.addLink(r2, rh2v4)
390
391 # External IPv6 Host behind r2
392 rh2v6 = self.addHost('rh2v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
393 self.addLink(r2, rh2v6)
394
395 # Another external IPv6 Host behind r1
396 rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801')
397 self.addLink(r2, rh22v6)
398
399 # create dhcp servers
400 if dhcp:
401 cs1 = self.addSwitch('cs1', cls=OVSBridge)
402 self.addLink(cs1, self.leafs[4])
403 if ipv4:
404 dhcp4 = self.addHost( 'dhcp', cls=TrellisHost,
405 mac="00:cc:00:00:00:01", ips=["10.0.3.253/24"],
406 gateway="10.0.3.254", dhcpServer=True)
407 self.addLink(dhcp4, cs1, **linkopts)
408 if ipv6:
409 dhcp6 = self.addHost( 'dhcp6', cls=TrellisHost,
410 mac="00:dd:00:00:00:01", ips=["2000::3fd/120"],
411 gateway="2000::3ff", dhcpServer=True, ipv6=True)
412 self.addLink(dhcp6, cs1, **linkopts)
413
414
415def config( opts ):
416
417 dhcp = bool(opts.dhcp)
418 routers = bool(opts.routers)
419 ipv6 = bool(opts.ipv6)
420 ipv4 = bool(opts.ipv4)
421
422 if opts.onosIp != '':
423 controllers = opts.onosIp.split( ',' )
424 else:
425 controllers = ['127.0.0.1']
426 topo = ComcastLeafSpineFabric(dhcp=dhcp, routers=routers, ipv6=ipv6,
427 ipv4=ipv4)
428
429 net = Mininet( topo=topo, link=TCLink, build=False,
430 controller=None, autoSetMacs=True )
431 i = 0
432 for ip in controllers:
433 net.addController( "c%s" % ( i ), controller=RemoteController, ip=ip )
434 i += 1
435
436 net.build()
437 net.start()
438 CLI( net )
439 net.stop()
440
441
442if __name__ == '__main__':
443 setLogLevel('info')
444 config(opts)
445 os.system('sudo mn -c')
446