blob: 59ee3d9f392de5ff70640a1bd15571d9b7f519bd [file] [log] [blame]
Naoki Shiota5a056062016-05-05 18:43:59 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070021import org.osgi.service.component.annotations.Activate;
22import org.osgi.service.component.annotations.Component;
23import org.osgi.service.component.annotations.Deactivate;
24import org.osgi.service.component.annotations.Modified;
25import org.osgi.service.component.annotations.Reference;
26import org.osgi.service.component.annotations.ReferenceCardinality;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070027import org.onlab.graph.DefaultEdgeWeigher;
28import org.onlab.graph.ScalarWeight;
29import org.onlab.graph.Weight;
Naoki Shiota5a056062016-05-05 18:43:59 -070030import org.onlab.util.Bandwidth;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070031import org.onlab.util.KryoNamespace;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070032import org.onlab.util.Tools;
Naoki Shiota5a056062016-05-05 18:43:59 -070033import org.onosproject.cluster.ClusterService;
Naoki Shiota5a056062016-05-05 18:43:59 -070034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Naoki Shiota5a056062016-05-05 18:43:59 -070036import org.onosproject.event.AbstractListenerManager;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070037import org.onosproject.event.ListenerTracker;
Naoki Shiota5a056062016-05-05 18:43:59 -070038import org.onosproject.mastership.MastershipService;
Naoki Shiota5a056062016-05-05 18:43:59 -070039import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.Device;
41import org.onosproject.net.DeviceId;
42import org.onosproject.net.Link;
Yuta HIGUCHI21033042017-05-04 17:58:24 -070043import org.onosproject.net.LinkKey;
Naoki Shiota5a056062016-05-05 18:43:59 -070044import org.onosproject.net.Path;
45import org.onosproject.net.Port;
46import org.onosproject.net.config.NetworkConfigService;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070047import org.onosproject.net.config.basics.BandwidthCapacity;
48import org.onosproject.net.config.basics.BasicLinkConfig;
Naoki Shiota5a056062016-05-05 18:43:59 -070049import 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;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070060import org.onosproject.net.optical.OchPort;
61import org.onosproject.net.optical.OduCltPort;
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;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070067import org.onosproject.net.topology.LinkWeigher;
Naoki Shiota5a056062016-05-05 18:43:59 -070068import org.onosproject.net.topology.TopologyEdge;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070069import org.onosproject.net.topology.TopologyService;
70import org.onosproject.net.topology.TopologyVertex;
71import org.onosproject.newoptical.api.OpticalConnectivityId;
72import org.onosproject.newoptical.api.OpticalPathEvent;
73import org.onosproject.newoptical.api.OpticalPathListener;
74import org.onosproject.newoptical.api.OpticalPathService;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070075import org.onosproject.store.serializers.KryoNamespaces;
Naoki Shiota5a056062016-05-05 18:43:59 -070076import org.onosproject.store.service.AtomicCounter;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070077import org.onosproject.store.service.ConsistentMap;
78import org.onosproject.store.service.DistributedSet;
79import org.onosproject.store.service.MapEvent;
80import org.onosproject.store.service.MapEventListener;
81import org.onosproject.store.service.Serializer;
Naoki Shiota5a056062016-05-05 18:43:59 -070082import org.onosproject.store.service.StorageService;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070083import org.onosproject.store.service.Versioned;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070084import org.osgi.service.component.ComponentContext;
Naoki Shiota5a056062016-05-05 18:43:59 -070085import org.slf4j.Logger;
86import org.slf4j.LoggerFactory;
87
88import java.time.Duration;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070089import java.util.ArrayList;
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -080090import java.util.Collection;
Naoki Shiota5a056062016-05-05 18:43:59 -070091import java.util.Collections;
Marc De Leenheer552eeb62017-05-15 17:43:27 -070092import java.util.Dictionary;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070093import java.util.HashMap;
94import java.util.HashSet;
Naoki Shiota5a056062016-05-05 18:43:59 -070095import java.util.Iterator;
96import java.util.LinkedList;
97import java.util.List;
98import java.util.Map;
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -070099import java.util.Map.Entry;
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700100import java.util.Objects;
Naoki Shiota5a056062016-05-05 18:43:59 -0700101import java.util.Optional;
102import java.util.Set;
Naoki Shiota5a056062016-05-05 18:43:59 -0700103import java.util.stream.Collectors;
104import java.util.stream.Stream;
105
106import static com.google.common.base.Preconditions.checkArgument;
107import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800108import static org.onosproject.net.LinkKey.linkKey;
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700109import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
Ray Milkey4694e062018-10-31 13:17:18 -0700110import static org.onosproject.newoptical.OsgiPropertyConstants.MAX_PATHS;
111import static org.onosproject.newoptical.OsgiPropertyConstants.MAX_PATHS_DEFAULT;
Naoki Shiota5a056062016-05-05 18:43:59 -0700112
113/**
114 * Main component to configure optical connectivity.
115 */
116@Beta
Ray Milkey4694e062018-10-31 13:17:18 -0700117@Component(
118 immediate = true,
119 service = OpticalPathService.class,
120 property = {
121 MAX_PATHS + ":Integer=" + MAX_PATHS_DEFAULT
122 }
123)
Naoki Shiota5a056062016-05-05 18:43:59 -0700124public class OpticalPathProvisioner
125 extends AbstractListenerManager<OpticalPathEvent, OpticalPathListener>
126 implements OpticalPathService {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800127
Ray Milkey9c9cde42018-01-12 14:22:06 -0800128 private static final Logger log = LoggerFactory.getLogger(OpticalPathProvisioner.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700129
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800130 /**
131 * Bandwidth representing no bandwidth requirement specified.
132 */
133 private static final Bandwidth NO_BW_REQUIREMENT = Bandwidth.bps(0);
134
Naoki Shiota5a056062016-05-05 18:43:59 -0700135 private static final String OPTICAL_CONNECTIVITY_ID_COUNTER = "optical-connectivity-id";
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700136 private static final String LINKPATH_MAP_NAME = "newoptical-linkpath";
137 private static final String CONNECTIVITY_MAP_NAME = "newoptical-connectivity";
138 private static final String CROSSCONNECTLINK_SET_NAME = "newoptical-crossconnectlink";
Naoki Shiota5a056062016-05-05 18:43:59 -0700139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700141 protected IntentService intentService;
142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700144 protected TopologyService topologyService;
Naoki Shiota5a056062016-05-05 18:43:59 -0700145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700147 protected CoreService coreService;
148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700150 protected LinkService linkService;
151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700153 protected MastershipService mastershipService;
154
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700156 protected ClusterService clusterService;
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700159 protected DeviceService deviceService;
160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700162 protected StorageService storageService;
163
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700165 protected NetworkConfigService networkConfigService;
166
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiota5a056062016-05-05 18:43:59 -0700168 protected ResourceService resourceService;
169
Ray Milkey4694e062018-10-31 13:17:18 -0700170 /** Maximum number of paths to consider for path provisioning. */
171 private int maxPaths = MAX_PATHS_DEFAULT;
Naoki Shiota5a056062016-05-05 18:43:59 -0700172
173 private ApplicationId appId;
174
175 private AtomicCounter idCounter;
176
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700177 private ListenerTracker listeners;
Naoki Shiota5a056062016-05-05 18:43:59 -0700178
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700179 private InternalStoreListener storeListener = new InternalStoreListener();
Naoki Shiota5a056062016-05-05 18:43:59 -0700180
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800181 /**
182 * Map from packet-layer link expected to be realized by some optical Intent to
183 * OpticalConnectivity (~=top level intent over multi-layer topology).
184 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700185 private ConsistentMap<PacketLinkRealizedByOptical, OpticalConnectivity> linkPathMap;
Naoki Shiota5a056062016-05-05 18:43:59 -0700186
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700187 private ConsistentMap<OpticalConnectivityId, OpticalConnectivity> connectivityMap;
188
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800189 // FIXME in the long run. This is effectively app's own resource subsystem
190 /**
191 * Set of cross connect link currently used.
192 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700193 private DistributedSet<Link> usedCrossConnectLinkSet;
194
195 private static final KryoNamespace.Builder LINKPATH_SERIALIZER = KryoNamespace.newBuilder()
196 .register(KryoNamespaces.API)
197 .register(PacketLinkRealizedByOptical.class)
198 .register(OpticalConnectivityId.class)
199 .register(OpticalConnectivity.class);
200
201 private static final KryoNamespace.Builder CONNECTIVITY_SERIALIZER = KryoNamespace.newBuilder()
202 .register(KryoNamespaces.API)
Yuta HIGUCHI0086cf82016-07-18 22:49:45 -0700203 .register(PacketLinkRealizedByOptical.class)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700204 .register(OpticalConnectivityId.class)
205 .register(OpticalConnectivity.class);
206
207 private static final KryoNamespace.Builder CROSSCONNECTLINKS_SERIALIZER = KryoNamespace.newBuilder()
208 .register(KryoNamespaces.API);
Naoki Shiota5a056062016-05-05 18:43:59 -0700209
210 @Activate
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700211 protected void activate(ComponentContext context) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700212 deviceService = opticalView(deviceService);
Naoki Shiota5a056062016-05-05 18:43:59 -0700213 appId = coreService.registerApplication("org.onosproject.newoptical");
214
Naoki Shiota03c29e12016-05-16 16:58:07 -0700215 idCounter = storageService.getAtomicCounter(OPTICAL_CONNECTIVITY_ID_COUNTER);
Naoki Shiota5a056062016-05-05 18:43:59 -0700216
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700217 linkPathMap = storageService.<PacketLinkRealizedByOptical, OpticalConnectivity>consistentMapBuilder()
218 .withSerializer(Serializer.using(LINKPATH_SERIALIZER.build()))
219 .withName(LINKPATH_MAP_NAME)
220 .withApplicationId(appId)
221 .build();
222
223 connectivityMap = storageService.<OpticalConnectivityId, OpticalConnectivity>consistentMapBuilder()
224 .withSerializer(Serializer.using(CONNECTIVITY_SERIALIZER.build()))
225 .withName(CONNECTIVITY_MAP_NAME)
226 .withApplicationId(appId)
227 .build();
228
229 usedCrossConnectLinkSet = storageService.<Link>setBuilder()
230 .withSerializer(Serializer.using(CROSSCONNECTLINKS_SERIALIZER.build()))
231 .withName(CROSSCONNECTLINK_SET_NAME)
232 .withApplicationId(appId)
233 .build()
234 .asDistributedSet();
235
Naoki Shiota5a056062016-05-05 18:43:59 -0700236 eventDispatcher.addSink(OpticalPathEvent.class, listenerRegistry);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700237
238 listeners = new ListenerTracker();
239 listeners.addListener(linkService, new InternalLinkListener())
240 .addListener(intentService, new InternalIntentListener());
Naoki Shiota5a056062016-05-05 18:43:59 -0700241
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700242 linkPathMap.addListener(storeListener);
243
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700244 readComponentConfiguration(context);
245
Naoki Shiota5a056062016-05-05 18:43:59 -0700246 log.info("Started");
247 }
248
249 @Deactivate
250 protected void deactivate() {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700251 linkPathMap.removeListener(storeListener);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700252 listeners.removeListeners();
253 eventDispatcher.removeSink(OpticalPathEvent.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700254
255 log.info("Stopped");
256 }
257
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700258 @Modified
259 public void modified(ComponentContext context) {
260 readComponentConfiguration(context);
261 }
262
263 /**
264 * Extracts properties from the component configuration context.
265 *
266 * @param context the component context
267 */
268 private void readComponentConfiguration(ComponentContext context) {
269 Dictionary<?, ?> properties = context.getProperties();
Ray Milkey4694e062018-10-31 13:17:18 -0700270 maxPaths = Tools.getIntegerProperty(properties, MAX_PATHS, MAX_PATHS_DEFAULT);
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700271 log.info("Configured. Maximum paths to consider is configured to {}", maxPaths);
272 }
273
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -0800274 @Override
275 public Collection<OpticalConnectivity> listConnectivity() {
276 return connectivityMap.values().stream()
277 .map(Versioned::value)
Yuta HIGUCHI498fa1d2017-05-17 16:08:40 -0700278 .collect(ImmutableList.toImmutableList());
Yuta HIGUCHIf167bf92017-03-08 13:19:04 -0800279 }
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -0700280
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700281 @Override
Yuta HIGUCHI8ac05092017-03-15 00:41:22 -0700282 public Set<Key> listIntents(OpticalConnectivityId id) {
283 return linkPathMap.entrySet().stream()
284 .filter(ent -> id.equals(ent.getValue().value().id()))
285 .map(Entry::getKey)
286 .map(PacketLinkRealizedByOptical::realizingIntentKey)
287 .collect(Collectors.toSet());
288 }
289
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800290 /*
291 * Request packet-layer connectivity between specified ports,
292 * over packet-optical multi-layer infrastructure.
293 *
294 * Functionality-wise this is effectively submitting Packet-Optical
295 * multi-layer P2P Intent.
296 *
297 * It computes multi-layer path meeting specified constraint,
298 * and calls setupPath.
299 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700300 @Override
301 public OpticalConnectivityId setupConnectivity(ConnectPoint ingress, ConnectPoint egress,
302 Bandwidth bandwidth, Duration latency) {
303 checkNotNull(ingress);
304 checkNotNull(egress);
305 log.info("setupConnectivity({}, {}, {}, {})", ingress, egress, bandwidth, latency);
306
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700307 Bandwidth bw = (bandwidth == null) ? NO_BW_REQUIREMENT : bandwidth;
Naoki Shiota5a056062016-05-05 18:43:59 -0700308
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700309 Stream<Path> paths = topologyService.getKShortestPaths(
310 topologyService.currentTopology(),
311 ingress.deviceId(), egress.deviceId(),
Naoki Shiota5a056062016-05-05 18:43:59 -0700312 new BandwidthLinkWeight(bandwidth));
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700313
314 // Path service calculates from node to node, we're only interested in port to port
315 Optional<OpticalConnectivityId> id =
316 paths.filter(p -> p.src().equals(ingress) && p.dst().equals(egress))
317 .limit(maxPaths)
318 .map(p -> setupPath(p, bw, latency))
319 .filter(Objects::nonNull)
320 .findFirst();
321
322 if (id.isPresent()) {
323 log.info("Assigned OpticalConnectivityId: {}", id);
324 } else {
325 log.error("setupConnectivity({}, {}, {}, {}) failed.", ingress, egress, bandwidth, latency);
Naoki Shiota5a056062016-05-05 18:43:59 -0700326 }
327
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700328 return id.orElse(null);
Naoki Shiota5a056062016-05-05 18:43:59 -0700329 }
330
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800331 /*
332 * Given a multi-layer path,
333 * compute a set of segments which requires
334 * OpticalConnectivity(~=OpticalConnectivityIntent or OpticalCircuitPath)
335 * to provide packet-layer connectivity.
336 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700337 @Override
338 public OpticalConnectivityId setupPath(Path path, Bandwidth bandwidth, Duration latency) {
339 checkNotNull(path);
Yuta HIGUCHI8fc32f82017-03-14 22:12:42 -0700340 log.debug("setupPath({}, {}, {})", path, bandwidth, latency);
Naoki Shiota5a056062016-05-05 18:43:59 -0700341
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700342 // map of cross connect points (optical port -> packet port)
343 Map<ConnectPoint, ConnectPoint> crossConnectPointMap = new HashMap<>();
344
345 // list of (src, dst) pair of optical ports between which optical path should be installed
346 List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints = new ArrayList<>();
347
348 // Scan path to find pairs of connect points between which optical intent is installed
349 // opticalSrcPort works as a flag parameter to show scanning status
350 ConnectPoint opticalSrcPort = null;
351 for (Link link : path.links()) {
352 if (!isCrossConnectLink(link)) {
353 continue;
354 }
355
356 if (opticalSrcPort != null) {
357 // opticalSrcPort!=null means src port was already found
358 // in this case link.src() is optical layer, and link.dst() is packet layer
359
360 // Check if types of src port and dst port matches
361 Device srcDevice = checkNotNull(deviceService.getDevice(opticalSrcPort.deviceId()),
362 "Unknown device ID");
363 Device dstDevice = checkNotNull(deviceService.getDevice(link.src().deviceId()),
364 "Unknown device ID");
365 if (srcDevice.type() != dstDevice.type()) {
366 log.error("Unsupported mix of cross connect points : {}, {}",
367 srcDevice.type(), dstDevice.type());
368 return null;
369 }
370
371 // Update cross connect points map
372 crossConnectPointMap.put(link.src(), link.dst());
373
374 // Add optical ports pair to list
375 crossConnectPoints.add(Pair.of(opticalSrcPort, link.src()));
376
377 // Reset flag parameter
378 opticalSrcPort = null;
379 } else {
380 // opticalSrcPort==null means src port was not found yet
381 // in this case link.src() is packet layer, and link.dst() is optical layer
382
383 // Update cross connect points map
384 crossConnectPointMap.put(link.dst(), link.src());
385 // Set opticalSrcPort to src of link (optical port)
386 opticalSrcPort = link.dst();
387 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700388 }
389
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700390 // create intents from cross connect points
391 List<Intent> intents = createIntents(crossConnectPoints);
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800392 if (intents.isEmpty()) {
393 log.error("No intents produced from {}", crossConnectPoints);
394 return null;
395 }
396
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700397 // create set of PacketLinkRealizedByOptical
398 Set<PacketLinkRealizedByOptical> packetLinks = createPacketLinkSet(crossConnectPoints,
399 intents, crossConnectPointMap);
400
401 // create OpticalConnectivity object and store information to distributed store
402 OpticalConnectivity connectivity = createConnectivity(path, bandwidth, latency, packetLinks);
Naoki Shiota5a056062016-05-05 18:43:59 -0700403
404 // store cross connect port usage
405 path.links().stream().filter(this::isCrossConnectLink)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700406 .forEach(usedCrossConnectLinkSet::add);
Naoki Shiota5a056062016-05-05 18:43:59 -0700407
408 // Submit the intents
409 for (Intent i : intents) {
410 intentService.submit(i);
411 log.debug("Submitted an intent: {}", i);
412 }
413
414 return connectivity.id();
415 }
416
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700417 private OpticalConnectivity createConnectivity(Path path, Bandwidth bandwidth, Duration latency,
418 Set<PacketLinkRealizedByOptical> links) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700419 OpticalConnectivityId id = OpticalConnectivityId.of(idCounter.getAndIncrement());
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700420 OpticalConnectivity connectivity = new OpticalConnectivity(id, path.links(), bandwidth, latency,
421 links, Collections.emptySet());
422
423 links.forEach(l -> linkPathMap.put(l, connectivity));
Naoki Shiota5a056062016-05-05 18:43:59 -0700424
Naoki Shiota5a056062016-05-05 18:43:59 -0700425 // store connectivity information
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700426 connectivityMap.put(connectivity.id(), connectivity);
Naoki Shiota5a056062016-05-05 18:43:59 -0700427
428 return connectivity;
429 }
430
431 @Override
432 public boolean removeConnectivity(OpticalConnectivityId id) {
433 log.info("removeConnectivity({})", id);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700434 Versioned<OpticalConnectivity> connectivity = connectivityMap.remove(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700435
436 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700437 log.info("OpticalConnectivity with id {} not found.", id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700438 return false;
439 }
440
441 // TODO withdraw intent only if all of connectivities that use the optical path are withdrawn
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700442 connectivity.value().getRealizingLinks().forEach(l -> {
Naoki Shiota5a056062016-05-05 18:43:59 -0700443 Intent intent = intentService.getIntent(l.realizingIntentKey());
444 intentService.withdraw(intent);
445 });
446
447 return true;
448 }
449
450 @Override
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700451 public Optional<List<Link>> getPath(OpticalConnectivityId id) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700452 Versioned<OpticalConnectivity> connectivity = connectivityMap.get(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700453 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700454 log.info("OpticalConnectivity with id {} not found.", id);
455 return Optional.empty();
Naoki Shiota5a056062016-05-05 18:43:59 -0700456 }
457
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700458 return Optional.of(ImmutableList.copyOf(connectivity.value().links()));
Naoki Shiota5a056062016-05-05 18:43:59 -0700459 }
460
461 /**
462 * Scans the list of cross connection points and returns a list of optical connectivity intents.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700463 * During the process, save information about packet links to given set.
Naoki Shiota5a056062016-05-05 18:43:59 -0700464 *
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700465 * @param crossConnectPoints list of (src, dst) pair between which optical path will be set up
Naoki Shiota5a056062016-05-05 18:43:59 -0700466 * @return list of optical connectivity intents
467 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700468 private List<Intent> createIntents(List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700469 List<Intent> intents = new LinkedList<>();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700470 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = crossConnectPoints.iterator();
Naoki Shiota5a056062016-05-05 18:43:59 -0700471
472 while (itr.hasNext()) {
473 // checkArgument at start ensures we'll always have pairs of connect points
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700474 Pair<ConnectPoint, ConnectPoint> next = itr.next();
475 ConnectPoint src = next.getLeft();
476 ConnectPoint dst = next.getRight();
Naoki Shiota5a056062016-05-05 18:43:59 -0700477
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700478 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
479 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
Naoki Shiota5a056062016-05-05 18:43:59 -0700480
481 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700482 OduCltPort srcOCPort = (OduCltPort) srcPort;
483 OduCltPort dstOCPort = (OduCltPort) dstPort;
484 if (!srcOCPort.signalType().equals(dstOCPort.signalType())) {
485 continue;
486 }
487
Naoki Shiota5a056062016-05-05 18:43:59 -0700488 // Create OTN circuit
489 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
490 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700491 .src(src)
492 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700493 .signalType(srcOCPort.signalType())
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700494 .bidirectional(false)
Naoki Shiota5a056062016-05-05 18:43:59 -0700495 .build();
496 intents.add(circuitIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700497 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700498 OchPort srcOchPort = (OchPort) srcPort;
499 OchPort dstOchPort = (OchPort) dstPort;
500 if (!srcOchPort.signalType().equals(dstOchPort.signalType())) {
501 continue;
502 }
503
Naoki Shiota5a056062016-05-05 18:43:59 -0700504 // Create lightpath
Naoki Shiota5a056062016-05-05 18:43:59 -0700505 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.builder()
506 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700507 .src(src)
508 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700509 .signalType(srcOchPort.signalType())
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700510 .bidirectional(false)
Naoki Shiota5a056062016-05-05 18:43:59 -0700511 .build();
512 intents.add(opticalIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700513 } else {
514 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
515 return Collections.emptyList();
516 }
517 }
518
519 return intents;
520 }
521
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700522 private Set<PacketLinkRealizedByOptical> createPacketLinkSet(List<Pair<ConnectPoint, ConnectPoint>> connectPoints,
523 List<Intent> intents,
524 Map<ConnectPoint, ConnectPoint> crossConnectPoints) {
525 checkArgument(connectPoints.size() == intents.size());
526
527 Set<PacketLinkRealizedByOptical> pLinks = new HashSet<>();
528
529 Iterator<Pair<ConnectPoint, ConnectPoint>> xcPointsItr = connectPoints.iterator();
530 Iterator<Intent> intentItr = intents.iterator();
531 while (xcPointsItr.hasNext()) {
532 Pair<ConnectPoint, ConnectPoint> xcPoints = xcPointsItr.next();
533 Intent intent = intentItr.next();
534
535 ConnectPoint packetSrc = checkNotNull(crossConnectPoints.get(xcPoints.getLeft()));
536 ConnectPoint packetDst = checkNotNull(crossConnectPoints.get(xcPoints.getRight()));
537
538 if (intent instanceof OpticalConnectivityIntent) {
539 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
540 (OpticalConnectivityIntent) intent));
541 } else if (intent instanceof OpticalCircuitIntent) {
542 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
543 (OpticalCircuitIntent) intent));
544 } else {
545 log.warn("Unexpected intent type: {}", intent.getClass());
546 }
547 }
548
549 return pLinks;
550 }
551
Naoki Shiota5a056062016-05-05 18:43:59 -0700552 /**
553 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
554 *
555 * @param type device type
556 * @return true if in packet layer, false otherwise
557 */
558 private boolean isPacketLayer(Device.Type type) {
559 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
560 }
561
562 /**
Yuta HIGUCHId2f041e2017-03-10 12:45:15 -0800563 * Verifies if given device type is NOT in packet layer, i.e., switch or router device.
Naoki Shiota5a056062016-05-05 18:43:59 -0700564 *
565 * @param type device type
566 * @return true if in packet layer, false otherwise
567 */
568 private boolean isTransportLayer(Device.Type type) {
569 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
570 }
571
572 /**
573 * Verifies if given link forms a cross-connection between packet and optical layer.
574 *
575 * @param link the link
576 * @return true if the link is a cross-connect link, false otherwise
577 */
578 private boolean isCrossConnectLink(Link link) {
579 if (link.type() != Link.Type.OPTICAL) {
580 return false;
581 }
582
583 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
584 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
585
586 return src != dst &&
587 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
588 }
589
590 /**
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800591 * Updates bandwidth resource of given connect point to specified value.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700592 *
Naoki Shiota5a056062016-05-05 18:43:59 -0700593 * @param cp Connect point
594 * @param bandwidth New bandwidth
595 */
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800596 private void setPortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700597 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
598 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
599 bwCapacity.capacity(bandwidth).apply();
Naoki Shiota5a056062016-05-05 18:43:59 -0700600 }
601
602 /**
603 * Updates usage information of bandwidth based on connectivity which is established.
604 * @param connectivity Optical connectivity
605 */
606 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800607 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
608 // no bandwidth requirement, nothing to allocate.
609 return;
610 }
611
Naoki Shiotacb744db2016-05-13 19:32:35 -0700612 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700613
614 List<Link> links = connectivity.links();
615
616 List<Resource> resources = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
617 .filter(cp -> !isTransportLayer(deviceService.getDevice(cp.deviceId()).type()))
618 .map(cp -> Resources.continuous(cp.deviceId(), cp.port(),
619 Bandwidth.class).resource(connectivity.bandwidth().bps()))
620 .collect(Collectors.toList());
621
Naoki Shiotacb744db2016-05-13 19:32:35 -0700622 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
623 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700624 if (allocations.isEmpty()) {
625 log.warn("Failed to allocate bandwidth {} to {}",
626 connectivity.bandwidth().bps(), resources);
627 // TODO any recovery?
628 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700629 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700630 }
631
632 /**
633 * Release bandwidth allocated by given connectivity.
634 * @param connectivity Optical connectivity
635 */
636 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700637 if (connectivity.links().isEmpty()) {
638 return;
Naoki Shiota5a056062016-05-05 18:43:59 -0700639 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800640 if (NO_BW_REQUIREMENT.equals(connectivity.bandwidth())) {
641 // no bandwidth requirement, nothing to release.
642 return;
643 }
644
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700645
646 // release resource only if this node is the master for link head device
647 if (mastershipService.isLocalMaster(connectivity.links().get(0).src().deviceId())) {
648 OpticalConnectivityId connectivityId = connectivity.id();
649
650 log.debug("releasing bandwidth allocated to {}", connectivityId);
651 if (!resourceService.release(connectivityId)) {
652 log.warn("Failed to release bandwidth allocated to {}",
653 connectivityId);
654 // TODO any recovery?
655 }
656 log.debug("DONE releasing bandwidth for {}", connectivityId);
657 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700658 }
659
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800660 private boolean linkDiscoveryEnabled(ConnectPoint cp) {
661 // FIXME should check Device feature and configuration state.
662
663 // short-term hack for ONS'17 time-frame,
664 // only expect OF device to have link discovery.
Jon Halla3fcf672017-03-28 16:53:22 -0700665 return "of".equals(cp.deviceId().uri().getScheme());
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800666 }
667
668 /**
669 * Returns true if both connect point support for link discovery & enabled.
670 *
671 * @param cp1 port 1
672 * @param cp2 port 2
673 * @return true if both connect point support for link discovery & enabled.
674 */
675 private boolean linkDiscoveryEnabled(ConnectPoint cp1, ConnectPoint cp2) {
676 return linkDiscoveryEnabled(cp1) && linkDiscoveryEnabled(cp2);
677 }
678
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700679 private class BandwidthLinkWeight extends DefaultEdgeWeigher<TopologyVertex, TopologyEdge> implements LinkWeigher {
Naoki Shiota5a056062016-05-05 18:43:59 -0700680 private Bandwidth bandwidth = null;
681
682 public BandwidthLinkWeight(Bandwidth bandwidth) {
683 this.bandwidth = bandwidth;
684 }
685
686 @Override
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700687 public Weight weight(TopologyEdge edge) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700688 Link l = edge.link();
689
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700690 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700691 if (l.state() == Link.State.INACTIVE) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800692 log.trace("{} is not active", l);
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700693 return ScalarWeight.NON_VIABLE_WEIGHT;
Naoki Shiota5a056062016-05-05 18:43:59 -0700694 }
695
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700696 // Avoid cross connect links with used ports
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700697 if (isCrossConnectLink(l) && usedCrossConnectLinkSet.contains(l)) {
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800698 log.trace("Cross connect {} in use", l);
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700699 return ScalarWeight.NON_VIABLE_WEIGHT;
Naoki Shiota5a056062016-05-05 18:43:59 -0700700 }
701
702 // Check availability of bandwidth
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800703 if (bandwidth != null && !NO_BW_REQUIREMENT.equals(bandwidth)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700704 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700705 return new ScalarWeight(1.0);
Naoki Shiota5a056062016-05-05 18:43:59 -0700706 } else {
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700707 log.trace("Not enough bandwidth on {}", l);
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700708 return ScalarWeight.NON_VIABLE_WEIGHT;
Naoki Shiota5a056062016-05-05 18:43:59 -0700709 }
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700710 // Allow everything else
Naoki Shiota5a056062016-05-05 18:43:59 -0700711 } else {
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700712 return new ScalarWeight(1.0);
Naoki Shiota5a056062016-05-05 18:43:59 -0700713 }
714 }
715
716 private boolean hasEnoughBandwidth(ConnectPoint cp) {
717 if (cp.elementId() instanceof DeviceId) {
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700718 Device device = deviceService.getDevice(cp.deviceId());
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700719 Device.Type type = device.type();
720
Naoki Shiota5a056062016-05-05 18:43:59 -0700721 if (isTransportLayer(type)) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700722 // Check if the port has enough capacity
723 Port port = deviceService.getPort(cp.deviceId(), cp.port());
724 if (port instanceof OduCltPort || port instanceof OchPort) {
725 // Port with capacity
726 return bandwidth.bps() < port.portSpeed() * 1000000.0;
727 } else {
728 // Port without valid capacity (OMS port, etc.)
729 return true;
730 }
731 } else {
732 // Check if enough amount of bandwidth resource remains
733 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
734 .resource(bandwidth.bps());
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800735 try {
736 return resourceService.isAvailable(resource);
737 } catch (Exception e) {
738 log.error("Resource service failed checking availability of {}",
Marc De Leenheer552eeb62017-05-15 17:43:27 -0700739 resource, e);
Yuta HIGUCHI806113f2017-03-07 22:46:20 -0800740 throw e;
741 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700742 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700743 }
744 return false;
745 }
746 }
747
Naoki Shiota5a056062016-05-05 18:43:59 -0700748 public class InternalIntentListener implements IntentListener {
749 @Override
750 public void event(IntentEvent event) {
751 switch (event.type()) {
752 case INSTALLED:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700753 log.debug("Intent {} installed.", event.subject());
Naoki Shiota5a056062016-05-05 18:43:59 -0700754 updateCrossConnectLink(event.subject());
755 break;
756 case WITHDRAWN:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700757 log.debug("Intent {} withdrawn.", event.subject());
Naoki Shiota5a056062016-05-05 18:43:59 -0700758 removeCrossConnectLinks(event.subject());
759 break;
760 case FAILED:
Yuta HIGUCHI2a772732017-05-01 20:14:33 -0700761 log.debug("Intent {} failed.", event.subject());
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800762 // TODO If it was one of it's own optical Intent,
763 // update link state
764 // TODO If it was packet P2P Intent, call setupConnectivity
Naoki Shiota5a056062016-05-05 18:43:59 -0700765 break;
766 default:
767 break;
768 }
769 }
770
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800771 // TODO rename "CrossConnectLink"?
772 /**
773 * Update packet-layer link/port state once Intent is installed.
774 *
775 * @param intent which reached installed state
776 */
Naoki Shiota5a056062016-05-05 18:43:59 -0700777 private void updateCrossConnectLink(Intent intent) {
778 linkPathMap.entrySet().stream()
779 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
780 .forEach(e -> {
781 ConnectPoint packetSrc = e.getKey().src();
782 ConnectPoint packetDst = e.getKey().dst();
783 Bandwidth bw = e.getKey().bandwidth();
Naoki Shiota5a056062016-05-05 18:43:59 -0700784
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700785 // reflect modification only if packetSrc is local_
786 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
787 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800788 setPortBandwidth(packetSrc, bw);
789 setPortBandwidth(packetDst, bw);
Naoki Shiota5a056062016-05-05 18:43:59 -0700790
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700791 // Updates link status in distributed map
792 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
793 e.getValue().value().setLinkEstablished(packetSrc, packetDst, true));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800794
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800795
796 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
797 injectLink(packetSrc, packetDst);
798 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700799 }
800 });
801 }
802
803 private void removeCrossConnectLinks(Intent intent) {
804 ConnectPoint src, dst;
805
806 if (intent instanceof OpticalCircuitIntent) {
807 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
808 src = circuit.getSrc();
809 dst = circuit.getDst();
810 } else if (intent instanceof OpticalConnectivityIntent) {
811 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
812 src = conn.getSrc();
813 dst = conn.getDst();
814 } else {
815 return;
816 }
817
818 removeXcLinkUsage(src);
819 removeXcLinkUsage(dst);
820
821 // Set bandwidth of 0 to cross connect ports
822 Bandwidth bw = Bandwidth.bps(0);
823 linkPathMap.entrySet().stream()
824 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
825 .forEach(e -> {
826 ConnectPoint packetSrc = e.getKey().src();
827 ConnectPoint packetDst = e.getKey().dst();
Naoki Shiota5a056062016-05-05 18:43:59 -0700828
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700829 // reflect modification only if packetSrc is local_
830 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
831 // Updates bandwidth of packet ports
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800832 setPortBandwidth(packetSrc, bw);
833 setPortBandwidth(packetDst, bw);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700834
835 // Updates link status in distributed map
836 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
837 e.getValue().value().setLinkEstablished(packetSrc, packetDst, false));
Yuta HIGUCHIe80ec2c2017-03-06 14:16:13 -0800838
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800839
840 if (!linkDiscoveryEnabled(packetSrc, packetDst)) {
841 removeInjectedLink(packetSrc, packetDst);
842 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700843 }
844 });
845 }
846
847 private void removeXcLinkUsage(ConnectPoint cp) {
848 Optional<Link> link = linkService.getLinks(cp).stream()
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700849 .filter(usedCrossConnectLinkSet::contains)
Naoki Shiota5a056062016-05-05 18:43:59 -0700850 .findAny();
851
852 if (!link.isPresent()) {
Yuta HIGUCHIe2689ee2017-05-04 16:53:18 -0700853 log.warn("Cross connect point {} has no cross connect link to release.", cp);
Naoki Shiota5a056062016-05-05 18:43:59 -0700854 return;
855 }
856
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700857 usedCrossConnectLinkSet.remove(link.get());
Naoki Shiota5a056062016-05-05 18:43:59 -0700858 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800859
860 /**
861 * Injects link between specified packet port.
862 *
863 * @param packetSrc port 1
864 * @param packetDst port 2
865 */
866 private void injectLink(ConnectPoint packetSrc,
867 ConnectPoint packetDst) {
868 // inject expected link or durable link
869 // if packet device cannot advertise packet link
870 try {
Yuta HIGUCHI21033042017-05-04 17:58:24 -0700871 // cannot call addConfig.
872 // it will create default BasicLinkConfig,
873 // which will end up advertising DIRECT links and
874 // DIRECT Link type cannot transition from DIRECT to INDIRECT
875 LinkKey lnkKey = linkKey(packetSrc, packetDst);
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800876 BasicLinkConfig lnkCfg = networkConfigService
Yuta HIGUCHI21033042017-05-04 17:58:24 -0700877 .getConfig(lnkKey, BasicLinkConfig.class);
878 if (lnkCfg == null) {
879 lnkCfg = new BasicLinkConfig(lnkKey);
880 }
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800881 lnkCfg.isAllowed(true);
882 lnkCfg.isDurable(true);
Marc De Leenheer43b91ad2017-03-17 14:45:28 -0700883 lnkCfg.type(Link.Type.INDIRECT);
884 lnkCfg.isBidirectional(false);
Yuta HIGUCHI21033042017-05-04 17:58:24 -0700885 // cannot call apply against manually created instance
886 //lnkCfg.apply();
887 networkConfigService.applyConfig(lnkKey,
888 BasicLinkConfig.class,
889 lnkCfg.node());
890
Yuta HIGUCHI9b9c7292017-03-07 22:50:04 -0800891 } catch (Exception ex) {
892 log.error("Applying BasicLinkConfig failed", ex);
893 }
894 }
895
896 /**
897 * Removes link injected between specified packet port.
898 *
899 * @param packetSrc port 1
900 * @param packetDst port 2
901 */
902 private void removeInjectedLink(ConnectPoint packetSrc,
903 ConnectPoint packetDst) {
904 // remove expected link or durable link
905 // if packet device cannot monitor packet link
906
907 try {
908 // hack to mark link off-line
909 BasicLinkConfig lnkCfg = networkConfigService
910 .getConfig(linkKey(packetSrc, packetDst),
911 BasicLinkConfig.class);
912 lnkCfg.isAllowed(false);
913 lnkCfg.apply();
914 } catch (Exception ex) {
915 log.error("Applying BasicLinkConfig failed", ex);
916 }
917
918 networkConfigService
919 .removeConfig(linkKey(packetSrc, packetDst),
920 BasicLinkConfig.class);
921 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700922 }
923
924
925 private class InternalLinkListener implements LinkListener {
926
927 @Override
928 public void event(LinkEvent event) {
929 switch (event.type()) {
930 case LINK_REMOVED:
931 Link link = event.subject();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700932 // updates linkPathMap only if src device of link is local
933 if (!mastershipService.isLocalMaster(link.src().deviceId())) {
934 return;
935 }
936
937 // find all packet links that correspond to removed link
Naoki Shiota5a056062016-05-05 18:43:59 -0700938 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
939 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
940 .collect(Collectors.toSet());
941
942 pLinks.forEach(l -> {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700943 // remove found packet links from distributed store
944 linkPathMap.computeIfPresent(l, (plink, conn) -> {
945 // Notifies listeners if all packet links are gone
946 if (conn.isAllRealizingLinkNotEstablished()) {
947 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, conn.id()));
948 }
949 return null;
950 });
Naoki Shiota5a056062016-05-05 18:43:59 -0700951 });
952 default:
953 break;
954 }
955 }
956 }
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700957
958 private class InternalStoreListener
959 implements MapEventListener<PacketLinkRealizedByOptical, OpticalConnectivity> {
960
961 @Override
962 public void event(MapEvent<PacketLinkRealizedByOptical, OpticalConnectivity> event) {
963 switch (event.type()) {
964 case UPDATE:
965 OpticalConnectivity oldConnectivity = event.oldValue().value();
966 OpticalConnectivity newConnectivity = event.newValue().value();
967
968 if (!oldConnectivity.isAllRealizingLinkEstablished() &&
969 newConnectivity.isAllRealizingLinkEstablished()) {
970 // Notifies listeners if all links are established
971 updateBandwidthUsage(newConnectivity);
972 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, newConnectivity.id()));
973 } else if (!oldConnectivity.isAllRealizingLinkNotEstablished() &&
974 newConnectivity.isAllRealizingLinkNotEstablished()) {
975 // Notifies listeners if all links are gone
976 releaseBandwidthUsage(newConnectivity);
977 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, newConnectivity.id()));
978 }
979
980 break;
981 default:
982 break;
983 }
984 }
985
986 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700987}
988