blob: 9267dc2bb0976c55df8aab8c03cb6c222d83f7fb [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;
Priyanka Ba32f6da2016-09-02 16:10:21 +053027
Avantika-Huawei73862d42016-05-12 18:58:06 +053028import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
31import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
33import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053034import org.onlab.packet.IpAddress;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053035import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053036import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
38import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053039import org.onosproject.incubator.net.tunnel.DefaultTunnel;
40import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
Avantika-Huawei73862d42016-05-12 18:58:06 +053041import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053042import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
43import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053044import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053045import org.onosproject.incubator.net.tunnel.TunnelListener;
46import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053047import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053048import org.onosproject.mastership.MastershipService;
Avantika-Huawei032a9872016-05-27 22:57:38 +053049import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053050import org.onosproject.net.DefaultAnnotations;
51import org.onosproject.net.DefaultAnnotations.Builder;
Priyanka Ba32f6da2016-09-02 16:10:21 +053052import org.onosproject.net.DefaultPath;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053053import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053054import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053055import org.onosproject.net.Link;
Priyanka Ba32f6da2016-09-02 16:10:21 +053056import org.onosproject.net.NetworkResource;
Priyanka Bb6963582016-05-20 20:21:20 +053057import org.onosproject.net.Path;
Priyanka Bb6963582016-05-20 20:21:20 +053058import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053059import org.onosproject.net.intent.Constraint;
60import org.onosproject.net.intent.constraint.BandwidthConstraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +053061import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053062import org.onosproject.net.MastershipRole;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053063import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
64import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
65import org.onosproject.pce.pceservice.constraint.CostConstraint;
66import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
67import org.onosproject.net.resource.Resource;
68import org.onosproject.net.resource.ResourceAllocation;
69import org.onosproject.net.resource.ResourceConsumer;
70import org.onosproject.net.resource.ResourceQueryService;
Priyanka Bb6963582016-05-20 20:21:20 +053071import org.onosproject.net.resource.ResourceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053072import org.onosproject.net.resource.Resources;
Priyanka Bb6963582016-05-20 20:21:20 +053073import org.onosproject.net.topology.LinkWeight;
74import org.onosproject.net.topology.PathService;
75import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053076import org.onosproject.net.topology.TopologyEvent;
77import org.onosproject.net.topology.TopologyListener;
78import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053079import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053080import org.onosproject.pce.pcestore.PcePathInfo;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053081import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +053082import org.onosproject.pcep.api.DeviceCapability;
Avantika-Huawei73862d42016-05-12 18:58:06 +053083import org.onosproject.store.serializers.KryoNamespaces;
84import org.onosproject.store.service.DistributedSet;
85import org.onosproject.store.service.Serializer;
86import org.onosproject.store.service.StorageService;
87import org.slf4j.Logger;
88import org.slf4j.LoggerFactory;
89
Priyanka Bb6963582016-05-20 20:21:20 +053090import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053091import com.google.common.collect.ImmutableSet;
Priyanka Ba32f6da2016-09-02 16:10:21 +053092import com.google.common.collect.Sets;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053093
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053094import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053095import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
Priyanka B4c3b4512016-07-22 11:41:49 +053096import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053097import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053098import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
99import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
100import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
101import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
102import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
103import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
104import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
105import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
106
Avantika-Huawei73862d42016-05-12 18:58:06 +0530107/**
108 * Implementation of PCE service.
109 */
110@Component(immediate = true)
111@Service
112public class PceManager implements PceService {
113 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
114
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530115 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
116 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530117 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530118 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530119 public static final String DEVICE_TYPE = "type";
120 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530121
122 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
123 private IdGenerator tunnelConsumerIdGen;
124
125 private static final String LSRID = "lsrId";
126 private static final String TRUE = "true";
127 private static final String FALSE = "false";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530128 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530129
Avantika-Huawei73862d42016-05-12 18:58:06 +0530130 private IdGenerator localLspIdIdGen;
131 protected DistributedSet<Short> localLspIdFreeList;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected CoreService coreService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530137 protected ResourceService resourceService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 protected ResourceQueryService resourceQueryService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 protected PathService pathService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
146 protected PceStore pceStore;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530149 protected TunnelService tunnelService;
150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka Bb6963582016-05-20 20:21:20 +0530152 protected DeviceService deviceService;
153
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530155 protected StorageService storageService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530156
157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530158 protected NetworkConfigService netCfgService;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka B3f92c5a2016-05-27 10:14:16 +0530161 protected MastershipService mastershipService;
162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
164 protected TopologyService topologyService;
165
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530166 private TunnelListener listener = new InnerTunnelListener();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530167 private ApplicationId appId;
168
Priyanka B3f92c5a2016-05-27 10:14:16 +0530169 private final TopologyListener topologyListener = new InternalTopologyListener();
Priyanka B9fa4ed32016-05-27 11:59:24 +0530170
171 public static final int INITIAL_DELAY = 30;
172 public static final int PERIODIC_DELAY = 30;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530173
Avantika-Huawei73862d42016-05-12 18:58:06 +0530174 /**
175 * Creates new instance of PceManager.
176 */
177 public PceManager() {
178 }
179
180 @Activate
181 protected void activate() {
182 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530183
184 tunnelService.addListener(listener);
185
186 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530187 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530188 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530189 localLspIdFreeList = storageService.<Short>setBuilder()
190 .withName("pcepLocalLspIdDeletedList")
191 .withSerializer(Serializer.using(KryoNamespaces.API))
192 .build()
193 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530194
Priyanka B3f92c5a2016-05-27 10:14:16 +0530195 topologyService.addListener(topologyListener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530196
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530197 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530198 }
199
200 @Deactivate
201 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530202 tunnelService.removeListener(listener);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530203 topologyService.removeListener(topologyListener);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530204 log.info("Stopped");
205 }
206
Priyanka Bb6963582016-05-20 20:21:20 +0530207 /**
208 * Returns an edge-weight capable of evaluating links on the basis of the
209 * specified constraints.
210 *
211 * @param constraints path constraints
212 * @return edge-weight function
213 */
214 private LinkWeight weight(List<Constraint> constraints) {
215 return new TeConstraintBasedLinkWeight(constraints);
216 }
217
218 /**
219 * Computes a path between two devices.
220 *
221 * @param src ingress device
222 * @param dst egress device
223 * @param constraints path constraints
224 * @return computed path based on constraints
225 */
226 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
227 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530228 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530229 }
230 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
231 if (!paths.isEmpty()) {
232 return paths;
233 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530234 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530235 }
236
Priyanka Ba32f6da2016-09-02 16:10:21 +0530237 //Computes the partial path from partial computed path to specified dst.
238 private List<Path> computePartialPath(List<Path> computedPath, DeviceId src, DeviceId dst,
239 List<Constraint> constraints) {
240 int size = computedPath.size();
241 Path path = null;
242 DeviceId deviceId = size == 0 ? src :
243 computedPath.get(size - 1).dst().deviceId();
244
245 Set<Path> tempComputePath = computePath(deviceId, dst, constraints);
246 if (tempComputePath.isEmpty()) {
247 return null;
248 }
249
250 //if path validation fails return null
251 //Validate computed path to avoid loop in the path
252 for (Path p : tempComputePath) {
253 if (pathValidation(computedPath, p)) {
254 path = p;
255 break;
256 }
257 }
258 if (path == null) {
259 return null;
260 }
261
262 //Store the partial path result in a list
263 computedPath.add(path);
264 return computedPath;
265 }
266
267 private List<DeviceId> createListOfDeviceIds(List<? extends NetworkResource> list) {
268 List<Link> links = new LinkedList<>();
269 if (!list.isEmpty() && list.iterator().next() instanceof Path) {
270 for (Path path : (List<Path>) list) {
271 links.addAll(path.links());
272 }
273 } else if (!list.isEmpty() && list.iterator().next() instanceof Link) {
274 links.addAll((List<Link>) list);
275 }
276
277 //List of devices for new path computed
278 DeviceId source = null;
279 DeviceId destination = null;
280 List<DeviceId> devList = new LinkedList<>();
281
282 for (Link l : links) {
283 if (!devList.contains(l.src().deviceId())) {
284 devList.add(l.src().deviceId());
285 }
286 if (!devList.contains(l.dst().deviceId())) {
287 devList.add(l.dst().deviceId());
288 }
289 }
290
291 return devList;
292 }
293
294 //To dectect loops in the path i.e if the partial paths has intersection node avoid it.
295 private boolean pathValidation(List<Path> partialPath, Path path) {
296
297 //List of devices in new path computed
298 List<DeviceId> newPartialPathDevList;
299 newPartialPathDevList = createListOfDeviceIds(path.links());
300
301 //List of devices in partial computed path
302 List<DeviceId> partialComputedPathDevList;
303 partialComputedPathDevList = createListOfDeviceIds(partialPath);
304
305 for (DeviceId deviceId : newPartialPathDevList) {
306 for (DeviceId devId : partialComputedPathDevList) {
307 if (!newPartialPathDevList.get(0).equals(deviceId) &&
308 !partialComputedPathDevList.get(partialComputedPathDevList.size() - 1).equals(devId)
309 && deviceId.equals(devId)) {
310 return false;
311 }
312 }
313 }
314
315 return true;
316 }
317
318 //Returns final computed explicit path (list of partial computed paths).
319 private List<Path> computeExplicitPath(List<ExplicitPathInfo> explicitPathInfo, DeviceId src, DeviceId dst,
320 List<Constraint> constraints) {
321 List<Path> finalComputedPath = new LinkedList<>();
322 for (ExplicitPathInfo info : explicitPathInfo) {
323 /*
324 * If explicit path object is LOOSE,
325 * 1) If specified as DeviceId (node) :
326 * If it is source , compute from source to destination (partial computation not required),
327 * otherwise compute from specified source to specified device
328 * 2) If specified as Link :
329 * Compute partial path from source to link's source , if path exists compute from link's source to dst
330 */
331 if (info.type().equals(ExplicitPathInfo.Type.LOOSE)) {
332 if (info.value() instanceof DeviceId) {
333 // If deviceId is source no need to compute
334 if (!(info.value()).equals(src)) {
335 finalComputedPath = computePartialPath(finalComputedPath, src, (DeviceId) info.value(),
336 constraints);
337 }
338
339 } else if (info.value() instanceof Link) {
340 if ((((Link) info.value()).src().deviceId().equals(src))
341 || (!finalComputedPath.isEmpty()
342 && finalComputedPath.get(finalComputedPath.size() - 1).dst().equals(
343 ((Link) info.value()).src().deviceId()))) {
344
345 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).dst()
346 .deviceId(), constraints);
347 } else {
348
349 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).src()
350 .deviceId(), constraints) != null ? computePartialPath(finalComputedPath, src,
351 ((Link) info.value()).dst().deviceId(), constraints) : null;
352 }
353 }
354 /*
355 * If explicit path object is STRICT,
356 * 1) If specified as DeviceId (node) :
357 * Check whether partial computed path has reachable to strict specified node or
358 * strict node is the source, if no set path as null else do nothing
359 * 2) If specified as Link :
360 * Check whether partial computed path has reachable to strict link's src, if yes compute
361 * path from strict link's src to link's dst (to include specified link)
362 */
363 } else if (info.type().equals(ExplicitPathInfo.Type.STRICT)) {
364 if (info.value() instanceof DeviceId) {
365 if (!(!finalComputedPath.isEmpty() && finalComputedPath.get(finalComputedPath.size() - 1).dst()
366 .deviceId().equals(info.value()))
367 && !info.value().equals(src)) {
368 finalComputedPath = null;
369 }
370
371 } else if (info.value() instanceof Link) {
372
373 finalComputedPath = ((Link) info.value()).src().deviceId().equals(src)
374 || !finalComputedPath.isEmpty()
375 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId()
376 .equals(((Link) info.value()).src().deviceId()) ? computePartialPath(
377 finalComputedPath, src, ((Link) info.value()).dst().deviceId(), constraints) : null;
378
379 }
380 }
381 if (finalComputedPath == null) {
382 return null;
383 }
384 }
385 // Destination is not reached in Partial computed path then compute till destination
386 if (finalComputedPath.isEmpty() || !finalComputedPath.isEmpty()
387 && !finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(dst)) {
388
389 finalComputedPath = computePartialPath(finalComputedPath, src, dst, constraints);
390 if (finalComputedPath == null) {
391 return null;
392 }
393 }
394
395 return finalComputedPath;
396 }
397
Avantika-Huawei73862d42016-05-12 18:58:06 +0530398 @Override
399 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
400 LspType lspType) {
Priyanka Ba32f6da2016-09-02 16:10:21 +0530401 return setupPath(src, dst, tunnelName, constraints, lspType, null);
402 }
403
404 //[TODO:] handle requests in queue
405 @Override
406 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
407 LspType lspType, List<ExplicitPathInfo> explicitPathInfo) {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530408 checkNotNull(src);
409 checkNotNull(dst);
410 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530411 checkNotNull(lspType);
412
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530413 // Convert from DeviceId to TunnelEndPoint
414 Device srcDevice = deviceService.getDevice(src);
415 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530416
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530417 if (srcDevice == null || dstDevice == null) {
418 // Device is not known.
Priyanka Ba32f6da2016-09-02 16:10:21 +0530419 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530420 return false;
421 }
422
423 // In future projections instead of annotations will be used to fetch LSR ID.
424 String srcLsrId = srcDevice.annotations().value(LSRID);
425 String dstLsrId = dstDevice.annotations().value(LSRID);
426
427 if (srcLsrId == null || dstLsrId == null) {
428 // LSR id is not known.
Priyanka Ba32f6da2016-09-02 16:10:21 +0530429 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530430 return false;
431 }
432
Avantika-Huawei032a9872016-05-27 22:57:38 +0530433 // Get device config from netconfig, to ascertain that session with ingress is present.
434 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
435 if (cfg == null) {
436 log.debug("No session to ingress.");
Priyanka Ba32f6da2016-09-02 16:10:21 +0530437 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huawei032a9872016-05-27 22:57:38 +0530438 return false;
439 }
440
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530441 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
442 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
443
444 double bwConstraintValue = 0;
445 CostConstraint costConstraint = null;
446 if (constraints != null) {
447 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
448 Iterator<Constraint> iterator = constraints.iterator();
449
450 while (iterator.hasNext()) {
451 Constraint constraint = iterator.next();
452 if (constraint instanceof BandwidthConstraint) {
453 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
454 } else if (constraint instanceof CostConstraint) {
455 costConstraint = (CostConstraint) constraint;
456 }
457 }
458
459 /*
460 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
461 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
462 * function can either return the result of limiting/capability constraint validation or the value of link
463 * cost, depending upon what is the last constraint in the loop.
464 */
465 if (costConstraint != null) {
466 constraints.remove(costConstraint);
467 constraints.add(costConstraint);
468 }
469 } else {
470 constraints = new LinkedList<>();
471 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
472 }
Priyanka Ba32f6da2016-09-02 16:10:21 +0530473 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530474
Priyanka Ba32f6da2016-09-02 16:10:21 +0530475 if (explicitPathInfo != null && !explicitPathInfo.isEmpty()) {
476 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo, src, dst, constraints);
477 if (finalComputedPath == null) {
478 return false;
479 }
480
481 pceStore.tunnelNameExplicitPathInfoMap(tunnelName, explicitPathInfo);
482 List<Link> links = new LinkedList<>();
483 double totalCost = 0;
484 // Add all partial computed paths
485 for (Path path : finalComputedPath) {
486 links.addAll(path.links());
487 totalCost = totalCost + path.cost();
488 }
489 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(), links, totalCost));
490 } else {
491 computedPathSet = computePath(src, dst, constraints);
492 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530493
494 // NO-PATH
495 if (computedPathSet.isEmpty()) {
Priyanka Ba32f6da2016-09-02 16:10:21 +0530496 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530497 return false;
498 }
499
500 Builder annotationBuilder = DefaultAnnotations.builder();
501 if (bwConstraintValue != 0) {
502 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
503 }
504 if (costConstraint != null) {
505 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
506 }
507 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
508 annotationBuilder.set(PCE_INIT, TRUE);
509 annotationBuilder.set(DELEGATE, TRUE);
510
511 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530512
513 if (lspType != WITH_SIGNALLING) {
514 /*
515 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
516 * PCE for non-RSVP signalled LSPs.
517 */
518 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
519 }
520
521 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
522 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
523 TunnelName.tunnelName(tunnelName), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530524 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530525
526 // Allocate bandwidth.
527 TunnelConsumerId consumerId = null;
528 if (bwConstraintValue != 0) {
529 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
530 if (consumerId == null) {
Priyanka Ba32f6da2016-09-02 16:10:21 +0530531 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints,
532 lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530533 return false;
534 }
535 }
536
537 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
538 if (tunnelId == null) {
Priyanka Ba32f6da2016-09-02 16:10:21 +0530539 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530540 if (consumerId != null) {
541 resourceService.release(consumerId);
542 }
543 return false;
544 }
545
546 if (consumerId != null) {
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530547 // Store tunnel consumer id in LSP store.
548 pceStore.addTunnelInfo(tunnelId, consumerId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530549 }
550 return true;
551 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530552
553 @Override
554 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
555 checkNotNull(tunnelId);
Priyanka Ba32f6da2016-09-02 16:10:21 +0530556 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530557 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530558
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530559 if (tunnel == null) {
560 return false;
561 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530562
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530563 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
564 // Only delegated LSPs can be updated.
565 return false;
566 }
567
568 List<Link> links = tunnel.path().links();
569 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
570 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530571 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530572 SharedBandwidthConstraint shBwConstraint = null;
573 BandwidthConstraint bwConstraint = null;
574 CostConstraint costConstraint = null;
575
576 if (constraints != null) {
577 // Call path computation in shared bandwidth mode.
578 Iterator<Constraint> iterator = constraints.iterator();
579 while (iterator.hasNext()) {
580 Constraint constraint = iterator.next();
581 if (constraint instanceof BandwidthConstraint) {
582 bwConstraint = (BandwidthConstraint) constraint;
583 bwConstraintValue = bwConstraint.bandwidth().bps();
584 } else if (constraint instanceof CostConstraint) {
585 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530586 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530587 }
588 }
589
590 // Remove and keep the cost constraint at the end of the list of constraints.
591 if (costConstraint != null) {
592 constraints.remove(costConstraint);
593 }
594
595 Bandwidth existingBwValue = null;
596 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
597 if (existingBwAnnotation != null) {
598 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
599
600 /*
601 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
602 * has been utilized to create shared bandwidth constraint.
603 */
604 if (bwConstraint != null) {
605 constraints.remove(bwConstraint);
606 }
607 }
608
609 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530610 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530611 bwConstraintValue = existingBwValue.bps();
612 }
613 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
614 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
615 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
616 existingBwValue, existingBwValue);
617
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530618 constraints.add(shBwConstraint);
619 }
620 } else {
621 constraints = new LinkedList<>();
622 }
623
624 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
625 if (costConstraint != null) {
626 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530627 } else {
628 //Take cost constraint from old tunnel if it is not specified in update flow
629 costType = tunnel.annotations().value(COST_TYPE);
630 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
631 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530632 }
633
Priyanka Ba32f6da2016-09-02 16:10:21 +0530634 List<ExplicitPathInfo> explicitPathInfo = pceStore
635 .getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value());
636 if (explicitPathInfo != null) {
637 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo,
638 tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
639 constraints);
640
641 if (finalComputedPath == null) {
642 return false;
643 }
644
645 List<Link> totalLinks = new LinkedList<>();
646 double totalCost = 0;
647 //Add all partial computed paths
648 for (Path path : finalComputedPath) {
649 totalLinks.addAll(path.links());
650 totalCost = totalCost + path.cost();
651 }
652 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(),
653 totalLinks, totalCost));
654 } else {
655 computedPathSet = computePath(tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
656 constraints);
657 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530658
659 // NO-PATH
660 if (computedPathSet.isEmpty()) {
661 return false;
662 }
663
664 Builder annotationBuilder = DefaultAnnotations.builder();
665 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530666 if (costType != null) {
667 annotationBuilder.set(COST_TYPE, costType);
668 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530669 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
670 annotationBuilder.set(PCE_INIT, TRUE);
671 annotationBuilder.set(DELEGATE, TRUE);
672 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
673 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
674
675 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530676 TunnelConsumerId consumerId = null;
677 LspType lspType = LspType.valueOf(lspSigType);
678 long localLspId = 0;
679 if (lspType != WITH_SIGNALLING) {
680 /*
681 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
682 * PCE for non-RSVP signalled LSPs.
683 */
684 localLspId = getNextLocalLspId();
685 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530686 }
687
688 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
689 tunnel.tunnelName(), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530690 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530691
692 // Allocate shared bandwidth.
693 if (bwConstraintValue != 0) {
694 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
695 if (consumerId == null) {
696 return false;
697 }
698 }
699
700 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
701 computedPath);
702
703 if (updatedTunnelId == null) {
704 if (consumerId != null) {
705 resourceService.release(consumerId);
706 }
707 return false;
708 }
709
710 if (consumerId != null) {
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530711 // Store tunnel consumer id in LSP store.
712 pceStore.addTunnelInfo(updatedTunnelId, consumerId);
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530713 }
714
Avantika-Huawei73862d42016-05-12 18:58:06 +0530715 return true;
716 }
717
718 @Override
719 public boolean releasePath(TunnelId tunnelId) {
720 checkNotNull(tunnelId);
721 // 1. Query Tunnel from Tunnel manager.
722 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
723
724 if (tunnel == null) {
725 return false;
726 }
727
728 // 2. Call tunnel service.
729 return tunnelService.downTunnel(appId, tunnel.tunnelId());
730 }
731
732 @Override
733 public Iterable<Tunnel> queryAllPath() {
734 return tunnelService.queryTunnel(MPLS);
735 }
736
737 @Override
738 public Tunnel queryPath(TunnelId tunnelId) {
739 return tunnelService.queryTunnel(tunnelId);
740 }
741
742 /**
743 * Returns the next local LSP identifier to be used either by getting from
744 * freed list if available otherwise generating a new one.
745 *
746 * @return value of local LSP identifier
747 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530748 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530749 // If there is any free id use it. Otherwise generate new id.
750 if (localLspIdFreeList.isEmpty()) {
751 return (short) localLspIdIdGen.getNewId();
752 }
753 Iterator<Short> it = localLspIdFreeList.iterator();
754 Short value = it.next();
755 localLspIdFreeList.remove(value);
756 return value;
757 }
758
Priyanka Bb6963582016-05-20 20:21:20 +0530759 protected class TeConstraintBasedLinkWeight implements LinkWeight {
760
761 private final List<Constraint> constraints;
762
763 /**
764 * Creates a new edge-weight function capable of evaluating links
765 * on the basis of the specified constraints.
766 *
767 * @param constraints path constraints
768 */
769 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
770 if (constraints == null) {
771 this.constraints = Collections.emptyList();
772 } else {
773 this.constraints = ImmutableList.copyOf(constraints);
774 }
775 }
776
777 @Override
778 public double weight(TopologyEdge edge) {
779 if (!constraints.iterator().hasNext()) {
780 //Takes default cost/hopcount as 1 if no constraints specified
781 return 1.0;
782 }
783
784 Iterator<Constraint> it = constraints.iterator();
785 double cost = 1;
786
787 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
788 while (it.hasNext() && cost > 0) {
789 Constraint constraint = it.next();
790 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530791 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
792 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530793 } else {
794 cost = constraint.cost(edge.link(), resourceService::isAvailable);
795 }
796 }
797 return cost;
798 }
799 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530800
Priyanka B3f92c5a2016-05-27 10:14:16 +0530801 //TODO: annotations used for temporarily later projection/network config will be used
802 private class InternalTopologyListener implements TopologyListener {
803 @Override
804 public void event(TopologyEvent event) {
805 event.reasons().forEach(e -> {
806 //If event type is link removed, get the impacted tunnel
807 if (e instanceof LinkEvent) {
808 LinkEvent linkEvent = (LinkEvent) e;
809 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
810 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530811 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530812 // Check whether this ONOS instance is master for ingress device if yes,
813 // recompute and send update
814 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
815 }
816 });
817 }
818 }
819 });
820 }
821 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530822
Priyanka B3f92c5a2016-05-27 10:14:16 +0530823 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
824 /**
825 * Master of ingress node will recompute and also delegation flag must be set.
826 */
827 if (mastershipService.isLocalMaster(src)
828 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
829 LinkedList<Constraint> constraintList = new LinkedList<>();
830
831 if (tunnel.annotations().value(BANDWIDTH) != null) {
832 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
833 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
834 .annotations().value(BANDWIDTH))));
835 constraintList.add(localConst);
836 }
837 if (tunnel.annotations().value(COST_TYPE) != null) {
838 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
839 COST_TYPE))));
840 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530841
842 /*
843 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
844 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
845 */
846 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530847 // If updation fails store in PCE store as failed path
848 // then PCInitiate (Remove)
849 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
850 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
Priyanka Ba32f6da2016-09-02 16:10:21 +0530851 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE)),
852 pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value())));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530853 //Release that tunnel calling PCInitiate
854 releasePath(tunnel.tunnelId());
855 }
856 }
857
858 return false;
859 }
860
861 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530862 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
863 SharedBandwidthConstraint shBwConstraint) {
864 checkNotNull(computedPath);
865 checkNotNull(bandwidthConstraint);
866 Resource resource = null;
867 double bwToAllocate = 0;
868
869 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
870
871 /**
872 * Shared bandwidth sub-case : Lesser bandwidth required than original -
873 * No reservation required.
874 */
875 Double additionalBwValue = null;
876 if (shBwConstraint != null) {
877 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
878 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
879 }
880
881 Optional<ResourceAllocation> resAlloc = null;
882 for (Link link : computedPath.links()) {
883 bwToAllocate = 0;
884 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
885 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530886 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530887 }
888 } else {
889 bwToAllocate = bandwidthConstraint;
890 }
891
892 /**
893 * In shared bandwidth cases, where new BW is lesser than old BW, it
894 * is not required to allocate anything.
895 */
896 if (bwToAllocate != 0) {
897 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
898 .resource(bwToAllocate);
899 resAlloc = resourceService.allocate(consumer, resource);
900
901 // If allocation for any link fails, then release the partially allocated bandwidth.
902 if (!resAlloc.isPresent()) {
903 resourceService.release(consumer);
904 return null;
905 }
906 }
907 }
908
909 /*
910 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
911 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
912 * to who is supposed to store/delete.
913 */
914 return consumer;
915 }
916
917 /*
918 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
919 */
920 private void releaseBandwidth(Tunnel tunnel) {
921 // Between same source and destination, search the tunnel with same symbolic path name.
922 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
923 Tunnel newTunnel = null;
924 for (Tunnel tunnelObj : tunnelQueryResult) {
925 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
926 newTunnel = tunnelObj;
927 break;
928 }
929 }
930
931 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
932 boolean isLinkShared = false;
933 if (newTunnel != null) {
934 for (Link link : tunnel.path().links()) {
935 if (newTunnel.path().links().contains(link)) {
936 isLinkShared = true;
937 break;
938 }
939 }
940 }
941
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530942 ResourceConsumer tunnelConsumerId = pceStore.getTunnelInfo(tunnel.tunnelId());
943 if (tunnelConsumerId == null) {
944 //If bandwidth for old tunnel is not allocated i,e 0 then no need to release
945 log.debug("Bandwidth not allocated (0 bandwidth) for old LSP.");
946 return;
947 }
948
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530949 if (isLinkShared) {
950 releaseSharedBandwidth(newTunnel, tunnel);
951 return;
952 }
953
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530954 resourceService.release(tunnelConsumerId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530955 /*
956 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
957 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
958 * to who is supposed to store/delete.
959 */
960 }
961
962 /**
963 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
964 * allocated in shared mode initially.
965 */
966 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
967 // 1. Release old tunnel's bandwidth.
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530968 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530969
Priyanka B4c3b4512016-07-22 11:41:49 +0530970 // 2. Release new tunnel's bandwidth, if new tunnel bandwidth is allocated
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530971 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId());
972 if (consumer == null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530973 //If bandwidth for new tunnel is not allocated i,e 0 then no need to allocate
974 return;
975 }
976
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530977 resourceService.release(consumer);
978
979 // 3. Allocate new tunnel's complete bandwidth.
980 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
981 Resource resource;
982
983 for (Link link : newTunnel.path().links()) {
984 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
985 .resource(bandwidth);
986 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530987
988 }
989 }
990
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530991 // Listens on tunnel events.
992 private class InnerTunnelListener implements TunnelListener {
993 @Override
994 public void event(TunnelEvent event) {
995 // Event gets generated with old tunnel object.
996 Tunnel tunnel = event.subject();
997 if (tunnel.type() != MPLS) {
998 return;
999 }
1000
1001 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1002 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1003 double bwConstraintValue = 0;
1004 if (tunnelBandwidth != null) {
1005 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1006 }
1007
1008 switch (event.type()) {
1009 case TUNNEL_ADDED:
1010 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1011 String pceInit = tunnel.annotations().value(PCE_INIT);
Avantika-Huawei9e848e82016-09-01 12:12:42 +05301012 if (FALSE.equalsIgnoreCase(pceInit) && bwConstraintValue != 0) {
1013 TunnelConsumerId consumerId = reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1014 if (consumerId != null) {
1015 // Store tunnel consumer id in LSP store.
1016 pceStore.addTunnelInfo(tunnel.tunnelId(), consumerId);
1017 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301018 }
1019 break;
1020
1021 case TUNNEL_UPDATED:
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301022 if (tunnel.state() == UNSTABLE) {
1023 /*
1024 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1025 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1026 * and setup while global reoptimization.
1027 */
1028
1029 List<Constraint> constraints = new LinkedList<>();
1030 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1031 if (bandwidth != null) {
1032 constraints.add(new BandwidthConstraint(Bandwidth
1033 .bps(Double.parseDouble(bandwidth))));
1034 }
1035
1036 String costType = tunnel.annotations().value(COST_TYPE);
1037 if (costType != null) {
1038 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1039 constraints.add(costConstraint);
1040 }
1041
1042 constraints.add(CapabilityConstraint
1043 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1044
1045 List<Link> links = tunnel.path().links();
1046 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1047 links.get(links.size() - 1).dst().deviceId(),
Priyanka Ba32f6da2016-09-02 16:10:21 +05301048 tunnel.tunnelName().value(), constraints, lspType,
1049 pceStore.getTunnelNameExplicitPathInfoMap(tunnel
1050 .tunnelName().value())));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301051 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301052
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301053 break;
1054
1055 case TUNNEL_REMOVED:
1056 if (lspType != WITH_SIGNALLING) {
1057 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1058 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301059 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Priyanka B3fdb9dd2016-08-08 10:47:24 +05301060 if (bwConstraintValue != 0
Priyanka B4c3b4512016-07-22 11:41:49 +05301061 && mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1062 releaseBandwidth(tunnel);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301063 }
Priyanka B4c3b4512016-07-22 11:41:49 +05301064
1065 if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
1066 pceStore.removeTunnelInfo(tunnel.tunnelId());
1067 }
1068
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301069 break;
1070
1071 default:
1072 break;
1073
1074 }
1075 return;
1076 }
1077 }
1078
Priyanka Ba32f6da2016-09-02 16:10:21 +05301079 @Override
1080 public List<ExplicitPathInfo> explicitPathInfoList(String tunnelName) {
1081 return pceStore.getTunnelNameExplicitPathInfoMap(tunnelName);
1082 }
1083
Priyanka B9fa4ed32016-05-27 11:59:24 +05301084 //Computes path from tunnel store and also path failed to setup.
1085 private void callForOptimization() {
1086 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1087 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1088 checkForMasterAndSetupPath(failedPathInfo);
1089 }
1090
1091 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1092 tunnelService.queryTunnel(MPLS).forEach(t -> {
1093 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1094 });
1095 }
1096
1097 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1098 /**
1099 * Master of ingress node will setup the path failed stored in PCE store.
1100 */
1101 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1102 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
Priyanka Ba32f6da2016-09-02 16:10:21 +05301103 failedPathInfo.constraints(), failedPathInfo.lspType(), failedPathInfo.explicitPathInfo())) {
Priyanka B9fa4ed32016-05-27 11:59:24 +05301104 // If computation is success remove that path
1105 pceStore.removeFailedPathInfo(failedPathInfo);
1106 return true;
1107 }
1108 }
1109
1110 return false;
1111 }
1112
1113 //Timer to call global optimization
1114 private class GlobalOptimizationTimer implements Runnable {
1115
1116 public GlobalOptimizationTimer() {
1117 }
1118
1119 @Override
1120 public void run() {
1121 callForOptimization();
1122 }
1123 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301124}