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