blob: bc80a7f97d116e36af71d5a9b2dc29ba7d39e51e [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
Satish K2eb5d842017-04-04 16:28:37 +053020import java.util.ArrayList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053021import java.util.Collection;
Priyanka Bb6963582016-05-20 20:21:20 +053022import java.util.Collections;
Satish K2eb5d842017-04-04 16:28:37 +053023import java.util.HashMap;
Avantika-Huawei73862d42016-05-12 18:58:06 +053024import java.util.Iterator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053025import java.util.LinkedList;
Avantika-Huawei73862d42016-05-12 18:58:06 +053026import java.util.List;
Satish K2eb5d842017-04-04 16:28:37 +053027import java.util.Map;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053028import java.util.Optional;
Priyanka Bb6963582016-05-20 20:21:20 +053029import java.util.Set;
Avantika-Huawei73862d42016-05-12 18:58:06 +053030import org.apache.felix.scr.annotations.Activate;
31import org.apache.felix.scr.annotations.Component;
32import org.apache.felix.scr.annotations.Deactivate;
33import org.apache.felix.scr.annotations.Reference;
34import org.apache.felix.scr.annotations.ReferenceCardinality;
35import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053036import org.onlab.packet.IpAddress;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053037import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
40import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053041import org.onosproject.incubator.net.tunnel.DefaultTunnel;
42import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
Avantika-Huawei73862d42016-05-12 18:58:06 +053043import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053044import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
45import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053046import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053047import org.onosproject.incubator.net.tunnel.TunnelListener;
48import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053049import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053050import org.onosproject.mastership.MastershipService;
Satish K2eb5d842017-04-04 16:28:37 +053051import org.onosproject.net.LinkKey;
52import org.onosproject.net.config.ConfigFactory;
53import org.onosproject.net.config.NetworkConfigRegistry;
Avantika-Huawei032a9872016-05-27 22:57:38 +053054import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053055import org.onosproject.net.DefaultAnnotations;
56import org.onosproject.net.DefaultAnnotations.Builder;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053057import org.onosproject.net.DefaultPath;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053058import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053059import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053060import org.onosproject.net.Link;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053061import org.onosproject.net.NetworkResource;
Priyanka Bb6963582016-05-20 20:21:20 +053062import org.onosproject.net.Path;
Satish K2eb5d842017-04-04 16:28:37 +053063import org.onosproject.net.config.basics.SubjectFactories;
Priyanka Bb6963582016-05-20 20:21:20 +053064import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053065import org.onosproject.net.intent.Constraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +053066import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053067import org.onosproject.net.MastershipRole;
Satish K2eb5d842017-04-04 16:28:37 +053068import org.onosproject.bandwidthmgr.api.BandwidthMgmtService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053069import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
70import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
71import org.onosproject.pce.pceservice.constraint.CostConstraint;
Satish K2eb5d842017-04-04 16:28:37 +053072import org.onosproject.pce.pceservice.constraint.PceBandwidthConstraint;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053073import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
74import org.onosproject.net.resource.Resource;
75import org.onosproject.net.resource.ResourceAllocation;
Priyanka Bb6963582016-05-20 20:21:20 +053076import org.onosproject.net.topology.LinkWeight;
77import org.onosproject.net.topology.PathService;
78import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053079import org.onosproject.net.topology.TopologyEvent;
80import org.onosproject.net.topology.TopologyListener;
81import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053082import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053083import org.onosproject.pce.pcestore.PcePathInfo;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053084import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +053085import org.onosproject.pcep.api.DeviceCapability;
Satish K2eb5d842017-04-04 16:28:37 +053086import org.onosproject.pcep.api.TeLinkConfig;
Avantika-Huawei73862d42016-05-12 18:58:06 +053087import org.onosproject.store.serializers.KryoNamespaces;
88import org.onosproject.store.service.DistributedSet;
89import org.onosproject.store.service.Serializer;
90import org.onosproject.store.service.StorageService;
91import org.slf4j.Logger;
92import org.slf4j.LoggerFactory;
93
Priyanka Bb6963582016-05-20 20:21:20 +053094import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053095import com.google.common.collect.ImmutableSet;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053096import com.google.common.collect.Sets;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053097
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053098import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053099import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
Priyanka B4c3b4512016-07-22 11:41:49 +0530100import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530101import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530102import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
103import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
104import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
105import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
106import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
107import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
108import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
109import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
110
Avantika-Huawei73862d42016-05-12 18:58:06 +0530111/**
112 * Implementation of PCE service.
113 */
114@Component(immediate = true)
115@Service
116public class PceManager implements PceService {
117 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
118
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530119 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
120 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530121 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530122 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530123 public static final String DEVICE_TYPE = "type";
124 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530125
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530126 private static final String LSRID = "lsrId";
127 private static final String TRUE = "true";
128 private static final String FALSE = "false";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530129 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530130
Avantika-Huawei73862d42016-05-12 18:58:06 +0530131 private IdGenerator localLspIdIdGen;
132 protected DistributedSet<Short> localLspIdFreeList;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected CoreService coreService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530138 protected PathService pathService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected PceStore pceStore;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530144 protected TunnelService tunnelService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka Bb6963582016-05-20 20:21:20 +0530147 protected DeviceService deviceService;
148
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530150 protected StorageService storageService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530151
152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530153 protected NetworkConfigService netCfgService;
154
155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka B3f92c5a2016-05-27 10:14:16 +0530156 protected MastershipService mastershipService;
157
158 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
159 protected TopologyService topologyService;
160
Satish K2eb5d842017-04-04 16:28:37 +0530161 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
162 protected BandwidthMgmtService bandwidthMgmtService;
163
164 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
165 protected NetworkConfigRegistry netConfigRegistry;
166
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530167 private TunnelListener listener = new InnerTunnelListener();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530168 private ApplicationId appId;
169
Priyanka B3f92c5a2016-05-27 10:14:16 +0530170 private final TopologyListener topologyListener = new InternalTopologyListener();
Priyanka B9fa4ed32016-05-27 11:59:24 +0530171
Satish K2eb5d842017-04-04 16:28:37 +0530172 private List<TunnelId> rsvpTunnelsWithLocalBw = new ArrayList<>();
173
174 private final ConfigFactory<LinkKey, TeLinkConfig> configFactory =
175 new ConfigFactory<LinkKey, TeLinkConfig>(SubjectFactories.LINK_SUBJECT_FACTORY,
176 TeLinkConfig.class, "teLinkConfig") {
177 @Override
178 public TeLinkConfig createConfig() {
179 return new TeLinkConfig();
180 }
181 };
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530182
Avantika-Huawei73862d42016-05-12 18:58:06 +0530183 /**
184 * Creates new instance of PceManager.
185 */
186 public PceManager() {
187 }
188
189 @Activate
190 protected void activate() {
191 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530192
193 tunnelService.addListener(listener);
194
Avantika-Huawei73862d42016-05-12 18:58:06 +0530195 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530196 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530197 localLspIdFreeList = storageService.<Short>setBuilder()
198 .withName("pcepLocalLspIdDeletedList")
199 .withSerializer(Serializer.using(KryoNamespaces.API))
200 .build()
201 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530202
Priyanka B3f92c5a2016-05-27 10:14:16 +0530203 topologyService.addListener(topologyListener);
Satish K2eb5d842017-04-04 16:28:37 +0530204 netConfigRegistry.registerConfigFactory(configFactory);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530205
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530206 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530207 }
208
209 @Deactivate
210 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530211 tunnelService.removeListener(listener);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530212 topologyService.removeListener(topologyListener);
Satish K2eb5d842017-04-04 16:28:37 +0530213 netConfigRegistry.unregisterConfigFactory(configFactory);
214
Avantika-Huawei73862d42016-05-12 18:58:06 +0530215 log.info("Stopped");
216 }
217
Priyanka Bb6963582016-05-20 20:21:20 +0530218 /**
219 * Returns an edge-weight capable of evaluating links on the basis of the
220 * specified constraints.
221 *
222 * @param constraints path constraints
223 * @return edge-weight function
224 */
225 private LinkWeight weight(List<Constraint> constraints) {
226 return new TeConstraintBasedLinkWeight(constraints);
227 }
228
229 /**
230 * Computes a path between two devices.
231 *
232 * @param src ingress device
233 * @param dst egress device
234 * @param constraints path constraints
235 * @return computed path based on constraints
236 */
237 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
238 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530239 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530240 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530241
Priyanka Bb6963582016-05-20 20:21:20 +0530242 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530243 log.info("paths in computePath ::" + paths);
Priyanka Bb6963582016-05-20 20:21:20 +0530244 if (!paths.isEmpty()) {
245 return paths;
246 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530247 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530248 }
249
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530250 //Computes the partial path from partial computed path to specified dst.
251 private List<Path> computePartialPath(List<Path> computedPath, DeviceId src, DeviceId dst,
252 List<Constraint> constraints) {
253 int size = computedPath.size();
254 Path path = null;
255 DeviceId deviceId = size == 0 ? src :
256 computedPath.get(size - 1).dst().deviceId();
257
258 Set<Path> tempComputePath = computePath(deviceId, dst, constraints);
259
260 if (tempComputePath.isEmpty()) {
261 return null;
262 }
263
264 //if path validation fails return null
265 //Validate computed path to avoid loop in the path
266 for (Path p : tempComputePath) {
267 if (pathValidation(computedPath, p)) {
268 path = p;
269 break;
270 }
271 }
272 if (path == null) {
273 return null;
274 }
275
276 //Store the partial path result in a list
277 computedPath.add(path);
278 return computedPath;
279 }
280
281 private List<DeviceId> createListOfDeviceIds(List<? extends NetworkResource> list) {
282 List<Link> links = new LinkedList<>();
283 if (!list.isEmpty() && list.iterator().next() instanceof Path) {
284 for (Path path : (List<Path>) list) {
285 links.addAll(path.links());
286 }
287 } else if (!list.isEmpty() && list.iterator().next() instanceof Link) {
288 links.addAll((List<Link>) list);
289 }
290
291 //List of devices for new path computed
292 DeviceId source = null;
293 DeviceId destination = null;
294 List<DeviceId> devList = new LinkedList<>();
295
296 for (Link l : links) {
297 if (!devList.contains(l.src().deviceId())) {
298 devList.add(l.src().deviceId());
299 }
300 if (!devList.contains(l.dst().deviceId())) {
301 devList.add(l.dst().deviceId());
302 }
303 }
304
305 return devList;
306 }
307
308 //To dectect loops in the path i.e if the partial paths has intersection node avoid it.
309 private boolean pathValidation(List<Path> partialPath, Path path) {
310
311 //List of devices in new path computed
312 List<DeviceId> newPartialPathDevList;
313 newPartialPathDevList = createListOfDeviceIds(path.links());
314
315 //List of devices in partial computed path
316 List<DeviceId> partialComputedPathDevList;
317 partialComputedPathDevList = createListOfDeviceIds(partialPath);
318
319 for (DeviceId deviceId : newPartialPathDevList) {
320 for (DeviceId devId : partialComputedPathDevList) {
321 if (!newPartialPathDevList.get(0).equals(deviceId) &&
322 !partialComputedPathDevList.get(partialComputedPathDevList.size() - 1).equals(devId)
323 && deviceId.equals(devId)) {
324 return false;
325 }
326 }
327 }
328 return true;
329 }
330
331 //Returns final computed explicit path (list of partial computed paths).
332 private List<Path> computeExplicitPath(List<ExplicitPathInfo> explicitPathInfo, DeviceId src, DeviceId dst,
333 List<Constraint> constraints) {
334 List<Path> finalComputedPath = new LinkedList<>();
335 for (ExplicitPathInfo info : explicitPathInfo) {
336 /*
337 * If explicit path object is LOOSE,
338 * 1) If specified as DeviceId (node) :
339 * If it is source , compute from source to destination (partial computation not required),
340 * otherwise compute from specified source to specified device
341 * 2) If specified as Link :
342 * Compute partial path from source to link's source , if path exists compute from link's source to dst
343 */
344 if (info.type().equals(ExplicitPathInfo.Type.LOOSE)) {
345 if (info.value() instanceof DeviceId) {
346 // If deviceId is source no need to compute
347 if (!(info.value()).equals(src)) {
348 log.debug("computeExplicitPath :: Loose , device");
349 finalComputedPath = computePartialPath(finalComputedPath, src, (DeviceId) info.value(),
350 constraints);
351 log.debug("finalComputedPath in computeExplicitPath ::" + finalComputedPath);
352 }
353
354 } else if (info.value() instanceof Link) {
355 if ((((Link) info.value()).src().deviceId().equals(src))
356 || (!finalComputedPath.isEmpty()
357 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(
358 ((Link) info.value()).src().deviceId()))) {
359
360 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).dst()
361 .deviceId(), constraints);
362 } else {
363
364 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).src()
365 .deviceId(), constraints) != null ? computePartialPath(finalComputedPath, src,
366 ((Link) info.value()).dst().deviceId(), constraints) : null;
367 }
368 }
369 /*
370 * If explicit path object is STRICT,
371 * 1) If specified as DeviceId (node) :
372 * Check whether partial computed path has reachable to strict specified node orde
373 * strict node is the source, if no set path as null else do nothing
374 * 2) If specified as Link :
375 * Check whether partial computed path has reachable to strict link's src, if yes compute
376 * path from strict link's src to link's dst (to include specified link)
377 */
378 } else if (info.type().equals(ExplicitPathInfo.Type.STRICT)) {
379 if (info.value() instanceof DeviceId) {
380 log.debug("computeExplicitPath :: Strict , device");
381 if (!(!finalComputedPath.isEmpty() && finalComputedPath.get(finalComputedPath.size() - 1).dst()
382 .deviceId().equals(info.value()))
383 && !info.value().equals(src)) {
384 finalComputedPath = null;
385 }
386
387 } else if (info.value() instanceof Link) {
388 log.info("computeExplicitPath :: Strict");
389 finalComputedPath = ((Link) info.value()).src().deviceId().equals(src)
390 || !finalComputedPath.isEmpty()
391 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId()
392 .equals(((Link) info.value()).src().deviceId()) ? computePartialPath(
393 finalComputedPath, src, ((Link) info.value()).dst().deviceId(), constraints) : null;
394
395 //Log.info("computeExplicitPath :: (Link) info.value() " + (Link) info.value());
396 //Log.info("computeExplicitPath :: finalComputedPath " + finalComputedPath);
397
398 if (finalComputedPath != null && !finalComputedPath.get(finalComputedPath.size() - 1).links()
399 .contains((Link) info.value())) {
400 finalComputedPath = null;
401 }
402 }
403 }
404 if (finalComputedPath == null) {
405 return null;
406 }
407 }
408 // Destination is not reached in Partial computed path then compute till destination
409 if (finalComputedPath.isEmpty() || !finalComputedPath.isEmpty()
410 && !finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(dst)) {
411
412 finalComputedPath = computePartialPath(finalComputedPath, src, dst, constraints);
413 if (finalComputedPath == null) {
414 return null;
415 }
416 }
417
418 return finalComputedPath;
419 }
420
Priyanka Ba32f6da2016-09-02 16:10:21 +0530421 @Override
422 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
Priyankab-Huawei3946d732016-10-11 06:24:38 +0000423 LspType lspType) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530424 return setupPath(src, dst, tunnelName, constraints, lspType, null);
425 }
426
427 //[TODO:] handle requests in queue
428 @Override
429 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
430 LspType lspType, List<ExplicitPathInfo> explicitPathInfo) {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530431 checkNotNull(src);
432 checkNotNull(dst);
433 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530434 checkNotNull(lspType);
435
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530436 // Convert from DeviceId to TunnelEndPoint
437 Device srcDevice = deviceService.getDevice(src);
438 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530439
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530440 if (srcDevice == null || dstDevice == null) {
441 // Device is not known.
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530442 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530443 return false;
444 }
445
446 // In future projections instead of annotations will be used to fetch LSR ID.
447 String srcLsrId = srcDevice.annotations().value(LSRID);
448 String dstLsrId = dstDevice.annotations().value(LSRID);
449
450 if (srcLsrId == null || dstLsrId == null) {
451 // LSR id is not known.
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530452 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530453 return false;
454 }
455
Avantika-Huawei032a9872016-05-27 22:57:38 +0530456 // Get device config from netconfig, to ascertain that session with ingress is present.
457 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
458 if (cfg == null) {
459 log.debug("No session to ingress.");
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530460 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huawei032a9872016-05-27 22:57:38 +0530461 return false;
462 }
463
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530464 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
465 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
466
467 double bwConstraintValue = 0;
468 CostConstraint costConstraint = null;
469 if (constraints != null) {
470 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
471 Iterator<Constraint> iterator = constraints.iterator();
472
473 while (iterator.hasNext()) {
474 Constraint constraint = iterator.next();
Satish K2eb5d842017-04-04 16:28:37 +0530475 if (constraint instanceof PceBandwidthConstraint) {
476 bwConstraintValue = ((PceBandwidthConstraint) constraint).bandwidth().bps();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530477 } else if (constraint instanceof CostConstraint) {
478 costConstraint = (CostConstraint) constraint;
479 }
480 }
481
482 /*
483 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
484 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
485 * function can either return the result of limiting/capability constraint validation or the value of link
486 * cost, depending upon what is the last constraint in the loop.
487 */
488 if (costConstraint != null) {
489 constraints.remove(costConstraint);
490 constraints.add(costConstraint);
491 }
492 } else {
493 constraints = new LinkedList<>();
494 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
495 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530496 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530497
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530498 if (explicitPathInfo != null && !explicitPathInfo.isEmpty()) {
499 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo, src, dst, constraints);
500 if (finalComputedPath == null) {
501 return false;
502 }
503
504 pceStore.tunnelNameExplicitPathInfoMap(tunnelName, explicitPathInfo);
505 List<Link> links = new LinkedList<>();
506 double totalCost = 0;
507 // Add all partial computed paths
508 for (Path path : finalComputedPath) {
509 links.addAll(path.links());
510 totalCost = totalCost + path.cost();
511 }
512 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(), links, totalCost));
513 } else {
514 computedPathSet = computePath(src, dst, constraints);
515 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530516
517 // NO-PATH
518 if (computedPathSet.isEmpty()) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530519 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530520 return false;
521 }
522
523 Builder annotationBuilder = DefaultAnnotations.builder();
524 if (bwConstraintValue != 0) {
525 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
526 }
527 if (costConstraint != null) {
528 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
529 }
530 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
531 annotationBuilder.set(PCE_INIT, TRUE);
532 annotationBuilder.set(DELEGATE, TRUE);
533
534 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530535
536 if (lspType != WITH_SIGNALLING) {
537 /*
538 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
539 * PCE for non-RSVP signalled LSPs.
540 */
541 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
542 }
543
544 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
545 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
546 TunnelName.tunnelName(tunnelName), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530547 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530548
Satish K2eb5d842017-04-04 16:28:37 +0530549 // Allocate bandwidth for all tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530550 if (bwConstraintValue != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530551 if (!reserveBandwidth(computedPath, bwConstraintValue, null)) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530552 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints,
553 lspType, explicitPathInfo));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530554 return false;
555 }
556 }
557
558 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
559 if (tunnelId == null) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530560 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
Satish K2eb5d842017-04-04 16:28:37 +0530561
562 if (bwConstraintValue != 0) {
563 computedPath.links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
564 Double.parseDouble(tunnel.annotations().value(BANDWIDTH))));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530565 }
Satish K2eb5d842017-04-04 16:28:37 +0530566
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530567 return false;
568 }
569
Satish K2eb5d842017-04-04 16:28:37 +0530570 if (bwConstraintValue != 0 && lspType == WITH_SIGNALLING) {
571 rsvpTunnelsWithLocalBw.add(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530572 }
Satish K2eb5d842017-04-04 16:28:37 +0530573
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530574 return true;
575 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530576
577 @Override
578 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
579 checkNotNull(tunnelId);
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530580 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530581 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530582
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530583 if (tunnel == null) {
584 return false;
585 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530586
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530587 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
588 // Only delegated LSPs can be updated.
589 return false;
590 }
591
592 List<Link> links = tunnel.path().links();
593 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
594 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530595 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530596 SharedBandwidthConstraint shBwConstraint = null;
Satish K2eb5d842017-04-04 16:28:37 +0530597 PceBandwidthConstraint bwConstraint = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530598 CostConstraint costConstraint = null;
599
600 if (constraints != null) {
601 // Call path computation in shared bandwidth mode.
602 Iterator<Constraint> iterator = constraints.iterator();
603 while (iterator.hasNext()) {
604 Constraint constraint = iterator.next();
Satish K2eb5d842017-04-04 16:28:37 +0530605 if (constraint instanceof PceBandwidthConstraint) {
606 bwConstraint = (PceBandwidthConstraint) constraint;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530607 bwConstraintValue = bwConstraint.bandwidth().bps();
608 } else if (constraint instanceof CostConstraint) {
609 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530610 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530611 }
612 }
613
614 // Remove and keep the cost constraint at the end of the list of constraints.
615 if (costConstraint != null) {
616 constraints.remove(costConstraint);
617 }
618
619 Bandwidth existingBwValue = null;
620 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
621 if (existingBwAnnotation != null) {
622 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
623
624 /*
625 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
626 * has been utilized to create shared bandwidth constraint.
627 */
628 if (bwConstraint != null) {
629 constraints.remove(bwConstraint);
630 }
631 }
632
633 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530634 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530635 bwConstraintValue = existingBwValue.bps();
636 }
637 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
638 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
639 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
640 existingBwValue, existingBwValue);
641
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530642 constraints.add(shBwConstraint);
643 }
644 } else {
645 constraints = new LinkedList<>();
646 }
647
648 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
649 if (costConstraint != null) {
650 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530651 } else {
652 //Take cost constraint from old tunnel if it is not specified in update flow
653 costType = tunnel.annotations().value(COST_TYPE);
654 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
655 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530656 }
657
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530658 List<ExplicitPathInfo> explicitPathInfo = pceStore
659 .getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value());
660 if (explicitPathInfo != null) {
661 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo,
662 tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
663 constraints);
664
665 if (finalComputedPath == null) {
666 return false;
667 }
668
669 List<Link> totalLinks = new LinkedList<>();
670 double totalCost = 0;
671 //Add all partial computed paths
672 for (Path path : finalComputedPath) {
673 totalLinks.addAll(path.links());
674 totalCost = totalCost + path.cost();
675 }
676 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(),
677 totalLinks, totalCost));
678 } else {
679 computedPathSet = computePath(tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
680 constraints);
681 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530682
683 // NO-PATH
684 if (computedPathSet.isEmpty()) {
685 return false;
686 }
687
688 Builder annotationBuilder = DefaultAnnotations.builder();
689 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530690 if (costType != null) {
691 annotationBuilder.set(COST_TYPE, costType);
692 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530693 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
694 annotationBuilder.set(PCE_INIT, TRUE);
695 annotationBuilder.set(DELEGATE, TRUE);
696 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
697 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
698
699 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530700 LspType lspType = LspType.valueOf(lspSigType);
701 long localLspId = 0;
702 if (lspType != WITH_SIGNALLING) {
703 /*
704 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
705 * PCE for non-RSVP signalled LSPs.
706 */
707 localLspId = getNextLocalLspId();
708 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530709 }
710
711 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
712 tunnel.tunnelName(), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530713 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530714
Satish K2eb5d842017-04-04 16:28:37 +0530715 // Allocate shared bandwidth for all tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530716 if (bwConstraintValue != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530717 if (!reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint)) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530718 return false;
719 }
720 }
721
722 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
723 computedPath);
724
725 if (updatedTunnelId == null) {
Satish K2eb5d842017-04-04 16:28:37 +0530726 if (bwConstraintValue != 0) {
727 releaseSharedBwForNewTunnel(computedPath, bwConstraintValue, shBwConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530728 }
729 return false;
730 }
731
Satish K2eb5d842017-04-04 16:28:37 +0530732 if (bwConstraintValue != 0 && lspType == WITH_SIGNALLING) {
733 rsvpTunnelsWithLocalBw.add(updatedTunnelId);
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530734 }
735
Avantika-Huawei73862d42016-05-12 18:58:06 +0530736 return true;
737 }
738
739 @Override
740 public boolean releasePath(TunnelId tunnelId) {
741 checkNotNull(tunnelId);
742 // 1. Query Tunnel from Tunnel manager.
743 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
744
745 if (tunnel == null) {
746 return false;
747 }
748
749 // 2. Call tunnel service.
750 return tunnelService.downTunnel(appId, tunnel.tunnelId());
751 }
752
753 @Override
754 public Iterable<Tunnel> queryAllPath() {
755 return tunnelService.queryTunnel(MPLS);
756 }
757
758 @Override
759 public Tunnel queryPath(TunnelId tunnelId) {
760 return tunnelService.queryTunnel(tunnelId);
761 }
762
Satish K2eb5d842017-04-04 16:28:37 +0530763 private boolean releaseSharedBwForNewTunnel(Path computedPath, double bandwidthConstraint,
764 SharedBandwidthConstraint shBwConstraint) {
765 checkNotNull(computedPath);
766 checkNotNull(bandwidthConstraint);
767 double bwToAllocate;
768
769 Double additionalBwValue = null;
770 if (shBwConstraint != null) {
771 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
772 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
773 }
774
775 for (Link link : computedPath.links()) {
776 bwToAllocate = 0;
777 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
778 if (additionalBwValue != null) {
779 bwToAllocate = additionalBwValue;
780 }
781 } else {
782 bwToAllocate = bandwidthConstraint;
783 }
784
785 if (bwToAllocate != 0) {
786 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link), bwToAllocate);
787 }
788 }
789 return true;
790 }
791
Avantika-Huawei73862d42016-05-12 18:58:06 +0530792 /**
793 * Returns the next local LSP identifier to be used either by getting from
794 * freed list if available otherwise generating a new one.
795 *
796 * @return value of local LSP identifier
797 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530798 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530799 // If there is any free id use it. Otherwise generate new id.
800 if (localLspIdFreeList.isEmpty()) {
801 return (short) localLspIdIdGen.getNewId();
802 }
803 Iterator<Short> it = localLspIdFreeList.iterator();
804 Short value = it.next();
805 localLspIdFreeList.remove(value);
806 return value;
807 }
808
Priyanka Bb6963582016-05-20 20:21:20 +0530809 protected class TeConstraintBasedLinkWeight implements LinkWeight {
810
811 private final List<Constraint> constraints;
812
813 /**
814 * Creates a new edge-weight function capable of evaluating links
815 * on the basis of the specified constraints.
816 *
817 * @param constraints path constraints
818 */
819 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
820 if (constraints == null) {
821 this.constraints = Collections.emptyList();
822 } else {
823 this.constraints = ImmutableList.copyOf(constraints);
824 }
825 }
826
827 @Override
828 public double weight(TopologyEdge edge) {
829 if (!constraints.iterator().hasNext()) {
830 //Takes default cost/hopcount as 1 if no constraints specified
831 return 1.0;
832 }
833
834 Iterator<Constraint> it = constraints.iterator();
835 double cost = 1;
836
837 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
838 while (it.hasNext() && cost > 0) {
839 Constraint constraint = it.next();
840 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530841 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
842 netCfgService) ? 1 : -1;
Satish K2eb5d842017-04-04 16:28:37 +0530843 } else if (constraint instanceof PceBandwidthConstraint) {
844 cost = ((PceBandwidthConstraint) constraint).isValidLink(edge.link(),
845 bandwidthMgmtService) ? 1 : -1;
846 } else if (constraint instanceof SharedBandwidthConstraint) {
847 cost = ((SharedBandwidthConstraint) constraint).isValidLink(edge.link(),
848 bandwidthMgmtService) ? 1 : -1;
849 } else if (constraint instanceof CostConstraint) {
850 cost = ((CostConstraint) constraint).isValidLink(edge.link(), netCfgService);
Priyanka Bb6963582016-05-20 20:21:20 +0530851 } else {
Satish K2eb5d842017-04-04 16:28:37 +0530852 cost = constraint.cost(edge.link(), null);
Priyanka Bb6963582016-05-20 20:21:20 +0530853 }
854 }
855 return cost;
856 }
857 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530858
Priyanka B3f92c5a2016-05-27 10:14:16 +0530859 //TODO: annotations used for temporarily later projection/network config will be used
860 private class InternalTopologyListener implements TopologyListener {
861 @Override
862 public void event(TopologyEvent event) {
863 event.reasons().forEach(e -> {
864 //If event type is link removed, get the impacted tunnel
865 if (e instanceof LinkEvent) {
866 LinkEvent linkEvent = (LinkEvent) e;
867 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
868 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530869 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530870 // Check whether this ONOS instance is master for ingress device if yes,
871 // recompute and send update
872 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
873 }
874 });
875 }
876 }
877 });
878 }
879 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530880
Priyanka B3f92c5a2016-05-27 10:14:16 +0530881 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
882 /**
883 * Master of ingress node will recompute and also delegation flag must be set.
884 */
885 if (mastershipService.isLocalMaster(src)
886 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
887 LinkedList<Constraint> constraintList = new LinkedList<>();
888
889 if (tunnel.annotations().value(BANDWIDTH) != null) {
890 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
Satish K2eb5d842017-04-04 16:28:37 +0530891 PceBandwidthConstraint localConst = new PceBandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
Priyanka B3f92c5a2016-05-27 10:14:16 +0530892 .annotations().value(BANDWIDTH))));
893 constraintList.add(localConst);
894 }
895 if (tunnel.annotations().value(COST_TYPE) != null) {
896 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
897 COST_TYPE))));
898 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530899
900 /*
901 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
902 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
903 */
904 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530905 // If updation fails store in PCE store as failed path
906 // then PCInitiate (Remove)
907 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
908 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530909 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE)),
910 pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value())));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530911 //Release that tunnel calling PCInitiate
912 releasePath(tunnel.tunnelId());
913 }
914 }
915
916 return false;
917 }
918
919 // Allocates the bandwidth locally for PCECC tunnels.
Satish K2eb5d842017-04-04 16:28:37 +0530920 private boolean reserveBandwidth(Path computedPath, double bandwidthConstraint,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530921 SharedBandwidthConstraint shBwConstraint) {
922 checkNotNull(computedPath);
923 checkNotNull(bandwidthConstraint);
924 Resource resource = null;
925 double bwToAllocate = 0;
Satish K2eb5d842017-04-04 16:28:37 +0530926 Map<Link, Double> linkMap = new HashMap<>();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530927
928 /**
929 * Shared bandwidth sub-case : Lesser bandwidth required than original -
930 * No reservation required.
931 */
932 Double additionalBwValue = null;
933 if (shBwConstraint != null) {
934 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
935 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
936 }
937
938 Optional<ResourceAllocation> resAlloc = null;
939 for (Link link : computedPath.links()) {
940 bwToAllocate = 0;
941 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
942 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530943 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530944 }
945 } else {
946 bwToAllocate = bandwidthConstraint;
947 }
948
949 /**
950 * In shared bandwidth cases, where new BW is lesser than old BW, it
951 * is not required to allocate anything.
952 */
953 if (bwToAllocate != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530954 if (!bandwidthMgmtService.allocLocalReservedBw(LinkKey.linkKey(link.src(), link.dst()),
955 bwToAllocate)) {
956 // If allocation for any link fails, then release the partially allocated bandwidth
957 // for all links allocated
958 linkMap.forEach((ln, aDouble) -> bandwidthMgmtService
959 .releaseLocalReservedBw(LinkKey.linkKey(ln), aDouble));
960 return false;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530961 }
Satish K2eb5d842017-04-04 16:28:37 +0530962
963 linkMap.put(link, bwToAllocate);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530964 }
965 }
966
Satish K2eb5d842017-04-04 16:28:37 +0530967 return true;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530968 }
969
970 /*
971 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
972 */
973 private void releaseBandwidth(Tunnel tunnel) {
974 // Between same source and destination, search the tunnel with same symbolic path name.
975 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
976 Tunnel newTunnel = null;
977 for (Tunnel tunnelObj : tunnelQueryResult) {
978 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
979 newTunnel = tunnelObj;
980 break;
981 }
982 }
983
984 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
985 boolean isLinkShared = false;
986 if (newTunnel != null) {
987 for (Link link : tunnel.path().links()) {
988 if (newTunnel.path().links().contains(link)) {
989 isLinkShared = true;
990 break;
991 }
992 }
993 }
994
995 if (isLinkShared) {
996 releaseSharedBandwidth(newTunnel, tunnel);
997 return;
998 }
999
Satish K2eb5d842017-04-04 16:28:37 +05301000 tunnel.path().links().forEach(tn -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(tn),
1001 Double.parseDouble(tunnel.annotations().value(BANDWIDTH))));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301002 }
1003
1004 /**
1005 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
1006 * allocated in shared mode initially.
1007 */
1008 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301009
Satish K2eb5d842017-04-04 16:28:37 +05301010 boolean isAllocate = false;
1011 Double oldTunnelBw = Double.parseDouble(oldTunnel.annotations().value(BANDWIDTH));
1012 Double newTunnelBw = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
1013
1014 if (newTunnelBw > oldTunnelBw) {
1015 isAllocate = true;
Priyanka B4c3b4512016-07-22 11:41:49 +05301016 }
1017
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301018 for (Link link : newTunnel.path().links()) {
Satish K2eb5d842017-04-04 16:28:37 +05301019 if (oldTunnel.path().links().contains(link)) {
1020 if (!isAllocate) {
1021 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link),
1022 oldTunnelBw - newTunnelBw);
1023 }
1024 } else {
1025 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link), oldTunnelBw);
1026 }
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301027 }
1028 }
1029
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301030 // Listens on tunnel events.
1031 private class InnerTunnelListener implements TunnelListener {
1032 @Override
1033 public void event(TunnelEvent event) {
1034 // Event gets generated with old tunnel object.
1035 Tunnel tunnel = event.subject();
1036 if (tunnel.type() != MPLS) {
1037 return;
1038 }
1039
1040 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1041 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1042 double bwConstraintValue = 0;
1043 if (tunnelBandwidth != null) {
1044 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1045 }
1046
1047 switch (event.type()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301048 case TUNNEL_UPDATED:
Satish K2eb5d842017-04-04 16:28:37 +05301049 if (rsvpTunnelsWithLocalBw.contains(tunnel.tunnelId())) {
1050 releaseBandwidth(event.subject());
1051 rsvpTunnelsWithLocalBw.remove(tunnel.tunnelId());
1052 }
1053
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301054 if (tunnel.state() == UNSTABLE) {
1055 /*
1056 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1057 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1058 * and setup while global reoptimization.
1059 */
1060
1061 List<Constraint> constraints = new LinkedList<>();
1062 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1063 if (bandwidth != null) {
Satish K2eb5d842017-04-04 16:28:37 +05301064 constraints.add(new PceBandwidthConstraint(Bandwidth
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301065 .bps(Double.parseDouble(bandwidth))));
1066 }
1067
1068 String costType = tunnel.annotations().value(COST_TYPE);
1069 if (costType != null) {
1070 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1071 constraints.add(costConstraint);
1072 }
1073
1074 constraints.add(CapabilityConstraint
1075 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1076
1077 List<Link> links = tunnel.path().links();
1078 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1079 links.get(links.size() - 1).dst().deviceId(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301080 tunnel.tunnelName().value(), constraints, lspType,
1081 pceStore.getTunnelNameExplicitPathInfoMap(tunnel
1082 .tunnelName().value())));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301083 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301084
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301085 break;
1086
1087 case TUNNEL_REMOVED:
1088 if (lspType != WITH_SIGNALLING) {
1089 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1090 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301091 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Satish K2eb5d842017-04-04 16:28:37 +05301092 if (bwConstraintValue != 0 && mastershipService.getLocalRole(tunnel.path().src()
1093 .deviceId()) == MastershipRole.MASTER) {
1094 if (lspType != WITH_SIGNALLING) {
1095 releaseBandwidth(tunnel);
1096 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301097 }
Priyanka B4c3b4512016-07-22 11:41:49 +05301098
Satish K2eb5d842017-04-04 16:28:37 +05301099 /*if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +05301100 pceStore.removeTunnelInfo(tunnel.tunnelId());
Satish K2eb5d842017-04-04 16:28:37 +05301101 }*/
Priyanka B4c3b4512016-07-22 11:41:49 +05301102
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301103 break;
1104
1105 default:
1106 break;
1107
1108 }
1109 return;
1110 }
1111 }
1112
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301113 @Override
1114 public List<ExplicitPathInfo> explicitPathInfoList(String tunnelName) {
1115 return pceStore.getTunnelNameExplicitPathInfoMap(tunnelName);
1116 }
1117
Priyanka B9fa4ed32016-05-27 11:59:24 +05301118 //Computes path from tunnel store and also path failed to setup.
1119 private void callForOptimization() {
1120 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1121 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1122 checkForMasterAndSetupPath(failedPathInfo);
1123 }
1124
1125 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1126 tunnelService.queryTunnel(MPLS).forEach(t -> {
1127 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1128 });
1129 }
1130
1131 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1132 /**
1133 * Master of ingress node will setup the path failed stored in PCE store.
1134 */
1135 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1136 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301137 failedPathInfo.constraints(), failedPathInfo.lspType(), failedPathInfo.explicitPathInfo())) {
Priyanka B9fa4ed32016-05-27 11:59:24 +05301138 // If computation is success remove that path
1139 pceStore.removeFailedPathInfo(failedPathInfo);
1140 return true;
1141 }
1142 }
1143
1144 return false;
1145 }
1146
1147 //Timer to call global optimization
1148 private class GlobalOptimizationTimer implements Runnable {
1149
1150 public GlobalOptimizationTimer() {
1151 }
1152
1153 @Override
1154 public void run() {
1155 callForOptimization();
1156 }
1157 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301158}