blob: 116c0cc20516efbd84a128a17ce521a37ce5fe40 [file] [log] [blame]
Brian O'Connoreb27c452014-12-07 02:43:58 -08001#!/usr/bin/python
2
3'''
4Notes:
5
6This file contains classes and methods useful for integrating LincOE with Mininet,
fahad44e62c72015-03-04 14:55:35 -08007such as startOE, stopOE, LINCLink, and OpticalSwitch
Brian O'Connoreb27c452014-12-07 02:43:58 -08008
9- $ONOS_ROOT ust be set
10- Need to run with sudo -E to preserve ONOS_ROOT env var
11- We assume LINC-Config-Generator is named LINC-Config-Generator
12- We also assume linc-oe is named linc-oe
13- LINC-config-generator and linc-oe must be subdirectories of the user's
14 home directory
15
16 TODO
17 -----------
18 - clean up files after runtime
19 - maybe save the old files in a separate directory?
20 - modify script to allow startOE to run before net.start()
21 - add ONOS as a controller in script
22
23 Usage:
24 ------------
fahad44e62c72015-03-04 14:55:35 -080025 - import LINCLink and OpticalSwitch from this module
Brian O'Connoreb27c452014-12-07 02:43:58 -080026 - import startOE and stopOE from this module
27 - create topology as you would a normal topology. when
fahad44e62c72015-03-04 14:55:35 -080028 to an optical switch with topo.addLink, always specify cls=LINCLink
Brian O'Connoreb27c452014-12-07 02:43:58 -080029 - when creating an optical switch, use cls=OpticalSwitch in topo.addSwitch
30 - for annotations on links and switches, a dictionary must be passed in as
31 the annotations argument
32 - startOE must be run AFTER net.start() with net as an argument.
33 - stopOE can be run at any time
34
35I created a separate function to start lincOE to avoid subclassing Mininet.
36In case anyone wants to write something that DOES subclass Mininet, I
37thought I would outline how:
38
39If we want an object that starts lincOE within the mininet class itself,
40we need to add another object to Mininet that contains all of the json object
41information for each switch. We would still subclass switch and link, but these
42classes would basically be dummy classes that store their own json information
43in the Mininet class object. We may also change the default switch class to add
44it's tap interfaces from lincOE during startup. The start() method for mininet would
45grab all of the information from these switches and links, write configuration files
46for lincOE using the json module, start lincOE, then run the start methodfor each
47switch. The new start() method for each switch would parse through the sys.config
48file that was created and find the tap interface it needs to connect to, similar
49to the findTap function that I currently use. After all of the controllers and
50switches have been started, the new Mininet start() method should also push the
51Topology configuration file to ONOS.
52
53'''
fahad44e62c72015-03-04 14:55:35 -080054import sys
Brian O'Connoreb27c452014-12-07 02:43:58 -080055import re
56import json
57import os
58from time import sleep
Marc De Leenheer16f857b2015-05-05 20:50:24 -070059import urllib2
Brian O'Connoreb27c452014-12-07 02:43:58 -080060
61from mininet.node import Switch, RemoteController
62from mininet.topo import Topo
63from mininet.util import quietRun
64from mininet.net import Mininet
65from mininet.log import setLogLevel, info, error, warn
66from mininet.link import Link, Intf
67from mininet.cli import CLI
68
Marc De Leenheer16f857b2015-05-05 20:50:24 -070069# Sleep time and timeout values in seconds
70SLEEP_TIME = .5
71TIMEOUT = 60
72
fahad44e62c72015-03-04 14:55:35 -080073class OpticalSwitch(Switch):
74 """
75 For now, same as Switch class.
76 """
77 pass
Brian O'Connoreb27c452014-12-07 02:43:58 -080078
fahad44e62c72015-03-04 14:55:35 -080079class OpticalIntf(Intf):
80 """
81 For now,same as Intf class.
82 """
83 pass
84
85class OpticalLink(Link):
86 """
87 For now, same as Link.
88 """
89 pass
90
91class LINCSwitch(OpticalSwitch):
92 """
93 LINCSwitch class
94 """
95 # FIXME:Sometimes LINC doesn't remove pipes and on restart increase the pipe
96 # number from erlang.pipe.1.* to erlang.pipe.2.*, so should read and write
97 # from latest pipe files. For now we are removing all the pipes before
98 # starting LINC.
99 ### User Name ###
100 user = os.getlogin()
101 ### pipes ###
102 readPipe = "/tmp/home/{}/linc-oe/rel/linc/erlang.pipe.1.r".format(user)
103 writePipe = "/tmp/home/{}/linc-oe/rel/linc/erlang.pipe.1.w".format(user)
104 ### sys.config path ###
105 sysConfig = "/home/{}/linc-oe/rel/linc/releases/1.0/sys.config".format(user)
106 ### method, mapping dpid to LINC switchId ###
107 @staticmethod
108 def dpids_to_ids(sysConfig):
109 '''
110 return the dict containing switch dpids as key and LINC switch id as values
111 '''
112 dpids_to_ids = {}
113 fd = None
114 try:
115 with open(sysConfig, 'r', 0) as fd:
116 switch_id = 1
117 for line in fd:
118 dpid = re.search(r'([0-9A-Fa-f]{2}[:-]){7}([0-9A-Fa-f]{2})+', line, re.I)
119 if dpid:
120 dpids_to_ids[dpid.group().replace(':', '')] = switch_id
121 switch_id += 1
122 return dpids_to_ids
123 except:
124 print "Error working with {}\nError: {}\n".format(sysConfig, sys.exc_info())
125 fd.close()
126 return None
127 ### dict of containing dpids as key and corresponding LINC switchId as values ###
128 dpidsToLINCSwitchId = dpids_to_ids.__func__(sysConfig)
129 @staticmethod
130 def findDir(directory, userName):
131 "finds and returns the path of any directory in the user's home directory"
132 homeDir = '/home/' + userName
133 Dir = quietRun('find %s -maxdepth 1 -name %s -type d' % (homeDir, directory)).strip('\n')
134 DirList = Dir.split('\n')
135 if not Dir:
136 return None
137 elif len(DirList) > 1 :
138 warn('***WARNING: Found multiple instances of %s; using %s\n'
139 % (directory, DirList[ 0 ]))
140 return DirList[ 0 ]
141 else:
142 return Dir
143 ### ONOS Directory ###
144 try:
145 onosDir = os.environ[ 'ONOS_ROOT' ]
146 except:
147 onosDir = findDir('onos', user)
148 if not onosDir:
149 error('Please set ONOS_ROOT environment variable!\n')
150 else:
151 os.environ[ 'ONOS_ROOT' ] = onosDir
152 ### LINC-directory
153 lincDir = findDir.__func__('linc-oe', user)
154 if not lincDir:
155 error("***ERROR: Could not find linc-oe in user's home directory\n")
156 ### LINC config generator directory###
157 configGen = findDir.__func__('LINC-config-generator', user)
158 if not configGen:
159 error("***ERROR: Could not find LINC-config-generator in user's home directory\n")
160 # list of all the controllers
161 controllers = None
162 def __init__(self, name, dpid=None, allowed=True,
163 switchType='ROADM', topo=None, annotations={}, controller=None, **params):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800164 params[ 'inNamespace' ] = False
fahad44e62c72015-03-04 14:55:35 -0800165 Switch.__init__(self, name, dpid=dpid, **params)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800166 self.name = name
167 self.annotations = annotations
168 self.allowed = allowed
169 self.switchType = switchType
fahad44e62c72015-03-04 14:55:35 -0800170 self.configDict = {} # dictionary that holds all of the JSON configuration data
171 self.crossConnects = []
172 self.deletedCrossConnects = []
173 self.controller = controller
174 self.lincId = self._get_linc_id() # use to communicate with LINC
175 self.lincStarted = False
Brian O'Connoreb27c452014-12-07 02:43:58 -0800176
fahad44e62c72015-03-04 14:55:35 -0800177 def start(self, *opts, **params):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800178 '''Instead of starting a virtual switch, we build the JSON
179 dictionary for the emulated optical switch'''
fahad44e62c72015-03-04 14:55:35 -0800180 # TODO:Once LINC has the ability to spawn network element dynamically
181 # we need to use this method to spawn new logical LINC switch rather then
182 # bulding JSON.
183 # if LINC is started then we can start and stop logical switches else create JSON
184 if self.lincStarted:
185 return self.start_oe()
Brian O'Connoreb27c452014-12-07 02:43:58 -0800186 self.configDict[ 'uri' ] = 'of:' + self.dpid
187 self.configDict[ 'annotations' ] = self.annotations
fahad44e62c72015-03-04 14:55:35 -0800188 self.configDict[ 'annotations' ].setdefault('name', self.name)
189 self.configDict[ 'hw' ] = 'LINC-OE'
Brian O'Connoreb27c452014-12-07 02:43:58 -0800190 self.configDict[ 'mfr' ] = 'Linc'
191 self.configDict[ 'mac' ] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1]
192 self.configDict[ 'type' ] = self.switchType
193 self.configDict[ 'ports' ] = []
194 for port, intf in self.intfs.items():
195 if intf.name == 'lo':
196 continue
197 else:
fahad44e62c72015-03-04 14:55:35 -0800198 self.configDict[ 'ports' ].append(intf.json())
199 self.lincStarted = True
Brian O'Connoreb27c452014-12-07 02:43:58 -0800200
fahad44e62c72015-03-04 14:55:35 -0800201 def stop(self, deleteIntfs=False):
202 '''
203 stop the existing switch
204 '''
205 # TODO:Add support for deleteIntf
206 self.stop_oe()
Brian O'Connoreb27c452014-12-07 02:43:58 -0800207
fahad44e62c72015-03-04 14:55:35 -0800208 def dpctl( self, *args ):
209 "Run dpctl command: ignore for now"
Brian O'Connoreb27c452014-12-07 02:43:58 -0800210 pass
211
fahad44e62c72015-03-04 14:55:35 -0800212 def write_to_cli(self, command):
213 '''
214 send command to LINC
215 '''
216 fd = None
217 try:
218 fd = open(self.writePipe, 'w', 0)
219 fd.write(command)
220 fd.close()
221 except:
222 print "Error working with {}\nError: {}\n".format(self.writePipe, sys.exc_info())
223 if fd:
224 fd.close()
Brian O'Connoreb27c452014-12-07 02:43:58 -0800225
fahad44e62c72015-03-04 14:55:35 -0800226 def read_from_cli(self):
227 '''
228 read the output from the LINC CLI
229 '''
230 response = None
231 fd = None
232 try:
233 fd = open(self.readPipe, 'r', 0)
234 fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) # for non-blocking read
235 # FIXME:Due to non-blocking read most for the time we read nothing
236 response = fd.read()
237 fd.close()
238 except :
239 # print "Error working with {}\nError: {}\n".format(self.readPipe, sys.exc_info())
240 if fd:
241 fd.close()
242 return response
243
244 def _get_linc_id(self):
245 '''
246 return the corresponding LINC switchId.
247 '''
248 return LINCSwitch.dpidsToLINCSwitchId.get(self.dpid)
249 #--------------------------------------------------------------------------
250 # LINC CLI commands
251 #--------------------------------------------------------------------------
252 def start_oe(self):
253 '''
254 start the existing LINC switch
255 '''
256 #starting Switch
257 cmd = "linc:start_switch({}).\r\n".format(self.lincId)
258 self.write_to_cli(cmd)
259 #hanlding taps interfaces related to the switch
260 crossConnectJSON = {}
261 linkConfig = []
262 for i in range(0,len(self.deletedCrossConnects)):
263 crossConnect = self.deletedCrossConnects.pop()
264 tap = None
265 if isinstance(crossConnect.intf1.node, LINCSwitch):
266 intf = crossConnect.intf2
267 tapPort = crossConnect.intf1.port
268 else:
269 intf = crossConnect.intf1
270 tapPort = crossConnect.intf2.port
271 tap = LINCSwitch.findTap(self, tapPort)
272 if tap:
273 LINCSwitch.setupInts([tap])
274 intf.node.attach(tap)
275 self.crossConnects.append(crossConnect)
276 linkConfig.append(crossConnect.json())
277 #Sending crossConnect info to the ONOS.
278 crossConnectJSON['links'] = linkConfig
279 with open("crossConnect.json", 'w') as fd:
280 json.dump(crossConnectJSON, fd, indent=4, separators=(',', ': '))
281 info('*** Pushing crossConnect.json to ONOS\n')
282 output = quietRun('%s/tools/test/bin/onos-topo-cfg %s\
283 Topology.json' % (self.onosDir, self.controllers[ 0 ].ip), shell=True)
284
285 def stop_oe(self):
286 '''
287 stop the existing LINC switch
288 '''
289 cmd = "linc:stop_switch({}).\r\n".format(self.lincId)
290 self.write_to_cli(cmd)
291 #handling taps if any
292 for i in range(0, len(self.crossConnects)):
293 crossConnect = self.crossConnects.pop()
294 if isinstance(crossConnect.intf1.node, LINCSwitch):
295 intf = crossConnect.intf2
296 tapPort = crossConnect.intf1.port
297 else:
298 intf = crossConnect.intf1
299 tapPort = crossConnect.intf2.port
300 intf.node.detach(LINCSwitch.findTap(self, tapPort))
301 self.deletedCrossConnects.append(crossConnect)
302
303 def w_port_up(self, port):
304 '''
305 port_up
306 '''
307 cmd = "linc:port_up({},{}).\r\n".format(self.lincId, port)
308 self.write_to_cli(cmd)
309
310 def w_port_down(self, port):
311 '''
312 port_down
313 '''
314 cmd = "linc:port_down({},{}).\r\n".format(self.lincId, port)
315 self.write_to_cli(cmd)
316
317 # helper functions
318 @staticmethod
319 def switchJSON(switch):
320 "Returns the json configuration for a packet switch"
321 configDict = {}
322 configDict[ 'uri' ] = 'of:' + switch.dpid
323 configDict[ 'mac' ] = quietRun('cat /sys/class/net/%s/address' % switch.name).strip('\n').translate(None, ':')
324 configDict[ 'hw' ] = 'PK' # FIXME what about OVS?
325 configDict[ 'mfr' ] = 'Linc' # FIXME what about OVS?
326 configDict[ 'type' ] = 'SWITCH' # FIXME what about OVS?
327 annotations = switch.params.get('annotations', {})
328 annotations.setdefault('name', switch.name)
329 configDict[ 'annotations' ] = annotations
330 ports = []
331 for port, intf in switch.intfs.items():
332 if intf.name == 'lo':
333 continue
334 portDict = {}
335 portDict[ 'port' ] = port
336 portDict[ 'type' ] = 'FIBER' if isinstance(intf.link, LINCLink) else 'COPPER'
337 intfList = [ intf.link.intf1, intf.link.intf2 ]
338 intfList.remove(intf)
339 portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance(intf.link, LINCLink) else 0
340 ports.append(portDict)
341 configDict[ 'ports' ] = ports
342 return configDict
343
344 @staticmethod
345 def bootOE(net):
346 "Start the LINC optical emulator within a mininet instance"
347 opticalJSON = {}
348 linkConfig = []
349 devices = []
350 #setting up the controllers for LINCSwitch class
351 LINCSwitch.controllers = net.controllers
352
353 for switch in net.switches:
354 if isinstance(switch, OpticalSwitch):
355 devices.append(switch.json())
356 else:
357 devices.append(LINCSwitch.switchJSON(switch))
358 opticalJSON[ 'devices' ] = devices
359
360 for link in net.links:
361 if isinstance(link, LINCLink) :
362 linkConfig.append(link.json())
363 opticalJSON[ 'links' ] = linkConfig
364
365 info('*** Writing Topology.json file\n')
366 with open('Topology.json', 'w') as outfile:
367 json.dump(opticalJSON, outfile, indent=4, separators=(',', ': '))
368
369 info('*** Converting Topology.json to linc-oe format (TopoConfig.json) file\n')
370 output = quietRun('%s/tools/test/bin/onos-oecfg ./Topology.json > TopoConfig.json' % LINCSwitch.onosDir, shell=True)
371 if output:
372 error('***ERROR: Error creating topology file: %s ' % output + '\n')
373 return False
374
375 info('*** Creating sys.config...\n')
376 output = quietRun('%s/config_generator TopoConfig.json %s/sys.config.template %s %s'
377 % (LINCSwitch.configGen, LINCSwitch.configGen, LINCSwitch.controllers[ 0 ].ip, LINCSwitch.controllers[ 0 ].port), shell=True)
378 if output:
379 error('***ERROR: Error creating sys.config file: %s\n' % output)
380 return False
381
382 info ('*** Setting multiple controllers in sys.config...\n')
383 searchStr = '\[{"Switch.*$'
384 ctrlStr = ''
385 for index in range(len(LINCSwitch.controllers)):
386 ctrlStr += '{"Switch%d-Controller","%s",%d,tcp},' % (index, net.controllers[index].ip, net.controllers[index].port)
387 replaceStr = '[%s]},' % ctrlStr[:-1] # Cut off last comma
388 sedCmd = 'sed -i \'s/%s/%s/\' sys.config' % (searchStr, replaceStr)
389 output = quietRun(sedCmd, shell=True)
390
391 info('*** Copying sys.config to linc-oe directory: ', output + '\n')
392 output = quietRun('cp -v sys.config %s/rel/linc/releases/1.0/' % LINCSwitch.lincDir, shell=True).strip('\n')
393 info(output + '\n')
394
395 info('*** Adding taps and bringing them up...\n')
396 LINCSwitch.setupInts(LINCSwitch.getTaps())
397
398 info('*** removing pipes if any \n')
399 quietRun('rm /tmp/home/%s/linc-oe/rel/linc/*' % LINCSwitch.user, shell=True)
400
401 info('*** Starting linc OE...\n')
402 output = quietRun('%s/rel/linc/bin/linc start' % LINCSwitch.lincDir, shell=True)
403 if output:
404 error('***ERROR: LINC-OE: %s' % output + '\n')
405 quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True)
406 return False
407
408 info('*** Waiting for linc-oe to start...\n')
409 LINCSwitch.waitStarted(net)
410
411 info('*** Adding cross-connect (tap) interfaces to packet switches...\n')
412 for link in net.links:
413 if isinstance(link, LINCLink):
414 if link.annotations[ 'optical.type' ] == 'cross-connect':
415 for intf in [ link.intf1, link.intf2 ]:
416 if not isinstance(intf, LINCIntf):
417 intfList = [ intf.link.intf1, intf.link.intf2 ]
418 intfList.remove(intf)
419 intf2 = intfList[ 0 ]
420 intf.node.attach(LINCSwitch.findTap(intf2.node, intf2.node.ports[ intf2 ]))
421
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700422 info('*** Waiting for all devices to be available in ONOS...\n')
423 url = 'http://%s:8181/onos/v1/devices' % LINCSwitch.controllers[0].ip
424 time = 0
425 while True:
426 response = json.load(urllib2.urlopen(url))
427 devs = response.get('devices')
428
429 # Wait for all devices to be registered & available
430 if (len(devices) == len(devs)):
431 for d in devs:
432 if not d['available']:
433 continue
434 break
435
436 if (time >= TIMEOUT):
437 error('***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT)
438 break
439
440 time += SLEEP_TIME
441 sleep(SLEEP_TIME)
442
fahad44e62c72015-03-04 14:55:35 -0800443 info('*** Pushing Topology.json to ONOS\n')
444 output = quietRun('%s/tools/test/bin/onos-topo-cfg %s Topology.json' % (LINCSwitch.onosDir, LINCSwitch.controllers[ 0 ].ip), shell=True)
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700445
fahad44e62c72015-03-04 14:55:35 -0800446 # successful output contains the two characters '{}'
447 # if there is more output than this, there is an issue
448 if output.strip('{}'):
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700449 warn('***WARNING: Could not push topology file to ONOS: %s\n' % output)
fahad44e62c72015-03-04 14:55:35 -0800450
451 @staticmethod
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700452 def waitStarted(net, timeout=TIMEOUT):
fahad44e62c72015-03-04 14:55:35 -0800453 "wait until all tap interfaces are available"
454 tapCount = 0
455 time = 0
456 for link in net.links:
457 if isinstance(link, LINCLink):
458 if link.annotations[ 'optical.type' ] == 'cross-connect':
459 tapCount += 1
460
461 while True:
462 if str(tapCount) == quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'):
463 return True
464 if timeout:
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700465 if time >= TIMEOUT:
466 error('***ERROR: LINC OE did not start within %s seconds\n' % TIMEOUT)
fahad44e62c72015-03-04 14:55:35 -0800467 return False
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700468 time += SLEEP_TIME
469 sleep(SLEEP_TIME)
fahad44e62c72015-03-04 14:55:35 -0800470
471 @staticmethod
472 def shutdownOE():
473 "stop the optical emulator"
474 info('*** Stopping linc OE...\n')
475 quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True)
476
477 @staticmethod
478 def setupInts(intfs):
479 '''
480 add taps and bring them up.
481 '''
482 for i in intfs:
483 quietRun('ip tuntap add dev %s mode tap' % i)
484 quietRun('ip link set dev %s up' % i)
485 info('*** Intf %s set\n' % i)
486
487 @staticmethod
488 def getTaps(path=None):
489 '''
490 return list of all the tops in sys.config
491 '''
492 if path is None:
493 path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir
494 fd = open(path, 'r', 0)
495 sys_data = fd.read()
496 taps = re.findall('tap\d+', sys_data)
497 fd.close()
498 return taps
499
500 @staticmethod
501 def findUser():
502 "Try to return logged-in (usually non-root) user"
503 try:
504 # If we're running sudo
505 return os.environ[ 'SUDO_USER' ]
506 except:
507 try:
508 # Logged-in user (if we have a tty)
509 return quietRun('who am i').split()[ 0 ]
510 except:
511 # Give up and return effective user
512 return quietRun('whoami')
513
514
515 @staticmethod
516 def findTap(node, port, path=None):
517 '''utility function to parse through a sys.config
518 file to find tap interfaces for a switch'''
519 switch = False
520 portLine = ''
521 intfLines = []
522
523 if path is None:
524 path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir
525
526 with open(path) as f:
527 for line in f:
528 if 'tap' in line:
529 intfLines.append(line)
530 if node.dpid in line.translate(None, ':'):
531 switch = True
532 continue
533 if switch:
534 if 'switch' in line:
535 switch = False
536 if 'port_no,%s}' % port in line:
537 portLine = line
538 break
539
540 if portLine:
541 m = re.search('port,\d+', portLine)
542 port = m.group(0).split(',')[ 1 ]
543 else:
544 error('***ERROR: Could not find any ports in sys.config\n')
545 return
546
547 for intfLine in intfLines:
548 if 'port,%s' % port in intfLine:
549 return re.findall('tap\d+', intfLine)[ 0 ]
550
551 def json(self):
552 "return json configuration dictionary for switch"
553 return self.configDict
554
555 def terminate(self):
556 pass
557
558class LINCLink(Link):
559 """
560 LINC link class
561 """
562 def __init__(self, node1, node2, port1=None, port2=None, allowed=True,
Brian O'Connoreb27c452014-12-07 02:43:58 -0800563 intfName1=None, intfName2=None, linkType='OPTICAL',
fahad44e62c72015-03-04 14:55:35 -0800564 annotations={}, speed1=0, speed2=0, **params):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800565 "Creates a dummy link without a virtual ethernet pair."
566 self.allowed = allowed
567 self.annotations = annotations
568 self.linkType = linkType
fahad44e62c72015-03-04 14:55:35 -0800569 self.port1 = port1
570 self.port2 = port2
Brian O'Connoreb27c452014-12-07 02:43:58 -0800571 params1 = { 'speed': speed1 }
572 params2 = { 'speed': speed2 }
fahad44e62c72015-03-04 14:55:35 -0800573 # self.isCrossConnect = True if self.annotations.get('optical.type') == 'cross-connect' else False
574 if isinstance(node1, LINCSwitch) and isinstance(node2, LINCSwitch):
575 self.isCrossConnect = False
576 else:
577 self.isCrossConnect = True
578 if isinstance(node1, LINCSwitch):
579 cls1 = LINCIntf
580 if self.isCrossConnect:
581 node1.crossConnects.append(self)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800582 else:
583 cls1 = Intf
584 # bad hack to stop error message from appearing when we try to set up intf in a packet switch,
585 # and there is no interface there( because we do not run makeIntfPair ). This way, we just set lo up
586 intfName1 = 'lo'
fahad44e62c72015-03-04 14:55:35 -0800587 if isinstance(node2, LINCSwitch):
588 cls2 = LINCIntf
589 if self.isCrossConnect:
590 node2.crossConnects.append(self)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800591 else:
592 cls2 = Intf
593 intfName2 = 'lo'
fahad44e62c72015-03-04 14:55:35 -0800594 Link.__init__(self, node1, node2, port1=port1, port2=port2,
Brian O'Connoreb27c452014-12-07 02:43:58 -0800595 intfName1=intfName1, intfName2=intfName2, cls1=cls1,
fahad44e62c72015-03-04 14:55:35 -0800596 cls2=cls2, params1=params1, params2=params2)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800597
598 @classmethod
fahad44e62c72015-03-04 14:55:35 -0800599 def makeIntfPair(_cls, intfName1, intfName2, *args, **kwargs):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800600 pass
601
fahad44e62c72015-03-04 14:55:35 -0800602 def json(self):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800603 "build and return the json configuration dictionary for this link"
604 configData = {}
fahad44e62c72015-03-04 14:55:35 -0800605 configData[ 'src' ] = ('of:' + self.intf1.node.dpid +
606 '/%s' % self.intf1.node.ports[ self.intf1 ])
607 configData[ 'dst' ] = ('of:' + self.intf2.node.dpid +
608 '/%s' % self.intf2.node.ports[ self.intf2 ])
Brian O'Connoreb27c452014-12-07 02:43:58 -0800609 configData[ 'type' ] = self.linkType
610 configData[ 'annotations' ] = self.annotations
611 return configData
612
fahad44e62c72015-03-04 14:55:35 -0800613class LINCIntf(OpticalIntf):
614 """
615 LINC interface class
616 """
617 def __init__(self, name=None, node=None, speed=0,
618 port=None, link=None, **params):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800619 self.node = node
620 self.speed = speed
621 self.port = port
622 self.link = link
623 self.name = name
fahad44e62c72015-03-04 14:55:35 -0800624 node.addIntf(self, port=port)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800625 self.params = params
626 self.ip = None
627
fahad44e62c72015-03-04 14:55:35 -0800628 def json(self):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800629 "build and return the JSON information for this interface( not used right now )"
630 configDict = {}
631 configDict[ 'port' ] = self.port
632 configDict[ 'speed' ] = self.speed
633 configDict[ 'type' ] = 'FIBER'
634 return configDict
635
fahad44e62c72015-03-04 14:55:35 -0800636 def config(self, *args, **kwargs):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800637 "dont configure a dummy interface"
638 pass
639
fahad44e62c72015-03-04 14:55:35 -0800640 def ifconfig(self, status):
641 "configure the status"
642 if status == "up":
643 return self.node.w_port_up(self.port)
644 elif status == "down":
645 return self.node.w_port_down(self.port)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800646
647
fahad44e62c72015-03-04 14:55:35 -0800648class MininetOE(Mininet):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800649 "Mininet with Linc-OE support (starts and stops linc-oe)"
650
fahad44e62c72015-03-04 14:55:35 -0800651 def start(self):
652 Mininet.start(self)
653 LINCSwitch.bootOE(self)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800654
fahad44e62c72015-03-04 14:55:35 -0800655 def stop(self):
656 Mininet.stop(self)
657 LINCSwitch.shutdownOE()
Brian O'Connoreb27c452014-12-07 02:43:58 -0800658
fahad44e62c72015-03-04 14:55:35 -0800659 def addControllers(self, controllers):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800660 i = 0
661 for ctrl in controllers:
fahad44e62c72015-03-04 14:55:35 -0800662 self.addController(RemoteController('c%d' % i, ip=ctrl))
663 i += 1
Brian O'Connoreb27c452014-12-07 02:43:58 -0800664
665if __name__ == '__main__':
fahad44e62c72015-03-04 14:55:35 -0800666 pass