blob: f64e5791189f707bd77c82d2d2467e2c7d787be4 [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
Naoki Shiota03c29e12016-05-16 16:58:07 -0700154 idCounter = storageService.getAtomicCounter(OPTICAL_CONNECTIVITY_ID_COUNTER);
Naoki Shiota5a056062016-05-05 18:43:59 -0700155
156 eventDispatcher.addSink(OpticalPathEvent.class, listenerRegistry);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700157
158 listeners = new ListenerTracker();
159 listeners.addListener(linkService, new InternalLinkListener())
160 .addListener(intentService, new InternalIntentListener());
Naoki Shiota5a056062016-05-05 18:43:59 -0700161
162 log.info("Started");
163 }
164
165 @Deactivate
166 protected void deactivate() {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700167 listeners.removeListeners();
168 eventDispatcher.removeSink(OpticalPathEvent.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700169
170 log.info("Stopped");
171 }
172
173 @Override
174 public OpticalConnectivityId setupConnectivity(ConnectPoint ingress, ConnectPoint egress,
175 Bandwidth bandwidth, Duration latency) {
176 checkNotNull(ingress);
177 checkNotNull(egress);
178 log.info("setupConnectivity({}, {}, {}, {})", ingress, egress, bandwidth, latency);
179
180 bandwidth = (bandwidth == null) ? Bandwidth.bps(0) : bandwidth;
181
182 Set<Path> paths = pathService.getPaths(ingress.deviceId(), egress.deviceId(),
183 new BandwidthLinkWeight(bandwidth));
184 if (paths.isEmpty()) {
185 log.warn("Unable to find multi-layer path.");
186 return null;
187 }
188
189 // Search path with available cross connect points
190 for (Path path : paths) {
191 OpticalConnectivityId id = setupPath(path, bandwidth, latency);
192 if (id != null) {
193 log.info("Assigned OpticalConnectivityId: {}", id);
194 return id;
195 }
196 }
197
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700198 log.info("setupConnectivity({}, {}, {}, {}) failed.", ingress, egress, bandwidth, latency);
199
Naoki Shiota5a056062016-05-05 18:43:59 -0700200 return null;
201 }
202
203 @Override
204 public OpticalConnectivityId setupPath(Path path, Bandwidth bandwidth, Duration latency) {
205 checkNotNull(path);
206 log.info("setupPath({}, {}, {})", path, bandwidth, latency);
207
208 // validate optical path
209 List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs = getCrossConnectPoints(path);
210 if (!checkXcPoints(xcPointPairs)) {
211 // Can't setup path if cross connect points are mismatched
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700212 log.error("Failed to setup path because of mismatched cross connect points.");
Naoki Shiota5a056062016-05-05 18:43:59 -0700213 return null;
214 }
215
216 OpticalConnectivity connectivity = createConnectivity(path, bandwidth, latency);
217
218 // create intents from cross connect points and set connectivity information
219 List<Intent> intents = createIntents(xcPointPairs, connectivity);
220
221 // store cross connect port usage
222 path.links().stream().filter(this::isCrossConnectLink)
223 .forEach(usedCrossConnectLinks::add);
224
225 // Submit the intents
226 for (Intent i : intents) {
227 intentService.submit(i);
228 log.debug("Submitted an intent: {}", i);
229 }
230
231 return connectivity.id();
232 }
233
234 private OpticalConnectivity createConnectivity(Path path, Bandwidth bandwidth, Duration latency) {
235 OpticalConnectivityId id = OpticalConnectivityId.of(idCounter.getAndIncrement());
236 OpticalConnectivity connectivity = new OpticalConnectivity(id, path, bandwidth, latency);
237
Naoki Shiota5a056062016-05-05 18:43:59 -0700238 // store connectivity information
239 connectivities.put(connectivity.id(), connectivity);
240
241 return connectivity;
242 }
243
244 @Override
245 public boolean removeConnectivity(OpticalConnectivityId id) {
246 log.info("removeConnectivity({})", id);
247 OpticalConnectivity connectivity = connectivities.remove(id);
248
249 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700250 log.info("OpticalConnectivity with id {} not found.", id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700251 return false;
252 }
253
254 // TODO withdraw intent only if all of connectivities that use the optical path are withdrawn
255 connectivity.getRealizingLinks().forEach(l -> {
256 Intent intent = intentService.getIntent(l.realizingIntentKey());
257 intentService.withdraw(intent);
258 });
259
260 return true;
261 }
262
263 @Override
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700264 public Optional<List<Link>> getPath(OpticalConnectivityId id) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700265 OpticalConnectivity connectivity = connectivities.get(id);
266 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700267 log.info("OpticalConnectivity with id {} not found.", id);
268 return Optional.empty();
Naoki Shiota5a056062016-05-05 18:43:59 -0700269 }
270
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700271 return Optional.of(ImmutableList.copyOf(connectivity.links()));
Naoki Shiota5a056062016-05-05 18:43:59 -0700272 }
273
274 /**
275 * Returns list of (optical, packet) pairs of cross connection points of missing optical path sections.
276 *
277 * Scans the given multi-layer path and looks for sections that use cross connect links.
278 * The ingress and egress points in the optical layer are combined to the packet layer ports, and
279 * are returned in a list.
280 *
281 * @param path the multi-layer path
282 * @return List of cross connect link's (packet port, optical port) pairs
283 */
284 private List<Pair<ConnectPoint, ConnectPoint>> getCrossConnectPoints(Path path) {
285 List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs = new LinkedList<>();
286 boolean scanning = false;
287
288 for (Link link : path.links()) {
289 if (!isCrossConnectLink(link)) {
290 continue;
291 }
292
293 if (scanning) {
294 // link.src() is packet, link.dst() is optical
295 xcPointPairs.add(Pair.of(checkNotNull(link.src()), checkNotNull(link.dst())));
296 scanning = false;
297 } else {
298 // link.src() is optical, link.dst() is packet
299 xcPointPairs.add(Pair.of(checkNotNull(link.dst()), checkNotNull(link.src())));
300 scanning = true;
301 }
302 }
303
304 return xcPointPairs;
305 }
306
307 /**
308 * Checks if optical cross connect points are of same type.
309 *
310 * @param xcPointPairs list of cross connection points
311 * @return true if cross connect point pairs are of same type, false otherwise
312 */
313 private boolean checkXcPoints(List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs) {
314 checkArgument(xcPointPairs.size() % 2 == 0);
315
316 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = xcPointPairs.iterator();
317
318 while (itr.hasNext()) {
319 // checkArgument at start ensures we'll always have pairs of connect points
320 Pair<ConnectPoint, ConnectPoint> src = itr.next();
321 Pair<ConnectPoint, ConnectPoint> dst = itr.next();
322
323 Device.Type srcType = deviceService.getDevice(src.getKey().deviceId()).type();
324 Device.Type dstType = deviceService.getDevice(dst.getKey().deviceId()).type();
325
326 // Only support connections between identical port types
327 if (srcType != dstType) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700328 log.warn("Unsupported mix of cross connect points : {}, {}", srcType, dstType);
Naoki Shiota5a056062016-05-05 18:43:59 -0700329 return false;
330 }
331 }
332
333 return true;
334 }
335
336 /**
337 * Scans the list of cross connection points and returns a list of optical connectivity intents.
338 * During the process, store intent ID and its realizing link information to given connectivity object.
339 *
340 * @param xcPointPairs list of cross connection points
341 * @return list of optical connectivity intents
342 */
343 private List<Intent> createIntents(List<Pair<ConnectPoint, ConnectPoint>> xcPointPairs,
344 OpticalConnectivity connectivity) {
345 checkArgument(xcPointPairs.size() % 2 == 0);
346
347 List<Intent> intents = new LinkedList<>();
348 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = xcPointPairs.iterator();
349
350 while (itr.hasNext()) {
351 // checkArgument at start ensures we'll always have pairs of connect points
352 Pair<ConnectPoint, ConnectPoint> src = itr.next();
353 Pair<ConnectPoint, ConnectPoint> dst = itr.next();
354
355 Port srcPort = deviceService.getPort(src.getKey().deviceId(), src.getKey().port());
356 Port dstPort = deviceService.getPort(dst.getKey().deviceId(), dst.getKey().port());
357
358 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700359 OduCltPort srcOCPort = (OduCltPort) srcPort;
360 OduCltPort dstOCPort = (OduCltPort) dstPort;
361 if (!srcOCPort.signalType().equals(dstOCPort.signalType())) {
362 continue;
363 }
364
Naoki Shiota5a056062016-05-05 18:43:59 -0700365 // Create OTN circuit
366 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
367 .appId(appId)
368 .src(src.getKey())
369 .dst(dst.getKey())
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700370 .signalType(srcOCPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700371 .bidirectional(true)
372 .build();
373 intents.add(circuitIntent);
374 PacketLinkRealizedByOptical pLink = PacketLinkRealizedByOptical.create(src.getValue(), dst.getValue(),
375 circuitIntent);
376 connectivity.addRealizingLink(pLink);
377 linkPathMap.put(pLink, connectivity);
378 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700379 OchPort srcOchPort = (OchPort) srcPort;
380 OchPort dstOchPort = (OchPort) dstPort;
381 if (!srcOchPort.signalType().equals(dstOchPort.signalType())) {
382 continue;
383 }
384
Naoki Shiota5a056062016-05-05 18:43:59 -0700385 // Create lightpath
Naoki Shiota5a056062016-05-05 18:43:59 -0700386 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.builder()
387 .appId(appId)
388 .src(src.getKey())
389 .dst(dst.getKey())
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700390 .signalType(srcOchPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700391 .bidirectional(true)
392 .build();
393 intents.add(opticalIntent);
394 PacketLinkRealizedByOptical pLink = PacketLinkRealizedByOptical.create(src.getValue(), dst.getValue(),
395 opticalIntent);
396 connectivity.addRealizingLink(pLink);
397 linkPathMap.put(pLink, connectivity);
398 } else {
399 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
400 return Collections.emptyList();
401 }
402 }
403
404 return intents;
405 }
406
407 /**
408 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
409 *
410 * @param type device type
411 * @return true if in packet layer, false otherwise
412 */
413 private boolean isPacketLayer(Device.Type type) {
414 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
415 }
416
417 /**
418 * Verifies if given device type is in packet layer, i.e., switch or router device.
419 *
420 * @param type device type
421 * @return true if in packet layer, false otherwise
422 */
423 private boolean isTransportLayer(Device.Type type) {
424 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
425 }
426
427 /**
428 * Verifies if given link forms a cross-connection between packet and optical layer.
429 *
430 * @param link the link
431 * @return true if the link is a cross-connect link, false otherwise
432 */
433 private boolean isCrossConnectLink(Link link) {
434 if (link.type() != Link.Type.OPTICAL) {
435 return false;
436 }
437
438 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
439 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
440
441 return src != dst &&
442 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
443 }
444
445 /**
446 * Updates bandwidth resource of given connect point.
447 * @param cp Connect point
448 * @param bandwidth New bandwidth
449 */
450 private void updatePortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
451 NodeId localNode = clusterService.getLocalNode().id();
452 NodeId sourceMaster = mastershipService.getMasterFor(cp.deviceId());
453 if (localNode.equals(sourceMaster)) {
454 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
455 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
456 bwCapacity.capacity(bandwidth).apply();
457 }
458 }
459
460 /**
461 * Updates usage information of bandwidth based on connectivity which is established.
462 * @param connectivity Optical connectivity
463 */
464 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiotacb744db2016-05-13 19:32:35 -0700465 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700466
467 List<Link> links = connectivity.links();
468
469 List<Resource> resources = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
470 .filter(cp -> !isTransportLayer(deviceService.getDevice(cp.deviceId()).type()))
471 .map(cp -> Resources.continuous(cp.deviceId(), cp.port(),
472 Bandwidth.class).resource(connectivity.bandwidth().bps()))
473 .collect(Collectors.toList());
474
Naoki Shiotacb744db2016-05-13 19:32:35 -0700475 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
476 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700477 if (allocations.isEmpty()) {
478 log.warn("Failed to allocate bandwidth {} to {}",
479 connectivity.bandwidth().bps(), resources);
480 // TODO any recovery?
481 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700482 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700483 }
484
485 /**
486 * Release bandwidth allocated by given connectivity.
487 * @param connectivity Optical connectivity
488 */
489 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiotacb744db2016-05-13 19:32:35 -0700490 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700491
Naoki Shiotacb744db2016-05-13 19:32:35 -0700492 log.debug("releasing bandwidth allocated to {}", connectivityId);
493 if (!resourceService.release(connectivityId)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700494 log.warn("Failed to release bandwidth allocated to {}",
Naoki Shiotacb744db2016-05-13 19:32:35 -0700495 connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700496 // TODO any recovery?
497 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700498 log.debug("DONE releasing bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700499 }
500
501 private class BandwidthLinkWeight implements LinkWeight {
502 private Bandwidth bandwidth = null;
503
504 public BandwidthLinkWeight(Bandwidth bandwidth) {
505 this.bandwidth = bandwidth;
506 }
507
508 @Override
509 public double weight(TopologyEdge edge) {
510 Link l = edge.link();
511
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700512 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700513 if (l.state() == Link.State.INACTIVE) {
514 return -1.0;
515 }
516
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700517 // Avoid cross connect links with used ports
Naoki Shiota5a056062016-05-05 18:43:59 -0700518 if (isCrossConnectLink(l) && usedCrossConnectLinks.contains(l)) {
519 return -1.0;
520 }
521
522 // Check availability of bandwidth
523 if (bandwidth != null) {
524 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
525 return 1.0;
526 } else {
527 return -1.0;
528 }
529 } else {
530 // TODO needs to differentiate optical and packet?
531 if (l.type() == Link.Type.OPTICAL) {
532 // Transport links
533 return 1.0;
534 } else {
535 // Packet links
536 return 1.0;
537 }
538 }
539 }
540
541 private boolean hasEnoughBandwidth(ConnectPoint cp) {
542 if (cp.elementId() instanceof DeviceId) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700543 Device device = deviceService.getDevice(cp.deviceId());
544 Device.Type type = device.type();
545
Naoki Shiota5a056062016-05-05 18:43:59 -0700546 if (isTransportLayer(type)) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700547 // Check if the port has enough capacity
548 Port port = deviceService.getPort(cp.deviceId(), cp.port());
549 if (port instanceof OduCltPort || port instanceof OchPort) {
550 // Port with capacity
551 return bandwidth.bps() < port.portSpeed() * 1000000.0;
552 } else {
553 // Port without valid capacity (OMS port, etc.)
554 return true;
555 }
556 } else {
557 // Check if enough amount of bandwidth resource remains
558 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
559 .resource(bandwidth.bps());
560 return resourceService.isAvailable(resource);
Naoki Shiota5a056062016-05-05 18:43:59 -0700561 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700562 }
563 return false;
564 }
565 }
566
567
568 public class InternalIntentListener implements IntentListener {
569 @Override
570 public void event(IntentEvent event) {
571 switch (event.type()) {
572 case INSTALLED:
573 log.info("Intent {} installed.", event.subject());
574 updateCrossConnectLink(event.subject());
575 break;
576 case WITHDRAWN:
577 log.info("Intent {} withdrawn.", event.subject());
578 removeCrossConnectLinks(event.subject());
579 break;
580 case FAILED:
581 log.info("Intent {} failed.", event.subject());
582 break;
583 default:
584 break;
585 }
586 }
587
588 private void updateCrossConnectLink(Intent intent) {
589 linkPathMap.entrySet().stream()
590 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
591 .forEach(e -> {
592 ConnectPoint packetSrc = e.getKey().src();
593 ConnectPoint packetDst = e.getKey().dst();
594 Bandwidth bw = e.getKey().bandwidth();
595 // Updates bandwidth of packet ports
596 updatePortBandwidth(packetSrc, bw);
597 updatePortBandwidth(packetDst, bw);
598
599 OpticalConnectivity connectivity = e.getValue();
600 connectivity.setLinkEstablished(packetSrc, packetDst);
601
602 if (e.getValue().isAllRealizingLinkEstablished()) {
603 updateBandwidthUsage(connectivity);
604
605 // Notifies listeners if all links are established
606 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, e.getValue().id()));
607 }
608 });
609 }
610
611 private void removeCrossConnectLinks(Intent intent) {
612 ConnectPoint src, dst;
613
614 if (intent instanceof OpticalCircuitIntent) {
615 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
616 src = circuit.getSrc();
617 dst = circuit.getDst();
618 } else if (intent instanceof OpticalConnectivityIntent) {
619 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
620 src = conn.getSrc();
621 dst = conn.getDst();
622 } else {
623 return;
624 }
625
626 removeXcLinkUsage(src);
627 removeXcLinkUsage(dst);
628
629 // Set bandwidth of 0 to cross connect ports
630 Bandwidth bw = Bandwidth.bps(0);
631 linkPathMap.entrySet().stream()
632 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
633 .forEach(e -> {
634 ConnectPoint packetSrc = e.getKey().src();
635 ConnectPoint packetDst = e.getKey().dst();
636 // Updates bandwidth of packet ports
637 updatePortBandwidth(packetSrc, bw);
638 updatePortBandwidth(packetDst, bw);
639 OpticalConnectivity connectivity = e.getValue();
640 connectivity.setLinkRemoved(packetSrc, packetDst);
641
642 // Notifies listeners if all links are gone
643 if (e.getValue().isAllRealizingLinkNotEstablished()) {
644 releaseBandwidthUsage(connectivity);
645 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, e.getValue().id()));
646 }
647 });
648 }
649
650 private void removeXcLinkUsage(ConnectPoint cp) {
651 Optional<Link> link = linkService.getLinks(cp).stream()
652 .filter(usedCrossConnectLinks::contains)
653 .findAny();
654
655 if (!link.isPresent()) {
656 log.warn("Cross connect point {} has no cross connect link.", cp);
657 return;
658 }
659
660 usedCrossConnectLinks.remove(link.get());
661 }
662 }
663
664
665 private class InternalLinkListener implements LinkListener {
666
667 @Override
668 public void event(LinkEvent event) {
669 switch (event.type()) {
670 case LINK_REMOVED:
671 Link link = event.subject();
672 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
673 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
674 .collect(Collectors.toSet());
675
676 pLinks.forEach(l -> {
677 OpticalConnectivity c = linkPathMap.get(l);
678 // Notifies listeners if all links are gone
679 if (c.isAllRealizingLinkNotEstablished()) {
680 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, c.id()));
681 }
682 linkPathMap.remove(l);
683 });
684 default:
685 break;
686 }
687 }
688 }
689}
690