blob: ecc1d72df60676fd839e48c93f8de29103cc9f4d [file] [log] [blame]
Avantika-Huawei73862d42016-05-12 18:58:06 +05301/*
2 * Copyright 2016-present 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.pce.pceservice;
17
18import static com.google.common.base.Preconditions.checkNotNull;
Avantika-Huawei73862d42016-05-12 18:58:06 +053019
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053020import java.util.Collection;
Priyanka Bb6963582016-05-20 20:21:20 +053021import java.util.Collections;
Avantika-Huawei73862d42016-05-12 18:58:06 +053022import java.util.Iterator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053023import java.util.LinkedList;
Avantika-Huawei73862d42016-05-12 18:58:06 +053024import java.util.List;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053025import java.util.Optional;
Priyanka Bb6963582016-05-20 20:21:20 +053026import java.util.Set;
Avantika-Huawei73862d42016-05-12 18:58:06 +053027import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
30import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
32import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053033import org.onlab.packet.IpAddress;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053034import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053038import org.onosproject.incubator.net.tunnel.DefaultTunnel;
39import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
Avantika-Huawei73862d42016-05-12 18:58:06 +053040import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053041import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
42import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053043import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053044import org.onosproject.incubator.net.tunnel.TunnelListener;
45import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053046import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053047import org.onosproject.mastership.MastershipService;
Avantika-Huawei032a9872016-05-27 22:57:38 +053048import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053049import org.onosproject.net.DefaultAnnotations;
50import org.onosproject.net.DefaultAnnotations.Builder;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053051import org.onosproject.net.DefaultPath;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053052import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053053import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053054import org.onosproject.net.Link;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053055import org.onosproject.net.NetworkResource;
Priyanka Bb6963582016-05-20 20:21:20 +053056import org.onosproject.net.Path;
Priyanka Bb6963582016-05-20 20:21:20 +053057import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053058import org.onosproject.net.intent.Constraint;
59import org.onosproject.net.intent.constraint.BandwidthConstraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +053060import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053061import org.onosproject.net.MastershipRole;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053062import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
63import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
64import org.onosproject.pce.pceservice.constraint.CostConstraint;
65import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
66import org.onosproject.net.resource.Resource;
67import org.onosproject.net.resource.ResourceAllocation;
68import org.onosproject.net.resource.ResourceConsumer;
69import org.onosproject.net.resource.ResourceQueryService;
Priyanka Bb6963582016-05-20 20:21:20 +053070import org.onosproject.net.resource.ResourceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053071import org.onosproject.net.resource.Resources;
Priyanka Bb6963582016-05-20 20:21:20 +053072import org.onosproject.net.topology.LinkWeight;
73import org.onosproject.net.topology.PathService;
74import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053075import org.onosproject.net.topology.TopologyEvent;
76import org.onosproject.net.topology.TopologyListener;
77import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053078import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053079import org.onosproject.pce.pcestore.PcePathInfo;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053080import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +053081import org.onosproject.pcep.api.DeviceCapability;
Avantika-Huawei73862d42016-05-12 18:58:06 +053082import org.onosproject.store.serializers.KryoNamespaces;
83import org.onosproject.store.service.DistributedSet;
84import org.onosproject.store.service.Serializer;
85import org.onosproject.store.service.StorageService;
86import org.slf4j.Logger;
87import org.slf4j.LoggerFactory;
88
Priyanka Bb6963582016-05-20 20:21:20 +053089import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053090import com.google.common.collect.ImmutableSet;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053091import com.google.common.collect.Sets;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053092
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053093import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053094import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
Priyanka B4c3b4512016-07-22 11:41:49 +053095import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053096import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053097import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
98import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
99import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
100import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
101import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
102import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
103import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
104import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
105
Avantika-Huawei73862d42016-05-12 18:58:06 +0530106/**
107 * Implementation of PCE service.
108 */
109@Component(immediate = true)
110@Service
111public class PceManager implements PceService {
112 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
113
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530114 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
115 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530116 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530117 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530118 public static final String DEVICE_TYPE = "type";
119 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530120
121 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
122 private IdGenerator tunnelConsumerIdGen;
123
124 private static final String LSRID = "lsrId";
125 private static final String TRUE = "true";
126 private static final String FALSE = "false";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530127 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530128
Avantika-Huawei73862d42016-05-12 18:58:06 +0530129 private IdGenerator localLspIdIdGen;
130 protected DistributedSet<Short> localLspIdFreeList;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected CoreService coreService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530136 protected ResourceService resourceService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected ResourceQueryService resourceQueryService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected PathService pathService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected PceStore pceStore;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530148 protected TunnelService tunnelService;
149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka Bb6963582016-05-20 20:21:20 +0530151 protected DeviceService deviceService;
152
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530154 protected StorageService storageService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530157 protected NetworkConfigService netCfgService;
158
159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka B3f92c5a2016-05-27 10:14:16 +0530160 protected MastershipService mastershipService;
161
162 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
163 protected TopologyService topologyService;
164
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530165 private TunnelListener listener = new InnerTunnelListener();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530166 private ApplicationId appId;
167
Priyanka B3f92c5a2016-05-27 10:14:16 +0530168 private final TopologyListener topologyListener = new InternalTopologyListener();
Priyanka B9fa4ed32016-05-27 11:59:24 +0530169
170 public static final int INITIAL_DELAY = 30;
171 public static final int PERIODIC_DELAY = 30;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530172
Avantika-Huawei73862d42016-05-12 18:58:06 +0530173 /**
174 * Creates new instance of PceManager.
175 */
176 public PceManager() {
177 }
178
179 @Activate
180 protected void activate() {
181 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530182
183 tunnelService.addListener(listener);
184
185 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530186 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530187 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530188 localLspIdFreeList = storageService.<Short>setBuilder()
189 .withName("pcepLocalLspIdDeletedList")
190 .withSerializer(Serializer.using(KryoNamespaces.API))
191 .build()
192 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530193
Priyanka B3f92c5a2016-05-27 10:14:16 +0530194 topologyService.addListener(topologyListener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530195
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530196 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530197 }
198
199 @Deactivate
200 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530201 tunnelService.removeListener(listener);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530202 topologyService.removeListener(topologyListener);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530203 log.info("Stopped");
204 }
205
Priyanka Bb6963582016-05-20 20:21:20 +0530206 /**
207 * Returns an edge-weight capable of evaluating links on the basis of the
208 * specified constraints.
209 *
210 * @param constraints path constraints
211 * @return edge-weight function
212 */
213 private LinkWeight weight(List<Constraint> constraints) {
214 return new TeConstraintBasedLinkWeight(constraints);
215 }
216
217 /**
218 * Computes a path between two devices.
219 *
220 * @param src ingress device
221 * @param dst egress device
222 * @param constraints path constraints
223 * @return computed path based on constraints
224 */
225 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
226 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530227 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530228 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530229
Priyanka Bb6963582016-05-20 20:21:20 +0530230 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530231 log.info("paths in computePath ::" + paths);
Priyanka Bb6963582016-05-20 20:21:20 +0530232 if (!paths.isEmpty()) {
233 return paths;
234 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530235 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530236 }
237
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530238 //Computes the partial path from partial computed path to specified dst.
239 private List<Path> computePartialPath(List<Path> computedPath, DeviceId src, DeviceId dst,
240 List<Constraint> constraints) {
241 int size = computedPath.size();
242 Path path = null;
243 DeviceId deviceId = size == 0 ? src :
244 computedPath.get(size - 1).dst().deviceId();
245
246 Set<Path> tempComputePath = computePath(deviceId, dst, constraints);
247
248 if (tempComputePath.isEmpty()) {
249 return null;
250 }
251
252 //if path validation fails return null
253 //Validate computed path to avoid loop in the path
254 for (Path p : tempComputePath) {
255 if (pathValidation(computedPath, p)) {
256 path = p;
257 break;
258 }
259 }
260 if (path == null) {
261 return null;
262 }
263
264 //Store the partial path result in a list
265 computedPath.add(path);
266 return computedPath;
267 }
268
269 private List<DeviceId> createListOfDeviceIds(List<? extends NetworkResource> list) {
270 List<Link> links = new LinkedList<>();
271 if (!list.isEmpty() && list.iterator().next() instanceof Path) {
272 for (Path path : (List<Path>) list) {
273 links.addAll(path.links());
274 }
275 } else if (!list.isEmpty() && list.iterator().next() instanceof Link) {
276 links.addAll((List<Link>) list);
277 }
278
279 //List of devices for new path computed
280 DeviceId source = null;
281 DeviceId destination = null;
282 List<DeviceId> devList = new LinkedList<>();
283
284 for (Link l : links) {
285 if (!devList.contains(l.src().deviceId())) {
286 devList.add(l.src().deviceId());
287 }
288 if (!devList.contains(l.dst().deviceId())) {
289 devList.add(l.dst().deviceId());
290 }
291 }
292
293 return devList;
294 }
295
296 //To dectect loops in the path i.e if the partial paths has intersection node avoid it.
297 private boolean pathValidation(List<Path> partialPath, Path path) {
298
299 //List of devices in new path computed
300 List<DeviceId> newPartialPathDevList;
301 newPartialPathDevList = createListOfDeviceIds(path.links());
302
303 //List of devices in partial computed path
304 List<DeviceId> partialComputedPathDevList;
305 partialComputedPathDevList = createListOfDeviceIds(partialPath);
306
307 for (DeviceId deviceId : newPartialPathDevList) {
308 for (DeviceId devId : partialComputedPathDevList) {
309 if (!newPartialPathDevList.get(0).equals(deviceId) &&
310 !partialComputedPathDevList.get(partialComputedPathDevList.size() - 1).equals(devId)
311 && deviceId.equals(devId)) {
312 return false;
313 }
314 }
315 }
316 return true;
317 }
318
319 //Returns final computed explicit path (list of partial computed paths).
320 private List<Path> computeExplicitPath(List<ExplicitPathInfo> explicitPathInfo, DeviceId src, DeviceId dst,
321 List<Constraint> constraints) {
322 List<Path> finalComputedPath = new LinkedList<>();
323 for (ExplicitPathInfo info : explicitPathInfo) {
324 /*
325 * If explicit path object is LOOSE,
326 * 1) If specified as DeviceId (node) :
327 * If it is source , compute from source to destination (partial computation not required),
328 * otherwise compute from specified source to specified device
329 * 2) If specified as Link :
330 * Compute partial path from source to link's source , if path exists compute from link's source to dst
331 */
332 if (info.type().equals(ExplicitPathInfo.Type.LOOSE)) {
333 if (info.value() instanceof DeviceId) {
334 // If deviceId is source no need to compute
335 if (!(info.value()).equals(src)) {
336 log.debug("computeExplicitPath :: Loose , device");
337 finalComputedPath = computePartialPath(finalComputedPath, src, (DeviceId) info.value(),
338 constraints);
339 log.debug("finalComputedPath in computeExplicitPath ::" + finalComputedPath);
340 }
341
342 } else if (info.value() instanceof Link) {
343 if ((((Link) info.value()).src().deviceId().equals(src))
344 || (!finalComputedPath.isEmpty()
345 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(
346 ((Link) info.value()).src().deviceId()))) {
347
348 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).dst()
349 .deviceId(), constraints);
350 } else {
351
352 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).src()
353 .deviceId(), constraints) != null ? computePartialPath(finalComputedPath, src,
354 ((Link) info.value()).dst().deviceId(), constraints) : null;
355 }
356 }
357 /*
358 * If explicit path object is STRICT,
359 * 1) If specified as DeviceId (node) :
360 * Check whether partial computed path has reachable to strict specified node orde
361 * strict node is the source, if no set path as null else do nothing
362 * 2) If specified as Link :
363 * Check whether partial computed path has reachable to strict link's src, if yes compute
364 * path from strict link's src to link's dst (to include specified link)
365 */
366 } else if (info.type().equals(ExplicitPathInfo.Type.STRICT)) {
367 if (info.value() instanceof DeviceId) {
368 log.debug("computeExplicitPath :: Strict , device");
369 if (!(!finalComputedPath.isEmpty() && finalComputedPath.get(finalComputedPath.size() - 1).dst()
370 .deviceId().equals(info.value()))
371 && !info.value().equals(src)) {
372 finalComputedPath = null;
373 }
374
375 } else if (info.value() instanceof Link) {
376 log.info("computeExplicitPath :: Strict");
377 finalComputedPath = ((Link) info.value()).src().deviceId().equals(src)
378 || !finalComputedPath.isEmpty()
379 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId()
380 .equals(((Link) info.value()).src().deviceId()) ? computePartialPath(
381 finalComputedPath, src, ((Link) info.value()).dst().deviceId(), constraints) : null;
382
383 //Log.info("computeExplicitPath :: (Link) info.value() " + (Link) info.value());
384 //Log.info("computeExplicitPath :: finalComputedPath " + finalComputedPath);
385
386 if (finalComputedPath != null && !finalComputedPath.get(finalComputedPath.size() - 1).links()
387 .contains((Link) info.value())) {
388 finalComputedPath = null;
389 }
390 }
391 }
392 if (finalComputedPath == null) {
393 return null;
394 }
395 }
396 // Destination is not reached in Partial computed path then compute till destination
397 if (finalComputedPath.isEmpty() || !finalComputedPath.isEmpty()
398 && !finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(dst)) {
399
400 finalComputedPath = computePartialPath(finalComputedPath, src, dst, constraints);
401 if (finalComputedPath == null) {
402 return null;
403 }
404 }
405
406 return finalComputedPath;
407 }
408
Priyanka Ba32f6da2016-09-02 16:10:21 +0530409 @Override
410 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
Priyankab-Huawei3946d732016-10-11 06:24:38 +0000411 LspType lspType) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530412 return setupPath(src, dst, tunnelName, constraints, lspType, null);
413 }
414
415 //[TODO:] handle requests in queue
416 @Override
417 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
418 LspType lspType, List<ExplicitPathInfo> explicitPathInfo) {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530419 checkNotNull(src);
420 checkNotNull(dst);
421 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530422 checkNotNull(lspType);
423
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530424 // Convert from DeviceId to TunnelEndPoint
425 Device srcDevice = deviceService.getDevice(src);
426 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530427
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530428 if (srcDevice == null || dstDevice == null) {
429 // Device is not known.
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530430 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530431 return false;
432 }
433
434 // In future projections instead of annotations will be used to fetch LSR ID.
435 String srcLsrId = srcDevice.annotations().value(LSRID);
436 String dstLsrId = dstDevice.annotations().value(LSRID);
437
438 if (srcLsrId == null || dstLsrId == null) {
439 // LSR id is not known.
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530440 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530441 return false;
442 }
443
Avantika-Huawei032a9872016-05-27 22:57:38 +0530444 // Get device config from netconfig, to ascertain that session with ingress is present.
445 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
446 if (cfg == null) {
447 log.debug("No session to ingress.");
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530448 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huawei032a9872016-05-27 22:57:38 +0530449 return false;
450 }
451
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530452 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
453 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
454
455 double bwConstraintValue = 0;
456 CostConstraint costConstraint = null;
457 if (constraints != null) {
458 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
459 Iterator<Constraint> iterator = constraints.iterator();
460
461 while (iterator.hasNext()) {
462 Constraint constraint = iterator.next();
463 if (constraint instanceof BandwidthConstraint) {
464 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
465 } else if (constraint instanceof CostConstraint) {
466 costConstraint = (CostConstraint) constraint;
467 }
468 }
469
470 /*
471 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
472 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
473 * function can either return the result of limiting/capability constraint validation or the value of link
474 * cost, depending upon what is the last constraint in the loop.
475 */
476 if (costConstraint != null) {
477 constraints.remove(costConstraint);
478 constraints.add(costConstraint);
479 }
480 } else {
481 constraints = new LinkedList<>();
482 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
483 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530484 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530485
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530486 if (explicitPathInfo != null && !explicitPathInfo.isEmpty()) {
487 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo, src, dst, constraints);
488 if (finalComputedPath == null) {
489 return false;
490 }
491
492 pceStore.tunnelNameExplicitPathInfoMap(tunnelName, explicitPathInfo);
493 List<Link> links = new LinkedList<>();
494 double totalCost = 0;
495 // Add all partial computed paths
496 for (Path path : finalComputedPath) {
497 links.addAll(path.links());
498 totalCost = totalCost + path.cost();
499 }
500 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(), links, totalCost));
501 } else {
502 computedPathSet = computePath(src, dst, constraints);
503 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530504
505 // NO-PATH
506 if (computedPathSet.isEmpty()) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530507 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530508 return false;
509 }
510
511 Builder annotationBuilder = DefaultAnnotations.builder();
512 if (bwConstraintValue != 0) {
513 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
514 }
515 if (costConstraint != null) {
516 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
517 }
518 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
519 annotationBuilder.set(PCE_INIT, TRUE);
520 annotationBuilder.set(DELEGATE, TRUE);
521
522 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530523
524 if (lspType != WITH_SIGNALLING) {
525 /*
526 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
527 * PCE for non-RSVP signalled LSPs.
528 */
529 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
530 }
531
532 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
533 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
534 TunnelName.tunnelName(tunnelName), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530535 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530536
537 // Allocate bandwidth.
538 TunnelConsumerId consumerId = null;
539 if (bwConstraintValue != 0) {
540 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
541 if (consumerId == null) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530542 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints,
543 lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530544 return false;
545 }
546 }
547
548 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
549 if (tunnelId == null) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530550 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530551 if (consumerId != null) {
552 resourceService.release(consumerId);
553 }
554 return false;
555 }
556
557 if (consumerId != null) {
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530558 // Store tunnel consumer id in LSP store.
559 pceStore.addTunnelInfo(tunnelId, consumerId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530560 }
561 return true;
562 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530563
564 @Override
565 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
566 checkNotNull(tunnelId);
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530567 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530568 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530569
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530570 if (tunnel == null) {
571 return false;
572 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530573
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530574 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
575 // Only delegated LSPs can be updated.
576 return false;
577 }
578
579 List<Link> links = tunnel.path().links();
580 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
581 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530582 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530583 SharedBandwidthConstraint shBwConstraint = null;
584 BandwidthConstraint bwConstraint = null;
585 CostConstraint costConstraint = null;
586
587 if (constraints != null) {
588 // Call path computation in shared bandwidth mode.
589 Iterator<Constraint> iterator = constraints.iterator();
590 while (iterator.hasNext()) {
591 Constraint constraint = iterator.next();
592 if (constraint instanceof BandwidthConstraint) {
593 bwConstraint = (BandwidthConstraint) constraint;
594 bwConstraintValue = bwConstraint.bandwidth().bps();
595 } else if (constraint instanceof CostConstraint) {
596 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530597 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530598 }
599 }
600
601 // Remove and keep the cost constraint at the end of the list of constraints.
602 if (costConstraint != null) {
603 constraints.remove(costConstraint);
604 }
605
606 Bandwidth existingBwValue = null;
607 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
608 if (existingBwAnnotation != null) {
609 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
610
611 /*
612 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
613 * has been utilized to create shared bandwidth constraint.
614 */
615 if (bwConstraint != null) {
616 constraints.remove(bwConstraint);
617 }
618 }
619
620 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530621 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530622 bwConstraintValue = existingBwValue.bps();
623 }
624 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
625 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
626 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
627 existingBwValue, existingBwValue);
628
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530629 constraints.add(shBwConstraint);
630 }
631 } else {
632 constraints = new LinkedList<>();
633 }
634
635 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
636 if (costConstraint != null) {
637 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530638 } else {
639 //Take cost constraint from old tunnel if it is not specified in update flow
640 costType = tunnel.annotations().value(COST_TYPE);
641 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
642 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530643 }
644
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530645 List<ExplicitPathInfo> explicitPathInfo = pceStore
646 .getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value());
647 if (explicitPathInfo != null) {
648 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo,
649 tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
650 constraints);
651
652 if (finalComputedPath == null) {
653 return false;
654 }
655
656 List<Link> totalLinks = new LinkedList<>();
657 double totalCost = 0;
658 //Add all partial computed paths
659 for (Path path : finalComputedPath) {
660 totalLinks.addAll(path.links());
661 totalCost = totalCost + path.cost();
662 }
663 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(),
664 totalLinks, totalCost));
665 } else {
666 computedPathSet = computePath(tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
667 constraints);
668 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530669
670 // NO-PATH
671 if (computedPathSet.isEmpty()) {
672 return false;
673 }
674
675 Builder annotationBuilder = DefaultAnnotations.builder();
676 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530677 if (costType != null) {
678 annotationBuilder.set(COST_TYPE, costType);
679 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530680 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
681 annotationBuilder.set(PCE_INIT, TRUE);
682 annotationBuilder.set(DELEGATE, TRUE);
683 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
684 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
685
686 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530687 TunnelConsumerId consumerId = null;
688 LspType lspType = LspType.valueOf(lspSigType);
689 long localLspId = 0;
690 if (lspType != WITH_SIGNALLING) {
691 /*
692 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
693 * PCE for non-RSVP signalled LSPs.
694 */
695 localLspId = getNextLocalLspId();
696 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530697 }
698
699 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
700 tunnel.tunnelName(), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530701 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530702
703 // Allocate shared bandwidth.
704 if (bwConstraintValue != 0) {
705 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
706 if (consumerId == null) {
707 return false;
708 }
709 }
710
711 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
712 computedPath);
713
714 if (updatedTunnelId == null) {
715 if (consumerId != null) {
716 resourceService.release(consumerId);
717 }
718 return false;
719 }
720
721 if (consumerId != null) {
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530722 // Store tunnel consumer id in LSP store.
723 pceStore.addTunnelInfo(updatedTunnelId, consumerId);
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530724 }
725
Avantika-Huawei73862d42016-05-12 18:58:06 +0530726 return true;
727 }
728
729 @Override
730 public boolean releasePath(TunnelId tunnelId) {
731 checkNotNull(tunnelId);
732 // 1. Query Tunnel from Tunnel manager.
733 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
734
735 if (tunnel == null) {
736 return false;
737 }
738
739 // 2. Call tunnel service.
740 return tunnelService.downTunnel(appId, tunnel.tunnelId());
741 }
742
743 @Override
744 public Iterable<Tunnel> queryAllPath() {
745 return tunnelService.queryTunnel(MPLS);
746 }
747
748 @Override
749 public Tunnel queryPath(TunnelId tunnelId) {
750 return tunnelService.queryTunnel(tunnelId);
751 }
752
753 /**
754 * Returns the next local LSP identifier to be used either by getting from
755 * freed list if available otherwise generating a new one.
756 *
757 * @return value of local LSP identifier
758 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530759 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530760 // If there is any free id use it. Otherwise generate new id.
761 if (localLspIdFreeList.isEmpty()) {
762 return (short) localLspIdIdGen.getNewId();
763 }
764 Iterator<Short> it = localLspIdFreeList.iterator();
765 Short value = it.next();
766 localLspIdFreeList.remove(value);
767 return value;
768 }
769
Priyanka Bb6963582016-05-20 20:21:20 +0530770 protected class TeConstraintBasedLinkWeight implements LinkWeight {
771
772 private final List<Constraint> constraints;
773
774 /**
775 * Creates a new edge-weight function capable of evaluating links
776 * on the basis of the specified constraints.
777 *
778 * @param constraints path constraints
779 */
780 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
781 if (constraints == null) {
782 this.constraints = Collections.emptyList();
783 } else {
784 this.constraints = ImmutableList.copyOf(constraints);
785 }
786 }
787
788 @Override
789 public double weight(TopologyEdge edge) {
790 if (!constraints.iterator().hasNext()) {
791 //Takes default cost/hopcount as 1 if no constraints specified
792 return 1.0;
793 }
794
795 Iterator<Constraint> it = constraints.iterator();
796 double cost = 1;
797
798 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
799 while (it.hasNext() && cost > 0) {
800 Constraint constraint = it.next();
801 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530802 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
803 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530804 } else {
805 cost = constraint.cost(edge.link(), resourceService::isAvailable);
806 }
807 }
808 return cost;
809 }
810 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530811
Priyanka B3f92c5a2016-05-27 10:14:16 +0530812 //TODO: annotations used for temporarily later projection/network config will be used
813 private class InternalTopologyListener implements TopologyListener {
814 @Override
815 public void event(TopologyEvent event) {
816 event.reasons().forEach(e -> {
817 //If event type is link removed, get the impacted tunnel
818 if (e instanceof LinkEvent) {
819 LinkEvent linkEvent = (LinkEvent) e;
820 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
821 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530822 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530823 // Check whether this ONOS instance is master for ingress device if yes,
824 // recompute and send update
825 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
826 }
827 });
828 }
829 }
830 });
831 }
832 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530833
Priyanka B3f92c5a2016-05-27 10:14:16 +0530834 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
835 /**
836 * Master of ingress node will recompute and also delegation flag must be set.
837 */
838 if (mastershipService.isLocalMaster(src)
839 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
840 LinkedList<Constraint> constraintList = new LinkedList<>();
841
842 if (tunnel.annotations().value(BANDWIDTH) != null) {
843 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
844 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
845 .annotations().value(BANDWIDTH))));
846 constraintList.add(localConst);
847 }
848 if (tunnel.annotations().value(COST_TYPE) != null) {
849 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
850 COST_TYPE))));
851 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530852
853 /*
854 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
855 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
856 */
857 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530858 // If updation fails store in PCE store as failed path
859 // then PCInitiate (Remove)
860 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
861 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530862 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE)),
863 pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value())));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530864 //Release that tunnel calling PCInitiate
865 releasePath(tunnel.tunnelId());
866 }
867 }
868
869 return false;
870 }
871
872 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530873 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
874 SharedBandwidthConstraint shBwConstraint) {
875 checkNotNull(computedPath);
876 checkNotNull(bandwidthConstraint);
877 Resource resource = null;
878 double bwToAllocate = 0;
879
880 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
881
882 /**
883 * Shared bandwidth sub-case : Lesser bandwidth required than original -
884 * No reservation required.
885 */
886 Double additionalBwValue = null;
887 if (shBwConstraint != null) {
888 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
889 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
890 }
891
892 Optional<ResourceAllocation> resAlloc = null;
893 for (Link link : computedPath.links()) {
894 bwToAllocate = 0;
895 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
896 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530897 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530898 }
899 } else {
900 bwToAllocate = bandwidthConstraint;
901 }
902
903 /**
904 * In shared bandwidth cases, where new BW is lesser than old BW, it
905 * is not required to allocate anything.
906 */
907 if (bwToAllocate != 0) {
908 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
909 .resource(bwToAllocate);
910 resAlloc = resourceService.allocate(consumer, resource);
911
912 // If allocation for any link fails, then release the partially allocated bandwidth.
913 if (!resAlloc.isPresent()) {
914 resourceService.release(consumer);
915 return null;
916 }
917 }
918 }
919
920 /*
921 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
922 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
923 * to who is supposed to store/delete.
924 */
925 return consumer;
926 }
927
928 /*
929 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
930 */
931 private void releaseBandwidth(Tunnel tunnel) {
932 // Between same source and destination, search the tunnel with same symbolic path name.
933 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
934 Tunnel newTunnel = null;
935 for (Tunnel tunnelObj : tunnelQueryResult) {
936 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
937 newTunnel = tunnelObj;
938 break;
939 }
940 }
941
942 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
943 boolean isLinkShared = false;
944 if (newTunnel != null) {
945 for (Link link : tunnel.path().links()) {
946 if (newTunnel.path().links().contains(link)) {
947 isLinkShared = true;
948 break;
949 }
950 }
951 }
952
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530953 ResourceConsumer tunnelConsumerId = pceStore.getTunnelInfo(tunnel.tunnelId());
954 if (tunnelConsumerId == null) {
955 //If bandwidth for old tunnel is not allocated i,e 0 then no need to release
956 log.debug("Bandwidth not allocated (0 bandwidth) for old LSP.");
957 return;
958 }
959
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530960 if (isLinkShared) {
961 releaseSharedBandwidth(newTunnel, tunnel);
962 return;
963 }
964
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530965 resourceService.release(tunnelConsumerId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530966 /*
967 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
968 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
969 * to who is supposed to store/delete.
970 */
971 }
972
973 /**
974 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
975 * allocated in shared mode initially.
976 */
977 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
978 // 1. Release old tunnel's bandwidth.
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530979 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530980
Priyanka B4c3b4512016-07-22 11:41:49 +0530981 // 2. Release new tunnel's bandwidth, if new tunnel bandwidth is allocated
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530982 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId());
983 if (consumer == null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530984 //If bandwidth for new tunnel is not allocated i,e 0 then no need to allocate
985 return;
986 }
987
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530988 resourceService.release(consumer);
989
990 // 3. Allocate new tunnel's complete bandwidth.
991 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
992 Resource resource;
993
994 for (Link link : newTunnel.path().links()) {
995 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
996 .resource(bandwidth);
997 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530998
999 }
1000 }
1001
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301002 // Listens on tunnel events.
1003 private class InnerTunnelListener implements TunnelListener {
1004 @Override
1005 public void event(TunnelEvent event) {
1006 // Event gets generated with old tunnel object.
1007 Tunnel tunnel = event.subject();
1008 if (tunnel.type() != MPLS) {
1009 return;
1010 }
1011
1012 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1013 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1014 double bwConstraintValue = 0;
1015 if (tunnelBandwidth != null) {
1016 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1017 }
1018
1019 switch (event.type()) {
1020 case TUNNEL_ADDED:
1021 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1022 String pceInit = tunnel.annotations().value(PCE_INIT);
Avantika-Huawei9e848e82016-09-01 12:12:42 +05301023 if (FALSE.equalsIgnoreCase(pceInit) && bwConstraintValue != 0) {
1024 TunnelConsumerId consumerId = reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1025 if (consumerId != null) {
1026 // Store tunnel consumer id in LSP store.
1027 pceStore.addTunnelInfo(tunnel.tunnelId(), consumerId);
1028 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301029 }
1030 break;
1031
1032 case TUNNEL_UPDATED:
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301033 if (tunnel.state() == UNSTABLE) {
1034 /*
1035 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1036 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1037 * and setup while global reoptimization.
1038 */
1039
1040 List<Constraint> constraints = new LinkedList<>();
1041 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1042 if (bandwidth != null) {
1043 constraints.add(new BandwidthConstraint(Bandwidth
1044 .bps(Double.parseDouble(bandwidth))));
1045 }
1046
1047 String costType = tunnel.annotations().value(COST_TYPE);
1048 if (costType != null) {
1049 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1050 constraints.add(costConstraint);
1051 }
1052
1053 constraints.add(CapabilityConstraint
1054 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1055
1056 List<Link> links = tunnel.path().links();
1057 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1058 links.get(links.size() - 1).dst().deviceId(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301059 tunnel.tunnelName().value(), constraints, lspType,
1060 pceStore.getTunnelNameExplicitPathInfoMap(tunnel
1061 .tunnelName().value())));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301062 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301063
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301064 break;
1065
1066 case TUNNEL_REMOVED:
1067 if (lspType != WITH_SIGNALLING) {
1068 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1069 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301070 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Priyanka B3fdb9dd2016-08-08 10:47:24 +05301071 if (bwConstraintValue != 0
Priyanka B4c3b4512016-07-22 11:41:49 +05301072 && mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1073 releaseBandwidth(tunnel);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301074 }
Priyanka B4c3b4512016-07-22 11:41:49 +05301075
1076 if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
1077 pceStore.removeTunnelInfo(tunnel.tunnelId());
1078 }
1079
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301080 break;
1081
1082 default:
1083 break;
1084
1085 }
1086 return;
1087 }
1088 }
1089
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301090 @Override
1091 public List<ExplicitPathInfo> explicitPathInfoList(String tunnelName) {
1092 return pceStore.getTunnelNameExplicitPathInfoMap(tunnelName);
1093 }
1094
Priyanka B9fa4ed32016-05-27 11:59:24 +05301095 //Computes path from tunnel store and also path failed to setup.
1096 private void callForOptimization() {
1097 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1098 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1099 checkForMasterAndSetupPath(failedPathInfo);
1100 }
1101
1102 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1103 tunnelService.queryTunnel(MPLS).forEach(t -> {
1104 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1105 });
1106 }
1107
1108 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1109 /**
1110 * Master of ingress node will setup the path failed stored in PCE store.
1111 */
1112 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1113 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301114 failedPathInfo.constraints(), failedPathInfo.lspType(), failedPathInfo.explicitPathInfo())) {
Priyanka B9fa4ed32016-05-27 11:59:24 +05301115 // If computation is success remove that path
1116 pceStore.removeFailedPathInfo(failedPathInfo);
1117 return true;
1118 }
1119 }
1120
1121 return false;
1122 }
1123
1124 //Timer to call global optimization
1125 private class GlobalOptimizationTimer implements Runnable {
1126
1127 public GlobalOptimizationTimer() {
1128 }
1129
1130 @Override
1131 public void run() {
1132 callForOptimization();
1133 }
1134 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301135}