blob: 775eb511ab0eb6718b7297471263464a9ff65019 [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;
Naoki Shiota5a056062016-05-05 18:43:59 -070043import org.onosproject.net.ConnectPoint;
44import org.onosproject.net.Device;
45import org.onosproject.net.DeviceId;
46import org.onosproject.net.Link;
Naoki Shiota5a056062016-05-05 18:43:59 -070047import org.onosproject.net.Path;
48import org.onosproject.net.Port;
49import org.onosproject.net.config.NetworkConfigService;
50import org.onosproject.net.device.DeviceService;
51import org.onosproject.net.intent.Intent;
52import org.onosproject.net.intent.IntentEvent;
Naoki Shiota5a056062016-05-05 18:43:59 -070053import org.onosproject.net.intent.IntentListener;
54import org.onosproject.net.intent.IntentService;
Naoki Shiota5a056062016-05-05 18:43:59 -070055import org.onosproject.net.intent.OpticalCircuitIntent;
56import org.onosproject.net.intent.OpticalConnectivityIntent;
Naoki Shiota5a056062016-05-05 18:43:59 -070057import org.onosproject.net.link.LinkEvent;
58import org.onosproject.net.link.LinkListener;
59import org.onosproject.net.link.LinkService;
Sho SHIMIZUb6c63a32016-05-26 12:07:19 -070060import org.onosproject.net.config.basics.BandwidthCapacity;
Naoki Shiota5a056062016-05-05 18:43:59 -070061import org.onosproject.net.resource.ContinuousResource;
62import org.onosproject.net.resource.Resource;
63import org.onosproject.net.resource.ResourceAllocation;
64import org.onosproject.net.resource.ResourceService;
65import org.onosproject.net.resource.Resources;
66import org.onosproject.net.topology.LinkWeight;
67import org.onosproject.net.topology.PathService;
68import org.onosproject.net.topology.TopologyEdge;
69import org.onosproject.store.service.AtomicCounter;
70import org.onosproject.store.service.StorageService;
71import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73
74import java.time.Duration;
75import java.util.Collections;
76import java.util.Iterator;
77import java.util.LinkedList;
78import java.util.List;
79import java.util.Map;
80import java.util.Optional;
81import java.util.Set;
82import java.util.concurrent.ConcurrentHashMap;
83import java.util.stream.Collectors;
84import java.util.stream.Stream;
85
86import static com.google.common.base.Preconditions.checkArgument;
87import static com.google.common.base.Preconditions.checkNotNull;
Naoki Shiotae1366ad2016-05-11 19:24:11 -070088import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
Naoki Shiota5a056062016-05-05 18:43:59 -070089
90/**
91 * Main component to configure optical connectivity.
92 */
93@Beta
94@Service
95@Component(immediate = true)
96public class OpticalPathProvisioner
97 extends AbstractListenerManager<OpticalPathEvent, OpticalPathListener>
98 implements OpticalPathService {
99 protected static final Logger log = LoggerFactory.getLogger(OpticalPathProvisioner.class);
100
101 private static final String OPTICAL_CONNECTIVITY_ID_COUNTER = "optical-connectivity-id";
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected IntentService intentService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected PathService pathService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected CoreService coreService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected LinkService linkService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected MastershipService mastershipService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected ClusterService clusterService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected DeviceService deviceService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected StorageService storageService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected NetworkConfigService networkConfigService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected ResourceService resourceService;
132
133
134 private ApplicationId appId;
135
136 private AtomicCounter idCounter;
137
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700138 private ListenerTracker listeners;
Naoki Shiota5a056062016-05-05 18:43:59 -0700139
140 private Map<PacketLinkRealizedByOptical, OpticalConnectivity> linkPathMap = new ConcurrentHashMap<>();
141
142 // TODO this should be stored to distributed store
143 private Map<OpticalConnectivityId, OpticalConnectivity> connectivities = new ConcurrentHashMap<>();
144
145 // TODO this should be stored to distributed store
146 // Map of cross connect link and installed path which uses the link
147 private Set<Link> usedCrossConnectLinks = Sets.newConcurrentHashSet();
148
149 @Activate
150 protected void activate() {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700151 deviceService = opticalView(deviceService);
Naoki Shiota5a056062016-05-05 18:43:59 -0700152 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) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700363 OduCltPort srcOCPort = (OduCltPort) srcPort;
364 OduCltPort dstOCPort = (OduCltPort) dstPort;
365 if (!srcOCPort.signalType().equals(dstOCPort.signalType())) {
366 continue;
367 }
368
Naoki Shiota5a056062016-05-05 18:43:59 -0700369 // Create OTN circuit
370 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
371 .appId(appId)
372 .src(src.getKey())
373 .dst(dst.getKey())
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700374 .signalType(srcOCPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700375 .bidirectional(true)
376 .build();
377 intents.add(circuitIntent);
378 PacketLinkRealizedByOptical pLink = PacketLinkRealizedByOptical.create(src.getValue(), dst.getValue(),
379 circuitIntent);
380 connectivity.addRealizingLink(pLink);
381 linkPathMap.put(pLink, connectivity);
382 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700383 OchPort srcOchPort = (OchPort) srcPort;
384 OchPort dstOchPort = (OchPort) dstPort;
385 if (!srcOchPort.signalType().equals(dstOchPort.signalType())) {
386 continue;
387 }
388
Naoki Shiota5a056062016-05-05 18:43:59 -0700389 // Create lightpath
Naoki Shiota5a056062016-05-05 18:43:59 -0700390 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.builder()
391 .appId(appId)
392 .src(src.getKey())
393 .dst(dst.getKey())
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700394 .signalType(srcOchPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700395 .bidirectional(true)
396 .build();
397 intents.add(opticalIntent);
398 PacketLinkRealizedByOptical pLink = PacketLinkRealizedByOptical.create(src.getValue(), dst.getValue(),
399 opticalIntent);
400 connectivity.addRealizingLink(pLink);
401 linkPathMap.put(pLink, connectivity);
402 } else {
403 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
404 return Collections.emptyList();
405 }
406 }
407
408 return intents;
409 }
410
411 /**
412 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
413 *
414 * @param type device type
415 * @return true if in packet layer, false otherwise
416 */
417 private boolean isPacketLayer(Device.Type type) {
418 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
419 }
420
421 /**
422 * Verifies if given device type is in packet layer, i.e., switch or router device.
423 *
424 * @param type device type
425 * @return true if in packet layer, false otherwise
426 */
427 private boolean isTransportLayer(Device.Type type) {
428 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
429 }
430
431 /**
432 * Verifies if given link forms a cross-connection between packet and optical layer.
433 *
434 * @param link the link
435 * @return true if the link is a cross-connect link, false otherwise
436 */
437 private boolean isCrossConnectLink(Link link) {
438 if (link.type() != Link.Type.OPTICAL) {
439 return false;
440 }
441
442 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
443 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
444
445 return src != dst &&
446 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
447 }
448
449 /**
450 * Updates bandwidth resource of given connect point.
451 * @param cp Connect point
452 * @param bandwidth New bandwidth
453 */
454 private void updatePortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
455 NodeId localNode = clusterService.getLocalNode().id();
456 NodeId sourceMaster = mastershipService.getMasterFor(cp.deviceId());
457 if (localNode.equals(sourceMaster)) {
458 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
459 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
460 bwCapacity.capacity(bandwidth).apply();
461 }
462 }
463
464 /**
465 * Updates usage information of bandwidth based on connectivity which is established.
466 * @param connectivity Optical connectivity
467 */
468 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiotacb744db2016-05-13 19:32:35 -0700469 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700470
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
Naoki Shiotacb744db2016-05-13 19:32:35 -0700479 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
480 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700481 if (allocations.isEmpty()) {
482 log.warn("Failed to allocate bandwidth {} to {}",
483 connectivity.bandwidth().bps(), resources);
484 // TODO any recovery?
485 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700486 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700487 }
488
489 /**
490 * Release bandwidth allocated by given connectivity.
491 * @param connectivity Optical connectivity
492 */
493 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiotacb744db2016-05-13 19:32:35 -0700494 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700495
Naoki Shiotacb744db2016-05-13 19:32:35 -0700496 log.debug("releasing bandwidth allocated to {}", connectivityId);
497 if (!resourceService.release(connectivityId)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700498 log.warn("Failed to release bandwidth allocated to {}",
Naoki Shiotacb744db2016-05-13 19:32:35 -0700499 connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700500 // TODO any recovery?
501 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700502 log.debug("DONE releasing bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700503 }
504
505 private class BandwidthLinkWeight implements LinkWeight {
506 private Bandwidth bandwidth = null;
507
508 public BandwidthLinkWeight(Bandwidth bandwidth) {
509 this.bandwidth = bandwidth;
510 }
511
512 @Override
513 public double weight(TopologyEdge edge) {
514 Link l = edge.link();
515
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700516 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700517 if (l.state() == Link.State.INACTIVE) {
518 return -1.0;
519 }
520
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700521 // Avoid cross connect links with used ports
Naoki Shiota5a056062016-05-05 18:43:59 -0700522 if (isCrossConnectLink(l) && usedCrossConnectLinks.contains(l)) {
523 return -1.0;
524 }
525
526 // Check availability of bandwidth
527 if (bandwidth != null) {
528 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
529 return 1.0;
530 } else {
531 return -1.0;
532 }
533 } else {
534 // TODO needs to differentiate optical and packet?
535 if (l.type() == Link.Type.OPTICAL) {
536 // Transport links
537 return 1.0;
538 } else {
539 // Packet links
540 return 1.0;
541 }
542 }
543 }
544
545 private boolean hasEnoughBandwidth(ConnectPoint cp) {
546 if (cp.elementId() instanceof DeviceId) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700547 Device device = deviceService.getDevice(cp.deviceId());
548 Device.Type type = device.type();
549
Naoki Shiota5a056062016-05-05 18:43:59 -0700550 if (isTransportLayer(type)) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700551 // Check if the port has enough capacity
552 Port port = deviceService.getPort(cp.deviceId(), cp.port());
553 if (port instanceof OduCltPort || port instanceof OchPort) {
554 // Port with capacity
555 return bandwidth.bps() < port.portSpeed() * 1000000.0;
556 } else {
557 // Port without valid capacity (OMS port, etc.)
558 return true;
559 }
560 } else {
561 // Check if enough amount of bandwidth resource remains
562 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
563 .resource(bandwidth.bps());
564 return resourceService.isAvailable(resource);
Naoki Shiota5a056062016-05-05 18:43:59 -0700565 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700566 }
567 return false;
568 }
569 }
570
571
572 public class InternalIntentListener implements IntentListener {
573 @Override
574 public void event(IntentEvent event) {
575 switch (event.type()) {
576 case INSTALLED:
577 log.info("Intent {} installed.", event.subject());
578 updateCrossConnectLink(event.subject());
579 break;
580 case WITHDRAWN:
581 log.info("Intent {} withdrawn.", event.subject());
582 removeCrossConnectLinks(event.subject());
583 break;
584 case FAILED:
585 log.info("Intent {} failed.", event.subject());
586 break;
587 default:
588 break;
589 }
590 }
591
592 private void updateCrossConnectLink(Intent intent) {
593 linkPathMap.entrySet().stream()
594 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
595 .forEach(e -> {
596 ConnectPoint packetSrc = e.getKey().src();
597 ConnectPoint packetDst = e.getKey().dst();
598 Bandwidth bw = e.getKey().bandwidth();
599 // Updates bandwidth of packet ports
600 updatePortBandwidth(packetSrc, bw);
601 updatePortBandwidth(packetDst, bw);
602
603 OpticalConnectivity connectivity = e.getValue();
604 connectivity.setLinkEstablished(packetSrc, packetDst);
605
606 if (e.getValue().isAllRealizingLinkEstablished()) {
607 updateBandwidthUsage(connectivity);
608
609 // Notifies listeners if all links are established
610 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, e.getValue().id()));
611 }
612 });
613 }
614
615 private void removeCrossConnectLinks(Intent intent) {
616 ConnectPoint src, dst;
617
618 if (intent instanceof OpticalCircuitIntent) {
619 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
620 src = circuit.getSrc();
621 dst = circuit.getDst();
622 } else if (intent instanceof OpticalConnectivityIntent) {
623 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
624 src = conn.getSrc();
625 dst = conn.getDst();
626 } else {
627 return;
628 }
629
630 removeXcLinkUsage(src);
631 removeXcLinkUsage(dst);
632
633 // Set bandwidth of 0 to cross connect ports
634 Bandwidth bw = Bandwidth.bps(0);
635 linkPathMap.entrySet().stream()
636 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
637 .forEach(e -> {
638 ConnectPoint packetSrc = e.getKey().src();
639 ConnectPoint packetDst = e.getKey().dst();
640 // Updates bandwidth of packet ports
641 updatePortBandwidth(packetSrc, bw);
642 updatePortBandwidth(packetDst, bw);
643 OpticalConnectivity connectivity = e.getValue();
644 connectivity.setLinkRemoved(packetSrc, packetDst);
645
646 // Notifies listeners if all links are gone
647 if (e.getValue().isAllRealizingLinkNotEstablished()) {
648 releaseBandwidthUsage(connectivity);
649 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, e.getValue().id()));
650 }
651 });
652 }
653
654 private void removeXcLinkUsage(ConnectPoint cp) {
655 Optional<Link> link = linkService.getLinks(cp).stream()
656 .filter(usedCrossConnectLinks::contains)
657 .findAny();
658
659 if (!link.isPresent()) {
660 log.warn("Cross connect point {} has no cross connect link.", cp);
661 return;
662 }
663
664 usedCrossConnectLinks.remove(link.get());
665 }
666 }
667
668
669 private class InternalLinkListener implements LinkListener {
670
671 @Override
672 public void event(LinkEvent event) {
673 switch (event.type()) {
674 case LINK_REMOVED:
675 Link link = event.subject();
676 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
677 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
678 .collect(Collectors.toSet());
679
680 pLinks.forEach(l -> {
681 OpticalConnectivity c = linkPathMap.get(l);
682 // Notifies listeners if all links are gone
683 if (c.isAllRealizingLinkNotEstablished()) {
684 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, c.id()));
685 }
686 linkPathMap.remove(l);
687 });
688 default:
689 break;
690 }
691 }
692 }
693}
694