blob: 79d1d2684f103272da05619ab6d3e61c4e085238 [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;
Yuta HIGUCHI21033042017-05-04 17:58:24 -070046import org.onosproject.net.LinkKey;
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;
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -070055import org.onosproject.net.intent.Key;
Naoki Shiota5a056062016-05-05 18:43:59 -070056import org.onosproject.net.intent.OpticalCircuitIntent;
57import org.onosproject.net.intent.OpticalConnectivityIntent;
Naoki Shiota5a056062016-05-05 18:43:59 -070058import org.onosproject.net.link.LinkEvent;
59import org.onosproject.net.link.LinkListener;
60import org.onosproject.net.link.LinkService;
Sho SHIMIZUb6c63a32016-05-26 12:07:19 -070061import org.onosproject.net.config.basics.BandwidthCapacity;
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -080062import org.onosproject.net.config.basics.BasicLinkConfig;
Naoki Shiota5a056062016-05-05 18:43:59 -070063import org.onosproject.net.resource.ContinuousResource;
64import org.onosproject.net.resource.Resource;
65import org.onosproject.net.resource.ResourceAllocation;
66import org.onosproject.net.resource.ResourceService;
67import org.onosproject.net.resource.Resources;
68import org.onosproject.net.topology.LinkWeight;
69import org.onosproject.net.topology.PathService;
70import org.onosproject.net.topology.TopologyEdge;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070071import org.onosproject.store.serializers.KryoNamespaces;
Naoki Shiota5a056062016-05-05 18:43:59 -070072import org.onosproject.store.service.AtomicCounter;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070073import org.onosproject.store.service.ConsistentMap;
74import org.onosproject.store.service.DistributedSet;
75import org.onosproject.store.service.MapEvent;
76import org.onosproject.store.service.MapEventListener;
77import org.onosproject.store.service.Serializer;
Naoki Shiota5a056062016-05-05 18:43:59 -070078import org.onosproject.store.service.StorageService;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070079import org.onosproject.store.service.Versioned;
Naoki Shiota5a056062016-05-05 18:43:59 -070080import org.slf4j.Logger;
81import org.slf4j.LoggerFactory;
82
83import java.time.Duration;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070084import java.util.ArrayList;
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -080085import java.util.Collection;
Naoki Shiota5a056062016-05-05 18:43:59 -070086import java.util.Collections;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070087import java.util.HashMap;
88import java.util.HashSet;
Naoki Shiota5a056062016-05-05 18:43:59 -070089import java.util.Iterator;
90import java.util.LinkedList;
91import java.util.List;
92import java.util.Map;
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -070093import java.util.Map.Entry;
Naoki Shiota5a056062016-05-05 18:43:59 -070094import java.util.Optional;
95import java.util.Set;
Naoki Shiota5a056062016-05-05 18:43:59 -070096import java.util.stream.Collectors;
97import java.util.stream.Stream;
98
99import static com.google.common.base.Preconditions.checkArgument;
100import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800101import static org.onosproject.net.LinkKey.linkKey;
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700102import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
Naoki Shiota5a056062016-05-05 18:43:59 -0700103
104/**
105 * Main component to configure optical connectivity.
106 */
107@Beta
108@Service
109@Component(immediate = true)
110public class OpticalPathProvisioner
111 extends AbstractListenerManager<OpticalPathEvent, OpticalPathListener>
112 implements OpticalPathService {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800113
Naoki Shiota5a056062016-05-05 18:43:59 -0700114 protected static final Logger log = LoggerFactory.getLogger(OpticalPathProvisioner.class);
115
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800116 /**
117 * Bandwidth representing no bandwidth requirement specified.
118 */
119 private static final Bandwidth NO_BW_REQUIREMENT = Bandwidth.bps(0);
120
Naoki Shiota5a056062016-05-05 18:43:59 -0700121 private static final String OPTICAL_CONNECTIVITY_ID_COUNTER = "optical-connectivity-id";
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700122 private static final String LINKPATH_MAP_NAME = "newoptical-linkpath";
123 private static final String CONNECTIVITY_MAP_NAME = "newoptical-connectivity";
124 private static final String CROSSCONNECTLINK_SET_NAME = "newoptical-crossconnectlink";
Naoki Shiota5a056062016-05-05 18:43:59 -0700125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected IntentService intentService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected PathService pathService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected CoreService coreService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected LinkService linkService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected MastershipService mastershipService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected ClusterService clusterService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected DeviceService deviceService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected StorageService storageService;
149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
151 protected NetworkConfigService networkConfigService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 protected ResourceService resourceService;
155
156
157 private ApplicationId appId;
158
159 private AtomicCounter idCounter;
160
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700161 private ListenerTracker listeners;
Naoki Shiota5a056062016-05-05 18:43:59 -0700162
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700163 private InternalStoreListener storeListener = new InternalStoreListener();
Naoki Shiota5a056062016-05-05 18:43:59 -0700164
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800165 /**
166 * Map from packet-layer link expected to be realized by some optical Intent to
167 * OpticalConnectivity (~=top level intent over multi-layer topology).
168 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700169 private ConsistentMap<PacketLinkRealizedByOptical, OpticalConnectivity> linkPathMap;
Naoki Shiota5a056062016-05-05 18:43:59 -0700170
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700171 private ConsistentMap<OpticalConnectivityId, OpticalConnectivity> connectivityMap;
172
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800173 // FIXME in the long run. This is effectively app's own resource subsystem
174 /**
175 * Set of cross connect link currently used.
176 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700177 private DistributedSet<Link> usedCrossConnectLinkSet;
178
179 private static final KryoNamespace.Builder LINKPATH_SERIALIZER = KryoNamespace.newBuilder()
180 .register(KryoNamespaces.API)
181 .register(PacketLinkRealizedByOptical.class)
182 .register(OpticalConnectivityId.class)
183 .register(OpticalConnectivity.class);
184
185 private static final KryoNamespace.Builder CONNECTIVITY_SERIALIZER = KryoNamespace.newBuilder()
186 .register(KryoNamespaces.API)
Yuta HIGUCHI0086cf82016-07-18 22:49:45 -0700187 .register(PacketLinkRealizedByOptical.class)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700188 .register(OpticalConnectivityId.class)
189 .register(OpticalConnectivity.class);
190
191 private static final KryoNamespace.Builder CROSSCONNECTLINKS_SERIALIZER = KryoNamespace.newBuilder()
192 .register(KryoNamespaces.API);
Naoki Shiota5a056062016-05-05 18:43:59 -0700193
194 @Activate
195 protected void activate() {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700196 deviceService = opticalView(deviceService);
Naoki Shiota5a056062016-05-05 18:43:59 -0700197 appId = coreService.registerApplication("org.onosproject.newoptical");
198
Naoki Shiota03c29e12016-05-16 16:58:07 -0700199 idCounter = storageService.getAtomicCounter(OPTICAL_CONNECTIVITY_ID_COUNTER);
Naoki Shiota5a056062016-05-05 18:43:59 -0700200
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700201 linkPathMap = storageService.<PacketLinkRealizedByOptical, OpticalConnectivity>consistentMapBuilder()
202 .withSerializer(Serializer.using(LINKPATH_SERIALIZER.build()))
203 .withName(LINKPATH_MAP_NAME)
204 .withApplicationId(appId)
205 .build();
206
207 connectivityMap = storageService.<OpticalConnectivityId, OpticalConnectivity>consistentMapBuilder()
208 .withSerializer(Serializer.using(CONNECTIVITY_SERIALIZER.build()))
209 .withName(CONNECTIVITY_MAP_NAME)
210 .withApplicationId(appId)
211 .build();
212
213 usedCrossConnectLinkSet = storageService.<Link>setBuilder()
214 .withSerializer(Serializer.using(CROSSCONNECTLINKS_SERIALIZER.build()))
215 .withName(CROSSCONNECTLINK_SET_NAME)
216 .withApplicationId(appId)
217 .build()
218 .asDistributedSet();
219
Naoki Shiota5a056062016-05-05 18:43:59 -0700220 eventDispatcher.addSink(OpticalPathEvent.class, listenerRegistry);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700221
222 listeners = new ListenerTracker();
223 listeners.addListener(linkService, new InternalLinkListener())
224 .addListener(intentService, new InternalIntentListener());
Naoki Shiota5a056062016-05-05 18:43:59 -0700225
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700226 linkPathMap.addListener(storeListener);
227
Naoki Shiota5a056062016-05-05 18:43:59 -0700228 log.info("Started");
229 }
230
231 @Deactivate
232 protected void deactivate() {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700233 linkPathMap.removeListener(storeListener);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700234 listeners.removeListeners();
235 eventDispatcher.removeSink(OpticalPathEvent.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700236
237 log.info("Stopped");
238 }
239
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -0800240 @Override
241 public Collection<OpticalConnectivity> listConnectivity() {
242 return connectivityMap.values().stream()
243 .map(Versioned::value)
244 .collect(GuavaCollectors.toImmutableList());
245 }
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -0700246
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700247 @Override
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -0700248 public Set<Key> listIntents(OpticalConnectivityId id) {
249 return linkPathMap.entrySet().stream()
250 .filter(ent -> id.equals(ent.getValue().value().id()))
251 .map(Entry::getKey)
252 .map(PacketLinkRealizedByOptical::realizingIntentKey)
253 .collect(Collectors.toSet());
254 }
255
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800256 /*
257 * Request packet-layer connectivity between specified ports,
258 * over packet-optical multi-layer infrastructure.
259 *
260 * Functionality-wise this is effectively submitting Packet-Optical
261 * multi-layer P2P Intent.
262 *
263 * It computes multi-layer path meeting specified constraint,
264 * and calls setupPath.
265 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700266 @Override
267 public OpticalConnectivityId setupConnectivity(ConnectPoint ingress, ConnectPoint egress,
268 Bandwidth bandwidth, Duration latency) {
269 checkNotNull(ingress);
270 checkNotNull(egress);
271 log.info("setupConnectivity({}, {}, {}, {})", ingress, egress, bandwidth, latency);
272
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800273 bandwidth = (bandwidth == null) ? NO_BW_REQUIREMENT : bandwidth;
Naoki Shiota5a056062016-05-05 18:43:59 -0700274
275 Set<Path> paths = pathService.getPaths(ingress.deviceId(), egress.deviceId(),
276 new BandwidthLinkWeight(bandwidth));
277 if (paths.isEmpty()) {
278 log.warn("Unable to find multi-layer path.");
279 return null;
280 }
281
282 // Search path with available cross connect points
283 for (Path path : paths) {
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700284 // Path service calculates from node to node, we're only interested in port to port
285 if (!path.src().equals(ingress) || !path.dst().equals(egress)) {
286 continue;
287 }
288
Naoki Shiota5a056062016-05-05 18:43:59 -0700289 OpticalConnectivityId id = setupPath(path, bandwidth, latency);
290 if (id != null) {
291 log.info("Assigned OpticalConnectivityId: {}", id);
292 return id;
293 }
294 }
295
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800296 log.error("setupConnectivity({}, {}, {}, {}) failed.", ingress, egress, bandwidth, latency);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700297
Naoki Shiota5a056062016-05-05 18:43:59 -0700298 return null;
299 }
300
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800301 /*
302 * Given a multi-layer path,
303 * compute a set of segments which requires
304 * OpticalConnectivity(~=OpticalConnectivityIntent or OpticalCircuitPath)
305 * to provide packet-layer connectivity.
306 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700307 @Override
308 public OpticalConnectivityId setupPath(Path path, Bandwidth bandwidth, Duration latency) {
309 checkNotNull(path);
Yuta HIGUCHI8fc32f82017-03-14 22:12:42 -0700310 log.debug("setupPath({}, {}, {})", path, bandwidth, latency);
Naoki Shiota5a056062016-05-05 18:43:59 -0700311
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700312 // map of cross connect points (optical port -> packet port)
313 Map<ConnectPoint, ConnectPoint> crossConnectPointMap = new HashMap<>();
314
315 // list of (src, dst) pair of optical ports between which optical path should be installed
316 List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints = new ArrayList<>();
317
318 // Scan path to find pairs of connect points between which optical intent is installed
319 // opticalSrcPort works as a flag parameter to show scanning status
320 ConnectPoint opticalSrcPort = null;
321 for (Link link : path.links()) {
322 if (!isCrossConnectLink(link)) {
323 continue;
324 }
325
326 if (opticalSrcPort != null) {
327 // opticalSrcPort!=null means src port was already found
328 // in this case link.src() is optical layer, and link.dst() is packet layer
329
330 // Check if types of src port and dst port matches
331 Device srcDevice = checkNotNull(deviceService.getDevice(opticalSrcPort.deviceId()),
332 "Unknown device ID");
333 Device dstDevice = checkNotNull(deviceService.getDevice(link.src().deviceId()),
334 "Unknown device ID");
335 if (srcDevice.type() != dstDevice.type()) {
336 log.error("Unsupported mix of cross connect points : {}, {}",
337 srcDevice.type(), dstDevice.type());
338 return null;
339 }
340
341 // Update cross connect points map
342 crossConnectPointMap.put(link.src(), link.dst());
343
344 // Add optical ports pair to list
345 crossConnectPoints.add(Pair.of(opticalSrcPort, link.src()));
346
347 // Reset flag parameter
348 opticalSrcPort = null;
349 } else {
350 // opticalSrcPort==null means src port was not found yet
351 // in this case link.src() is packet layer, and link.dst() is optical layer
352
353 // Update cross connect points map
354 crossConnectPointMap.put(link.dst(), link.src());
355 // Set opticalSrcPort to src of link (optical port)
356 opticalSrcPort = link.dst();
357 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700358 }
359
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700360 // create intents from cross connect points
361 List<Intent> intents = createIntents(crossConnectPoints);
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800362 if (intents.isEmpty()) {
363 log.error("No intents produced from {}", crossConnectPoints);
364 return null;
365 }
366
Naoki Shiota5a056062016-05-05 18:43:59 -0700367
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700368 // create set of PacketLinkRealizedByOptical
369 Set<PacketLinkRealizedByOptical> packetLinks = createPacketLinkSet(crossConnectPoints,
370 intents, crossConnectPointMap);
371
372 // create OpticalConnectivity object and store information to distributed store
373 OpticalConnectivity connectivity = createConnectivity(path, bandwidth, latency, packetLinks);
Naoki Shiota5a056062016-05-05 18:43:59 -0700374
375 // store cross connect port usage
376 path.links().stream().filter(this::isCrossConnectLink)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700377 .forEach(usedCrossConnectLinkSet::add);
Naoki Shiota5a056062016-05-05 18:43:59 -0700378
379 // Submit the intents
380 for (Intent i : intents) {
381 intentService.submit(i);
382 log.debug("Submitted an intent: {}", i);
383 }
384
385 return connectivity.id();
386 }
387
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700388 private OpticalConnectivity createConnectivity(Path path, Bandwidth bandwidth, Duration latency,
389 Set<PacketLinkRealizedByOptical> links) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700390 OpticalConnectivityId id = OpticalConnectivityId.of(idCounter.getAndIncrement());
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700391 OpticalConnectivity connectivity = new OpticalConnectivity(id, path.links(), bandwidth, latency,
392 links, Collections.emptySet());
393
394 links.forEach(l -> linkPathMap.put(l, connectivity));
Naoki Shiota5a056062016-05-05 18:43:59 -0700395
Naoki Shiota5a056062016-05-05 18:43:59 -0700396 // store connectivity information
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700397 connectivityMap.put(connectivity.id(), connectivity);
Naoki Shiota5a056062016-05-05 18:43:59 -0700398
399 return connectivity;
400 }
401
402 @Override
403 public boolean removeConnectivity(OpticalConnectivityId id) {
404 log.info("removeConnectivity({})", id);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700405 Versioned<OpticalConnectivity> connectivity = connectivityMap.remove(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700406
407 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700408 log.info("OpticalConnectivity with id {} not found.", id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700409 return false;
410 }
411
412 // TODO withdraw intent only if all of connectivities that use the optical path are withdrawn
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700413 connectivity.value().getRealizingLinks().forEach(l -> {
Naoki Shiota5a056062016-05-05 18:43:59 -0700414 Intent intent = intentService.getIntent(l.realizingIntentKey());
415 intentService.withdraw(intent);
416 });
417
418 return true;
419 }
420
421 @Override
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700422 public Optional<List<Link>> getPath(OpticalConnectivityId id) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700423 Versioned<OpticalConnectivity> connectivity = connectivityMap.get(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700424 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700425 log.info("OpticalConnectivity with id {} not found.", id);
426 return Optional.empty();
Naoki Shiota5a056062016-05-05 18:43:59 -0700427 }
428
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700429 return Optional.of(ImmutableList.copyOf(connectivity.value().links()));
Naoki Shiota5a056062016-05-05 18:43:59 -0700430 }
431
432 /**
433 * Scans the list of cross connection points and returns a list of optical connectivity intents.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700434 * During the process, save information about packet links to given set.
Naoki Shiota5a056062016-05-05 18:43:59 -0700435 *
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700436 * @param crossConnectPoints list of (src, dst) pair between which optical path will be set up
Naoki Shiota5a056062016-05-05 18:43:59 -0700437 * @return list of optical connectivity intents
438 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700439 private List<Intent> createIntents(List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700440 List<Intent> intents = new LinkedList<>();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700441 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = crossConnectPoints.iterator();
Naoki Shiota5a056062016-05-05 18:43:59 -0700442
443 while (itr.hasNext()) {
444 // checkArgument at start ensures we'll always have pairs of connect points
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700445 Pair<ConnectPoint, ConnectPoint> next = itr.next();
446 ConnectPoint src = next.getLeft();
447 ConnectPoint dst = next.getRight();
Naoki Shiota5a056062016-05-05 18:43:59 -0700448
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700449 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
450 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
Naoki Shiota5a056062016-05-05 18:43:59 -0700451
452 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700453 OduCltPort srcOCPort = (OduCltPort) srcPort;
454 OduCltPort dstOCPort = (OduCltPort) dstPort;
455 if (!srcOCPort.signalType().equals(dstOCPort.signalType())) {
456 continue;
457 }
458
Naoki Shiota5a056062016-05-05 18:43:59 -0700459 // Create OTN circuit
460 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
461 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700462 .src(src)
463 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700464 .signalType(srcOCPort.signalType())
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700465 .bidirectional(false)
Naoki Shiota5a056062016-05-05 18:43:59 -0700466 .build();
467 intents.add(circuitIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700468 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700469 OchPort srcOchPort = (OchPort) srcPort;
470 OchPort dstOchPort = (OchPort) dstPort;
471 if (!srcOchPort.signalType().equals(dstOchPort.signalType())) {
472 continue;
473 }
474
Naoki Shiota5a056062016-05-05 18:43:59 -0700475 // Create lightpath
Naoki Shiota5a056062016-05-05 18:43:59 -0700476 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.builder()
477 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700478 .src(src)
479 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700480 .signalType(srcOchPort.signalType())
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700481 .bidirectional(false)
Naoki Shiota5a056062016-05-05 18:43:59 -0700482 .build();
483 intents.add(opticalIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700484 } else {
485 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
486 return Collections.emptyList();
487 }
488 }
489
490 return intents;
491 }
492
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700493 private Set<PacketLinkRealizedByOptical> createPacketLinkSet(List<Pair<ConnectPoint, ConnectPoint>> connectPoints,
494 List<Intent> intents,
495 Map<ConnectPoint, ConnectPoint> crossConnectPoints) {
496 checkArgument(connectPoints.size() == intents.size());
497
498 Set<PacketLinkRealizedByOptical> pLinks = new HashSet<>();
499
500 Iterator<Pair<ConnectPoint, ConnectPoint>> xcPointsItr = connectPoints.iterator();
501 Iterator<Intent> intentItr = intents.iterator();
502 while (xcPointsItr.hasNext()) {
503 Pair<ConnectPoint, ConnectPoint> xcPoints = xcPointsItr.next();
504 Intent intent = intentItr.next();
505
506 ConnectPoint packetSrc = checkNotNull(crossConnectPoints.get(xcPoints.getLeft()));
507 ConnectPoint packetDst = checkNotNull(crossConnectPoints.get(xcPoints.getRight()));
508
509 if (intent instanceof OpticalConnectivityIntent) {
510 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
511 (OpticalConnectivityIntent) intent));
512 } else if (intent instanceof OpticalCircuitIntent) {
513 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
514 (OpticalCircuitIntent) intent));
515 } else {
516 log.warn("Unexpected intent type: {}", intent.getClass());
517 }
518 }
519
520 return pLinks;
521 }
522
Naoki Shiota5a056062016-05-05 18:43:59 -0700523 /**
524 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
525 *
526 * @param type device type
527 * @return true if in packet layer, false otherwise
528 */
529 private boolean isPacketLayer(Device.Type type) {
530 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
531 }
532
533 /**
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800534 * Verifies if given device type is NOT in packet layer, i.e., switch or router device.
Naoki Shiota5a056062016-05-05 18:43:59 -0700535 *
536 * @param type device type
537 * @return true if in packet layer, false otherwise
538 */
539 private boolean isTransportLayer(Device.Type type) {
540 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
541 }
542
543 /**
544 * Verifies if given link forms a cross-connection between packet and optical layer.
545 *
546 * @param link the link
547 * @return true if the link is a cross-connect link, false otherwise
548 */
549 private boolean isCrossConnectLink(Link link) {
550 if (link.type() != Link.Type.OPTICAL) {
551 return false;
552 }
553
554 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
555 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
556
557 return src != dst &&
558 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
559 }
560
561 /**
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800562 * Updates bandwidth resource of given connect point to specified value.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700563 *
Naoki Shiota5a056062016-05-05 18:43:59 -0700564 * @param cp Connect point
565 * @param bandwidth New bandwidth
566 */
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800567 private void setPortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700568 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
569 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
570 bwCapacity.capacity(bandwidth).apply();
Naoki Shiota5a056062016-05-05 18:43:59 -0700571 }
572
573 /**
574 * Updates usage information of bandwidth based on connectivity which is established.
575 * @param connectivity Optical connectivity
576 */
577 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800578 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
579 // no bandwidth requirement, nothing to allocate.
580 return;
581 }
582
Naoki Shiotacb744db2016-05-13 19:32:35 -0700583 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700584
585 List<Link> links = connectivity.links();
586
587 List<Resource> resources = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
588 .filter(cp -> !isTransportLayer(deviceService.getDevice(cp.deviceId()).type()))
589 .map(cp -> Resources.continuous(cp.deviceId(), cp.port(),
590 Bandwidth.class).resource(connectivity.bandwidth().bps()))
591 .collect(Collectors.toList());
592
Naoki Shiotacb744db2016-05-13 19:32:35 -0700593 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
594 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700595 if (allocations.isEmpty()) {
596 log.warn("Failed to allocate bandwidth {} to {}",
597 connectivity.bandwidth().bps(), resources);
598 // TODO any recovery?
599 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700600 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700601 }
602
603 /**
604 * Release bandwidth allocated by given connectivity.
605 * @param connectivity Optical connectivity
606 */
607 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700608 if (connectivity.links().isEmpty()) {
609 return;
Naoki Shiota5a056062016-05-05 18:43:59 -0700610 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800611 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
612 // no bandwidth requirement, nothing to release.
613 return;
614 }
615
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700616
617 // release resource only if this node is the master for link head device
618 if (mastershipService.isLocalMaster(connectivity.links().get(0).src().deviceId())) {
619 OpticalConnectivityId connectivityId = connectivity.id();
620
621 log.debug("releasing bandwidth allocated to {}", connectivityId);
622 if (!resourceService.release(connectivityId)) {
623 log.warn("Failed to release bandwidth allocated to {}",
624 connectivityId);
625 // TODO any recovery?
626 }
627 log.debug("DONE releasing bandwidth for {}", connectivityId);
628 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700629 }
630
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800631 private boolean linkDiscoveryEnabled(ConnectPoint cp) {
632 // FIXME should check Device feature and configuration state.
633
634 // short-term hack for ONS'17 time-frame,
635 // only expect OF device to have link discovery.
Jon Halla3fcf672017-03-28 16:53:22 -0700636 return "of".equals(cp.deviceId().uri().getScheme());
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800637 }
638
639 /**
640 * Returns true if both connect point support for link discovery & enabled.
641 *
642 * @param cp1 port 1
643 * @param cp2 port 2
644 * @return true if both connect point support for link discovery & enabled.
645 */
646 private boolean linkDiscoveryEnabled(ConnectPoint cp1, ConnectPoint cp2) {
647 return linkDiscoveryEnabled(cp1) && linkDiscoveryEnabled(cp2);
648 }
649
Naoki Shiota5a056062016-05-05 18:43:59 -0700650 private class BandwidthLinkWeight implements LinkWeight {
651 private Bandwidth bandwidth = null;
652
653 public BandwidthLinkWeight(Bandwidth bandwidth) {
654 this.bandwidth = bandwidth;
655 }
656
657 @Override
658 public double weight(TopologyEdge edge) {
659 Link l = edge.link();
660
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700661 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700662 if (l.state() == Link.State.INACTIVE) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800663 log.trace("{} is not active", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700664 return -1.0;
665 }
666
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700667 // Avoid cross connect links with used ports
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700668 if (isCrossConnectLink(l) && usedCrossConnectLinkSet.contains(l)) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800669 log.trace("Cross connect {} in use", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700670 return -1.0;
671 }
672
673 // Check availability of bandwidth
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800674 if (bandwidth != null && !NO_BW_REQUIREMENT.equals(bandwidth)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700675 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
676 return 1.0;
677 } else {
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700678 log.trace("Not enough bandwidth on {}", l);
Naoki Shiota5a056062016-05-05 18:43:59 -0700679 return -1.0;
680 }
681 } else {
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700682 // Use everything except our own indirect links
683 if (l.type() == Link.Type.INDIRECT) {
684 return -1.0;
Naoki Shiota5a056062016-05-05 18:43:59 -0700685 } else {
Naoki Shiota5a056062016-05-05 18:43:59 -0700686 return 1.0;
687 }
688 }
689 }
690
691 private boolean hasEnoughBandwidth(ConnectPoint cp) {
692 if (cp.elementId() instanceof DeviceId) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700693 Device device = deviceService.getDevice(cp.deviceId());
694 Device.Type type = device.type();
695
Naoki Shiota5a056062016-05-05 18:43:59 -0700696 if (isTransportLayer(type)) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700697 // Check if the port has enough capacity
698 Port port = deviceService.getPort(cp.deviceId(), cp.port());
699 if (port instanceof OduCltPort || port instanceof OchPort) {
700 // Port with capacity
701 return bandwidth.bps() < port.portSpeed() * 1000000.0;
702 } else {
703 // Port without valid capacity (OMS port, etc.)
704 return true;
705 }
706 } else {
707 // Check if enough amount of bandwidth resource remains
708 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
709 .resource(bandwidth.bps());
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800710 try {
711 return resourceService.isAvailable(resource);
712 } catch (Exception e) {
713 log.error("Resource service failed checking availability of {}",
714 resource, e);
715 throw e;
716 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700717 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700718 }
719 return false;
720 }
721 }
722
723
724 public class InternalIntentListener implements IntentListener {
725 @Override
726 public void event(IntentEvent event) {
727 switch (event.type()) {
728 case INSTALLED:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700729 log.debug("Intent {} installed.", event.subject());
Naoki Shiota5a056062016-05-05 18:43:59 -0700730 updateCrossConnectLink(event.subject());
731 break;
732 case WITHDRAWN:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700733 log.debug("Intent {} withdrawn.", event.subject());
Naoki Shiota5a056062016-05-05 18:43:59 -0700734 removeCrossConnectLinks(event.subject());
735 break;
736 case FAILED:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700737 log.debug("Intent {} failed.", event.subject());
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800738 // TODO If it was one of it's own optical Intent,
739 // update link state
740 // TODO If it was packet P2P Intent, call setupConnectivity
Naoki Shiota5a056062016-05-05 18:43:59 -0700741 break;
742 default:
743 break;
744 }
745 }
746
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800747 // TODO rename "CrossConnectLink"?
748 /**
749 * Update packet-layer link/port state once Intent is installed.
750 *
751 * @param intent which reached installed state
752 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700753 private void updateCrossConnectLink(Intent intent) {
754 linkPathMap.entrySet().stream()
755 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
756 .forEach(e -> {
757 ConnectPoint packetSrc = e.getKey().src();
758 ConnectPoint packetDst = e.getKey().dst();
759 Bandwidth bw = e.getKey().bandwidth();
Naoki Shiota5a056062016-05-05 18:43:59 -0700760
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700761 // reflect modification only if packetSrc is local_
762 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
763 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800764 setPortBandwidth(packetSrc, bw);
765 setPortBandwidth(packetDst, bw);
Naoki Shiota5a056062016-05-05 18:43:59 -0700766
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700767 // Updates link status in distributed map
768 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
769 e.getValue().value().setLinkEstablished(packetSrc, packetDst, true));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800770
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800771
772 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
773 injectLink(packetSrc, packetDst);
774 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700775 }
776 });
777 }
778
779 private void removeCrossConnectLinks(Intent intent) {
780 ConnectPoint src, dst;
781
782 if (intent instanceof OpticalCircuitIntent) {
783 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
784 src = circuit.getSrc();
785 dst = circuit.getDst();
786 } else if (intent instanceof OpticalConnectivityIntent) {
787 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
788 src = conn.getSrc();
789 dst = conn.getDst();
790 } else {
791 return;
792 }
793
794 removeXcLinkUsage(src);
795 removeXcLinkUsage(dst);
796
797 // Set bandwidth of 0 to cross connect ports
798 Bandwidth bw = Bandwidth.bps(0);
799 linkPathMap.entrySet().stream()
800 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
801 .forEach(e -> {
802 ConnectPoint packetSrc = e.getKey().src();
803 ConnectPoint packetDst = e.getKey().dst();
Naoki Shiota5a056062016-05-05 18:43:59 -0700804
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700805 // reflect modification only if packetSrc is local_
806 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
807 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800808 setPortBandwidth(packetSrc, bw);
809 setPortBandwidth(packetDst, bw);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700810
811 // Updates link status in distributed map
812 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
813 e.getValue().value().setLinkEstablished(packetSrc, packetDst, false));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800814
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800815
816 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
817 removeInjectedLink(packetSrc, packetDst);
818 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700819 }
820 });
821 }
822
823 private void removeXcLinkUsage(ConnectPoint cp) {
824 Optional<Link> link = linkService.getLinks(cp).stream()
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700825 .filter(usedCrossConnectLinkSet::contains)
Naoki Shiota5a056062016-05-05 18:43:59 -0700826 .findAny();
827
828 if (!link.isPresent()) {
Yuta HIGUCHIe2689ee2017-05-04 16:53:18 -0700829 log.warn("Cross connect point {} has no cross connect link to release.", cp);
Naoki Shiota5a056062016-05-05 18:43:59 -0700830 return;
831 }
832
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700833 usedCrossConnectLinkSet.remove(link.get());
Naoki Shiota5a056062016-05-05 18:43:59 -0700834 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800835
836 /**
837 * Injects link between specified packet port.
838 *
839 * @param packetSrc port 1
840 * @param packetDst port 2
841 */
842 private void injectLink(ConnectPoint packetSrc,
843 ConnectPoint packetDst) {
844 // inject expected link or durable link
845 // if packet device cannot advertise packet link
846 try {
Yuta HIGUCHI21033042017-05-04 17:58:24 -0700847 // cannot call addConfig.
848 // it will create default BasicLinkConfig,
849 // which will end up advertising DIRECT links and
850 // DIRECT Link type cannot transition from DIRECT to INDIRECT
851 LinkKey lnkKey = linkKey(packetSrc, packetDst);
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800852 BasicLinkConfig lnkCfg = networkConfigService
Yuta HIGUCHI21033042017-05-04 17:58:24 -0700853 .getConfig(lnkKey, BasicLinkConfig.class);
854 if (lnkCfg == null) {
855 lnkCfg = new BasicLinkConfig(lnkKey);
856 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800857 lnkCfg.isAllowed(true);
858 lnkCfg.isDurable(true);
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700859 lnkCfg.type(Link.Type.INDIRECT);
860 lnkCfg.isBidirectional(false);
Yuta HIGUCHI21033042017-05-04 17:58:24 -0700861 // cannot call apply against manually created instance
862 //lnkCfg.apply();
863 networkConfigService.applyConfig(lnkKey,
864 BasicLinkConfig.class,
865 lnkCfg.node());
866
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800867 } catch (Exception ex) {
868 log.error("Applying BasicLinkConfig failed", ex);
869 }
870 }
871
872 /**
873 * Removes link injected between specified packet port.
874 *
875 * @param packetSrc port 1
876 * @param packetDst port 2
877 */
878 private void removeInjectedLink(ConnectPoint packetSrc,
879 ConnectPoint packetDst) {
880 // remove expected link or durable link
881 // if packet device cannot monitor packet link
882
883 try {
884 // hack to mark link off-line
885 BasicLinkConfig lnkCfg = networkConfigService
886 .getConfig(linkKey(packetSrc, packetDst),
887 BasicLinkConfig.class);
888 lnkCfg.isAllowed(false);
889 lnkCfg.apply();
890 } catch (Exception ex) {
891 log.error("Applying BasicLinkConfig failed", ex);
892 }
893
894 networkConfigService
895 .removeConfig(linkKey(packetSrc, packetDst),
896 BasicLinkConfig.class);
897 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700898 }
899
900
901 private class InternalLinkListener implements LinkListener {
902
903 @Override
904 public void event(LinkEvent event) {
905 switch (event.type()) {
906 case LINK_REMOVED:
907 Link link = event.subject();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700908 // updates linkPathMap only if src device of link is local
909 if (!mastershipService.isLocalMaster(link.src().deviceId())) {
910 return;
911 }
912
913 // find all packet links that correspond to removed link
Naoki Shiota5a056062016-05-05 18:43:59 -0700914 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
915 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
916 .collect(Collectors.toSet());
917
918 pLinks.forEach(l -> {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700919 // remove found packet links from distributed store
920 linkPathMap.computeIfPresent(l, (plink, conn) -> {
921 // Notifies listeners if all packet links are gone
922 if (conn.isAllRealizingLinkNotEstablished()) {
923 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, conn.id()));
924 }
925 return null;
926 });
Naoki Shiota5a056062016-05-05 18:43:59 -0700927 });
928 default:
929 break;
930 }
931 }
932 }
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700933
934 private class InternalStoreListener
935 implements MapEventListener<PacketLinkRealizedByOptical, OpticalConnectivity> {
936
937 @Override
938 public void event(MapEvent<PacketLinkRealizedByOptical, OpticalConnectivity> event) {
939 switch (event.type()) {
940 case UPDATE:
941 OpticalConnectivity oldConnectivity = event.oldValue().value();
942 OpticalConnectivity newConnectivity = event.newValue().value();
943
944 if (!oldConnectivity.isAllRealizingLinkEstablished() &&
945 newConnectivity.isAllRealizingLinkEstablished()) {
946 // Notifies listeners if all links are established
947 updateBandwidthUsage(newConnectivity);
948 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, newConnectivity.id()));
949 } else if (!oldConnectivity.isAllRealizingLinkNotEstablished() &&
950 newConnectivity.isAllRealizingLinkNotEstablished()) {
951 // Notifies listeners if all links are gone
952 releaseBandwidthUsage(newConnectivity);
953 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, newConnectivity.id()));
954 }
955
956 break;
957 default:
958 break;
959 }
960 }
961
962 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700963}
964