blob: 1a0b54f46a52464307ede4d3e6c3f4cfa6420604 [file] [log] [blame]
Naoki Shiota5a056062016-05-05 18:43:59 -07001/*
Brian O'Connor0a4e6742016-09-15 23:03:10 -07002 * Copyright 2016-present Open Networking Laboratory
Naoki Shiota5a056062016-05-05 18:43:59 -07003 *
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;
Naoki Shiota5a056062016-05-05 18:43:59 -070020import org.apache.commons.lang3.tuple.Pair;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.util.Bandwidth;
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -080028import org.onlab.util.GuavaCollectors;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070029import org.onlab.util.KryoNamespace;
Naoki Shiota5a056062016-05-05 18:43:59 -070030import org.onosproject.cluster.ClusterService;
Naoki Shiota5a056062016-05-05 18:43:59 -070031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Naoki Shiota0d2943e2016-05-13 18:53:21 -070033import org.onosproject.event.ListenerTracker;
34import org.onosproject.net.optical.OchPort;
35import org.onosproject.net.optical.OduCltPort;
Naoki Shiota5a056062016-05-05 18:43:59 -070036import org.onosproject.newoptical.api.OpticalConnectivityId;
37import org.onosproject.newoptical.api.OpticalPathEvent;
38import org.onosproject.newoptical.api.OpticalPathListener;
39import org.onosproject.newoptical.api.OpticalPathService;
40import org.onosproject.event.AbstractListenerManager;
41import org.onosproject.mastership.MastershipService;
Naoki Shiota5a056062016-05-05 18:43:59 -070042import org.onosproject.net.ConnectPoint;
43import org.onosproject.net.Device;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Link;
Naoki Shiota5a056062016-05-05 18:43:59 -070046import org.onosproject.net.Path;
47import org.onosproject.net.Port;
48import org.onosproject.net.config.NetworkConfigService;
49import org.onosproject.net.device.DeviceService;
50import org.onosproject.net.intent.Intent;
51import org.onosproject.net.intent.IntentEvent;
Naoki Shiota5a056062016-05-05 18:43:59 -070052import org.onosproject.net.intent.IntentListener;
53import org.onosproject.net.intent.IntentService;
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -070054import org.onosproject.net.intent.Key;
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;
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -080061import org.onosproject.net.config.basics.BasicLinkConfig;
Naoki Shiota5a056062016-05-05 18:43:59 -070062import org.onosproject.net.resource.ContinuousResource;
63import org.onosproject.net.resource.Resource;
64import org.onosproject.net.resource.ResourceAllocation;
65import org.onosproject.net.resource.ResourceService;
66import org.onosproject.net.resource.Resources;
67import org.onosproject.net.topology.LinkWeight;
68import org.onosproject.net.topology.PathService;
69import org.onosproject.net.topology.TopologyEdge;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070070import org.onosproject.store.serializers.KryoNamespaces;
Naoki Shiota5a056062016-05-05 18:43:59 -070071import org.onosproject.store.service.AtomicCounter;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070072import org.onosproject.store.service.ConsistentMap;
73import org.onosproject.store.service.DistributedSet;
74import org.onosproject.store.service.MapEvent;
75import org.onosproject.store.service.MapEventListener;
76import org.onosproject.store.service.Serializer;
Naoki Shiota5a056062016-05-05 18:43:59 -070077import org.onosproject.store.service.StorageService;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070078import org.onosproject.store.service.Versioned;
Naoki Shiota5a056062016-05-05 18:43:59 -070079import org.slf4j.Logger;
80import org.slf4j.LoggerFactory;
81
82import java.time.Duration;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070083import java.util.ArrayList;
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -080084import java.util.Collection;
Naoki Shiota5a056062016-05-05 18:43:59 -070085import java.util.Collections;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070086import java.util.HashMap;
87import java.util.HashSet;
Naoki Shiota5a056062016-05-05 18:43:59 -070088import java.util.Iterator;
89import java.util.LinkedList;
90import java.util.List;
91import java.util.Map;
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -070092import java.util.Map.Entry;
Naoki Shiota5a056062016-05-05 18:43:59 -070093import java.util.Optional;
94import java.util.Set;
Naoki Shiota5a056062016-05-05 18:43:59 -070095import java.util.stream.Collectors;
96import java.util.stream.Stream;
97
98import static com.google.common.base.Preconditions.checkArgument;
99import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800100import static org.onosproject.net.LinkKey.linkKey;
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700101import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
Naoki Shiota5a056062016-05-05 18:43:59 -0700102
103/**
104 * Main component to configure optical connectivity.
105 */
106@Beta
107@Service
108@Component(immediate = true)
109public class OpticalPathProvisioner
110 extends AbstractListenerManager<OpticalPathEvent, OpticalPathListener>
111 implements OpticalPathService {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800112
Naoki Shiota5a056062016-05-05 18:43:59 -0700113 protected static final Logger log = LoggerFactory.getLogger(OpticalPathProvisioner.class);
114
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800115 /**
116 * Bandwidth representing no bandwidth requirement specified.
117 */
118 private static final Bandwidth NO_BW_REQUIREMENT = Bandwidth.bps(0);
119
Naoki Shiota5a056062016-05-05 18:43:59 -0700120 private static final String OPTICAL_CONNECTIVITY_ID_COUNTER = "optical-connectivity-id";
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700121 private static final String LINKPATH_MAP_NAME = "newoptical-linkpath";
122 private static final String CONNECTIVITY_MAP_NAME = "newoptical-connectivity";
123 private static final String CROSSCONNECTLINK_SET_NAME = "newoptical-crossconnectlink";
Naoki Shiota5a056062016-05-05 18:43:59 -0700124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected IntentService intentService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected PathService pathService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected CoreService coreService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected LinkService linkService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected MastershipService mastershipService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected ClusterService clusterService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected DeviceService deviceService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
147 protected StorageService storageService;
148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 protected NetworkConfigService networkConfigService;
151
152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected ResourceService resourceService;
154
155
156 private ApplicationId appId;
157
158 private AtomicCounter idCounter;
159
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700160 private ListenerTracker listeners;
Naoki Shiota5a056062016-05-05 18:43:59 -0700161
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700162 private InternalStoreListener storeListener = new InternalStoreListener();
Naoki Shiota5a056062016-05-05 18:43:59 -0700163
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800164 /**
165 * Map from packet-layer link expected to be realized by some optical Intent to
166 * OpticalConnectivity (~=top level intent over multi-layer topology).
167 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700168 private ConsistentMap<PacketLinkRealizedByOptical, OpticalConnectivity> linkPathMap;
Naoki Shiota5a056062016-05-05 18:43:59 -0700169
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700170 private ConsistentMap<OpticalConnectivityId, OpticalConnectivity> connectivityMap;
171
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800172 // FIXME in the long run. This is effectively app's own resource subsystem
173 /**
174 * Set of cross connect link currently used.
175 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700176 private DistributedSet<Link> usedCrossConnectLinkSet;
177
178 private static final KryoNamespace.Builder LINKPATH_SERIALIZER = KryoNamespace.newBuilder()
179 .register(KryoNamespaces.API)
180 .register(PacketLinkRealizedByOptical.class)
181 .register(OpticalConnectivityId.class)
182 .register(OpticalConnectivity.class);
183
184 private static final KryoNamespace.Builder CONNECTIVITY_SERIALIZER = KryoNamespace.newBuilder()
185 .register(KryoNamespaces.API)
Yuta HIGUCHI0086cf82016-07-18 22:49:45 -0700186 .register(PacketLinkRealizedByOptical.class)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700187 .register(OpticalConnectivityId.class)
188 .register(OpticalConnectivity.class);
189
190 private static final KryoNamespace.Builder CROSSCONNECTLINKS_SERIALIZER = KryoNamespace.newBuilder()
191 .register(KryoNamespaces.API);
Naoki Shiota5a056062016-05-05 18:43:59 -0700192
193 @Activate
194 protected void activate() {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700195 deviceService = opticalView(deviceService);
Naoki Shiota5a056062016-05-05 18:43:59 -0700196 appId = coreService.registerApplication("org.onosproject.newoptical");
197
Naoki Shiota03c29e12016-05-16 16:58:07 -0700198 idCounter = storageService.getAtomicCounter(OPTICAL_CONNECTIVITY_ID_COUNTER);
Naoki Shiota5a056062016-05-05 18:43:59 -0700199
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700200 linkPathMap = storageService.<PacketLinkRealizedByOptical, OpticalConnectivity>consistentMapBuilder()
201 .withSerializer(Serializer.using(LINKPATH_SERIALIZER.build()))
202 .withName(LINKPATH_MAP_NAME)
203 .withApplicationId(appId)
204 .build();
205
206 connectivityMap = storageService.<OpticalConnectivityId, OpticalConnectivity>consistentMapBuilder()
207 .withSerializer(Serializer.using(CONNECTIVITY_SERIALIZER.build()))
208 .withName(CONNECTIVITY_MAP_NAME)
209 .withApplicationId(appId)
210 .build();
211
212 usedCrossConnectLinkSet = storageService.<Link>setBuilder()
213 .withSerializer(Serializer.using(CROSSCONNECTLINKS_SERIALIZER.build()))
214 .withName(CROSSCONNECTLINK_SET_NAME)
215 .withApplicationId(appId)
216 .build()
217 .asDistributedSet();
218
Naoki Shiota5a056062016-05-05 18:43:59 -0700219 eventDispatcher.addSink(OpticalPathEvent.class, listenerRegistry);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700220
221 listeners = new ListenerTracker();
222 listeners.addListener(linkService, new InternalLinkListener())
223 .addListener(intentService, new InternalIntentListener());
Naoki Shiota5a056062016-05-05 18:43:59 -0700224
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700225 linkPathMap.addListener(storeListener);
226
Naoki Shiota5a056062016-05-05 18:43:59 -0700227 log.info("Started");
228 }
229
230 @Deactivate
231 protected void deactivate() {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700232 linkPathMap.removeListener(storeListener);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700233 listeners.removeListeners();
234 eventDispatcher.removeSink(OpticalPathEvent.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700235
236 log.info("Stopped");
237 }
238
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -0800239 @Override
240 public Collection<OpticalConnectivity> listConnectivity() {
241 return connectivityMap.values().stream()
242 .map(Versioned::value)
243 .collect(GuavaCollectors.toImmutableList());
244 }
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -0700245
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700246 @Override
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -0700247 public Set<Key> listIntents(OpticalConnectivityId id) {
248 return linkPathMap.entrySet().stream()
249 .filter(ent -> id.equals(ent.getValue().value().id()))
250 .map(Entry::getKey)
251 .map(PacketLinkRealizedByOptical::realizingIntentKey)
252 .collect(Collectors.toSet());
253 }
254
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800255 /*
256 * Request packet-layer connectivity between specified ports,
257 * over packet-optical multi-layer infrastructure.
258 *
259 * Functionality-wise this is effectively submitting Packet-Optical
260 * multi-layer P2P Intent.
261 *
262 * It computes multi-layer path meeting specified constraint,
263 * and calls setupPath.
264 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700265 @Override
266 public OpticalConnectivityId setupConnectivity(ConnectPoint ingress, ConnectPoint egress,
267 Bandwidth bandwidth, Duration latency) {
268 checkNotNull(ingress);
269 checkNotNull(egress);
270 log.info("setupConnectivity({}, {}, {}, {})", ingress, egress, bandwidth, latency);
271
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800272 bandwidth = (bandwidth == null) ? NO_BW_REQUIREMENT : bandwidth;
Naoki Shiota5a056062016-05-05 18:43:59 -0700273
274 Set<Path> paths = pathService.getPaths(ingress.deviceId(), egress.deviceId(),
275 new BandwidthLinkWeight(bandwidth));
276 if (paths.isEmpty()) {
277 log.warn("Unable to find multi-layer path.");
278 return null;
279 }
280
281 // Search path with available cross connect points
282 for (Path path : paths) {
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700283 // Path service calculates from node to node, we're only interested in port to port
284 if (!path.src().equals(ingress) || !path.dst().equals(egress)) {
285 continue;
286 }
287
Naoki Shiota5a056062016-05-05 18:43:59 -0700288 OpticalConnectivityId id = setupPath(path, bandwidth, latency);
289 if (id != null) {
290 log.info("Assigned OpticalConnectivityId: {}", id);
291 return id;
292 }
293 }
294
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800295 log.error("setupConnectivity({}, {}, {}, {}) failed.", ingress, egress, bandwidth, latency);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700296
Naoki Shiota5a056062016-05-05 18:43:59 -0700297 return null;
298 }
299
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800300 /*
301 * Given a multi-layer path,
302 * compute a set of segments which requires
303 * OpticalConnectivity(~=OpticalConnectivityIntent or OpticalCircuitPath)
304 * to provide packet-layer connectivity.
305 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700306 @Override
307 public OpticalConnectivityId setupPath(Path path, Bandwidth bandwidth, Duration latency) {
308 checkNotNull(path);
Yuta HIGUCHI8fc32f82017-03-14 22:12:42 -0700309 log.debug("setupPath({}, {}, {})", path, bandwidth, latency);
Naoki Shiota5a056062016-05-05 18:43:59 -0700310
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700311 // map of cross connect points (optical port -> packet port)
312 Map<ConnectPoint, ConnectPoint> crossConnectPointMap = new HashMap<>();
313
314 // list of (src, dst) pair of optical ports between which optical path should be installed
315 List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints = new ArrayList<>();
316
317 // Scan path to find pairs of connect points between which optical intent is installed
318 // opticalSrcPort works as a flag parameter to show scanning status
319 ConnectPoint opticalSrcPort = null;
320 for (Link link : path.links()) {
321 if (!isCrossConnectLink(link)) {
322 continue;
323 }
324
325 if (opticalSrcPort != null) {
326 // opticalSrcPort!=null means src port was already found
327 // in this case link.src() is optical layer, and link.dst() is packet layer
328
329 // Check if types of src port and dst port matches
330 Device srcDevice = checkNotNull(deviceService.getDevice(opticalSrcPort.deviceId()),
331 "Unknown device ID");
332 Device dstDevice = checkNotNull(deviceService.getDevice(link.src().deviceId()),
333 "Unknown device ID");
334 if (srcDevice.type() != dstDevice.type()) {
335 log.error("Unsupported mix of cross connect points : {}, {}",
336 srcDevice.type(), dstDevice.type());
337 return null;
338 }
339
340 // Update cross connect points map
341 crossConnectPointMap.put(link.src(), link.dst());
342
343 // Add optical ports pair to list
344 crossConnectPoints.add(Pair.of(opticalSrcPort, link.src()));
345
346 // Reset flag parameter
347 opticalSrcPort = null;
348 } else {
349 // opticalSrcPort==null means src port was not found yet
350 // in this case link.src() is packet layer, and link.dst() is optical layer
351
352 // Update cross connect points map
353 crossConnectPointMap.put(link.dst(), link.src());
354 // Set opticalSrcPort to src of link (optical port)
355 opticalSrcPort = link.dst();
356 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700357 }
358
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700359 // create intents from cross connect points
360 List<Intent> intents = createIntents(crossConnectPoints);
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800361 if (intents.isEmpty()) {
362 log.error("No intents produced from {}", crossConnectPoints);
363 return null;
364 }
365
Naoki Shiota5a056062016-05-05 18:43:59 -0700366
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700367 // create set of PacketLinkRealizedByOptical
368 Set<PacketLinkRealizedByOptical> packetLinks = createPacketLinkSet(crossConnectPoints,
369 intents, crossConnectPointMap);
370
371 // create OpticalConnectivity object and store information to distributed store
372 OpticalConnectivity connectivity = createConnectivity(path, bandwidth, latency, packetLinks);
Naoki Shiota5a056062016-05-05 18:43:59 -0700373
374 // store cross connect port usage
375 path.links().stream().filter(this::isCrossConnectLink)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700376 .forEach(usedCrossConnectLinkSet::add);
Naoki Shiota5a056062016-05-05 18:43:59 -0700377
378 // Submit the intents
379 for (Intent i : intents) {
380 intentService.submit(i);
381 log.debug("Submitted an intent: {}", i);
382 }
383
384 return connectivity.id();
385 }
386
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700387 private OpticalConnectivity createConnectivity(Path path, Bandwidth bandwidth, Duration latency,
388 Set<PacketLinkRealizedByOptical> links) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700389 OpticalConnectivityId id = OpticalConnectivityId.of(idCounter.getAndIncrement());
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700390 OpticalConnectivity connectivity = new OpticalConnectivity(id, path.links(), bandwidth, latency,
391 links, Collections.emptySet());
392
393 links.forEach(l -> linkPathMap.put(l, connectivity));
Naoki Shiota5a056062016-05-05 18:43:59 -0700394
Naoki Shiota5a056062016-05-05 18:43:59 -0700395 // store connectivity information
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700396 connectivityMap.put(connectivity.id(), connectivity);
Naoki Shiota5a056062016-05-05 18:43:59 -0700397
398 return connectivity;
399 }
400
401 @Override
402 public boolean removeConnectivity(OpticalConnectivityId id) {
403 log.info("removeConnectivity({})", id);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700404 Versioned<OpticalConnectivity> connectivity = connectivityMap.remove(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700405
406 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700407 log.info("OpticalConnectivity with id {} not found.", id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700408 return false;
409 }
410
411 // TODO withdraw intent only if all of connectivities that use the optical path are withdrawn
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700412 connectivity.value().getRealizingLinks().forEach(l -> {
Naoki Shiota5a056062016-05-05 18:43:59 -0700413 Intent intent = intentService.getIntent(l.realizingIntentKey());
414 intentService.withdraw(intent);
415 });
416
417 return true;
418 }
419
420 @Override
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700421 public Optional<List<Link>> getPath(OpticalConnectivityId id) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700422 Versioned<OpticalConnectivity> connectivity = connectivityMap.get(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700423 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700424 log.info("OpticalConnectivity with id {} not found.", id);
425 return Optional.empty();
Naoki Shiota5a056062016-05-05 18:43:59 -0700426 }
427
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700428 return Optional.of(ImmutableList.copyOf(connectivity.value().links()));
Naoki Shiota5a056062016-05-05 18:43:59 -0700429 }
430
431 /**
432 * Scans the list of cross connection points and returns a list of optical connectivity intents.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700433 * During the process, save information about packet links to given set.
Naoki Shiota5a056062016-05-05 18:43:59 -0700434 *
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700435 * @param crossConnectPoints list of (src, dst) pair between which optical path will be set up
Naoki Shiota5a056062016-05-05 18:43:59 -0700436 * @return list of optical connectivity intents
437 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700438 private List<Intent> createIntents(List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700439 List<Intent> intents = new LinkedList<>();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700440 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = crossConnectPoints.iterator();
Naoki Shiota5a056062016-05-05 18:43:59 -0700441
442 while (itr.hasNext()) {
443 // checkArgument at start ensures we'll always have pairs of connect points
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700444 Pair<ConnectPoint, ConnectPoint> next = itr.next();
445 ConnectPoint src = next.getLeft();
446 ConnectPoint dst = next.getRight();
Naoki Shiota5a056062016-05-05 18:43:59 -0700447
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700448 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
449 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
Naoki Shiota5a056062016-05-05 18:43:59 -0700450
451 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700452 OduCltPort srcOCPort = (OduCltPort) srcPort;
453 OduCltPort dstOCPort = (OduCltPort) dstPort;
454 if (!srcOCPort.signalType().equals(dstOCPort.signalType())) {
455 continue;
456 }
457
Naoki Shiota5a056062016-05-05 18:43:59 -0700458 // Create OTN circuit
459 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
460 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700461 .src(src)
462 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700463 .signalType(srcOCPort.signalType())
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700464 .bidirectional(false)
Naoki Shiota5a056062016-05-05 18:43:59 -0700465 .build();
466 intents.add(circuitIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700467 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700468 OchPort srcOchPort = (OchPort) srcPort;
469 OchPort dstOchPort = (OchPort) dstPort;
470 if (!srcOchPort.signalType().equals(dstOchPort.signalType())) {
471 continue;
472 }
473
Naoki Shiota5a056062016-05-05 18:43:59 -0700474 // Create lightpath
Naoki Shiota5a056062016-05-05 18:43:59 -0700475 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.builder()
476 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700477 .src(src)
478 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700479 .signalType(srcOchPort.signalType())
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700480 .bidirectional(false)
Naoki Shiota5a056062016-05-05 18:43:59 -0700481 .build();
482 intents.add(opticalIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700483 } else {
484 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
485 return Collections.emptyList();
486 }
487 }
488
489 return intents;
490 }
491
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700492 private Set<PacketLinkRealizedByOptical> createPacketLinkSet(List<Pair<ConnectPoint, ConnectPoint>> connectPoints,
493 List<Intent> intents,
494 Map<ConnectPoint, ConnectPoint> crossConnectPoints) {
495 checkArgument(connectPoints.size() == intents.size());
496
497 Set<PacketLinkRealizedByOptical> pLinks = new HashSet<>();
498
499 Iterator<Pair<ConnectPoint, ConnectPoint>> xcPointsItr = connectPoints.iterator();
500 Iterator<Intent> intentItr = intents.iterator();
501 while (xcPointsItr.hasNext()) {
502 Pair<ConnectPoint, ConnectPoint> xcPoints = xcPointsItr.next();
503 Intent intent = intentItr.next();
504
505 ConnectPoint packetSrc = checkNotNull(crossConnectPoints.get(xcPoints.getLeft()));
506 ConnectPoint packetDst = checkNotNull(crossConnectPoints.get(xcPoints.getRight()));
507
508 if (intent instanceof OpticalConnectivityIntent) {
509 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
510 (OpticalConnectivityIntent) intent));
511 } else if (intent instanceof OpticalCircuitIntent) {
512 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
513 (OpticalCircuitIntent) intent));
514 } else {
515 log.warn("Unexpected intent type: {}", intent.getClass());
516 }
517 }
518
519 return pLinks;
520 }
521
Naoki Shiota5a056062016-05-05 18:43:59 -0700522 /**
523 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
524 *
525 * @param type device type
526 * @return true if in packet layer, false otherwise
527 */
528 private boolean isPacketLayer(Device.Type type) {
529 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
530 }
531
532 /**
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800533 * Verifies if given device type is NOT in packet layer, i.e., switch or router device.
Naoki Shiota5a056062016-05-05 18:43:59 -0700534 *
535 * @param type device type
536 * @return true if in packet layer, false otherwise
537 */
538 private boolean isTransportLayer(Device.Type type) {
539 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
540 }
541
542 /**
543 * Verifies if given link forms a cross-connection between packet and optical layer.
544 *
545 * @param link the link
546 * @return true if the link is a cross-connect link, false otherwise
547 */
548 private boolean isCrossConnectLink(Link link) {
549 if (link.type() != Link.Type.OPTICAL) {
550 return false;
551 }
552
553 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
554 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
555
556 return src != dst &&
557 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
558 }
559
560 /**
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800561 * Updates bandwidth resource of given connect point to specified value.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700562 *
Naoki Shiota5a056062016-05-05 18:43:59 -0700563 * @param cp Connect point
564 * @param bandwidth New bandwidth
565 */
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800566 private void setPortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700567 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
568 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
569 bwCapacity.capacity(bandwidth).apply();
Naoki Shiota5a056062016-05-05 18:43:59 -0700570 }
571
572 /**
573 * Updates usage information of bandwidth based on connectivity which is established.
574 * @param connectivity Optical connectivity
575 */
576 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800577 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
578 // no bandwidth requirement, nothing to allocate.
579 return;
580 }
581
Naoki Shiotacb744db2016-05-13 19:32:35 -0700582 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700583
584 List<Link> links = connectivity.links();
585
586 List<Resource> resources = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
587 .filter(cp -> !isTransportLayer(deviceService.getDevice(cp.deviceId()).type()))
588 .map(cp -> Resources.continuous(cp.deviceId(), cp.port(),
589 Bandwidth.class).resource(connectivity.bandwidth().bps()))
590 .collect(Collectors.toList());
591
Naoki Shiotacb744db2016-05-13 19:32:35 -0700592 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
593 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700594 if (allocations.isEmpty()) {
595 log.warn("Failed to allocate bandwidth {} to {}",
596 connectivity.bandwidth().bps(), resources);
597 // TODO any recovery?
598 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700599 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700600 }
601
602 /**
603 * Release bandwidth allocated by given connectivity.
604 * @param connectivity Optical connectivity
605 */
606 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700607 if (connectivity.links().isEmpty()) {
608 return;
Naoki Shiota5a056062016-05-05 18:43:59 -0700609 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800610 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
611 // no bandwidth requirement, nothing to release.
612 return;
613 }
614
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700615
616 // release resource only if this node is the master for link head device
617 if (mastershipService.isLocalMaster(connectivity.links().get(0).src().deviceId())) {
618 OpticalConnectivityId connectivityId = connectivity.id();
619
620 log.debug("releasing bandwidth allocated to {}", connectivityId);
621 if (!resourceService.release(connectivityId)) {
622 log.warn("Failed to release bandwidth allocated to {}",
623 connectivityId);
624 // TODO any recovery?
625 }
626 log.debug("DONE releasing bandwidth for {}", connectivityId);
627 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700628 }
629
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800630 private boolean linkDiscoveryEnabled(ConnectPoint cp) {
631 // FIXME should check Device feature and configuration state.
632
633 // short-term hack for ONS'17 time-frame,
634 // only expect OF device to have link discovery.
Jon Halla3fcf672017-03-28 16:53:22 -0700635 return "of".equals(cp.deviceId().uri().getScheme());
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800636 }
637
638 /**
639 * Returns true if both connect point support for link discovery & enabled.
640 *
641 * @param cp1 port 1
642 * @param cp2 port 2
643 * @return true if both connect point support for link discovery & enabled.
644 */
645 private boolean linkDiscoveryEnabled(ConnectPoint cp1, ConnectPoint cp2) {
646 return linkDiscoveryEnabled(cp1) && linkDiscoveryEnabled(cp2);
647 }
648
Naoki Shiota5a056062016-05-05 18:43:59 -0700649 private class BandwidthLinkWeight implements LinkWeight {
650 private Bandwidth bandwidth = null;
651
652 public BandwidthLinkWeight(Bandwidth bandwidth) {
653 this.bandwidth = bandwidth;
654 }
655
656 @Override
657 public double weight(TopologyEdge edge) {
658 Link l = edge.link();
659
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700660 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700661 if (l.state() == Link.State.INACTIVE) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800662 log.trace("{} is not active", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700663 return -1.0;
664 }
665
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700666 // Avoid cross connect links with used ports
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700667 if (isCrossConnectLink(l) && usedCrossConnectLinkSet.contains(l)) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800668 log.trace("Cross connect {} in use", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700669 return -1.0;
670 }
671
672 // Check availability of bandwidth
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800673 if (bandwidth != null && !NO_BW_REQUIREMENT.equals(bandwidth)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700674 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
675 return 1.0;
676 } else {
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700677 log.trace("Not enough bandwidth on {}", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700678 return -1.0;
679 }
680 } else {
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700681 // Use everything except our own indirect links
682 if (l.type() == Link.Type.INDIRECT) {
683 return -1.0;
Naoki Shiota5a056062016-05-05 18:43:59 -0700684 } else {
Naoki Shiota5a056062016-05-05 18:43:59 -0700685 return 1.0;
686 }
687 }
688 }
689
690 private boolean hasEnoughBandwidth(ConnectPoint cp) {
691 if (cp.elementId() instanceof DeviceId) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700692 Device device = deviceService.getDevice(cp.deviceId());
693 Device.Type type = device.type();
694
Naoki Shiota5a056062016-05-05 18:43:59 -0700695 if (isTransportLayer(type)) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700696 // Check if the port has enough capacity
697 Port port = deviceService.getPort(cp.deviceId(), cp.port());
698 if (port instanceof OduCltPort || port instanceof OchPort) {
699 // Port with capacity
700 return bandwidth.bps() < port.portSpeed() * 1000000.0;
701 } else {
702 // Port without valid capacity (OMS port, etc.)
703 return true;
704 }
705 } else {
706 // Check if enough amount of bandwidth resource remains
707 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
708 .resource(bandwidth.bps());
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800709 try {
710 return resourceService.isAvailable(resource);
711 } catch (Exception e) {
712 log.error("Resource service failed checking availability of {}",
713 resource, e);
714 throw e;
715 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700716 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700717 }
718 return false;
719 }
720 }
721
722
723 public class InternalIntentListener implements IntentListener {
724 @Override
725 public void event(IntentEvent event) {
726 switch (event.type()) {
727 case INSTALLED:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700728 log.debug("Intent {} installed.", event.subject());
Naoki Shiota5a056062016-05-05 18:43:59 -0700729 updateCrossConnectLink(event.subject());
730 break;
731 case WITHDRAWN:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700732 log.debug("Intent {} withdrawn.", event.subject());
Naoki Shiota5a056062016-05-05 18:43:59 -0700733 removeCrossConnectLinks(event.subject());
734 break;
735 case FAILED:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700736 log.debug("Intent {} failed.", event.subject());
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800737 // TODO If it was one of it's own optical Intent,
738 // update link state
739 // TODO If it was packet P2P Intent, call setupConnectivity
Naoki Shiota5a056062016-05-05 18:43:59 -0700740 break;
741 default:
742 break;
743 }
744 }
745
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800746 // TODO rename "CrossConnectLink"?
747 /**
748 * Update packet-layer link/port state once Intent is installed.
749 *
750 * @param intent which reached installed state
751 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700752 private void updateCrossConnectLink(Intent intent) {
753 linkPathMap.entrySet().stream()
754 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
755 .forEach(e -> {
756 ConnectPoint packetSrc = e.getKey().src();
757 ConnectPoint packetDst = e.getKey().dst();
758 Bandwidth bw = e.getKey().bandwidth();
Naoki Shiota5a056062016-05-05 18:43:59 -0700759
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700760 // reflect modification only if packetSrc is local_
761 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
762 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800763 setPortBandwidth(packetSrc, bw);
764 setPortBandwidth(packetDst, bw);
Naoki Shiota5a056062016-05-05 18:43:59 -0700765
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700766 // Updates link status in distributed map
767 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
768 e.getValue().value().setLinkEstablished(packetSrc, packetDst, true));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800769
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800770
771 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
772 injectLink(packetSrc, packetDst);
773 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700774 }
775 });
776 }
777
778 private void removeCrossConnectLinks(Intent intent) {
779 ConnectPoint src, dst;
780
781 if (intent instanceof OpticalCircuitIntent) {
782 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
783 src = circuit.getSrc();
784 dst = circuit.getDst();
785 } else if (intent instanceof OpticalConnectivityIntent) {
786 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
787 src = conn.getSrc();
788 dst = conn.getDst();
789 } else {
790 return;
791 }
792
793 removeXcLinkUsage(src);
794 removeXcLinkUsage(dst);
795
796 // Set bandwidth of 0 to cross connect ports
797 Bandwidth bw = Bandwidth.bps(0);
798 linkPathMap.entrySet().stream()
799 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
800 .forEach(e -> {
801 ConnectPoint packetSrc = e.getKey().src();
802 ConnectPoint packetDst = e.getKey().dst();
Naoki Shiota5a056062016-05-05 18:43:59 -0700803
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700804 // reflect modification only if packetSrc is local_
805 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
806 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800807 setPortBandwidth(packetSrc, bw);
808 setPortBandwidth(packetDst, bw);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700809
810 // Updates link status in distributed map
811 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
812 e.getValue().value().setLinkEstablished(packetSrc, packetDst, false));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800813
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800814
815 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
816 removeInjectedLink(packetSrc, packetDst);
817 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700818 }
819 });
820 }
821
822 private void removeXcLinkUsage(ConnectPoint cp) {
823 Optional<Link> link = linkService.getLinks(cp).stream()
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700824 .filter(usedCrossConnectLinkSet::contains)
Naoki Shiota5a056062016-05-05 18:43:59 -0700825 .findAny();
826
827 if (!link.isPresent()) {
828 log.warn("Cross connect point {} has no cross connect link.", cp);
829 return;
830 }
831
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700832 usedCrossConnectLinkSet.remove(link.get());
Naoki Shiota5a056062016-05-05 18:43:59 -0700833 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800834
835 /**
836 * Injects link between specified packet port.
837 *
838 * @param packetSrc port 1
839 * @param packetDst port 2
840 */
841 private void injectLink(ConnectPoint packetSrc,
842 ConnectPoint packetDst) {
843 // inject expected link or durable link
844 // if packet device cannot advertise packet link
845 try {
846 BasicLinkConfig lnkCfg = networkConfigService
847 .addConfig(linkKey(packetSrc, packetDst),
848 BasicLinkConfig.class);
849 lnkCfg.isAllowed(true);
850 lnkCfg.isDurable(true);
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700851 lnkCfg.type(Link.Type.INDIRECT);
852 lnkCfg.isBidirectional(false);
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800853 lnkCfg.apply();
854 } catch (Exception ex) {
855 log.error("Applying BasicLinkConfig failed", ex);
856 }
857 }
858
859 /**
860 * Removes link injected between specified packet port.
861 *
862 * @param packetSrc port 1
863 * @param packetDst port 2
864 */
865 private void removeInjectedLink(ConnectPoint packetSrc,
866 ConnectPoint packetDst) {
867 // remove expected link or durable link
868 // if packet device cannot monitor packet link
869
870 try {
871 // hack to mark link off-line
872 BasicLinkConfig lnkCfg = networkConfigService
873 .getConfig(linkKey(packetSrc, packetDst),
874 BasicLinkConfig.class);
875 lnkCfg.isAllowed(false);
876 lnkCfg.apply();
877 } catch (Exception ex) {
878 log.error("Applying BasicLinkConfig failed", ex);
879 }
880
881 networkConfigService
882 .removeConfig(linkKey(packetSrc, packetDst),
883 BasicLinkConfig.class);
884 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700885 }
886
887
888 private class InternalLinkListener implements LinkListener {
889
890 @Override
891 public void event(LinkEvent event) {
892 switch (event.type()) {
893 case LINK_REMOVED:
894 Link link = event.subject();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700895 // updates linkPathMap only if src device of link is local
896 if (!mastershipService.isLocalMaster(link.src().deviceId())) {
897 return;
898 }
899
900 // find all packet links that correspond to removed link
Naoki Shiota5a056062016-05-05 18:43:59 -0700901 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
902 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
903 .collect(Collectors.toSet());
904
905 pLinks.forEach(l -> {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700906 // remove found packet links from distributed store
907 linkPathMap.computeIfPresent(l, (plink, conn) -> {
908 // Notifies listeners if all packet links are gone
909 if (conn.isAllRealizingLinkNotEstablished()) {
910 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, conn.id()));
911 }
912 return null;
913 });
Naoki Shiota5a056062016-05-05 18:43:59 -0700914 });
915 default:
916 break;
917 }
918 }
919 }
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700920
921 private class InternalStoreListener
922 implements MapEventListener<PacketLinkRealizedByOptical, OpticalConnectivity> {
923
924 @Override
925 public void event(MapEvent<PacketLinkRealizedByOptical, OpticalConnectivity> event) {
926 switch (event.type()) {
927 case UPDATE:
928 OpticalConnectivity oldConnectivity = event.oldValue().value();
929 OpticalConnectivity newConnectivity = event.newValue().value();
930
931 if (!oldConnectivity.isAllRealizingLinkEstablished() &&
932 newConnectivity.isAllRealizingLinkEstablished()) {
933 // Notifies listeners if all links are established
934 updateBandwidthUsage(newConnectivity);
935 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, newConnectivity.id()));
936 } else if (!oldConnectivity.isAllRealizingLinkNotEstablished() &&
937 newConnectivity.isAllRealizingLinkNotEstablished()) {
938 // Notifies listeners if all links are gone
939 releaseBandwidthUsage(newConnectivity);
940 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, newConnectivity.id()));
941 }
942
943 break;
944 default:
945 break;
946 }
947 }
948
949 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700950}
951