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