Committed by
Gerrit Code Review
OECF removed working
Change-Id: I178a227fedacb4efc8669c839042d952f4efd670
Showing
4 changed files
with
382 additions
and
746 deletions
apps/oecfg/pom.xml
deleted
100644 → 0
1 | -<?xml version="1.0" encoding="UTF-8"?> | ||
2 | -<!-- | ||
3 | - ~ Copyright 2014 Open Networking Laboratory | ||
4 | - ~ | ||
5 | - ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | - ~ you may not use this file except in compliance with the License. | ||
7 | - ~ You may obtain a copy of the License at | ||
8 | - ~ | ||
9 | - ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | - ~ | ||
11 | - ~ Unless required by applicable law or agreed to in writing, software | ||
12 | - ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | - ~ See the License for the specific language governing permissions and | ||
15 | - ~ limitations under the License. | ||
16 | - --> | ||
17 | -<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
18 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
19 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
20 | - <modelVersion>4.0.0</modelVersion> | ||
21 | - | ||
22 | - <parent> | ||
23 | - <groupId>org.onosproject</groupId> | ||
24 | - <artifactId>onos-apps</artifactId> | ||
25 | - <version>1.3.0-SNAPSHOT</version> | ||
26 | - <relativePath>../pom.xml</relativePath> | ||
27 | - </parent> | ||
28 | - | ||
29 | - <artifactId>onos-app-oecfg</artifactId> | ||
30 | - <packaging>jar</packaging> | ||
31 | - | ||
32 | - <description>Standalone utility for converting ONOS JSON config to OE-Linc JSON config</description> | ||
33 | - | ||
34 | - <dependencies> | ||
35 | - <dependency> | ||
36 | - <groupId>com.fasterxml.jackson.core</groupId> | ||
37 | - <artifactId>jackson-databind</artifactId> | ||
38 | - <scope>compile</scope> | ||
39 | - </dependency> | ||
40 | - <dependency> | ||
41 | - <groupId>com.fasterxml.jackson.core</groupId> | ||
42 | - <artifactId>jackson-annotations</artifactId> | ||
43 | - <scope>compile</scope> | ||
44 | - </dependency> | ||
45 | - </dependencies> | ||
46 | - | ||
47 | - <build> | ||
48 | - <plugins> | ||
49 | - <plugin> | ||
50 | - <groupId>org.apache.maven.plugins</groupId> | ||
51 | - <artifactId>maven-shade-plugin</artifactId> | ||
52 | - <executions> | ||
53 | - <execution> | ||
54 | - <phase>package</phase> | ||
55 | - <goals> | ||
56 | - <goal>shade</goal> | ||
57 | - </goals> | ||
58 | - <configuration> | ||
59 | - <transformers> | ||
60 | - <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | ||
61 | - <manifestEntries> | ||
62 | - <Main-Class>org.onosproject.oecfg.OELinkConfig</Main-Class> | ||
63 | - </manifestEntries> | ||
64 | - </transformer> | ||
65 | - </transformers> | ||
66 | - </configuration> | ||
67 | - </execution> | ||
68 | - </executions> | ||
69 | - </plugin> | ||
70 | - </plugins> | ||
71 | - </build> | ||
72 | - | ||
73 | -</project> |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onosproject.oecfg; | ||
17 | - | ||
18 | -import com.fasterxml.jackson.databind.JsonNode; | ||
19 | -import com.fasterxml.jackson.databind.ObjectMapper; | ||
20 | -import com.fasterxml.jackson.databind.node.ArrayNode; | ||
21 | -import com.fasterxml.jackson.databind.node.ObjectNode; | ||
22 | - | ||
23 | -import java.io.IOException; | ||
24 | -import java.io.InputStream; | ||
25 | -import java.util.HashMap; | ||
26 | -import java.util.Map; | ||
27 | - | ||
28 | -/** | ||
29 | - * Utility program to convert standard ONOS config JSON to format expected | ||
30 | - * by the OE Link switch. | ||
31 | - */ | ||
32 | -public final class OELinkConfig { | ||
33 | - | ||
34 | - private ObjectMapper mapper = new ObjectMapper(); | ||
35 | - private Map<String, String> dpidToName = new HashMap<>(); | ||
36 | - | ||
37 | - public static void main(String[] args) { | ||
38 | - try { | ||
39 | - OELinkConfig config = new OELinkConfig(); | ||
40 | - JsonNode json = config.convert(System.in); | ||
41 | - System.out.println(json.toString()); | ||
42 | - } catch (IOException e) { | ||
43 | - System.err.println("Unable to convert JSON due to: " + e.getMessage()); | ||
44 | - e.printStackTrace(); | ||
45 | - } | ||
46 | - } | ||
47 | - | ||
48 | - private OELinkConfig() { | ||
49 | - } | ||
50 | - | ||
51 | - private JsonNode convert(InputStream input) throws IOException { | ||
52 | - JsonNode json = mapper.readTree(input); | ||
53 | - ObjectNode result = mapper.createObjectNode(); | ||
54 | - result.set("switchConfig", opticalSwitches(json)); | ||
55 | - result.set("linkConfig", opticalLinks(json)); | ||
56 | - return result; | ||
57 | - } | ||
58 | - | ||
59 | - private JsonNode opticalSwitches(JsonNode json) { | ||
60 | - ArrayNode result = mapper.createArrayNode(); | ||
61 | - for (JsonNode node : json.get("devices")) { | ||
62 | - String dpid = dpid(node.path("uri")); | ||
63 | - String name = node.path("name").asText("none"); | ||
64 | - dpidToName.put(dpid, name); | ||
65 | - if (node.path("type").asText("none").equals("ROADM")) { | ||
66 | - result.add(opticalSwitch(dpid, name, (ObjectNode) node)); | ||
67 | - } | ||
68 | - } | ||
69 | - return result; | ||
70 | - } | ||
71 | - | ||
72 | - private ObjectNode opticalSwitch(String dpid, String name, ObjectNode node) { | ||
73 | - ObjectNode result = mapper.createObjectNode(); | ||
74 | - ObjectNode annot = (ObjectNode) node.path("annotations"); | ||
75 | - result.put("allowed", true).put("type", "Roadm") | ||
76 | - .put("name", name).put("nodeDpid", dpid) | ||
77 | - .put("latitude", annot.path("latitude").asDouble(0.0)) | ||
78 | - .put("longitude", annot.path("longitude").asDouble(0.0)) | ||
79 | - .set("params", switchParams(annot)); | ||
80 | - return result; | ||
81 | - } | ||
82 | - | ||
83 | - private ObjectNode switchParams(ObjectNode annot) { | ||
84 | - return mapper.createObjectNode() | ||
85 | - .put("numRegen", annot.path("optical.regens").asInt(0)); | ||
86 | - } | ||
87 | - | ||
88 | - private JsonNode opticalLinks(JsonNode json) { | ||
89 | - ArrayNode result = mapper.createArrayNode(); | ||
90 | - for (JsonNode node : json.get("links")) { | ||
91 | - if (node.path("type").asText("none").equals("OPTICAL")) { | ||
92 | - result.add(opticalLink((ObjectNode) node)); | ||
93 | - } | ||
94 | - } | ||
95 | - return result; | ||
96 | - } | ||
97 | - | ||
98 | - private ObjectNode opticalLink(ObjectNode node) { | ||
99 | - ObjectNode result = mapper.createObjectNode(); | ||
100 | - ObjectNode annot = (ObjectNode) node.path("annotations"); | ||
101 | - String src = dpid(node.path("src")); | ||
102 | - String dst = dpid(node.path("dst")); | ||
103 | - result.put("allowed", true).put("type", linkType(annot)) | ||
104 | - .put("nodeDpid1", src).put("nodeDpid2", dst) | ||
105 | - .set("params", linkParams(src, dst, node, annot)); | ||
106 | - return result; | ||
107 | - } | ||
108 | - | ||
109 | - private String linkType(ObjectNode annot) { | ||
110 | - return annot.path("optical.type").asText("cross-connect").equals("WDM") ? | ||
111 | - "wdmLink" : "pktOptLink"; | ||
112 | - } | ||
113 | - | ||
114 | - private ObjectNode linkParams(String src, String dst, | ||
115 | - ObjectNode node, ObjectNode annot) { | ||
116 | - ObjectNode result = mapper.createObjectNode() | ||
117 | - .put("nodeName1", dpidToName.get(src)) | ||
118 | - .put("nodeName2", dpidToName.get(dst)) | ||
119 | - .put("port1", port(node.path("src"))) | ||
120 | - .put("port2", port(node.path("dst"))); | ||
121 | - if (annot.has("bandwidth")) { | ||
122 | - result.put("bandwidth", annot.path("bandwidth").asInt()); | ||
123 | - } | ||
124 | - if (annot.has("optical.waves")) { | ||
125 | - result.put("numWaves", annot.path("optical.waves").asInt()); | ||
126 | - } | ||
127 | - return result; | ||
128 | - } | ||
129 | - | ||
130 | - private String dpid(JsonNode node) { | ||
131 | - String s = node.asText("of:0000000000000000").substring(3); | ||
132 | - return s.substring(0, 2) + ":" + s.substring(2, 4) + ":" + | ||
133 | - s.substring(4, 6) + ":" + s.substring(6, 8) + ":" + | ||
134 | - s.substring(8, 10) + ":" + s.substring(10, 12) + ":" + | ||
135 | - s.substring(12, 14) + ":" + s.substring(14, 16); | ||
136 | - } | ||
137 | - | ||
138 | - private int port(JsonNode node) { | ||
139 | - return Integer.parseInt(node.asText("of:0000000000000000/0").substring(20)); | ||
140 | - } | ||
141 | - | ||
142 | -} |
... | @@ -40,7 +40,6 @@ | ... | @@ -40,7 +40,6 @@ |
40 | <module>sdnip</module> | 40 | <module>sdnip</module> |
41 | <module>optical</module> | 41 | <module>optical</module> |
42 | <module>metrics</module> | 42 | <module>metrics</module> |
43 | - <module>oecfg</module> | ||
44 | <module>routing</module> | 43 | <module>routing</module> |
45 | <module>routing-api</module> | 44 | <module>routing-api</module> |
46 | <module>reactive-routing</module> | 45 | <module>reactive-routing</module> | ... | ... |
... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
4 | Notes: | 4 | Notes: |
5 | 5 | ||
6 | This file contains classes and methods useful for integrating LincOE with Mininet, | 6 | This file contains classes and methods useful for integrating LincOE with Mininet, |
7 | -such as startOE, stopOE, LINCLink, and OpticalSwitch | 7 | +such as startOE, stopOE, OpticalLink, and OpticalSwitch |
8 | 8 | ||
9 | - $ONOS_ROOT ust be set | 9 | - $ONOS_ROOT ust be set |
10 | - Need to run with sudo -E to preserve ONOS_ROOT env var | 10 | - Need to run with sudo -E to preserve ONOS_ROOT env var |
... | @@ -22,10 +22,10 @@ such as startOE, stopOE, LINCLink, and OpticalSwitch | ... | @@ -22,10 +22,10 @@ such as startOE, stopOE, LINCLink, and OpticalSwitch |
22 | 22 | ||
23 | Usage: | 23 | Usage: |
24 | ------------ | 24 | ------------ |
25 | - - import LINCLink and OpticalSwitch from this module | 25 | + - import OpticalLink and OpticalSwitch from this module |
26 | - import startOE and stopOE from this module | 26 | - import startOE and stopOE from this module |
27 | - create topology as you would a normal topology. when | 27 | - create topology as you would a normal topology. when |
28 | - to an optical switch with topo.addLink, always specify cls=LINCLink | 28 | + to an optical switch with topo.addLink, always specify cls=OpticalLink |
29 | - when creating an optical switch, use cls=OpticalSwitch in topo.addSwitch | 29 | - 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 | 30 | - for annotations on links and switches, a dictionary must be passed in as |
31 | the annotations argument | 31 | the annotations argument |
... | @@ -51,12 +51,11 @@ switches have been started, the new Mininet start() method should also push the | ... | @@ -51,12 +51,11 @@ switches have been started, the new Mininet start() method should also push the |
51 | Topology configuration file to ONOS. | 51 | Topology configuration file to ONOS. |
52 | 52 | ||
53 | ''' | 53 | ''' |
54 | -import sys | 54 | + |
55 | import re | 55 | import re |
56 | import json | 56 | import json |
57 | import os | 57 | import os |
58 | from time import sleep | 58 | from time import sleep |
59 | -import urllib2 | ||
60 | 59 | ||
61 | from mininet.node import Switch, RemoteController | 60 | from mininet.node import Switch, RemoteController |
62 | from mininet.topo import Topo | 61 | from mininet.topo import Topo |
... | @@ -66,127 +65,25 @@ from mininet.log import setLogLevel, info, error, warn | ... | @@ -66,127 +65,25 @@ from mininet.log import setLogLevel, info, error, warn |
66 | from mininet.link import Link, Intf | 65 | from mininet.link import Link, Intf |
67 | from mininet.cli import CLI | 66 | from mininet.cli import CLI |
68 | 67 | ||
69 | -# Sleep time and timeout values in seconds | 68 | +class OpticalSwitch( Switch ): |
70 | -SLEEP_TIME = 2 | 69 | + |
71 | -TIMEOUT = 60 | 70 | + def __init__( self, name, dpid=None, allowed=True, |
72 | - | 71 | + switchType='ROADM', annotations={}, **params ): |
73 | -class OpticalSwitch(Switch): | ||
74 | - """ | ||
75 | - For now, same as Switch class. | ||
76 | - """ | ||
77 | - pass | ||
78 | - | ||
79 | -class OpticalIntf(Intf): | ||
80 | - """ | ||
81 | - For now,same as Intf class. | ||
82 | - """ | ||
83 | - pass | ||
84 | - | ||
85 | -class OpticalLink(Link): | ||
86 | - """ | ||
87 | - For now, same as Link. | ||
88 | - """ | ||
89 | - pass | ||
90 | - | ||
91 | -class 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): | ||
164 | params[ 'inNamespace' ] = False | 72 | params[ 'inNamespace' ] = False |
165 | - Switch.__init__(self, name, dpid=dpid, **params) | 73 | + Switch.__init__( self, name, dpid=dpid, **params ) |
166 | self.name = name | 74 | self.name = name |
167 | self.annotations = annotations | 75 | self.annotations = annotations |
168 | self.allowed = allowed | 76 | self.allowed = allowed |
169 | self.switchType = switchType | 77 | self.switchType = switchType |
170 | - self.configDict = {} # dictionary that holds all of the JSON configuration data | 78 | + self.configDict = {} # dictionary that holds all of the JSON configuration data |
171 | - self.crossConnects = [] | 79 | + |
172 | - self.deletedCrossConnects = [] | 80 | + def start( self, *opts, **params ): |
173 | - self.controller = controller | ||
174 | - self.lincId = self._get_linc_id() # use to communicate with LINC | ||
175 | - self.lincStarted = False | ||
176 | - | ||
177 | - def start(self, *opts, **params): | ||
178 | '''Instead of starting a virtual switch, we build the JSON | 81 | '''Instead of starting a virtual switch, we build the JSON |
179 | dictionary for the emulated optical switch''' | 82 | dictionary for the emulated optical switch''' |
180 | - # 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() | ||
186 | self.configDict[ 'uri' ] = 'of:' + self.dpid | 83 | self.configDict[ 'uri' ] = 'of:' + self.dpid |
187 | self.configDict[ 'annotations' ] = self.annotations | 84 | self.configDict[ 'annotations' ] = self.annotations |
188 | - self.configDict[ 'annotations' ].setdefault('name', self.name) | 85 | + self.configDict[ 'annotations' ].setdefault( 'name', self.name ) |
189 | - self.configDict[ 'hw' ] = 'LINC-OE' | 86 | + self.configDict[ 'hw' ] = 'OE' |
190 | self.configDict[ 'mfr' ] = 'Linc' | 87 | self.configDict[ 'mfr' ] = 'Linc' |
191 | self.configDict[ 'mac' ] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1] | 88 | self.configDict[ 'mac' ] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1] |
192 | self.configDict[ 'type' ] = self.switchType | 89 | self.configDict[ 'type' ] = self.switchType |
... | @@ -195,441 +92,74 @@ class LINCSwitch(OpticalSwitch): | ... | @@ -195,441 +92,74 @@ class LINCSwitch(OpticalSwitch): |
195 | if intf.name == 'lo': | 92 | if intf.name == 'lo': |
196 | continue | 93 | continue |
197 | else: | 94 | else: |
198 | - self.configDict[ 'ports' ].append(intf.json()) | 95 | + self.configDict[ 'ports' ].append( intf.json() ) |
199 | - self.lincStarted = True | ||
200 | - | ||
201 | - def stop(self, deleteIntfs=False): | ||
202 | - ''' | ||
203 | - stop the existing switch | ||
204 | - ''' | ||
205 | - # TODO:Add support for deleteIntf | ||
206 | - self.stop_oe() | ||
207 | - | ||
208 | - def dpctl( self, *args ): | ||
209 | - "Run dpctl command: ignore for now" | ||
210 | - pass | ||
211 | - | ||
212 | - 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() | ||
225 | - | ||
226 | - 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 | - | ||
422 | - info('*** Waiting for all devices to be available in ONOS...\n') | ||
423 | - url = 'http://%s:8181/onos/v1/devices' % LINCSwitch.controllers[0].ip | ||
424 | - time = 0 | ||
425 | - while True: | ||
426 | - response = json.load(urllib2.urlopen(url)) | ||
427 | - devs = response.get('devices') | ||
428 | - | ||
429 | - # Wait for all devices to be registered | ||
430 | - if (len(devices) != len(devs)): | ||
431 | - continue | ||
432 | 96 | ||
433 | - # Wait for all devices to available | ||
434 | - available = True | ||
435 | - for d in devs: | ||
436 | - available &= d['available'] | ||
437 | - if available: | ||
438 | - 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 | - | ||
447 | - info('*** Pushing Topology.json to ONOS\n') | ||
448 | - 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) | ||
454 | - | ||
455 | - @staticmethod | ||
456 | - def waitStarted(net, timeout=TIMEOUT): | ||
457 | - "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: | ||
469 | - if time >= TIMEOUT: | ||
470 | - error('***ERROR: LINC OE did not start within %s seconds\n' % TIMEOUT) | ||
471 | - return False | ||
472 | - time += SLEEP_TIME | ||
473 | - sleep(SLEEP_TIME) | ||
474 | - | ||
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 | 97 | ||
551 | - for intfLine in intfLines: | 98 | + def json( self ): |
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" | 99 | "return json configuration dictionary for switch" |
557 | return self.configDict | 100 | return self.configDict |
558 | - | 101 | + |
559 | - def terminate(self): | 102 | + def terminate( self ): |
560 | pass | 103 | pass |
561 | 104 | ||
562 | -class LINCLink(Link): | 105 | +class OpticalLink( Link ): |
563 | - """ | 106 | + |
564 | - LINC link class | 107 | + def __init__( self, node1, node2, port1=None, port2=None, allowed=True, |
565 | - """ | ||
566 | - def __init__(self, node1, node2, port1=None, port2=None, allowed=True, | ||
567 | intfName1=None, intfName2=None, linkType='OPTICAL', | 108 | intfName1=None, intfName2=None, linkType='OPTICAL', |
568 | - annotations={}, speed1=0, speed2=0, **params): | 109 | + annotations={}, speed1=0, speed2=0, **params ): |
569 | "Creates a dummy link without a virtual ethernet pair." | 110 | "Creates a dummy link without a virtual ethernet pair." |
570 | self.allowed = allowed | 111 | self.allowed = allowed |
571 | self.annotations = annotations | 112 | self.annotations = annotations |
572 | self.linkType = linkType | 113 | self.linkType = linkType |
573 | - self.port1 = port1 | ||
574 | - self.port2 = port2 | ||
575 | params1 = { 'speed': speed1 } | 114 | params1 = { 'speed': speed1 } |
576 | params2 = { 'speed': speed2 } | 115 | params2 = { 'speed': speed2 } |
577 | - # self.isCrossConnect = True if self.annotations.get('optical.type') == 'cross-connect' else False | 116 | + |
578 | - if isinstance(node1, LINCSwitch) and isinstance(node2, LINCSwitch): | 117 | + if isinstance( node1, OpticalSwitch ): |
579 | - self.isCrossConnect = False | 118 | + cls1 = OpticalIntf |
580 | - else: | ||
581 | - self.isCrossConnect = True | ||
582 | - if isinstance(node1, LINCSwitch): | ||
583 | - cls1 = LINCIntf | ||
584 | - if self.isCrossConnect: | ||
585 | - node1.crossConnects.append(self) | ||
586 | else: | 119 | else: |
587 | cls1 = Intf | 120 | cls1 = Intf |
588 | # bad hack to stop error message from appearing when we try to set up intf in a packet switch, | 121 | # 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 | 122 | # and there is no interface there( because we do not run makeIntfPair ). This way, we just set lo up |
590 | intfName1 = 'lo' | 123 | intfName1 = 'lo' |
591 | - if isinstance(node2, LINCSwitch): | 124 | + if isinstance( node2, OpticalSwitch ): |
592 | - cls2 = LINCIntf | 125 | + cls2 = OpticalIntf |
593 | - if self.isCrossConnect: | ||
594 | - node2.crossConnects.append(self) | ||
595 | else: | 126 | else: |
596 | cls2 = Intf | 127 | cls2 = Intf |
597 | intfName2 = 'lo' | 128 | intfName2 = 'lo' |
598 | - Link.__init__(self, node1, node2, port1=port1, port2=port2, | 129 | + Link.__init__( self, node1, node2, port1=port1, port2=port2, |
599 | intfName1=intfName1, intfName2=intfName2, cls1=cls1, | 130 | intfName1=intfName1, intfName2=intfName2, cls1=cls1, |
600 | - cls2=cls2, params1=params1, params2=params2) | 131 | + cls2=cls2, params1=params1, params2=params2 ) |
132 | + | ||
601 | 133 | ||
602 | @classmethod | 134 | @classmethod |
603 | - def makeIntfPair(_cls, intfName1, intfName2, *args, **kwargs): | 135 | + def makeIntfPair( _cls, intfName1, intfName2, *args, **kwargs ): |
604 | pass | 136 | pass |
605 | 137 | ||
606 | - def json(self): | 138 | + def json( self ): |
607 | "build and return the json configuration dictionary for this link" | 139 | "build and return the json configuration dictionary for this link" |
608 | configData = {} | 140 | configData = {} |
609 | - configData[ 'src' ] = ('of:' + self.intf1.node.dpid + | 141 | + configData[ 'src' ] = ( 'of:' + self.intf1.node.dpid + |
610 | - '/%s' % self.intf1.node.ports[ self.intf1 ]) | 142 | + '/%s' % self.intf1.node.ports[ self.intf1 ] ) |
611 | - configData[ 'dst' ] = ('of:' + self.intf2.node.dpid + | 143 | + configData[ 'dst' ] = ( 'of:' + self.intf2.node.dpid + |
612 | - '/%s' % self.intf2.node.ports[ self.intf2 ]) | 144 | + '/%s' % self.intf2.node.ports[ self.intf2 ] ) |
613 | configData[ 'type' ] = self.linkType | 145 | configData[ 'type' ] = self.linkType |
614 | configData[ 'annotations' ] = self.annotations | 146 | configData[ 'annotations' ] = self.annotations |
615 | return configData | 147 | return configData |
616 | 148 | ||
617 | -class LINCIntf(OpticalIntf): | 149 | +class OpticalIntf( Intf ): |
618 | - """ | 150 | + |
619 | - LINC interface class | 151 | + def __init__( self, name=None, node=None, speed=0, |
620 | - """ | 152 | + port=None, link=None, **params ): |
621 | - def __init__(self, name=None, node=None, speed=0, | ||
622 | - port=None, link=None, **params): | ||
623 | self.node = node | 153 | self.node = node |
624 | self.speed = speed | 154 | self.speed = speed |
625 | self.port = port | 155 | self.port = port |
626 | self.link = link | 156 | self.link = link |
627 | self.name = name | 157 | self.name = name |
628 | - node.addIntf(self, port=port) | 158 | + node.addIntf( self, port=port ) |
629 | self.params = params | 159 | self.params = params |
630 | self.ip = None | 160 | self.ip = None |
631 | 161 | ||
632 | - def json(self): | 162 | + def json( self ): |
633 | "build and return the JSON information for this interface( not used right now )" | 163 | "build and return the JSON information for this interface( not used right now )" |
634 | configDict = {} | 164 | configDict = {} |
635 | configDict[ 'port' ] = self.port | 165 | configDict[ 'port' ] = self.port |
... | @@ -637,34 +167,356 @@ class LINCIntf(OpticalIntf): | ... | @@ -637,34 +167,356 @@ class LINCIntf(OpticalIntf): |
637 | configDict[ 'type' ] = 'FIBER' | 167 | configDict[ 'type' ] = 'FIBER' |
638 | return configDict | 168 | return configDict |
639 | 169 | ||
640 | - def config(self, *args, **kwargs): | 170 | + def config( self, *args, **kwargs ): |
641 | "dont configure a dummy interface" | 171 | "dont configure a dummy interface" |
642 | pass | 172 | pass |
643 | 173 | ||
644 | - def ifconfig(self, status): | 174 | +def switchJSON( switch ): |
645 | - "configure the status" | 175 | + "Returns the json configuration for a packet switch" |
646 | - if status == "up": | 176 | + configDict = {} |
647 | - return self.node.w_port_up(self.port) | 177 | + configDict[ 'uri' ] = 'of:' + switch.dpid |
648 | - elif status == "down": | 178 | + configDict[ 'mac' ] = quietRun( 'cat /sys/class/net/%s/address' % switch.name ).strip( '\n' ).translate( None, ':' ) |
649 | - return self.node.w_port_down(self.port) | 179 | + configDict[ 'hw' ] = 'PK' # FIXME what about OVS? |
180 | + configDict[ 'mfr' ] = 'Linc' # FIXME what about OVS? | ||
181 | + configDict[ 'type' ] = 'SWITCH' # FIXME what about OVS? | ||
182 | + annotations = switch.params.get( 'annotations', {} ) | ||
183 | + annotations.setdefault( 'name', switch.name ) | ||
184 | + configDict[ 'annotations' ] = annotations | ||
185 | + ports = [] | ||
186 | + for port, intf in switch.intfs.items(): | ||
187 | + if intf.name == 'lo': | ||
188 | + continue | ||
189 | + portDict = {} | ||
190 | + portDict[ 'port' ] = port | ||
191 | + portDict[ 'type' ] = 'FIBER' if isinstance( intf.link, OpticalLink ) else 'COPPER' | ||
192 | + intfList = [ intf.link.intf1, intf.link.intf2 ] | ||
193 | + intfList.remove( intf ) | ||
194 | + portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance( intf.link, OpticalLink ) else 0 | ||
195 | + ports.append( portDict ) | ||
196 | + configDict[ 'ports' ] = ports | ||
197 | + return configDict | ||
198 | + | ||
199 | + | ||
200 | +def startOE( net ): | ||
201 | + "Start the LINC optical emulator within a mininet instance" | ||
202 | + opticalJSON = {} | ||
203 | + linkConfig = [] | ||
204 | + devices = [] | ||
205 | + | ||
206 | + for switch in net.switches: | ||
207 | + if isinstance( switch, OpticalSwitch ): | ||
208 | + devices.append( switch.json() ) | ||
209 | + else: | ||
210 | + devices.append( switchJSON( switch ) ) | ||
211 | + opticalJSON[ 'devices' ] = devices | ||
212 | + | ||
213 | + for link in net.links: | ||
214 | + if isinstance( link, OpticalLink ) : | ||
215 | + linkConfig.append( link.json() ) | ||
216 | + | ||
217 | + opticalJSON[ 'links' ] = linkConfig | ||
218 | + | ||
219 | + try: | ||
220 | + onosDir = os.environ[ 'ONOS_ROOT' ] | ||
221 | + except: | ||
222 | + onosDir = findDir( 'onos' ) | ||
223 | + if not onosDir: | ||
224 | + error( 'Please set ONOS_ROOT environment variable!\n' ) | ||
225 | + return False | ||
226 | + else: | ||
227 | + os.environ[ 'ONOS_ROOT' ] = onosDir | ||
228 | + | ||
229 | + info( '*** Writing Topology.json file\n' ) | ||
230 | + with open( 'Topology.json', 'w' ) as outfile: | ||
231 | + json.dump( opticalJSON, outfile, indent=4, separators=(',', ': ') ) | ||
232 | + | ||
233 | + info( '*** Converting Topology.json to linc-oe format (TopoConfig.json) file (not using oecfg) \n' ) | ||
234 | + | ||
235 | + topoConfigJson = {}; | ||
236 | + newLinkConfig = []; | ||
237 | + switchConfig = []; | ||
238 | + dpIdToName = {}; | ||
239 | + | ||
240 | + #Iterate through all switches and convert the ROADM switches to linc-oe format | ||
241 | + for switch in opticalJSON["devices"]: | ||
242 | + if switch["type"] == "ROADM": | ||
243 | + builtSwitch = {} | ||
244 | + | ||
245 | + #set basic switch params based on annotations | ||
246 | + builtSwitch["allowed"] = True; | ||
247 | + builtSwitch["latitude"] = switch["annotations"]["latitude"]; | ||
248 | + builtSwitch["longitude"] = switch["annotations"]["longitude"]; | ||
249 | + | ||
250 | + nodeId = switch["uri"] | ||
251 | + | ||
252 | + #convert the nodeId to linc-oe format | ||
253 | + nodeDpid = dpId(nodeId); | ||
254 | + | ||
255 | + if "name" in switch: | ||
256 | + builtSwitch["name"] = switch["name"] | ||
257 | + else: | ||
258 | + builtSwitch["name"] = "none" | ||
259 | + | ||
260 | + #keep track of the name corresponding to each switch dpid | ||
261 | + dpIdToName[nodeDpid] = builtSwitch["name"]; | ||
262 | + | ||
263 | + builtSwitch["nodeDpid"] = nodeDpid | ||
264 | + | ||
265 | + #set switch params and type | ||
266 | + builtSwitch["params"] = {}; | ||
267 | + builtSwitch["params"]["numregens"] = switch["annotations"]["optical.regens"]; | ||
268 | + builtSwitch["type"] = "Roadm" | ||
650 | 269 | ||
270 | + #append to list of switches | ||
271 | + switchConfig.append(builtSwitch); | ||
651 | 272 | ||
652 | -class MininetOE(Mininet): | 273 | + topoConfigJson["switchConfig"] = switchConfig; |
274 | + | ||
275 | + #Iterate through all optical links and convert them to linc-oe format | ||
276 | + for link in opticalJSON["links"]: | ||
277 | + if link["type"] == "OPTICAL": | ||
278 | + builtLink = {} | ||
279 | + | ||
280 | + #set basic link params for src and dst | ||
281 | + builtLink["allowed"] = True; | ||
282 | + builtLink["nodeDpid1"] = dpId(link["src"]) | ||
283 | + builtLink["nodeDpid2"] = dpId(link["dst"]) | ||
284 | + | ||
285 | + #set more params such as name/bandwidth/port/waves if they exist | ||
286 | + params = {} | ||
287 | + params["nodeName1"] = dpIdToName.get(builtLink["nodeDpid1"], "none") | ||
288 | + params["nodeName2"] = dpIdToName.get(builtLink["nodeDpid2"], "none") | ||
289 | + if "bandwidth" in link["annotations"]: | ||
290 | + params["bandwidth"] = link["annotations"]["bandwidth"] | ||
291 | + params["port1"] = int(link["src"].split("/")[1]) | ||
292 | + params["port2"] = int(link["dst"].split("/")[1]) | ||
293 | + | ||
294 | + if "optical.waves" in link["annotations"]: | ||
295 | + params["numWaves"] = link["annotations"]["optical.waves"] | ||
296 | + builtLink["params"] = params | ||
297 | + | ||
298 | + #set type of link (WDM or pktOpt) | ||
299 | + if link["annotations"]["optical.type"] == "WDM": | ||
300 | + builtLink["type"] = "wdmLink" | ||
301 | + else: | ||
302 | + builtLink["type"] = "pktOptLink" | ||
303 | + | ||
304 | + newLinkConfig.append(builtLink); | ||
305 | + | ||
306 | + topoConfigJson["linkConfig"] = newLinkConfig; | ||
307 | + | ||
308 | + #Writing to TopoConfig.json | ||
309 | + with open( 'TopoConfig.json', 'w' ) as outfile: | ||
310 | + json.dump( topoConfigJson, outfile, indent=4, separators=(',', ': ') ) | ||
311 | + | ||
312 | + info( '*** Creating sys.config...\n' ) | ||
313 | + configGen = findDir( 'LINC-config-generator' ) | ||
314 | + if not configGen: | ||
315 | + error( "***ERROR: Could not find LINC-config-generator in user's home directory\n" ) | ||
316 | + return False | ||
317 | + output = quietRun( '%s/config_generator TopoConfig.json %s/sys.config.template %s %s' | ||
318 | + % ( configGen, configGen, net.controllers[ 0 ].ip, net.controllers[ 0 ].port ), shell=True ) | ||
319 | + if output: | ||
320 | + error( '***ERROR: Error creating sys.config file: %s\n' % output ) | ||
321 | + return False | ||
322 | + | ||
323 | + info ('*** Setting multiple controllers in sys.config...\n' ) | ||
324 | + searchStr = '{controllers,.*$' | ||
325 | + ctrlStr = '' | ||
326 | + for index in range(len(net.controllers)): | ||
327 | + ctrlStr += '{"Switch%d-Controller","%s",%d,tcp},' % (index, net.controllers[index].ip, net.controllers[index].port) | ||
328 | + replaceStr = '{controllers,[%s]},' % ctrlStr[:-1] # Cut off last comma | ||
329 | + sedCmd = 'sed -i \'s/%s/%s/\' sys.config' % (searchStr, replaceStr) | ||
330 | + output = quietRun( sedCmd, shell=True ) | ||
331 | + | ||
332 | + info( '*** Copying sys.config to linc-oe directory: ', output + '\n' ) | ||
333 | + lincDir = findDir( 'linc-oe' ) | ||
334 | + if not lincDir: | ||
335 | + error( "***ERROR: Could not find linc-oe in user's home directory\n" ) | ||
336 | + return False | ||
337 | + output = quietRun( 'cp -v sys.config %s/rel/linc/releases/1.0/' % lincDir, shell=True ).strip( '\n' ) | ||
338 | + info( output + '\n' ) | ||
339 | + | ||
340 | + info( '*** Starting linc OE...\n' ) | ||
341 | + output = quietRun( '%s/rel/linc/bin/linc start' % lincDir, shell=True ) | ||
342 | + if output: | ||
343 | + error( '***ERROR: LINC-OE: %s' % output + '\n' ) | ||
344 | + quietRun( '%s/rel/linc/bin/linc stop' % lincDir, shell=True ) | ||
345 | + return False | ||
346 | + | ||
347 | + info( '*** Waiting for linc-oe to start...\n' ) | ||
348 | + waitStarted( net ) | ||
349 | + | ||
350 | + info( '*** Adding cross-connect (tap) interfaces to packet switches...\n' ) | ||
351 | + for link in net.links: | ||
352 | + if isinstance( link, OpticalLink ): | ||
353 | + if link.annotations[ 'optical.type' ] == 'cross-connect': | ||
354 | + for intf in [ link.intf1, link.intf2 ]: | ||
355 | + if not isinstance( intf, OpticalIntf ): | ||
356 | + intfList = [ intf.link.intf1, intf.link.intf2 ] | ||
357 | + intfList.remove( intf ) | ||
358 | + intf2 = intfList[ 0 ] | ||
359 | + intf.node.attach( findTap( intf2.node, intf2.node.ports[ intf2 ] ) ) | ||
360 | + | ||
361 | + info( '*** Press ENTER to push Topology.json to onos...\n' ) | ||
362 | + raw_input() # FIXME... we should eventually remove this | ||
363 | + info( '*** Pushing Topology.json to ONOS\n' ) | ||
364 | + output = quietRun( '%s/tools/test/bin/onos-topo-cfg %s Topology.json' % ( onosDir, net.controllers[ 0 ].ip ), shell=True ) | ||
365 | + # successful output contains the two characters '{}' | ||
366 | + # if there is more output than this, there is an issue | ||
367 | + if output.strip( '{}' ): | ||
368 | + warn( '***WARNING: Could not push topology file to ONOS: %s' % output ) | ||
369 | + | ||
370 | +#converts node ids to linc-oe format, with colons every two chars | ||
371 | +def dpId(id): | ||
372 | + nodeDpid = "" | ||
373 | + id = id.split("/", 1)[0] | ||
374 | + for i in range(3, len(id) - 1, 2): | ||
375 | + nodeDpid += (id[i:(i + 2):]) + ":" | ||
376 | + return nodeDpid[0:(len(nodeDpid) - 1)]; | ||
377 | + | ||
378 | +def waitStarted( net, timeout=None ): | ||
379 | + "wait until all tap interfaces are available" | ||
380 | + tapCount = 0 | ||
381 | + time = 0 | ||
382 | + for link in net.links: | ||
383 | + if isinstance( link, OpticalLink ): | ||
384 | + if link.annotations[ 'optical.type' ] == 'cross-connect': | ||
385 | + tapCount += 1 | ||
386 | + | ||
387 | + while True: | ||
388 | + if str( tapCount ) == quietRun( 'ip addr | grep tap | wc -l', shell=True ).strip( '\n' ): | ||
389 | + return True | ||
390 | + if timeout: | ||
391 | + if time >= timeout: | ||
392 | + error( '***ERROR: Linc OE did not start within %s seconds' % timeout ) | ||
393 | + return False | ||
394 | + time += .5 | ||
395 | + sleep( .5 ) | ||
396 | + | ||
397 | +def stopOE(): | ||
398 | + "stop the optical emulator" | ||
399 | + info( '*** Stopping linc OE...\n' ) | ||
400 | + lincDir = findDir( 'linc-oe' ) | ||
401 | + quietRun( '%s/rel/linc/bin/linc stop' % lincDir, shell=True ) | ||
402 | + | ||
403 | +def findDir( directory ): | ||
404 | + "finds and returns the path of any directory in the user's home directory" | ||
405 | + user = findUser() | ||
406 | + homeDir = '/home/' + user | ||
407 | + Dir = quietRun( 'find %s -maxdepth 1 -name %s -type d' % ( homeDir, directory ) ).strip( '\n' ) | ||
408 | + DirList = Dir.split( '\n' ) | ||
409 | + if not Dir: | ||
410 | + return None | ||
411 | + elif len( DirList ) > 1 : | ||
412 | + warn( '***WARNING: Found multiple instances of %s; using %s\n' | ||
413 | + % ( directory, DirList[ 0 ] ) ) | ||
414 | + return DirList[ 0 ] | ||
415 | + else: | ||
416 | + return Dir | ||
417 | + | ||
418 | +def findUser(): | ||
419 | + "Try to return logged-in (usually non-root) user" | ||
420 | + try: | ||
421 | + # If we're running sudo | ||
422 | + return os.environ[ 'SUDO_USER' ] | ||
423 | + except: | ||
424 | + try: | ||
425 | + # Logged-in user (if we have a tty) | ||
426 | + return quietRun( 'who am i' ).split()[ 0 ] | ||
427 | + except: | ||
428 | + # Give up and return effective user | ||
429 | + return quietRun( 'whoami' ) | ||
430 | + | ||
431 | + | ||
432 | +def findTap( node, port, path=None ): | ||
433 | + '''utility function to parse through a sys.config | ||
434 | + file to find tap interfaces for a switch''' | ||
435 | + switch=False | ||
436 | + portLine = '' | ||
437 | + intfLines = [] | ||
438 | + | ||
439 | + if path is None: | ||
440 | + lincDir = findDir( 'linc-oe' ) | ||
441 | + if not lincDir: | ||
442 | + error( '***ERROR: Could not find linc-oe in users home directory\n' ) | ||
443 | + return None | ||
444 | + path = '%s/rel/linc/releases/1.0/sys.config' % lincDir | ||
445 | + | ||
446 | + with open( path ) as f: | ||
447 | + for line in f: | ||
448 | + if 'tap' in line: | ||
449 | + intfLines.append( line ) | ||
450 | + if node.dpid in line.translate( None, ':' ): | ||
451 | + switch=True | ||
452 | + continue | ||
453 | + if switch: | ||
454 | + if 'switch' in line: | ||
455 | + switch = False | ||
456 | + if 'port_no,%s}' % port in line: | ||
457 | + portLine = line | ||
458 | + break | ||
459 | + | ||
460 | + if portLine: | ||
461 | + m = re.search( 'port,\d+', portLine ) | ||
462 | + port = m.group( 0 ).split( ',' )[ 1 ] | ||
463 | + else: | ||
464 | + error( '***ERROR: Could not find any ports in sys.config\n' ) | ||
465 | + return | ||
466 | + | ||
467 | + for intfLine in intfLines: | ||
468 | + if 'port,%s' % port in intfLine: | ||
469 | + return re.findall( 'tap\d+', intfLine )[ 0 ] | ||
470 | + | ||
471 | + | ||
472 | +class MininetOE( Mininet ): | ||
653 | "Mininet with Linc-OE support (starts and stops linc-oe)" | 473 | "Mininet with Linc-OE support (starts and stops linc-oe)" |
654 | 474 | ||
655 | - def start(self): | 475 | + def start( self ): |
656 | - Mininet.start(self) | 476 | + Mininet.start( self ) |
657 | - LINCSwitch.bootOE(self) | 477 | + startOE( self ) |
658 | 478 | ||
659 | - def stop(self): | 479 | + def stop( self ): |
660 | - Mininet.stop(self) | 480 | + Mininet.stop( self ) |
661 | - LINCSwitch.shutdownOE() | 481 | + stopOE() |
662 | 482 | ||
663 | - def addControllers(self, controllers): | 483 | + def addControllers( self, controllers ): |
664 | i = 0 | 484 | i = 0 |
665 | for ctrl in controllers: | 485 | for ctrl in controllers: |
666 | - self.addController(RemoteController('c%d' % i, ip=ctrl)) | 486 | + self.addController( RemoteController( 'c%d' % i, ip=ctrl ) ) |
667 | - i += 1 | 487 | + |
488 | + | ||
489 | +class OpticalTestTopo( Topo ): | ||
490 | + | ||
491 | + def build( self ): | ||
492 | + opticalAnn = { 'optical.waves': 80, 'optical.type': "WDM", 'durable': True } | ||
493 | + switchAnn = { 'bandwidth': 100000, 'optical.type': 'cross-connect', 'durable': True } | ||
494 | + h1 = self.addHost( 'h1' ) | ||
495 | + h2 = self.addHost( 'h2' ) | ||
496 | + s1 = self.addSwitch( 's1' ) | ||
497 | + s2 = self.addSwitch( 's2' ) | ||
498 | + O4 = self.addSwitch( 'O4', cls=OpticalSwitch ) | ||
499 | + O5 = self.addSwitch( 'O5', cls=OpticalSwitch ) | ||
500 | + O6 = self.addSwitch( 'O6', cls=OpticalSwitch ) | ||
501 | + self.addLink( O4, O5, cls=OpticalLink, annotations=opticalAnn ) | ||
502 | + self.addLink( O5, O6, cls=OpticalLink, annotations=opticalAnn ) | ||
503 | + self.addLink( s1, O4, cls=OpticalLink, annotations=switchAnn ) | ||
504 | + self.addLink( s2, O6, cls=OpticalLink, annotations=switchAnn ) | ||
505 | + self.addLink( h1, s1 ) | ||
506 | + self.addLink( h2, s2 ) | ||
668 | 507 | ||
669 | if __name__ == '__main__': | 508 | if __name__ == '__main__': |
670 | - pass | 509 | + import sys |
510 | + if len( sys.argv ) >= 2: | ||
511 | + controllers = sys.argv[1:] | ||
512 | + else: | ||
513 | + print 'Usage: ./opticalUtils.py (<Controller IP>)+' | ||
514 | + print 'Using localhost...\n' | ||
515 | + controllers = [ '127.0.0.1' ] | ||
516 | + | ||
517 | + setLogLevel( 'info' ) | ||
518 | + net = MininetOE( topo=OpticalTestTopo(), controller=None, autoSetMacs=True ) | ||
519 | + net.addControllers( controllers ) | ||
520 | + net.start() | ||
521 | + CLI( net ) | ||
522 | + net.stop() | ... | ... |
-
Please register or login to post a comment