blob: 906fe3373dc7276f6c59f7242ca33b87bfbacd98 [file] [log] [blame]
Naoki Shiota5a056062016-05-05 18:43:59 -07001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.newoptical;
17
18import com.google.common.annotations.Beta;
19import com.google.common.collect.ImmutableList;
Naoki Shiota5a056062016-05-05 18:43:59 -070020
21import org.apache.commons.lang3.tuple.Pair;
22import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
28import org.onlab.util.Bandwidth;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070029import org.onlab.util.KryoNamespace;
Naoki Shiota5a056062016-05-05 18:43:59 -070030import org.onosproject.cluster.ClusterService;
Naoki Shiota5a056062016-05-05 18:43:59 -070031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Naoki Shiota0d2943e2016-05-13 18:53:21 -070033import org.onosproject.event.ListenerTracker;
34import org.onosproject.net.optical.OchPort;
35import org.onosproject.net.optical.OduCltPort;
Naoki Shiota5a056062016-05-05 18:43:59 -070036import org.onosproject.newoptical.api.OpticalConnectivityId;
37import org.onosproject.newoptical.api.OpticalPathEvent;
38import org.onosproject.newoptical.api.OpticalPathListener;
39import org.onosproject.newoptical.api.OpticalPathService;
40import org.onosproject.event.AbstractListenerManager;
41import org.onosproject.mastership.MastershipService;
Naoki Shiota5a056062016-05-05 18:43:59 -070042import org.onosproject.net.ConnectPoint;
43import org.onosproject.net.Device;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Link;
Naoki Shiota5a056062016-05-05 18:43:59 -070046import org.onosproject.net.Path;
47import org.onosproject.net.Port;
48import org.onosproject.net.config.NetworkConfigService;
49import org.onosproject.net.device.DeviceService;
50import org.onosproject.net.intent.Intent;
51import org.onosproject.net.intent.IntentEvent;
Naoki Shiota5a056062016-05-05 18:43:59 -070052import org.onosproject.net.intent.IntentListener;
53import org.onosproject.net.intent.IntentService;
Naoki Shiota5a056062016-05-05 18:43:59 -070054import org.onosproject.net.intent.OpticalCircuitIntent;
55import org.onosproject.net.intent.OpticalConnectivityIntent;
Naoki Shiota5a056062016-05-05 18:43:59 -070056import org.onosproject.net.link.LinkEvent;
57import org.onosproject.net.link.LinkListener;
58import org.onosproject.net.link.LinkService;
Sho SHIMIZUb6c63a32016-05-26 12:07:19 -070059import org.onosproject.net.config.basics.BandwidthCapacity;
Naoki Shiota5a056062016-05-05 18:43:59 -070060import org.onosproject.net.resource.ContinuousResource;
61import org.onosproject.net.resource.Resource;
62import org.onosproject.net.resource.ResourceAllocation;
63import org.onosproject.net.resource.ResourceService;
64import org.onosproject.net.resource.Resources;
65import org.onosproject.net.topology.LinkWeight;
66import org.onosproject.net.topology.PathService;
67import org.onosproject.net.topology.TopologyEdge;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070068import org.onosproject.store.serializers.KryoNamespaces;
Naoki Shiota5a056062016-05-05 18:43:59 -070069import org.onosproject.store.service.AtomicCounter;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070070import org.onosproject.store.service.ConsistentMap;
71import org.onosproject.store.service.DistributedSet;
72import org.onosproject.store.service.MapEvent;
73import org.onosproject.store.service.MapEventListener;
74import org.onosproject.store.service.Serializer;
Naoki Shiota5a056062016-05-05 18:43:59 -070075import org.onosproject.store.service.StorageService;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070076import org.onosproject.store.service.Versioned;
Naoki Shiota5a056062016-05-05 18:43:59 -070077import org.slf4j.Logger;
78import org.slf4j.LoggerFactory;
79
80import java.time.Duration;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070081import java.util.ArrayList;
Naoki Shiota5a056062016-05-05 18:43:59 -070082import java.util.Collections;
Naoki Shiota7c3111b2016-06-09 16:12:11 -070083import java.util.HashMap;
84import java.util.HashSet;
Naoki Shiota5a056062016-05-05 18:43:59 -070085import java.util.Iterator;
86import java.util.LinkedList;
87import java.util.List;
88import java.util.Map;
89import java.util.Optional;
90import java.util.Set;
Naoki Shiota5a056062016-05-05 18:43:59 -070091import java.util.stream.Collectors;
92import java.util.stream.Stream;
93
94import static com.google.common.base.Preconditions.checkArgument;
95import static com.google.common.base.Preconditions.checkNotNull;
Naoki Shiotae1366ad2016-05-11 19:24:11 -070096import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
Naoki Shiota5a056062016-05-05 18:43:59 -070097
98/**
99 * Main component to configure optical connectivity.
100 */
101@Beta
102@Service
103@Component(immediate = true)
104public class OpticalPathProvisioner
105 extends AbstractListenerManager<OpticalPathEvent, OpticalPathListener>
106 implements OpticalPathService {
107 protected static final Logger log = LoggerFactory.getLogger(OpticalPathProvisioner.class);
108
109 private static final String OPTICAL_CONNECTIVITY_ID_COUNTER = "optical-connectivity-id";
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700110 private static final String LINKPATH_MAP_NAME = "newoptical-linkpath";
111 private static final String CONNECTIVITY_MAP_NAME = "newoptical-connectivity";
112 private static final String CROSSCONNECTLINK_SET_NAME = "newoptical-crossconnectlink";
Naoki Shiota5a056062016-05-05 18:43:59 -0700113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected IntentService intentService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected PathService pathService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected CoreService coreService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected LinkService linkService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected MastershipService mastershipService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected ClusterService clusterService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected DeviceService deviceService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected StorageService storageService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected NetworkConfigService networkConfigService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected ResourceService resourceService;
143
144
145 private ApplicationId appId;
146
147 private AtomicCounter idCounter;
148
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700149 private ListenerTracker listeners;
Naoki Shiota5a056062016-05-05 18:43:59 -0700150
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700151 private InternalStoreListener storeListener = new InternalStoreListener();
Naoki Shiota5a056062016-05-05 18:43:59 -0700152
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700153 private ConsistentMap<PacketLinkRealizedByOptical, OpticalConnectivity> linkPathMap;
Naoki Shiota5a056062016-05-05 18:43:59 -0700154
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700155 private ConsistentMap<OpticalConnectivityId, OpticalConnectivity> connectivityMap;
156
Naoki Shiota5a056062016-05-05 18:43:59 -0700157 // Map of cross connect link and installed path which uses the link
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700158 private DistributedSet<Link> usedCrossConnectLinkSet;
159
160 private static final KryoNamespace.Builder LINKPATH_SERIALIZER = KryoNamespace.newBuilder()
161 .register(KryoNamespaces.API)
162 .register(PacketLinkRealizedByOptical.class)
163 .register(OpticalConnectivityId.class)
164 .register(OpticalConnectivity.class);
165
166 private static final KryoNamespace.Builder CONNECTIVITY_SERIALIZER = KryoNamespace.newBuilder()
167 .register(KryoNamespaces.API)
168 .register(OpticalConnectivityId.class)
169 .register(OpticalConnectivity.class);
170
171 private static final KryoNamespace.Builder CROSSCONNECTLINKS_SERIALIZER = KryoNamespace.newBuilder()
172 .register(KryoNamespaces.API);
Naoki Shiota5a056062016-05-05 18:43:59 -0700173
174 @Activate
175 protected void activate() {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700176 deviceService = opticalView(deviceService);
Naoki Shiota5a056062016-05-05 18:43:59 -0700177 appId = coreService.registerApplication("org.onosproject.newoptical");
178
Naoki Shiota03c29e12016-05-16 16:58:07 -0700179 idCounter = storageService.getAtomicCounter(OPTICAL_CONNECTIVITY_ID_COUNTER);
Naoki Shiota5a056062016-05-05 18:43:59 -0700180
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700181 linkPathMap = storageService.<PacketLinkRealizedByOptical, OpticalConnectivity>consistentMapBuilder()
182 .withSerializer(Serializer.using(LINKPATH_SERIALIZER.build()))
183 .withName(LINKPATH_MAP_NAME)
184 .withApplicationId(appId)
185 .build();
186
187 connectivityMap = storageService.<OpticalConnectivityId, OpticalConnectivity>consistentMapBuilder()
188 .withSerializer(Serializer.using(CONNECTIVITY_SERIALIZER.build()))
189 .withName(CONNECTIVITY_MAP_NAME)
190 .withApplicationId(appId)
191 .build();
192
193 usedCrossConnectLinkSet = storageService.<Link>setBuilder()
194 .withSerializer(Serializer.using(CROSSCONNECTLINKS_SERIALIZER.build()))
195 .withName(CROSSCONNECTLINK_SET_NAME)
196 .withApplicationId(appId)
197 .build()
198 .asDistributedSet();
199
Naoki Shiota5a056062016-05-05 18:43:59 -0700200 eventDispatcher.addSink(OpticalPathEvent.class, listenerRegistry);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700201
202 listeners = new ListenerTracker();
203 listeners.addListener(linkService, new InternalLinkListener())
204 .addListener(intentService, new InternalIntentListener());
Naoki Shiota5a056062016-05-05 18:43:59 -0700205
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700206 linkPathMap.addListener(storeListener);
207
Naoki Shiota5a056062016-05-05 18:43:59 -0700208 log.info("Started");
209 }
210
211 @Deactivate
212 protected void deactivate() {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700213 linkPathMap.removeListener(storeListener);
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700214 listeners.removeListeners();
215 eventDispatcher.removeSink(OpticalPathEvent.class);
Naoki Shiota5a056062016-05-05 18:43:59 -0700216
217 log.info("Stopped");
218 }
219
220 @Override
221 public OpticalConnectivityId setupConnectivity(ConnectPoint ingress, ConnectPoint egress,
222 Bandwidth bandwidth, Duration latency) {
223 checkNotNull(ingress);
224 checkNotNull(egress);
225 log.info("setupConnectivity({}, {}, {}, {})", ingress, egress, bandwidth, latency);
226
227 bandwidth = (bandwidth == null) ? Bandwidth.bps(0) : bandwidth;
228
229 Set<Path> paths = pathService.getPaths(ingress.deviceId(), egress.deviceId(),
230 new BandwidthLinkWeight(bandwidth));
231 if (paths.isEmpty()) {
232 log.warn("Unable to find multi-layer path.");
233 return null;
234 }
235
236 // Search path with available cross connect points
237 for (Path path : paths) {
238 OpticalConnectivityId id = setupPath(path, bandwidth, latency);
239 if (id != null) {
240 log.info("Assigned OpticalConnectivityId: {}", id);
241 return id;
242 }
243 }
244
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700245 log.info("setupConnectivity({}, {}, {}, {}) failed.", ingress, egress, bandwidth, latency);
246
Naoki Shiota5a056062016-05-05 18:43:59 -0700247 return null;
248 }
249
250 @Override
251 public OpticalConnectivityId setupPath(Path path, Bandwidth bandwidth, Duration latency) {
252 checkNotNull(path);
253 log.info("setupPath({}, {}, {})", path, bandwidth, latency);
254
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700255 // map of cross connect points (optical port -> packet port)
256 Map<ConnectPoint, ConnectPoint> crossConnectPointMap = new HashMap<>();
257
258 // list of (src, dst) pair of optical ports between which optical path should be installed
259 List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints = new ArrayList<>();
260
261 // Scan path to find pairs of connect points between which optical intent is installed
262 // opticalSrcPort works as a flag parameter to show scanning status
263 ConnectPoint opticalSrcPort = null;
264 for (Link link : path.links()) {
265 if (!isCrossConnectLink(link)) {
266 continue;
267 }
268
269 if (opticalSrcPort != null) {
270 // opticalSrcPort!=null means src port was already found
271 // in this case link.src() is optical layer, and link.dst() is packet layer
272
273 // Check if types of src port and dst port matches
274 Device srcDevice = checkNotNull(deviceService.getDevice(opticalSrcPort.deviceId()),
275 "Unknown device ID");
276 Device dstDevice = checkNotNull(deviceService.getDevice(link.src().deviceId()),
277 "Unknown device ID");
278 if (srcDevice.type() != dstDevice.type()) {
279 log.error("Unsupported mix of cross connect points : {}, {}",
280 srcDevice.type(), dstDevice.type());
281 return null;
282 }
283
284 // Update cross connect points map
285 crossConnectPointMap.put(link.src(), link.dst());
286
287 // Add optical ports pair to list
288 crossConnectPoints.add(Pair.of(opticalSrcPort, link.src()));
289
290 // Reset flag parameter
291 opticalSrcPort = null;
292 } else {
293 // opticalSrcPort==null means src port was not found yet
294 // in this case link.src() is packet layer, and link.dst() is optical layer
295
296 // Update cross connect points map
297 crossConnectPointMap.put(link.dst(), link.src());
298 // Set opticalSrcPort to src of link (optical port)
299 opticalSrcPort = link.dst();
300 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700301 }
302
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700303 // create intents from cross connect points
304 List<Intent> intents = createIntents(crossConnectPoints);
Naoki Shiota5a056062016-05-05 18:43:59 -0700305
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700306 // create set of PacketLinkRealizedByOptical
307 Set<PacketLinkRealizedByOptical> packetLinks = createPacketLinkSet(crossConnectPoints,
308 intents, crossConnectPointMap);
309
310 // create OpticalConnectivity object and store information to distributed store
311 OpticalConnectivity connectivity = createConnectivity(path, bandwidth, latency, packetLinks);
Naoki Shiota5a056062016-05-05 18:43:59 -0700312
313 // store cross connect port usage
314 path.links().stream().filter(this::isCrossConnectLink)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700315 .forEach(usedCrossConnectLinkSet::add);
Naoki Shiota5a056062016-05-05 18:43:59 -0700316
317 // Submit the intents
318 for (Intent i : intents) {
319 intentService.submit(i);
320 log.debug("Submitted an intent: {}", i);
321 }
322
323 return connectivity.id();
324 }
325
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700326 private OpticalConnectivity createConnectivity(Path path, Bandwidth bandwidth, Duration latency,
327 Set<PacketLinkRealizedByOptical> links) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700328 OpticalConnectivityId id = OpticalConnectivityId.of(idCounter.getAndIncrement());
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700329 OpticalConnectivity connectivity = new OpticalConnectivity(id, path.links(), bandwidth, latency,
330 links, Collections.emptySet());
331
332 links.forEach(l -> linkPathMap.put(l, connectivity));
Naoki Shiota5a056062016-05-05 18:43:59 -0700333
Naoki Shiota5a056062016-05-05 18:43:59 -0700334 // store connectivity information
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700335 connectivityMap.put(connectivity.id(), connectivity);
Naoki Shiota5a056062016-05-05 18:43:59 -0700336
337 return connectivity;
338 }
339
340 @Override
341 public boolean removeConnectivity(OpticalConnectivityId id) {
342 log.info("removeConnectivity({})", id);
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700343 Versioned<OpticalConnectivity> connectivity = connectivityMap.remove(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700344
345 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700346 log.info("OpticalConnectivity with id {} not found.", id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700347 return false;
348 }
349
350 // TODO withdraw intent only if all of connectivities that use the optical path are withdrawn
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700351 connectivity.value().getRealizingLinks().forEach(l -> {
Naoki Shiota5a056062016-05-05 18:43:59 -0700352 Intent intent = intentService.getIntent(l.realizingIntentKey());
353 intentService.withdraw(intent);
354 });
355
356 return true;
357 }
358
359 @Override
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700360 public Optional<List<Link>> getPath(OpticalConnectivityId id) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700361 Versioned<OpticalConnectivity> connectivity = connectivityMap.get(id);
Naoki Shiota5a056062016-05-05 18:43:59 -0700362 if (connectivity == null) {
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700363 log.info("OpticalConnectivity with id {} not found.", id);
364 return Optional.empty();
Naoki Shiota5a056062016-05-05 18:43:59 -0700365 }
366
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700367 return Optional.of(ImmutableList.copyOf(connectivity.value().links()));
Naoki Shiota5a056062016-05-05 18:43:59 -0700368 }
369
370 /**
371 * Scans the list of cross connection points and returns a list of optical connectivity intents.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700372 * During the process, save information about packet links to given set.
Naoki Shiota5a056062016-05-05 18:43:59 -0700373 *
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700374 * @param crossConnectPoints list of (src, dst) pair between which optical path will be set up
Naoki Shiota5a056062016-05-05 18:43:59 -0700375 * @return list of optical connectivity intents
376 */
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700377 private List<Intent> createIntents(List<Pair<ConnectPoint, ConnectPoint>> crossConnectPoints) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700378 List<Intent> intents = new LinkedList<>();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700379 Iterator<Pair<ConnectPoint, ConnectPoint>> itr = crossConnectPoints.iterator();
Naoki Shiota5a056062016-05-05 18:43:59 -0700380
381 while (itr.hasNext()) {
382 // checkArgument at start ensures we'll always have pairs of connect points
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700383 Pair<ConnectPoint, ConnectPoint> next = itr.next();
384 ConnectPoint src = next.getLeft();
385 ConnectPoint dst = next.getRight();
Naoki Shiota5a056062016-05-05 18:43:59 -0700386
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700387 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
388 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
Naoki Shiota5a056062016-05-05 18:43:59 -0700389
390 if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700391 OduCltPort srcOCPort = (OduCltPort) srcPort;
392 OduCltPort dstOCPort = (OduCltPort) dstPort;
393 if (!srcOCPort.signalType().equals(dstOCPort.signalType())) {
394 continue;
395 }
396
Naoki Shiota5a056062016-05-05 18:43:59 -0700397 // Create OTN circuit
398 OpticalCircuitIntent circuitIntent = OpticalCircuitIntent.builder()
399 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700400 .src(src)
401 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700402 .signalType(srcOCPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700403 .bidirectional(true)
404 .build();
405 intents.add(circuitIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700406 } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700407 OchPort srcOchPort = (OchPort) srcPort;
408 OchPort dstOchPort = (OchPort) dstPort;
409 if (!srcOchPort.signalType().equals(dstOchPort.signalType())) {
410 continue;
411 }
412
Naoki Shiota5a056062016-05-05 18:43:59 -0700413 // Create lightpath
Naoki Shiota5a056062016-05-05 18:43:59 -0700414 OpticalConnectivityIntent opticalIntent = OpticalConnectivityIntent.builder()
415 .appId(appId)
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700416 .src(src)
417 .dst(dst)
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700418 .signalType(srcOchPort.signalType())
Naoki Shiota5a056062016-05-05 18:43:59 -0700419 .bidirectional(true)
420 .build();
421 intents.add(opticalIntent);
Naoki Shiota5a056062016-05-05 18:43:59 -0700422 } else {
423 log.warn("Unsupported cross connect point types {} {}", srcPort.type(), dstPort.type());
424 return Collections.emptyList();
425 }
426 }
427
428 return intents;
429 }
430
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700431 private Set<PacketLinkRealizedByOptical> createPacketLinkSet(List<Pair<ConnectPoint, ConnectPoint>> connectPoints,
432 List<Intent> intents,
433 Map<ConnectPoint, ConnectPoint> crossConnectPoints) {
434 checkArgument(connectPoints.size() == intents.size());
435
436 Set<PacketLinkRealizedByOptical> pLinks = new HashSet<>();
437
438 Iterator<Pair<ConnectPoint, ConnectPoint>> xcPointsItr = connectPoints.iterator();
439 Iterator<Intent> intentItr = intents.iterator();
440 while (xcPointsItr.hasNext()) {
441 Pair<ConnectPoint, ConnectPoint> xcPoints = xcPointsItr.next();
442 Intent intent = intentItr.next();
443
444 ConnectPoint packetSrc = checkNotNull(crossConnectPoints.get(xcPoints.getLeft()));
445 ConnectPoint packetDst = checkNotNull(crossConnectPoints.get(xcPoints.getRight()));
446
447 if (intent instanceof OpticalConnectivityIntent) {
448 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
449 (OpticalConnectivityIntent) intent));
450 } else if (intent instanceof OpticalCircuitIntent) {
451 pLinks.add(PacketLinkRealizedByOptical.create(packetSrc, packetDst,
452 (OpticalCircuitIntent) intent));
453 } else {
454 log.warn("Unexpected intent type: {}", intent.getClass());
455 }
456 }
457
458 return pLinks;
459 }
460
Naoki Shiota5a056062016-05-05 18:43:59 -0700461 /**
462 * Verifies if given device type is in packet layer, i.e., ROADM, OTN or ROADM_OTN device.
463 *
464 * @param type device type
465 * @return true if in packet layer, false otherwise
466 */
467 private boolean isPacketLayer(Device.Type type) {
468 return type == Device.Type.SWITCH || type == Device.Type.ROUTER || type == Device.Type.VIRTUAL;
469 }
470
471 /**
472 * Verifies if given device type is in packet layer, i.e., switch or router device.
473 *
474 * @param type device type
475 * @return true if in packet layer, false otherwise
476 */
477 private boolean isTransportLayer(Device.Type type) {
478 return type == Device.Type.ROADM || type == Device.Type.OTN || type == Device.Type.ROADM_OTN;
479 }
480
481 /**
482 * Verifies if given link forms a cross-connection between packet and optical layer.
483 *
484 * @param link the link
485 * @return true if the link is a cross-connect link, false otherwise
486 */
487 private boolean isCrossConnectLink(Link link) {
488 if (link.type() != Link.Type.OPTICAL) {
489 return false;
490 }
491
492 Device.Type src = deviceService.getDevice(link.src().deviceId()).type();
493 Device.Type dst = deviceService.getDevice(link.dst().deviceId()).type();
494
495 return src != dst &&
496 ((isPacketLayer(src) && isTransportLayer(dst)) || (isPacketLayer(dst) && isTransportLayer(src)));
497 }
498
499 /**
500 * Updates bandwidth resource of given connect point.
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700501 *
Naoki Shiota5a056062016-05-05 18:43:59 -0700502 * @param cp Connect point
503 * @param bandwidth New bandwidth
504 */
505 private void updatePortBandwidth(ConnectPoint cp, Bandwidth bandwidth) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700506 log.debug("update Port {} Bandwidth {}", cp, bandwidth);
507 BandwidthCapacity bwCapacity = networkConfigService.addConfig(cp, BandwidthCapacity.class);
508 bwCapacity.capacity(bandwidth).apply();
Naoki Shiota5a056062016-05-05 18:43:59 -0700509 }
510
511 /**
512 * Updates usage information of bandwidth based on connectivity which is established.
513 * @param connectivity Optical connectivity
514 */
515 private void updateBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiotacb744db2016-05-13 19:32:35 -0700516 OpticalConnectivityId connectivityId = connectivity.id();
Naoki Shiota5a056062016-05-05 18:43:59 -0700517
518 List<Link> links = connectivity.links();
519
520 List<Resource> resources = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
521 .filter(cp -> !isTransportLayer(deviceService.getDevice(cp.deviceId()).type()))
522 .map(cp -> Resources.continuous(cp.deviceId(), cp.port(),
523 Bandwidth.class).resource(connectivity.bandwidth().bps()))
524 .collect(Collectors.toList());
525
Naoki Shiotacb744db2016-05-13 19:32:35 -0700526 log.debug("allocating bandwidth for {} : {}", connectivityId, resources);
527 List<ResourceAllocation> allocations = resourceService.allocate(connectivityId, resources);
Naoki Shiota5a056062016-05-05 18:43:59 -0700528 if (allocations.isEmpty()) {
529 log.warn("Failed to allocate bandwidth {} to {}",
530 connectivity.bandwidth().bps(), resources);
531 // TODO any recovery?
532 }
Naoki Shiotacb744db2016-05-13 19:32:35 -0700533 log.debug("Done allocating bandwidth for {}", connectivityId);
Naoki Shiota5a056062016-05-05 18:43:59 -0700534 }
535
536 /**
537 * Release bandwidth allocated by given connectivity.
538 * @param connectivity Optical connectivity
539 */
540 private void releaseBandwidthUsage(OpticalConnectivity connectivity) {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700541 if (connectivity.links().isEmpty()) {
542 return;
Naoki Shiota5a056062016-05-05 18:43:59 -0700543 }
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700544
545 // release resource only if this node is the master for link head device
546 if (mastershipService.isLocalMaster(connectivity.links().get(0).src().deviceId())) {
547 OpticalConnectivityId connectivityId = connectivity.id();
548
549 log.debug("releasing bandwidth allocated to {}", connectivityId);
550 if (!resourceService.release(connectivityId)) {
551 log.warn("Failed to release bandwidth allocated to {}",
552 connectivityId);
553 // TODO any recovery?
554 }
555 log.debug("DONE releasing bandwidth for {}", connectivityId);
556 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700557 }
558
559 private class BandwidthLinkWeight implements LinkWeight {
560 private Bandwidth bandwidth = null;
561
562 public BandwidthLinkWeight(Bandwidth bandwidth) {
563 this.bandwidth = bandwidth;
564 }
565
566 @Override
567 public double weight(TopologyEdge edge) {
568 Link l = edge.link();
569
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700570 // Avoid inactive links
Naoki Shiota5a056062016-05-05 18:43:59 -0700571 if (l.state() == Link.State.INACTIVE) {
572 return -1.0;
573 }
574
Naoki Shiota0d2943e2016-05-13 18:53:21 -0700575 // Avoid cross connect links with used ports
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700576 if (isCrossConnectLink(l) && usedCrossConnectLinkSet.contains(l)) {
Naoki Shiota5a056062016-05-05 18:43:59 -0700577 return -1.0;
578 }
579
580 // Check availability of bandwidth
581 if (bandwidth != null) {
582 if (hasEnoughBandwidth(l.src()) && hasEnoughBandwidth(l.dst())) {
583 return 1.0;
584 } else {
585 return -1.0;
586 }
587 } else {
588 // TODO needs to differentiate optical and packet?
589 if (l.type() == Link.Type.OPTICAL) {
590 // Transport links
591 return 1.0;
592 } else {
593 // Packet links
594 return 1.0;
595 }
596 }
597 }
598
599 private boolean hasEnoughBandwidth(ConnectPoint cp) {
600 if (cp.elementId() instanceof DeviceId) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700601 Device device = deviceService.getDevice(cp.deviceId());
602 Device.Type type = device.type();
603
Naoki Shiota5a056062016-05-05 18:43:59 -0700604 if (isTransportLayer(type)) {
Naoki Shiotae1366ad2016-05-11 19:24:11 -0700605 // Check if the port has enough capacity
606 Port port = deviceService.getPort(cp.deviceId(), cp.port());
607 if (port instanceof OduCltPort || port instanceof OchPort) {
608 // Port with capacity
609 return bandwidth.bps() < port.portSpeed() * 1000000.0;
610 } else {
611 // Port without valid capacity (OMS port, etc.)
612 return true;
613 }
614 } else {
615 // Check if enough amount of bandwidth resource remains
616 ContinuousResource resource = Resources.continuous(cp.deviceId(), cp.port(), Bandwidth.class)
617 .resource(bandwidth.bps());
618 return resourceService.isAvailable(resource);
Naoki Shiota5a056062016-05-05 18:43:59 -0700619 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700620 }
621 return false;
622 }
623 }
624
625
626 public class InternalIntentListener implements IntentListener {
627 @Override
628 public void event(IntentEvent event) {
629 switch (event.type()) {
630 case INSTALLED:
631 log.info("Intent {} installed.", event.subject());
632 updateCrossConnectLink(event.subject());
633 break;
634 case WITHDRAWN:
635 log.info("Intent {} withdrawn.", event.subject());
636 removeCrossConnectLinks(event.subject());
637 break;
638 case FAILED:
639 log.info("Intent {} failed.", event.subject());
640 break;
641 default:
642 break;
643 }
644 }
645
646 private void updateCrossConnectLink(Intent intent) {
647 linkPathMap.entrySet().stream()
648 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
649 .forEach(e -> {
650 ConnectPoint packetSrc = e.getKey().src();
651 ConnectPoint packetDst = e.getKey().dst();
652 Bandwidth bw = e.getKey().bandwidth();
Naoki Shiota5a056062016-05-05 18:43:59 -0700653
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700654 // reflect modification only if packetSrc is local_
655 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
656 // Updates bandwidth of packet ports
657 updatePortBandwidth(packetSrc, bw);
658 updatePortBandwidth(packetDst, bw);
Naoki Shiota5a056062016-05-05 18:43:59 -0700659
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700660 // Updates link status in distributed map
661 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
662 e.getValue().value().setLinkEstablished(packetSrc, packetDst, true));
Naoki Shiota5a056062016-05-05 18:43:59 -0700663 }
664 });
665 }
666
667 private void removeCrossConnectLinks(Intent intent) {
668 ConnectPoint src, dst;
669
670 if (intent instanceof OpticalCircuitIntent) {
671 OpticalCircuitIntent circuit = (OpticalCircuitIntent) intent;
672 src = circuit.getSrc();
673 dst = circuit.getDst();
674 } else if (intent instanceof OpticalConnectivityIntent) {
675 OpticalConnectivityIntent conn = (OpticalConnectivityIntent) intent;
676 src = conn.getSrc();
677 dst = conn.getDst();
678 } else {
679 return;
680 }
681
682 removeXcLinkUsage(src);
683 removeXcLinkUsage(dst);
684
685 // Set bandwidth of 0 to cross connect ports
686 Bandwidth bw = Bandwidth.bps(0);
687 linkPathMap.entrySet().stream()
688 .filter(e -> e.getKey().realizingIntentKey().equals(intent.key()))
689 .forEach(e -> {
690 ConnectPoint packetSrc = e.getKey().src();
691 ConnectPoint packetDst = e.getKey().dst();
Naoki Shiota5a056062016-05-05 18:43:59 -0700692
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700693 // reflect modification only if packetSrc is local_
694 if (mastershipService.isLocalMaster(packetSrc.deviceId())) {
695 // Updates bandwidth of packet ports
696 updatePortBandwidth(packetSrc, bw);
697 updatePortBandwidth(packetDst, bw);
698
699 // Updates link status in distributed map
700 linkPathMap.computeIfPresent(e.getKey(), (link, connectivity) ->
701 e.getValue().value().setLinkEstablished(packetSrc, packetDst, false));
Naoki Shiota5a056062016-05-05 18:43:59 -0700702 }
703 });
704 }
705
706 private void removeXcLinkUsage(ConnectPoint cp) {
707 Optional<Link> link = linkService.getLinks(cp).stream()
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700708 .filter(usedCrossConnectLinkSet::contains)
Naoki Shiota5a056062016-05-05 18:43:59 -0700709 .findAny();
710
711 if (!link.isPresent()) {
712 log.warn("Cross connect point {} has no cross connect link.", cp);
713 return;
714 }
715
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700716 usedCrossConnectLinkSet.remove(link.get());
Naoki Shiota5a056062016-05-05 18:43:59 -0700717 }
718 }
719
720
721 private class InternalLinkListener implements LinkListener {
722
723 @Override
724 public void event(LinkEvent event) {
725 switch (event.type()) {
726 case LINK_REMOVED:
727 Link link = event.subject();
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700728 // updates linkPathMap only if src device of link is local
729 if (!mastershipService.isLocalMaster(link.src().deviceId())) {
730 return;
731 }
732
733 // find all packet links that correspond to removed link
Naoki Shiota5a056062016-05-05 18:43:59 -0700734 Set<PacketLinkRealizedByOptical> pLinks = linkPathMap.keySet().stream()
735 .filter(l -> l.isBetween(link.src(), link.dst()) || l.isBetween(link.dst(), link.src()))
736 .collect(Collectors.toSet());
737
738 pLinks.forEach(l -> {
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700739 // remove found packet links from distributed store
740 linkPathMap.computeIfPresent(l, (plink, conn) -> {
741 // Notifies listeners if all packet links are gone
742 if (conn.isAllRealizingLinkNotEstablished()) {
743 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, conn.id()));
744 }
745 return null;
746 });
Naoki Shiota5a056062016-05-05 18:43:59 -0700747 });
748 default:
749 break;
750 }
751 }
752 }
Naoki Shiota7c3111b2016-06-09 16:12:11 -0700753
754 private class InternalStoreListener
755 implements MapEventListener<PacketLinkRealizedByOptical, OpticalConnectivity> {
756
757 @Override
758 public void event(MapEvent<PacketLinkRealizedByOptical, OpticalConnectivity> event) {
759 switch (event.type()) {
760 case UPDATE:
761 OpticalConnectivity oldConnectivity = event.oldValue().value();
762 OpticalConnectivity newConnectivity = event.newValue().value();
763
764 if (!oldConnectivity.isAllRealizingLinkEstablished() &&
765 newConnectivity.isAllRealizingLinkEstablished()) {
766 // Notifies listeners if all links are established
767 updateBandwidthUsage(newConnectivity);
768 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_INSTALLED, newConnectivity.id()));
769 } else if (!oldConnectivity.isAllRealizingLinkNotEstablished() &&
770 newConnectivity.isAllRealizingLinkNotEstablished()) {
771 // Notifies listeners if all links are gone
772 releaseBandwidthUsage(newConnectivity);
773 post(new OpticalPathEvent(OpticalPathEvent.Type.PATH_REMOVED, newConnectivity.id()));
774 }
775
776 break;
777 default:
778 break;
779 }
780 }
781
782 }
Naoki Shiota5a056062016-05-05 18:43:59 -0700783}
784