blob: 41d54c2806b1f871e99a3963c48b9726ae50fa8f [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
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700310 //To detect loops in the path i.e if the partial paths has intersection node avoid it.
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530311 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
Ray Milkey74e59132018-01-17 15:24:52 -0800613 DisjointPath path = paths.iterator().next();
Satish Kba1c9122017-04-05 15:27:23 +0530614
615 Builder annotationBuilder = DefaultAnnotations.builder();
616 double bw = 0;
617 if (bwConstraintValue != 0) {
618 //TODO: BW needs to be divided by 2 :: bwConstraintValue/2
619 bw = bwConstraintValue / 2;
620 annotationBuilder.set(BANDWIDTH, String.valueOf(bw));
621 }
622 if (costConstraint != null) {
623 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
624 }
625 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
626 annotationBuilder.set(PCE_INIT, TRUE);
627 annotationBuilder.set(DELEGATE, TRUE);
628 annotationBuilder.set(LOAD_BALANCING_PATH_NAME, tunnelName);
629
630 //Path computedPath = computedPathSet.iterator().next();
631
632 if (lspType != WITH_SIGNALLING) {
633 /*
634 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
635 * PCE for non-RSVP signalled LSPs.
636 */
637 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
638 }
639
640 //Generate different tunnel name for disjoint paths
641 String tunnel1 = (new StringBuilder()).append(tunnelName).append("_1").toString();
642 String tunnel2 = (new StringBuilder()).append(tunnelName).append("_2").toString();
643
644 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
645 Tunnel tunnelPrimary = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
646 TunnelName.tunnelName(tunnel1), path.primary(),
647 annotationBuilder.build());
648
649 Tunnel tunnelBackup = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
650 TunnelName.tunnelName(tunnel2), path.backup(),
651 annotationBuilder.build());
652
653 // Allocate bandwidth.
654 if (bwConstraintValue != 0) {
655 if (!reserveBandwidth(path.primary(), bw, null)) {
656 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel1, constraints,
657 lspType, null, true));
658 return false;
659 }
660
661 if (!reserveBandwidth(path.backup(), bw, null)) {
662 //Release bandwidth resource for tunnel1
663 if (bwConstraintValue != 0) {
664 path.primary().links().forEach(ln ->
665 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
666 Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
667 }
668
669 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel2, constraints,
670 lspType, null, true));
671 return false;
672 }
673 }
674
675 TunnelId tunnelId1 = tunnelService.setupTunnel(appId, src, tunnelPrimary, path.primary());
676 if (tunnelId1 == null) {
677 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
678
679 if (bwConstraintValue != 0) {
680 path.primary().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
681 Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
682 }
683
684 return false;
685 }
686
687 TunnelId tunnelId2 = tunnelService.setupTunnel(appId, src, tunnelBackup, path.backup());
688 if (tunnelId2 == null) {
689 //Release 1st tunnel
rohitsharan483bed42017-04-12 19:04:57 +0530690 releasePath(tunnelId1);
Satish Kba1c9122017-04-05 15:27:23 +0530691
692 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
693
694 if (bwConstraintValue != 0) {
695 path.backup().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
696 Double.parseDouble(tunnelBackup.annotations().value(BANDWIDTH))));
697 }
698
699 return false;
700 }
701
702 pceStore.addLoadBalancingTunnelIdsInfo(tunnelName, tunnelId1, tunnelId2);
703 //pceStore.addDisjointPathInfo(tunnelName, path);
704 return true;
705 }
706
Avantika-Huawei73862d42016-05-12 18:58:06 +0530707 @Override
708 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
709 checkNotNull(tunnelId);
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530710 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530711 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530712
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530713 if (tunnel == null) {
714 return false;
715 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530716
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530717 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
718 // Only delegated LSPs can be updated.
719 return false;
720 }
721
722 List<Link> links = tunnel.path().links();
723 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
724 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530725 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530726 SharedBandwidthConstraint shBwConstraint = null;
Satish K2eb5d842017-04-04 16:28:37 +0530727 PceBandwidthConstraint bwConstraint = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530728 CostConstraint costConstraint = null;
729
730 if (constraints != null) {
731 // Call path computation in shared bandwidth mode.
732 Iterator<Constraint> iterator = constraints.iterator();
733 while (iterator.hasNext()) {
734 Constraint constraint = iterator.next();
Satish K2eb5d842017-04-04 16:28:37 +0530735 if (constraint instanceof PceBandwidthConstraint) {
736 bwConstraint = (PceBandwidthConstraint) constraint;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530737 bwConstraintValue = bwConstraint.bandwidth().bps();
738 } else if (constraint instanceof CostConstraint) {
739 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530740 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530741 }
742 }
743
744 // Remove and keep the cost constraint at the end of the list of constraints.
745 if (costConstraint != null) {
746 constraints.remove(costConstraint);
747 }
748
749 Bandwidth existingBwValue = null;
750 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
751 if (existingBwAnnotation != null) {
752 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
753
754 /*
755 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
756 * has been utilized to create shared bandwidth constraint.
757 */
758 if (bwConstraint != null) {
759 constraints.remove(bwConstraint);
760 }
761 }
762
763 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530764 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530765 bwConstraintValue = existingBwValue.bps();
766 }
767 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
768 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
769 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
770 existingBwValue, existingBwValue);
771
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530772 constraints.add(shBwConstraint);
773 }
774 } else {
775 constraints = new LinkedList<>();
776 }
777
778 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
779 if (costConstraint != null) {
780 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530781 } else {
782 //Take cost constraint from old tunnel if it is not specified in update flow
783 costType = tunnel.annotations().value(COST_TYPE);
784 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
785 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530786 }
787
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530788 List<ExplicitPathInfo> explicitPathInfo = pceStore
789 .getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value());
790 if (explicitPathInfo != null) {
791 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo,
792 tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
793 constraints);
794
795 if (finalComputedPath == null) {
796 return false;
797 }
798
799 List<Link> totalLinks = new LinkedList<>();
800 double totalCost = 0;
801 //Add all partial computed paths
802 for (Path path : finalComputedPath) {
803 totalLinks.addAll(path.links());
804 totalCost = totalCost + path.cost();
805 }
806 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(),
807 totalLinks, totalCost));
808 } else {
809 computedPathSet = computePath(tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
810 constraints);
811 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530812
813 // NO-PATH
814 if (computedPathSet.isEmpty()) {
815 return false;
816 }
817
818 Builder annotationBuilder = DefaultAnnotations.builder();
819 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530820 if (costType != null) {
821 annotationBuilder.set(COST_TYPE, costType);
822 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530823 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
824 annotationBuilder.set(PCE_INIT, TRUE);
825 annotationBuilder.set(DELEGATE, TRUE);
826 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
827 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
828
829 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530830 LspType lspType = LspType.valueOf(lspSigType);
831 long localLspId = 0;
832 if (lspType != WITH_SIGNALLING) {
833 /*
834 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
835 * PCE for non-RSVP signalled LSPs.
836 */
837 localLspId = getNextLocalLspId();
838 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530839 }
840
841 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
842 tunnel.tunnelName(), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530843 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530844
Satish K2eb5d842017-04-04 16:28:37 +0530845 // Allocate shared bandwidth for all tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530846 if (bwConstraintValue != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530847 if (!reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint)) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530848 return false;
849 }
850 }
851
852 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
853 computedPath);
854
855 if (updatedTunnelId == null) {
Satish K2eb5d842017-04-04 16:28:37 +0530856 if (bwConstraintValue != 0) {
857 releaseSharedBwForNewTunnel(computedPath, bwConstraintValue, shBwConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530858 }
859 return false;
860 }
861
Satish K2eb5d842017-04-04 16:28:37 +0530862 if (bwConstraintValue != 0 && lspType == WITH_SIGNALLING) {
863 rsvpTunnelsWithLocalBw.add(updatedTunnelId);
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530864 }
865
Avantika-Huawei73862d42016-05-12 18:58:06 +0530866 return true;
867 }
868
869 @Override
870 public boolean releasePath(TunnelId tunnelId) {
871 checkNotNull(tunnelId);
872 // 1. Query Tunnel from Tunnel manager.
873 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
874
875 if (tunnel == null) {
876 return false;
877 }
878
879 // 2. Call tunnel service.
880 return tunnelService.downTunnel(appId, tunnel.tunnelId());
881 }
882
883 @Override
Satish Kba1c9122017-04-05 15:27:23 +0530884 public boolean releasePath(String loadBalancingPathName) {
885 checkNotNull(loadBalancingPathName);
886
887 List<TunnelId> tunnelIds = pceStore.getLoadBalancingTunnelIds(loadBalancingPathName);
888 if (tunnelIds != null && !tunnelIds.isEmpty()) {
889 for (TunnelId id : tunnelIds) {
890 if (!tunnelService.downTunnel(appId, id)) {
891 return false;
892 }
893 }
894
895 //pceStore.removeDisjointPathInfo(loadBalancedPathName);
896 pceStore.removeLoadBalancingTunnelIdsInfo(loadBalancingPathName);
897 return true;
898 }
899
900 return false;
901 }
902
903 @Override
Avantika-Huawei73862d42016-05-12 18:58:06 +0530904 public Iterable<Tunnel> queryAllPath() {
905 return tunnelService.queryTunnel(MPLS);
906 }
907
908 @Override
909 public Tunnel queryPath(TunnelId tunnelId) {
910 return tunnelService.queryTunnel(tunnelId);
911 }
912
Satish K2eb5d842017-04-04 16:28:37 +0530913 private boolean releaseSharedBwForNewTunnel(Path computedPath, double bandwidthConstraint,
914 SharedBandwidthConstraint shBwConstraint) {
915 checkNotNull(computedPath);
916 checkNotNull(bandwidthConstraint);
917 double bwToAllocate;
918
919 Double additionalBwValue = null;
920 if (shBwConstraint != null) {
921 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
922 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
923 }
924
925 for (Link link : computedPath.links()) {
926 bwToAllocate = 0;
927 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
928 if (additionalBwValue != null) {
929 bwToAllocate = additionalBwValue;
930 }
931 } else {
932 bwToAllocate = bandwidthConstraint;
933 }
934
935 if (bwToAllocate != 0) {
936 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link), bwToAllocate);
937 }
938 }
939 return true;
940 }
941
Avantika-Huawei73862d42016-05-12 18:58:06 +0530942 /**
943 * Returns the next local LSP identifier to be used either by getting from
944 * freed list if available otherwise generating a new one.
945 *
946 * @return value of local LSP identifier
947 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530948 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530949 // If there is any free id use it. Otherwise generate new id.
950 if (localLspIdFreeList.isEmpty()) {
951 return (short) localLspIdIdGen.getNewId();
952 }
953 Iterator<Short> it = localLspIdFreeList.iterator();
954 Short value = it.next();
955 localLspIdFreeList.remove(value);
956 return value;
957 }
958
Priyanka Bb6963582016-05-20 20:21:20 +0530959 protected class TeConstraintBasedLinkWeight implements LinkWeight {
960
961 private final List<Constraint> constraints;
962
963 /**
964 * Creates a new edge-weight function capable of evaluating links
965 * on the basis of the specified constraints.
966 *
967 * @param constraints path constraints
968 */
969 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
970 if (constraints == null) {
971 this.constraints = Collections.emptyList();
972 } else {
973 this.constraints = ImmutableList.copyOf(constraints);
974 }
975 }
976
977 @Override
978 public double weight(TopologyEdge edge) {
979 if (!constraints.iterator().hasNext()) {
980 //Takes default cost/hopcount as 1 if no constraints specified
981 return 1.0;
982 }
983
984 Iterator<Constraint> it = constraints.iterator();
985 double cost = 1;
986
987 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
988 while (it.hasNext() && cost > 0) {
989 Constraint constraint = it.next();
990 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530991 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
992 netCfgService) ? 1 : -1;
Satish K2eb5d842017-04-04 16:28:37 +0530993 } else if (constraint instanceof PceBandwidthConstraint) {
994 cost = ((PceBandwidthConstraint) constraint).isValidLink(edge.link(),
995 bandwidthMgmtService) ? 1 : -1;
996 } else if (constraint instanceof SharedBandwidthConstraint) {
997 cost = ((SharedBandwidthConstraint) constraint).isValidLink(edge.link(),
998 bandwidthMgmtService) ? 1 : -1;
999 } else if (constraint instanceof CostConstraint) {
1000 cost = ((CostConstraint) constraint).isValidLink(edge.link(), netCfgService);
Priyanka Bb6963582016-05-20 20:21:20 +05301001 } else {
Satish K2eb5d842017-04-04 16:28:37 +05301002 cost = constraint.cost(edge.link(), null);
Priyanka Bb6963582016-05-20 20:21:20 +05301003 }
1004 }
1005 return cost;
1006 }
1007 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301008
Priyanka B3f92c5a2016-05-27 10:14:16 +05301009 //TODO: annotations used for temporarily later projection/network config will be used
1010 private class InternalTopologyListener implements TopologyListener {
1011 @Override
1012 public void event(TopologyEvent event) {
1013 event.reasons().forEach(e -> {
1014 //If event type is link removed, get the impacted tunnel
1015 if (e instanceof LinkEvent) {
1016 LinkEvent linkEvent = (LinkEvent) e;
1017 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
1018 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301019 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +05301020 // Check whether this ONOS instance is master for ingress device if yes,
1021 // recompute and send update
1022 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1023 }
1024 });
1025 }
1026 }
1027 });
1028 }
1029 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301030
Priyanka B3f92c5a2016-05-27 10:14:16 +05301031 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
1032 /**
1033 * Master of ingress node will recompute and also delegation flag must be set.
1034 */
1035 if (mastershipService.isLocalMaster(src)
1036 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
1037 LinkedList<Constraint> constraintList = new LinkedList<>();
1038
1039 if (tunnel.annotations().value(BANDWIDTH) != null) {
1040 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
Satish K2eb5d842017-04-04 16:28:37 +05301041 PceBandwidthConstraint localConst = new PceBandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
Priyanka B3f92c5a2016-05-27 10:14:16 +05301042 .annotations().value(BANDWIDTH))));
1043 constraintList.add(localConst);
1044 }
1045 if (tunnel.annotations().value(COST_TYPE) != null) {
1046 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
1047 COST_TYPE))));
1048 }
Priyanka B9fa4ed32016-05-27 11:59:24 +05301049
1050 /*
1051 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
1052 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
1053 */
1054 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +05301055 // If updation fails store in PCE store as failed path
1056 // then PCInitiate (Remove)
1057 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
1058 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301059 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE)),
Satish Kba1c9122017-04-05 15:27:23 +05301060 pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value()),
1061 tunnel.annotations().value(LOAD_BALANCING_PATH_NAME) != null ? true : false));
Priyanka B3f92c5a2016-05-27 10:14:16 +05301062 //Release that tunnel calling PCInitiate
1063 releasePath(tunnel.tunnelId());
1064 }
1065 }
1066
1067 return false;
1068 }
1069
1070 // Allocates the bandwidth locally for PCECC tunnels.
Satish K2eb5d842017-04-04 16:28:37 +05301071 private boolean reserveBandwidth(Path computedPath, double bandwidthConstraint,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301072 SharedBandwidthConstraint shBwConstraint) {
1073 checkNotNull(computedPath);
1074 checkNotNull(bandwidthConstraint);
1075 Resource resource = null;
1076 double bwToAllocate = 0;
Satish K2eb5d842017-04-04 16:28:37 +05301077 Map<Link, Double> linkMap = new HashMap<>();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301078
1079 /**
1080 * Shared bandwidth sub-case : Lesser bandwidth required than original -
1081 * No reservation required.
1082 */
1083 Double additionalBwValue = null;
1084 if (shBwConstraint != null) {
1085 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
1086 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
1087 }
1088
1089 Optional<ResourceAllocation> resAlloc = null;
1090 for (Link link : computedPath.links()) {
1091 bwToAllocate = 0;
1092 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
1093 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +05301094 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301095 }
1096 } else {
1097 bwToAllocate = bandwidthConstraint;
1098 }
1099
1100 /**
1101 * In shared bandwidth cases, where new BW is lesser than old BW, it
1102 * is not required to allocate anything.
1103 */
1104 if (bwToAllocate != 0) {
Satish K2eb5d842017-04-04 16:28:37 +05301105 if (!bandwidthMgmtService.allocLocalReservedBw(LinkKey.linkKey(link.src(), link.dst()),
1106 bwToAllocate)) {
1107 // If allocation for any link fails, then release the partially allocated bandwidth
1108 // for all links allocated
1109 linkMap.forEach((ln, aDouble) -> bandwidthMgmtService
1110 .releaseLocalReservedBw(LinkKey.linkKey(ln), aDouble));
1111 return false;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301112 }
Satish K2eb5d842017-04-04 16:28:37 +05301113
1114 linkMap.put(link, bwToAllocate);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301115 }
1116 }
1117
Satish K2eb5d842017-04-04 16:28:37 +05301118 return true;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301119 }
1120
1121 /*
1122 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
1123 */
1124 private void releaseBandwidth(Tunnel tunnel) {
1125 // Between same source and destination, search the tunnel with same symbolic path name.
1126 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
1127 Tunnel newTunnel = null;
1128 for (Tunnel tunnelObj : tunnelQueryResult) {
1129 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
1130 newTunnel = tunnelObj;
1131 break;
1132 }
1133 }
1134
1135 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
1136 boolean isLinkShared = false;
1137 if (newTunnel != null) {
1138 for (Link link : tunnel.path().links()) {
1139 if (newTunnel.path().links().contains(link)) {
1140 isLinkShared = true;
1141 break;
1142 }
1143 }
1144 }
1145
1146 if (isLinkShared) {
1147 releaseSharedBandwidth(newTunnel, tunnel);
1148 return;
1149 }
1150
Satish K2eb5d842017-04-04 16:28:37 +05301151 tunnel.path().links().forEach(tn -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(tn),
1152 Double.parseDouble(tunnel.annotations().value(BANDWIDTH))));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301153 }
1154
1155 /**
1156 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
1157 * allocated in shared mode initially.
1158 */
1159 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301160
Satish K2eb5d842017-04-04 16:28:37 +05301161 boolean isAllocate = false;
1162 Double oldTunnelBw = Double.parseDouble(oldTunnel.annotations().value(BANDWIDTH));
1163 Double newTunnelBw = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
1164
1165 if (newTunnelBw > oldTunnelBw) {
1166 isAllocate = true;
Priyanka B4c3b4512016-07-22 11:41:49 +05301167 }
1168
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301169 for (Link link : newTunnel.path().links()) {
Satish K2eb5d842017-04-04 16:28:37 +05301170 if (oldTunnel.path().links().contains(link)) {
1171 if (!isAllocate) {
1172 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link),
1173 oldTunnelBw - newTunnelBw);
1174 }
1175 } else {
1176 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link), oldTunnelBw);
1177 }
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301178 }
1179 }
1180
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301181 // Listens on tunnel events.
1182 private class InnerTunnelListener implements TunnelListener {
1183 @Override
1184 public void event(TunnelEvent event) {
1185 // Event gets generated with old tunnel object.
1186 Tunnel tunnel = event.subject();
1187 if (tunnel.type() != MPLS) {
1188 return;
1189 }
1190
1191 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1192 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1193 double bwConstraintValue = 0;
1194 if (tunnelBandwidth != null) {
1195 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1196 }
1197
1198 switch (event.type()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301199 case TUNNEL_UPDATED:
Satish K2eb5d842017-04-04 16:28:37 +05301200 if (rsvpTunnelsWithLocalBw.contains(tunnel.tunnelId())) {
1201 releaseBandwidth(event.subject());
1202 rsvpTunnelsWithLocalBw.remove(tunnel.tunnelId());
1203 }
1204
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301205 if (tunnel.state() == UNSTABLE) {
1206 /*
1207 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1208 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1209 * and setup while global reoptimization.
1210 */
1211
1212 List<Constraint> constraints = new LinkedList<>();
1213 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1214 if (bandwidth != null) {
Satish K2eb5d842017-04-04 16:28:37 +05301215 constraints.add(new PceBandwidthConstraint(Bandwidth
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301216 .bps(Double.parseDouble(bandwidth))));
1217 }
1218
1219 String costType = tunnel.annotations().value(COST_TYPE);
1220 if (costType != null) {
1221 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1222 constraints.add(costConstraint);
1223 }
1224
1225 constraints.add(CapabilityConstraint
1226 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1227
1228 List<Link> links = tunnel.path().links();
1229 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1230 links.get(links.size() - 1).dst().deviceId(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301231 tunnel.tunnelName().value(), constraints, lspType,
1232 pceStore.getTunnelNameExplicitPathInfoMap(tunnel
Satish Kba1c9122017-04-05 15:27:23 +05301233 .tunnelName().value()), tunnel.annotations()
1234 .value(LOAD_BALANCING_PATH_NAME) != null ? true : false));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301235 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301236
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301237 break;
1238
1239 case TUNNEL_REMOVED:
1240 if (lspType != WITH_SIGNALLING) {
1241 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1242 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301243 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Satish K2eb5d842017-04-04 16:28:37 +05301244 if (bwConstraintValue != 0 && mastershipService.getLocalRole(tunnel.path().src()
1245 .deviceId()) == MastershipRole.MASTER) {
1246 if (lspType != WITH_SIGNALLING) {
1247 releaseBandwidth(tunnel);
1248 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301249 }
Priyanka B4c3b4512016-07-22 11:41:49 +05301250
Satish K2eb5d842017-04-04 16:28:37 +05301251 /*if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +05301252 pceStore.removeTunnelInfo(tunnel.tunnelId());
Satish K2eb5d842017-04-04 16:28:37 +05301253 }*/
Priyanka B4c3b4512016-07-22 11:41:49 +05301254
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301255 break;
1256
1257 default:
1258 break;
1259
1260 }
1261 return;
1262 }
1263 }
1264
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301265 @Override
1266 public List<ExplicitPathInfo> explicitPathInfoList(String tunnelName) {
1267 return pceStore.getTunnelNameExplicitPathInfoMap(tunnelName);
1268 }
1269
Satish Kba1c9122017-04-05 15:27:23 +05301270 @Override
1271 public List<TunnelId> queryLoadBalancingPath(String pathName) {
1272 return pceStore.getLoadBalancingTunnelIds(pathName);
1273 }
1274
Priyanka B9fa4ed32016-05-27 11:59:24 +05301275 //Computes path from tunnel store and also path failed to setup.
1276 private void callForOptimization() {
1277 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1278 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1279 checkForMasterAndSetupPath(failedPathInfo);
1280 }
1281
1282 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1283 tunnelService.queryTunnel(MPLS).forEach(t -> {
1284 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1285 });
1286 }
1287
1288 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1289 /**
1290 * Master of ingress node will setup the path failed stored in PCE store.
1291 */
1292 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1293 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301294 failedPathInfo.constraints(), failedPathInfo.lspType(), failedPathInfo.explicitPathInfo())) {
Priyanka B9fa4ed32016-05-27 11:59:24 +05301295 // If computation is success remove that path
1296 pceStore.removeFailedPathInfo(failedPathInfo);
1297 return true;
1298 }
1299 }
1300
1301 return false;
1302 }
1303
1304 //Timer to call global optimization
1305 private class GlobalOptimizationTimer implements Runnable {
1306
1307 public GlobalOptimizationTimer() {
1308 }
1309
1310 @Override
1311 public void run() {
1312 callForOptimization();
1313 }
1314 }
rohitsharan483bed42017-04-12 19:04:57 +05301315}