blob: 904371d370cab7cfae2353cee898aba53471dcfe [file] [log] [blame]
Avantika-Huawei73862d42016-05-12 18:58:06 +05301/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.pce.pceservice;
17
18import static com.google.common.base.Preconditions.checkNotNull;
Avantika-Huawei73862d42016-05-12 18:58:06 +053019
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053020import java.util.Collection;
Priyanka Bb6963582016-05-20 20:21:20 +053021import java.util.Collections;
Avantika-Huawei73862d42016-05-12 18:58:06 +053022import java.util.Iterator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053023import java.util.LinkedList;
Avantika-Huawei73862d42016-05-12 18:58:06 +053024import java.util.List;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053025import java.util.Map;
26import java.util.Optional;
27import java.util.Map.Entry;
Priyanka Bb6963582016-05-20 20:21:20 +053028import java.util.Set;
Avantika-Huawei73862d42016-05-12 18:58:06 +053029
30import org.apache.felix.scr.annotations.Activate;
31import org.apache.felix.scr.annotations.Component;
32import org.apache.felix.scr.annotations.Deactivate;
33import org.apache.felix.scr.annotations.Reference;
34import org.apache.felix.scr.annotations.ReferenceCardinality;
35import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053036import org.onlab.packet.IpAddress;
37import org.onlab.packet.IpPrefix;
38import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053041import org.onosproject.incubator.net.resource.label.LabelResourceAdminService;
42import org.onosproject.incubator.net.resource.label.LabelResourceId;
43import org.onosproject.incubator.net.resource.label.LabelResourceService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053044import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053045import org.onosproject.incubator.net.tunnel.DefaultTunnel;
46import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
47import org.onosproject.incubator.net.tunnel.LabelStack;
Avantika-Huawei73862d42016-05-12 18:58:06 +053048import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053049import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
50import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053051import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053052import org.onosproject.incubator.net.tunnel.TunnelListener;
53import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053054import org.onosproject.incubator.net.tunnel.TunnelService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053055import org.onosproject.net.DefaultAnnotations;
56import org.onosproject.net.DefaultAnnotations.Builder;
57import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053058import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053059import org.onosproject.net.Link;
Priyanka Bb6963582016-05-20 20:21:20 +053060import org.onosproject.net.Path;
Priyanka Bb6963582016-05-20 20:21:20 +053061import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053062import org.onosproject.net.flowobjective.FlowObjectiveService;
63import org.onosproject.net.flowobjective.Objective;
64import org.onosproject.net.intent.Constraint;
65import org.onosproject.net.intent.constraint.BandwidthConstraint;
66import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
67import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
68import org.onosproject.pce.pceservice.constraint.CostConstraint;
69import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
70import org.onosproject.net.resource.Resource;
71import org.onosproject.net.resource.ResourceAllocation;
72import org.onosproject.net.resource.ResourceConsumer;
73import org.onosproject.net.resource.ResourceQueryService;
Priyanka Bb6963582016-05-20 20:21:20 +053074import org.onosproject.net.resource.ResourceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053075import org.onosproject.net.resource.Resources;
Priyanka Bb6963582016-05-20 20:21:20 +053076import org.onosproject.net.topology.LinkWeight;
77import org.onosproject.net.topology.PathService;
78import org.onosproject.net.topology.TopologyEdge;
Avantika-Huawei73862d42016-05-12 18:58:06 +053079import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053080import org.onosproject.pce.pcestore.PcePathInfo;
81import org.onosproject.pce.pcestore.PceccTunnelInfo;
82import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei73862d42016-05-12 18:58:06 +053083import org.onosproject.store.serializers.KryoNamespaces;
84import org.onosproject.store.service.DistributedSet;
85import org.onosproject.store.service.Serializer;
86import org.onosproject.store.service.StorageService;
87import org.slf4j.Logger;
88import org.slf4j.LoggerFactory;
89
Priyanka Bb6963582016-05-20 20:21:20 +053090import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053091import com.google.common.collect.ImmutableSet;
92
93import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
94import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
95import static org.onosproject.incubator.net.tunnel.Tunnel.State.ESTABLISHED;
96import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
97import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
98import static org.onosproject.pce.pceservice.LspType.SR_WITHOUT_SIGNALLING;
99import static org.onosproject.pce.pceservice.LspType.WITHOUT_SIGNALLING_AND_WITHOUT_SR;
100
101import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
102import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
103import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
104import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
105import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
106import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
107import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
108import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
109
110import org.onosproject.net.packet.InboundPacket;
111import org.onosproject.net.packet.PacketContext;
112import org.onosproject.net.packet.PacketProcessor;
113import org.onosproject.net.packet.PacketService;
Priyanka Bb6963582016-05-20 20:21:20 +0530114
Avantika-Huawei73862d42016-05-12 18:58:06 +0530115/**
116 * Implementation of PCE service.
117 */
118@Component(immediate = true)
119@Service
120public class PceManager implements PceService {
121 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
122
123 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";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530125 private static final int PREFIX_LENGTH = 32;
126
127 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
128 private IdGenerator tunnelConsumerIdGen;
129
130 private static final String LSRID = "lsrId";
131 private static final String TRUE = "true";
132 private static final String FALSE = "false";
133 private static final String END_OF_SYNC_IP_PREFIX = "0.0.0.0/32";
134
Avantika-Huawei73862d42016-05-12 18:58:06 +0530135 private IdGenerator localLspIdIdGen;
136 protected DistributedSet<Short> localLspIdFreeList;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected CoreService coreService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530142 protected ResourceService resourceService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected ResourceQueryService resourceQueryService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected PathService pathService;
149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
151 protected PceStore pceStore;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530154 protected TunnelService tunnelService;
155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
157 protected StorageService storageService;
158
Priyanka Bb6963582016-05-20 20:21:20 +0530159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530160 protected PacketService packetService;
Priyanka Bb6963582016-05-20 20:21:20 +0530161
162 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
163 protected DeviceService deviceService;
164
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530165 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
166 protected LabelResourceAdminService labelRsrcAdminService;
167
168 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
169 protected LabelResourceService labelRsrcService;
170
171 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
172 protected FlowObjectiveService flowObjectiveService;
173
174 private TunnelListener listener = new InnerTunnelListener();
175 private BasicPceccHandler crHandler;
176 private PceccSrTeBeHandler srTeHandler;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530177 private ApplicationId appId;
178
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530179 private final PcepPacketProcessor processor = new PcepPacketProcessor();
180
Avantika-Huawei73862d42016-05-12 18:58:06 +0530181 /**
182 * Creates new instance of PceManager.
183 */
184 public PceManager() {
185 }
186
187 @Activate
188 protected void activate() {
189 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530190 crHandler = BasicPceccHandler.getInstance();
191 crHandler.initialize(labelRsrcService, flowObjectiveService, appId, pceStore);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530192
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530193 srTeHandler = PceccSrTeBeHandler.getInstance();
194 srTeHandler.initialize(labelRsrcAdminService, labelRsrcService, flowObjectiveService, appId, pceStore);
195
196 tunnelService.addListener(listener);
197
198 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530199 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
200 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
206 packetService.addProcessor(processor, PacketProcessor.director(4));
207 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530208 }
209
210 @Deactivate
211 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530212 tunnelService.removeListener(listener);
213 packetService.removeProcessor(processor);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530214 log.info("Stopped");
215 }
216
Priyanka Bb6963582016-05-20 20:21:20 +0530217 /**
218 * Returns an edge-weight capable of evaluating links on the basis of the
219 * specified constraints.
220 *
221 * @param constraints path constraints
222 * @return edge-weight function
223 */
224 private LinkWeight weight(List<Constraint> constraints) {
225 return new TeConstraintBasedLinkWeight(constraints);
226 }
227
228 /**
229 * Computes a path between two devices.
230 *
231 * @param src ingress device
232 * @param dst egress device
233 * @param constraints path constraints
234 * @return computed path based on constraints
235 */
236 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
237 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530238 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530239 }
240 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
241 if (!paths.isEmpty()) {
242 return paths;
243 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530244 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530245 }
246
Avantika-Huawei73862d42016-05-12 18:58:06 +0530247 //[TODO:] handle requests in queue
248 @Override
249 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
250 LspType lspType) {
251 checkNotNull(src);
252 checkNotNull(dst);
253 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530254 checkNotNull(lspType);
255
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530256 // Convert from DeviceId to TunnelEndPoint
257 Device srcDevice = deviceService.getDevice(src);
258 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530259
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530260 if (srcDevice == null || dstDevice == null) {
261 // Device is not known.
262 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
263 return false;
264 }
265
266 // In future projections instead of annotations will be used to fetch LSR ID.
267 String srcLsrId = srcDevice.annotations().value(LSRID);
268 String dstLsrId = dstDevice.annotations().value(LSRID);
269
270 if (srcLsrId == null || dstLsrId == null) {
271 // LSR id is not known.
272 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
273 return false;
274 }
275
276 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
277 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
278
279 double bwConstraintValue = 0;
280 CostConstraint costConstraint = null;
281 if (constraints != null) {
282 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
283 Iterator<Constraint> iterator = constraints.iterator();
284
285 while (iterator.hasNext()) {
286 Constraint constraint = iterator.next();
287 if (constraint instanceof BandwidthConstraint) {
288 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
289 } else if (constraint instanceof CostConstraint) {
290 costConstraint = (CostConstraint) constraint;
291 }
292 }
293
294 /*
295 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
296 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
297 * function can either return the result of limiting/capability constraint validation or the value of link
298 * cost, depending upon what is the last constraint in the loop.
299 */
300 if (costConstraint != null) {
301 constraints.remove(costConstraint);
302 constraints.add(costConstraint);
303 }
304 } else {
305 constraints = new LinkedList<>();
306 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
307 }
308
309 Set<Path> computedPathSet = computePath(src, dst, constraints);
310
311 // NO-PATH
312 if (computedPathSet.isEmpty()) {
313 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
314 return false;
315 }
316
317 Builder annotationBuilder = DefaultAnnotations.builder();
318 if (bwConstraintValue != 0) {
319 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
320 }
321 if (costConstraint != null) {
322 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
323 }
324 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
325 annotationBuilder.set(PCE_INIT, TRUE);
326 annotationBuilder.set(DELEGATE, TRUE);
327
328 Path computedPath = computedPathSet.iterator().next();
329 LabelStack labelStack = null;
330
331 if (lspType == SR_WITHOUT_SIGNALLING) {
332 labelStack = srTeHandler.computeLabelStack(computedPath);
333 // Failed to form a label stack.
334 if (labelStack == null) {
335 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
336 return false;
337 }
338 }
339
340 if (lspType != WITH_SIGNALLING) {
341 /*
342 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
343 * PCE for non-RSVP signalled LSPs.
344 */
345 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
346 }
347
348 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
349 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
350 TunnelName.tunnelName(tunnelName), computedPath,
351 labelStack, annotationBuilder.build());
352
353 // Allocate bandwidth.
354 TunnelConsumerId consumerId = null;
355 if (bwConstraintValue != 0) {
356 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
357 if (consumerId == null) {
358 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
359 return false;
360 }
361 }
362
363 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
364 if (tunnelId == null) {
365 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
366 if (consumerId != null) {
367 resourceService.release(consumerId);
368 }
369 return false;
370 }
371
372 if (consumerId != null) {
373 // Store tunnel consumer id in LSP-Label store.
374 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
375 pceStore.addTunnelInfo(tunnelId, pceccTunnelInfo);
376 }
377 return true;
378 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530379
380 @Override
381 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
382 checkNotNull(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530383 Set<Path> computedPathSet = null;
384 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530385
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530386 if (tunnel == null) {
387 return false;
388 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530389
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530390 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
391 // Only delegated LSPs can be updated.
392 return false;
393 }
394
395 List<Link> links = tunnel.path().links();
396 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
397 double bwConstraintValue = 0;
398 SharedBandwidthConstraint shBwConstraint = null;
399 BandwidthConstraint bwConstraint = null;
400 CostConstraint costConstraint = null;
401
402 if (constraints != null) {
403 // Call path computation in shared bandwidth mode.
404 Iterator<Constraint> iterator = constraints.iterator();
405 while (iterator.hasNext()) {
406 Constraint constraint = iterator.next();
407 if (constraint instanceof BandwidthConstraint) {
408 bwConstraint = (BandwidthConstraint) constraint;
409 bwConstraintValue = bwConstraint.bandwidth().bps();
410 } else if (constraint instanceof CostConstraint) {
411 costConstraint = (CostConstraint) constraint;
412 }
413 }
414
415 // Remove and keep the cost constraint at the end of the list of constraints.
416 if (costConstraint != null) {
417 constraints.remove(costConstraint);
418 }
419
420 Bandwidth existingBwValue = null;
421 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
422 if (existingBwAnnotation != null) {
423 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
424
425 /*
426 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
427 * has been utilized to create shared bandwidth constraint.
428 */
429 if (bwConstraint != null) {
430 constraints.remove(bwConstraint);
431 }
432 }
433
434 if (existingBwValue != null) {
435 shBwConstraint = new SharedBandwidthConstraint(links, existingBwValue, bwConstraint.bandwidth());
436 constraints.add(shBwConstraint);
437 }
438 } else {
439 constraints = new LinkedList<>();
440 }
441
442 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
443 if (costConstraint != null) {
444 constraints.add(costConstraint);
445 }
446
447 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
448 constraints);
449
450 // NO-PATH
451 if (computedPathSet.isEmpty()) {
452 return false;
453 }
454
455 Builder annotationBuilder = DefaultAnnotations.builder();
456 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
457 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
458 annotationBuilder.set(PCE_INIT, TRUE);
459 annotationBuilder.set(DELEGATE, TRUE);
460 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
461 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
462
463 Path computedPath = computedPathSet.iterator().next();
464 LabelStack labelStack = null;
465 TunnelConsumerId consumerId = null;
466 LspType lspType = LspType.valueOf(lspSigType);
467 long localLspId = 0;
468 if (lspType != WITH_SIGNALLING) {
469 /*
470 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
471 * PCE for non-RSVP signalled LSPs.
472 */
473 localLspId = getNextLocalLspId();
474 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
475
476 if (lspType == SR_WITHOUT_SIGNALLING) {
477 labelStack = srTeHandler.computeLabelStack(computedPath);
478 // Failed to form a label stack.
479 if (labelStack == null) {
480 return false;
481 }
482 }
483 }
484
485 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
486 tunnel.tunnelName(), computedPath,
487 labelStack, annotationBuilder.build());
488
489 // Allocate shared bandwidth.
490 if (bwConstraintValue != 0) {
491 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
492 if (consumerId == null) {
493 return false;
494 }
495 }
496
497 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
498 computedPath);
499
500 if (updatedTunnelId == null) {
501 if (consumerId != null) {
502 resourceService.release(consumerId);
503 }
504 return false;
505 }
506
507 if (consumerId != null) {
508 // Store tunnel consumer id in LSP-Label store.
509 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
510 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
511 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530512 return true;
513 }
514
515 @Override
516 public boolean releasePath(TunnelId tunnelId) {
517 checkNotNull(tunnelId);
518 // 1. Query Tunnel from Tunnel manager.
519 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
520
521 if (tunnel == null) {
522 return false;
523 }
524
525 // 2. Call tunnel service.
526 return tunnelService.downTunnel(appId, tunnel.tunnelId());
527 }
528
529 @Override
530 public Iterable<Tunnel> queryAllPath() {
531 return tunnelService.queryTunnel(MPLS);
532 }
533
534 @Override
535 public Tunnel queryPath(TunnelId tunnelId) {
536 return tunnelService.queryTunnel(tunnelId);
537 }
538
539 /**
540 * Returns the next local LSP identifier to be used either by getting from
541 * freed list if available otherwise generating a new one.
542 *
543 * @return value of local LSP identifier
544 */
545 private short getNextLocalLspId() {
546 // If there is any free id use it. Otherwise generate new id.
547 if (localLspIdFreeList.isEmpty()) {
548 return (short) localLspIdIdGen.getNewId();
549 }
550 Iterator<Short> it = localLspIdFreeList.iterator();
551 Short value = it.next();
552 localLspIdFreeList.remove(value);
553 return value;
554 }
555
Priyanka Bb6963582016-05-20 20:21:20 +0530556 protected class TeConstraintBasedLinkWeight implements LinkWeight {
557
558 private final List<Constraint> constraints;
559
560 /**
561 * Creates a new edge-weight function capable of evaluating links
562 * on the basis of the specified constraints.
563 *
564 * @param constraints path constraints
565 */
566 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
567 if (constraints == null) {
568 this.constraints = Collections.emptyList();
569 } else {
570 this.constraints = ImmutableList.copyOf(constraints);
571 }
572 }
573
574 @Override
575 public double weight(TopologyEdge edge) {
576 if (!constraints.iterator().hasNext()) {
577 //Takes default cost/hopcount as 1 if no constraints specified
578 return 1.0;
579 }
580
581 Iterator<Constraint> it = constraints.iterator();
582 double cost = 1;
583
584 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
585 while (it.hasNext() && cost > 0) {
586 Constraint constraint = it.next();
587 if (constraint instanceof CapabilityConstraint) {
588 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService) ? 1 : -1;
589 } else {
590 cost = constraint.cost(edge.link(), resourceService::isAvailable);
591 }
592 }
593 return cost;
594 }
595 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530596
597
598 // Allocates the bandwidth locally for PCECC tunnels.
599 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
600 SharedBandwidthConstraint shBwConstraint) {
601 checkNotNull(computedPath);
602 checkNotNull(bandwidthConstraint);
603 Resource resource = null;
604 double bwToAllocate = 0;
605
606 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
607
608 /**
609 * Shared bandwidth sub-case : Lesser bandwidth required than original -
610 * No reservation required.
611 */
612 Double additionalBwValue = null;
613 if (shBwConstraint != null) {
614 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
615 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
616 }
617
618 Optional<ResourceAllocation> resAlloc = null;
619 for (Link link : computedPath.links()) {
620 bwToAllocate = 0;
621 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
622 if (additionalBwValue != null) {
623 bwToAllocate = bandwidthConstraint - additionalBwValue;
624 }
625 } else {
626 bwToAllocate = bandwidthConstraint;
627 }
628
629 /**
630 * In shared bandwidth cases, where new BW is lesser than old BW, it
631 * is not required to allocate anything.
632 */
633 if (bwToAllocate != 0) {
634 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
635 .resource(bwToAllocate);
636 resAlloc = resourceService.allocate(consumer, resource);
637
638 // If allocation for any link fails, then release the partially allocated bandwidth.
639 if (!resAlloc.isPresent()) {
640 resourceService.release(consumer);
641 return null;
642 }
643 }
644 }
645
646 /*
647 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
648 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
649 * to who is supposed to store/delete.
650 */
651 return consumer;
652 }
653
654 /*
655 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
656 */
657 private void releaseBandwidth(Tunnel tunnel) {
658 // Between same source and destination, search the tunnel with same symbolic path name.
659 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
660 Tunnel newTunnel = null;
661 for (Tunnel tunnelObj : tunnelQueryResult) {
662 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
663 newTunnel = tunnelObj;
664 break;
665 }
666 }
667
668 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
669 boolean isLinkShared = false;
670 if (newTunnel != null) {
671 for (Link link : tunnel.path().links()) {
672 if (newTunnel.path().links().contains(link)) {
673 isLinkShared = true;
674 break;
675 }
676 }
677 }
678
679 if (isLinkShared) {
680 releaseSharedBandwidth(newTunnel, tunnel);
681 return;
682 }
683
684 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
685 return;
686
687 /*
688 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
689 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
690 * to who is supposed to store/delete.
691 */
692 }
693
694 /**
695 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
696 * allocated in shared mode initially.
697 */
698 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
699 // 1. Release old tunnel's bandwidth.
700 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
701
702 // 2. Release new tunnel's bandwidth
703 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
704 resourceService.release(consumer);
705
706 // 3. Allocate new tunnel's complete bandwidth.
707 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
708 Resource resource;
709
710 for (Link link : newTunnel.path().links()) {
711 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
712 .resource(bandwidth);
713 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
714 }
715 }
716
717 // Listens on tunnel events.
718 private class InnerTunnelListener implements TunnelListener {
719 @Override
720 public void event(TunnelEvent event) {
721 // Event gets generated with old tunnel object.
722 Tunnel tunnel = event.subject();
723 if (tunnel.type() != MPLS) {
724 return;
725 }
726
727 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
728 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
729 double bwConstraintValue = 0;
730 if (tunnelBandwidth != null) {
731 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
732 }
733
734 switch (event.type()) {
735 case TUNNEL_ADDED:
736 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
737 String pceInit = tunnel.annotations().value(PCE_INIT);
738 if (FALSE.equalsIgnoreCase(pceInit)
739 && bwConstraintValue != 0) {
740 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
741 }
742 break;
743
744 case TUNNEL_UPDATED:
745 // Allocate/send labels for basic PCECC tunnels.
746 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)) {
747 crHandler.allocateLabel(tunnel);
748 }
749
750 if (tunnel.state() == UNSTABLE) {
751 /*
752 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
753 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
754 * and setup while global reoptimization.
755 */
756
757 List<Constraint> constraints = new LinkedList<>();
758 String bandwidth = tunnel.annotations().value(BANDWIDTH);
759 if (bandwidth != null) {
760 constraints.add(new BandwidthConstraint(Bandwidth
761 .bps(Double.parseDouble(bandwidth))));
762 }
763
764 String costType = tunnel.annotations().value(COST_TYPE);
765 if (costType != null) {
766 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
767 constraints.add(costConstraint);
768 }
769
770 constraints.add(CapabilityConstraint
771 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
772
773 List<Link> links = tunnel.path().links();
774 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
775 links.get(links.size() - 1).dst().deviceId(),
776 tunnel.tunnelName().value(), constraints, lspType));
777 }
778 break;
779
780 case TUNNEL_REMOVED:
781 if (lspType != WITH_SIGNALLING) {
782 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
783 }
784
785 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
786 if (bwConstraintValue != 0) {
787 releaseBandwidth(event.subject());
788
789 // Release basic PCECC labels.
790 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
791 // Delete stored tunnel consumer id from PCE store (while still retaining label list.)
792 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
793 pceccTunnelInfo.tunnelConsumerId(null);
794 crHandler.releaseLabel(tunnel);
795 } else {
796 pceStore.removeTunnelInfo(tunnel.tunnelId());
797 }
798 }
799 break;
800
801 default:
802 break;
803
804 }
805 return;
806 }
807 }
808
809 private boolean syncLabelDb(DeviceId deviceId) {
810 checkNotNull(deviceId);
811 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
812
813 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
814
815 // Convert from DeviceId to TunnelEndPoint
816 Device srcDevice = deviceService.getDevice(entry.getKey());
817
818 /*
819 * If there is a slight difference in timing such that if device subsystem has removed the device but PCE
820 * store still has it, just ignore such devices.
821 */
822 if (srcDevice == null) {
823 continue;
824 }
825
826 String srcLsrId = srcDevice.annotations().value(LSRID);
827 if (srcLsrId == null) {
828 continue;
829 }
830
831 srTeHandler.advertiseNodeLabelRule(deviceId,
832 entry.getValue(),
833 IpPrefix.valueOf(IpAddress.valueOf(srcLsrId), PREFIX_LENGTH),
834 Objective.Operation.ADD, false);
835 }
836
837 Map<Link, LabelResourceId> adjLabelMap = pceStore.getAdjLabels();
838 for (Entry<Link, LabelResourceId> entry : adjLabelMap.entrySet()) {
839 if (entry.getKey().src().deviceId().equals(deviceId)) {
840 srTeHandler.installAdjLabelRule(deviceId,
841 entry.getValue(),
842 entry.getKey().src().port(),
843 entry.getKey().dst().port(),
844 Objective.Operation.ADD);
845 }
846 }
847
848 srTeHandler.advertiseNodeLabelRule(deviceId,
849 LabelResourceId.labelResourceId(0),
850 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
851 Objective.Operation.ADD, true);
852
853 return true;
854 }
855
856 // Process the packet received.
857 private class PcepPacketProcessor implements PacketProcessor {
858 // Process the packet received and in our case initiates the label DB sync.
859 @Override
860 public void process(PacketContext context) {
861 // Stop processing if the packet has been handled, since we
862 // can't do any more to it.
863
864 if (context.isHandled()) {
865 return;
866 }
867
868 InboundPacket pkt = context.inPacket();
869 syncLabelDb(pkt.receivedFrom().deviceId());
870 }
871 }
872
Avantika-Huawei73862d42016-05-12 18:58:06 +0530873}