blob: 5b47d53f1f6df2048e19edeeb40ad99a9f51ac84 [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
Marc De Leenheerd24420f2015-05-27 09:40:59 -070070SLEEP_TIME = 2
Marc De Leenheer16f857b2015-05-05 20:50:24 -070071TIMEOUT = 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
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700429 # Wait for all devices to be registered
430 if (len(devices) != len(devs)):
431 continue
432
433 # Wait for all devices to available
434 available = True
435 for d in devs:
436 available &= d['available']
437 if available:
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700438 break
439
440 if (time >= TIMEOUT):
441 error('***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT)
442 break
443
444 time += SLEEP_TIME
445 sleep(SLEEP_TIME)
446
fahad44e62c72015-03-04 14:55:35 -0800447 info('*** Pushing Topology.json to ONOS\n')
Ayaka Koshibe74b55272015-05-28 15:16:04 -0700448 for index in range(len(LINCSwitch.controllers)):
449 output = quietRun('%s/tools/test/bin/onos-topo-cfg %s Topology.json &' % (LINCSwitch.onosDir, LINCSwitch.controllers[ index ].ip), shell=True)
450 # successful output contains the two characters '{}'
451 # if there is more output than this, there is an issue
452 if output.strip('{}'):
453 warn('***WARNING: Could not push topology file to ONOS: %s\n' % output)
fahad44e62c72015-03-04 14:55:35 -0800454
455 @staticmethod
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700456 def waitStarted(net, timeout=TIMEOUT):
fahad44e62c72015-03-04 14:55:35 -0800457 "wait until all tap interfaces are available"
458 tapCount = 0
459 time = 0
460 for link in net.links:
461 if isinstance(link, LINCLink):
462 if link.annotations[ 'optical.type' ] == 'cross-connect':
463 tapCount += 1
464
465 while True:
466 if str(tapCount) == quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'):
467 return True
468 if timeout:
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700469 if time >= TIMEOUT:
470 error('***ERROR: LINC OE did not start within %s seconds\n' % TIMEOUT)
fahad44e62c72015-03-04 14:55:35 -0800471 return False
Marc De Leenheer16f857b2015-05-05 20:50:24 -0700472 time += SLEEP_TIME
473 sleep(SLEEP_TIME)
fahad44e62c72015-03-04 14:55:35 -0800474
475 @staticmethod
476 def shutdownOE():
477 "stop the optical emulator"
478 info('*** Stopping linc OE...\n')
479 quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True)
480
481 @staticmethod
482 def setupInts(intfs):
483 '''
484 add taps and bring them up.
485 '''
486 for i in intfs:
487 quietRun('ip tuntap add dev %s mode tap' % i)
488 quietRun('ip link set dev %s up' % i)
489 info('*** Intf %s set\n' % i)
490
491 @staticmethod
492 def getTaps(path=None):
493 '''
494 return list of all the tops in sys.config
495 '''
496 if path is None:
497 path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir
498 fd = open(path, 'r', 0)
499 sys_data = fd.read()
500 taps = re.findall('tap\d+', sys_data)
501 fd.close()
502 return taps
503
504 @staticmethod
505 def findUser():
506 "Try to return logged-in (usually non-root) user"
507 try:
508 # If we're running sudo
509 return os.environ[ 'SUDO_USER' ]
510 except:
511 try:
512 # Logged-in user (if we have a tty)
513 return quietRun('who am i').split()[ 0 ]
514 except:
515 # Give up and return effective user
516 return quietRun('whoami')
517
518
519 @staticmethod
520 def findTap(node, port, path=None):
521 '''utility function to parse through a sys.config
522 file to find tap interfaces for a switch'''
523 switch = False
524 portLine = ''
525 intfLines = []
526
527 if path is None:
528 path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir
529
530 with open(path) as f:
531 for line in f:
532 if 'tap' in line:
533 intfLines.append(line)
534 if node.dpid in line.translate(None, ':'):
535 switch = True
536 continue
537 if switch:
538 if 'switch' in line:
539 switch = False
540 if 'port_no,%s}' % port in line:
541 portLine = line
542 break
543
544 if portLine:
545 m = re.search('port,\d+', portLine)
546 port = m.group(0).split(',')[ 1 ]
547 else:
548 error('***ERROR: Could not find any ports in sys.config\n')
549 return
550
551 for intfLine in intfLines:
552 if 'port,%s' % port in intfLine:
553 return re.findall('tap\d+', intfLine)[ 0 ]
554
555 def json(self):
556 "return json configuration dictionary for switch"
557 return self.configDict
558
559 def terminate(self):
560 pass
561
562class LINCLink(Link):
563 """
564 LINC link class
565 """
566 def __init__(self, node1, node2, port1=None, port2=None, allowed=True,
Brian O'Connoreb27c452014-12-07 02:43:58 -0800567 intfName1=None, intfName2=None, linkType='OPTICAL',
fahad44e62c72015-03-04 14:55:35 -0800568 annotations={}, speed1=0, speed2=0, **params):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800569 "Creates a dummy link without a virtual ethernet pair."
570 self.allowed = allowed
571 self.annotations = annotations
572 self.linkType = linkType
fahad44e62c72015-03-04 14:55:35 -0800573 self.port1 = port1
574 self.port2 = port2
Brian O'Connoreb27c452014-12-07 02:43:58 -0800575 params1 = { 'speed': speed1 }
576 params2 = { 'speed': speed2 }
fahad44e62c72015-03-04 14:55:35 -0800577 # self.isCrossConnect = True if self.annotations.get('optical.type') == 'cross-connect' else False
578 if isinstance(node1, LINCSwitch) and isinstance(node2, LINCSwitch):
579 self.isCrossConnect = False
580 else:
581 self.isCrossConnect = True
582 if isinstance(node1, LINCSwitch):
583 cls1 = LINCIntf
584 if self.isCrossConnect:
585 node1.crossConnects.append(self)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800586 else:
587 cls1 = Intf
588 # bad hack to stop error message from appearing when we try to set up intf in a packet switch,
589 # and there is no interface there( because we do not run makeIntfPair ). This way, we just set lo up
590 intfName1 = 'lo'
fahad44e62c72015-03-04 14:55:35 -0800591 if isinstance(node2, LINCSwitch):
592 cls2 = LINCIntf
593 if self.isCrossConnect:
594 node2.crossConnects.append(self)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800595 else:
596 cls2 = Intf
597 intfName2 = 'lo'
fahad44e62c72015-03-04 14:55:35 -0800598 Link.__init__(self, node1, node2, port1=port1, port2=port2,
Brian O'Connoreb27c452014-12-07 02:43:58 -0800599 intfName1=intfName1, intfName2=intfName2, cls1=cls1,
fahad44e62c72015-03-04 14:55:35 -0800600 cls2=cls2, params1=params1, params2=params2)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800601
602 @classmethod
fahad44e62c72015-03-04 14:55:35 -0800603 def makeIntfPair(_cls, intfName1, intfName2, *args, **kwargs):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800604 pass
605
fahad44e62c72015-03-04 14:55:35 -0800606 def json(self):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800607 "build and return the json configuration dictionary for this link"
608 configData = {}
fahad44e62c72015-03-04 14:55:35 -0800609 configData[ 'src' ] = ('of:' + self.intf1.node.dpid +
610 '/%s' % self.intf1.node.ports[ self.intf1 ])
611 configData[ 'dst' ] = ('of:' + self.intf2.node.dpid +
612 '/%s' % self.intf2.node.ports[ self.intf2 ])
Brian O'Connoreb27c452014-12-07 02:43:58 -0800613 configData[ 'type' ] = self.linkType
614 configData[ 'annotations' ] = self.annotations
615 return configData
616
fahad44e62c72015-03-04 14:55:35 -0800617class LINCIntf(OpticalIntf):
618 """
619 LINC interface class
620 """
621 def __init__(self, name=None, node=None, speed=0,
622 port=None, link=None, **params):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800623 self.node = node
624 self.speed = speed
625 self.port = port
626 self.link = link
627 self.name = name
fahad44e62c72015-03-04 14:55:35 -0800628 node.addIntf(self, port=port)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800629 self.params = params
630 self.ip = None
631
fahad44e62c72015-03-04 14:55:35 -0800632 def json(self):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800633 "build and return the JSON information for this interface( not used right now )"
634 configDict = {}
635 configDict[ 'port' ] = self.port
636 configDict[ 'speed' ] = self.speed
637 configDict[ 'type' ] = 'FIBER'
638 return configDict
639
fahad44e62c72015-03-04 14:55:35 -0800640 def config(self, *args, **kwargs):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800641 "dont configure a dummy interface"
642 pass
643
fahad44e62c72015-03-04 14:55:35 -0800644 def ifconfig(self, status):
645 "configure the status"
646 if status == "up":
647 return self.node.w_port_up(self.port)
648 elif status == "down":
649 return self.node.w_port_down(self.port)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800650
651
fahad44e62c72015-03-04 14:55:35 -0800652class MininetOE(Mininet):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800653 "Mininet with Linc-OE support (starts and stops linc-oe)"
654
fahad44e62c72015-03-04 14:55:35 -0800655 def start(self):
656 Mininet.start(self)
657 LINCSwitch.bootOE(self)
Brian O'Connoreb27c452014-12-07 02:43:58 -0800658
fahad44e62c72015-03-04 14:55:35 -0800659 def stop(self):
660 Mininet.stop(self)
661 LINCSwitch.shutdownOE()
Brian O'Connoreb27c452014-12-07 02:43:58 -0800662
fahad44e62c72015-03-04 14:55:35 -0800663 def addControllers(self, controllers):
Brian O'Connoreb27c452014-12-07 02:43:58 -0800664 i = 0
665 for ctrl in controllers:
fahad44e62c72015-03-04 14:55:35 -0800666 self.addController(RemoteController('c%d' % i, ip=ctrl))
667 i += 1
Brian O'Connoreb27c452014-12-07 02:43:58 -0800668
669if __name__ == '__main__':
fahad44e62c72015-03-04 14:55:35 -0800670 pass