blob: 2c5aad70cd5c313f8d6f96a3eec5e083fbeaa3ee [file] [log] [blame]
Avantika-Huawei73862d42016-05-12 18:58:06 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Avantika-Huawei73862d42016-05-12 18:58:06 +05303 *
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 Kba1c9122017-04-05 15:27:23 +053020import org.onosproject.net.DisjointPath;
Satish K2eb5d842017-04-04 16:28:37 +053021import java.util.ArrayList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053022import java.util.Collection;
Priyanka Bb6963582016-05-20 20:21:20 +053023import java.util.Collections;
Satish K2eb5d842017-04-04 16:28:37 +053024import java.util.HashMap;
Avantika-Huawei73862d42016-05-12 18:58:06 +053025import java.util.Iterator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053026import java.util.LinkedList;
Avantika-Huawei73862d42016-05-12 18:58:06 +053027import java.util.List;
Satish K2eb5d842017-04-04 16:28:37 +053028import java.util.Map;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053029import java.util.Optional;
Priyanka Bb6963582016-05-20 20:21:20 +053030import java.util.Set;
Avantika-Huawei73862d42016-05-12 18:58:06 +053031import org.apache.felix.scr.annotations.Activate;
32import org.apache.felix.scr.annotations.Component;
33import org.apache.felix.scr.annotations.Deactivate;
34import org.apache.felix.scr.annotations.Reference;
35import org.apache.felix.scr.annotations.ReferenceCardinality;
36import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053037import org.onlab.packet.IpAddress;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053038import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
41import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053042import org.onosproject.incubator.net.tunnel.DefaultTunnel;
43import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
Avantika-Huawei73862d42016-05-12 18:58:06 +053044import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053045import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
46import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053047import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053048import org.onosproject.incubator.net.tunnel.TunnelListener;
49import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053050import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053051import org.onosproject.mastership.MastershipService;
Satish K2eb5d842017-04-04 16:28:37 +053052import org.onosproject.net.LinkKey;
53import org.onosproject.net.config.ConfigFactory;
54import org.onosproject.net.config.NetworkConfigRegistry;
Avantika-Huawei032a9872016-05-27 22:57:38 +053055import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053056import org.onosproject.net.DefaultAnnotations;
57import org.onosproject.net.DefaultAnnotations.Builder;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053058import org.onosproject.net.DefaultPath;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053059import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053060import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053061import org.onosproject.net.Link;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053062import org.onosproject.net.NetworkResource;
Priyanka Bb6963582016-05-20 20:21:20 +053063import org.onosproject.net.Path;
Satish K2eb5d842017-04-04 16:28:37 +053064import org.onosproject.net.config.basics.SubjectFactories;
Priyanka Bb6963582016-05-20 20:21:20 +053065import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053066import org.onosproject.net.intent.Constraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +053067import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053068import org.onosproject.net.MastershipRole;
Satish K2eb5d842017-04-04 16:28:37 +053069import org.onosproject.bandwidthmgr.api.BandwidthMgmtService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053070import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
71import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
72import org.onosproject.pce.pceservice.constraint.CostConstraint;
Satish K2eb5d842017-04-04 16:28:37 +053073import org.onosproject.pce.pceservice.constraint.PceBandwidthConstraint;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053074import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
75import org.onosproject.net.resource.Resource;
76import org.onosproject.net.resource.ResourceAllocation;
Priyanka Bb6963582016-05-20 20:21:20 +053077import org.onosproject.net.topology.LinkWeight;
78import org.onosproject.net.topology.PathService;
79import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053080import org.onosproject.net.topology.TopologyEvent;
81import org.onosproject.net.topology.TopologyListener;
82import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053083import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053084import org.onosproject.pce.pcestore.PcePathInfo;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053085import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +053086import org.onosproject.pcep.api.DeviceCapability;
Satish K2eb5d842017-04-04 16:28:37 +053087import org.onosproject.pcep.api.TeLinkConfig;
Avantika-Huawei73862d42016-05-12 18:58:06 +053088import org.onosproject.store.serializers.KryoNamespaces;
89import org.onosproject.store.service.DistributedSet;
90import org.onosproject.store.service.Serializer;
91import org.onosproject.store.service.StorageService;
92import org.slf4j.Logger;
93import org.slf4j.LoggerFactory;
94
Priyanka Bb6963582016-05-20 20:21:20 +053095import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053096import com.google.common.collect.ImmutableSet;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053097import com.google.common.collect.Sets;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053098
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053099import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530100import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
Priyanka B4c3b4512016-07-22 11:41:49 +0530101import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530102import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530103import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
104import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
105import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
106import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
107import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
108import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
109import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
110import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
111
Avantika-Huawei73862d42016-05-12 18:58:06 +0530112/**
113 * Implementation of PCE service.
114 */
115@Component(immediate = true)
116@Service
117public class PceManager implements PceService {
118 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
119
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530120 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
121 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530122 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530123 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530124 public static final String DEVICE_TYPE = "type";
125 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530126
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530127 private static final String LSRID = "lsrId";
128 private static final String TRUE = "true";
129 private static final String FALSE = "false";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530130 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530131
Avantika-Huawei73862d42016-05-12 18:58:06 +0530132 private IdGenerator localLspIdIdGen;
133 protected DistributedSet<Short> localLspIdFreeList;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected CoreService coreService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530139 protected PathService pathService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected PceStore pceStore;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530145 protected TunnelService tunnelService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka Bb6963582016-05-20 20:21:20 +0530148 protected DeviceService deviceService;
149
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530151 protected StorageService storageService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530154 protected NetworkConfigService netCfgService;
155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka B3f92c5a2016-05-27 10:14:16 +0530157 protected MastershipService mastershipService;
158
159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
160 protected TopologyService topologyService;
161
Satish K2eb5d842017-04-04 16:28:37 +0530162 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
163 protected BandwidthMgmtService bandwidthMgmtService;
164
165 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
166 protected NetworkConfigRegistry netConfigRegistry;
167
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530168 private TunnelListener listener = new InnerTunnelListener();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530169 private ApplicationId appId;
170
Priyanka B3f92c5a2016-05-27 10:14:16 +0530171 private final TopologyListener topologyListener = new InternalTopologyListener();
Satish Kba1c9122017-04-05 15:27:23 +0530172 public static final String LOAD_BALANCING_PATH_NAME = "loadBalancingPathName";
Priyanka B9fa4ed32016-05-27 11:59:24 +0530173
Satish K2eb5d842017-04-04 16:28:37 +0530174 private List<TunnelId> rsvpTunnelsWithLocalBw = new ArrayList<>();
175
176 private final ConfigFactory<LinkKey, TeLinkConfig> configFactory =
177 new ConfigFactory<LinkKey, TeLinkConfig>(SubjectFactories.LINK_SUBJECT_FACTORY,
178 TeLinkConfig.class, "teLinkConfig") {
179 @Override
180 public TeLinkConfig createConfig() {
181 return new TeLinkConfig();
182 }
183 };
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530184
Avantika-Huawei73862d42016-05-12 18:58:06 +0530185 /**
186 * Creates new instance of PceManager.
187 */
188 public PceManager() {
189 }
190
191 @Activate
192 protected void activate() {
193 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530194
195 tunnelService.addListener(listener);
196
Avantika-Huawei73862d42016-05-12 18:58:06 +0530197 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530198 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530199 localLspIdFreeList = storageService.<Short>setBuilder()
200 .withName("pcepLocalLspIdDeletedList")
201 .withSerializer(Serializer.using(KryoNamespaces.API))
202 .build()
203 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530204
Priyanka B3f92c5a2016-05-27 10:14:16 +0530205 topologyService.addListener(topologyListener);
Satish K2eb5d842017-04-04 16:28:37 +0530206 netConfigRegistry.registerConfigFactory(configFactory);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530207
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530208 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530209 }
210
211 @Deactivate
212 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530213 tunnelService.removeListener(listener);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530214 topologyService.removeListener(topologyListener);
Satish K2eb5d842017-04-04 16:28:37 +0530215 netConfigRegistry.unregisterConfigFactory(configFactory);
216
Avantika-Huawei73862d42016-05-12 18:58:06 +0530217 log.info("Stopped");
218 }
219
Priyanka Bb6963582016-05-20 20:21:20 +0530220 /**
221 * Returns an edge-weight capable of evaluating links on the basis of the
222 * specified constraints.
223 *
224 * @param constraints path constraints
225 * @return edge-weight function
226 */
227 private LinkWeight weight(List<Constraint> constraints) {
228 return new TeConstraintBasedLinkWeight(constraints);
229 }
230
231 /**
232 * Computes a path between two devices.
233 *
234 * @param src ingress device
235 * @param dst egress device
236 * @param constraints path constraints
237 * @return computed path based on constraints
238 */
239 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
240 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530241 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530242 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530243
Priyanka Bb6963582016-05-20 20:21:20 +0530244 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530245 log.info("paths in computePath ::" + paths);
Priyanka Bb6963582016-05-20 20:21:20 +0530246 if (!paths.isEmpty()) {
247 return paths;
248 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530249 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530250 }
251
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530252 //Computes the partial path from partial computed path to specified dst.
253 private List<Path> computePartialPath(List<Path> computedPath, DeviceId src, DeviceId dst,
254 List<Constraint> constraints) {
255 int size = computedPath.size();
256 Path path = null;
257 DeviceId deviceId = size == 0 ? src :
258 computedPath.get(size - 1).dst().deviceId();
259
260 Set<Path> tempComputePath = computePath(deviceId, dst, constraints);
261
262 if (tempComputePath.isEmpty()) {
263 return null;
264 }
265
266 //if path validation fails return null
267 //Validate computed path to avoid loop in the path
268 for (Path p : tempComputePath) {
269 if (pathValidation(computedPath, p)) {
270 path = p;
271 break;
272 }
273 }
274 if (path == null) {
275 return null;
276 }
277
278 //Store the partial path result in a list
279 computedPath.add(path);
280 return computedPath;
281 }
282
283 private List<DeviceId> createListOfDeviceIds(List<? extends NetworkResource> list) {
284 List<Link> links = new LinkedList<>();
285 if (!list.isEmpty() && list.iterator().next() instanceof Path) {
286 for (Path path : (List<Path>) list) {
287 links.addAll(path.links());
288 }
289 } else if (!list.isEmpty() && list.iterator().next() instanceof Link) {
290 links.addAll((List<Link>) list);
291 }
292
293 //List of devices for new path computed
294 DeviceId source = null;
295 DeviceId destination = null;
296 List<DeviceId> devList = new LinkedList<>();
297
298 for (Link l : links) {
299 if (!devList.contains(l.src().deviceId())) {
300 devList.add(l.src().deviceId());
301 }
302 if (!devList.contains(l.dst().deviceId())) {
303 devList.add(l.dst().deviceId());
304 }
305 }
306
307 return devList;
308 }
309
310 //To dectect loops in the path i.e if the partial paths has intersection node avoid it.
311 private boolean pathValidation(List<Path> partialPath, Path path) {
312
313 //List of devices in new path computed
314 List<DeviceId> newPartialPathDevList;
315 newPartialPathDevList = createListOfDeviceIds(path.links());
316
317 //List of devices in partial computed path
318 List<DeviceId> partialComputedPathDevList;
319 partialComputedPathDevList = createListOfDeviceIds(partialPath);
320
321 for (DeviceId deviceId : newPartialPathDevList) {
322 for (DeviceId devId : partialComputedPathDevList) {
323 if (!newPartialPathDevList.get(0).equals(deviceId) &&
324 !partialComputedPathDevList.get(partialComputedPathDevList.size() - 1).equals(devId)
325 && deviceId.equals(devId)) {
326 return false;
327 }
328 }
329 }
330 return true;
331 }
332
333 //Returns final computed explicit path (list of partial computed paths).
334 private List<Path> computeExplicitPath(List<ExplicitPathInfo> explicitPathInfo, DeviceId src, DeviceId dst,
335 List<Constraint> constraints) {
336 List<Path> finalComputedPath = new LinkedList<>();
337 for (ExplicitPathInfo info : explicitPathInfo) {
338 /*
339 * If explicit path object is LOOSE,
340 * 1) If specified as DeviceId (node) :
341 * If it is source , compute from source to destination (partial computation not required),
342 * otherwise compute from specified source to specified device
343 * 2) If specified as Link :
344 * Compute partial path from source to link's source , if path exists compute from link's source to dst
345 */
346 if (info.type().equals(ExplicitPathInfo.Type.LOOSE)) {
347 if (info.value() instanceof DeviceId) {
348 // If deviceId is source no need to compute
349 if (!(info.value()).equals(src)) {
350 log.debug("computeExplicitPath :: Loose , device");
351 finalComputedPath = computePartialPath(finalComputedPath, src, (DeviceId) info.value(),
352 constraints);
353 log.debug("finalComputedPath in computeExplicitPath ::" + finalComputedPath);
354 }
355
356 } else if (info.value() instanceof Link) {
357 if ((((Link) info.value()).src().deviceId().equals(src))
358 || (!finalComputedPath.isEmpty()
359 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(
360 ((Link) info.value()).src().deviceId()))) {
361
362 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).dst()
363 .deviceId(), constraints);
364 } else {
365
366 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).src()
367 .deviceId(), constraints) != null ? computePartialPath(finalComputedPath, src,
368 ((Link) info.value()).dst().deviceId(), constraints) : null;
369 }
370 }
371 /*
372 * If explicit path object is STRICT,
373 * 1) If specified as DeviceId (node) :
374 * Check whether partial computed path has reachable to strict specified node orde
375 * strict node is the source, if no set path as null else do nothing
376 * 2) If specified as Link :
377 * Check whether partial computed path has reachable to strict link's src, if yes compute
378 * path from strict link's src to link's dst (to include specified link)
379 */
380 } else if (info.type().equals(ExplicitPathInfo.Type.STRICT)) {
381 if (info.value() instanceof DeviceId) {
382 log.debug("computeExplicitPath :: Strict , device");
383 if (!(!finalComputedPath.isEmpty() && finalComputedPath.get(finalComputedPath.size() - 1).dst()
384 .deviceId().equals(info.value()))
385 && !info.value().equals(src)) {
386 finalComputedPath = null;
387 }
388
389 } else if (info.value() instanceof Link) {
390 log.info("computeExplicitPath :: Strict");
391 finalComputedPath = ((Link) info.value()).src().deviceId().equals(src)
392 || !finalComputedPath.isEmpty()
393 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId()
394 .equals(((Link) info.value()).src().deviceId()) ? computePartialPath(
395 finalComputedPath, src, ((Link) info.value()).dst().deviceId(), constraints) : null;
396
397 //Log.info("computeExplicitPath :: (Link) info.value() " + (Link) info.value());
398 //Log.info("computeExplicitPath :: finalComputedPath " + finalComputedPath);
399
400 if (finalComputedPath != null && !finalComputedPath.get(finalComputedPath.size() - 1).links()
401 .contains((Link) info.value())) {
402 finalComputedPath = null;
403 }
404 }
405 }
406 if (finalComputedPath == null) {
407 return null;
408 }
409 }
410 // Destination is not reached in Partial computed path then compute till destination
411 if (finalComputedPath.isEmpty() || !finalComputedPath.isEmpty()
412 && !finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(dst)) {
413
414 finalComputedPath = computePartialPath(finalComputedPath, src, dst, constraints);
415 if (finalComputedPath == null) {
416 return null;
417 }
418 }
419
420 return finalComputedPath;
421 }
422
Priyanka Ba32f6da2016-09-02 16:10:21 +0530423 @Override
424 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
Priyankab-Huawei3946d732016-10-11 06:24:38 +0000425 LspType lspType) {
Satish Kba1c9122017-04-05 15:27:23 +0530426 return setupPath(src, dst, tunnelName, constraints, lspType, null, false);
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530427 }
428
429 //[TODO:] handle requests in queue
430 @Override
431 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
432 LspType lspType, List<ExplicitPathInfo> explicitPathInfo) {
Satish Kba1c9122017-04-05 15:27:23 +0530433 return setupPath(src, dst, tunnelName, constraints, lspType, explicitPathInfo, false);
434
435 }
436
437 @Override
438 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
439 LspType lspType, boolean loadBalancing) {
440 return setupPath(src, dst, tunnelName, constraints, lspType, null, loadBalancing);
441 }
442
443 @Override
444 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
445 LspType lspType, List<ExplicitPathInfo> explicitPathInfo, boolean loadBalancing) {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530446 checkNotNull(src);
447 checkNotNull(dst);
448 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530449 checkNotNull(lspType);
450
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530451 // Convert from DeviceId to TunnelEndPoint
452 Device srcDevice = deviceService.getDevice(src);
453 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530454
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530455 if (srcDevice == null || dstDevice == null) {
456 // Device is not known.
Satish Kba1c9122017-04-05 15:27:23 +0530457 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
458 loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530459 return false;
460 }
461
462 // In future projections instead of annotations will be used to fetch LSR ID.
463 String srcLsrId = srcDevice.annotations().value(LSRID);
464 String dstLsrId = dstDevice.annotations().value(LSRID);
465
466 if (srcLsrId == null || dstLsrId == null) {
467 // LSR id is not known.
Satish Kba1c9122017-04-05 15:27:23 +0530468 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
469 loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530470 return false;
471 }
472
Avantika-Huawei032a9872016-05-27 22:57:38 +0530473 // Get device config from netconfig, to ascertain that session with ingress is present.
474 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
475 if (cfg == null) {
476 log.debug("No session to ingress.");
Satish Kba1c9122017-04-05 15:27:23 +0530477 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
478 loadBalancing));
Avantika-Huawei032a9872016-05-27 22:57:38 +0530479 return false;
480 }
481
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530482 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
483 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
484
485 double bwConstraintValue = 0;
486 CostConstraint costConstraint = null;
487 if (constraints != null) {
488 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
489 Iterator<Constraint> iterator = constraints.iterator();
490
491 while (iterator.hasNext()) {
492 Constraint constraint = iterator.next();
Satish K2eb5d842017-04-04 16:28:37 +0530493 if (constraint instanceof PceBandwidthConstraint) {
494 bwConstraintValue = ((PceBandwidthConstraint) constraint).bandwidth().bps();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530495 } else if (constraint instanceof CostConstraint) {
496 costConstraint = (CostConstraint) constraint;
497 }
498 }
499
500 /*
501 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
502 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
503 * function can either return the result of limiting/capability constraint validation or the value of link
504 * cost, depending upon what is the last constraint in the loop.
505 */
506 if (costConstraint != null) {
507 constraints.remove(costConstraint);
508 constraints.add(costConstraint);
509 }
510 } else {
511 constraints = new LinkedList<>();
512 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
513 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530514 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530515
Satish Kba1c9122017-04-05 15:27:23 +0530516 if (loadBalancing) {
517 return setupDisjointPaths(src, dst, constraints, tunnelName, bwConstraintValue, lspType, costConstraint,
518 srcEndPoint, dstEndPoint);
519 }
520
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530521 if (explicitPathInfo != null && !explicitPathInfo.isEmpty()) {
522 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo, src, dst, constraints);
523 if (finalComputedPath == null) {
524 return false;
525 }
526
527 pceStore.tunnelNameExplicitPathInfoMap(tunnelName, explicitPathInfo);
528 List<Link> links = new LinkedList<>();
529 double totalCost = 0;
530 // Add all partial computed paths
531 for (Path path : finalComputedPath) {
532 links.addAll(path.links());
533 totalCost = totalCost + path.cost();
534 }
535 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(), links, totalCost));
536 } else {
537 computedPathSet = computePath(src, dst, constraints);
538 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530539
540 // NO-PATH
541 if (computedPathSet.isEmpty()) {
Satish Kba1c9122017-04-05 15:27:23 +0530542 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
543 loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530544 return false;
545 }
546
547 Builder annotationBuilder = DefaultAnnotations.builder();
548 if (bwConstraintValue != 0) {
549 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
550 }
551 if (costConstraint != null) {
552 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
553 }
554 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
555 annotationBuilder.set(PCE_INIT, TRUE);
556 annotationBuilder.set(DELEGATE, TRUE);
557
558 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530559
560 if (lspType != WITH_SIGNALLING) {
561 /*
562 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
563 * PCE for non-RSVP signalled LSPs.
564 */
565 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
566 }
567
568 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
569 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
570 TunnelName.tunnelName(tunnelName), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530571 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530572
Satish K2eb5d842017-04-04 16:28:37 +0530573 // Allocate bandwidth for all tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530574 if (bwConstraintValue != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530575 if (!reserveBandwidth(computedPath, bwConstraintValue, null)) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530576 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints,
Satish Kba1c9122017-04-05 15:27:23 +0530577 lspType, explicitPathInfo, loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530578 return false;
579 }
580 }
581
582 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
583 if (tunnelId == null) {
Satish Kba1c9122017-04-05 15:27:23 +0530584 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
585 loadBalancing));
Satish K2eb5d842017-04-04 16:28:37 +0530586
587 if (bwConstraintValue != 0) {
588 computedPath.links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
589 Double.parseDouble(tunnel.annotations().value(BANDWIDTH))));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530590 }
Satish K2eb5d842017-04-04 16:28:37 +0530591
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530592 return false;
593 }
594
Satish K2eb5d842017-04-04 16:28:37 +0530595 if (bwConstraintValue != 0 && lspType == WITH_SIGNALLING) {
596 rsvpTunnelsWithLocalBw.add(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530597 }
Satish K2eb5d842017-04-04 16:28:37 +0530598
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530599 return true;
600 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530601
Satish Kba1c9122017-04-05 15:27:23 +0530602 private boolean setupDisjointPaths(DeviceId src, DeviceId dst, List<Constraint> constraints, String tunnelName,
603 double bwConstraintValue, LspType lspType, CostConstraint costConstraint,
604 TunnelEndPoint srcEndPoint, TunnelEndPoint dstEndPoint) {
605 Set<DisjointPath> paths = pathService.getDisjointPaths(src, dst, weight(constraints));
606
607 // NO-PATH
608 if (paths.isEmpty()) {
609 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
610 return false;
611 }
612
613 DisjointPath path = null;
614 if (!paths.isEmpty()) {
615 path = paths.iterator().next();
616 }
617
618 Builder annotationBuilder = DefaultAnnotations.builder();
619 double bw = 0;
620 if (bwConstraintValue != 0) {
621 //TODO: BW needs to be divided by 2 :: bwConstraintValue/2
622 bw = bwConstraintValue / 2;
623 annotationBuilder.set(BANDWIDTH, String.valueOf(bw));
624 }
625 if (costConstraint != null) {
626 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
627 }
628 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
629 annotationBuilder.set(PCE_INIT, TRUE);
630 annotationBuilder.set(DELEGATE, TRUE);
631 annotationBuilder.set(LOAD_BALANCING_PATH_NAME, tunnelName);
632
633 //Path computedPath = computedPathSet.iterator().next();
634
635 if (lspType != WITH_SIGNALLING) {
636 /*
637 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
638 * PCE for non-RSVP signalled LSPs.
639 */
640 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
641 }
642
643 //Generate different tunnel name for disjoint paths
644 String tunnel1 = (new StringBuilder()).append(tunnelName).append("_1").toString();
645 String tunnel2 = (new StringBuilder()).append(tunnelName).append("_2").toString();
646
647 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
648 Tunnel tunnelPrimary = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
649 TunnelName.tunnelName(tunnel1), path.primary(),
650 annotationBuilder.build());
651
652 Tunnel tunnelBackup = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
653 TunnelName.tunnelName(tunnel2), path.backup(),
654 annotationBuilder.build());
655
656 // Allocate bandwidth.
657 if (bwConstraintValue != 0) {
658 if (!reserveBandwidth(path.primary(), bw, null)) {
659 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel1, constraints,
660 lspType, null, true));
661 return false;
662 }
663
664 if (!reserveBandwidth(path.backup(), bw, null)) {
665 //Release bandwidth resource for tunnel1
666 if (bwConstraintValue != 0) {
667 path.primary().links().forEach(ln ->
668 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
669 Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
670 }
671
672 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel2, constraints,
673 lspType, null, true));
674 return false;
675 }
676 }
677
678 TunnelId tunnelId1 = tunnelService.setupTunnel(appId, src, tunnelPrimary, path.primary());
679 if (tunnelId1 == null) {
680 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
681
682 if (bwConstraintValue != 0) {
683 path.primary().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
684 Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
685 }
686
687 return false;
688 }
689
690 TunnelId tunnelId2 = tunnelService.setupTunnel(appId, src, tunnelBackup, path.backup());
691 if (tunnelId2 == null) {
692 //Release 1st tunnel
rohitsharan483bed42017-04-12 19:04:57 +0530693 releasePath(tunnelId1);
Satish Kba1c9122017-04-05 15:27:23 +0530694
695 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
696
697 if (bwConstraintValue != 0) {
698 path.backup().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
699 Double.parseDouble(tunnelBackup.annotations().value(BANDWIDTH))));
700 }
701
702 return false;
703 }
704
705 pceStore.addLoadBalancingTunnelIdsInfo(tunnelName, tunnelId1, tunnelId2);
706 //pceStore.addDisjointPathInfo(tunnelName, path);
707 return true;
708 }
709
Avantika-Huawei73862d42016-05-12 18:58:06 +0530710 @Override
711 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
712 checkNotNull(tunnelId);
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530713 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530714 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530715
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530716 if (tunnel == null) {
717 return false;
718 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530719
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530720 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
721 // Only delegated LSPs can be updated.
722 return false;
723 }
724
725 List<Link> links = tunnel.path().links();
726 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
727 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530728 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530729 SharedBandwidthConstraint shBwConstraint = null;
Satish K2eb5d842017-04-04 16:28:37 +0530730 PceBandwidthConstraint bwConstraint = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530731 CostConstraint costConstraint = null;
732
733 if (constraints != null) {
734 // Call path computation in shared bandwidth mode.
735 Iterator<Constraint> iterator = constraints.iterator();
736 while (iterator.hasNext()) {
737 Constraint constraint = iterator.next();
Satish K2eb5d842017-04-04 16:28:37 +0530738 if (constraint instanceof PceBandwidthConstraint) {
739 bwConstraint = (PceBandwidthConstraint) constraint;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530740 bwConstraintValue = bwConstraint.bandwidth().bps();
741 } else if (constraint instanceof CostConstraint) {
742 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530743 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530744 }
745 }
746
747 // Remove and keep the cost constraint at the end of the list of constraints.
748 if (costConstraint != null) {
749 constraints.remove(costConstraint);
750 }
751
752 Bandwidth existingBwValue = null;
753 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
754 if (existingBwAnnotation != null) {
755 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
756
757 /*
758 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
759 * has been utilized to create shared bandwidth constraint.
760 */
761 if (bwConstraint != null) {
762 constraints.remove(bwConstraint);
763 }
764 }
765
766 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530767 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530768 bwConstraintValue = existingBwValue.bps();
769 }
770 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
771 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
772 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
773 existingBwValue, existingBwValue);
774
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530775 constraints.add(shBwConstraint);
776 }
777 } else {
778 constraints = new LinkedList<>();
779 }
780
781 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
782 if (costConstraint != null) {
783 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530784 } else {
785 //Take cost constraint from old tunnel if it is not specified in update flow
786 costType = tunnel.annotations().value(COST_TYPE);
787 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
788 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530789 }
790
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530791 List<ExplicitPathInfo> explicitPathInfo = pceStore
792 .getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value());
793 if (explicitPathInfo != null) {
794 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo,
795 tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
796 constraints);
797
798 if (finalComputedPath == null) {
799 return false;
800 }
801
802 List<Link> totalLinks = new LinkedList<>();
803 double totalCost = 0;
804 //Add all partial computed paths
805 for (Path path : finalComputedPath) {
806 totalLinks.addAll(path.links());
807 totalCost = totalCost + path.cost();
808 }
809 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(),
810 totalLinks, totalCost));
811 } else {
812 computedPathSet = computePath(tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
813 constraints);
814 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530815
816 // NO-PATH
817 if (computedPathSet.isEmpty()) {
818 return false;
819 }
820
821 Builder annotationBuilder = DefaultAnnotations.builder();
822 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530823 if (costType != null) {
824 annotationBuilder.set(COST_TYPE, costType);
825 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530826 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
827 annotationBuilder.set(PCE_INIT, TRUE);
828 annotationBuilder.set(DELEGATE, TRUE);
829 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
830 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
831
832 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530833 LspType lspType = LspType.valueOf(lspSigType);
834 long localLspId = 0;
835 if (lspType != WITH_SIGNALLING) {
836 /*
837 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
838 * PCE for non-RSVP signalled LSPs.
839 */
840 localLspId = getNextLocalLspId();
841 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530842 }
843
844 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
845 tunnel.tunnelName(), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530846 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530847
Satish K2eb5d842017-04-04 16:28:37 +0530848 // Allocate shared bandwidth for all tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530849 if (bwConstraintValue != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530850 if (!reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint)) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530851 return false;
852 }
853 }
854
855 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
856 computedPath);
857
858 if (updatedTunnelId == null) {
Satish K2eb5d842017-04-04 16:28:37 +0530859 if (bwConstraintValue != 0) {
860 releaseSharedBwForNewTunnel(computedPath, bwConstraintValue, shBwConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530861 }
862 return false;
863 }
864
Satish K2eb5d842017-04-04 16:28:37 +0530865 if (bwConstraintValue != 0 && lspType == WITH_SIGNALLING) {
866 rsvpTunnelsWithLocalBw.add(updatedTunnelId);
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530867 }
868
Avantika-Huawei73862d42016-05-12 18:58:06 +0530869 return true;
870 }
871
872 @Override
873 public boolean releasePath(TunnelId tunnelId) {
874 checkNotNull(tunnelId);
875 // 1. Query Tunnel from Tunnel manager.
876 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
877
878 if (tunnel == null) {
879 return false;
880 }
881
882 // 2. Call tunnel service.
883 return tunnelService.downTunnel(appId, tunnel.tunnelId());
884 }
885
886 @Override
Satish Kba1c9122017-04-05 15:27:23 +0530887 public boolean releasePath(String loadBalancingPathName) {
888 checkNotNull(loadBalancingPathName);
889
890 List<TunnelId> tunnelIds = pceStore.getLoadBalancingTunnelIds(loadBalancingPathName);
891 if (tunnelIds != null && !tunnelIds.isEmpty()) {
892 for (TunnelId id : tunnelIds) {
893 if (!tunnelService.downTunnel(appId, id)) {
894 return false;
895 }
896 }
897
898 //pceStore.removeDisjointPathInfo(loadBalancedPathName);
899 pceStore.removeLoadBalancingTunnelIdsInfo(loadBalancingPathName);
900 return true;
901 }
902
903 return false;
904 }
905
906 @Override
Avantika-Huawei73862d42016-05-12 18:58:06 +0530907 public Iterable<Tunnel> queryAllPath() {
908 return tunnelService.queryTunnel(MPLS);
909 }
910
911 @Override
912 public Tunnel queryPath(TunnelId tunnelId) {
913 return tunnelService.queryTunnel(tunnelId);
914 }
915
Satish K2eb5d842017-04-04 16:28:37 +0530916 private boolean releaseSharedBwForNewTunnel(Path computedPath, double bandwidthConstraint,
917 SharedBandwidthConstraint shBwConstraint) {
918 checkNotNull(computedPath);
919 checkNotNull(bandwidthConstraint);
920 double bwToAllocate;
921
922 Double additionalBwValue = null;
923 if (shBwConstraint != null) {
924 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
925 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
926 }
927
928 for (Link link : computedPath.links()) {
929 bwToAllocate = 0;
930 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
931 if (additionalBwValue != null) {
932 bwToAllocate = additionalBwValue;
933 }
934 } else {
935 bwToAllocate = bandwidthConstraint;
936 }
937
938 if (bwToAllocate != 0) {
939 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link), bwToAllocate);
940 }
941 }
942 return true;
943 }
944
Avantika-Huawei73862d42016-05-12 18:58:06 +0530945 /**
946 * Returns the next local LSP identifier to be used either by getting from
947 * freed list if available otherwise generating a new one.
948 *
949 * @return value of local LSP identifier
950 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530951 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530952 // If there is any free id use it. Otherwise generate new id.
953 if (localLspIdFreeList.isEmpty()) {
954 return (short) localLspIdIdGen.getNewId();
955 }
956 Iterator<Short> it = localLspIdFreeList.iterator();
957 Short value = it.next();
958 localLspIdFreeList.remove(value);
959 return value;
960 }
961
Priyanka Bb6963582016-05-20 20:21:20 +0530962 protected class TeConstraintBasedLinkWeight implements LinkWeight {
963
964 private final List<Constraint> constraints;
965
966 /**
967 * Creates a new edge-weight function capable of evaluating links
968 * on the basis of the specified constraints.
969 *
970 * @param constraints path constraints
971 */
972 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
973 if (constraints == null) {
974 this.constraints = Collections.emptyList();
975 } else {
976 this.constraints = ImmutableList.copyOf(constraints);
977 }
978 }
979
980 @Override
981 public double weight(TopologyEdge edge) {
982 if (!constraints.iterator().hasNext()) {
983 //Takes default cost/hopcount as 1 if no constraints specified
984 return 1.0;
985 }
986
987 Iterator<Constraint> it = constraints.iterator();
988 double cost = 1;
989
990 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
991 while (it.hasNext() && cost > 0) {
992 Constraint constraint = it.next();
993 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530994 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
995 netCfgService) ? 1 : -1;
Satish K2eb5d842017-04-04 16:28:37 +0530996 } else if (constraint instanceof PceBandwidthConstraint) {
997 cost = ((PceBandwidthConstraint) constraint).isValidLink(edge.link(),
998 bandwidthMgmtService) ? 1 : -1;
999 } else if (constraint instanceof SharedBandwidthConstraint) {
1000 cost = ((SharedBandwidthConstraint) constraint).isValidLink(edge.link(),
1001 bandwidthMgmtService) ? 1 : -1;
1002 } else if (constraint instanceof CostConstraint) {
1003 cost = ((CostConstraint) constraint).isValidLink(edge.link(), netCfgService);
Priyanka Bb6963582016-05-20 20:21:20 +05301004 } else {
Satish K2eb5d842017-04-04 16:28:37 +05301005 cost = constraint.cost(edge.link(), null);
Priyanka Bb6963582016-05-20 20:21:20 +05301006 }
1007 }
1008 return cost;
1009 }
1010 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301011
Priyanka B3f92c5a2016-05-27 10:14:16 +05301012 //TODO: annotations used for temporarily later projection/network config will be used
1013 private class InternalTopologyListener implements TopologyListener {
1014 @Override
1015 public void event(TopologyEvent event) {
1016 event.reasons().forEach(e -> {
1017 //If event type is link removed, get the impacted tunnel
1018 if (e instanceof LinkEvent) {
1019 LinkEvent linkEvent = (LinkEvent) e;
1020 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
1021 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301022 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +05301023 // Check whether this ONOS instance is master for ingress device if yes,
1024 // recompute and send update
1025 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1026 }
1027 });
1028 }
1029 }
1030 });
1031 }
1032 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301033
Priyanka B3f92c5a2016-05-27 10:14:16 +05301034 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
1035 /**
1036 * Master of ingress node will recompute and also delegation flag must be set.
1037 */
1038 if (mastershipService.isLocalMaster(src)
1039 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
1040 LinkedList<Constraint> constraintList = new LinkedList<>();
1041
1042 if (tunnel.annotations().value(BANDWIDTH) != null) {
1043 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
Satish K2eb5d842017-04-04 16:28:37 +05301044 PceBandwidthConstraint localConst = new PceBandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
Priyanka B3f92c5a2016-05-27 10:14:16 +05301045 .annotations().value(BANDWIDTH))));
1046 constraintList.add(localConst);
1047 }
1048 if (tunnel.annotations().value(COST_TYPE) != null) {
1049 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
1050 COST_TYPE))));
1051 }
Priyanka B9fa4ed32016-05-27 11:59:24 +05301052
1053 /*
1054 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
1055 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
1056 */
1057 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +05301058 // If updation fails store in PCE store as failed path
1059 // then PCInitiate (Remove)
1060 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
1061 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301062 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE)),
Satish Kba1c9122017-04-05 15:27:23 +05301063 pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value()),
1064 tunnel.annotations().value(LOAD_BALANCING_PATH_NAME) != null ? true : false));
Priyanka B3f92c5a2016-05-27 10:14:16 +05301065 //Release that tunnel calling PCInitiate
1066 releasePath(tunnel.tunnelId());
1067 }
1068 }
1069
1070 return false;
1071 }
1072
1073 // Allocates the bandwidth locally for PCECC tunnels.
Satish K2eb5d842017-04-04 16:28:37 +05301074 private boolean reserveBandwidth(Path computedPath, double bandwidthConstraint,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301075 SharedBandwidthConstraint shBwConstraint) {
1076 checkNotNull(computedPath);
1077 checkNotNull(bandwidthConstraint);
1078 Resource resource = null;
1079 double bwToAllocate = 0;
Satish K2eb5d842017-04-04 16:28:37 +05301080 Map<Link, Double> linkMap = new HashMap<>();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301081
1082 /**
1083 * Shared bandwidth sub-case : Lesser bandwidth required than original -
1084 * No reservation required.
1085 */
1086 Double additionalBwValue = null;
1087 if (shBwConstraint != null) {
1088 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
1089 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
1090 }
1091
1092 Optional<ResourceAllocation> resAlloc = null;
1093 for (Link link : computedPath.links()) {
1094 bwToAllocate = 0;
1095 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
1096 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +05301097 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301098 }
1099 } else {
1100 bwToAllocate = bandwidthConstraint;
1101 }
1102
1103 /**
1104 * In shared bandwidth cases, where new BW is lesser than old BW, it
1105 * is not required to allocate anything.
1106 */
1107 if (bwToAllocate != 0) {
Satish K2eb5d842017-04-04 16:28:37 +05301108 if (!bandwidthMgmtService.allocLocalReservedBw(LinkKey.linkKey(link.src(), link.dst()),
1109 bwToAllocate)) {
1110 // If allocation for any link fails, then release the partially allocated bandwidth
1111 // for all links allocated
1112 linkMap.forEach((ln, aDouble) -> bandwidthMgmtService
1113 .releaseLocalReservedBw(LinkKey.linkKey(ln), aDouble));
1114 return false;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301115 }
Satish K2eb5d842017-04-04 16:28:37 +05301116
1117 linkMap.put(link, bwToAllocate);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301118 }
1119 }
1120
Satish K2eb5d842017-04-04 16:28:37 +05301121 return true;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301122 }
1123
1124 /*
1125 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
1126 */
1127 private void releaseBandwidth(Tunnel tunnel) {
1128 // Between same source and destination, search the tunnel with same symbolic path name.
1129 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
1130 Tunnel newTunnel = null;
1131 for (Tunnel tunnelObj : tunnelQueryResult) {
1132 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
1133 newTunnel = tunnelObj;
1134 break;
1135 }
1136 }
1137
1138 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
1139 boolean isLinkShared = false;
1140 if (newTunnel != null) {
1141 for (Link link : tunnel.path().links()) {
1142 if (newTunnel.path().links().contains(link)) {
1143 isLinkShared = true;
1144 break;
1145 }
1146 }
1147 }
1148
1149 if (isLinkShared) {
1150 releaseSharedBandwidth(newTunnel, tunnel);
1151 return;
1152 }
1153
Satish K2eb5d842017-04-04 16:28:37 +05301154 tunnel.path().links().forEach(tn -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(tn),
1155 Double.parseDouble(tunnel.annotations().value(BANDWIDTH))));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301156 }
1157
1158 /**
1159 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
1160 * allocated in shared mode initially.
1161 */
1162 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301163
Satish K2eb5d842017-04-04 16:28:37 +05301164 boolean isAllocate = false;
1165 Double oldTunnelBw = Double.parseDouble(oldTunnel.annotations().value(BANDWIDTH));
1166 Double newTunnelBw = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
1167
1168 if (newTunnelBw > oldTunnelBw) {
1169 isAllocate = true;
Priyanka B4c3b4512016-07-22 11:41:49 +05301170 }
1171
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301172 for (Link link : newTunnel.path().links()) {
Satish K2eb5d842017-04-04 16:28:37 +05301173 if (oldTunnel.path().links().contains(link)) {
1174 if (!isAllocate) {
1175 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link),
1176 oldTunnelBw - newTunnelBw);
1177 }
1178 } else {
1179 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link), oldTunnelBw);
1180 }
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301181 }
1182 }
1183
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301184 // Listens on tunnel events.
1185 private class InnerTunnelListener implements TunnelListener {
1186 @Override
1187 public void event(TunnelEvent event) {
1188 // Event gets generated with old tunnel object.
1189 Tunnel tunnel = event.subject();
1190 if (tunnel.type() != MPLS) {
1191 return;
1192 }
1193
1194 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1195 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1196 double bwConstraintValue = 0;
1197 if (tunnelBandwidth != null) {
1198 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1199 }
1200
1201 switch (event.type()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301202 case TUNNEL_UPDATED:
Satish K2eb5d842017-04-04 16:28:37 +05301203 if (rsvpTunnelsWithLocalBw.contains(tunnel.tunnelId())) {
1204 releaseBandwidth(event.subject());
1205 rsvpTunnelsWithLocalBw.remove(tunnel.tunnelId());
1206 }
1207
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301208 if (tunnel.state() == UNSTABLE) {
1209 /*
1210 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1211 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1212 * and setup while global reoptimization.
1213 */
1214
1215 List<Constraint> constraints = new LinkedList<>();
1216 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1217 if (bandwidth != null) {
Satish K2eb5d842017-04-04 16:28:37 +05301218 constraints.add(new PceBandwidthConstraint(Bandwidth
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301219 .bps(Double.parseDouble(bandwidth))));
1220 }
1221
1222 String costType = tunnel.annotations().value(COST_TYPE);
1223 if (costType != null) {
1224 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1225 constraints.add(costConstraint);
1226 }
1227
1228 constraints.add(CapabilityConstraint
1229 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1230
1231 List<Link> links = tunnel.path().links();
1232 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1233 links.get(links.size() - 1).dst().deviceId(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301234 tunnel.tunnelName().value(), constraints, lspType,
1235 pceStore.getTunnelNameExplicitPathInfoMap(tunnel
Satish Kba1c9122017-04-05 15:27:23 +05301236 .tunnelName().value()), tunnel.annotations()
1237 .value(LOAD_BALANCING_PATH_NAME) != null ? true : false));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301238 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301239
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301240 break;
1241
1242 case TUNNEL_REMOVED:
1243 if (lspType != WITH_SIGNALLING) {
1244 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1245 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301246 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Satish K2eb5d842017-04-04 16:28:37 +05301247 if (bwConstraintValue != 0 && mastershipService.getLocalRole(tunnel.path().src()
1248 .deviceId()) == MastershipRole.MASTER) {
1249 if (lspType != WITH_SIGNALLING) {
1250 releaseBandwidth(tunnel);
1251 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301252 }
Priyanka B4c3b4512016-07-22 11:41:49 +05301253
Satish K2eb5d842017-04-04 16:28:37 +05301254 /*if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +05301255 pceStore.removeTunnelInfo(tunnel.tunnelId());
Satish K2eb5d842017-04-04 16:28:37 +05301256 }*/
Priyanka B4c3b4512016-07-22 11:41:49 +05301257
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301258 break;
1259
1260 default:
1261 break;
1262
1263 }
1264 return;
1265 }
1266 }
1267
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301268 @Override
1269 public List<ExplicitPathInfo> explicitPathInfoList(String tunnelName) {
1270 return pceStore.getTunnelNameExplicitPathInfoMap(tunnelName);
1271 }
1272
Satish Kba1c9122017-04-05 15:27:23 +05301273 @Override
1274 public List<TunnelId> queryLoadBalancingPath(String pathName) {
1275 return pceStore.getLoadBalancingTunnelIds(pathName);
1276 }
1277
Priyanka B9fa4ed32016-05-27 11:59:24 +05301278 //Computes path from tunnel store and also path failed to setup.
1279 private void callForOptimization() {
1280 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1281 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1282 checkForMasterAndSetupPath(failedPathInfo);
1283 }
1284
1285 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1286 tunnelService.queryTunnel(MPLS).forEach(t -> {
1287 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1288 });
1289 }
1290
1291 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1292 /**
1293 * Master of ingress node will setup the path failed stored in PCE store.
1294 */
1295 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1296 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301297 failedPathInfo.constraints(), failedPathInfo.lspType(), failedPathInfo.explicitPathInfo())) {
Priyanka B9fa4ed32016-05-27 11:59:24 +05301298 // If computation is success remove that path
1299 pceStore.removeFailedPathInfo(failedPathInfo);
1300 return true;
1301 }
1302 }
1303
1304 return false;
1305 }
1306
1307 //Timer to call global optimization
1308 private class GlobalOptimizationTimer implements Runnable {
1309
1310 public GlobalOptimizationTimer() {
1311 }
1312
1313 @Override
1314 public void run() {
1315 callForOptimization();
1316 }
1317 }
rohitsharan483bed42017-04-12 19:04:57 +05301318}