blob: 2200ef047aaeb585cec6b371417505f8219103d9 [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 -070020
21import org.apache.commons.lang3.tuple.Pair;
22import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
28import org.onlab.util.Bandwidth;
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -080029import org.onlab.util.GuavaCollectors;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070030import org.onlab.util.KryoNamespace;
Naoki Shiota5a056062016-05-05 18:43:59 -070031import org.onosproject.cluster.ClusterService;
Naoki Shiota5a056062016-05-05 18:43:59 -070032import 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;
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;
92import java.util.Optional;
93import java.util.Set;
Naoki Shiota5a056062016-05-05 18:43:59 -070094import java.util.stream.Collectors;
95import java.util.stream.Stream;
96
97import static com.google.common.base.Preconditions.checkArgument;
98import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -080099import static org.onosproject.net.LinkKey.linkKey;
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700100import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
Naoki Shiota5a056062016-05-05 18:43:59 -0700101
102/**
103 * Main component to configure optical connectivity.
104 */
105@Beta
106@Service
107@Component(immediate = true)
108public class OpticalPathProvisioner
109 extends AbstractListenerManager<OpticalPathEvent, OpticalPathListener>
110 implements OpticalPathService {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800111
Naoki Shiota5a056062016-05-05 18:43:59 -0700112 protected static final Logger log = LoggerFactory.getLogger(OpticalPathProvisioner.class);
113
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800114 /**
115 * Bandwidth representing no bandwidth requirement specified.
116 */
117 private static final Bandwidth NO_BW_REQUIREMENT = Bandwidth.bps(0);
118
Naoki Shiota5a056062016-05-05 18:43:59 -0700119 private static final String OPTICAL_CONNECTIVITY_ID_COUNTER = "optical-connectivity-id";
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700120 private static final String LINKPATH_MAP_NAME = "newoptical-linkpath";
121 private static final String CONNECTIVITY_MAP_NAME = "newoptical-connectivity";
122 private static final String CROSSCONNECTLINK_SET_NAME = "newoptical-crossconnectlink";
Naoki Shiota5a056062016-05-05 18:43:59 -0700123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected IntentService intentService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected PathService pathService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected CoreService coreService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected LinkService linkService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected MastershipService mastershipService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 protected ClusterService clusterService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 protected DeviceService deviceService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
146 protected StorageService storageService;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
149 protected NetworkConfigService networkConfigService;
150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected ResourceService resourceService;
153
154
155 private ApplicationId appId;
156
157 private AtomicCounter idCounter;
158
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700159 private ListenerTracker listeners;
Naoki Shiota5a056062016-05-05 18:43:59 -0700160
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700161 private InternalStoreListener storeListener = new InternalStoreListener();
Naoki Shiota5a056062016-05-05 18:43:59 -0700162
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800163 /**
164 * Map from packet-layer link expected to be realized by some optical Intent to
165 * OpticalConnectivity (~=top level intent over multi-layer topology).
166 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700167 private ConsistentMap<PacketLinkRealizedByOptical, OpticalConnectivity> linkPathMap;
Naoki Shiota5a056062016-05-05 18:43:59 -0700168
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700169 private ConsistentMap<OpticalConnectivityId, OpticalConnectivity> connectivityMap;
170
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800171 // FIXME in the long run. This is effectively app's own resource subsystem
172 /**
173 * Set of cross connect link currently used.
174 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700175 private DistributedSet<Link> usedCrossConnectLinkSet;
176
177 private static final KryoNamespace.Builder LINKPATH_SERIALIZER = KryoNamespace.newBuilder()
178 .register(KryoNamespaces.API)
179 .register(PacketLinkRealizedByOptical.class)
180 .register(OpticalConnectivityId.class)
181 .register(OpticalConnectivity.class);
182
183 private static final KryoNamespace.Builder CONNECTIVITY_SERIALIZER = KryoNamespace.newBuilder()
184 .register(KryoNamespaces.API)
Yuta HIGUCHI0086cf82016-07-18 22:49:45 -0700185 .register(PacketLinkRealizedByOptical.class)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700186 .register(OpticalConnectivityId.class)
187 .register(OpticalConnectivity.class);
188
189 private static final KryoNamespace.Builder CROSSCONNECTLINKS_SERIALIZER = KryoNamespace.newBuilder()
190 .register(KryoNamespaces.API);
Naoki Shiota5a056062016-05-05 18:43:59 -0700191
192 @Activate
193 protected void activate() {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700194 deviceService = opticalView(deviceService);
Naoki Shiota5a056062016-05-05 18:43:59 -0700195 appId = coreService.registerApplication("org.onosproject.newoptical");
196
Naoki Shiota03c29e12016-05-16 16:58:07 -0700197 idCounter = storageService.getAtomicCounter(OPTICAL_CONNECTIVITY_ID_COUNTER);
Naoki Shiota5a056062016-05-05 18:43:59 -0700198
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700199 linkPathMap = storageService.<PacketLinkRealizedByOptical, OpticalConnectivity>consistentMapBuilder()
200 .withSerializer(Serializer.using(LINKPATH_SERIALIZER.build()))
201 .withName(LINKPATH_MAP_NAME)
202 .withApplicationId(appId)
203 .build();
204
205 connectivityMap = storageService.<OpticalConnectivityId, OpticalConnectivity>consistentMapBuilder()
206 .withSerializer(Serializer.using(CONNECTIVITY_SERIALIZER.build()))
207 .withName(CONNECTIVITY_MAP_NAME)
208 .withApplicationId(appId)
209 .build();
210
211 usedCrossConnectLinkSet = storageService.<Link>setBuilder()
212 .withSerializer(Serializer.using(CROSSCONNECTLINKS_SERIALIZER.build()))
213 .withName(CROSSCONNECTLINK_SET_NAME)
214 .withApplicationId(appId)
215 .build()
216 .asDistributedSet();
217
Naoki Shiota5a056062016-05-05 18:43:59 -0700218 eventDispatcher.addSink(OpticalPathEvent.class, listenerRegistry);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700219
220 listeners = new ListenerTracker();
221 listeners.addListener(linkService, new InternalLinkListener())
222 .addListener(intentService, new InternalIntentListener());
Naoki Shiota5a056062016-05-05 18:43:59 -0700223
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700224 linkPathMap.addListener(storeListener);
225
Naoki Shiota5a056062016-05-05 18:43:59 -0700226 log.info("Started");
227 }
228
229 @Deactivate
230 protected void deactivate() {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700231 linkPathMap.removeListener(storeListener);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700232 listeners.removeListeners();
233 eventDispatcher.removeSink(OpticalPathEvent.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700234
235 log.info("Stopped");
236 }
237
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -0800238 @Override
239 public Collection<OpticalConnectivity> listConnectivity() {
240 return connectivityMap.values().stream()
241 .map(Versioned::value)
242 .collect(GuavaCollectors.toImmutableList());
243 }
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800244 /*
245 * Request packet-layer connectivity between specified ports,
246 * over packet-optical multi-layer infrastructure.
247 *
248 * Functionality-wise this is effectively submitting Packet-Optical
249 * multi-layer P2P Intent.
250 *
251 * It computes multi-layer path meeting specified constraint,
252 * and calls setupPath.
253 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700254 @Override
255 public OpticalConnectivityId setupConnectivity(ConnectPoint ingress, ConnectPoint egress,
256 Bandwidth bandwidth, Duration latency) {
257 checkNotNull(ingress);
258 checkNotNull(egress);
259 log.info("setupConnectivity({}, {}, {}, {})", ingress, egress, bandwidth, latency);
260
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800261 bandwidth = (bandwidth == null) ? NO_BW_REQUIREMENT : bandwidth;
Naoki Shiota5a056062016-05-05 18:43:59 -0700262
263 Set<Path> paths = pathService.getPaths(ingress.deviceId(), egress.deviceId(),
264 new BandwidthLinkWeight(bandwidth));
265 if (paths.isEmpty()) {
266 log.warn("Unable to find multi-layer path.");
267 return null;
268 }
269
270 // Search path with available cross connect points
271 for (Path path : paths) {
272 OpticalConnectivityId id = setupPath(path, bandwidth, latency);
273 if (id != null) {
274 log.info("Assigned OpticalConnectivityId: {}", id);
275 return id;
276 }
277 }
278
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800279 log.error("setupConnectivity({}, {}, {}, {}) failed.", ingress, egress, bandwidth, latency);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700280
Naoki Shiota5a056062016-05-05 18:43:59 -0700281 return null;
282 }
283
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800284 /*
285 * Given a multi-layer path,
286 * compute a set of segments which requires
287 * OpticalConnectivity(~=OpticalConnectivityIntent or OpticalCircuitPath)
288 * to provide packet-layer connectivity.
289 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700290 @Override
291 public OpticalConnectivityId setupPath(Path path, Bandwidth bandwidth, Duration latency) {
292 checkNotNull(path);
Yuta HIGUCHI8fc32f82017-03-14 22:12:42 -0700293 log.debug("setupPath({}, {}, {})", path, bandwidth, latency);
Naoki Shiota5a056062016-05-05 18:43:59 -0700294
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700295 // map of cross connect points (optical port -> packet port)
296 Map<ConnectPoint, ConnectPoint> crossConnectPointMap = new HashMap<>();
297
298 // list of (src, dst) pair of optical ports between which optical path should be installed
299 List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints = new ArrayList<>();
300
301 // Scan path to find pairs of connect points between which optical intent is installed
302 // opticalSrcPort works as a flag parameter to show scanning status
303 ConnectPoint opticalSrcPort = null;
304 for (Link link : path.links()) {
305 if (!isCrossConnectLink(link)) {
306 continue;
307 }
308
309 if (opticalSrcPort != null) {
310 // opticalSrcPort!=null means src port was already found
311 // in this case link.src() is optical layer, and link.dst() is packet layer
312
313 // Check if types of src port and dst port matches
314 Device srcDevice = checkNotNull(deviceService.getDevice(opticalSrcPort.deviceId()),
315 "Unknown device ID");
316 Device dstDevice = checkNotNull(deviceService.getDevice(link.src().deviceId()),
317 "Unknown device ID");
318 if (srcDevice.type() != dstDevice.type()) {
319 log.error("Unsupported mix of cross connect points : {}, {}",
320 srcDevice.type(), dstDevice.type());
321 return null;
322 }
323
324 // Update cross connect points map
325 crossConnectPointMap.put(link.src(), link.dst());
326
327 // Add optical ports pair to list
328 crossConnectPoints.add(Pair.of(opticalSrcPort, link.src()));
329
330 // Reset flag parameter
331 opticalSrcPort = null;
332 } else {
333 // opticalSrcPort==null means src port was not found yet
334 // in this case link.src() is packet layer, and link.dst() is optical layer
335
336 // Update cross connect points map
337 crossConnectPointMap.put(link.dst(), link.src());
338 // Set opticalSrcPort to src of link (optical port)
339 opticalSrcPort = link.dst();
340 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700341 }
342
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700343 // create intents from cross connect points
344 List<Intent> intents = createIntents(crossConnectPoints);
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800345 if (intents.isEmpty()) {
346 log.error("No intents produced from {}", crossConnectPoints);
347 return null;
348 }
349
Naoki Shiota5a056062016-05-05 18:43:59 -0700350
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700351 // create set of PacketLinkRealizedByOptical
352 Set<PacketLinkRealizedByOptical> packetLinks = createPacketLinkSet(crossConnectPoints,
353 intents, crossConnectPointMap);
354
355 // create OpticalConnectivity object and store information to distributed store
356 OpticalConnectivity connectivity = createConnectivity(path, bandwidth, latency, packetLinks);
Naoki Shiota5a056062016-05-05 18:43:59 -0700357
358 // store cross connect port usage
359 path.links().stream().filter(this::isCrossConnectLink)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700360 .forEach(usedCrossConnectLinkSet::add);
Naoki Shiota5a056062016-05-05 18:43:59 -0700361
362 // Submit the intents
363 for (Intent i : intents) {
364 intentService.submit(i);
365 log.debug("Submitted an intent: {}", i);
366 }
367
368 return connectivity.id();
369 }
370
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700371 private OpticalConnectivity createConnectivity(Path path, Bandwidth bandwidth, Duration latency,
372 Set<PacketLinkRealizedByOptical> links) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700373 OpticalConnectivityId id = OpticalConnectivityId.of(idCounter.getAndIncrement());
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700374 OpticalConnectivity connectivity = new OpticalConnectivity(id, path.links(), bandwidth, latency,
375 links, Collections.emptySet());
376
377 links.forEach(l -> linkPathMap.put(l, connectivity));
Naoki Shiota5a056062016-05-05 18:43:59 -0700378
Naoki Shiota5a056062016-05-05 18:43:59 -0700379 // store connectivity information
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700380 connectivityMap.put(connectivity.id(), connectivity);
Naoki Shiota5a056062016-05-05 18:43:59 -0700381
382 return connectivity;
383 }
384
385 @Override
386 public boolean removeConnectivity(OpticalConnectivityId id) {
387 log.info("removeConnectivity({})", id);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700388 Versioned<OpticalConnectivity> connectivity = connectivityMap.remove(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700389
390 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700391 log.info("OpticalConnectivity with id {} not found.", id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700392 return false;
393 }
394
395 // TODO withdraw intent only if all of connectivities that use the optical path are withdrawn
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700396 connectivity.value().getRealizingLinks().forEach(l -> {
Naoki Shiota5a056062016-05-05 18:43:59 -0700397 Intent intent = intentService.getIntent(l.realizingIntentKey());
398 intentService.withdraw(intent);
399 });
400
401 return true;
402 }
403
404 @Override
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700405 public Optional<List<Link>> getPath(OpticalConnectivityId id) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700406 Versioned<OpticalConnectivity> connectivity = connectivityMap.get(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700407 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700408 log.info("OpticalConnectivity with id {} not found.", id);
409 return Optional.empty();
Naoki Shiota5a056062016-05-05 18:43:59 -0700410 }
411
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700412 return Optional.of(ImmutableList.copyOf(connectivity.value().links()));
Naoki Shiota5a056062016-05-05 18:43:59 -0700413 }
414
415 /**
416 * Scans the list of cross connection points and returns a list of optical connectivity intents.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700417 * During the process, save information about packet links to given set.
Naoki Shiota5a056062016-05-05 18:43:59 -0700418 *
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700419 * @param crossConnectPoints list of (src, dst) pair between which optical path will be set up
Naoki Shiota5a056062016-05-05 18:43:59 -0700420 * @return list of optical connectivity intents
421 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700422 private List<Intent> createIntents(List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700423 List<Intent> intents = new LinkedList<>();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700424 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = crossConnectPoints.iterator();
Naoki Shiota5a056062016-05-05 18:43:59 -0700425
426 while (itr.hasNext()) {
427 // checkArgument at start ensures we'll always have pairs of connect points
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700428 Pair<ConnectPoint, ConnectPoint> next = itr.next();
429 ConnectPoint src = next.getLeft();
430 ConnectPoint dst = next.getRight();
Naoki Shiota5a056062016-05-05 18:43:59 -0700431
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700432 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
433 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
Naoki Shiota5a056062016-05-05 18:43:59 -0700434
435 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700436 OduCltPort srcOCPort = (OduCltPort) srcPort;
437 OduCltPort dstOCPort = (OduCltPort) dstPort;
438 if (!srcOCPort.signalType().equals(dstOCPort.signalType())) {
439 continue;
440 }
441
Naoki Shiota5a056062016-05-05 18:43:59 -0700442 // Create OTN circuit
443 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
444 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700445 .src(src)
446 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700447 .signalType(srcOCPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700448 .bidirectional(true)
449 .build();
450 intents.add(circuitIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700451 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700452 OchPort srcOchPort = (OchPort) srcPort;
453 OchPort dstOchPort = (OchPort) dstPort;
454 if (!srcOchPort.signalType().equals(dstOchPort.signalType())) {
455 continue;
456 }
457
Naoki Shiota5a056062016-05-05 18:43:59 -0700458 // Create lightpath
Naoki Shiota5a056062016-05-05 18:43:59 -0700459 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.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(srcOchPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700464 .bidirectional(true)
465 .build();
466 intents.add(opticalIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700467 } else {
468 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
469 return Collections.emptyList();
470 }
471 }
472
473 return intents;
474 }
475
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700476 private Set<PacketLinkRealizedByOptical> createPacketLinkSet(List<Pair<ConnectPoint, ConnectPoint>> connectPoints,
477 List<Intent> intents,
478 Map<ConnectPoint, ConnectPoint> crossConnectPoints) {
479 checkArgument(connectPoints.size() == intents.size());
480
481 Set<PacketLinkRealizedByOptical> pLinks = new HashSet<>();
482
483 Iterator<Pair<ConnectPoint, ConnectPoint>> xcPointsItr = connectPoints.iterator();
484 Iterator<Intent> intentItr = intents.iterator();
485 while (xcPointsItr.hasNext()) {
486 Pair<ConnectPoint, ConnectPoint> xcPoints = xcPointsItr.next();
487 Intent intent = intentItr.next();
488
489 ConnectPoint packetSrc = checkNotNull(crossConnectPoints.get(xcPoints.getLeft()));
490 ConnectPoint packetDst = checkNotNull(crossConnectPoints.get(xcPoints.getRight()));
491
492 if (intent instanceof OpticalConnectivityIntent) {
493 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
494 (OpticalConnectivityIntent) intent));
495 } else if (intent instanceof OpticalCircuitIntent) {
496 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
497 (OpticalCircuitIntent) intent));
498 } else {
499 log.warn("Unexpected intent type: {}", intent.getClass());
500 }
501 }
502
503 return pLinks;
504 }
505
Naoki Shiota5a056062016-05-05 18:43:59 -0700506 /**
507 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
508 *
509 * @param type device type
510 * @return true if in packet layer, false otherwise
511 */
512 private boolean isPacketLayer(Device.Type type) {
513 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
514 }
515
516 /**
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800517 * Verifies if given device type is NOT in packet layer, i.e., switch or router device.
Naoki Shiota5a056062016-05-05 18:43:59 -0700518 *
519 * @param type device type
520 * @return true if in packet layer, false otherwise
521 */
522 private boolean isTransportLayer(Device.Type type) {
523 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
524 }
525
526 /**
527 * Verifies if given link forms a cross-connection between packet and optical layer.
528 *
529 * @param link the link
530 * @return true if the link is a cross-connect link, false otherwise
531 */
532 private boolean isCrossConnectLink(Link link) {
533 if (link.type() != Link.Type.OPTICAL) {
534 return false;
535 }
536
537 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
538 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
539
540 return src != dst &&
541 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
542 }
543
544 /**
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800545 * Updates bandwidth resource of given connect point to specified value.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700546 *
Naoki Shiota5a056062016-05-05 18:43:59 -0700547 * @param cp Connect point
548 * @param bandwidth New bandwidth
549 */
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800550 private void setPortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700551 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
552 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
553 bwCapacity.capacity(bandwidth).apply();
Naoki Shiota5a056062016-05-05 18:43:59 -0700554 }
555
556 /**
557 * Updates usage information of bandwidth based on connectivity which is established.
558 * @param connectivity Optical connectivity
559 */
560 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800561 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
562 // no bandwidth requirement, nothing to allocate.
563 return;
564 }
565
Naoki Shiotacb744db2016-05-13 19:32:35 -0700566 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700567
568 List<Link> links = connectivity.links();
569
570 List<Resource> resources = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
571 .filter(cp -> !isTransportLayer(deviceService.getDevice(cp.deviceId()).type()))
572 .map(cp -> Resources.continuous(cp.deviceId(), cp.port(),
573 Bandwidth.class).resource(connectivity.bandwidth().bps()))
574 .collect(Collectors.toList());
575
Naoki Shiotacb744db2016-05-13 19:32:35 -0700576 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
577 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700578 if (allocations.isEmpty()) {
579 log.warn("Failed to allocate bandwidth {} to {}",
580 connectivity.bandwidth().bps(), resources);
581 // TODO any recovery?
582 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700583 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700584 }
585
586 /**
587 * Release bandwidth allocated by given connectivity.
588 * @param connectivity Optical connectivity
589 */
590 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700591 if (connectivity.links().isEmpty()) {
592 return;
Naoki Shiota5a056062016-05-05 18:43:59 -0700593 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800594 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
595 // no bandwidth requirement, nothing to release.
596 return;
597 }
598
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700599
600 // release resource only if this node is the master for link head device
601 if (mastershipService.isLocalMaster(connectivity.links().get(0).src().deviceId())) {
602 OpticalConnectivityId connectivityId = connectivity.id();
603
604 log.debug("releasing bandwidth allocated to {}", connectivityId);
605 if (!resourceService.release(connectivityId)) {
606 log.warn("Failed to release bandwidth allocated to {}",
607 connectivityId);
608 // TODO any recovery?
609 }
610 log.debug("DONE releasing bandwidth for {}", connectivityId);
611 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700612 }
613
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800614 private boolean linkDiscoveryEnabled(ConnectPoint cp) {
615 // FIXME should check Device feature and configuration state.
616
617 // short-term hack for ONS'17 time-frame,
618 // only expect OF device to have link discovery.
619 return cp.deviceId().uri().getScheme().equals("of");
620 }
621
622 /**
623 * Returns true if both connect point support for link discovery & enabled.
624 *
625 * @param cp1 port 1
626 * @param cp2 port 2
627 * @return true if both connect point support for link discovery & enabled.
628 */
629 private boolean linkDiscoveryEnabled(ConnectPoint cp1, ConnectPoint cp2) {
630 return linkDiscoveryEnabled(cp1) && linkDiscoveryEnabled(cp2);
631 }
632
Naoki Shiota5a056062016-05-05 18:43:59 -0700633 private class BandwidthLinkWeight implements LinkWeight {
634 private Bandwidth bandwidth = null;
635
636 public BandwidthLinkWeight(Bandwidth bandwidth) {
637 this.bandwidth = bandwidth;
638 }
639
640 @Override
641 public double weight(TopologyEdge edge) {
642 Link l = edge.link();
643
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700644 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700645 if (l.state() == Link.State.INACTIVE) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800646 log.trace("{} is not active", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700647 return -1.0;
648 }
649
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700650 // Avoid cross connect links with used ports
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700651 if (isCrossConnectLink(l) && usedCrossConnectLinkSet.contains(l)) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800652 log.trace("Cross connect {} in use", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700653 return -1.0;
654 }
655
656 // Check availability of bandwidth
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800657 if (bandwidth != null && !NO_BW_REQUIREMENT.equals(bandwidth)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700658 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
659 return 1.0;
660 } else {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800661 log.trace("Not enought bandwidth on {}", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700662 return -1.0;
663 }
664 } else {
665 // TODO needs to differentiate optical and packet?
666 if (l.type() == Link.Type.OPTICAL) {
667 // Transport links
668 return 1.0;
669 } else {
670 // Packet links
671 return 1.0;
672 }
673 }
674 }
675
676 private boolean hasEnoughBandwidth(ConnectPoint cp) {
677 if (cp.elementId() instanceof DeviceId) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700678 Device device = deviceService.getDevice(cp.deviceId());
679 Device.Type type = device.type();
680
Naoki Shiota5a056062016-05-05 18:43:59 -0700681 if (isTransportLayer(type)) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700682 // Check if the port has enough capacity
683 Port port = deviceService.getPort(cp.deviceId(), cp.port());
684 if (port instanceof OduCltPort || port instanceof OchPort) {
685 // Port with capacity
686 return bandwidth.bps() < port.portSpeed() * 1000000.0;
687 } else {
688 // Port without valid capacity (OMS port, etc.)
689 return true;
690 }
691 } else {
692 // Check if enough amount of bandwidth resource remains
693 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
694 .resource(bandwidth.bps());
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800695 try {
696 return resourceService.isAvailable(resource);
697 } catch (Exception e) {
698 log.error("Resource service failed checking availability of {}",
699 resource, e);
700 throw e;
701 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700702 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700703 }
704 return false;
705 }
706 }
707
708
709 public class InternalIntentListener implements IntentListener {
710 @Override
711 public void event(IntentEvent event) {
712 switch (event.type()) {
713 case INSTALLED:
714 log.info("Intent {} installed.", event.subject());
715 updateCrossConnectLink(event.subject());
716 break;
717 case WITHDRAWN:
718 log.info("Intent {} withdrawn.", event.subject());
719 removeCrossConnectLinks(event.subject());
720 break;
721 case FAILED:
722 log.info("Intent {} failed.", event.subject());
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800723 // TODO If it was one of it's own optical Intent,
724 // update link state
725 // TODO If it was packet P2P Intent, call setupConnectivity
Naoki Shiota5a056062016-05-05 18:43:59 -0700726 break;
727 default:
728 break;
729 }
730 }
731
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800732 // TODO rename "CrossConnectLink"?
733 /**
734 * Update packet-layer link/port state once Intent is installed.
735 *
736 * @param intent which reached installed state
737 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700738 private void updateCrossConnectLink(Intent intent) {
739 linkPathMap.entrySet().stream()
740 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
741 .forEach(e -> {
742 ConnectPoint packetSrc = e.getKey().src();
743 ConnectPoint packetDst = e.getKey().dst();
744 Bandwidth bw = e.getKey().bandwidth();
Naoki Shiota5a056062016-05-05 18:43:59 -0700745
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700746 // reflect modification only if packetSrc is local_
747 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
748 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800749 setPortBandwidth(packetSrc, bw);
750 setPortBandwidth(packetDst, bw);
Naoki Shiota5a056062016-05-05 18:43:59 -0700751
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700752 // Updates link status in distributed map
753 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
754 e.getValue().value().setLinkEstablished(packetSrc, packetDst, true));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800755
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800756
757 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
758 injectLink(packetSrc, packetDst);
759 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700760 }
761 });
762 }
763
764 private void removeCrossConnectLinks(Intent intent) {
765 ConnectPoint src, dst;
766
767 if (intent instanceof OpticalCircuitIntent) {
768 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
769 src = circuit.getSrc();
770 dst = circuit.getDst();
771 } else if (intent instanceof OpticalConnectivityIntent) {
772 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
773 src = conn.getSrc();
774 dst = conn.getDst();
775 } else {
776 return;
777 }
778
779 removeXcLinkUsage(src);
780 removeXcLinkUsage(dst);
781
782 // Set bandwidth of 0 to cross connect ports
783 Bandwidth bw = Bandwidth.bps(0);
784 linkPathMap.entrySet().stream()
785 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
786 .forEach(e -> {
787 ConnectPoint packetSrc = e.getKey().src();
788 ConnectPoint packetDst = e.getKey().dst();
Naoki Shiota5a056062016-05-05 18:43:59 -0700789
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700790 // reflect modification only if packetSrc is local_
791 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
792 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800793 setPortBandwidth(packetSrc, bw);
794 setPortBandwidth(packetDst, bw);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700795
796 // Updates link status in distributed map
797 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
798 e.getValue().value().setLinkEstablished(packetSrc, packetDst, false));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800799
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800800
801 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
802 removeInjectedLink(packetSrc, packetDst);
803 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700804 }
805 });
806 }
807
808 private void removeXcLinkUsage(ConnectPoint cp) {
809 Optional<Link> link = linkService.getLinks(cp).stream()
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700810 .filter(usedCrossConnectLinkSet::contains)
Naoki Shiota5a056062016-05-05 18:43:59 -0700811 .findAny();
812
813 if (!link.isPresent()) {
814 log.warn("Cross connect point {} has no cross connect link.", cp);
815 return;
816 }
817
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700818 usedCrossConnectLinkSet.remove(link.get());
Naoki Shiota5a056062016-05-05 18:43:59 -0700819 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800820
821 /**
822 * Injects link between specified packet port.
823 *
824 * @param packetSrc port 1
825 * @param packetDst port 2
826 */
827 private void injectLink(ConnectPoint packetSrc,
828 ConnectPoint packetDst) {
829 // inject expected link or durable link
830 // if packet device cannot advertise packet link
831 try {
832 BasicLinkConfig lnkCfg = networkConfigService
833 .addConfig(linkKey(packetSrc, packetDst),
834 BasicLinkConfig.class);
835 lnkCfg.isAllowed(true);
836 lnkCfg.isDurable(true);
837 lnkCfg.type(Link.Type.DIRECT);
838 lnkCfg.apply();
839 } catch (Exception ex) {
840 log.error("Applying BasicLinkConfig failed", ex);
841 }
842 }
843
844 /**
845 * Removes link injected between specified packet port.
846 *
847 * @param packetSrc port 1
848 * @param packetDst port 2
849 */
850 private void removeInjectedLink(ConnectPoint packetSrc,
851 ConnectPoint packetDst) {
852 // remove expected link or durable link
853 // if packet device cannot monitor packet link
854
855 try {
856 // hack to mark link off-line
857 BasicLinkConfig lnkCfg = networkConfigService
858 .getConfig(linkKey(packetSrc, packetDst),
859 BasicLinkConfig.class);
860 lnkCfg.isAllowed(false);
861 lnkCfg.apply();
862 } catch (Exception ex) {
863 log.error("Applying BasicLinkConfig failed", ex);
864 }
865
866 networkConfigService
867 .removeConfig(linkKey(packetSrc, packetDst),
868 BasicLinkConfig.class);
869 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700870 }
871
872
873 private class InternalLinkListener implements LinkListener {
874
875 @Override
876 public void event(LinkEvent event) {
877 switch (event.type()) {
878 case LINK_REMOVED:
879 Link link = event.subject();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700880 // updates linkPathMap only if src device of link is local
881 if (!mastershipService.isLocalMaster(link.src().deviceId())) {
882 return;
883 }
884
885 // find all packet links that correspond to removed link
Naoki Shiota5a056062016-05-05 18:43:59 -0700886 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
887 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
888 .collect(Collectors.toSet());
889
890 pLinks.forEach(l -> {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700891 // remove found packet links from distributed store
892 linkPathMap.computeIfPresent(l, (plink, conn) -> {
893 // Notifies listeners if all packet links are gone
894 if (conn.isAllRealizingLinkNotEstablished()) {
895 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, conn.id()));
896 }
897 return null;
898 });
Naoki Shiota5a056062016-05-05 18:43:59 -0700899 });
900 default:
901 break;
902 }
903 }
904 }
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700905
906 private class InternalStoreListener
907 implements MapEventListener<PacketLinkRealizedByOptical, OpticalConnectivity> {
908
909 @Override
910 public void event(MapEvent<PacketLinkRealizedByOptical, OpticalConnectivity> event) {
911 switch (event.type()) {
912 case UPDATE:
913 OpticalConnectivity oldConnectivity = event.oldValue().value();
914 OpticalConnectivity newConnectivity = event.newValue().value();
915
916 if (!oldConnectivity.isAllRealizingLinkEstablished() &&
917 newConnectivity.isAllRealizingLinkEstablished()) {
918 // Notifies listeners if all links are established
919 updateBandwidthUsage(newConnectivity);
920 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, newConnectivity.id()));
921 } else if (!oldConnectivity.isAllRealizingLinkNotEstablished() &&
922 newConnectivity.isAllRealizingLinkNotEstablished()) {
923 // Notifies listeners if all links are gone
924 releaseBandwidthUsage(newConnectivity);
925 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, newConnectivity.id()));
926 }
927
928 break;
929 default:
930 break;
931 }
932 }
933
934 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700935}
936