OECF removed working
Change-Id: I178a227fedacb4efc8669c839042d952f4efd670
diff --git a/apps/oecfg/pom.xml b/apps/oecfg/pom.xml
deleted file mode 100644
index 8f595db..0000000
--- a/apps/oecfg/pom.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright 2014 Open Networking Laboratory
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-apps</artifactId>
- <version>1.3.0-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <artifactId>onos-app-oecfg</artifactId>
- <packaging>jar</packaging>
-
- <description>Standalone utility for converting ONOS JSON config to OE-Linc JSON config</description>
-
- <dependencies>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-databind</artifactId>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-annotations</artifactId>
- <scope>compile</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-shade-plugin</artifactId>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>shade</goal>
- </goals>
- <configuration>
- <transformers>
- <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
- <manifestEntries>
- <Main-Class>org.onosproject.oecfg.OELinkConfig</Main-Class>
- </manifestEntries>
- </transformer>
- </transformers>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
-</project>
diff --git a/apps/oecfg/src/main/java/org/onosproject/oecfg/OELinkConfig.java b/apps/oecfg/src/main/java/org/onosproject/oecfg/OELinkConfig.java
deleted file mode 100644
index 480640c..0000000
--- a/apps/oecfg/src/main/java/org/onosproject/oecfg/OELinkConfig.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.oecfg;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Utility program to convert standard ONOS config JSON to format expected
- * by the OE Link switch.
- */
-public final class OELinkConfig {
-
- private ObjectMapper mapper = new ObjectMapper();
- private Map<String, String> dpidToName = new HashMap<>();
-
- public static void main(String[] args) {
- try {
- OELinkConfig config = new OELinkConfig();
- JsonNode json = config.convert(System.in);
- System.out.println(json.toString());
- } catch (IOException e) {
- System.err.println("Unable to convert JSON due to: " + e.getMessage());
- e.printStackTrace();
- }
- }
-
- private OELinkConfig() {
- }
-
- private JsonNode convert(InputStream input) throws IOException {
- JsonNode json = mapper.readTree(input);
- ObjectNode result = mapper.createObjectNode();
- result.set("switchConfig", opticalSwitches(json));
- result.set("linkConfig", opticalLinks(json));
- return result;
- }
-
- private JsonNode opticalSwitches(JsonNode json) {
- ArrayNode result = mapper.createArrayNode();
- for (JsonNode node : json.get("devices")) {
- String dpid = dpid(node.path("uri"));
- String name = node.path("name").asText("none");
- dpidToName.put(dpid, name);
- if (node.path("type").asText("none").equals("ROADM")) {
- result.add(opticalSwitch(dpid, name, (ObjectNode) node));
- }
- }
- return result;
- }
-
- private ObjectNode opticalSwitch(String dpid, String name, ObjectNode node) {
- ObjectNode result = mapper.createObjectNode();
- ObjectNode annot = (ObjectNode) node.path("annotations");
- result.put("allowed", true).put("type", "Roadm")
- .put("name", name).put("nodeDpid", dpid)
- .put("latitude", annot.path("latitude").asDouble(0.0))
- .put("longitude", annot.path("longitude").asDouble(0.0))
- .set("params", switchParams(annot));
- return result;
- }
-
- private ObjectNode switchParams(ObjectNode annot) {
- return mapper.createObjectNode()
- .put("numRegen", annot.path("optical.regens").asInt(0));
- }
-
- private JsonNode opticalLinks(JsonNode json) {
- ArrayNode result = mapper.createArrayNode();
- for (JsonNode node : json.get("links")) {
- if (node.path("type").asText("none").equals("OPTICAL")) {
- result.add(opticalLink((ObjectNode) node));
- }
- }
- return result;
- }
-
- private ObjectNode opticalLink(ObjectNode node) {
- ObjectNode result = mapper.createObjectNode();
- ObjectNode annot = (ObjectNode) node.path("annotations");
- String src = dpid(node.path("src"));
- String dst = dpid(node.path("dst"));
- result.put("allowed", true).put("type", linkType(annot))
- .put("nodeDpid1", src).put("nodeDpid2", dst)
- .set("params", linkParams(src, dst, node, annot));
- return result;
- }
-
- private String linkType(ObjectNode annot) {
- return annot.path("optical.type").asText("cross-connect").equals("WDM") ?
- "wdmLink" : "pktOptLink";
- }
-
- private ObjectNode linkParams(String src, String dst,
- ObjectNode node, ObjectNode annot) {
- ObjectNode result = mapper.createObjectNode()
- .put("nodeName1", dpidToName.get(src))
- .put("nodeName2", dpidToName.get(dst))
- .put("port1", port(node.path("src")))
- .put("port2", port(node.path("dst")));
- if (annot.has("bandwidth")) {
- result.put("bandwidth", annot.path("bandwidth").asInt());
- }
- if (annot.has("optical.waves")) {
- result.put("numWaves", annot.path("optical.waves").asInt());
- }
- return result;
- }
-
- private String dpid(JsonNode node) {
- String s = node.asText("of:0000000000000000").substring(3);
- return s.substring(0, 2) + ":" + s.substring(2, 4) + ":" +
- s.substring(4, 6) + ":" + s.substring(6, 8) + ":" +
- s.substring(8, 10) + ":" + s.substring(10, 12) + ":" +
- s.substring(12, 14) + ":" + s.substring(14, 16);
- }
-
- private int port(JsonNode node) {
- return Integer.parseInt(node.asText("of:0000000000000000/0").substring(20));
- }
-
-}
diff --git a/apps/pom.xml b/apps/pom.xml
index cc7e1f6..de25b9d 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -40,7 +40,6 @@
<module>sdnip</module>
<module>optical</module>
<module>metrics</module>
- <module>oecfg</module>
<module>routing</module>
<module>routing-api</module>
<module>reactive-routing</module>
diff --git a/tools/test/topos/opticalUtils.py b/tools/test/topos/opticalUtils.py
index 5b47d53..3315ce6 100644
--- a/tools/test/topos/opticalUtils.py
+++ b/tools/test/topos/opticalUtils.py
@@ -4,7 +4,7 @@
Notes:
This file contains classes and methods useful for integrating LincOE with Mininet,
-such as startOE, stopOE, LINCLink, and OpticalSwitch
+such as startOE, stopOE, OpticalLink, and OpticalSwitch
- $ONOS_ROOT ust be set
- Need to run with sudo -E to preserve ONOS_ROOT env var
@@ -22,10 +22,10 @@
Usage:
------------
- - import LINCLink and OpticalSwitch from this module
+ - import OpticalLink 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
+ to an optical switch with topo.addLink, always specify cls=OpticalLink
- 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
@@ -51,12 +51,11 @@
Topology configuration file to ONOS.
'''
-import sys
+
import re
import json
import os
from time import sleep
-import urllib2
from mininet.node import Switch, RemoteController
from mininet.topo import Topo
@@ -66,127 +65,25 @@
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 ):
-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
- ### 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):
+ def __init__( self, name, dpid=None, allowed=True,
+ switchType='ROADM', annotations={}, **params ):
params[ 'inNamespace' ] = False
- Switch.__init__(self, name, dpid=dpid, **params)
+ 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
+ self.configDict = {} # dictionary that holds all of the JSON configuration data
- def start(self, *opts, **params):
+ 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[ 'annotations' ].setdefault( 'name', self.name )
+ self.configDict[ 'hw' ] = 'OE'
self.configDict[ 'mfr' ] = 'Linc'
self.configDict[ 'mac' ] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1]
self.configDict[ 'type' ] = self.switchType
@@ -195,441 +92,74 @@
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):
- '''
- start the 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' % (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
- portDict[ 'type' ] = 'FIBER' if isinstance(intf.link, LINCLink) else 'COPPER'
- 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):
- "Start the LINC optical emulator within a mininet instance"
- opticalJSON = {}
- linkConfig = []
- devices = []
- #setting up the controllers for LINCSwitch class
- LINCSwitch.controllers = net.controllers
-
- for switch in net.switches:
- if isinstance(switch, OpticalSwitch):
- devices.append(switch.json())
- else:
- devices.append(LINCSwitch.switchJSON(switch))
- opticalJSON[ 'devices' ] = devices
-
- for link in net.links:
- if isinstance(link, LINCLink) :
- linkConfig.append(link.json())
- opticalJSON[ 'links' ] = linkConfig
-
- info('*** Writing Topology.json file\n')
- with open('Topology.json', 'w') as outfile:
- json.dump(opticalJSON, outfile, indent=4, separators=(',', ': '))
-
- info('*** Converting Topology.json to linc-oe format (TopoConfig.json) file\n')
- output = quietRun('%s/tools/test/bin/onos-oecfg ./Topology.json > TopoConfig.json' % LINCSwitch.onosDir, shell=True)
- if output:
- error('***ERROR: Error creating topology file: %s ' % output + '\n')
- return False
-
- 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
- while True:
- response = json.load(urllib2.urlopen(url))
- devs = response.get('devices')
-
- # Wait for all devices to be registered
- if (len(devices) != len(devs)):
- continue
-
- # Wait for all devices to available
- available = True
- for d in devs:
- 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 &' % (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)
-
- @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:
- if str(tapCount) == quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'):
- 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')
+ self.configDict[ 'ports' ].append( intf.json() )
- @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):
+ def json( self ):
"return json configuration dictionary for switch"
return self.configDict
-
- def terminate(self):
+
+ def terminate( self ):
pass
-class LINCLink(Link):
- """
- LINC link class
- """
- def __init__(self, node1, node2, port1=None, port2=None, allowed=True,
+class OpticalLink( Link ):
+
+ def __init__( self, node1, node2, port1=None, port2=None, allowed=True,
intfName1=None, intfName2=None, linkType='OPTICAL',
- annotations={}, speed1=0, speed2=0, **params):
+ 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)
+
+ if isinstance( node1, OpticalSwitch ):
+ cls1 = OpticalIntf
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)
+ if isinstance( node2, OpticalSwitch ):
+ cls2 = OpticalIntf
else:
cls2 = Intf
intfName2 = 'lo'
- Link.__init__(self, node1, node2, port1=port1, port2=port2,
+ Link.__init__( self, node1, node2, port1=port1, port2=port2,
intfName1=intfName1, intfName2=intfName2, cls1=cls1,
- cls2=cls2, params1=params1, params2=params2)
+ cls2=cls2, params1=params1, params2=params2 )
+
@classmethod
- def makeIntfPair(_cls, intfName1, intfName2, *args, **kwargs):
+ def makeIntfPair( _cls, intfName1, intfName2, *args, **kwargs ):
pass
- def json(self):
+ 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[ '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):
+class OpticalIntf( Intf ):
+
+ 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)
+ node.addIntf( self, port=port )
self.params = params
self.ip = None
- def json(self):
+ def json( self ):
"build and return the JSON information for this interface( not used right now )"
configDict = {}
configDict[ 'port' ] = self.port
@@ -637,34 +167,356 @@
configDict[ 'type' ] = 'FIBER'
return configDict
- def config(self, *args, **kwargs):
+ 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)
+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
+ portDict[ 'type' ] = 'FIBER' if isinstance( intf.link, OpticalLink ) else 'COPPER'
+ intfList = [ intf.link.intf1, intf.link.intf2 ]
+ intfList.remove( intf )
+ portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance( intf.link, OpticalLink ) else 0
+ ports.append( portDict )
+ configDict[ 'ports' ] = ports
+ return configDict
-class MininetOE(Mininet):
+def startOE( net ):
+ "Start the LINC optical emulator within a mininet instance"
+ opticalJSON = {}
+ linkConfig = []
+ devices = []
+
+ for switch in net.switches:
+ if isinstance( switch, OpticalSwitch ):
+ devices.append( switch.json() )
+ else:
+ devices.append( switchJSON( switch ) )
+ opticalJSON[ 'devices' ] = devices
+
+ for link in net.links:
+ if isinstance( link, OpticalLink ) :
+ linkConfig.append( link.json() )
+
+ opticalJSON[ 'links' ] = linkConfig
+
+ try:
+ onosDir = os.environ[ 'ONOS_ROOT' ]
+ except:
+ onosDir = findDir( 'onos' )
+ if not onosDir:
+ error( 'Please set ONOS_ROOT environment variable!\n' )
+ return False
+ else:
+ os.environ[ 'ONOS_ROOT' ] = onosDir
+
+ info( '*** Writing Topology.json file\n' )
+ with open( 'Topology.json', 'w' ) as outfile:
+ json.dump( opticalJSON, outfile, indent=4, separators=(',', ': ') )
+
+ info( '*** Converting Topology.json to linc-oe format (TopoConfig.json) file (not using oecfg) \n' )
+
+ topoConfigJson = {};
+ newLinkConfig = [];
+ switchConfig = [];
+ dpIdToName = {};
+
+ #Iterate through all switches and convert the ROADM switches to linc-oe format
+ for switch in opticalJSON["devices"]:
+ if switch["type"] == "ROADM":
+ builtSwitch = {}
+
+ #set basic switch params based on annotations
+ builtSwitch["allowed"] = True;
+ builtSwitch["latitude"] = switch["annotations"]["latitude"];
+ builtSwitch["longitude"] = switch["annotations"]["longitude"];
+
+ nodeId = switch["uri"]
+
+ #convert the nodeId to linc-oe format
+ nodeDpid = dpId(nodeId);
+
+ if "name" in switch:
+ builtSwitch["name"] = switch["name"]
+ else:
+ builtSwitch["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"]["optical.regens"];
+ builtSwitch["type"] = "Roadm"
+
+ #append to list of switches
+ switchConfig.append(builtSwitch);
+
+ topoConfigJson["switchConfig"] = switchConfig;
+
+ #Iterate through all optical links and convert them to linc-oe format
+ for link in opticalJSON["links"]:
+ if link["type"] == "OPTICAL":
+ builtLink = {}
+
+ #set basic link params for src and dst
+ builtLink["allowed"] = True;
+ builtLink["nodeDpid1"] = dpId(link["src"])
+ builtLink["nodeDpid2"] = 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")
+ if "bandwidth" in link["annotations"]:
+ params["bandwidth"] = link["annotations"]["bandwidth"]
+ params["port1"] = int(link["src"].split("/")[1])
+ params["port2"] = int(link["dst"].split("/")[1])
+
+ 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"]["optical.type"] == "WDM":
+ builtLink["type"] = "wdmLink"
+ else:
+ builtLink["type"] = "pktOptLink"
+
+ newLinkConfig.append(builtLink);
+
+ topoConfigJson["linkConfig"] = newLinkConfig;
+
+ #Writing to TopoConfig.json
+ with open( 'TopoConfig.json', 'w' ) as outfile:
+ json.dump( topoConfigJson, outfile, indent=4, separators=(',', ': ') )
+
+ info( '*** Creating sys.config...\n' )
+ configGen = findDir( 'LINC-config-generator' )
+ if not configGen:
+ error( "***ERROR: Could not find LINC-config-generator in user's home directory\n" )
+ return False
+ output = quietRun( '%s/config_generator TopoConfig.json %s/sys.config.template %s %s'
+ % ( configGen, configGen, net.controllers[ 0 ].ip, net.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 = '{controllers,.*$'
+ ctrlStr = ''
+ for index in range(len(net.controllers)):
+ ctrlStr += '{"Switch%d-Controller","%s",%d,tcp},' % (index, net.controllers[index].ip, net.controllers[index].port)
+ replaceStr = '{controllers,[%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' )
+ lincDir = findDir( 'linc-oe' )
+ if not lincDir:
+ error( "***ERROR: Could not find linc-oe in user's home directory\n" )
+ return False
+ output = quietRun( 'cp -v sys.config %s/rel/linc/releases/1.0/' % lincDir, shell=True ).strip( '\n' )
+ info( output + '\n' )
+
+ info( '*** Starting linc OE...\n' )
+ output = quietRun( '%s/rel/linc/bin/linc start' % lincDir, shell=True )
+ if output:
+ error( '***ERROR: LINC-OE: %s' % output + '\n' )
+ quietRun( '%s/rel/linc/bin/linc stop' % lincDir, shell=True )
+ return False
+
+ info( '*** Waiting for linc-oe to start...\n' )
+ waitStarted( net )
+
+ info( '*** Adding cross-connect (tap) interfaces to packet switches...\n' )
+ for link in net.links:
+ if isinstance( link, OpticalLink ):
+ if link.annotations[ 'optical.type' ] == 'cross-connect':
+ for intf in [ link.intf1, link.intf2 ]:
+ if not isinstance( intf, OpticalIntf ):
+ intfList = [ intf.link.intf1, intf.link.intf2 ]
+ intfList.remove( intf )
+ intf2 = intfList[ 0 ]
+ intf.node.attach( findTap( intf2.node, intf2.node.ports[ intf2 ] ) )
+
+ info( '*** Press ENTER to push Topology.json to onos...\n' )
+ raw_input() # FIXME... we should eventually remove this
+ info( '*** Pushing Topology.json to ONOS\n' )
+ output = quietRun( '%s/tools/test/bin/onos-topo-cfg %s Topology.json' % ( onosDir, net.controllers[ 0 ].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' % output )
+
+#converts node ids to linc-oe format, with colons every two chars
+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:(len(nodeDpid) - 1)];
+
+def waitStarted( net, timeout=None ):
+ "wait until all tap interfaces are available"
+ tapCount = 0
+ time = 0
+ for link in net.links:
+ if isinstance( link, OpticalLink ):
+ if link.annotations[ 'optical.type' ] == 'cross-connect':
+ tapCount += 1
+
+ while True:
+ if str( tapCount ) == quietRun( 'ip addr | grep tap | wc -l', shell=True ).strip( '\n' ):
+ return True
+ if timeout:
+ if time >= timeout:
+ error( '***ERROR: Linc OE did not start within %s seconds' % timeout )
+ return False
+ time += .5
+ sleep( .5 )
+
+def stopOE():
+ "stop the optical emulator"
+ info( '*** Stopping linc OE...\n' )
+ lincDir = findDir( 'linc-oe' )
+ quietRun( '%s/rel/linc/bin/linc stop' % lincDir, shell=True )
+
+def findDir( directory ):
+ "finds and returns the path of any directory in the user's home directory"
+ user = findUser()
+ homeDir = '/home/' + user
+ 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
+
+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' )
+
+
+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:
+ lincDir = findDir( 'linc-oe' )
+ if not lincDir:
+ error( '***ERROR: Could not find linc-oe in users home directory\n' )
+ return None
+ path = '%s/rel/linc/releases/1.0/sys.config' % 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 ]
+
+
+class MininetOE( Mininet ):
"Mininet with Linc-OE support (starts and stops linc-oe)"
- def start(self):
- Mininet.start(self)
- LINCSwitch.bootOE(self)
+ def start( self ):
+ Mininet.start( self )
+ startOE( self )
- def stop(self):
- Mininet.stop(self)
- LINCSwitch.shutdownOE()
+ def stop( self ):
+ Mininet.stop( self )
+ stopOE()
- def addControllers(self, controllers):
+ def addControllers( self, controllers ):
i = 0
for ctrl in controllers:
- self.addController(RemoteController('c%d' % i, ip=ctrl))
- i += 1
+ self.addController( RemoteController( 'c%d' % i, ip=ctrl ) )
+
+
+class OpticalTestTopo( Topo ):
+
+ def build( self ):
+ opticalAnn = { 'optical.waves': 80, 'optical.type': "WDM", 'durable': True }
+ switchAnn = { 'bandwidth': 100000, 'optical.type': 'cross-connect', 'durable': True }
+ h1 = self.addHost( 'h1' )
+ h2 = self.addHost( 'h2' )
+ s1 = self.addSwitch( 's1' )
+ s2 = self.addSwitch( 's2' )
+ O4 = self.addSwitch( 'O4', cls=OpticalSwitch )
+ O5 = self.addSwitch( 'O5', cls=OpticalSwitch )
+ O6 = self.addSwitch( 'O6', cls=OpticalSwitch )
+ self.addLink( O4, O5, cls=OpticalLink, annotations=opticalAnn )
+ self.addLink( O5, O6, cls=OpticalLink, annotations=opticalAnn )
+ self.addLink( s1, O4, cls=OpticalLink, annotations=switchAnn )
+ self.addLink( s2, O6, cls=OpticalLink, annotations=switchAnn )
+ self.addLink( h1, s1 )
+ self.addLink( h2, s2 )
if __name__ == '__main__':
- pass
+ import sys
+ if len( sys.argv ) >= 2:
+ controllers = sys.argv[1:]
+ else:
+ print 'Usage: ./opticalUtils.py (<Controller IP>)+'
+ print 'Using localhost...\n'
+ controllers = [ '127.0.0.1' ]
+
+ setLogLevel( 'info' )
+ net = MininetOE( topo=OpticalTestTopo(), controller=None, autoSetMacs=True )
+ net.addControllers( controllers )
+ net.start()
+ CLI( net )
+ net.stop()