Committed by
Gerrit Code Review
Revert "OECF removed working"
This reverts commit 5f8f8f0c. Change-Id: I13207976c26fc210994c90e213349790a4227440
Showing
4 changed files
with
691 additions
and
327 deletions
apps/oecfg/pom.xml
0 → 100644
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 | +} |
... | @@ -41,6 +41,7 @@ | ... | @@ -41,6 +41,7 @@ |
41 | <module>sdnip</module> | 41 | <module>sdnip</module> |
42 | <module>optical</module> | 42 | <module>optical</module> |
43 | <module>metrics</module> | 43 | <module>metrics</module> |
44 | + <module>oecfg</module> | ||
44 | <module>routing</module> | 45 | <module>routing</module> |
45 | <module>routing-api</module> | 46 | <module>routing-api</module> |
46 | <module>reactive-routing</module> | 47 | <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, OpticalLink, and OpticalSwitch | 7 | +such as startOE, stopOE, LINCLink, 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, OpticalLink, and OpticalSwitch | ... | @@ -22,10 +22,10 @@ such as startOE, stopOE, OpticalLink, and OpticalSwitch |
22 | 22 | ||
23 | Usage: | 23 | Usage: |
24 | ------------ | 24 | ------------ |
25 | - - import OpticalLink and OpticalSwitch from this module | 25 | + - import LINCLink 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=OpticalLink | 28 | + to an optical switch with topo.addLink, always specify cls=LINCLink |
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,11 +51,12 @@ switches have been started, the new Mininet start() method should also push the | ... | @@ -51,11 +51,12 @@ 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 | - | 54 | +import sys |
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 | ||
59 | 60 | ||
60 | from mininet.node import Switch, RemoteController | 61 | from mininet.node import Switch, RemoteController |
61 | from mininet.topo import Topo | 62 | from mininet.topo import Topo |
... | @@ -65,25 +66,127 @@ from mininet.log import setLogLevel, info, error, warn | ... | @@ -65,25 +66,127 @@ from mininet.log import setLogLevel, info, error, warn |
65 | from mininet.link import Link, Intf | 66 | from mininet.link import Link, Intf |
66 | from mininet.cli import CLI | 67 | from mininet.cli import CLI |
67 | 68 | ||
68 | -class OpticalSwitch( Switch ): | 69 | +# Sleep time and timeout values in seconds |
70 | +SLEEP_TIME = 2 | ||
71 | +TIMEOUT = 60 | ||
72 | + | ||
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 | ||
69 | 90 | ||
70 | - def __init__( self, name, dpid=None, allowed=True, | 91 | +class LINCSwitch(OpticalSwitch): |
71 | - switchType='ROADM', annotations={}, **params ): | 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): | ||
72 | params[ 'inNamespace' ] = False | 164 | params[ 'inNamespace' ] = False |
73 | - Switch.__init__( self, name, dpid=dpid, **params ) | 165 | + Switch.__init__(self, name, dpid=dpid, **params) |
74 | self.name = name | 166 | self.name = name |
75 | self.annotations = annotations | 167 | self.annotations = annotations |
76 | self.allowed = allowed | 168 | self.allowed = allowed |
77 | self.switchType = switchType | 169 | self.switchType = switchType |
78 | self.configDict = {} # dictionary that holds all of the JSON configuration data | 170 | self.configDict = {} # dictionary that holds all of the JSON configuration data |
171 | + self.crossConnects = [] | ||
172 | + self.deletedCrossConnects = [] | ||
173 | + self.controller = controller | ||
174 | + self.lincId = self._get_linc_id() # use to communicate with LINC | ||
175 | + self.lincStarted = False | ||
79 | 176 | ||
80 | - def start( self, *opts, **params ): | 177 | + def start(self, *opts, **params): |
81 | '''Instead of starting a virtual switch, we build the JSON | 178 | '''Instead of starting a virtual switch, we build the JSON |
82 | dictionary for the emulated optical switch''' | 179 | 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() | ||
83 | self.configDict[ 'uri' ] = 'of:' + self.dpid | 186 | self.configDict[ 'uri' ] = 'of:' + self.dpid |
84 | self.configDict[ 'annotations' ] = self.annotations | 187 | self.configDict[ 'annotations' ] = self.annotations |
85 | - self.configDict[ 'annotations' ].setdefault( 'name', self.name ) | 188 | + self.configDict[ 'annotations' ].setdefault('name', self.name) |
86 | - self.configDict[ 'hw' ] = 'OE' | 189 | + self.configDict[ 'hw' ] = 'LINC-OE' |
87 | self.configDict[ 'mfr' ] = 'Linc' | 190 | self.configDict[ 'mfr' ] = 'Linc' |
88 | self.configDict[ 'mac' ] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1] | 191 | self.configDict[ 'mac' ] = 'ffffffffffff' + self.dpid[-2] + self.dpid[-1] |
89 | self.configDict[ 'type' ] = self.switchType | 192 | self.configDict[ 'type' ] = self.switchType |
... | @@ -92,95 +195,137 @@ class OpticalSwitch( Switch ): | ... | @@ -92,95 +195,137 @@ class OpticalSwitch( Switch ): |
92 | if intf.name == 'lo': | 195 | if intf.name == 'lo': |
93 | continue | 196 | continue |
94 | else: | 197 | else: |
95 | - self.configDict[ 'ports' ].append( intf.json() ) | 198 | + self.configDict[ 'ports' ].append(intf.json()) |
96 | - | 199 | + self.lincStarted = True |
97 | - | 200 | + |
98 | - def json( self ): | 201 | + def stop(self, deleteIntfs=False): |
99 | - "return json configuration dictionary for switch" | 202 | + ''' |
100 | - return self.configDict | 203 | + stop the existing switch |
101 | - | 204 | + ''' |
102 | - def terminate( self ): | 205 | + # TODO:Add support for deleteIntf |
206 | + self.stop_oe() | ||
207 | + | ||
208 | + def dpctl( self, *args ): | ||
209 | + "Run dpctl command: ignore for now" | ||
103 | pass | 210 | pass |
104 | 211 | ||
105 | -class OpticalLink( Link ): | 212 | + def write_to_cli(self, command): |
106 | - | 213 | + ''' |
107 | - def __init__( self, node1, node2, port1=None, port2=None, allowed=True, | 214 | + send command to LINC |
108 | - intfName1=None, intfName2=None, linkType='OPTICAL', | 215 | + ''' |
109 | - annotations={}, speed1=0, speed2=0, **params ): | 216 | + fd = None |
110 | - "Creates a dummy link without a virtual ethernet pair." | 217 | + try: |
111 | - self.allowed = allowed | 218 | + fd = open(self.writePipe, 'w', 0) |
112 | - self.annotations = annotations | 219 | + fd.write(command) |
113 | - self.linkType = linkType | 220 | + fd.close() |
114 | - params1 = { 'speed': speed1 } | 221 | + except: |
115 | - params2 = { 'speed': speed2 } | 222 | + print "Error working with {}\nError: {}\n".format(self.writePipe, sys.exc_info()) |
116 | - | 223 | + if fd: |
117 | - if isinstance( node1, OpticalSwitch ): | 224 | + fd.close() |
118 | - cls1 = OpticalIntf | 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 | ||
119 | else: | 268 | else: |
120 | - cls1 = Intf | 269 | + intf = crossConnect.intf1 |
121 | - # bad hack to stop error message from appearing when we try to set up intf in a packet switch, | 270 | + tapPort = crossConnect.intf2.port |
122 | - # and there is no interface there( because we do not run makeIntfPair ). This way, we just set lo up | 271 | + tap = LINCSwitch.findTap(self, tapPort) |
123 | - intfName1 = 'lo' | 272 | + if tap: |
124 | - if isinstance( node2, OpticalSwitch ): | 273 | + LINCSwitch.setupInts([tap]) |
125 | - cls2 = OpticalIntf | 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 | ||
126 | else: | 297 | else: |
127 | - cls2 = Intf | 298 | + intf = crossConnect.intf1 |
128 | - intfName2 = 'lo' | 299 | + tapPort = crossConnect.intf2.port |
129 | - Link.__init__( self, node1, node2, port1=port1, port2=port2, | 300 | + intf.node.detach(LINCSwitch.findTap(self, tapPort)) |
130 | - intfName1=intfName1, intfName2=intfName2, cls1=cls1, | 301 | + self.deletedCrossConnects.append(crossConnect) |
131 | - cls2=cls2, params1=params1, params2=params2 ) | 302 | + |
132 | - | 303 | + def w_port_up(self, port): |
133 | - | 304 | + ''' |
134 | - @classmethod | 305 | + port_up |
135 | - def makeIntfPair( _cls, intfName1, intfName2, *args, **kwargs ): | 306 | + ''' |
136 | - pass | 307 | + cmd = "linc:port_up({},{}).\r\n".format(self.lincId, port) |
137 | - | 308 | + self.write_to_cli(cmd) |
138 | - def json( self ): | 309 | + |
139 | - "build and return the json configuration dictionary for this link" | 310 | + def w_port_down(self, port): |
140 | - configData = {} | 311 | + ''' |
141 | - configData[ 'src' ] = ( 'of:' + self.intf1.node.dpid + | 312 | + port_down |
142 | - '/%s' % self.intf1.node.ports[ self.intf1 ] ) | 313 | + ''' |
143 | - configData[ 'dst' ] = ( 'of:' + self.intf2.node.dpid + | 314 | + cmd = "linc:port_down({},{}).\r\n".format(self.lincId, port) |
144 | - '/%s' % self.intf2.node.ports[ self.intf2 ] ) | 315 | + self.write_to_cli(cmd) |
145 | - configData[ 'type' ] = self.linkType | 316 | + |
146 | - configData[ 'annotations' ] = self.annotations | 317 | + # helper functions |
147 | - return configData | 318 | + @staticmethod |
148 | - | 319 | + def switchJSON(switch): |
149 | -class OpticalIntf( Intf ): | ||
150 | - | ||
151 | - def __init__( self, name=None, node=None, speed=0, | ||
152 | - port=None, link=None, **params ): | ||
153 | - self.node = node | ||
154 | - self.speed = speed | ||
155 | - self.port = port | ||
156 | - self.link = link | ||
157 | - self.name = name | ||
158 | - node.addIntf( self, port=port ) | ||
159 | - self.params = params | ||
160 | - self.ip = None | ||
161 | - | ||
162 | - def json( self ): | ||
163 | - "build and return the JSON information for this interface( not used right now )" | ||
164 | - configDict = {} | ||
165 | - configDict[ 'port' ] = self.port | ||
166 | - configDict[ 'speed' ] = self.speed | ||
167 | - configDict[ 'type' ] = 'FIBER' | ||
168 | - return configDict | ||
169 | - | ||
170 | - def config( self, *args, **kwargs ): | ||
171 | - "dont configure a dummy interface" | ||
172 | - pass | ||
173 | - | ||
174 | -def switchJSON( switch ): | ||
175 | "Returns the json configuration for a packet switch" | 320 | "Returns the json configuration for a packet switch" |
176 | configDict = {} | 321 | configDict = {} |
177 | configDict[ 'uri' ] = 'of:' + switch.dpid | 322 | configDict[ 'uri' ] = 'of:' + switch.dpid |
178 | - configDict[ 'mac' ] = quietRun( 'cat /sys/class/net/%s/address' % switch.name ).strip( '\n' ).translate( None, ':' ) | 323 | + configDict[ 'mac' ] = quietRun('cat /sys/class/net/%s/address' % switch.name).strip('\n').translate(None, ':') |
179 | configDict[ 'hw' ] = 'PK' # FIXME what about OVS? | 324 | configDict[ 'hw' ] = 'PK' # FIXME what about OVS? |
180 | configDict[ 'mfr' ] = 'Linc' # FIXME what about OVS? | 325 | configDict[ 'mfr' ] = 'Linc' # FIXME what about OVS? |
181 | configDict[ 'type' ] = 'SWITCH' # FIXME what about OVS? | 326 | configDict[ 'type' ] = 'SWITCH' # FIXME what about OVS? |
182 | - annotations = switch.params.get( 'annotations', {} ) | 327 | + annotations = switch.params.get('annotations', {}) |
183 | - annotations.setdefault( 'name', switch.name ) | 328 | + annotations.setdefault('name', switch.name) |
184 | configDict[ 'annotations' ] = annotations | 329 | configDict[ 'annotations' ] = annotations |
185 | ports = [] | 330 | ports = [] |
186 | for port, intf in switch.intfs.items(): | 331 | for port, intf in switch.intfs.items(): |
... | @@ -188,234 +333,176 @@ def switchJSON( switch ): | ... | @@ -188,234 +333,176 @@ def switchJSON( switch ): |
188 | continue | 333 | continue |
189 | portDict = {} | 334 | portDict = {} |
190 | portDict[ 'port' ] = port | 335 | portDict[ 'port' ] = port |
191 | - portDict[ 'type' ] = 'FIBER' if isinstance( intf.link, OpticalLink ) else 'COPPER' | 336 | + portDict[ 'type' ] = 'FIBER' if isinstance(intf.link, LINCLink) else 'COPPER' |
192 | intfList = [ intf.link.intf1, intf.link.intf2 ] | 337 | intfList = [ intf.link.intf1, intf.link.intf2 ] |
193 | - intfList.remove( intf ) | 338 | + intfList.remove(intf) |
194 | - portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance( intf.link, OpticalLink ) else 0 | 339 | + portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance(intf.link, LINCLink) else 0 |
195 | - ports.append( portDict ) | 340 | + ports.append(portDict) |
196 | configDict[ 'ports' ] = ports | 341 | configDict[ 'ports' ] = ports |
197 | return configDict | 342 | return configDict |
198 | 343 | ||
199 | - | 344 | + @staticmethod |
200 | -def startOE( net ): | 345 | + def bootOE(net): |
201 | "Start the LINC optical emulator within a mininet instance" | 346 | "Start the LINC optical emulator within a mininet instance" |
202 | opticalJSON = {} | 347 | opticalJSON = {} |
203 | linkConfig = [] | 348 | linkConfig = [] |
204 | devices = [] | 349 | devices = [] |
350 | + #setting up the controllers for LINCSwitch class | ||
351 | + LINCSwitch.controllers = net.controllers | ||
205 | 352 | ||
206 | for switch in net.switches: | 353 | for switch in net.switches: |
207 | - if isinstance( switch, OpticalSwitch ): | 354 | + if isinstance(switch, OpticalSwitch): |
208 | - devices.append( switch.json() ) | 355 | + devices.append(switch.json()) |
209 | else: | 356 | else: |
210 | - devices.append( switchJSON( switch ) ) | 357 | + devices.append(LINCSwitch.switchJSON(switch)) |
211 | opticalJSON[ 'devices' ] = devices | 358 | opticalJSON[ 'devices' ] = devices |
212 | 359 | ||
213 | for link in net.links: | 360 | for link in net.links: |
214 | - if isinstance( link, OpticalLink ) : | 361 | + if isinstance(link, LINCLink) : |
215 | - linkConfig.append( link.json() ) | 362 | + linkConfig.append(link.json()) |
216 | - | ||
217 | opticalJSON[ 'links' ] = linkConfig | 363 | opticalJSON[ 'links' ] = linkConfig |
218 | 364 | ||
219 | - try: | 365 | + info('*** Writing Topology.json file\n') |
220 | - onosDir = os.environ[ 'ONOS_ROOT' ] | 366 | + with open('Topology.json', 'w') as outfile: |
221 | - except: | 367 | + json.dump(opticalJSON, outfile, indent=4, separators=(',', ': ')) |
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" | ||
269 | - | ||
270 | - #append to list of switches | ||
271 | - switchConfig.append(builtSwitch); | ||
272 | - | ||
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 | 368 | ||
308 | - #Writing to TopoConfig.json | 369 | + info('*** Converting Topology.json to linc-oe format (TopoConfig.json) file\n') |
309 | - with open( 'TopoConfig.json', 'w' ) as outfile: | 370 | + output = quietRun('%s/tools/test/bin/onos-oecfg ./Topology.json > TopoConfig.json' % LINCSwitch.onosDir, shell=True) |
310 | - json.dump( topoConfigJson, outfile, indent=4, separators=(',', ': ') ) | 371 | + if output: |
311 | - | 372 | + error('***ERROR: Error creating topology file: %s ' % output + '\n') |
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 | 373 | return False |
317 | - output = quietRun( '%s/config_generator TopoConfig.json %s/sys.config.template %s %s' | 374 | + |
318 | - % ( configGen, configGen, net.controllers[ 0 ].ip, net.controllers[ 0 ].port ), shell=True ) | 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) | ||
319 | if output: | 378 | if output: |
320 | - error( '***ERROR: Error creating sys.config file: %s\n' % output ) | 379 | + error('***ERROR: Error creating sys.config file: %s\n' % output) |
321 | return False | 380 | return False |
322 | 381 | ||
323 | - info ('*** Setting multiple controllers in sys.config...\n' ) | 382 | + info ('*** Setting multiple controllers in sys.config...\n') |
324 | - searchStr = '{controllers,.*$' | 383 | + searchStr = '\[{"Switch.*$' |
325 | ctrlStr = '' | 384 | ctrlStr = '' |
326 | - for index in range(len(net.controllers)): | 385 | + for index in range(len(LINCSwitch.controllers)): |
327 | ctrlStr += '{"Switch%d-Controller","%s",%d,tcp},' % (index, net.controllers[index].ip, net.controllers[index].port) | 386 | 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 | 387 | + replaceStr = '[%s]},' % ctrlStr[:-1] # Cut off last comma |
329 | sedCmd = 'sed -i \'s/%s/%s/\' sys.config' % (searchStr, replaceStr) | 388 | sedCmd = 'sed -i \'s/%s/%s/\' sys.config' % (searchStr, replaceStr) |
330 | - output = quietRun( sedCmd, shell=True ) | 389 | + output = quietRun(sedCmd, shell=True) |
331 | 390 | ||
332 | - info( '*** Copying sys.config to linc-oe directory: ', output + '\n' ) | 391 | + info('*** Copying sys.config to linc-oe directory: ', output + '\n') |
333 | - lincDir = findDir( 'linc-oe' ) | 392 | + output = quietRun('cp -v sys.config %s/rel/linc/releases/1.0/' % LINCSwitch.lincDir, shell=True).strip('\n') |
334 | - if not lincDir: | 393 | + info(output + '\n') |
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 | 394 | ||
340 | - info( '*** Starting linc OE...\n' ) | 395 | + info('*** Adding taps and bringing them up...\n') |
341 | - output = quietRun( '%s/rel/linc/bin/linc start' % lincDir, shell=True ) | 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) | ||
342 | if output: | 403 | if output: |
343 | - error( '***ERROR: LINC-OE: %s' % output + '\n' ) | 404 | + error('***ERROR: LINC-OE: %s' % output + '\n') |
344 | - quietRun( '%s/rel/linc/bin/linc stop' % lincDir, shell=True ) | 405 | + quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True) |
345 | return False | 406 | return False |
346 | 407 | ||
347 | - info( '*** Waiting for linc-oe to start...\n' ) | 408 | + info('*** Waiting for linc-oe to start...\n') |
348 | - waitStarted( net ) | 409 | + LINCSwitch.waitStarted(net) |
349 | 410 | ||
350 | - info( '*** Adding cross-connect (tap) interfaces to packet switches...\n' ) | 411 | + info('*** Adding cross-connect (tap) interfaces to packet switches...\n') |
351 | for link in net.links: | 412 | for link in net.links: |
352 | - if isinstance( link, OpticalLink ): | 413 | + if isinstance(link, LINCLink): |
353 | if link.annotations[ 'optical.type' ] == 'cross-connect': | 414 | if link.annotations[ 'optical.type' ] == 'cross-connect': |
354 | for intf in [ link.intf1, link.intf2 ]: | 415 | for intf in [ link.intf1, link.intf2 ]: |
355 | - if not isinstance( intf, OpticalIntf ): | 416 | + if not isinstance(intf, LINCIntf): |
356 | intfList = [ intf.link.intf1, intf.link.intf2 ] | 417 | intfList = [ intf.link.intf1, intf.link.intf2 ] |
357 | - intfList.remove( intf ) | 418 | + intfList.remove(intf) |
358 | intf2 = intfList[ 0 ] | 419 | intf2 = intfList[ 0 ] |
359 | - intf.node.attach( findTap( intf2.node, intf2.node.ports[ intf2 ] ) ) | 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') | ||
360 | 428 | ||
361 | - info( '*** Press ENTER to push Topology.json to onos...\n' ) | 429 | + # Wait for all devices to be registered |
362 | - raw_input() # FIXME... we should eventually remove this | 430 | + if (len(devices) != len(devs)): |
363 | - info( '*** Pushing Topology.json to ONOS\n' ) | 431 | + continue |
364 | - output = quietRun( '%s/tools/test/bin/onos-topo-cfg %s Topology.json' % ( onosDir, net.controllers[ 0 ].ip ), shell=True ) | 432 | + |
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) | ||
365 | # successful output contains the two characters '{}' | 450 | # successful output contains the two characters '{}' |
366 | # if there is more output than this, there is an issue | 451 | # if there is more output than this, there is an issue |
367 | - if output.strip( '{}' ): | 452 | + if output.strip('{}'): |
368 | - warn( '***WARNING: Could not push topology file to ONOS: %s' % output ) | 453 | + warn('***WARNING: Could not push topology file to ONOS: %s\n' % output) |
369 | - | 454 | + |
370 | -#converts node ids to linc-oe format, with colons every two chars | 455 | + @staticmethod |
371 | -def dpId(id): | 456 | + def waitStarted(net, timeout=TIMEOUT): |
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" | 457 | "wait until all tap interfaces are available" |
380 | tapCount = 0 | 458 | tapCount = 0 |
381 | time = 0 | 459 | time = 0 |
382 | for link in net.links: | 460 | for link in net.links: |
383 | - if isinstance( link, OpticalLink ): | 461 | + if isinstance(link, LINCLink): |
384 | if link.annotations[ 'optical.type' ] == 'cross-connect': | 462 | if link.annotations[ 'optical.type' ] == 'cross-connect': |
385 | tapCount += 1 | 463 | tapCount += 1 |
386 | 464 | ||
387 | while True: | 465 | while True: |
388 | - if str( tapCount ) == quietRun( 'ip addr | grep tap | wc -l', shell=True ).strip( '\n' ): | 466 | + if str(tapCount) == quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'): |
389 | return True | 467 | return True |
390 | if timeout: | 468 | if timeout: |
391 | - if time >= timeout: | 469 | + if time >= TIMEOUT: |
392 | - error( '***ERROR: Linc OE did not start within %s seconds' % timeout ) | 470 | + error('***ERROR: LINC OE did not start within %s seconds\n' % TIMEOUT) |
393 | return False | 471 | return False |
394 | - time += .5 | 472 | + time += SLEEP_TIME |
395 | - sleep( .5 ) | 473 | + sleep(SLEEP_TIME) |
396 | 474 | ||
397 | -def stopOE(): | 475 | + @staticmethod |
476 | + def shutdownOE(): | ||
398 | "stop the optical emulator" | 477 | "stop the optical emulator" |
399 | - info( '*** Stopping linc OE...\n' ) | 478 | + info('*** Stopping linc OE...\n') |
400 | - lincDir = findDir( 'linc-oe' ) | 479 | + quietRun('%s/rel/linc/bin/linc stop' % LINCSwitch.lincDir, shell=True) |
401 | - quietRun( '%s/rel/linc/bin/linc stop' % lincDir, shell=True ) | 480 | + |
402 | - | 481 | + @staticmethod |
403 | -def findDir( directory ): | 482 | + def setupInts(intfs): |
404 | - "finds and returns the path of any directory in the user's home directory" | 483 | + ''' |
405 | - user = findUser() | 484 | + add taps and bring them up. |
406 | - homeDir = '/home/' + user | 485 | + ''' |
407 | - Dir = quietRun( 'find %s -maxdepth 1 -name %s -type d' % ( homeDir, directory ) ).strip( '\n' ) | 486 | + for i in intfs: |
408 | - DirList = Dir.split( '\n' ) | 487 | + quietRun('ip tuntap add dev %s mode tap' % i) |
409 | - if not Dir: | 488 | + quietRun('ip link set dev %s up' % i) |
410 | - return None | 489 | + info('*** Intf %s set\n' % i) |
411 | - elif len( DirList ) > 1 : | 490 | + |
412 | - warn( '***WARNING: Found multiple instances of %s; using %s\n' | 491 | + @staticmethod |
413 | - % ( directory, DirList[ 0 ] ) ) | 492 | + def getTaps(path=None): |
414 | - return DirList[ 0 ] | 493 | + ''' |
415 | - else: | 494 | + return list of all the tops in sys.config |
416 | - return Dir | 495 | + ''' |
417 | - | 496 | + if path is None: |
418 | -def findUser(): | 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(): | ||
419 | "Try to return logged-in (usually non-root) user" | 506 | "Try to return logged-in (usually non-root) user" |
420 | try: | 507 | try: |
421 | # If we're running sudo | 508 | # If we're running sudo |
... | @@ -423,32 +510,29 @@ def findUser(): | ... | @@ -423,32 +510,29 @@ def findUser(): |
423 | except: | 510 | except: |
424 | try: | 511 | try: |
425 | # Logged-in user (if we have a tty) | 512 | # Logged-in user (if we have a tty) |
426 | - return quietRun( 'who am i' ).split()[ 0 ] | 513 | + return quietRun('who am i').split()[ 0 ] |
427 | except: | 514 | except: |
428 | # Give up and return effective user | 515 | # Give up and return effective user |
429 | - return quietRun( 'whoami' ) | 516 | + return quietRun('whoami') |
430 | 517 | ||
431 | 518 | ||
432 | -def findTap( node, port, path=None ): | 519 | + @staticmethod |
520 | + def findTap(node, port, path=None): | ||
433 | '''utility function to parse through a sys.config | 521 | '''utility function to parse through a sys.config |
434 | file to find tap interfaces for a switch''' | 522 | file to find tap interfaces for a switch''' |
435 | - switch=False | 523 | + switch = False |
436 | portLine = '' | 524 | portLine = '' |
437 | intfLines = [] | 525 | intfLines = [] |
438 | 526 | ||
439 | if path is None: | 527 | if path is None: |
440 | - lincDir = findDir( 'linc-oe' ) | 528 | + path = '%s/rel/linc/releases/1.0/sys.config' % LINCSwitch.lincDir |
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 | 529 | ||
446 | - with open( path ) as f: | 530 | + with open(path) as f: |
447 | for line in f: | 531 | for line in f: |
448 | if 'tap' in line: | 532 | if 'tap' in line: |
449 | - intfLines.append( line ) | 533 | + intfLines.append(line) |
450 | - if node.dpid in line.translate( None, ':' ): | 534 | + if node.dpid in line.translate(None, ':'): |
451 | - switch=True | 535 | + switch = True |
452 | continue | 536 | continue |
453 | if switch: | 537 | if switch: |
454 | if 'switch' in line: | 538 | if 'switch' in line: |
... | @@ -458,65 +542,129 @@ def findTap( node, port, path=None ): | ... | @@ -458,65 +542,129 @@ def findTap( node, port, path=None ): |
458 | break | 542 | break |
459 | 543 | ||
460 | if portLine: | 544 | if portLine: |
461 | - m = re.search( 'port,\d+', portLine ) | 545 | + m = re.search('port,\d+', portLine) |
462 | - port = m.group( 0 ).split( ',' )[ 1 ] | 546 | + port = m.group(0).split(',')[ 1 ] |
463 | else: | 547 | else: |
464 | - error( '***ERROR: Could not find any ports in sys.config\n' ) | 548 | + error('***ERROR: Could not find any ports in sys.config\n') |
465 | return | 549 | return |
466 | 550 | ||
467 | for intfLine in intfLines: | 551 | for intfLine in intfLines: |
468 | if 'port,%s' % port in intfLine: | 552 | if 'port,%s' % port in intfLine: |
469 | - return re.findall( 'tap\d+', intfLine )[ 0 ] | 553 | + return re.findall('tap\d+', intfLine)[ 0 ] |
554 | + | ||
555 | + def json(self): | ||
556 | + "return json configuration dictionary for switch" | ||
557 | + return self.configDict | ||
470 | 558 | ||
559 | + def terminate(self): | ||
560 | + pass | ||
471 | 561 | ||
472 | -class MininetOE( Mininet ): | 562 | +class LINCLink(Link): |
563 | + """ | ||
564 | + LINC link class | ||
565 | + """ | ||
566 | + def __init__(self, node1, node2, port1=None, port2=None, allowed=True, | ||
567 | + intfName1=None, intfName2=None, linkType='OPTICAL', | ||
568 | + annotations={}, speed1=0, speed2=0, **params): | ||
569 | + "Creates a dummy link without a virtual ethernet pair." | ||
570 | + self.allowed = allowed | ||
571 | + self.annotations = annotations | ||
572 | + self.linkType = linkType | ||
573 | + self.port1 = port1 | ||
574 | + self.port2 = port2 | ||
575 | + params1 = { 'speed': speed1 } | ||
576 | + params2 = { 'speed': speed2 } | ||
577 | + # self.isCrossConnect = True if self.annotations.get('optical.type') == 'cross-connect' else False | ||
578 | + if isinstance(node1, LINCSwitch) and isinstance(node2, LINCSwitch): | ||
579 | + self.isCrossConnect = False | ||
580 | + else: | ||
581 | + self.isCrossConnect = True | ||
582 | + if isinstance(node1, LINCSwitch): | ||
583 | + cls1 = LINCIntf | ||
584 | + if self.isCrossConnect: | ||
585 | + node1.crossConnects.append(self) | ||
586 | + else: | ||
587 | + cls1 = Intf | ||
588 | + # bad hack to stop error message from appearing when we try to set up intf in a packet switch, | ||
589 | + # and there is no interface there( because we do not run makeIntfPair ). This way, we just set lo up | ||
590 | + intfName1 = 'lo' | ||
591 | + if isinstance(node2, LINCSwitch): | ||
592 | + cls2 = LINCIntf | ||
593 | + if self.isCrossConnect: | ||
594 | + node2.crossConnects.append(self) | ||
595 | + else: | ||
596 | + cls2 = Intf | ||
597 | + intfName2 = 'lo' | ||
598 | + Link.__init__(self, node1, node2, port1=port1, port2=port2, | ||
599 | + intfName1=intfName1, intfName2=intfName2, cls1=cls1, | ||
600 | + cls2=cls2, params1=params1, params2=params2) | ||
601 | + | ||
602 | + @classmethod | ||
603 | + def makeIntfPair(_cls, intfName1, intfName2, *args, **kwargs): | ||
604 | + pass | ||
605 | + | ||
606 | + def json(self): | ||
607 | + "build and return the json configuration dictionary for this link" | ||
608 | + configData = {} | ||
609 | + configData[ 'src' ] = ('of:' + self.intf1.node.dpid + | ||
610 | + '/%s' % self.intf1.node.ports[ self.intf1 ]) | ||
611 | + configData[ 'dst' ] = ('of:' + self.intf2.node.dpid + | ||
612 | + '/%s' % self.intf2.node.ports[ self.intf2 ]) | ||
613 | + configData[ 'type' ] = self.linkType | ||
614 | + configData[ 'annotations' ] = self.annotations | ||
615 | + return configData | ||
616 | + | ||
617 | +class LINCIntf(OpticalIntf): | ||
618 | + """ | ||
619 | + LINC interface class | ||
620 | + """ | ||
621 | + def __init__(self, name=None, node=None, speed=0, | ||
622 | + port=None, link=None, **params): | ||
623 | + self.node = node | ||
624 | + self.speed = speed | ||
625 | + self.port = port | ||
626 | + self.link = link | ||
627 | + self.name = name | ||
628 | + node.addIntf(self, port=port) | ||
629 | + self.params = params | ||
630 | + self.ip = None | ||
631 | + | ||
632 | + def json(self): | ||
633 | + "build and return the JSON information for this interface( not used right now )" | ||
634 | + configDict = {} | ||
635 | + configDict[ 'port' ] = self.port | ||
636 | + configDict[ 'speed' ] = self.speed | ||
637 | + configDict[ 'type' ] = 'FIBER' | ||
638 | + return configDict | ||
639 | + | ||
640 | + def config(self, *args, **kwargs): | ||
641 | + "dont configure a dummy interface" | ||
642 | + pass | ||
643 | + | ||
644 | + def ifconfig(self, status): | ||
645 | + "configure the status" | ||
646 | + if status == "up": | ||
647 | + return self.node.w_port_up(self.port) | ||
648 | + elif status == "down": | ||
649 | + return self.node.w_port_down(self.port) | ||
650 | + | ||
651 | + | ||
652 | +class MininetOE(Mininet): | ||
473 | "Mininet with Linc-OE support (starts and stops linc-oe)" | 653 | "Mininet with Linc-OE support (starts and stops linc-oe)" |
474 | 654 | ||
475 | - def start( self ): | 655 | + def start(self): |
476 | - Mininet.start( self ) | 656 | + Mininet.start(self) |
477 | - startOE( self ) | 657 | + LINCSwitch.bootOE(self) |
478 | 658 | ||
479 | - def stop( self ): | 659 | + def stop(self): |
480 | - Mininet.stop( self ) | 660 | + Mininet.stop(self) |
481 | - stopOE() | 661 | + LINCSwitch.shutdownOE() |
482 | 662 | ||
483 | - def addControllers( self, controllers ): | 663 | + def addControllers(self, controllers): |
484 | i = 0 | 664 | i = 0 |
485 | for ctrl in controllers: | 665 | for ctrl in controllers: |
486 | - self.addController( RemoteController( 'c%d' % i, ip=ctrl ) ) | 666 | + self.addController(RemoteController('c%d' % i, ip=ctrl)) |
487 | - | 667 | + i += 1 |
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 ) | ||
507 | 668 | ||
508 | if __name__ == '__main__': | 669 | if __name__ == '__main__': |
509 | - import sys | 670 | + pass |
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