blob: a4c2aa655f633e764cfb62978364db2ef6156167 [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.Optional;
Priyanka Bb6963582016-05-20 20:21:20 +053026import java.util.Set;
Avantika-Huawei73862d42016-05-12 18:58:06 +053027import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
30import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
32import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053033import org.onlab.packet.IpAddress;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053034import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053038import org.onosproject.incubator.net.tunnel.DefaultTunnel;
39import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
Avantika-Huawei73862d42016-05-12 18:58:06 +053040import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053041import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
42import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053043import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053044import org.onosproject.incubator.net.tunnel.TunnelListener;
45import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053046import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053047import org.onosproject.mastership.MastershipService;
Avantika-Huawei032a9872016-05-27 22:57:38 +053048import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053049import org.onosproject.net.DefaultAnnotations;
50import org.onosproject.net.DefaultAnnotations.Builder;
51import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053052import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053053import org.onosproject.net.Link;
Priyanka Bb6963582016-05-20 20:21:20 +053054import org.onosproject.net.Path;
Priyanka Bb6963582016-05-20 20:21:20 +053055import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053056import org.onosproject.net.intent.Constraint;
57import org.onosproject.net.intent.constraint.BandwidthConstraint;
Priyanka B3f92c5a2016-05-27 10:14:16 +053058import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053059import org.onosproject.net.MastershipRole;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053060import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
61import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
62import org.onosproject.pce.pceservice.constraint.CostConstraint;
63import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
64import org.onosproject.net.resource.Resource;
65import org.onosproject.net.resource.ResourceAllocation;
66import org.onosproject.net.resource.ResourceConsumer;
67import org.onosproject.net.resource.ResourceQueryService;
Priyanka Bb6963582016-05-20 20:21:20 +053068import org.onosproject.net.resource.ResourceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053069import org.onosproject.net.resource.Resources;
Priyanka Bb6963582016-05-20 20:21:20 +053070import org.onosproject.net.topology.LinkWeight;
71import org.onosproject.net.topology.PathService;
72import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053073import org.onosproject.net.topology.TopologyEvent;
74import org.onosproject.net.topology.TopologyListener;
75import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053076import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053077import org.onosproject.pce.pcestore.PcePathInfo;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053078import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +053079import org.onosproject.pcep.api.DeviceCapability;
Avantika-Huawei73862d42016-05-12 18:58:06 +053080import org.onosproject.store.serializers.KryoNamespaces;
81import org.onosproject.store.service.DistributedSet;
82import org.onosproject.store.service.Serializer;
83import org.onosproject.store.service.StorageService;
84import org.slf4j.Logger;
85import org.slf4j.LoggerFactory;
86
Priyanka Bb6963582016-05-20 20:21:20 +053087import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053088import com.google.common.collect.ImmutableSet;
89
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053090import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053091import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
Priyanka B4c3b4512016-07-22 11:41:49 +053092import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053093import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053094import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
95import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
96import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
97import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
98import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
99import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
100import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
101import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
102
Avantika-Huawei73862d42016-05-12 18:58:06 +0530103/**
104 * Implementation of PCE service.
105 */
106@Component(immediate = true)
107@Service
108public class PceManager implements PceService {
109 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
110
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530111 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
112 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530113 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530114 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530115 public static final String DEVICE_TYPE = "type";
116 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530117
118 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
119 private IdGenerator tunnelConsumerIdGen;
120
121 private static final String LSRID = "lsrId";
122 private static final String TRUE = "true";
123 private static final String FALSE = "false";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530124 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530125
Avantika-Huawei73862d42016-05-12 18:58:06 +0530126 private IdGenerator localLspIdIdGen;
127 protected DistributedSet<Short> localLspIdFreeList;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected CoreService coreService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530133 protected ResourceService resourceService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected ResourceQueryService resourceQueryService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected PathService pathService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected PceStore pceStore;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530145 protected TunnelService tunnelService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka Bb6963582016-05-20 20:21:20 +0530148 protected DeviceService deviceService;
149
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530151 protected StorageService storageService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530154 protected NetworkConfigService netCfgService;
155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Priyanka B3f92c5a2016-05-27 10:14:16 +0530157 protected MastershipService mastershipService;
158
159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
160 protected TopologyService topologyService;
161
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530162 private TunnelListener listener = new InnerTunnelListener();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530163 private ApplicationId appId;
164
Priyanka B3f92c5a2016-05-27 10:14:16 +0530165 private final TopologyListener topologyListener = new InternalTopologyListener();
Priyanka B9fa4ed32016-05-27 11:59:24 +0530166
167 public static final int INITIAL_DELAY = 30;
168 public static final int PERIODIC_DELAY = 30;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530169
Avantika-Huawei73862d42016-05-12 18:58:06 +0530170 /**
171 * Creates new instance of PceManager.
172 */
173 public PceManager() {
174 }
175
176 @Activate
177 protected void activate() {
178 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530179
180 tunnelService.addListener(listener);
181
182 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530183 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530184 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530185 localLspIdFreeList = storageService.<Short>setBuilder()
186 .withName("pcepLocalLspIdDeletedList")
187 .withSerializer(Serializer.using(KryoNamespaces.API))
188 .build()
189 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530190
Priyanka B3f92c5a2016-05-27 10:14:16 +0530191 topologyService.addListener(topologyListener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530192
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530193 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530194 }
195
196 @Deactivate
197 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530198 tunnelService.removeListener(listener);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530199 topologyService.removeListener(topologyListener);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530200 log.info("Stopped");
201 }
202
Priyanka Bb6963582016-05-20 20:21:20 +0530203 /**
204 * Returns an edge-weight capable of evaluating links on the basis of the
205 * specified constraints.
206 *
207 * @param constraints path constraints
208 * @return edge-weight function
209 */
210 private LinkWeight weight(List<Constraint> constraints) {
211 return new TeConstraintBasedLinkWeight(constraints);
212 }
213
214 /**
215 * Computes a path between two devices.
216 *
217 * @param src ingress device
218 * @param dst egress device
219 * @param constraints path constraints
220 * @return computed path based on constraints
221 */
222 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
223 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530224 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530225 }
226 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
227 if (!paths.isEmpty()) {
228 return paths;
229 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530230 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530231 }
232
Avantika-Huawei73862d42016-05-12 18:58:06 +0530233 //[TODO:] handle requests in queue
234 @Override
235 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
236 LspType lspType) {
237 checkNotNull(src);
238 checkNotNull(dst);
239 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530240 checkNotNull(lspType);
241
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530242 // Convert from DeviceId to TunnelEndPoint
243 Device srcDevice = deviceService.getDevice(src);
244 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530245
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530246 if (srcDevice == null || dstDevice == null) {
247 // Device is not known.
248 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
249 return false;
250 }
251
252 // In future projections instead of annotations will be used to fetch LSR ID.
253 String srcLsrId = srcDevice.annotations().value(LSRID);
254 String dstLsrId = dstDevice.annotations().value(LSRID);
255
256 if (srcLsrId == null || dstLsrId == null) {
257 // LSR id is not known.
258 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
259 return false;
260 }
261
Avantika-Huawei032a9872016-05-27 22:57:38 +0530262 // Get device config from netconfig, to ascertain that session with ingress is present.
263 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
264 if (cfg == null) {
265 log.debug("No session to ingress.");
266 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
267 return false;
268 }
269
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530270 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
271 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
272
273 double bwConstraintValue = 0;
274 CostConstraint costConstraint = null;
275 if (constraints != null) {
276 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
277 Iterator<Constraint> iterator = constraints.iterator();
278
279 while (iterator.hasNext()) {
280 Constraint constraint = iterator.next();
281 if (constraint instanceof BandwidthConstraint) {
282 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
283 } else if (constraint instanceof CostConstraint) {
284 costConstraint = (CostConstraint) constraint;
285 }
286 }
287
288 /*
289 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
290 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
291 * function can either return the result of limiting/capability constraint validation or the value of link
292 * cost, depending upon what is the last constraint in the loop.
293 */
294 if (costConstraint != null) {
295 constraints.remove(costConstraint);
296 constraints.add(costConstraint);
297 }
298 } else {
299 constraints = new LinkedList<>();
300 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
301 }
302
303 Set<Path> computedPathSet = computePath(src, dst, constraints);
304
305 // NO-PATH
306 if (computedPathSet.isEmpty()) {
307 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
308 return false;
309 }
310
311 Builder annotationBuilder = DefaultAnnotations.builder();
312 if (bwConstraintValue != 0) {
313 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
314 }
315 if (costConstraint != null) {
316 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
317 }
318 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
319 annotationBuilder.set(PCE_INIT, TRUE);
320 annotationBuilder.set(DELEGATE, TRUE);
321
322 Path computedPath = computedPathSet.iterator().next();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530323
324 if (lspType != WITH_SIGNALLING) {
325 /*
326 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
327 * PCE for non-RSVP signalled LSPs.
328 */
329 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
330 }
331
332 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
333 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
334 TunnelName.tunnelName(tunnelName), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530335 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530336
337 // Allocate bandwidth.
338 TunnelConsumerId consumerId = null;
339 if (bwConstraintValue != 0) {
340 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
341 if (consumerId == null) {
342 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
343 return false;
344 }
345 }
346
347 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
348 if (tunnelId == null) {
349 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
350 if (consumerId != null) {
351 resourceService.release(consumerId);
352 }
353 return false;
354 }
355
356 if (consumerId != null) {
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530357 // Store tunnel consumer id in LSP store.
358 pceStore.addTunnelInfo(tunnelId, consumerId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530359 }
360 return true;
361 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530362
363 @Override
364 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
365 checkNotNull(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530366 Set<Path> computedPathSet = null;
367 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530368
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530369 if (tunnel == null) {
370 return false;
371 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530372
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530373 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
374 // Only delegated LSPs can be updated.
375 return false;
376 }
377
378 List<Link> links = tunnel.path().links();
379 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
380 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530381 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530382 SharedBandwidthConstraint shBwConstraint = null;
383 BandwidthConstraint bwConstraint = null;
384 CostConstraint costConstraint = null;
385
386 if (constraints != null) {
387 // Call path computation in shared bandwidth mode.
388 Iterator<Constraint> iterator = constraints.iterator();
389 while (iterator.hasNext()) {
390 Constraint constraint = iterator.next();
391 if (constraint instanceof BandwidthConstraint) {
392 bwConstraint = (BandwidthConstraint) constraint;
393 bwConstraintValue = bwConstraint.bandwidth().bps();
394 } else if (constraint instanceof CostConstraint) {
395 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530396 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530397 }
398 }
399
400 // Remove and keep the cost constraint at the end of the list of constraints.
401 if (costConstraint != null) {
402 constraints.remove(costConstraint);
403 }
404
405 Bandwidth existingBwValue = null;
406 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
407 if (existingBwAnnotation != null) {
408 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
409
410 /*
411 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
412 * has been utilized to create shared bandwidth constraint.
413 */
414 if (bwConstraint != null) {
415 constraints.remove(bwConstraint);
416 }
417 }
418
419 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530420 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530421 bwConstraintValue = existingBwValue.bps();
422 }
423 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
424 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
425 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
426 existingBwValue, existingBwValue);
427
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530428 constraints.add(shBwConstraint);
429 }
430 } else {
431 constraints = new LinkedList<>();
432 }
433
434 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
435 if (costConstraint != null) {
436 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530437 } else {
438 //Take cost constraint from old tunnel if it is not specified in update flow
439 costType = tunnel.annotations().value(COST_TYPE);
440 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
441 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530442 }
443
444 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
445 constraints);
446
447 // NO-PATH
448 if (computedPathSet.isEmpty()) {
449 return false;
450 }
451
452 Builder annotationBuilder = DefaultAnnotations.builder();
453 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530454 if (costType != null) {
455 annotationBuilder.set(COST_TYPE, costType);
456 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530457 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();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530464 TunnelConsumerId consumerId = null;
465 LspType lspType = LspType.valueOf(lspSigType);
466 long localLspId = 0;
467 if (lspType != WITH_SIGNALLING) {
468 /*
469 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
470 * PCE for non-RSVP signalled LSPs.
471 */
472 localLspId = getNextLocalLspId();
473 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530474 }
475
476 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
477 tunnel.tunnelName(), computedPath,
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530478 annotationBuilder.build());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530479
480 // Allocate shared bandwidth.
481 if (bwConstraintValue != 0) {
482 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
483 if (consumerId == null) {
484 return false;
485 }
486 }
487
488 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
489 computedPath);
490
491 if (updatedTunnelId == null) {
492 if (consumerId != null) {
493 resourceService.release(consumerId);
494 }
495 return false;
496 }
497
498 if (consumerId != null) {
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530499 // Store tunnel consumer id in LSP store.
500 pceStore.addTunnelInfo(updatedTunnelId, consumerId);
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530501 }
502
Avantika-Huawei73862d42016-05-12 18:58:06 +0530503 return true;
504 }
505
506 @Override
507 public boolean releasePath(TunnelId tunnelId) {
508 checkNotNull(tunnelId);
509 // 1. Query Tunnel from Tunnel manager.
510 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
511
512 if (tunnel == null) {
513 return false;
514 }
515
516 // 2. Call tunnel service.
517 return tunnelService.downTunnel(appId, tunnel.tunnelId());
518 }
519
520 @Override
521 public Iterable<Tunnel> queryAllPath() {
522 return tunnelService.queryTunnel(MPLS);
523 }
524
525 @Override
526 public Tunnel queryPath(TunnelId tunnelId) {
527 return tunnelService.queryTunnel(tunnelId);
528 }
529
530 /**
531 * Returns the next local LSP identifier to be used either by getting from
532 * freed list if available otherwise generating a new one.
533 *
534 * @return value of local LSP identifier
535 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530536 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530537 // If there is any free id use it. Otherwise generate new id.
538 if (localLspIdFreeList.isEmpty()) {
539 return (short) localLspIdIdGen.getNewId();
540 }
541 Iterator<Short> it = localLspIdFreeList.iterator();
542 Short value = it.next();
543 localLspIdFreeList.remove(value);
544 return value;
545 }
546
Priyanka Bb6963582016-05-20 20:21:20 +0530547 protected class TeConstraintBasedLinkWeight implements LinkWeight {
548
549 private final List<Constraint> constraints;
550
551 /**
552 * Creates a new edge-weight function capable of evaluating links
553 * on the basis of the specified constraints.
554 *
555 * @param constraints path constraints
556 */
557 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
558 if (constraints == null) {
559 this.constraints = Collections.emptyList();
560 } else {
561 this.constraints = ImmutableList.copyOf(constraints);
562 }
563 }
564
565 @Override
566 public double weight(TopologyEdge edge) {
567 if (!constraints.iterator().hasNext()) {
568 //Takes default cost/hopcount as 1 if no constraints specified
569 return 1.0;
570 }
571
572 Iterator<Constraint> it = constraints.iterator();
573 double cost = 1;
574
575 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
576 while (it.hasNext() && cost > 0) {
577 Constraint constraint = it.next();
578 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530579 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
580 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530581 } else {
582 cost = constraint.cost(edge.link(), resourceService::isAvailable);
583 }
584 }
585 return cost;
586 }
587 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530588
Priyanka B3f92c5a2016-05-27 10:14:16 +0530589 //TODO: annotations used for temporarily later projection/network config will be used
590 private class InternalTopologyListener implements TopologyListener {
591 @Override
592 public void event(TopologyEvent event) {
593 event.reasons().forEach(e -> {
594 //If event type is link removed, get the impacted tunnel
595 if (e instanceof LinkEvent) {
596 LinkEvent linkEvent = (LinkEvent) e;
597 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
598 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530599 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530600 // Check whether this ONOS instance is master for ingress device if yes,
601 // recompute and send update
602 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
603 }
604 });
605 }
606 }
607 });
608 }
609 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530610
Priyanka B3f92c5a2016-05-27 10:14:16 +0530611 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
612 /**
613 * Master of ingress node will recompute and also delegation flag must be set.
614 */
615 if (mastershipService.isLocalMaster(src)
616 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
617 LinkedList<Constraint> constraintList = new LinkedList<>();
618
619 if (tunnel.annotations().value(BANDWIDTH) != null) {
620 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
621 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
622 .annotations().value(BANDWIDTH))));
623 constraintList.add(localConst);
624 }
625 if (tunnel.annotations().value(COST_TYPE) != null) {
626 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
627 COST_TYPE))));
628 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530629
630 /*
631 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
632 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
633 */
634 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530635 // If updation fails store in PCE store as failed path
636 // then PCInitiate (Remove)
637 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
638 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
639 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
640 //Release that tunnel calling PCInitiate
641 releasePath(tunnel.tunnelId());
642 }
643 }
644
645 return false;
646 }
647
648 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530649 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
650 SharedBandwidthConstraint shBwConstraint) {
651 checkNotNull(computedPath);
652 checkNotNull(bandwidthConstraint);
653 Resource resource = null;
654 double bwToAllocate = 0;
655
656 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
657
658 /**
659 * Shared bandwidth sub-case : Lesser bandwidth required than original -
660 * No reservation required.
661 */
662 Double additionalBwValue = null;
663 if (shBwConstraint != null) {
664 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
665 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
666 }
667
668 Optional<ResourceAllocation> resAlloc = null;
669 for (Link link : computedPath.links()) {
670 bwToAllocate = 0;
671 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
672 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530673 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530674 }
675 } else {
676 bwToAllocate = bandwidthConstraint;
677 }
678
679 /**
680 * In shared bandwidth cases, where new BW is lesser than old BW, it
681 * is not required to allocate anything.
682 */
683 if (bwToAllocate != 0) {
684 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
685 .resource(bwToAllocate);
686 resAlloc = resourceService.allocate(consumer, resource);
687
688 // If allocation for any link fails, then release the partially allocated bandwidth.
689 if (!resAlloc.isPresent()) {
690 resourceService.release(consumer);
691 return null;
692 }
693 }
694 }
695
696 /*
697 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
698 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
699 * to who is supposed to store/delete.
700 */
701 return consumer;
702 }
703
704 /*
705 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
706 */
707 private void releaseBandwidth(Tunnel tunnel) {
708 // Between same source and destination, search the tunnel with same symbolic path name.
709 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
710 Tunnel newTunnel = null;
711 for (Tunnel tunnelObj : tunnelQueryResult) {
712 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
713 newTunnel = tunnelObj;
714 break;
715 }
716 }
717
718 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
719 boolean isLinkShared = false;
720 if (newTunnel != null) {
721 for (Link link : tunnel.path().links()) {
722 if (newTunnel.path().links().contains(link)) {
723 isLinkShared = true;
724 break;
725 }
726 }
727 }
728
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530729 ResourceConsumer tunnelConsumerId = pceStore.getTunnelInfo(tunnel.tunnelId());
730 if (tunnelConsumerId == null) {
731 //If bandwidth for old tunnel is not allocated i,e 0 then no need to release
732 log.debug("Bandwidth not allocated (0 bandwidth) for old LSP.");
733 return;
734 }
735
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530736 if (isLinkShared) {
737 releaseSharedBandwidth(newTunnel, tunnel);
738 return;
739 }
740
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530741 resourceService.release(tunnelConsumerId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530742 /*
743 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
744 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
745 * to who is supposed to store/delete.
746 */
747 }
748
749 /**
750 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
751 * allocated in shared mode initially.
752 */
753 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
754 // 1. Release old tunnel's bandwidth.
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530755 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()));
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530756
Priyanka B4c3b4512016-07-22 11:41:49 +0530757 // 2. Release new tunnel's bandwidth, if new tunnel bandwidth is allocated
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530758 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId());
759 if (consumer == null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530760 //If bandwidth for new tunnel is not allocated i,e 0 then no need to allocate
761 return;
762 }
763
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530764 resourceService.release(consumer);
765
766 // 3. Allocate new tunnel's complete bandwidth.
767 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
768 Resource resource;
769
770 for (Link link : newTunnel.path().links()) {
771 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
772 .resource(bandwidth);
773 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530774
775 }
776 }
777
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530778 // Listens on tunnel events.
779 private class InnerTunnelListener implements TunnelListener {
780 @Override
781 public void event(TunnelEvent event) {
782 // Event gets generated with old tunnel object.
783 Tunnel tunnel = event.subject();
784 if (tunnel.type() != MPLS) {
785 return;
786 }
787
788 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
789 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
790 double bwConstraintValue = 0;
791 if (tunnelBandwidth != null) {
792 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
793 }
794
795 switch (event.type()) {
796 case TUNNEL_ADDED:
797 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
798 String pceInit = tunnel.annotations().value(PCE_INIT);
Avantika-Huawei9e848e82016-09-01 12:12:42 +0530799 if (FALSE.equalsIgnoreCase(pceInit) && bwConstraintValue != 0) {
800 TunnelConsumerId consumerId = reserveBandwidth(tunnel.path(), bwConstraintValue, null);
801 if (consumerId != null) {
802 // Store tunnel consumer id in LSP store.
803 pceStore.addTunnelInfo(tunnel.tunnelId(), consumerId);
804 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530805 }
806 break;
807
808 case TUNNEL_UPDATED:
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530809 if (tunnel.state() == UNSTABLE) {
810 /*
811 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
812 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
813 * and setup while global reoptimization.
814 */
815
816 List<Constraint> constraints = new LinkedList<>();
817 String bandwidth = tunnel.annotations().value(BANDWIDTH);
818 if (bandwidth != null) {
819 constraints.add(new BandwidthConstraint(Bandwidth
820 .bps(Double.parseDouble(bandwidth))));
821 }
822
823 String costType = tunnel.annotations().value(COST_TYPE);
824 if (costType != null) {
825 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
826 constraints.add(costConstraint);
827 }
828
829 constraints.add(CapabilityConstraint
830 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
831
832 List<Link> links = tunnel.path().links();
833 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
834 links.get(links.size() - 1).dst().deviceId(),
835 tunnel.tunnelName().value(), constraints, lspType));
836 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530837
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530838 break;
839
840 case TUNNEL_REMOVED:
841 if (lspType != WITH_SIGNALLING) {
842 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
843 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530844 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530845 if (bwConstraintValue != 0
Priyanka B4c3b4512016-07-22 11:41:49 +0530846 && mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
847 releaseBandwidth(tunnel);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530848 }
Priyanka B4c3b4512016-07-22 11:41:49 +0530849
850 if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
851 pceStore.removeTunnelInfo(tunnel.tunnelId());
852 }
853
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530854 break;
855
856 default:
857 break;
858
859 }
860 return;
861 }
862 }
863
Priyanka B9fa4ed32016-05-27 11:59:24 +0530864 //Computes path from tunnel store and also path failed to setup.
865 private void callForOptimization() {
866 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
867 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
868 checkForMasterAndSetupPath(failedPathInfo);
869 }
870
871 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
872 tunnelService.queryTunnel(MPLS).forEach(t -> {
873 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
874 });
875 }
876
877 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
878 /**
879 * Master of ingress node will setup the path failed stored in PCE store.
880 */
881 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
882 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
883 failedPathInfo.constraints(), failedPathInfo.lspType())) {
884 // If computation is success remove that path
885 pceStore.removeFailedPathInfo(failedPathInfo);
886 return true;
887 }
888 }
889
890 return false;
891 }
892
893 //Timer to call global optimization
894 private class GlobalOptimizationTimer implements Runnable {
895
896 public GlobalOptimizationTimer() {
897 }
898
899 @Override
900 public void run() {
901 callForOptimization();
902 }
903 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530904}