blob: 3ecdd5bc05142d48a88c085cc8eca317599dfe7f [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
Ray Milkeya7cf8c82018-02-08 15:07:06 -080020import org.onlab.graph.ScalarWeight;
Satish Kba1c9122017-04-05 15:27:23 +053021import org.onosproject.net.DisjointPath;
Satish K2eb5d842017-04-04 16:28:37 +053022import java.util.ArrayList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053023import java.util.Collection;
Priyanka Bb6963582016-05-20 20:21:20 +053024import java.util.Collections;
Satish K2eb5d842017-04-04 16:28:37 +053025import java.util.HashMap;
Avantika-Huawei73862d42016-05-12 18:58:06 +053026import java.util.Iterator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053027import java.util.LinkedList;
Avantika-Huawei73862d42016-05-12 18:58:06 +053028import java.util.List;
Satish K2eb5d842017-04-04 16:28:37 +053029import java.util.Map;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053030import java.util.Optional;
Priyanka Bb6963582016-05-20 20:21:20 +053031import java.util.Set;
Avantika-Huawei73862d42016-05-12 18:58:06 +053032import org.apache.felix.scr.annotations.Activate;
33import org.apache.felix.scr.annotations.Component;
34import org.apache.felix.scr.annotations.Deactivate;
35import org.apache.felix.scr.annotations.Reference;
36import org.apache.felix.scr.annotations.ReferenceCardinality;
37import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053038import org.onlab.packet.IpAddress;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053039import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053040import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
42import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053043import org.onosproject.incubator.net.tunnel.DefaultTunnel;
44import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
Avantika-Huawei73862d42016-05-12 18:58:06 +053045import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053046import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
47import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053048import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053049import org.onosproject.incubator.net.tunnel.TunnelListener;
50import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053051import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053052import org.onosproject.mastership.MastershipService;
Satish K2eb5d842017-04-04 16:28:37 +053053import org.onosproject.net.LinkKey;
54import org.onosproject.net.config.ConfigFactory;
55import org.onosproject.net.config.NetworkConfigRegistry;
Avantika-Huawei032a9872016-05-27 22:57:38 +053056import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053057import org.onosproject.net.DefaultAnnotations;
58import org.onosproject.net.DefaultAnnotations.Builder;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053059import org.onosproject.net.DefaultPath;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053060import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053061import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053062import org.onosproject.net.Link;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053063import org.onosproject.net.NetworkResource;
Priyanka Bb6963582016-05-20 20:21:20 +053064import org.onosproject.net.Path;
Satish K2eb5d842017-04-04 16:28:37 +053065import org.onosproject.net.config.basics.SubjectFactories;
Priyanka Bb6963582016-05-20 20:21:20 +053066import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053067import org.onosproject.net.intent.Constraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +053068import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053069import org.onosproject.net.MastershipRole;
Satish K2eb5d842017-04-04 16:28:37 +053070import org.onosproject.bandwidthmgr.api.BandwidthMgmtService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053071import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
72import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
73import org.onosproject.pce.pceservice.constraint.CostConstraint;
Satish K2eb5d842017-04-04 16:28:37 +053074import org.onosproject.pce.pceservice.constraint.PceBandwidthConstraint;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053075import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
76import org.onosproject.net.resource.Resource;
77import org.onosproject.net.resource.ResourceAllocation;
Priyanka Bb6963582016-05-20 20:21:20 +053078import org.onosproject.net.topology.LinkWeight;
79import org.onosproject.net.topology.PathService;
80import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053081import org.onosproject.net.topology.TopologyEvent;
82import org.onosproject.net.topology.TopologyListener;
83import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053084import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053085import org.onosproject.pce.pcestore.PcePathInfo;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053086import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +053087import org.onosproject.pcep.api.DeviceCapability;
Satish K2eb5d842017-04-04 16:28:37 +053088import org.onosproject.pcep.api.TeLinkConfig;
Avantika-Huawei73862d42016-05-12 18:58:06 +053089import org.onosproject.store.serializers.KryoNamespaces;
90import org.onosproject.store.service.DistributedSet;
91import org.onosproject.store.service.Serializer;
92import org.onosproject.store.service.StorageService;
93import org.slf4j.Logger;
94import org.slf4j.LoggerFactory;
95
Priyanka Bb6963582016-05-20 20:21:20 +053096import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053097import com.google.common.collect.ImmutableSet;
Priyanka Bbae0eeb12016-11-30 11:59:48 +053098import com.google.common.collect.Sets;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053099
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530100import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530101import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
Priyanka B4c3b4512016-07-22 11:41:49 +0530102import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530103import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530104import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
105import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
106import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
107import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
108import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
109import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
110import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
111import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
112
Avantika-Huawei73862d42016-05-12 18:58:06 +0530113/**
114 * Implementation of PCE service.
115 */
116@Component(immediate = true)
117@Service
118public class PceManager implements PceService {
119 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
120
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530121 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
122 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530123 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530124 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530125 public static final String DEVICE_TYPE = "type";
126 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530127
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530128 private static final String LSRID = "lsrId";
129 private static final String TRUE = "true";
130 private static final String FALSE = "false";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530131 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530132
Avantika-Huawei73862d42016-05-12 18:58:06 +0530133 private IdGenerator localLspIdIdGen;
134 protected DistributedSet<Short> localLspIdFreeList;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected CoreService coreService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530140 protected PathService pathService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 protected PceStore pceStore;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530146 protected TunnelService tunnelService;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka Bb6963582016-05-20 20:21:20 +0530149 protected DeviceService deviceService;
150
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530152 protected StorageService storageService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530153
154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530155 protected NetworkConfigService netCfgService;
156
157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka B3f92c5a2016-05-27 10:14:16 +0530158 protected MastershipService mastershipService;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
161 protected TopologyService topologyService;
162
Satish K2eb5d842017-04-04 16:28:37 +0530163 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
164 protected BandwidthMgmtService bandwidthMgmtService;
165
166 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
167 protected NetworkConfigRegistry netConfigRegistry;
168
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530169 private TunnelListener listener = new InnerTunnelListener();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530170 private ApplicationId appId;
171
Priyanka B3f92c5a2016-05-27 10:14:16 +0530172 private final TopologyListener topologyListener = new InternalTopologyListener();
Satish Kba1c9122017-04-05 15:27:23 +0530173 public static final String LOAD_BALANCING_PATH_NAME = "loadBalancingPathName";
Priyanka B9fa4ed32016-05-27 11:59:24 +0530174
Satish K2eb5d842017-04-04 16:28:37 +0530175 private List<TunnelId> rsvpTunnelsWithLocalBw = new ArrayList<>();
176
177 private final ConfigFactory<LinkKey, TeLinkConfig> configFactory =
178 new ConfigFactory<LinkKey, TeLinkConfig>(SubjectFactories.LINK_SUBJECT_FACTORY,
179 TeLinkConfig.class, "teLinkConfig") {
180 @Override
181 public TeLinkConfig createConfig() {
182 return new TeLinkConfig();
183 }
184 };
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530185
Avantika-Huawei73862d42016-05-12 18:58:06 +0530186 /**
187 * Creates new instance of PceManager.
188 */
189 public PceManager() {
190 }
191
192 @Activate
193 protected void activate() {
194 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530195
196 tunnelService.addListener(listener);
197
Avantika-Huawei73862d42016-05-12 18:58:06 +0530198 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530199 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530200 localLspIdFreeList = storageService.<Short>setBuilder()
201 .withName("pcepLocalLspIdDeletedList")
202 .withSerializer(Serializer.using(KryoNamespaces.API))
203 .build()
204 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530205
Priyanka B3f92c5a2016-05-27 10:14:16 +0530206 topologyService.addListener(topologyListener);
Satish K2eb5d842017-04-04 16:28:37 +0530207 netConfigRegistry.registerConfigFactory(configFactory);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530208
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530209 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530210 }
211
212 @Deactivate
213 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530214 tunnelService.removeListener(listener);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530215 topologyService.removeListener(topologyListener);
Satish K2eb5d842017-04-04 16:28:37 +0530216 netConfigRegistry.unregisterConfigFactory(configFactory);
217
Avantika-Huawei73862d42016-05-12 18:58:06 +0530218 log.info("Stopped");
219 }
220
Priyanka Bb6963582016-05-20 20:21:20 +0530221 /**
222 * Returns an edge-weight capable of evaluating links on the basis of the
223 * specified constraints.
224 *
225 * @param constraints path constraints
226 * @return edge-weight function
227 */
228 private LinkWeight weight(List<Constraint> constraints) {
229 return new TeConstraintBasedLinkWeight(constraints);
230 }
231
232 /**
233 * Computes a path between two devices.
234 *
235 * @param src ingress device
236 * @param dst egress device
237 * @param constraints path constraints
238 * @return computed path based on constraints
239 */
240 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
241 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530242 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530243 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530244
Priyanka Bb6963582016-05-20 20:21:20 +0530245 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530246 log.info("paths in computePath ::" + paths);
Priyanka Bb6963582016-05-20 20:21:20 +0530247 if (!paths.isEmpty()) {
248 return paths;
249 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530250 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530251 }
252
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530253 //Computes the partial path from partial computed path to specified dst.
254 private List<Path> computePartialPath(List<Path> computedPath, DeviceId src, DeviceId dst,
255 List<Constraint> constraints) {
256 int size = computedPath.size();
257 Path path = null;
258 DeviceId deviceId = size == 0 ? src :
259 computedPath.get(size - 1).dst().deviceId();
260
261 Set<Path> tempComputePath = computePath(deviceId, dst, constraints);
262
263 if (tempComputePath.isEmpty()) {
264 return null;
265 }
266
267 //if path validation fails return null
268 //Validate computed path to avoid loop in the path
269 for (Path p : tempComputePath) {
270 if (pathValidation(computedPath, p)) {
271 path = p;
272 break;
273 }
274 }
275 if (path == null) {
276 return null;
277 }
278
279 //Store the partial path result in a list
280 computedPath.add(path);
281 return computedPath;
282 }
283
284 private List<DeviceId> createListOfDeviceIds(List<? extends NetworkResource> list) {
285 List<Link> links = new LinkedList<>();
286 if (!list.isEmpty() && list.iterator().next() instanceof Path) {
287 for (Path path : (List<Path>) list) {
288 links.addAll(path.links());
289 }
290 } else if (!list.isEmpty() && list.iterator().next() instanceof Link) {
291 links.addAll((List<Link>) list);
292 }
293
294 //List of devices for new path computed
295 DeviceId source = null;
296 DeviceId destination = null;
297 List<DeviceId> devList = new LinkedList<>();
298
299 for (Link l : links) {
300 if (!devList.contains(l.src().deviceId())) {
301 devList.add(l.src().deviceId());
302 }
303 if (!devList.contains(l.dst().deviceId())) {
304 devList.add(l.dst().deviceId());
305 }
306 }
307
308 return devList;
309 }
310
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700311 //To detect loops in the path i.e if the partial paths has intersection node avoid it.
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530312 private boolean pathValidation(List<Path> partialPath, Path path) {
313
314 //List of devices in new path computed
315 List<DeviceId> newPartialPathDevList;
316 newPartialPathDevList = createListOfDeviceIds(path.links());
317
318 //List of devices in partial computed path
319 List<DeviceId> partialComputedPathDevList;
320 partialComputedPathDevList = createListOfDeviceIds(partialPath);
321
322 for (DeviceId deviceId : newPartialPathDevList) {
323 for (DeviceId devId : partialComputedPathDevList) {
324 if (!newPartialPathDevList.get(0).equals(deviceId) &&
325 !partialComputedPathDevList.get(partialComputedPathDevList.size() - 1).equals(devId)
326 && deviceId.equals(devId)) {
327 return false;
328 }
329 }
330 }
331 return true;
332 }
333
334 //Returns final computed explicit path (list of partial computed paths).
335 private List<Path> computeExplicitPath(List<ExplicitPathInfo> explicitPathInfo, DeviceId src, DeviceId dst,
336 List<Constraint> constraints) {
337 List<Path> finalComputedPath = new LinkedList<>();
338 for (ExplicitPathInfo info : explicitPathInfo) {
339 /*
340 * If explicit path object is LOOSE,
341 * 1) If specified as DeviceId (node) :
342 * If it is source , compute from source to destination (partial computation not required),
343 * otherwise compute from specified source to specified device
344 * 2) If specified as Link :
345 * Compute partial path from source to link's source , if path exists compute from link's source to dst
346 */
347 if (info.type().equals(ExplicitPathInfo.Type.LOOSE)) {
348 if (info.value() instanceof DeviceId) {
349 // If deviceId is source no need to compute
350 if (!(info.value()).equals(src)) {
351 log.debug("computeExplicitPath :: Loose , device");
352 finalComputedPath = computePartialPath(finalComputedPath, src, (DeviceId) info.value(),
353 constraints);
354 log.debug("finalComputedPath in computeExplicitPath ::" + finalComputedPath);
355 }
356
357 } else if (info.value() instanceof Link) {
358 if ((((Link) info.value()).src().deviceId().equals(src))
359 || (!finalComputedPath.isEmpty()
360 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(
361 ((Link) info.value()).src().deviceId()))) {
362
363 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).dst()
364 .deviceId(), constraints);
365 } else {
366
367 finalComputedPath = computePartialPath(finalComputedPath, src, ((Link) info.value()).src()
368 .deviceId(), constraints) != null ? computePartialPath(finalComputedPath, src,
369 ((Link) info.value()).dst().deviceId(), constraints) : null;
370 }
371 }
372 /*
373 * If explicit path object is STRICT,
374 * 1) If specified as DeviceId (node) :
375 * Check whether partial computed path has reachable to strict specified node orde
376 * strict node is the source, if no set path as null else do nothing
377 * 2) If specified as Link :
378 * Check whether partial computed path has reachable to strict link's src, if yes compute
379 * path from strict link's src to link's dst (to include specified link)
380 */
381 } else if (info.type().equals(ExplicitPathInfo.Type.STRICT)) {
382 if (info.value() instanceof DeviceId) {
383 log.debug("computeExplicitPath :: Strict , device");
384 if (!(!finalComputedPath.isEmpty() && finalComputedPath.get(finalComputedPath.size() - 1).dst()
385 .deviceId().equals(info.value()))
386 && !info.value().equals(src)) {
387 finalComputedPath = null;
388 }
389
390 } else if (info.value() instanceof Link) {
391 log.info("computeExplicitPath :: Strict");
392 finalComputedPath = ((Link) info.value()).src().deviceId().equals(src)
393 || !finalComputedPath.isEmpty()
394 && finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId()
395 .equals(((Link) info.value()).src().deviceId()) ? computePartialPath(
396 finalComputedPath, src, ((Link) info.value()).dst().deviceId(), constraints) : null;
397
398 //Log.info("computeExplicitPath :: (Link) info.value() " + (Link) info.value());
399 //Log.info("computeExplicitPath :: finalComputedPath " + finalComputedPath);
400
401 if (finalComputedPath != null && !finalComputedPath.get(finalComputedPath.size() - 1).links()
Yuta HIGUCHI488a94c2018-01-26 17:24:09 -0800402 .contains(info.value())) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530403 finalComputedPath = null;
404 }
405 }
406 }
407 if (finalComputedPath == null) {
408 return null;
409 }
410 }
411 // Destination is not reached in Partial computed path then compute till destination
412 if (finalComputedPath.isEmpty() || !finalComputedPath.isEmpty()
413 && !finalComputedPath.get(finalComputedPath.size() - 1).dst().deviceId().equals(dst)) {
414
415 finalComputedPath = computePartialPath(finalComputedPath, src, dst, constraints);
416 if (finalComputedPath == null) {
417 return null;
418 }
419 }
420
421 return finalComputedPath;
422 }
423
Priyanka Ba32f6da2016-09-02 16:10:21 +0530424 @Override
425 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
Priyankab-Huawei3946d732016-10-11 06:24:38 +0000426 LspType lspType) {
Satish Kba1c9122017-04-05 15:27:23 +0530427 return setupPath(src, dst, tunnelName, constraints, lspType, null, false);
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530428 }
429
430 //[TODO:] handle requests in queue
431 @Override
432 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
433 LspType lspType, List<ExplicitPathInfo> explicitPathInfo) {
Satish Kba1c9122017-04-05 15:27:23 +0530434 return setupPath(src, dst, tunnelName, constraints, lspType, explicitPathInfo, false);
435
436 }
437
438 @Override
439 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
440 LspType lspType, boolean loadBalancing) {
441 return setupPath(src, dst, tunnelName, constraints, lspType, null, loadBalancing);
442 }
443
444 @Override
445 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
446 LspType lspType, List<ExplicitPathInfo> explicitPathInfo, boolean loadBalancing) {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530447 checkNotNull(src);
448 checkNotNull(dst);
449 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530450 checkNotNull(lspType);
451
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530452 // Convert from DeviceId to TunnelEndPoint
453 Device srcDevice = deviceService.getDevice(src);
454 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530455
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530456 if (srcDevice == null || dstDevice == null) {
457 // Device is not known.
Satish Kba1c9122017-04-05 15:27:23 +0530458 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
459 loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530460 return false;
461 }
462
463 // In future projections instead of annotations will be used to fetch LSR ID.
464 String srcLsrId = srcDevice.annotations().value(LSRID);
465 String dstLsrId = dstDevice.annotations().value(LSRID);
466
467 if (srcLsrId == null || dstLsrId == null) {
468 // LSR id is not known.
Satish Kba1c9122017-04-05 15:27:23 +0530469 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
470 loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530471 return false;
472 }
473
Avantika-Huawei032a9872016-05-27 22:57:38 +0530474 // Get device config from netconfig, to ascertain that session with ingress is present.
475 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
476 if (cfg == null) {
477 log.debug("No session to ingress.");
Satish Kba1c9122017-04-05 15:27:23 +0530478 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
479 loadBalancing));
Avantika-Huawei032a9872016-05-27 22:57:38 +0530480 return false;
481 }
482
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530483 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
484 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
485
486 double bwConstraintValue = 0;
487 CostConstraint costConstraint = null;
488 if (constraints != null) {
489 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
490 Iterator<Constraint> iterator = constraints.iterator();
491
492 while (iterator.hasNext()) {
493 Constraint constraint = iterator.next();
Satish K2eb5d842017-04-04 16:28:37 +0530494 if (constraint instanceof PceBandwidthConstraint) {
495 bwConstraintValue = ((PceBandwidthConstraint) constraint).bandwidth().bps();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530496 } else if (constraint instanceof CostConstraint) {
497 costConstraint = (CostConstraint) constraint;
498 }
499 }
500
501 /*
502 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
503 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
504 * function can either return the result of limiting/capability constraint validation or the value of link
505 * cost, depending upon what is the last constraint in the loop.
506 */
507 if (costConstraint != null) {
508 constraints.remove(costConstraint);
509 constraints.add(costConstraint);
510 }
511 } else {
512 constraints = new LinkedList<>();
513 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
514 }
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530515 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530516
Satish Kba1c9122017-04-05 15:27:23 +0530517 if (loadBalancing) {
518 return setupDisjointPaths(src, dst, constraints, tunnelName, bwConstraintValue, lspType, costConstraint,
519 srcEndPoint, dstEndPoint);
520 }
521
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530522 if (explicitPathInfo != null && !explicitPathInfo.isEmpty()) {
523 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo, src, dst, constraints);
524 if (finalComputedPath == null) {
525 return false;
526 }
527
528 pceStore.tunnelNameExplicitPathInfoMap(tunnelName, explicitPathInfo);
529 List<Link> links = new LinkedList<>();
530 double totalCost = 0;
531 // Add all partial computed paths
532 for (Path path : finalComputedPath) {
533 links.addAll(path.links());
534 totalCost = totalCost + path.cost();
535 }
Ray Milkeya7cf8c82018-02-08 15:07:06 -0800536 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(), links,
537 ScalarWeight.toWeight(totalCost)));
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530538 } else {
539 computedPathSet = computePath(src, dst, constraints);
540 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530541
542 // NO-PATH
543 if (computedPathSet.isEmpty()) {
Satish Kba1c9122017-04-05 15:27:23 +0530544 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
545 loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530546 return false;
547 }
548
549 Builder annotationBuilder = DefaultAnnotations.builder();
550 if (bwConstraintValue != 0) {
551 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
552 }
553 if (costConstraint != null) {
554 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
555 }
556 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
557 annotationBuilder.set(PCE_INIT, TRUE);
558 annotationBuilder.set(DELEGATE, TRUE);
559
560 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530561
562 if (lspType != WITH_SIGNALLING) {
563 /*
564 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
565 * PCE for non-RSVP signalled LSPs.
566 */
567 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
568 }
569
570 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
571 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
572 TunnelName.tunnelName(tunnelName), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530573 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530574
Satish K2eb5d842017-04-04 16:28:37 +0530575 // Allocate bandwidth for all tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530576 if (bwConstraintValue != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530577 if (!reserveBandwidth(computedPath, bwConstraintValue, null)) {
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530578 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints,
Satish Kba1c9122017-04-05 15:27:23 +0530579 lspType, explicitPathInfo, loadBalancing));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530580 return false;
581 }
582 }
583
584 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
585 if (tunnelId == null) {
Satish Kba1c9122017-04-05 15:27:23 +0530586 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
587 loadBalancing));
Satish K2eb5d842017-04-04 16:28:37 +0530588
589 if (bwConstraintValue != 0) {
590 computedPath.links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
591 Double.parseDouble(tunnel.annotations().value(BANDWIDTH))));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530592 }
Satish K2eb5d842017-04-04 16:28:37 +0530593
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530594 return false;
595 }
596
Satish K2eb5d842017-04-04 16:28:37 +0530597 if (bwConstraintValue != 0 && lspType == WITH_SIGNALLING) {
598 rsvpTunnelsWithLocalBw.add(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530599 }
Satish K2eb5d842017-04-04 16:28:37 +0530600
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530601 return true;
602 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530603
Satish Kba1c9122017-04-05 15:27:23 +0530604 private boolean setupDisjointPaths(DeviceId src, DeviceId dst, List<Constraint> constraints, String tunnelName,
605 double bwConstraintValue, LspType lspType, CostConstraint costConstraint,
606 TunnelEndPoint srcEndPoint, TunnelEndPoint dstEndPoint) {
607 Set<DisjointPath> paths = pathService.getDisjointPaths(src, dst, weight(constraints));
608
609 // NO-PATH
610 if (paths.isEmpty()) {
611 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
612 return false;
613 }
614
Ray Milkey74e59132018-01-17 15:24:52 -0800615 DisjointPath path = paths.iterator().next();
Satish Kba1c9122017-04-05 15:27:23 +0530616
617 Builder annotationBuilder = DefaultAnnotations.builder();
618 double bw = 0;
619 if (bwConstraintValue != 0) {
620 //TODO: BW needs to be divided by 2 :: bwConstraintValue/2
621 bw = bwConstraintValue / 2;
622 annotationBuilder.set(BANDWIDTH, String.valueOf(bw));
623 }
624 if (costConstraint != null) {
625 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
626 }
627 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
628 annotationBuilder.set(PCE_INIT, TRUE);
629 annotationBuilder.set(DELEGATE, TRUE);
630 annotationBuilder.set(LOAD_BALANCING_PATH_NAME, tunnelName);
631
632 //Path computedPath = computedPathSet.iterator().next();
633
634 if (lspType != WITH_SIGNALLING) {
635 /*
636 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
637 * PCE for non-RSVP signalled LSPs.
638 */
639 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
640 }
641
642 //Generate different tunnel name for disjoint paths
643 String tunnel1 = (new StringBuilder()).append(tunnelName).append("_1").toString();
644 String tunnel2 = (new StringBuilder()).append(tunnelName).append("_2").toString();
645
646 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
647 Tunnel tunnelPrimary = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
648 TunnelName.tunnelName(tunnel1), path.primary(),
649 annotationBuilder.build());
650
651 Tunnel tunnelBackup = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
652 TunnelName.tunnelName(tunnel2), path.backup(),
653 annotationBuilder.build());
654
655 // Allocate bandwidth.
656 if (bwConstraintValue != 0) {
657 if (!reserveBandwidth(path.primary(), bw, null)) {
658 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel1, constraints,
659 lspType, null, true));
660 return false;
661 }
662
663 if (!reserveBandwidth(path.backup(), bw, null)) {
664 //Release bandwidth resource for tunnel1
665 if (bwConstraintValue != 0) {
666 path.primary().links().forEach(ln ->
667 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
668 Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
669 }
670
671 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel2, constraints,
672 lspType, null, true));
673 return false;
674 }
675 }
676
677 TunnelId tunnelId1 = tunnelService.setupTunnel(appId, src, tunnelPrimary, path.primary());
678 if (tunnelId1 == null) {
679 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
680
681 if (bwConstraintValue != 0) {
682 path.primary().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
683 Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
684 }
685
686 return false;
687 }
688
689 TunnelId tunnelId2 = tunnelService.setupTunnel(appId, src, tunnelBackup, path.backup());
690 if (tunnelId2 == null) {
691 //Release 1st tunnel
rohitsharan483bed42017-04-12 19:04:57 +0530692 releasePath(tunnelId1);
Satish Kba1c9122017-04-05 15:27:23 +0530693
694 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
695
696 if (bwConstraintValue != 0) {
697 path.backup().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
698 Double.parseDouble(tunnelBackup.annotations().value(BANDWIDTH))));
699 }
700
701 return false;
702 }
703
704 pceStore.addLoadBalancingTunnelIdsInfo(tunnelName, tunnelId1, tunnelId2);
705 //pceStore.addDisjointPathInfo(tunnelName, path);
706 return true;
707 }
708
Avantika-Huawei73862d42016-05-12 18:58:06 +0530709 @Override
710 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
711 checkNotNull(tunnelId);
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530712 Set<Path> computedPathSet = Sets.newLinkedHashSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530713 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530714
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530715 if (tunnel == null) {
716 return false;
717 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530718
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530719 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
720 // Only delegated LSPs can be updated.
721 return false;
722 }
723
724 List<Link> links = tunnel.path().links();
725 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
726 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530727 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530728 SharedBandwidthConstraint shBwConstraint = null;
Satish K2eb5d842017-04-04 16:28:37 +0530729 PceBandwidthConstraint bwConstraint = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530730 CostConstraint costConstraint = null;
731
732 if (constraints != null) {
733 // Call path computation in shared bandwidth mode.
734 Iterator<Constraint> iterator = constraints.iterator();
735 while (iterator.hasNext()) {
736 Constraint constraint = iterator.next();
Satish K2eb5d842017-04-04 16:28:37 +0530737 if (constraint instanceof PceBandwidthConstraint) {
738 bwConstraint = (PceBandwidthConstraint) constraint;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530739 bwConstraintValue = bwConstraint.bandwidth().bps();
740 } else if (constraint instanceof CostConstraint) {
741 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530742 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530743 }
744 }
745
746 // Remove and keep the cost constraint at the end of the list of constraints.
747 if (costConstraint != null) {
748 constraints.remove(costConstraint);
749 }
750
751 Bandwidth existingBwValue = null;
752 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
753 if (existingBwAnnotation != null) {
754 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
755
756 /*
757 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
758 * has been utilized to create shared bandwidth constraint.
759 */
760 if (bwConstraint != null) {
761 constraints.remove(bwConstraint);
762 }
763 }
764
765 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530766 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530767 bwConstraintValue = existingBwValue.bps();
768 }
769 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
770 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
771 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
772 existingBwValue, existingBwValue);
773
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530774 constraints.add(shBwConstraint);
775 }
776 } else {
777 constraints = new LinkedList<>();
778 }
779
780 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
781 if (costConstraint != null) {
782 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530783 } else {
784 //Take cost constraint from old tunnel if it is not specified in update flow
785 costType = tunnel.annotations().value(COST_TYPE);
786 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
787 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530788 }
789
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530790 List<ExplicitPathInfo> explicitPathInfo = pceStore
791 .getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value());
792 if (explicitPathInfo != null) {
793 List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo,
794 tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
795 constraints);
796
797 if (finalComputedPath == null) {
798 return false;
799 }
800
801 List<Link> totalLinks = new LinkedList<>();
802 double totalCost = 0;
803 //Add all partial computed paths
804 for (Path path : finalComputedPath) {
805 totalLinks.addAll(path.links());
806 totalCost = totalCost + path.cost();
807 }
808 computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(),
Ray Milkeya7cf8c82018-02-08 15:07:06 -0800809 totalLinks, ScalarWeight.toWeight(totalCost)));
Priyanka Bbae0eeb12016-11-30 11:59:48 +0530810 } else {
811 computedPathSet = computePath(tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
812 constraints);
813 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530814
815 // NO-PATH
816 if (computedPathSet.isEmpty()) {
817 return false;
818 }
819
820 Builder annotationBuilder = DefaultAnnotations.builder();
821 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530822 if (costType != null) {
823 annotationBuilder.set(COST_TYPE, costType);
824 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530825 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
826 annotationBuilder.set(PCE_INIT, TRUE);
827 annotationBuilder.set(DELEGATE, TRUE);
828 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
829 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
830
831 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530832 LspType lspType = LspType.valueOf(lspSigType);
833 long localLspId = 0;
834 if (lspType != WITH_SIGNALLING) {
835 /*
836 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
837 * PCE for non-RSVP signalled LSPs.
838 */
839 localLspId = getNextLocalLspId();
840 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530841 }
842
843 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
844 tunnel.tunnelName(), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530845 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530846
Satish K2eb5d842017-04-04 16:28:37 +0530847 // Allocate shared bandwidth for all tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530848 if (bwConstraintValue != 0) {
Satish K2eb5d842017-04-04 16:28:37 +0530849 if (!reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint)) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530850 return false;
851 }
852 }
853
854 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
855 computedPath);
856
857 if (updatedTunnelId == null) {
Satish K2eb5d842017-04-04 16:28:37 +0530858 if (bwConstraintValue != 0) {
859 releaseSharedBwForNewTunnel(computedPath, bwConstraintValue, shBwConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530860 }
861 return false;
862 }
863
Satish K2eb5d842017-04-04 16:28:37 +0530864 if (bwConstraintValue != 0 && lspType == WITH_SIGNALLING) {
865 rsvpTunnelsWithLocalBw.add(updatedTunnelId);
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530866 }
867
Avantika-Huawei73862d42016-05-12 18:58:06 +0530868 return true;
869 }
870
871 @Override
872 public boolean releasePath(TunnelId tunnelId) {
873 checkNotNull(tunnelId);
874 // 1. Query Tunnel from Tunnel manager.
875 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
876
877 if (tunnel == null) {
878 return false;
879 }
880
881 // 2. Call tunnel service.
882 return tunnelService.downTunnel(appId, tunnel.tunnelId());
883 }
884
885 @Override
Satish Kba1c9122017-04-05 15:27:23 +0530886 public boolean releasePath(String loadBalancingPathName) {
887 checkNotNull(loadBalancingPathName);
888
889 List<TunnelId> tunnelIds = pceStore.getLoadBalancingTunnelIds(loadBalancingPathName);
890 if (tunnelIds != null && !tunnelIds.isEmpty()) {
891 for (TunnelId id : tunnelIds) {
892 if (!tunnelService.downTunnel(appId, id)) {
893 return false;
894 }
895 }
896
897 //pceStore.removeDisjointPathInfo(loadBalancedPathName);
898 pceStore.removeLoadBalancingTunnelIdsInfo(loadBalancingPathName);
899 return true;
900 }
901
902 return false;
903 }
904
905 @Override
Avantika-Huawei73862d42016-05-12 18:58:06 +0530906 public Iterable<Tunnel> queryAllPath() {
907 return tunnelService.queryTunnel(MPLS);
908 }
909
910 @Override
911 public Tunnel queryPath(TunnelId tunnelId) {
912 return tunnelService.queryTunnel(tunnelId);
913 }
914
Satish K2eb5d842017-04-04 16:28:37 +0530915 private boolean releaseSharedBwForNewTunnel(Path computedPath, double bandwidthConstraint,
916 SharedBandwidthConstraint shBwConstraint) {
917 checkNotNull(computedPath);
Satish K2eb5d842017-04-04 16:28:37 +0530918 double bwToAllocate;
919
920 Double additionalBwValue = null;
921 if (shBwConstraint != null) {
922 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
923 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
924 }
925
926 for (Link link : computedPath.links()) {
927 bwToAllocate = 0;
928 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
929 if (additionalBwValue != null) {
930 bwToAllocate = additionalBwValue;
931 }
932 } else {
933 bwToAllocate = bandwidthConstraint;
934 }
935
936 if (bwToAllocate != 0) {
937 bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(link), bwToAllocate);
938 }
939 }
940 return true;
941 }
942
Avantika-Huawei73862d42016-05-12 18:58:06 +0530943 /**
944 * Returns the next local LSP identifier to be used either by getting from
945 * freed list if available otherwise generating a new one.
946 *
947 * @return value of local LSP identifier
948 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530949 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530950 // If there is any free id use it. Otherwise generate new id.
951 if (localLspIdFreeList.isEmpty()) {
952 return (short) localLspIdIdGen.getNewId();
953 }
954 Iterator<Short> it = localLspIdFreeList.iterator();
955 Short value = it.next();
956 localLspIdFreeList.remove(value);
957 return value;
958 }
959
Priyanka Bb6963582016-05-20 20:21:20 +0530960 protected class TeConstraintBasedLinkWeight implements LinkWeight {
961
962 private final List<Constraint> constraints;
963
964 /**
965 * Creates a new edge-weight function capable of evaluating links
966 * on the basis of the specified constraints.
967 *
968 * @param constraints path constraints
969 */
970 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
971 if (constraints == null) {
972 this.constraints = Collections.emptyList();
973 } else {
974 this.constraints = ImmutableList.copyOf(constraints);
975 }
976 }
977
978 @Override
979 public double weight(TopologyEdge edge) {
980 if (!constraints.iterator().hasNext()) {
981 //Takes default cost/hopcount as 1 if no constraints specified
982 return 1.0;
983 }
984
985 Iterator<Constraint> it = constraints.iterator();
986 double cost = 1;
987
988 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
989 while (it.hasNext() && cost > 0) {
990 Constraint constraint = it.next();
991 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530992 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
993 netCfgService) ? 1 : -1;
Satish K2eb5d842017-04-04 16:28:37 +0530994 } else if (constraint instanceof PceBandwidthConstraint) {
995 cost = ((PceBandwidthConstraint) constraint).isValidLink(edge.link(),
996 bandwidthMgmtService) ? 1 : -1;
997 } else if (constraint instanceof SharedBandwidthConstraint) {
998 cost = ((SharedBandwidthConstraint) constraint).isValidLink(edge.link(),
999 bandwidthMgmtService) ? 1 : -1;
1000 } else if (constraint instanceof CostConstraint) {
1001 cost = ((CostConstraint) constraint).isValidLink(edge.link(), netCfgService);
Priyanka Bb6963582016-05-20 20:21:20 +05301002 } else {
Satish K2eb5d842017-04-04 16:28:37 +05301003 cost = constraint.cost(edge.link(), null);
Priyanka Bb6963582016-05-20 20:21:20 +05301004 }
1005 }
1006 return cost;
1007 }
1008 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301009
Priyanka B3f92c5a2016-05-27 10:14:16 +05301010 //TODO: annotations used for temporarily later projection/network config will be used
1011 private class InternalTopologyListener implements TopologyListener {
1012 @Override
1013 public void event(TopologyEvent event) {
1014 event.reasons().forEach(e -> {
1015 //If event type is link removed, get the impacted tunnel
1016 if (e instanceof LinkEvent) {
1017 LinkEvent linkEvent = (LinkEvent) e;
1018 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
1019 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301020 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +05301021 // Check whether this ONOS instance is master for ingress device if yes,
1022 // recompute and send update
1023 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1024 }
1025 });
1026 }
1027 }
1028 });
1029 }
1030 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301031
Priyanka B3f92c5a2016-05-27 10:14:16 +05301032 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
1033 /**
1034 * Master of ingress node will recompute and also delegation flag must be set.
1035 */
1036 if (mastershipService.isLocalMaster(src)
1037 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
1038 LinkedList<Constraint> constraintList = new LinkedList<>();
1039
1040 if (tunnel.annotations().value(BANDWIDTH) != null) {
1041 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
Satish K2eb5d842017-04-04 16:28:37 +05301042 PceBandwidthConstraint localConst = new PceBandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
Priyanka B3f92c5a2016-05-27 10:14:16 +05301043 .annotations().value(BANDWIDTH))));
1044 constraintList.add(localConst);
1045 }
1046 if (tunnel.annotations().value(COST_TYPE) != null) {
1047 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
1048 COST_TYPE))));
1049 }
Priyanka B9fa4ed32016-05-27 11:59:24 +05301050
1051 /*
1052 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
1053 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
1054 */
1055 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +05301056 // If updation fails store in PCE store as failed path
1057 // then PCInitiate (Remove)
1058 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
1059 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
Priyanka Bbae0eeb12016-11-30 11:59:48 +05301060 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE)),
Satish Kba1c9122017-04-05 15:27:23 +05301061 pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value()),
1062 tunnel.annotations().value(LOAD_BALANCING_PATH_NAME) != null ? true : false));
Priyanka B3f92c5a2016-05-27 10:14:16 +05301063 //Release that tunnel calling PCInitiate
1064 releasePath(tunnel.tunnelId());
1065 }
1066 }
1067
1068 return false;
1069 }
1070
1071 // Allocates the bandwidth locally for PCECC tunnels.
Satish K2eb5d842017-04-04 16:28:37 +05301072 private boolean reserveBandwidth(Path computedPath, double bandwidthConstraint,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301073 SharedBandwidthConstraint shBwConstraint) {
1074 checkNotNull(computedPath);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301075 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}