blob: 11cc18e37a22ba0c9e79ab2b923c1c44e265e242 [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;
Priyanka B3f92c5a2016-05-27 10:14:16 +053055import org.onosproject.mastership.MastershipService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053056import org.onosproject.net.DefaultAnnotations;
57import org.onosproject.net.DefaultAnnotations.Builder;
58import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053059import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053060import org.onosproject.net.Link;
Priyanka Bb6963582016-05-20 20:21:20 +053061import org.onosproject.net.Path;
Priyanka Bb6963582016-05-20 20:21:20 +053062import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053063import org.onosproject.net.flowobjective.FlowObjectiveService;
64import org.onosproject.net.flowobjective.Objective;
65import org.onosproject.net.intent.Constraint;
66import org.onosproject.net.intent.constraint.BandwidthConstraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +053067import org.onosproject.net.link.LinkEvent;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053068import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
69import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
70import org.onosproject.pce.pceservice.constraint.CostConstraint;
71import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
72import org.onosproject.net.resource.Resource;
73import org.onosproject.net.resource.ResourceAllocation;
74import org.onosproject.net.resource.ResourceConsumer;
75import org.onosproject.net.resource.ResourceQueryService;
Priyanka Bb6963582016-05-20 20:21:20 +053076import org.onosproject.net.resource.ResourceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053077import org.onosproject.net.resource.Resources;
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;
86import org.onosproject.pce.pcestore.PceccTunnelInfo;
87import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei73862d42016-05-12 18:58:06 +053088import org.onosproject.store.serializers.KryoNamespaces;
89import org.onosproject.store.service.DistributedSet;
90import org.onosproject.store.service.Serializer;
91import org.onosproject.store.service.StorageService;
92import org.slf4j.Logger;
93import org.slf4j.LoggerFactory;
94
Priyanka Bb6963582016-05-20 20:21:20 +053095import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053096import com.google.common.collect.ImmutableSet;
97
98import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
99import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
100import static org.onosproject.incubator.net.tunnel.Tunnel.State.ESTABLISHED;
101import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
102import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
103import static org.onosproject.pce.pceservice.LspType.SR_WITHOUT_SIGNALLING;
104import static org.onosproject.pce.pceservice.LspType.WITHOUT_SIGNALLING_AND_WITHOUT_SR;
105
106import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
107import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
108import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
109import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
110import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
111import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
112import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
113import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
114
115import org.onosproject.net.packet.InboundPacket;
116import org.onosproject.net.packet.PacketContext;
117import org.onosproject.net.packet.PacketProcessor;
118import org.onosproject.net.packet.PacketService;
Priyanka Bb6963582016-05-20 20:21:20 +0530119
Avantika-Huawei73862d42016-05-12 18:58:06 +0530120/**
121 * Implementation of PCE service.
122 */
123@Component(immediate = true)
124@Service
125public class PceManager implements PceService {
126 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
127
128 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530129 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530130 private static final int PREFIX_LENGTH = 32;
131
132 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
133 private IdGenerator tunnelConsumerIdGen;
134
135 private static final String LSRID = "lsrId";
136 private static final String TRUE = "true";
137 private static final String FALSE = "false";
138 private static final String END_OF_SYNC_IP_PREFIX = "0.0.0.0/32";
139
Avantika-Huawei73862d42016-05-12 18:58:06 +0530140 private IdGenerator localLspIdIdGen;
141 protected DistributedSet<Short> localLspIdFreeList;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected CoreService coreService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530147 protected ResourceService resourceService;
148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 protected ResourceQueryService resourceQueryService;
151
152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected PathService pathService;
154
155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 protected PceStore pceStore;
157
158 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530159 protected TunnelService tunnelService;
160
161 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
162 protected StorageService storageService;
163
Priyanka Bb6963582016-05-20 20:21:20 +0530164 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530165 protected PacketService packetService;
Priyanka Bb6963582016-05-20 20:21:20 +0530166
167 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
168 protected DeviceService deviceService;
169
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530170 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
171 protected LabelResourceAdminService labelRsrcAdminService;
172
173 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
174 protected LabelResourceService labelRsrcService;
175
176 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
177 protected FlowObjectiveService flowObjectiveService;
178
Priyanka B3f92c5a2016-05-27 10:14:16 +0530179 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
180 protected MastershipService mastershipService;
181
182 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
183 protected TopologyService topologyService;
184
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530185 private TunnelListener listener = new InnerTunnelListener();
186 private BasicPceccHandler crHandler;
187 private PceccSrTeBeHandler srTeHandler;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530188 private ApplicationId appId;
189
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530190 private final PcepPacketProcessor processor = new PcepPacketProcessor();
Priyanka B3f92c5a2016-05-27 10:14:16 +0530191 private final TopologyListener topologyListener = new InternalTopologyListener();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530192
Avantika-Huawei73862d42016-05-12 18:58:06 +0530193 /**
194 * Creates new instance of PceManager.
195 */
196 public PceManager() {
197 }
198
199 @Activate
200 protected void activate() {
201 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530202 crHandler = BasicPceccHandler.getInstance();
203 crHandler.initialize(labelRsrcService, flowObjectiveService, appId, pceStore);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530204
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530205 srTeHandler = PceccSrTeBeHandler.getInstance();
206 srTeHandler.initialize(labelRsrcAdminService, labelRsrcService, flowObjectiveService, appId, pceStore);
207
208 tunnelService.addListener(listener);
209
210 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530211 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
212 localLspIdFreeList = storageService.<Short>setBuilder()
213 .withName("pcepLocalLspIdDeletedList")
214 .withSerializer(Serializer.using(KryoNamespaces.API))
215 .build()
216 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530217
218 packetService.addProcessor(processor, PacketProcessor.director(4));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530219 topologyService.addListener(topologyListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530220 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530221 }
222
223 @Deactivate
224 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530225 tunnelService.removeListener(listener);
226 packetService.removeProcessor(processor);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530227 topologyService.removeListener(topologyListener);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530228 log.info("Stopped");
229 }
230
Priyanka Bb6963582016-05-20 20:21:20 +0530231 /**
232 * Returns an edge-weight capable of evaluating links on the basis of the
233 * specified constraints.
234 *
235 * @param constraints path constraints
236 * @return edge-weight function
237 */
238 private LinkWeight weight(List<Constraint> constraints) {
239 return new TeConstraintBasedLinkWeight(constraints);
240 }
241
242 /**
243 * Computes a path between two devices.
244 *
245 * @param src ingress device
246 * @param dst egress device
247 * @param constraints path constraints
248 * @return computed path based on constraints
249 */
250 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
251 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530252 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530253 }
254 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
255 if (!paths.isEmpty()) {
256 return paths;
257 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530258 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530259 }
260
Avantika-Huawei73862d42016-05-12 18:58:06 +0530261 //[TODO:] handle requests in queue
262 @Override
263 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
264 LspType lspType) {
265 checkNotNull(src);
266 checkNotNull(dst);
267 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530268 checkNotNull(lspType);
269
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530270 // Convert from DeviceId to TunnelEndPoint
271 Device srcDevice = deviceService.getDevice(src);
272 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530273
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530274 if (srcDevice == null || dstDevice == null) {
275 // Device is not known.
276 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
277 return false;
278 }
279
280 // In future projections instead of annotations will be used to fetch LSR ID.
281 String srcLsrId = srcDevice.annotations().value(LSRID);
282 String dstLsrId = dstDevice.annotations().value(LSRID);
283
284 if (srcLsrId == null || dstLsrId == null) {
285 // LSR id is not known.
286 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
287 return false;
288 }
289
290 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
291 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
292
293 double bwConstraintValue = 0;
294 CostConstraint costConstraint = null;
295 if (constraints != null) {
296 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
297 Iterator<Constraint> iterator = constraints.iterator();
298
299 while (iterator.hasNext()) {
300 Constraint constraint = iterator.next();
301 if (constraint instanceof BandwidthConstraint) {
302 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
303 } else if (constraint instanceof CostConstraint) {
304 costConstraint = (CostConstraint) constraint;
305 }
306 }
307
308 /*
309 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
310 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
311 * function can either return the result of limiting/capability constraint validation or the value of link
312 * cost, depending upon what is the last constraint in the loop.
313 */
314 if (costConstraint != null) {
315 constraints.remove(costConstraint);
316 constraints.add(costConstraint);
317 }
318 } else {
319 constraints = new LinkedList<>();
320 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
321 }
322
323 Set<Path> computedPathSet = computePath(src, dst, constraints);
324
325 // NO-PATH
326 if (computedPathSet.isEmpty()) {
327 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
328 return false;
329 }
330
331 Builder annotationBuilder = DefaultAnnotations.builder();
332 if (bwConstraintValue != 0) {
333 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
334 }
335 if (costConstraint != null) {
336 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
337 }
338 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
339 annotationBuilder.set(PCE_INIT, TRUE);
340 annotationBuilder.set(DELEGATE, TRUE);
341
342 Path computedPath = computedPathSet.iterator().next();
343 LabelStack labelStack = null;
344
345 if (lspType == SR_WITHOUT_SIGNALLING) {
346 labelStack = srTeHandler.computeLabelStack(computedPath);
347 // Failed to form a label stack.
348 if (labelStack == null) {
349 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
350 return false;
351 }
352 }
353
354 if (lspType != WITH_SIGNALLING) {
355 /*
356 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
357 * PCE for non-RSVP signalled LSPs.
358 */
359 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
360 }
361
362 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
363 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
364 TunnelName.tunnelName(tunnelName), computedPath,
365 labelStack, annotationBuilder.build());
366
367 // Allocate bandwidth.
368 TunnelConsumerId consumerId = null;
369 if (bwConstraintValue != 0) {
370 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
371 if (consumerId == null) {
372 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
373 return false;
374 }
375 }
376
377 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
378 if (tunnelId == null) {
379 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
380 if (consumerId != null) {
381 resourceService.release(consumerId);
382 }
383 return false;
384 }
385
386 if (consumerId != null) {
387 // Store tunnel consumer id in LSP-Label store.
388 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
389 pceStore.addTunnelInfo(tunnelId, pceccTunnelInfo);
390 }
391 return true;
392 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530393
394 @Override
395 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
396 checkNotNull(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530397 Set<Path> computedPathSet = null;
398 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530399
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530400 if (tunnel == null) {
401 return false;
402 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530403
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530404 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
405 // Only delegated LSPs can be updated.
406 return false;
407 }
408
409 List<Link> links = tunnel.path().links();
410 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
411 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530412 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530413 SharedBandwidthConstraint shBwConstraint = null;
414 BandwidthConstraint bwConstraint = null;
415 CostConstraint costConstraint = null;
416
417 if (constraints != null) {
418 // Call path computation in shared bandwidth mode.
419 Iterator<Constraint> iterator = constraints.iterator();
420 while (iterator.hasNext()) {
421 Constraint constraint = iterator.next();
422 if (constraint instanceof BandwidthConstraint) {
423 bwConstraint = (BandwidthConstraint) constraint;
424 bwConstraintValue = bwConstraint.bandwidth().bps();
425 } else if (constraint instanceof CostConstraint) {
426 costConstraint = (CostConstraint) constraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530427 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530428 }
429 }
430
431 // Remove and keep the cost constraint at the end of the list of constraints.
432 if (costConstraint != null) {
433 constraints.remove(costConstraint);
434 }
435
436 Bandwidth existingBwValue = null;
437 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
438 if (existingBwAnnotation != null) {
439 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
440
441 /*
442 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
443 * has been utilized to create shared bandwidth constraint.
444 */
445 if (bwConstraint != null) {
446 constraints.remove(bwConstraint);
447 }
448 }
449
450 if (existingBwValue != null) {
451 shBwConstraint = new SharedBandwidthConstraint(links, existingBwValue, bwConstraint.bandwidth());
452 constraints.add(shBwConstraint);
453 }
454 } else {
455 constraints = new LinkedList<>();
456 }
457
458 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
459 if (costConstraint != null) {
460 constraints.add(costConstraint);
461 }
462
463 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
464 constraints);
465
466 // NO-PATH
467 if (computedPathSet.isEmpty()) {
468 return false;
469 }
470
471 Builder annotationBuilder = DefaultAnnotations.builder();
472 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530473 if (costType != null) {
474 annotationBuilder.set(COST_TYPE, costType);
475 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530476 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
477 annotationBuilder.set(PCE_INIT, TRUE);
478 annotationBuilder.set(DELEGATE, TRUE);
479 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
480 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
481
482 Path computedPath = computedPathSet.iterator().next();
483 LabelStack labelStack = null;
484 TunnelConsumerId consumerId = null;
485 LspType lspType = LspType.valueOf(lspSigType);
486 long localLspId = 0;
487 if (lspType != WITH_SIGNALLING) {
488 /*
489 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
490 * PCE for non-RSVP signalled LSPs.
491 */
492 localLspId = getNextLocalLspId();
493 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
494
495 if (lspType == SR_WITHOUT_SIGNALLING) {
496 labelStack = srTeHandler.computeLabelStack(computedPath);
497 // Failed to form a label stack.
498 if (labelStack == null) {
499 return false;
500 }
501 }
502 }
503
504 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
505 tunnel.tunnelName(), computedPath,
506 labelStack, annotationBuilder.build());
507
508 // Allocate shared bandwidth.
509 if (bwConstraintValue != 0) {
510 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
511 if (consumerId == null) {
512 return false;
513 }
514 }
515
516 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
517 computedPath);
518
519 if (updatedTunnelId == null) {
520 if (consumerId != null) {
521 resourceService.release(consumerId);
522 }
523 return false;
524 }
525
526 if (consumerId != null) {
527 // Store tunnel consumer id in LSP-Label store.
528 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
529 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
530 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530531 return true;
532 }
533
534 @Override
535 public boolean releasePath(TunnelId tunnelId) {
536 checkNotNull(tunnelId);
537 // 1. Query Tunnel from Tunnel manager.
538 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
539
540 if (tunnel == null) {
541 return false;
542 }
543
544 // 2. Call tunnel service.
545 return tunnelService.downTunnel(appId, tunnel.tunnelId());
546 }
547
548 @Override
549 public Iterable<Tunnel> queryAllPath() {
550 return tunnelService.queryTunnel(MPLS);
551 }
552
553 @Override
554 public Tunnel queryPath(TunnelId tunnelId) {
555 return tunnelService.queryTunnel(tunnelId);
556 }
557
558 /**
559 * Returns the next local LSP identifier to be used either by getting from
560 * freed list if available otherwise generating a new one.
561 *
562 * @return value of local LSP identifier
563 */
564 private short getNextLocalLspId() {
565 // If there is any free id use it. Otherwise generate new id.
566 if (localLspIdFreeList.isEmpty()) {
567 return (short) localLspIdIdGen.getNewId();
568 }
569 Iterator<Short> it = localLspIdFreeList.iterator();
570 Short value = it.next();
571 localLspIdFreeList.remove(value);
572 return value;
573 }
574
Priyanka Bb6963582016-05-20 20:21:20 +0530575 protected class TeConstraintBasedLinkWeight implements LinkWeight {
576
577 private final List<Constraint> constraints;
578
579 /**
580 * Creates a new edge-weight function capable of evaluating links
581 * on the basis of the specified constraints.
582 *
583 * @param constraints path constraints
584 */
585 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
586 if (constraints == null) {
587 this.constraints = Collections.emptyList();
588 } else {
589 this.constraints = ImmutableList.copyOf(constraints);
590 }
591 }
592
593 @Override
594 public double weight(TopologyEdge edge) {
595 if (!constraints.iterator().hasNext()) {
596 //Takes default cost/hopcount as 1 if no constraints specified
597 return 1.0;
598 }
599
600 Iterator<Constraint> it = constraints.iterator();
601 double cost = 1;
602
603 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
604 while (it.hasNext() && cost > 0) {
605 Constraint constraint = it.next();
606 if (constraint instanceof CapabilityConstraint) {
607 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService) ? 1 : -1;
608 } else {
609 cost = constraint.cost(edge.link(), resourceService::isAvailable);
610 }
611 }
612 return cost;
613 }
614 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530615
Priyanka B3f92c5a2016-05-27 10:14:16 +0530616 //TODO: annotations used for temporarily later projection/network config will be used
617 private class InternalTopologyListener implements TopologyListener {
618 @Override
619 public void event(TopologyEvent event) {
620 event.reasons().forEach(e -> {
621 //If event type is link removed, get the impacted tunnel
622 if (e instanceof LinkEvent) {
623 LinkEvent linkEvent = (LinkEvent) e;
624 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
625 tunnelService.queryTunnel(MPLS).forEach(t -> {
626 if (t.path().links().contains(((Link) e.subject()))) {
627 // Check whether this ONOS instance is master for ingress device if yes,
628 // recompute and send update
629 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
630 }
631 });
632 }
633 }
634 });
635 }
636 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530637
Priyanka B3f92c5a2016-05-27 10:14:16 +0530638 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
639 /**
640 * Master of ingress node will recompute and also delegation flag must be set.
641 */
642 if (mastershipService.isLocalMaster(src)
643 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
644 LinkedList<Constraint> constraintList = new LinkedList<>();
645
646 if (tunnel.annotations().value(BANDWIDTH) != null) {
647 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
648 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
649 .annotations().value(BANDWIDTH))));
650 constraintList.add(localConst);
651 }
652 if (tunnel.annotations().value(COST_TYPE) != null) {
653 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
654 COST_TYPE))));
655 }
656 if (!updatePath(tunnel.tunnelId(), constraintList)) {
657 // If updation fails store in PCE store as failed path
658 // then PCInitiate (Remove)
659 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
660 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
661 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
662 //Release that tunnel calling PCInitiate
663 releasePath(tunnel.tunnelId());
664 }
665 }
666
667 return false;
668 }
669
670 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530671 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
672 SharedBandwidthConstraint shBwConstraint) {
673 checkNotNull(computedPath);
674 checkNotNull(bandwidthConstraint);
675 Resource resource = null;
676 double bwToAllocate = 0;
677
678 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
679
680 /**
681 * Shared bandwidth sub-case : Lesser bandwidth required than original -
682 * No reservation required.
683 */
684 Double additionalBwValue = null;
685 if (shBwConstraint != null) {
686 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
687 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
688 }
689
690 Optional<ResourceAllocation> resAlloc = null;
691 for (Link link : computedPath.links()) {
692 bwToAllocate = 0;
693 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
694 if (additionalBwValue != null) {
695 bwToAllocate = bandwidthConstraint - additionalBwValue;
696 }
697 } else {
698 bwToAllocate = bandwidthConstraint;
699 }
700
701 /**
702 * In shared bandwidth cases, where new BW is lesser than old BW, it
703 * is not required to allocate anything.
704 */
705 if (bwToAllocate != 0) {
706 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
707 .resource(bwToAllocate);
708 resAlloc = resourceService.allocate(consumer, resource);
709
710 // If allocation for any link fails, then release the partially allocated bandwidth.
711 if (!resAlloc.isPresent()) {
712 resourceService.release(consumer);
713 return null;
714 }
715 }
716 }
717
718 /*
719 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
720 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
721 * to who is supposed to store/delete.
722 */
723 return consumer;
724 }
725
726 /*
727 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
728 */
729 private void releaseBandwidth(Tunnel tunnel) {
730 // Between same source and destination, search the tunnel with same symbolic path name.
731 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
732 Tunnel newTunnel = null;
733 for (Tunnel tunnelObj : tunnelQueryResult) {
734 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
735 newTunnel = tunnelObj;
736 break;
737 }
738 }
739
740 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
741 boolean isLinkShared = false;
742 if (newTunnel != null) {
743 for (Link link : tunnel.path().links()) {
744 if (newTunnel.path().links().contains(link)) {
745 isLinkShared = true;
746 break;
747 }
748 }
749 }
750
751 if (isLinkShared) {
752 releaseSharedBandwidth(newTunnel, tunnel);
753 return;
754 }
755
756 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
757 return;
758
759 /*
760 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
761 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
762 * to who is supposed to store/delete.
763 */
764 }
765
766 /**
767 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
768 * allocated in shared mode initially.
769 */
770 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
771 // 1. Release old tunnel's bandwidth.
772 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
773
774 // 2. Release new tunnel's bandwidth
775 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
776 resourceService.release(consumer);
777
778 // 3. Allocate new tunnel's complete bandwidth.
779 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
780 Resource resource;
781
782 for (Link link : newTunnel.path().links()) {
783 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
784 .resource(bandwidth);
785 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
786 }
787 }
788
789 // Listens on tunnel events.
790 private class InnerTunnelListener implements TunnelListener {
791 @Override
792 public void event(TunnelEvent event) {
793 // Event gets generated with old tunnel object.
794 Tunnel tunnel = event.subject();
795 if (tunnel.type() != MPLS) {
796 return;
797 }
798
799 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
800 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
801 double bwConstraintValue = 0;
802 if (tunnelBandwidth != null) {
803 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
804 }
805
806 switch (event.type()) {
807 case TUNNEL_ADDED:
808 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
809 String pceInit = tunnel.annotations().value(PCE_INIT);
810 if (FALSE.equalsIgnoreCase(pceInit)
811 && bwConstraintValue != 0) {
812 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
813 }
814 break;
815
816 case TUNNEL_UPDATED:
817 // Allocate/send labels for basic PCECC tunnels.
818 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)) {
819 crHandler.allocateLabel(tunnel);
820 }
821
822 if (tunnel.state() == UNSTABLE) {
823 /*
824 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
825 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
826 * and setup while global reoptimization.
827 */
828
829 List<Constraint> constraints = new LinkedList<>();
830 String bandwidth = tunnel.annotations().value(BANDWIDTH);
831 if (bandwidth != null) {
832 constraints.add(new BandwidthConstraint(Bandwidth
833 .bps(Double.parseDouble(bandwidth))));
834 }
835
836 String costType = tunnel.annotations().value(COST_TYPE);
837 if (costType != null) {
838 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
839 constraints.add(costConstraint);
840 }
841
842 constraints.add(CapabilityConstraint
843 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
844
845 List<Link> links = tunnel.path().links();
846 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
847 links.get(links.size() - 1).dst().deviceId(),
848 tunnel.tunnelName().value(), constraints, lspType));
849 }
850 break;
851
852 case TUNNEL_REMOVED:
853 if (lspType != WITH_SIGNALLING) {
854 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
855 }
856
857 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
858 if (bwConstraintValue != 0) {
859 releaseBandwidth(event.subject());
860
861 // Release basic PCECC labels.
862 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
863 // Delete stored tunnel consumer id from PCE store (while still retaining label list.)
864 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
865 pceccTunnelInfo.tunnelConsumerId(null);
866 crHandler.releaseLabel(tunnel);
867 } else {
868 pceStore.removeTunnelInfo(tunnel.tunnelId());
869 }
870 }
871 break;
872
873 default:
874 break;
875
876 }
877 return;
878 }
879 }
880
881 private boolean syncLabelDb(DeviceId deviceId) {
882 checkNotNull(deviceId);
883 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
884
885 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
886
887 // Convert from DeviceId to TunnelEndPoint
888 Device srcDevice = deviceService.getDevice(entry.getKey());
889
890 /*
891 * If there is a slight difference in timing such that if device subsystem has removed the device but PCE
892 * store still has it, just ignore such devices.
893 */
894 if (srcDevice == null) {
895 continue;
896 }
897
898 String srcLsrId = srcDevice.annotations().value(LSRID);
899 if (srcLsrId == null) {
900 continue;
901 }
902
903 srTeHandler.advertiseNodeLabelRule(deviceId,
904 entry.getValue(),
905 IpPrefix.valueOf(IpAddress.valueOf(srcLsrId), PREFIX_LENGTH),
906 Objective.Operation.ADD, false);
907 }
908
909 Map<Link, LabelResourceId> adjLabelMap = pceStore.getAdjLabels();
910 for (Entry<Link, LabelResourceId> entry : adjLabelMap.entrySet()) {
911 if (entry.getKey().src().deviceId().equals(deviceId)) {
912 srTeHandler.installAdjLabelRule(deviceId,
913 entry.getValue(),
914 entry.getKey().src().port(),
915 entry.getKey().dst().port(),
916 Objective.Operation.ADD);
917 }
918 }
919
920 srTeHandler.advertiseNodeLabelRule(deviceId,
921 LabelResourceId.labelResourceId(0),
922 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
923 Objective.Operation.ADD, true);
924
925 return true;
926 }
927
928 // Process the packet received.
929 private class PcepPacketProcessor implements PacketProcessor {
930 // Process the packet received and in our case initiates the label DB sync.
931 @Override
932 public void process(PacketContext context) {
933 // Stop processing if the packet has been handled, since we
934 // can't do any more to it.
935
936 if (context.isHandled()) {
937 return;
938 }
939
940 InboundPacket pkt = context.inPacket();
941 syncLabelDb(pkt.receivedFrom().deviceId());
942 }
943 }
944
Avantika-Huawei73862d42016-05-12 18:58:06 +0530945}