aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/tools/test/topos/opticalUtils.py
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/tools/test/topos/opticalUtils.py')
-rw-r--r--framework/src/onos/tools/test/topos/opticalUtils.py846
1 files changed, 0 insertions, 846 deletions
diff --git a/framework/src/onos/tools/test/topos/opticalUtils.py b/framework/src/onos/tools/test/topos/opticalUtils.py
deleted file mode 100644
index 87903cc5..00000000
--- a/framework/src/onos/tools/test/topos/opticalUtils.py
+++ /dev/null
@@ -1,846 +0,0 @@
-#!/usr/bin/python
-
-'''
-Notes:
-
-This file contains classes and methods useful for integrating LincOE with Mininet,
-such as startOE, stopOE, LINCLink, and OpticalSwitch
-
-- $ONOS_ROOT ust be set
-- Need to run with sudo -E to preserve ONOS_ROOT env var
-- We assume LINC-Config-Generator is named LINC-Config-Generator
-- We also assume linc-oe is named linc-oe
-- LINC-config-generator and linc-oe must be subdirectories of the user's
- home directory
-
- TODO
- -----------
- - clean up files after runtime
- - maybe save the old files in a separate directory?
- - modify script to allow startOE to run before net.start()
- - add ONOS as a controller in script
-
- Usage:
- ------------
- - import LINCLink and OpticalSwitch from this module
- - import startOE and stopOE from this module
- - create topology as you would a normal topology. when
- to an optical switch with topo.addLink, always specify cls=LINCLink
- - when creating an optical switch, use cls=OpticalSwitch in topo.addSwitch
- - for annotations on links and switches, a dictionary must be passed in as
- the annotations argument
- - startOE must be run AFTER net.start() with net as an argument.
- - stopOE can be run at any time
-
-I created a separate function to start lincOE to avoid subclassing Mininet.
-In case anyone wants to write something that DOES subclass Mininet, I
-thought I would outline how:
-
-If we want an object that starts lincOE within the mininet class itself,
-we need to add another object to Mininet that contains all of the json object
-information for each switch. We would still subclass switch and link, but these
-classes would basically be dummy classes that store their own json information
-in the Mininet class object. We may also change the default switch class to add
-it's tap interfaces from lincOE during startup. The start() method for mininet would
-grab all of the information from these switches and links, write configuration files
-for lincOE using the json module, start lincOE, then run the start methodfor each
-switch. The new start() method for each switch would parse through the sys.config
-file that was created and find the tap interface it needs to connect to, similar
-to the findTap function that I currently use. After all of the controllers and
-switches have been started, the new Mininet start() method should also push the
-Topology configuration file to ONOS.
-
-'''
-import sys
-import re
-import json
-import os
-from time import sleep
-import urllib2
-
-from mininet.node import Switch, OVSSwitch, RemoteController
-from mininet.topo import Topo
-from mininet.util import quietRun
-from mininet.net import Mininet
-from mininet.log import setLogLevel, info, error, warn
-from mininet.link import Link, Intf
-from mininet.cli import CLI
-
-# Sleep time and timeout values in seconds
-SLEEP_TIME = 2
-TIMEOUT = 60
-
-class OpticalSwitch(Switch):
- """
- For now, same as Switch class.
- """
- pass
-
-class OpticalIntf(Intf):
- """
- For now,same as Intf class.
- """
- pass
-
-class OpticalLink(Link):
- """
- For now, same as Link.
- """
- pass
-
-class LINCSwitch(OpticalSwitch):
- """
- LINCSwitch class
- """
- # FIXME:Sometimes LINC doesn't remove pipes and on restart increase the pipe
- # number from erlang.pipe.1.* to erlang.pipe.2.*, so should read and write
- # from latest pipe files. For now we are removing all the pipes before
- # starting LINC.
- ### User Name ###
- user = os.getlogin()
- ### pipes ###
- readPipe = "/tmp/home/{}/linc-oe/rel/linc/erlang.pipe.1.r".format(user)
- writePipe = "/tmp/home/{}/linc-oe/rel/linc/erlang.pipe.1.w".format(user)
- ### sys.config path ###
- sysConfig = "/home/{}/linc-oe/rel/linc/releases/1.0/sys.config".format(user)
- ### method, mapping dpid to LINC switchId ###
- @staticmethod
- def dpids_to_ids(sysConfig):
- '''
- return the dict containing switch dpids as key and LINC switch id as values
- '''
- dpids_to_ids = {}
- fd = None
- try:
- with open(sysConfig, 'r', 0) as fd:
- switch_id = 1
- for line in fd:
- dpid = re.search(r'([0-9A-Fa-f]{2}[:-]){7}([0-9A-Fa-f]{2})+', line, re.I)
- if dpid:
- dpids_to_ids[dpid.group().replace(':', '')] = switch_id
- switch_id += 1
- return dpids_to_ids
- except:
- print "Error working with {}\nError: {}\n".format(sysConfig, sys.exc_info())
- fd.close()
- return None
- ### dict of containing dpids as key and corresponding LINC switchId as values ###
- dpidsToLINCSwitchId = dpids_to_ids.__func__(sysConfig)
- @staticmethod
- def findDir(directory, userName):
- "finds and returns the path of any directory in the user's home directory"
- homeDir = '/home/' + userName
- Dir = quietRun('find %s -maxdepth 1 -name %s -type d' % (homeDir, directory)).strip('\n')
- DirList = Dir.split('\n')
- if not Dir:
- return None
- elif len(DirList) > 1 :
- warn('***WARNING: Found multiple instances of %s; using %s\n'
- % (directory, DirList[ 0 ]))
- return DirList[ 0 ]
- else:
- return Dir
- ### ONOS Directory ###
- try:
- onosDir = os.environ[ 'ONOS_ROOT' ]
- except:
- onosDir = findDir('onos', user)
- if not onosDir:
- error('Please set ONOS_ROOT environment variable!\n')
- else:
- os.environ[ 'ONOS_ROOT' ] = onosDir
- ### REST USER/PASS ###
- try:
- restUser = os.environ[ 'ONOS_WEB_USER' ]
- restPass = os.environ[ 'ONOS_WEB_PASS' ]
- except:
- error('***WARNING: $ONOS_WEB_USER and $ONOS_WEB_PASS aren\'t set!\n')
- error('***WARNING: Setting (probably) sane WEB user/pass values\n')
- restUser = 'onos'
- restPass = 'rocks'
- os.environ[ 'ONOS_WEB_USER' ] = restUser
- os.environ[ 'ONOS_WEB_PASS' ] = restPass
- ### LINC-directory
- lincDir = findDir.__func__('linc-oe', user)
- if not lincDir:
- error("***ERROR: Could not find linc-oe in user's home directory\n")
- ### LINC config generator directory###
- configGen = findDir.__func__('LINC-config-generator', user)
- if not configGen:
- error("***ERROR: Could not find LINC-config-generator in user's home directory\n")
- # list of all the controllers
- controllers = None
- def __init__(self, name, dpid=None, allowed=True,
- switchType='ROADM', topo=None, annotations={}, controller=None, **params):
- params[ 'inNamespace' ] = False
- Switch.__init__(self, name, dpid=dpid, **params)
- self.name = name
- self.annotations = annotations
- self.allowed = allowed
- self.switchType = switchType
- self.configDict = {} # dictionary that holds all of the JSON configuration data
- self.crossConnects = []
- self.deletedCrossConnects = []
- self.controller = controller
- self.lincId = self._get_linc_id() # use to communicate with LINC
- self.lincStarted = False
-
- def start(self, *opts, **params):
- '''Instead of starting a virtual switch, we build the JSON
- dictionary for the emulated optical switch'''
- # TODO:Once LINC has the ability to spawn network element dynamically
- # we need to use this method to spawn new logical LINC switch rather then
- # bulding JSON.
- # if LINC is started then we can start and stop logical switches else create JSON
- if self.lincStarted:
- return self.start_oe()
- self.configDict[ 'uri' ] = 'of:' + self.dpid
- self.configDict[ 'annotations' ] = self.annotations
- self.configDict[ 'annotations' ].setdefault('name', self.name)
- self.configDict[ 'hw' ] = 'LINC-OE'
- self.configDict[ 'mfr' ] = 'Linc'
- self.configDict[ 'mac' ] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1]
- self.configDict[ 'type' ] = self.switchType
- self.configDict[ 'ports' ] = []
- for port, intf in self.intfs.items():
- if intf.name == 'lo':
- continue
- else:
- self.configDict[ 'ports' ].append(intf.json())
- self.lincStarted = True
-
- def stop(self, deleteIntfs=False):
- '''
- stop the existing switch
- '''
- # TODO:Add support for deleteIntf
- self.stop_oe()
-
- def dpctl( self, *args ):
- "Run dpctl command: ignore for now"
- pass
-
- def write_to_cli(self, command):
- '''
- send command to LINC
- '''
- fd = None
- try:
- fd = open(self.writePipe, 'w', 0)
- fd.write(command)
- fd.close()
- except:
- print "Error working with {}\nError: {}\n".format(self.writePipe, sys.exc_info())
- if fd:
- fd.close()
-
- def read_from_cli(self):
- '''
- read the output from the LINC CLI
- '''
- response = None
- fd = None
- try:
- fd = open(self.readPipe, 'r', 0)
- fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) # for non-blocking read
- # FIXME:Due to non-blocking read most for the time we read nothing
- response = fd.read()
- fd.close()
- except :
- # print "Error working with {}\nError: {}\n".format(self.readPipe, sys.exc_info())
- if fd:
- fd.close()
- return response
-
- def _get_linc_id(self):
- '''
- return the corresponding LINC switchId.
- '''
- return LINCSwitch.dpidsToLINCSwitchId.get(self.dpid)
- #--------------------------------------------------------------------------
- # LINC CLI commands
- #--------------------------------------------------------------------------
- def start_oe(self):
- '''
- existing LINC switch
- '''
- #starting Switch
- cmd = "linc:start_switch({}).\r\n".format(self.lincId)
- self.write_to_cli(cmd)
- #hanlding taps interfaces related to the switch
- crossConnectJSON = {}
- linkConfig = []
- for i in range(0,len(self.deletedCrossConnects)):
- crossConnect = self.deletedCrossConnects.pop()
- tap = None
- if isinstance(crossConnect.intf1.node, LINCSwitch):
- intf = crossConnect.intf2
- tapPort = crossConnect.intf1.port
- else:
- intf = crossConnect.intf1
- tapPort = crossConnect.intf2.port
- tap = LINCSwitch.findTap(self, tapPort)
- if tap:
- LINCSwitch.setupInts([tap])
- intf.node.attach(tap)
- self.crossConnects.append(crossConnect)
- linkConfig.append(crossConnect.json())
- #Sending crossConnect info to the ONOS.
- crossConnectJSON['links'] = linkConfig
- with open("crossConnect.json", 'w') as fd:
- json.dump(crossConnectJSON, fd, indent=4, separators=(',', ': '))
- info('*** Pushing crossConnect.json to ONOS\n')
- output = quietRun('%s/tools/test/bin/onos-topo-cfg %s\
- Topology.json network/configuration/' % (self.onosDir, self.controllers[ 0 ].ip), shell=True)
-
- def stop_oe(self):
- '''
- stop the existing LINC switch
- '''
- cmd = "linc:stop_switch({}).\r\n".format(self.lincId)
- self.write_to_cli(cmd)
- #handling taps if any
- for i in range(0, len(self.crossConnects)):
- crossConnect = self.crossConnects.pop()
- if isinstance(crossConnect.intf1.node, LINCSwitch):
- intf = crossConnect.intf2
- tapPort = crossConnect.intf1.port
- else:
- intf = crossConnect.intf1
- tapPort = crossConnect.intf2.port
- intf.node.detach(LINCSwitch.findTap(self, tapPort))
- self.deletedCrossConnects.append(crossConnect)
-
- def w_port_up(self, port):
- '''
- port_up
- '''
- cmd = "linc:port_up({},{}).\r\n".format(self.lincId, port)
- self.write_to_cli(cmd)
-
- def w_port_down(self, port):
- '''
- port_down
- '''
- cmd = "linc:port_down({},{}).\r\n".format(self.lincId, port)
- self.write_to_cli(cmd)
-
- # helper functions
- @staticmethod
- def switchJSON(switch):
- "Returns the json configuration for a packet switch"
- configDict = {}
- configDict[ 'uri' ] = 'of:' + switch.dpid
- configDict[ 'mac' ] = quietRun('cat /sys/class/net/%s/address' % switch.name).strip('\n').translate(None, ':')
- configDict[ 'hw' ] = 'PK' # FIXME what about OVS?
- configDict[ 'mfr' ] = 'Linc' # FIXME what about OVS?
- configDict[ 'type' ] = 'SWITCH' # FIXME what about OVS?
- annotations = switch.params.get('annotations', {})
- annotations.setdefault('name', switch.name)
- configDict[ 'annotations' ] = annotations
- ports = []
- for port, intf in switch.intfs.items():
- if intf.name == 'lo':
- continue
- portDict = {}
- portDict[ 'port' ] = port
- portType = 'COPPER'
- if isinstance(intf.link, LINCLink):
- portType = 'OCH' if intf.link.isCrossConnect else 'OMS'
- portDict[ 'type' ] = portType
- intfList = [ intf.link.intf1, intf.link.intf2 ]
- intfList.remove(intf)
- portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance(intf.link, LINCLink) else 0
- ports.append(portDict)
- configDict[ 'ports' ] = ports
- return configDict
-
- @staticmethod
- def bootOE(net, domain=None):
- """
- Start the LINC optical emulator within a mininet instance
-
- This involves 1. converting the information stored in Linc* to configs
- for both LINC and the network config system, 2. starting Linc, 3. connecting
- cross-connects, and finally pushing the network configs to ONOS.
-
- Inevitably, there are times when we have OVS switches that should not be
- under the control of the controller in charge of the Linc switches. We
- hint at these by passing domain information.
- """
- LINCSwitch.opticalJSON = {}
- linkConfig = []
- devices = []
- #setting up the controllers for LINCSwitch class
- LINCSwitch.controllers = net.controllers
-
- for switch in net.switches:
- if domain and switch not in domain:
- continue
- if isinstance(switch, OpticalSwitch):
- devices.append(switch.json())
- elif isinstance(switch, OVSSwitch):
- devices.append(LINCSwitch.switchJSON(switch))
- LINCSwitch.opticalJSON[ 'devices' ] = devices
-
- for link in net.links:
- if isinstance(link, LINCLink) :
- linkConfig.append(link.json())
- LINCSwitch.opticalJSON[ 'links' ] = linkConfig
-
- info('*** Writing Topology.json file\n')
- topoJSON = LINCSwitch.makeTopoJSON()
- with open('Topology.json', 'w') as outfile:
- json.dump(topoJSON, outfile, indent=4, separators=(',', ': '))
-
- info('*** Converting Topology.json to linc-oe format (TopoConfig.json) file (no oecfg) \n')
-
- topoConfigJson = {}
- dpIdToName = {}
-
- topoConfigJson["switchConfig"] = LINCSwitch.getSwitchConfig(dpIdToName)
- topoConfigJson["linkConfig"] = LINCSwitch.getLinkConfig(dpIdToName)
-
- #Writing to TopoConfig.json
- with open( 'TopoConfig.json', 'w' ) as outfile:
- json.dump( topoConfigJson, outfile, indent=4, separators=(',', ': ') )
-
- info('*** Creating sys.config...\n')
- output = quietRun('%s/config_generator TopoConfig.json %s/sys.config.template %s %s'
- % (LINCSwitch.configGen, LINCSwitch.configGen, LINCSwitch.controllers[ 0 ].ip, LINCSwitch.controllers[ 0 ].port), shell=True)
- if output:
- error('***ERROR: Error creating sys.config file: %s\n' % output)
- return False
-
- info ('*** Setting multiple controllers in sys.config...\n')
- searchStr = '\[{"Switch.*$'
- ctrlStr = ''
- for index in range(len(LINCSwitch.controllers)):
- ctrlStr += '{"Switch%d-Controller","%s",%d,tcp},' % (index, net.controllers[index].ip, net.controllers[index].port)
- replaceStr = '[%s]},' % ctrlStr[:-1] # Cut off last comma
- sedCmd = 'sed -i \'s/%s/%s/\' sys.config' % (searchStr, replaceStr)
- output = quietRun(sedCmd, shell=True)
-
- info('*** Copying sys.config to linc-oe directory: ', output + '\n')
- output = quietRun('cp -v sys.config %s/rel/linc/releases/1.0/' % LINCSwitch.lincDir, shell=True).strip('\n')
- info(output + '\n')
-
- info('*** Adding taps and bringing them up...\n')
- LINCSwitch.setupInts(LINCSwitch.getTaps())
-
- info('*** removing pipes if any \n')
- quietRun('rm /tmp/home/%s/linc-oe/rel/linc/*' % LINCSwitch.user, shell=True)
-
- info('*** Starting linc OE...\n')
- output = quietRun('%s/rel/linc/bin/linc start' % LINCSwitch.lincDir, shell=True)
- if output:
- error('***ERROR: LINC-OE: %s' % output + '\n')
- quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True)
- return False
-
- info('*** Waiting for linc-oe to start...\n')
- LINCSwitch.waitStarted(net)
-
- info('*** Adding cross-connect (tap) interfaces to packet switches...\n')
- for link in net.links:
- if isinstance(link, LINCLink):
- if link.annotations[ 'optical.type' ] == 'cross-connect':
- for intf in [ link.intf1, link.intf2 ]:
- if not isinstance(intf, LINCIntf):
- intfList = [ intf.link.intf1, intf.link.intf2 ]
- intfList.remove(intf)
- intf2 = intfList[ 0 ]
- intf.node.attach(LINCSwitch.findTap(intf2.node, intf2.node.ports[ intf2 ]))
-
- info('*** Waiting for all devices to be available in ONOS...\n')
- url = 'http://%s:8181/onos/v1/devices' % LINCSwitch.controllers[0].ip
- time = 0
- # Set up password authentication
- pw_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
- pw_mgr.add_password(None, url, LINCSwitch.restUser, LINCSwitch.restPass)
- handler = urllib2.HTTPBasicAuthHandler(pw_mgr)
- opener = urllib2.build_opener(handler)
- opener.open(url)
- urllib2.install_opener(opener)
- # focus on just checking the state of devices we're interested in
- devlist = map( lambda x: x['uri'], devices )
- while True:
- response = json.load(urllib2.urlopen(url))
- devs = response.get('devices')
-
- # Wait for all devices to be registered. There is a chance that this is only a subgraph.
- if (len(devices) > len(devs)):
- continue
-
- # Wait for all devices to available
- available = True
- for d in devs:
- if d['id'] in devlist:
- available &= d['available']
- if available:
- break
-
- if (time >= TIMEOUT):
- error('***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT)
- break
-
- time += SLEEP_TIME
- sleep(SLEEP_TIME)
-
- info('*** Pushing Topology.json to ONOS\n')
- for index in range(len(LINCSwitch.controllers)):
- output = quietRun('%s/tools/test/bin/onos-topo-cfg %s Topology.json network/configuration/ &'\
- % (LINCSwitch.onosDir, LINCSwitch.controllers[ index ].ip), shell=True)
- # successful output contains the two characters '{}'
- # if there is more output than this, there is an issue
- if output.strip('{}'):
- warn('***WARNING: Could not push topology file to ONOS: %s\n' % output)
-
- #converts node ids to linc-oe format, with colons every two chars
- @staticmethod
- def dpId(id):
- nodeDpid = ""
- id = id.split("/", 1)[0]
- for i in range(3, len(id) - 1, 2):
- nodeDpid += (id[i:(i + 2):]) + ":"
- return nodeDpid[0:-1];
-
- @staticmethod
- def makeTopoJSON():
- """
- Builds ONOS network conifg system compatible dicts to be written as Topology.json file.
- """
- topology = {}
- links = {}
- devices = {}
- ports = {}
-
- for switch in LINCSwitch.opticalJSON[ 'devices' ]:
- # build device entries - keyed on uri (DPID) and config key 'basic'
- devDict = {}
- devDict[ 'driver' ] = switch[ 'hw' ]
- devDict[ 'mfr' ] = switch[ 'mfr' ]
- devDict[ 'mac' ] = switch[ 'mac' ]
- devDict[ 'type' ] = switch[ 'type' ]
- devDict.update(switch[ 'annotations' ])
-
- devSubj = switch[ 'uri' ]
- devices[ devSubj ] = { 'basic': devDict }
-
- # build port entries - keyed on "uri/port" and config key 'optical'
- for port in switch[ 'ports' ]:
- portSubj = devSubj + '/' + str(port[ 'port' ])
- ports[ portSubj ] = { 'optical': port }
-
- # build link entries - keyed on "uri/port-uri/port" and config key 'basic'
- for link in LINCSwitch.opticalJSON[ 'links' ]:
- linkDict = {}
- linkDict[ 'type' ] = link[ 'type' ]
- linkDict.update(link[ 'annotations' ])
-
- linkSubj = link[ 'src' ] + '-' + link[ 'dst' ]
- links[ linkSubj ] = { 'basic': linkDict }
-
- topology[ 'links' ] = links
- topology[ 'devices' ] = devices
- topology[ 'ports' ] = ports
-
- return topology
-
- @staticmethod
- def getSwitchConfig (dpIdToName):
- switchConfig = [];
- #Iterate through all switches and convert the ROADM switches to linc-oe format
- for switch in LINCSwitch.opticalJSON["devices"]:
- if switch.get("type", "none") == "ROADM":
- builtSwitch = {}
-
- #set basic switch params based on annotations
- builtSwitch["allowed"] = True;
- builtSwitch["latitude"] = switch["annotations"].get("latitude", 0.0);
- builtSwitch["longitude"] = switch["annotations"].get("longitude", 0.0);
-
- #assumed that all switches have this entry
- nodeId = switch["uri"]
-
- #convert the nodeId to linc-oe format
- nodeDpid = LINCSwitch.dpId(nodeId);
-
- builtSwitch["name"] = switch.get("name", "none");
-
- #keep track of the name corresponding to each switch dpid
- dpIdToName[nodeDpid] = builtSwitch["name"];
-
- builtSwitch["nodeDpid"] = nodeDpid
-
- #set switch params and type
- builtSwitch["params"] = {};
- builtSwitch["params"]["numregens"] = switch["annotations"].get("optical.regens", 0);
- builtSwitch["type"] = "Roadm"
-
- #append to list of switches
- switchConfig.append(builtSwitch);
- return switchConfig
-
- @staticmethod
- def getLinkConfig (dpIdToName):
- newLinkConfig = [];
- #Iterate through all optical links and convert them to linc-oe format
- for link in LINCSwitch.opticalJSON["links"]:
- if link.get("type", "none") == "OPTICAL":
- builtLink = {}
-
- #set basic link params for src and dst
- builtLink["allowed"] = True;
- builtLink["nodeDpid1"] = LINCSwitch.dpId(link["src"])
- builtLink["nodeDpid2"] = LINCSwitch.dpId(link["dst"])
-
- #set more params such as name/bandwidth/port/waves if they exist
- params = {}
- params["nodeName1"] = dpIdToName.get(builtLink["nodeDpid1"], "none")
- params["nodeName2"] = dpIdToName.get(builtLink["nodeDpid2"], "none")
-
- params["port1"] = int(link["src"].split("/")[1])
- params["port2"] = int(link["dst"].split("/")[1])
-
- if "bandwidth" in link["annotations"]:
- params["bandwidth"] = link["annotations"]["bandwidth"]
-
- if "optical.waves" in link["annotations"]:
- params["numWaves"] = link["annotations"]["optical.waves"]
-
- builtLink["params"] = params
-
- #set type of link (WDM or pktOpt)
- if link["annotations"].get("optical.type", "cross-connect") == "WDM":
- builtLink["type"] = "wdmLink"
- else:
- builtLink["type"] = "pktOptLink"
-
- newLinkConfig.append(builtLink);
- return newLinkConfig
-
-
- @staticmethod
- def waitStarted(net, timeout=TIMEOUT):
- "wait until all tap interfaces are available"
- tapCount = 0
- time = 0
- for link in net.links:
- if isinstance(link, LINCLink):
- if link.annotations[ 'optical.type' ] == 'cross-connect':
- tapCount += 1
- while True:
- # tapCount can be less than the actual number of taps if the optical network
- # is a subgraph of a larger multidomain network.
- tapNum = int(quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'))
- if tapCount <= tapNum:
- return True
- if timeout:
- if time >= TIMEOUT:
- error('***ERROR: LINC OE did not start within %s seconds\n' % TIMEOUT)
- return False
- time += SLEEP_TIME
- sleep(SLEEP_TIME)
-
- @staticmethod
- def shutdownOE():
- "stop the optical emulator"
- info('*** Stopping linc OE...\n')
- quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True)
-
- @staticmethod
- def setupInts(intfs):
- '''
- add taps and bring them up.
- '''
- for i in intfs:
- quietRun('ip tuntap add dev %s mode tap' % i)
- quietRun('ip link set dev %s up' % i)
- info('*** Intf %s set\n' % i)
-
- @staticmethod
- def getTaps(path=None):
- '''
- return list of all the tops in sys.config
- '''
- if path is None:
- path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir
- fd = open(path, 'r', 0)
- sys_data = fd.read()
- taps = re.findall('tap\d+', sys_data)
- fd.close()
- return taps
-
- @staticmethod
- def findUser():
- "Try to return logged-in (usually non-root) user"
- try:
- # If we're running sudo
- return os.environ[ 'SUDO_USER' ]
- except:
- try:
- # Logged-in user (if we have a tty)
- return quietRun('who am i').split()[ 0 ]
- except:
- # Give up and return effective user
- return quietRun('whoami')
-
-
- @staticmethod
- def findTap(node, port, path=None):
- '''utility function to parse through a sys.config
- file to find tap interfaces for a switch'''
- switch = False
- portLine = ''
- intfLines = []
-
- if path is None:
- path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir
-
- with open(path) as f:
- for line in f:
- if 'tap' in line:
- intfLines.append(line)
- if node.dpid in line.translate(None, ':'):
- switch = True
- continue
- if switch:
- if 'switch' in line:
- switch = False
- if 'port_no,%s}' % port in line:
- portLine = line
- break
-
- if portLine:
- m = re.search('port,\d+', portLine)
- port = m.group(0).split(',')[ 1 ]
- else:
- error('***ERROR: Could not find any ports in sys.config\n')
- return
-
- for intfLine in intfLines:
- if 'port,%s' % port in intfLine:
- return re.findall('tap\d+', intfLine)[ 0 ]
-
- def json(self):
- "return json configuration dictionary for switch"
- return self.configDict
-
- def terminate(self):
- pass
-
-
-
-class LINCLink(Link):
- """
- LINC link class
- """
- def __init__(self, node1, node2, port1=None, port2=None, allowed=True,
- intfName1=None, intfName2=None, linkType='OPTICAL',
- annotations={}, speed1=0, speed2=0, **params):
- "Creates a dummy link without a virtual ethernet pair."
- self.allowed = allowed
- self.annotations = annotations
- self.linkType = linkType
- self.port1 = port1
- self.port2 = port2
- params1 = { 'speed': speed1 }
- params2 = { 'speed': speed2 }
- # self.isCrossConnect = True if self.annotations.get('optical.type') == 'cross-connect' else False
- if isinstance(node1, LINCSwitch) and isinstance(node2, LINCSwitch):
- self.isCrossConnect = False
- else:
- self.isCrossConnect = True
- if isinstance(node1, LINCSwitch):
- cls1 = LINCIntf
- if self.isCrossConnect:
- node1.crossConnects.append(self)
- else:
- cls1 = Intf
- # bad hack to stop error message from appearing when we try to set up intf in a packet switch,
- # and there is no interface there( because we do not run makeIntfPair ). This way, we just set lo up
- intfName1 = 'lo'
- if isinstance(node2, LINCSwitch):
- cls2 = LINCIntf
- if self.isCrossConnect:
- node2.crossConnects.append(self)
- else:
- cls2 = Intf
- intfName2 = 'lo'
- Link.__init__(self, node1, node2, port1=port1, port2=port2,
- intfName1=intfName1, intfName2=intfName2, cls1=cls1,
- cls2=cls2, params1=params1, params2=params2)
-
- @classmethod
- def makeIntfPair(_cls, intfName1, intfName2, *args, **kwargs):
- pass
-
- def json(self):
- "build and return the json configuration dictionary for this link"
- configData = {}
- configData[ 'src' ] = ('of:' + self.intf1.node.dpid +
- '/%s' % self.intf1.node.ports[ self.intf1 ])
- configData[ 'dst' ] = ('of:' + self.intf2.node.dpid +
- '/%s' % self.intf2.node.ports[ self.intf2 ])
- configData[ 'type' ] = self.linkType
- configData[ 'annotations' ] = self.annotations
- return configData
-
-class LINCIntf(OpticalIntf):
- """
- LINC interface class
- """
- def __init__(self, name=None, node=None, speed=0,
- port=None, link=None, **params):
- self.node = node
- self.speed = speed
- self.port = port
- self.link = link
- self.name = name
- node.addIntf(self, port=port)
- self.params = params
- self.ip = None
-
- def json(self):
- "build and return the JSON information for this interface( not used right now )"
- configDict = {}
- configDict[ 'port' ] = self.port
- configDict[ 'speed' ] = self.speed
- portType = 'COPPER'
- if isinstance(self.link, LINCLink):
- portType = 'OCH' if self.link.isCrossConnect else 'OMS'
- configDict[ 'type' ] = portType
- return configDict
-
- def config(self, *args, **kwargs):
- "dont configure a dummy interface"
- pass
-
- def ifconfig(self, status):
- "configure the status"
- if status == "up":
- return self.node.w_port_up(self.port)
- elif status == "down":
- return self.node.w_port_down(self.port)
-
-
-class MininetOE(Mininet):
- "Mininet with Linc-OE support (starts and stops linc-oe)"
-
- def start(self):
- Mininet.start(self)
- LINCSwitch.bootOE(self)
-
- def stop(self):
- Mininet.stop(self)
- LINCSwitch.shutdownOE()
-
- def addControllers(self, controllers):
- i = 0
- for ctrl in controllers:
- self.addController(RemoteController('c%d' % i, ip=ctrl))
- i += 1
-
-if __name__ == '__main__':
- pass