Committed by
Gerrit Code Review
First round of cleanups in optical path provisioner. No more user input for pack…
…et/optical mininet script. Change-Id: Ibbfa6a17a97432da8dee63e9cd15fa6b1c2c1e46
Showing
2 changed files
with
184 additions
and
86 deletions
... | @@ -18,6 +18,7 @@ package org.onosproject.optical; | ... | @@ -18,6 +18,7 @@ package org.onosproject.optical; |
18 | import com.google.common.collect.Lists; | 18 | import com.google.common.collect.Lists; |
19 | import org.apache.felix.scr.annotations.Activate; | 19 | import org.apache.felix.scr.annotations.Activate; |
20 | import org.apache.felix.scr.annotations.Component; | 20 | import org.apache.felix.scr.annotations.Component; |
21 | +import org.apache.felix.scr.annotations.Deactivate; | ||
21 | import org.apache.felix.scr.annotations.Reference; | 22 | import org.apache.felix.scr.annotations.Reference; |
22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 23 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
23 | import org.onosproject.cluster.ClusterService; | 24 | import org.onosproject.cluster.ClusterService; |
... | @@ -44,19 +45,23 @@ import org.onosproject.net.topology.TopologyEdge; | ... | @@ -44,19 +45,23 @@ import org.onosproject.net.topology.TopologyEdge; |
44 | import org.slf4j.Logger; | 45 | import org.slf4j.Logger; |
45 | import org.slf4j.LoggerFactory; | 46 | import org.slf4j.LoggerFactory; |
46 | 47 | ||
48 | +import java.util.Collections; | ||
47 | import java.util.Iterator; | 49 | import java.util.Iterator; |
50 | +import java.util.LinkedList; | ||
48 | import java.util.List; | 51 | import java.util.List; |
49 | import java.util.Map; | 52 | import java.util.Map; |
50 | import java.util.Set; | 53 | import java.util.Set; |
51 | import java.util.concurrent.ConcurrentHashMap; | 54 | import java.util.concurrent.ConcurrentHashMap; |
52 | 55 | ||
56 | +import static com.google.common.base.Preconditions.checkArgument; | ||
53 | import static org.onosproject.net.intent.IntentState.INSTALLED; | 57 | import static org.onosproject.net.intent.IntentState.INSTALLED; |
54 | 58 | ||
59 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
60 | + | ||
55 | /** | 61 | /** |
56 | - * OpticalPathProvisioner listens event notifications from the Intent F/W. | 62 | + * OpticalPathProvisioner listens for event notifications from the Intent F/W. |
57 | * It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W | 63 | * It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W |
58 | * for adding/releasing capacity at the packet layer. | 64 | * for adding/releasing capacity at the packet layer. |
59 | - * | ||
60 | */ | 65 | */ |
61 | 66 | ||
62 | @Component(immediate = true) | 67 | @Component(immediate = true) |
... | @@ -86,12 +91,12 @@ public class OpticalPathProvisioner { | ... | @@ -86,12 +91,12 @@ public class OpticalPathProvisioner { |
86 | private ApplicationId appId; | 91 | private ApplicationId appId; |
87 | 92 | ||
88 | // TODO use a shared map for distributed operation | 93 | // TODO use a shared map for distributed operation |
89 | - protected final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap = | 94 | + private final Map<ConnectPoint, OpticalConnectivityIntent> inStatusTportMap = |
90 | new ConcurrentHashMap<>(); | 95 | new ConcurrentHashMap<>(); |
91 | - protected final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap = | 96 | + private final Map<ConnectPoint, OpticalConnectivityIntent> outStatusTportMap = |
92 | new ConcurrentHashMap<>(); | 97 | new ConcurrentHashMap<>(); |
93 | 98 | ||
94 | - protected final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap = | 99 | + private final Map<ConnectPoint, Map<ConnectPoint, Intent>> intentMap = |
95 | new ConcurrentHashMap<>(); | 100 | new ConcurrentHashMap<>(); |
96 | 101 | ||
97 | private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner(); | 102 | private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner(); |
... | @@ -101,7 +106,13 @@ public class OpticalPathProvisioner { | ... | @@ -101,7 +106,13 @@ public class OpticalPathProvisioner { |
101 | intentService.addListener(pathProvisioner); | 106 | intentService.addListener(pathProvisioner); |
102 | appId = coreService.registerApplication("org.onosproject.optical"); | 107 | appId = coreService.registerApplication("org.onosproject.optical"); |
103 | initTport(); | 108 | initTport(); |
104 | - log.info("Starting optical path provisioning..."); | 109 | + log.info("Started"); |
110 | + } | ||
111 | + | ||
112 | + @Deactivate | ||
113 | + protected void deactivate() { | ||
114 | + intentService.removeListener(pathProvisioner); | ||
115 | + log.info("Stopped"); | ||
105 | } | 116 | } |
106 | 117 | ||
107 | protected void initTport() { | 118 | protected void initTport() { |
... | @@ -119,10 +130,6 @@ public class OpticalPathProvisioner { | ... | @@ -119,10 +130,6 @@ public class OpticalPathProvisioner { |
119 | } | 130 | } |
120 | } | 131 | } |
121 | 132 | ||
122 | - protected void deactivate() { | ||
123 | - intentService.removeListener(pathProvisioner); | ||
124 | - } | ||
125 | - | ||
126 | public class InternalOpticalPathProvisioner implements IntentListener { | 133 | public class InternalOpticalPathProvisioner implements IntentListener { |
127 | @Override | 134 | @Override |
128 | public void event(IntentEvent event) { | 135 | public void event(IntentEvent event) { |
... | @@ -132,11 +139,11 @@ public class OpticalPathProvisioner { | ... | @@ -132,11 +139,11 @@ public class OpticalPathProvisioner { |
132 | case INSTALLED: | 139 | case INSTALLED: |
133 | break; | 140 | break; |
134 | case FAILED: | 141 | case FAILED: |
135 | - log.info("packet intent {} failed, calling optical path provisioning APP.", event.subject()); | 142 | + log.info("Intent {} failed, calling optical path provisioning app.", event.subject()); |
136 | setupLightpath(event.subject()); | 143 | setupLightpath(event.subject()); |
137 | break; | 144 | break; |
138 | case WITHDRAWN: | 145 | case WITHDRAWN: |
139 | - log.info("intent {} withdrawn.", event.subject()); | 146 | + log.info("Intent {} withdrawn.", event.subject()); |
140 | //FIXME | 147 | //FIXME |
141 | //teardownLightpath(event.subject()); | 148 | //teardownLightpath(event.subject()); |
142 | break; | 149 | break; |
... | @@ -162,6 +169,7 @@ public class OpticalPathProvisioner { | ... | @@ -162,6 +169,7 @@ public class OpticalPathProvisioner { |
162 | 169 | ||
163 | /** | 170 | /** |
164 | * Registers an intent from src to dst. | 171 | * Registers an intent from src to dst. |
172 | + * | ||
165 | * @param src source point | 173 | * @param src source point |
166 | * @param dst destination point | 174 | * @param dst destination point |
167 | * @param intent intent to be registered | 175 | * @param intent intent to be registered |
... | @@ -242,78 +250,124 @@ public class OpticalPathProvisioner { | ... | @@ -242,78 +250,124 @@ public class OpticalPathProvisioner { |
242 | } | 250 | } |
243 | } | 251 | } |
244 | 252 | ||
253 | + /** | ||
254 | + * Returns list of cross connection points of missing optical path sections. | ||
255 | + * | ||
256 | + * Scans the given multi-layer path and looks for sections that use cross connect links. | ||
257 | + * The ingress and egress points in the optical layer are returned in a list. | ||
258 | + * | ||
259 | + * @param path the multi-layer path | ||
260 | + * @return list of cross connection points on the optical layer | ||
261 | + */ | ||
262 | + private List<ConnectPoint> getCrossConnectPoints(Path path) { | ||
263 | + boolean scanning = false; | ||
264 | + List<ConnectPoint> connectPoints = new LinkedList<ConnectPoint>(); | ||
265 | + | ||
266 | + for (Link link : path.links()) { | ||
267 | + if (!isCrossConnectLink(link)) { | ||
268 | + continue; | ||
269 | + } | ||
270 | + | ||
271 | + if (scanning) { | ||
272 | + connectPoints.add(checkNotNull(link.src())); | ||
273 | + scanning = false; | ||
274 | + } else { | ||
275 | + connectPoints.add(checkNotNull(link.dst())); | ||
276 | + scanning = true; | ||
277 | + } | ||
278 | + } | ||
279 | + | ||
280 | + return connectPoints; | ||
281 | + } | ||
282 | + | ||
283 | + /** | ||
284 | + * Checks availability of cross connect points by verifying T port status. | ||
285 | + * TODO: refactor after rewriting OpticalConnectivityIntentCompiler | ||
286 | + * | ||
287 | + * @param crossConnectPoints list of cross connection points | ||
288 | + * @return true if all cross connect points are available, false otherwise | ||
289 | + */ | ||
290 | + private boolean checkCrossConnectPoints(List<ConnectPoint> crossConnectPoints) { | ||
291 | + checkArgument(crossConnectPoints.size() % 2 == 0); | ||
292 | + | ||
293 | + Iterator<ConnectPoint> itr = crossConnectPoints.iterator(); | ||
294 | + | ||
295 | + while (itr.hasNext()) { | ||
296 | + // checkArgument at start ensures we'll always have pairs of connect points | ||
297 | + ConnectPoint src = itr.next(); | ||
298 | + ConnectPoint dst = itr.next(); | ||
299 | + | ||
300 | + if (inStatusTportMap.get(src) != null || outStatusTportMap.get(dst) != null) { | ||
301 | + return false; | ||
302 | + } | ||
303 | + } | ||
304 | + | ||
305 | + return true; | ||
306 | + } | ||
307 | + | ||
308 | + /** | ||
309 | + * Scans the list of cross connection points and returns a list of optical connectivity intents | ||
310 | + * in both directions. | ||
311 | + * | ||
312 | + * @param crossConnectPoints list of cross connection points | ||
313 | + * @return list of optical connectivity intents | ||
314 | + */ | ||
315 | + private List<Intent> getIntents(List<ConnectPoint> crossConnectPoints) { | ||
316 | + checkArgument(crossConnectPoints.size() % 2 == 0); | ||
317 | + | ||
318 | + List<Intent> intents = new LinkedList<Intent>(); | ||
319 | + Iterator<ConnectPoint> itr = crossConnectPoints.iterator(); | ||
320 | + | ||
321 | + while (itr.hasNext()) { | ||
322 | + // checkArgument at start ensures we'll always have pairs of connect points | ||
323 | + ConnectPoint src = itr.next(); | ||
324 | + ConnectPoint dst = itr.next(); | ||
325 | + | ||
326 | + // TODO: should have option for bidirectional OpticalConnectivityIntent | ||
327 | + Intent opticalIntent = OpticalConnectivityIntent.builder() | ||
328 | + .appId(appId) | ||
329 | + .src(src) | ||
330 | + .dst(dst) | ||
331 | + .build(); | ||
332 | + Intent opticalIntentRev = OpticalConnectivityIntent.builder() | ||
333 | + .appId(appId) | ||
334 | + .src(dst) | ||
335 | + .dst(src) | ||
336 | + .build(); | ||
337 | + intents.add(opticalIntent); | ||
338 | + intents.add(opticalIntentRev); | ||
339 | + } | ||
340 | + | ||
341 | + return intents; | ||
342 | + } | ||
343 | + | ||
245 | private List<Intent> getOpticalPath(ConnectPoint ingress, ConnectPoint egress) { | 344 | private List<Intent> getOpticalPath(ConnectPoint ingress, ConnectPoint egress) { |
246 | Set<Path> paths = pathService.getPaths(ingress.deviceId(), | 345 | Set<Path> paths = pathService.getPaths(ingress.deviceId(), |
247 | - egress.deviceId(), | 346 | + egress.deviceId(), |
248 | - new OpticalLinkWeight()); | 347 | + new OpticalLinkWeight()); |
249 | 348 | ||
250 | if (paths.isEmpty()) { | 349 | if (paths.isEmpty()) { |
251 | - return Lists.newArrayList(); | 350 | + return Collections.emptyList(); |
252 | } | 351 | } |
253 | 352 | ||
254 | List<Intent> connectionList = Lists.newArrayList(); | 353 | List<Intent> connectionList = Lists.newArrayList(); |
255 | 354 | ||
355 | + // Iterate over all paths until a suitable one has been found | ||
256 | Iterator<Path> itrPath = paths.iterator(); | 356 | Iterator<Path> itrPath = paths.iterator(); |
257 | while (itrPath.hasNext()) { | 357 | while (itrPath.hasNext()) { |
258 | - boolean usedTportFound = false; | ||
259 | Path nextPath = itrPath.next(); | 358 | Path nextPath = itrPath.next(); |
260 | - log.info(nextPath.links().toString()); // TODO drop log level | ||
261 | - | ||
262 | - Iterator<Link> itrLink = nextPath.links().iterator(); | ||
263 | - while (itrLink.hasNext()) { | ||
264 | - ConnectPoint srcWdmPoint, dstWdmPoint; | ||
265 | - Link link1 = itrLink.next(); | ||
266 | - if (!isOpticalLink(link1)) { | ||
267 | - continue; | ||
268 | - } else { | ||
269 | - srcWdmPoint = link1.dst(); | ||
270 | - dstWdmPoint = srcWdmPoint; | ||
271 | - } | ||
272 | 359 | ||
273 | - while (itrLink.hasNext()) { | 360 | + List<ConnectPoint> crossConnectPoints = getCrossConnectPoints(nextPath); |
274 | - Link link2 = itrLink.next(); | ||
275 | - if (isOpticalLink(link2)) { | ||
276 | - dstWdmPoint = link2.src(); | ||
277 | - } else { | ||
278 | - break; | ||
279 | - } | ||
280 | - } | ||
281 | - | ||
282 | - if (inStatusTportMap.get(srcWdmPoint) != null || | ||
283 | - outStatusTportMap.get(dstWdmPoint) != null) { | ||
284 | - usedTportFound = true; | ||
285 | - // log.info("used ConnectPoint {} to {} were found", srcWdmPoint, dstWdmPoint); | ||
286 | - break; | ||
287 | - } | ||
288 | 361 | ||
289 | - Intent opticalIntent = OpticalConnectivityIntent.builder() | 362 | + // Skip to next path if not all connect points are available |
290 | - .appId(appId) | 363 | + if (!checkCrossConnectPoints(crossConnectPoints)) { |
291 | - .src(srcWdmPoint) | 364 | + continue; |
292 | - .dst(dstWdmPoint) | ||
293 | - .build(); | ||
294 | - Intent opticalIntent2 = OpticalConnectivityIntent.builder() | ||
295 | - .appId(appId) | ||
296 | - .src(dstWdmPoint) | ||
297 | - .dst(srcWdmPoint) | ||
298 | - .build(); | ||
299 | - log.info("Creating optical intent from {} to {}", srcWdmPoint, dstWdmPoint); | ||
300 | - log.info("Creating optical intent from {} to {}", dstWdmPoint, srcWdmPoint); | ||
301 | - connectionList.add(opticalIntent); | ||
302 | - connectionList.add(opticalIntent2); | ||
303 | - | ||
304 | - break; | ||
305 | - } | ||
306 | - | ||
307 | - if (!usedTportFound) { | ||
308 | - break; | ||
309 | - } else { | ||
310 | - // reset the connection list | ||
311 | - connectionList = Lists.newArrayList(); | ||
312 | } | 365 | } |
313 | 366 | ||
367 | + return getIntents(crossConnectPoints); | ||
314 | } | 368 | } |
315 | 369 | ||
316 | - return connectionList; | 370 | + return Collections.emptyList(); |
317 | } | 371 | } |
318 | 372 | ||
319 | private void teardownLightpath(Intent intent) { | 373 | private void teardownLightpath(Intent intent) { |
... | @@ -330,26 +384,45 @@ public class OpticalPathProvisioner { | ... | @@ -330,26 +384,45 @@ public class OpticalPathProvisioner { |
330 | 384 | ||
331 | } | 385 | } |
332 | 386 | ||
333 | - private static boolean isOpticalLink(Link link) { | 387 | + /** |
334 | - boolean isOptical = false; | 388 | + * Verifies if given link is cross-connect between packet and optical layer. |
335 | - Link.Type lt = link.type(); | 389 | + * |
336 | - if (lt == Link.Type.OPTICAL) { | 390 | + * @param link the link |
337 | - isOptical = true; | 391 | + * @return true if the link is a cross-connect link |
392 | + */ | ||
393 | + public static boolean isCrossConnectLink(Link link) { | ||
394 | + if (link.type() != Link.Type.OPTICAL) { | ||
395 | + return false; | ||
338 | } | 396 | } |
339 | - return isOptical; | 397 | + |
398 | + checkNotNull(link.annotations()); | ||
399 | + checkNotNull(link.annotations().value("optical.type")); | ||
400 | + | ||
401 | + if (link.annotations().value("optical.type").equals("cross-connect")) { | ||
402 | + return true; | ||
403 | + } | ||
404 | + | ||
405 | + return false; | ||
340 | } | 406 | } |
341 | 407 | ||
408 | + /** | ||
409 | + * Link weight function that emphasizes re-use of packet links. | ||
410 | + */ | ||
342 | private static class OpticalLinkWeight implements LinkWeight { | 411 | private static class OpticalLinkWeight implements LinkWeight { |
343 | @Override | 412 | @Override |
344 | public double weight(TopologyEdge edge) { | 413 | public double weight(TopologyEdge edge) { |
414 | + // Ignore inactive links | ||
345 | if (edge.link().state() == Link.State.INACTIVE) { | 415 | if (edge.link().state() == Link.State.INACTIVE) { |
346 | - return -1; // ignore inactive links | 416 | + return -1; |
347 | } | 417 | } |
348 | - if (isOpticalLink(edge.link())) { | 418 | + |
349 | - return 1000; // optical links | 419 | + // Transport links have highest weight |
350 | - } else { | 420 | + if (edge.link().type() == Link.Type.OPTICAL) { |
351 | - return 1; // packet links | 421 | + return 1000; |
352 | } | 422 | } |
423 | + | ||
424 | + // Packet links | ||
425 | + return 1; | ||
353 | } | 426 | } |
354 | } | 427 | } |
355 | 428 | ... | ... |
... | @@ -56,6 +56,7 @@ import re | ... | @@ -56,6 +56,7 @@ 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,6 +66,10 @@ from mininet.log import setLogLevel, info, error, warn | ... | @@ -65,6 +66,10 @@ 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 | ||
69 | +# Sleep time and timeout values in seconds | ||
70 | +SLEEP_TIME = .5 | ||
71 | +TIMEOUT = 60 | ||
72 | + | ||
68 | class OpticalSwitch(Switch): | 73 | class OpticalSwitch(Switch): |
69 | """ | 74 | """ |
70 | For now, same as Switch class. | 75 | For now, same as Switch class. |
... | @@ -414,17 +419,37 @@ class LINCSwitch(OpticalSwitch): | ... | @@ -414,17 +419,37 @@ class LINCSwitch(OpticalSwitch): |
414 | intf2 = intfList[ 0 ] | 419 | intf2 = intfList[ 0 ] |
415 | intf.node.attach(LINCSwitch.findTap(intf2.node, intf2.node.ports[ intf2 ])) | 420 | intf.node.attach(LINCSwitch.findTap(intf2.node, intf2.node.ports[ intf2 ])) |
416 | 421 | ||
417 | - info('*** Press ENTER to push Topology.json to onos...\n') | 422 | + info('*** Waiting for all devices to be available in ONOS...\n') |
418 | - raw_input() # FIXME... we should eventually remove this | 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 & available | ||
430 | + if (len(devices) == len(devs)): | ||
431 | + for d in devs: | ||
432 | + if not d['available']: | ||
433 | + continue | ||
434 | + break | ||
435 | + | ||
436 | + if (time >= TIMEOUT): | ||
437 | + error('***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT) | ||
438 | + break | ||
439 | + | ||
440 | + time += SLEEP_TIME | ||
441 | + sleep(SLEEP_TIME) | ||
442 | + | ||
419 | info('*** Pushing Topology.json to ONOS\n') | 443 | info('*** Pushing Topology.json to ONOS\n') |
420 | output = quietRun('%s/tools/test/bin/onos-topo-cfg %s Topology.json' % (LINCSwitch.onosDir, LINCSwitch.controllers[ 0 ].ip), shell=True) | 444 | output = quietRun('%s/tools/test/bin/onos-topo-cfg %s Topology.json' % (LINCSwitch.onosDir, LINCSwitch.controllers[ 0 ].ip), shell=True) |
445 | + | ||
421 | # successful output contains the two characters '{}' | 446 | # successful output contains the two characters '{}' |
422 | # if there is more output than this, there is an issue | 447 | # if there is more output than this, there is an issue |
423 | if output.strip('{}'): | 448 | if output.strip('{}'): |
424 | - warn('***WARNING: Could not push topology file to ONOS: %s' % output) | 449 | + warn('***WARNING: Could not push topology file to ONOS: %s\n' % output) |
425 | 450 | ||
426 | @staticmethod | 451 | @staticmethod |
427 | - def waitStarted(net, timeout=None): | 452 | + def waitStarted(net, timeout=TIMEOUT): |
428 | "wait until all tap interfaces are available" | 453 | "wait until all tap interfaces are available" |
429 | tapCount = 0 | 454 | tapCount = 0 |
430 | time = 0 | 455 | time = 0 |
... | @@ -437,11 +462,11 @@ class LINCSwitch(OpticalSwitch): | ... | @@ -437,11 +462,11 @@ class LINCSwitch(OpticalSwitch): |
437 | if str(tapCount) == quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'): | 462 | if str(tapCount) == quietRun('ip addr | grep tap | wc -l', shell=True).strip('\n'): |
438 | return True | 463 | return True |
439 | if timeout: | 464 | if timeout: |
440 | - if time >= timeout: | 465 | + if time >= TIMEOUT: |
441 | - error('***ERROR: Linc OE did not start within %s seconds' % timeout) | 466 | + error('***ERROR: LINC OE did not start within %s seconds\n' % TIMEOUT) |
442 | return False | 467 | return False |
443 | - time += .5 | 468 | + time += SLEEP_TIME |
444 | - sleep(.5) | 469 | + sleep(SLEEP_TIME) |
445 | 470 | ||
446 | @staticmethod | 471 | @staticmethod |
447 | def shutdownOE(): | 472 | def shutdownOE(): | ... | ... |
-
Please register or login to post a comment