blob: 61c0c02ba9de5793cb197c68232a16749e473a28 [file] [log] [blame]
Naoki Shiota5a056062016-05-05 18:43:59 -07001/*
2 * Copyright 2016 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 */
16package org.onosproject.newoptical;
17
18import com.google.common.annotations.Beta;
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.Sets;
21
22import org.apache.commons.lang3.tuple.Pair;
23import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
29import org.onlab.util.Bandwidth;
30import org.onosproject.cluster.ClusterService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Naoki Shiota0d2943e2016-05-13 18:53:21 -070034import org.onosproject.event.ListenerTracker;
35import org.onosproject.net.optical.OchPort;
36import org.onosproject.net.optical.OduCltPort;
Naoki Shiota5a056062016-05-05 18:43:59 -070037import org.onosproject.newoptical.api.OpticalConnectivityId;
38import org.onosproject.newoptical.api.OpticalPathEvent;
39import org.onosproject.newoptical.api.OpticalPathListener;
40import org.onosproject.newoptical.api.OpticalPathService;
41import org.onosproject.event.AbstractListenerManager;
42import org.onosproject.mastership.MastershipService;
43import org.onosproject.net.CltSignalType;
44import org.onosproject.net.ConnectPoint;
45import org.onosproject.net.Device;
46import org.onosproject.net.DeviceId;
47import org.onosproject.net.Link;
Naoki Shiota5a056062016-05-05 18:43:59 -070048import org.onosproject.net.OduSignalType;
49import org.onosproject.net.Path;
50import org.onosproject.net.Port;
51import org.onosproject.net.config.NetworkConfigService;
52import org.onosproject.net.device.DeviceService;
53import org.onosproject.net.intent.Intent;
54import org.onosproject.net.intent.IntentEvent;
Naoki Shiota5a056062016-05-05 18:43:59 -070055import org.onosproject.net.intent.IntentListener;
56import org.onosproject.net.intent.IntentService;
Naoki Shiota5a056062016-05-05 18:43:59 -070057import org.onosproject.net.intent.OpticalCircuitIntent;
58import org.onosproject.net.intent.OpticalConnectivityIntent;
Naoki Shiota5a056062016-05-05 18:43:59 -070059import org.onosproject.net.link.LinkEvent;
60import org.onosproject.net.link.LinkListener;
61import org.onosproject.net.link.LinkService;
62import org.onosproject.net.resource.BandwidthCapacity;
63import org.onosproject.net.resource.ContinuousResource;
64import org.onosproject.net.resource.Resource;
65import org.onosproject.net.resource.ResourceAllocation;
66import org.onosproject.net.resource.ResourceService;
67import org.onosproject.net.resource.Resources;
68import org.onosproject.net.topology.LinkWeight;
69import org.onosproject.net.topology.PathService;
70import org.onosproject.net.topology.TopologyEdge;
71import org.onosproject.store.service.AtomicCounter;
72import org.onosproject.store.service.StorageService;
73import org.slf4j.Logger;
74import org.slf4j.LoggerFactory;
75
76import java.time.Duration;
77import java.util.Collections;
78import java.util.Iterator;
79import java.util.LinkedList;
80import java.util.List;
81import java.util.Map;
82import java.util.Optional;
83import java.util.Set;
84import java.util.concurrent.ConcurrentHashMap;
85import java.util.stream.Collectors;
86import java.util.stream.Stream;
87
88import static com.google.common.base.Preconditions.checkArgument;
89import static com.google.common.base.Preconditions.checkNotNull;
90
91/**
92 * Main component to configure optical connectivity.
93 */
94@Beta
95@Service
96@Component(immediate = true)
97public class OpticalPathProvisioner
98 extends AbstractListenerManager<OpticalPathEvent, OpticalPathListener>
99 implements OpticalPathService {
100 protected static final Logger log = LoggerFactory.getLogger(OpticalPathProvisioner.class);
101
102 private static final String OPTICAL_CONNECTIVITY_ID_COUNTER = "optical-connectivity-id";
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected IntentService intentService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected PathService pathService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected CoreService coreService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected LinkService linkService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected MastershipService mastershipService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected ClusterService clusterService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DeviceService deviceService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected StorageService storageService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected NetworkConfigService networkConfigService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected ResourceService resourceService;
133
134
135 private ApplicationId appId;
136
137 private AtomicCounter idCounter;
138
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700139 private ListenerTracker listeners;
Naoki Shiota5a056062016-05-05 18:43:59 -0700140
141 private Map<PacketLinkRealizedByOptical, OpticalConnectivity> linkPathMap = new ConcurrentHashMap<>();
142
143 // TODO this should be stored to distributed store
144 private Map<OpticalConnectivityId, OpticalConnectivity> connectivities = new ConcurrentHashMap<>();
145
146 // TODO this should be stored to distributed store
147 // Map of cross connect link and installed path which uses the link
148 private Set<Link> usedCrossConnectLinks = Sets.newConcurrentHashSet();
149
150 @Activate
151 protected void activate() {
152 appId = coreService.registerApplication("org.onosproject.newoptical");
153
154 idCounter = storageService.atomicCounterBuilder()
155 .withName(OPTICAL_CONNECTIVITY_ID_COUNTER)
156 .withMeteringDisabled()
157 .build()
158 .asAtomicCounter();
159
160 eventDispatcher.addSink(OpticalPathEvent.class, listenerRegistry);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700161
162 listeners = new ListenerTracker();
163 listeners.addListener(linkService, new InternalLinkListener())
164 .addListener(intentService, new InternalIntentListener());
Naoki Shiota5a056062016-05-05 18:43:59 -0700165
166 log.info("Started");
167 }
168
169 @Deactivate
170 protected void deactivate() {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700171 listeners.removeListeners();
172 eventDispatcher.removeSink(OpticalPathEvent.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700173
174 log.info("Stopped");
175 }
176
177 @Override
178 public OpticalConnectivityId setupConnectivity(ConnectPoint ingress, ConnectPoint egress,
179 Bandwidth bandwidth, Duration latency) {
180 checkNotNull(ingress);
181 checkNotNull(egress);
182 log.info("setupConnectivity({}, {}, {}, {})", ingress, egress, bandwidth, latency);
183
184 bandwidth = (bandwidth == null) ? Bandwidth.bps(0) : bandwidth;
185
186 Set<Path> paths = pathService.getPaths(ingress.deviceId(), egress.deviceId(),
187 new BandwidthLinkWeight(bandwidth));
188 if (paths.isEmpty()) {
189 log.warn("Unable to find multi-layer path.");
190 return null;
191 }
192
193 // Search path with available cross connect points
194 for (Path path : paths) {
195 OpticalConnectivityId id = setupPath(path, bandwidth, latency);
196 if (id != null) {
197 log.info("Assigned OpticalConnectivityId: {}", id);
198 return id;
199 }
200 }
201
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700202 log.info("setupConnectivity({}, {}, {}, {}) failed.", ingress, egress, bandwidth, latency);
203
Naoki Shiota5a056062016-05-05 18:43:59 -0700204 return null;
205 }
206
207 @Override
208 public OpticalConnectivityId setupPath(Path path, Bandwidth bandwidth, Duration latency) {
209 checkNotNull(path);
210 log.info("setupPath({}, {}, {})", path, bandwidth, latency);
211
212 // validate optical path
213 List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs = getCrossConnectPoints(path);
214 if (!checkXcPoints(xcPointPairs)) {
215 // Can't setup path if cross connect points are mismatched
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700216 log.error("Failed to setup path because of mismatched cross connect points.");
Naoki Shiota5a056062016-05-05 18:43:59 -0700217 return null;
218 }
219
220 OpticalConnectivity connectivity = createConnectivity(path, bandwidth, latency);
221
222 // create intents from cross connect points and set connectivity information
223 List<Intent> intents = createIntents(xcPointPairs, connectivity);
224
225 // store cross connect port usage
226 path.links().stream().filter(this::isCrossConnectLink)
227 .forEach(usedCrossConnectLinks::add);
228
229 // Submit the intents
230 for (Intent i : intents) {
231 intentService.submit(i);
232 log.debug("Submitted an intent: {}", i);
233 }
234
235 return connectivity.id();
236 }
237
238 private OpticalConnectivity createConnectivity(Path path, Bandwidth bandwidth, Duration latency) {
239 OpticalConnectivityId id = OpticalConnectivityId.of(idCounter.getAndIncrement());
240 OpticalConnectivity connectivity = new OpticalConnectivity(id, path, bandwidth, latency);
241
Naoki Shiota5a056062016-05-05 18:43:59 -0700242 // store connectivity information
243 connectivities.put(connectivity.id(), connectivity);
244
245 return connectivity;
246 }
247
248 @Override
249 public boolean removeConnectivity(OpticalConnectivityId id) {
250 log.info("removeConnectivity({})", id);
251 OpticalConnectivity connectivity = connectivities.remove(id);
252
253 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700254 log.info("OpticalConnectivity with id {} not found.", id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700255 return false;
256 }
257
258 // TODO withdraw intent only if all of connectivities that use the optical path are withdrawn
259 connectivity.getRealizingLinks().forEach(l -> {
260 Intent intent = intentService.getIntent(l.realizingIntentKey());
261 intentService.withdraw(intent);
262 });
263
264 return true;
265 }
266
267 @Override
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700268 public Optional<List<Link>> getPath(OpticalConnectivityId id) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700269 OpticalConnectivity connectivity = connectivities.get(id);
270 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700271 log.info("OpticalConnectivity with id {} not found.", id);
272 return Optional.empty();
Naoki Shiota5a056062016-05-05 18:43:59 -0700273 }
274
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700275 return Optional.of(ImmutableList.copyOf(connectivity.links()));
Naoki Shiota5a056062016-05-05 18:43:59 -0700276 }
277
278 /**
279 * Returns list of (optical, packet) pairs of cross connection points of missing optical path sections.
280 *
281 * Scans the given multi-layer path and looks for sections that use cross connect links.
282 * The ingress and egress points in the optical layer are combined to the packet layer ports, and
283 * are returned in a list.
284 *
285 * @param path the multi-layer path
286 * @return List of cross connect link's (packet port, optical port) pairs
287 */
288 private List<Pair<ConnectPoint, ConnectPoint>> getCrossConnectPoints(Path path) {
289 List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs = new LinkedList<>();
290 boolean scanning = false;
291
292 for (Link link : path.links()) {
293 if (!isCrossConnectLink(link)) {
294 continue;
295 }
296
297 if (scanning) {
298 // link.src() is packet, link.dst() is optical
299 xcPointPairs.add(Pair.of(checkNotNull(link.src()), checkNotNull(link.dst())));
300 scanning = false;
301 } else {
302 // link.src() is optical, link.dst() is packet
303 xcPointPairs.add(Pair.of(checkNotNull(link.dst()), checkNotNull(link.src())));
304 scanning = true;
305 }
306 }
307
308 return xcPointPairs;
309 }
310
311 /**
312 * Checks if optical cross connect points are of same type.
313 *
314 * @param xcPointPairs list of cross connection points
315 * @return true if cross connect point pairs are of same type, false otherwise
316 */
317 private boolean checkXcPoints(List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs) {
318 checkArgument(xcPointPairs.size() % 2 == 0);
319
320 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = xcPointPairs.iterator();
321
322 while (itr.hasNext()) {
323 // checkArgument at start ensures we'll always have pairs of connect points
324 Pair<ConnectPoint, ConnectPoint> src = itr.next();
325 Pair<ConnectPoint, ConnectPoint> dst = itr.next();
326
327 Device.Type srcType = deviceService.getDevice(src.getKey().deviceId()).type();
328 Device.Type dstType = deviceService.getDevice(dst.getKey().deviceId()).type();
329
330 // Only support connections between identical port types
331 if (srcType != dstType) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700332 log.warn("Unsupported mix of cross connect points : {}, {}", srcType, dstType);
Naoki Shiota5a056062016-05-05 18:43:59 -0700333 return false;
334 }
335 }
336
337 return true;
338 }
339
340 /**
341 * Scans the list of cross connection points and returns a list of optical connectivity intents.
342 * During the process, store intent ID and its realizing link information to given connectivity object.
343 *
344 * @param xcPointPairs list of cross connection points
345 * @return list of optical connectivity intents
346 */
347 private List<Intent> createIntents(List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs,
348 OpticalConnectivity connectivity) {
349 checkArgument(xcPointPairs.size() % 2 == 0);
350
351 List<Intent> intents = new LinkedList<>();
352 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = xcPointPairs.iterator();
353
354 while (itr.hasNext()) {
355 // checkArgument at start ensures we'll always have pairs of connect points
356 Pair<ConnectPoint, ConnectPoint> src = itr.next();
357 Pair<ConnectPoint, ConnectPoint> dst = itr.next();
358
359 Port srcPort = deviceService.getPort(src.getKey().deviceId(), src.getKey().port());
360 Port dstPort = deviceService.getPort(dst.getKey().deviceId(), dst.getKey().port());
361
362 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
363 // Create OTN circuit
364 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
365 .appId(appId)
366 .src(src.getKey())
367 .dst(dst.getKey())
368 .signalType(CltSignalType.CLT_10GBE)
369 .bidirectional(true)
370 .build();
371 intents.add(circuitIntent);
372 PacketLinkRealizedByOptical pLink = PacketLinkRealizedByOptical.create(src.getValue(), dst.getValue(),
373 circuitIntent);
374 connectivity.addRealizingLink(pLink);
375 linkPathMap.put(pLink, connectivity);
376 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
377 // Create lightpath
378 // FIXME: hardcoded ODU signal type
379 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.builder()
380 .appId(appId)
381 .src(src.getKey())
382 .dst(dst.getKey())
383 .signalType(OduSignalType.ODU4)
384 .bidirectional(true)
385 .build();
386 intents.add(opticalIntent);
387 PacketLinkRealizedByOptical pLink = PacketLinkRealizedByOptical.create(src.getValue(), dst.getValue(),
388 opticalIntent);
389 connectivity.addRealizingLink(pLink);
390 linkPathMap.put(pLink, connectivity);
391 } else {
392 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
393 return Collections.emptyList();
394 }
395 }
396
397 return intents;
398 }
399
400 /**
401 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
402 *
403 * @param type device type
404 * @return true if in packet layer, false otherwise
405 */
406 private boolean isPacketLayer(Device.Type type) {
407 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
408 }
409
410 /**
411 * Verifies if given device type is in packet layer, i.e., switch or router device.
412 *
413 * @param type device type
414 * @return true if in packet layer, false otherwise
415 */
416 private boolean isTransportLayer(Device.Type type) {
417 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
418 }
419
420 /**
421 * Verifies if given link forms a cross-connection between packet and optical layer.
422 *
423 * @param link the link
424 * @return true if the link is a cross-connect link, false otherwise
425 */
426 private boolean isCrossConnectLink(Link link) {
427 if (link.type() != Link.Type.OPTICAL) {
428 return false;
429 }
430
431 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
432 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
433
434 return src != dst &&
435 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
436 }
437
438 /**
439 * Updates bandwidth resource of given connect point.
440 * @param cp Connect point
441 * @param bandwidth New bandwidth
442 */
443 private void updatePortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
444 NodeId localNode = clusterService.getLocalNode().id();
445 NodeId sourceMaster = mastershipService.getMasterFor(cp.deviceId());
446 if (localNode.equals(sourceMaster)) {
447 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
448 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
449 bwCapacity.capacity(bandwidth).apply();
450 }
451 }
452
453 /**
454 * Updates usage information of bandwidth based on connectivity which is established.
455 * @param connectivity Optical connectivity
456 */
457 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiotacb744db2016-05-13 19:32:35 -0700458 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700459
460 List<Link> links = connectivity.links();
461
462 List<Resource> resources = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
463 .filter(cp -> !isTransportLayer(deviceService.getDevice(cp.deviceId()).type()))
464 .map(cp -> Resources.continuous(cp.deviceId(), cp.port(),
465 Bandwidth.class).resource(connectivity.bandwidth().bps()))
466 .collect(Collectors.toList());
467
Naoki Shiotacb744db2016-05-13 19:32:35 -0700468 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
469 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700470 if (allocations.isEmpty()) {
471 log.warn("Failed to allocate bandwidth {} to {}",
472 connectivity.bandwidth().bps(), resources);
473 // TODO any recovery?
474 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700475 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700476 }
477
478 /**
479 * Release bandwidth allocated by given connectivity.
480 * @param connectivity Optical connectivity
481 */
482 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiotacb744db2016-05-13 19:32:35 -0700483 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700484
Naoki Shiotacb744db2016-05-13 19:32:35 -0700485 log.debug("releasing bandwidth allocated to {}", connectivityId);
486 if (!resourceService.release(connectivityId)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700487 log.warn("Failed to release bandwidth allocated to {}",
Naoki Shiotacb744db2016-05-13 19:32:35 -0700488 connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700489 // TODO any recovery?
490 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700491 log.debug("DONE releasing bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700492 }
493
494 private class BandwidthLinkWeight implements LinkWeight {
495 private Bandwidth bandwidth = null;
496
497 public BandwidthLinkWeight(Bandwidth bandwidth) {
498 this.bandwidth = bandwidth;
499 }
500
501 @Override
502 public double weight(TopologyEdge edge) {
503 Link l = edge.link();
504
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700505 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700506 if (l.state() == Link.State.INACTIVE) {
507 return -1.0;
508 }
509
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700510 // Avoid cross connect links with used ports
Naoki Shiota5a056062016-05-05 18:43:59 -0700511 if (isCrossConnectLink(l) && usedCrossConnectLinks.contains(l)) {
512 return -1.0;
513 }
514
515 // Check availability of bandwidth
516 if (bandwidth != null) {
517 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
518 return 1.0;
519 } else {
520 return -1.0;
521 }
522 } else {
523 // TODO needs to differentiate optical and packet?
524 if (l.type() == Link.Type.OPTICAL) {
525 // Transport links
526 return 1.0;
527 } else {
528 // Packet links
529 return 1.0;
530 }
531 }
532 }
533
534 private boolean hasEnoughBandwidth(ConnectPoint cp) {
535 if (cp.elementId() instanceof DeviceId) {
536 Device.Type type = deviceService.getDevice(cp.deviceId()).type();
537 if (isTransportLayer(type)) {
538 // Optical ports are assumed to have enough bandwidth
539 // TODO should look up physical limit?
540 return true;
541 }
542
543 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
544 .resource(bandwidth.bps());
545
546 return resourceService.isAvailable(resource);
547 }
548 return false;
549 }
550 }
551
552
553 public class InternalIntentListener implements IntentListener {
554 @Override
555 public void event(IntentEvent event) {
556 switch (event.type()) {
557 case INSTALLED:
558 log.info("Intent {} installed.", event.subject());
559 updateCrossConnectLink(event.subject());
560 break;
561 case WITHDRAWN:
562 log.info("Intent {} withdrawn.", event.subject());
563 removeCrossConnectLinks(event.subject());
564 break;
565 case FAILED:
566 log.info("Intent {} failed.", event.subject());
567 break;
568 default:
569 break;
570 }
571 }
572
573 private void updateCrossConnectLink(Intent intent) {
574 linkPathMap.entrySet().stream()
575 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
576 .forEach(e -> {
577 ConnectPoint packetSrc = e.getKey().src();
578 ConnectPoint packetDst = e.getKey().dst();
579 Bandwidth bw = e.getKey().bandwidth();
580 // Updates bandwidth of packet ports
581 updatePortBandwidth(packetSrc, bw);
582 updatePortBandwidth(packetDst, bw);
583
584 OpticalConnectivity connectivity = e.getValue();
585 connectivity.setLinkEstablished(packetSrc, packetDst);
586
587 if (e.getValue().isAllRealizingLinkEstablished()) {
588 updateBandwidthUsage(connectivity);
589
590 // Notifies listeners if all links are established
591 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, e.getValue().id()));
592 }
593 });
594 }
595
596 private void removeCrossConnectLinks(Intent intent) {
597 ConnectPoint src, dst;
598
599 if (intent instanceof OpticalCircuitIntent) {
600 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
601 src = circuit.getSrc();
602 dst = circuit.getDst();
603 } else if (intent instanceof OpticalConnectivityIntent) {
604 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
605 src = conn.getSrc();
606 dst = conn.getDst();
607 } else {
608 return;
609 }
610
611 removeXcLinkUsage(src);
612 removeXcLinkUsage(dst);
613
614 // Set bandwidth of 0 to cross connect ports
615 Bandwidth bw = Bandwidth.bps(0);
616 linkPathMap.entrySet().stream()
617 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
618 .forEach(e -> {
619 ConnectPoint packetSrc = e.getKey().src();
620 ConnectPoint packetDst = e.getKey().dst();
621 // Updates bandwidth of packet ports
622 updatePortBandwidth(packetSrc, bw);
623 updatePortBandwidth(packetDst, bw);
624 OpticalConnectivity connectivity = e.getValue();
625 connectivity.setLinkRemoved(packetSrc, packetDst);
626
627 // Notifies listeners if all links are gone
628 if (e.getValue().isAllRealizingLinkNotEstablished()) {
629 releaseBandwidthUsage(connectivity);
630 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, e.getValue().id()));
631 }
632 });
633 }
634
635 private void removeXcLinkUsage(ConnectPoint cp) {
636 Optional<Link> link = linkService.getLinks(cp).stream()
637 .filter(usedCrossConnectLinks::contains)
638 .findAny();
639
640 if (!link.isPresent()) {
641 log.warn("Cross connect point {} has no cross connect link.", cp);
642 return;
643 }
644
645 usedCrossConnectLinks.remove(link.get());
646 }
647 }
648
649
650 private class InternalLinkListener implements LinkListener {
651
652 @Override
653 public void event(LinkEvent event) {
654 switch (event.type()) {
655 case LINK_REMOVED:
656 Link link = event.subject();
657 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
658 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
659 .collect(Collectors.toSet());
660
661 pLinks.forEach(l -> {
662 OpticalConnectivity c = linkPathMap.get(l);
663 // Notifies listeners if all links are gone
664 if (c.isAllRealizingLinkNotEstablished()) {
665 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, c.id()));
666 }
667 linkPathMap.remove(l);
668 });
669 default:
670 break;
671 }
672 }
673 }
674}
675