blob: c622f0ecbc15023d30afdb70afe4e9267dac2ab9 [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;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053022import java.util.HashMap;
Avantika-Huawei73862d42016-05-12 18:58:06 +053023import java.util.Iterator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053024import java.util.LinkedList;
Avantika-Huawei73862d42016-05-12 18:58:06 +053025import java.util.List;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053026import java.util.Map;
27import java.util.Optional;
28import java.util.Map.Entry;
Priyanka Bb6963582016-05-20 20:21:20 +053029import java.util.Set;
Priyanka B9fa4ed32016-05-27 11:59:24 +053030import java.util.concurrent.ScheduledExecutorService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053031
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +053032import org.onlab.packet.Ethernet;
33import org.onlab.packet.IPv4;
34
Avantika-Huawei73862d42016-05-12 18:58:06 +053035import org.apache.felix.scr.annotations.Activate;
36import org.apache.felix.scr.annotations.Component;
37import org.apache.felix.scr.annotations.Deactivate;
38import org.apache.felix.scr.annotations.Reference;
39import org.apache.felix.scr.annotations.ReferenceCardinality;
40import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053041import org.onlab.packet.IpAddress;
42import org.onlab.packet.IpPrefix;
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +053043import org.onlab.packet.TCP;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053044import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053045import org.onosproject.core.ApplicationId;
46import org.onosproject.core.CoreService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053047import org.onosproject.incubator.net.resource.label.LabelResourceAdminService;
48import org.onosproject.incubator.net.resource.label.LabelResourceId;
49import org.onosproject.incubator.net.resource.label.LabelResourceService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053050import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053051import org.onosproject.incubator.net.tunnel.DefaultTunnel;
52import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
53import org.onosproject.incubator.net.tunnel.LabelStack;
Avantika-Huawei73862d42016-05-12 18:58:06 +053054import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053055import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
56import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053057import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053058import org.onosproject.incubator.net.tunnel.TunnelListener;
59import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053060import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053061import org.onosproject.mastership.MastershipService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053062import org.onosproject.net.config.NetworkConfigEvent;
63import org.onosproject.net.config.NetworkConfigListener;
Avantika-Huawei032a9872016-05-27 22:57:38 +053064import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053065import org.onosproject.net.DefaultAnnotations;
66import org.onosproject.net.DefaultAnnotations.Builder;
67import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053068import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053069import org.onosproject.net.Link;
Priyanka Bb6963582016-05-20 20:21:20 +053070import org.onosproject.net.Path;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053071import org.onosproject.net.device.DeviceEvent;
72import org.onosproject.net.device.DeviceListener;
Priyanka Bb6963582016-05-20 20:21:20 +053073import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053074import org.onosproject.net.flowobjective.FlowObjectiveService;
75import org.onosproject.net.flowobjective.Objective;
76import org.onosproject.net.intent.Constraint;
77import org.onosproject.net.intent.constraint.BandwidthConstraint;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053078import org.onosproject.net.link.LinkListener;
Priyanka B3f92c5a2016-05-27 10:14:16 +053079import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053080import org.onosproject.net.link.LinkService;
81import org.onosproject.net.MastershipRole;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053082import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
83import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
84import org.onosproject.pce.pceservice.constraint.CostConstraint;
85import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
86import org.onosproject.net.resource.Resource;
87import org.onosproject.net.resource.ResourceAllocation;
88import org.onosproject.net.resource.ResourceConsumer;
89import org.onosproject.net.resource.ResourceQueryService;
Priyanka Bb6963582016-05-20 20:21:20 +053090import org.onosproject.net.resource.ResourceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053091import org.onosproject.net.resource.Resources;
Priyanka Bb6963582016-05-20 20:21:20 +053092import org.onosproject.net.topology.LinkWeight;
93import org.onosproject.net.topology.PathService;
94import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053095import org.onosproject.net.topology.TopologyEvent;
96import org.onosproject.net.topology.TopologyListener;
97import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053098import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053099import org.onosproject.pce.pcestore.PcePathInfo;
100import org.onosproject.pce.pcestore.PceccTunnelInfo;
101import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530102import org.onosproject.pcep.api.DeviceCapability;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530103import org.onosproject.store.serializers.KryoNamespaces;
104import org.onosproject.store.service.DistributedSet;
105import org.onosproject.store.service.Serializer;
106import org.onosproject.store.service.StorageService;
107import org.slf4j.Logger;
108import org.slf4j.LoggerFactory;
109
Priyanka Bb6963582016-05-20 20:21:20 +0530110import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530111import com.google.common.collect.ImmutableSet;
112
Priyanka B4c3b4512016-07-22 11:41:49 +0530113import static org.onosproject.incubator.net.tunnel.Tunnel.State.ACTIVE;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530114import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
115import static org.onosproject.incubator.net.tunnel.Tunnel.State.ESTABLISHED;
116import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
Priyanka B4c3b4512016-07-22 11:41:49 +0530117import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530118import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
119import static org.onosproject.pce.pceservice.LspType.SR_WITHOUT_SIGNALLING;
120import static org.onosproject.pce.pceservice.LspType.WITHOUT_SIGNALLING_AND_WITHOUT_SR;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530121import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
122import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
123import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
124import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
125import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
126import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
127import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
128import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
129
130import org.onosproject.net.packet.InboundPacket;
131import org.onosproject.net.packet.PacketContext;
132import org.onosproject.net.packet.PacketProcessor;
133import org.onosproject.net.packet.PacketService;
Priyanka Bb6963582016-05-20 20:21:20 +0530134
Avantika-Huawei73862d42016-05-12 18:58:06 +0530135/**
136 * Implementation of PCE service.
137 */
138@Component(immediate = true)
139@Service
140public class PceManager implements PceService {
141 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
142
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530143 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
144 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
145 private static final String DEVICE_NULL = "Device-cannot be null";
146 private static final String LINK_NULL = "Link-cannot be null";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530147 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530148 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530149 public static final String DEVICE_TYPE = "type";
150 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530151 private static final int PREFIX_LENGTH = 32;
152
153 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
154 private IdGenerator tunnelConsumerIdGen;
155
156 private static final String LSRID = "lsrId";
157 private static final String TRUE = "true";
158 private static final String FALSE = "false";
159 private static final String END_OF_SYNC_IP_PREFIX = "0.0.0.0/32";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530160 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530161
Avantika-Huawei73862d42016-05-12 18:58:06 +0530162 private IdGenerator localLspIdIdGen;
163 protected DistributedSet<Short> localLspIdFreeList;
164
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530165 // LSR-id and device-id mapping for checking capability if L3 device is not
166 // having its capability
167 private Map<String, DeviceId> lsrIdDeviceIdMap = new HashMap<>();
168
Avantika-Huawei73862d42016-05-12 18:58:06 +0530169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
170 protected CoreService coreService;
171
172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530173 protected ResourceService resourceService;
174
175 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
176 protected ResourceQueryService resourceQueryService;
177
178 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
179 protected PathService pathService;
180
181 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
182 protected PceStore pceStore;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530185 protected TunnelService tunnelService;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
188 protected StorageService storageService;
189
Priyanka Bb6963582016-05-20 20:21:20 +0530190 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530191 protected PacketService packetService;
Priyanka Bb6963582016-05-20 20:21:20 +0530192
193 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
194 protected DeviceService deviceService;
195
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530196 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530197 protected LinkService linkService;
198
199 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530200 protected NetworkConfigService netCfgService;
201
202 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530203 protected LabelResourceAdminService labelRsrcAdminService;
204
205 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
206 protected LabelResourceService labelRsrcService;
207
208 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
209 protected FlowObjectiveService flowObjectiveService;
210
Priyanka B3f92c5a2016-05-27 10:14:16 +0530211 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
212 protected MastershipService mastershipService;
213
214 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
215 protected TopologyService topologyService;
216
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530217 private TunnelListener listener = new InnerTunnelListener();
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530218 private DeviceListener deviceListener = new InternalDeviceListener();
219 private LinkListener linkListener = new InternalLinkListener();
220 private InternalConfigListener cfgListener = new InternalConfigListener();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530221 private BasicPceccHandler crHandler;
222 private PceccSrTeBeHandler srTeHandler;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530223 private ApplicationId appId;
224
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530225 private final PcepPacketProcessor processor = new PcepPacketProcessor();
Priyanka B3f92c5a2016-05-27 10:14:16 +0530226 private final TopologyListener topologyListener = new InternalTopologyListener();
Priyanka B9fa4ed32016-05-27 11:59:24 +0530227 private ScheduledExecutorService executor;
228
229 public static final int INITIAL_DELAY = 30;
230 public static final int PERIODIC_DELAY = 30;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530231
Avantika-Huawei73862d42016-05-12 18:58:06 +0530232 /**
233 * Creates new instance of PceManager.
234 */
235 public PceManager() {
236 }
237
238 @Activate
239 protected void activate() {
240 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530241 crHandler = BasicPceccHandler.getInstance();
242 crHandler.initialize(labelRsrcService, flowObjectiveService, appId, pceStore);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530243
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530244 srTeHandler = PceccSrTeBeHandler.getInstance();
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530245 srTeHandler.initialize(labelRsrcAdminService, labelRsrcService, flowObjectiveService, appId, pceStore,
246 deviceService);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530247
248 tunnelService.addListener(listener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530249 deviceService.addListener(deviceListener);
250 linkService.addListener(linkListener);
251 netCfgService.addListener(cfgListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530252
253 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530254 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530255 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530256 localLspIdFreeList = storageService.<Short>setBuilder()
257 .withName("pcepLocalLspIdDeletedList")
258 .withSerializer(Serializer.using(KryoNamespaces.API))
259 .build()
260 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530261
262 packetService.addProcessor(processor, PacketProcessor.director(4));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530263 topologyService.addListener(topologyListener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530264
265 // Reserve global node pool
266 if (!srTeHandler.reserveGlobalPool(GLOBAL_LABEL_SPACE_MIN, GLOBAL_LABEL_SPACE_MAX)) {
267 log.debug("Global node pool was already reserved.");
268 }
269
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530270 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530271 }
272
273 @Deactivate
274 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530275 tunnelService.removeListener(listener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530276 deviceService.removeListener(deviceListener);
277 linkService.removeListener(linkListener);
278 netCfgService.removeListener(cfgListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530279 packetService.removeProcessor(processor);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530280 topologyService.removeListener(topologyListener);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530281 log.info("Stopped");
282 }
283
Priyanka Bb6963582016-05-20 20:21:20 +0530284 /**
285 * Returns an edge-weight capable of evaluating links on the basis of the
286 * specified constraints.
287 *
288 * @param constraints path constraints
289 * @return edge-weight function
290 */
291 private LinkWeight weight(List<Constraint> constraints) {
292 return new TeConstraintBasedLinkWeight(constraints);
293 }
294
295 /**
296 * Computes a path between two devices.
297 *
298 * @param src ingress device
299 * @param dst egress device
300 * @param constraints path constraints
301 * @return computed path based on constraints
302 */
303 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
304 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530305 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530306 }
307 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
308 if (!paths.isEmpty()) {
309 return paths;
310 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530311 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530312 }
313
Avantika-Huawei73862d42016-05-12 18:58:06 +0530314 //[TODO:] handle requests in queue
315 @Override
316 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
317 LspType lspType) {
318 checkNotNull(src);
319 checkNotNull(dst);
320 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530321 checkNotNull(lspType);
322
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530323 // Convert from DeviceId to TunnelEndPoint
324 Device srcDevice = deviceService.getDevice(src);
325 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530326
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530327 if (srcDevice == null || dstDevice == null) {
328 // Device is not known.
329 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
330 return false;
331 }
332
333 // In future projections instead of annotations will be used to fetch LSR ID.
334 String srcLsrId = srcDevice.annotations().value(LSRID);
335 String dstLsrId = dstDevice.annotations().value(LSRID);
336
337 if (srcLsrId == null || dstLsrId == null) {
338 // LSR id is not known.
339 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
340 return false;
341 }
342
Avantika-Huawei032a9872016-05-27 22:57:38 +0530343 // Get device config from netconfig, to ascertain that session with ingress is present.
344 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
345 if (cfg == null) {
346 log.debug("No session to ingress.");
347 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
348 return false;
349 }
350
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530351 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
352 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
353
354 double bwConstraintValue = 0;
355 CostConstraint costConstraint = null;
356 if (constraints != null) {
357 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
358 Iterator<Constraint> iterator = constraints.iterator();
359
360 while (iterator.hasNext()) {
361 Constraint constraint = iterator.next();
362 if (constraint instanceof BandwidthConstraint) {
363 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
364 } else if (constraint instanceof CostConstraint) {
365 costConstraint = (CostConstraint) constraint;
366 }
367 }
368
369 /*
370 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
371 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
372 * function can either return the result of limiting/capability constraint validation or the value of link
373 * cost, depending upon what is the last constraint in the loop.
374 */
375 if (costConstraint != null) {
376 constraints.remove(costConstraint);
377 constraints.add(costConstraint);
378 }
379 } else {
380 constraints = new LinkedList<>();
381 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
382 }
383
384 Set<Path> computedPathSet = computePath(src, dst, constraints);
385
386 // NO-PATH
387 if (computedPathSet.isEmpty()) {
388 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
389 return false;
390 }
391
392 Builder annotationBuilder = DefaultAnnotations.builder();
393 if (bwConstraintValue != 0) {
394 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
395 }
396 if (costConstraint != null) {
397 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
398 }
399 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
400 annotationBuilder.set(PCE_INIT, TRUE);
401 annotationBuilder.set(DELEGATE, TRUE);
402
403 Path computedPath = computedPathSet.iterator().next();
404 LabelStack labelStack = null;
405
406 if (lspType == SR_WITHOUT_SIGNALLING) {
407 labelStack = srTeHandler.computeLabelStack(computedPath);
408 // Failed to form a label stack.
409 if (labelStack == null) {
410 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
411 return false;
412 }
413 }
414
415 if (lspType != WITH_SIGNALLING) {
416 /*
417 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
418 * PCE for non-RSVP signalled LSPs.
419 */
420 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
421 }
422
423 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
424 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
425 TunnelName.tunnelName(tunnelName), computedPath,
426 labelStack, annotationBuilder.build());
427
428 // Allocate bandwidth.
429 TunnelConsumerId consumerId = null;
430 if (bwConstraintValue != 0) {
431 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
432 if (consumerId == null) {
433 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
434 return false;
435 }
436 }
437
438 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
439 if (tunnelId == null) {
440 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
441 if (consumerId != null) {
442 resourceService.release(consumerId);
443 }
444 return false;
445 }
446
447 if (consumerId != null) {
448 // Store tunnel consumer id in LSP-Label store.
449 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
450 pceStore.addTunnelInfo(tunnelId, pceccTunnelInfo);
451 }
452 return true;
453 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530454
455 @Override
456 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
457 checkNotNull(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530458 Set<Path> computedPathSet = null;
459 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530460
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530461 if (tunnel == null) {
462 return false;
463 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530464
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530465 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
466 // Only delegated LSPs can be updated.
467 return false;
468 }
469
470 List<Link> links = tunnel.path().links();
471 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
472 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530473 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530474 SharedBandwidthConstraint shBwConstraint = null;
475 BandwidthConstraint bwConstraint = null;
476 CostConstraint costConstraint = null;
477
478 if (constraints != null) {
479 // Call path computation in shared bandwidth mode.
480 Iterator<Constraint> iterator = constraints.iterator();
481 while (iterator.hasNext()) {
482 Constraint constraint = iterator.next();
483 if (constraint instanceof BandwidthConstraint) {
484 bwConstraint = (BandwidthConstraint) constraint;
485 bwConstraintValue = bwConstraint.bandwidth().bps();
486 } else if (constraint instanceof CostConstraint) {
487 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530488 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530489 }
490 }
491
492 // Remove and keep the cost constraint at the end of the list of constraints.
493 if (costConstraint != null) {
494 constraints.remove(costConstraint);
495 }
496
497 Bandwidth existingBwValue = null;
498 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
499 if (existingBwAnnotation != null) {
500 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
501
502 /*
503 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
504 * has been utilized to create shared bandwidth constraint.
505 */
506 if (bwConstraint != null) {
507 constraints.remove(bwConstraint);
508 }
509 }
510
511 if (existingBwValue != null) {
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530512 if (bwConstraint == null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530513 bwConstraintValue = existingBwValue.bps();
514 }
515 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
516 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
517 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
518 existingBwValue, existingBwValue);
519
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530520 constraints.add(shBwConstraint);
521 }
522 } else {
523 constraints = new LinkedList<>();
524 }
525
526 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
527 if (costConstraint != null) {
528 constraints.add(costConstraint);
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530529 } else {
530 //Take cost constraint from old tunnel if it is not specified in update flow
531 costType = tunnel.annotations().value(COST_TYPE);
532 costConstraint = CostConstraint.of(CostConstraint.Type.valueOf(costType));
533 constraints.add(costConstraint);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530534 }
535
536 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
537 constraints);
538
539 // NO-PATH
540 if (computedPathSet.isEmpty()) {
541 return false;
542 }
543
544 Builder annotationBuilder = DefaultAnnotations.builder();
545 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530546 if (costType != null) {
547 annotationBuilder.set(COST_TYPE, costType);
548 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530549 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
550 annotationBuilder.set(PCE_INIT, TRUE);
551 annotationBuilder.set(DELEGATE, TRUE);
552 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
553 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
554
555 Path computedPath = computedPathSet.iterator().next();
556 LabelStack labelStack = null;
557 TunnelConsumerId consumerId = null;
558 LspType lspType = LspType.valueOf(lspSigType);
559 long localLspId = 0;
560 if (lspType != WITH_SIGNALLING) {
561 /*
562 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
563 * PCE for non-RSVP signalled LSPs.
564 */
565 localLspId = getNextLocalLspId();
566 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
567
568 if (lspType == SR_WITHOUT_SIGNALLING) {
569 labelStack = srTeHandler.computeLabelStack(computedPath);
570 // Failed to form a label stack.
571 if (labelStack == null) {
572 return false;
573 }
574 }
575 }
576
577 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
578 tunnel.tunnelName(), computedPath,
579 labelStack, annotationBuilder.build());
580
581 // Allocate shared bandwidth.
582 if (bwConstraintValue != 0) {
583 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
584 if (consumerId == null) {
585 return false;
586 }
587 }
588
589 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
590 computedPath);
591
592 if (updatedTunnelId == null) {
593 if (consumerId != null) {
594 resourceService.release(consumerId);
595 }
596 return false;
597 }
598
599 if (consumerId != null) {
600 // Store tunnel consumer id in LSP-Label store.
601 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
602 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
603 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530604
605 // For CR cases, download labels and send update message.
606 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
607 Tunnel tunnelForlabelDownload = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null,
608 updatedTunnelId, tunnel.tunnelName(), computedPath,
609 labelStack, annotationBuilder.build());
610
611 if (!crHandler.allocateLabel(tunnelForlabelDownload)) {
612 log.error("Unable to allocate labels for the tunnel {}.", tunnel.toString());
613 }
614 }
615
Avantika-Huawei73862d42016-05-12 18:58:06 +0530616 return true;
617 }
618
619 @Override
620 public boolean releasePath(TunnelId tunnelId) {
621 checkNotNull(tunnelId);
622 // 1. Query Tunnel from Tunnel manager.
623 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
624
625 if (tunnel == null) {
626 return false;
627 }
628
Priyanka B4c3b4512016-07-22 11:41:49 +0530629 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
630 // Release basic PCECC labels.
631 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
632 crHandler.releaseLabel(tunnel);
633 }
634
Avantika-Huawei73862d42016-05-12 18:58:06 +0530635 // 2. Call tunnel service.
636 return tunnelService.downTunnel(appId, tunnel.tunnelId());
637 }
638
639 @Override
640 public Iterable<Tunnel> queryAllPath() {
641 return tunnelService.queryTunnel(MPLS);
642 }
643
644 @Override
645 public Tunnel queryPath(TunnelId tunnelId) {
646 return tunnelService.queryTunnel(tunnelId);
647 }
648
649 /**
650 * Returns the next local LSP identifier to be used either by getting from
651 * freed list if available otherwise generating a new one.
652 *
653 * @return value of local LSP identifier
654 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530655 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530656 // If there is any free id use it. Otherwise generate new id.
657 if (localLspIdFreeList.isEmpty()) {
658 return (short) localLspIdIdGen.getNewId();
659 }
660 Iterator<Short> it = localLspIdFreeList.iterator();
661 Short value = it.next();
662 localLspIdFreeList.remove(value);
663 return value;
664 }
665
Priyanka Bb6963582016-05-20 20:21:20 +0530666 protected class TeConstraintBasedLinkWeight implements LinkWeight {
667
668 private final List<Constraint> constraints;
669
670 /**
671 * Creates a new edge-weight function capable of evaluating links
672 * on the basis of the specified constraints.
673 *
674 * @param constraints path constraints
675 */
676 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
677 if (constraints == null) {
678 this.constraints = Collections.emptyList();
679 } else {
680 this.constraints = ImmutableList.copyOf(constraints);
681 }
682 }
683
684 @Override
685 public double weight(TopologyEdge edge) {
686 if (!constraints.iterator().hasNext()) {
687 //Takes default cost/hopcount as 1 if no constraints specified
688 return 1.0;
689 }
690
691 Iterator<Constraint> it = constraints.iterator();
692 double cost = 1;
693
694 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
695 while (it.hasNext() && cost > 0) {
696 Constraint constraint = it.next();
697 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530698 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
699 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530700 } else {
701 cost = constraint.cost(edge.link(), resourceService::isAvailable);
702 }
703 }
704 return cost;
705 }
706 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530707
Priyanka B3f92c5a2016-05-27 10:14:16 +0530708 //TODO: annotations used for temporarily later projection/network config will be used
709 private class InternalTopologyListener implements TopologyListener {
710 @Override
711 public void event(TopologyEvent event) {
712 event.reasons().forEach(e -> {
713 //If event type is link removed, get the impacted tunnel
714 if (e instanceof LinkEvent) {
715 LinkEvent linkEvent = (LinkEvent) e;
716 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
717 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530718 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530719 // Check whether this ONOS instance is master for ingress device if yes,
720 // recompute and send update
721 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
722 }
723 });
724 }
725 }
726 });
727 }
728 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530729
Priyanka B3f92c5a2016-05-27 10:14:16 +0530730 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
731 /**
732 * Master of ingress node will recompute and also delegation flag must be set.
733 */
734 if (mastershipService.isLocalMaster(src)
735 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
736 LinkedList<Constraint> constraintList = new LinkedList<>();
737
738 if (tunnel.annotations().value(BANDWIDTH) != null) {
739 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
740 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
741 .annotations().value(BANDWIDTH))));
742 constraintList.add(localConst);
743 }
744 if (tunnel.annotations().value(COST_TYPE) != null) {
745 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
746 COST_TYPE))));
747 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530748
749 /*
750 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
751 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
752 */
753 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530754 // If updation fails store in PCE store as failed path
755 // then PCInitiate (Remove)
756 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
757 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
758 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
759 //Release that tunnel calling PCInitiate
760 releasePath(tunnel.tunnelId());
761 }
762 }
763
764 return false;
765 }
766
767 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530768 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
769 SharedBandwidthConstraint shBwConstraint) {
770 checkNotNull(computedPath);
771 checkNotNull(bandwidthConstraint);
772 Resource resource = null;
773 double bwToAllocate = 0;
774
775 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
776
777 /**
778 * Shared bandwidth sub-case : Lesser bandwidth required than original -
779 * No reservation required.
780 */
781 Double additionalBwValue = null;
782 if (shBwConstraint != null) {
783 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
784 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
785 }
786
787 Optional<ResourceAllocation> resAlloc = null;
788 for (Link link : computedPath.links()) {
789 bwToAllocate = 0;
790 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
791 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530792 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530793 }
794 } else {
795 bwToAllocate = bandwidthConstraint;
796 }
797
798 /**
799 * In shared bandwidth cases, where new BW is lesser than old BW, it
800 * is not required to allocate anything.
801 */
802 if (bwToAllocate != 0) {
803 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
804 .resource(bwToAllocate);
805 resAlloc = resourceService.allocate(consumer, resource);
806
807 // If allocation for any link fails, then release the partially allocated bandwidth.
808 if (!resAlloc.isPresent()) {
809 resourceService.release(consumer);
810 return null;
811 }
812 }
813 }
814
815 /*
816 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
817 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
818 * to who is supposed to store/delete.
819 */
820 return consumer;
821 }
822
823 /*
824 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
825 */
826 private void releaseBandwidth(Tunnel tunnel) {
827 // Between same source and destination, search the tunnel with same symbolic path name.
828 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
829 Tunnel newTunnel = null;
830 for (Tunnel tunnelObj : tunnelQueryResult) {
831 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
832 newTunnel = tunnelObj;
833 break;
834 }
835 }
836
837 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
838 boolean isLinkShared = false;
839 if (newTunnel != null) {
840 for (Link link : tunnel.path().links()) {
841 if (newTunnel.path().links().contains(link)) {
842 isLinkShared = true;
843 break;
844 }
845 }
846 }
847
848 if (isLinkShared) {
849 releaseSharedBandwidth(newTunnel, tunnel);
850 return;
851 }
852
Priyanka B3fdb9dd2016-08-08 10:47:24 +0530853 if (pceStore.getTunnelInfo(tunnel.tunnelId()) == null) {
854 //If bandwidth for old tunnel is not allocated i,e 0 then no need to release
855 return;
856 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530857 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
858 return;
859
860 /*
861 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
862 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
863 * to who is supposed to store/delete.
864 */
865 }
866
867 /**
868 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
869 * allocated in shared mode initially.
870 */
871 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
872 // 1. Release old tunnel's bandwidth.
873 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
874
Priyanka B4c3b4512016-07-22 11:41:49 +0530875 // 2. Release new tunnel's bandwidth, if new tunnel bandwidth is allocated
876 if (pceStore.getTunnelInfo(newTunnel.tunnelId()) == null) {
877 //If bandwidth for new tunnel is not allocated i,e 0 then no need to allocate
878 return;
879 }
880
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530881 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
882 resourceService.release(consumer);
883
884 // 3. Allocate new tunnel's complete bandwidth.
885 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
886 Resource resource;
887
888 for (Link link : newTunnel.path().links()) {
889 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
890 .resource(bandwidth);
891 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530892
893 }
894 }
895
896 /**
897 * Allocates node label to specific device.
898 *
899 * @param specificDevice device to which node label needs to be allocated
900 */
901 public void allocateNodeLabel(Device specificDevice) {
902 checkNotNull(specificDevice, DEVICE_NULL);
903
904 DeviceId deviceId = specificDevice.id();
905
906 // Retrieve lsrId of a specific device
907 if (specificDevice.annotations() == null) {
908 log.debug("Device {} does not have annotations.", specificDevice.toString());
909 return;
910 }
911
912 String lsrId = specificDevice.annotations().value(LSRID);
913 if (lsrId == null) {
914 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
915 return;
916 }
917
918 // Get capability config from netconfig
919 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
920 if (cfg == null) {
921 log.error("Unable to find corresponding capability for a lsrd {} from NetConfig.", lsrId);
922 // Save info. When PCEP session is comes up then allocate node-label
923 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
924 return;
925 }
926
927 // Check whether device has SR-TE Capability
928 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530929 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530930 }
931 }
932
933 /**
934 * Releases node label of a specific device.
935 *
936 * @param specificDevice this device label and lsr-id information will be
937 * released in other existing devices
938 */
939 public void releaseNodeLabel(Device specificDevice) {
940 checkNotNull(specificDevice, DEVICE_NULL);
941
942 DeviceId deviceId = specificDevice.id();
943
944 // Retrieve lsrId of a specific device
945 if (specificDevice.annotations() == null) {
946 log.debug("Device {} does not have annotations.", specificDevice.toString());
947 return;
948 }
949
950 String lsrId = specificDevice.annotations().value(LSRID);
951 if (lsrId == null) {
952 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
953 return;
954 }
955
956 // Get capability config from netconfig
957 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
958 if (cfg == null) {
959 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
960 return;
961 }
962
963 // Check whether device has SR-TE Capability
964 if (cfg.labelStackCap()) {
965 if (!srTeHandler.releaseNodeLabel(deviceId, lsrId)) {
966 log.error("Unable to release node label for a device id {}.", deviceId.toString());
967 }
968 }
969 }
970
971 /**
972 * Allocates adjacency label for a link.
973 *
974 * @param link link
975 */
976 public void allocateAdjacencyLabel(Link link) {
977 checkNotNull(link, LINK_NULL);
978
979 Device specificDevice = deviceService.getDevice(link.src().deviceId());
980 DeviceId deviceId = specificDevice.id();
981
982 // Retrieve lsrId of a specific device
983 if (specificDevice.annotations() == null) {
984 log.debug("Device {} does not have annotations.", specificDevice.toString());
985 return;
986 }
987
988 String lsrId = specificDevice.annotations().value(LSRID);
989 if (lsrId == null) {
990 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
991 return;
992 }
993
994 // Get capability config from netconfig
995 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
996 if (cfg == null) {
997 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
998 // Save info. When PCEP session comes up then allocate adjacency
999 // label
1000 if (lsrIdDeviceIdMap.get(lsrId) != null) {
1001 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
1002 }
1003 return;
1004 }
1005
1006 // Check whether device has SR-TE Capability
1007 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301008 srTeHandler.allocateAdjacencyLabel(link);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301009 }
1010
1011 return;
1012 }
1013
1014 /**
1015 * Releases allocated adjacency label of a link.
1016 *
1017 * @param link link
1018 */
1019 public void releaseAdjacencyLabel(Link link) {
1020 checkNotNull(link, LINK_NULL);
1021
1022 Device specificDevice = deviceService.getDevice(link.src().deviceId());
1023 DeviceId deviceId = specificDevice.id();
1024
1025 // Retrieve lsrId of a specific device
1026 if (specificDevice.annotations() == null) {
1027 log.debug("Device {} does not have annotations.", specificDevice.toString());
1028 return;
1029 }
1030
1031 String lsrId = specificDevice.annotations().value(LSRID);
1032 if (lsrId == null) {
1033 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
1034 return;
1035 }
1036
1037 // Get capability config from netconfig
1038 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1039 if (cfg == null) {
1040 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
1041 return;
1042 }
1043
1044 // Check whether device has SR-TE Capability
1045 if (cfg.labelStackCap()) {
1046 if (!srTeHandler.releaseAdjacencyLabel(link)) {
1047 log.error("Unable to release adjacency labels for a link {}.", link.toString());
1048 return;
1049 }
1050 }
1051
1052 return;
1053 }
1054
1055 /*
1056 * Handle device events.
1057 */
1058 private class InternalDeviceListener implements DeviceListener {
1059 @Override
1060 public void event(DeviceEvent event) {
1061 Device specificDevice = (Device) event.subject();
1062 if (specificDevice == null) {
1063 log.error("Unable to find device from device event.");
1064 return;
1065 }
1066
1067 switch (event.type()) {
1068
1069 case DEVICE_ADDED:
1070 // Node-label allocation is being done during Label DB Sync.
1071 // So, when device is detected, no need to do node-label
1072 // allocation.
Avantika-Huawei28b53752016-06-23 17:04:49 +05301073 String lsrId = specificDevice.annotations().value(LSRID);
1074 if (lsrId != null) {
1075 pceStore.addLsrIdDevice(lsrId, specificDevice.id());
1076
1077 // Search in failed DB sync store. If found, trigger label DB sync.
1078 DeviceId pccDeviceId = DeviceId.deviceId(lsrId);
1079 if (pceStore.hasPccLsr(pccDeviceId)) {
1080 log.debug("Continue to perform label DB sync for device {}.", pccDeviceId.toString());
1081 syncLabelDb(pccDeviceId);
1082 pceStore.removePccLsr(pccDeviceId);
1083 }
1084 }
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301085 break;
1086
1087 case DEVICE_REMOVED:
1088 // Release node-label
1089 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1090 releaseNodeLabel(specificDevice);
1091 }
Avantika-Huawei28b53752016-06-23 17:04:49 +05301092
1093 if (specificDevice.annotations().value(LSRID) != null) {
1094 pceStore.removeLsrIdDevice(specificDevice.annotations().value(LSRID));
1095 }
1096
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301097 break;
1098
1099 default:
1100 break;
1101 }
1102 }
1103 }
1104
1105 /*
1106 * Handle link events.
1107 */
1108 private class InternalLinkListener implements LinkListener {
1109 @Override
1110 public void event(LinkEvent event) {
1111 Link link = (Link) event.subject();
1112
1113 switch (event.type()) {
1114
1115 case LINK_ADDED:
1116 // Allocate adjacency label
1117 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1118 allocateAdjacencyLabel(link);
1119 }
1120 break;
1121
1122 case LINK_REMOVED:
1123 // Release adjacency label
1124 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1125 releaseAdjacencyLabel(link);
1126 }
1127 break;
1128
1129 default:
1130 break;
1131 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301132 }
1133 }
1134
1135 // Listens on tunnel events.
1136 private class InnerTunnelListener implements TunnelListener {
1137 @Override
1138 public void event(TunnelEvent event) {
1139 // Event gets generated with old tunnel object.
1140 Tunnel tunnel = event.subject();
1141 if (tunnel.type() != MPLS) {
1142 return;
1143 }
1144
1145 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1146 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1147 double bwConstraintValue = 0;
1148 if (tunnelBandwidth != null) {
1149 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1150 }
1151
1152 switch (event.type()) {
1153 case TUNNEL_ADDED:
1154 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1155 String pceInit = tunnel.annotations().value(PCE_INIT);
1156 if (FALSE.equalsIgnoreCase(pceInit)
1157 && bwConstraintValue != 0) {
1158 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1159 }
1160 break;
1161
1162 case TUNNEL_UPDATED:
1163 // Allocate/send labels for basic PCECC tunnels.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301164 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)
1165 && (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER)) {
1166 if (!crHandler.allocateLabel(tunnel)) {
1167 log.error("Unable to allocate labels for a tunnel {}.", tunnel.toString());
1168 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301169 }
1170
Priyanka B4c3b4512016-07-22 11:41:49 +05301171 //In CR case, release labels when new tunnel for it is updated.
1172 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR && tunnel.state() == ACTIVE
1173 && mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1174 Collection<Tunnel> tunnels = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
1175
1176 for (Tunnel t : tunnels) {
1177 if (tunnel.annotations().value(PLSP_ID).equals(t.annotations().value(PLSP_ID))
1178 && !tunnel.annotations().value(LOCAL_LSP_ID)
1179 .equals(t.annotations().value(LOCAL_LSP_ID))) {
1180 // Release basic PCECC labels.
1181 crHandler.releaseLabel(t);
1182 break;
1183 }
1184 }
1185 }
1186
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301187 if (tunnel.state() == UNSTABLE) {
1188 /*
1189 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1190 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1191 * and setup while global reoptimization.
1192 */
1193
1194 List<Constraint> constraints = new LinkedList<>();
1195 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1196 if (bandwidth != null) {
1197 constraints.add(new BandwidthConstraint(Bandwidth
1198 .bps(Double.parseDouble(bandwidth))));
1199 }
1200
1201 String costType = tunnel.annotations().value(COST_TYPE);
1202 if (costType != null) {
1203 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1204 constraints.add(costConstraint);
1205 }
1206
1207 constraints.add(CapabilityConstraint
1208 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1209
1210 List<Link> links = tunnel.path().links();
1211 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1212 links.get(links.size() - 1).dst().deviceId(),
1213 tunnel.tunnelName().value(), constraints, lspType));
1214 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301215
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301216 break;
1217
1218 case TUNNEL_REMOVED:
1219 if (lspType != WITH_SIGNALLING) {
1220 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1221 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301222 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Priyanka B3fdb9dd2016-08-08 10:47:24 +05301223 if (bwConstraintValue != 0
Priyanka B4c3b4512016-07-22 11:41:49 +05301224 && mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1225 releaseBandwidth(tunnel);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301226 }
Priyanka B4c3b4512016-07-22 11:41:49 +05301227
1228 if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
1229 pceStore.removeTunnelInfo(tunnel.tunnelId());
1230 }
1231
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301232 break;
1233
1234 default:
1235 break;
1236
1237 }
1238 return;
1239 }
1240 }
1241
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301242 private class InternalConfigListener implements NetworkConfigListener {
1243
1244 @Override
1245 public void event(NetworkConfigEvent event) {
1246
1247 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED)
1248 && event.configClass().equals(DeviceCapability.class)) {
1249
1250 DeviceId deviceIdLsrId = (DeviceId) event.subject();
1251 String lsrId = deviceIdLsrId.toString();
1252 DeviceId deviceId = lsrIdDeviceIdMap.get(lsrId);
1253 if (deviceId == null) {
1254 log.debug("Unable to find device id for a lsr-id {} from lsr-id and device-id map.", lsrId);
1255 return;
1256 }
1257
1258 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1259 if (cfg == null) {
1260 log.error("Unable to find corresponding capabilty for a lsrd {}.", lsrId);
1261 return;
1262 }
1263
1264 if (cfg.labelStackCap()) {
1265 if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
1266 // Allocate node-label
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301267 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301268
1269 // Allocate adjacency label to links which are
1270 // originated from this specific device id
1271 Set<Link> links = linkService.getDeviceEgressLinks(deviceId);
1272 for (Link link : links) {
1273 if (!srTeHandler.allocateAdjacencyLabel(link)) {
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301274 return;
1275 }
1276 }
1277 }
1278 }
1279
1280 // Remove lsrId info from map
1281 lsrIdDeviceIdMap.remove(lsrId);
1282 }
1283 }
1284 }
1285
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301286 private boolean syncLabelDb(DeviceId deviceId) {
1287 checkNotNull(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301288
Avantika-Huawei28b53752016-06-23 17:04:49 +05301289 DeviceId actualDevcieId = pceStore.getLsrIdDevice(deviceId.toString());
1290 if (actualDevcieId == null) {
1291 log.error("Device not available {}.", deviceId.toString());
1292 pceStore.addPccLsr(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301293 return false;
1294 }
1295
Avantika-Huawei28b53752016-06-23 17:04:49 +05301296 Device specificDevice = deviceService.getDevice(actualDevcieId);
1297 if (specificDevice == null) {
1298 log.error("Unable to find device for specific device id {}.", actualDevcieId.toString());
1299 return false;
1300 }
1301
1302 if (pceStore.getGlobalNodeLabel(actualDevcieId) != null) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301303 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301304
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301305 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301306
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301307 // Convert from DeviceId to TunnelEndPoint
1308 Device srcDevice = deviceService.getDevice(entry.getKey());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301309
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301310 /*
1311 * If there is a slight difference in timing such that if device subsystem has removed the device but
1312 * PCE store still has it, just ignore such devices.
1313 */
1314 if (srcDevice == null) {
1315 continue;
1316 }
1317
1318 String srcLsrId = srcDevice.annotations().value(LSRID);
1319 if (srcLsrId == null) {
1320 continue;
1321 }
1322
Avantika-Huawei28b53752016-06-23 17:04:49 +05301323 srTeHandler.advertiseNodeLabelRule(actualDevcieId,
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301324 entry.getValue(),
1325 IpPrefix.valueOf(IpAddress.valueOf(srcLsrId), PREFIX_LENGTH),
1326 Objective.Operation.ADD, false);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301327 }
1328
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301329 Map<Link, LabelResourceId> adjLabelMap = pceStore.getAdjLabels();
1330 for (Entry<Link, LabelResourceId> entry : adjLabelMap.entrySet()) {
Avantika-Huawei28b53752016-06-23 17:04:49 +05301331 if (entry.getKey().src().deviceId().equals(actualDevcieId)) {
1332 srTeHandler.installAdjLabelRule(actualDevcieId,
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301333 entry.getValue(),
1334 entry.getKey().src().port(),
1335 entry.getKey().dst().port(),
1336 Objective.Operation.ADD);
1337 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301338 }
1339 }
1340
Avantika-Huawei28b53752016-06-23 17:04:49 +05301341 srTeHandler.advertiseNodeLabelRule(actualDevcieId,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301342 LabelResourceId.labelResourceId(0),
1343 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
1344 Objective.Operation.ADD, true);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301345
Avantika-Huawei28b53752016-06-23 17:04:49 +05301346 log.debug("End of label DB sync for device {}", actualDevcieId);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301347
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301348 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1349 // Allocate node-label to this specific device.
1350 allocateNodeLabel(specificDevice);
1351
1352 // Allocate adjacency label
1353 Set<Link> links = linkService.getDeviceEgressLinks(specificDevice.id());
1354 if (links != null) {
1355 for (Link link : links) {
1356 allocateAdjacencyLabel(link);
1357 }
1358 }
1359 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301360
1361 return true;
1362 }
1363
1364 // Process the packet received.
1365 private class PcepPacketProcessor implements PacketProcessor {
1366 // Process the packet received and in our case initiates the label DB sync.
1367 @Override
1368 public void process(PacketContext context) {
1369 // Stop processing if the packet has been handled, since we
1370 // can't do any more to it.
Avantika-Huawei3524d852016-06-04 20:44:13 +05301371 log.debug("Received trigger for label DB sync.");
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301372 if (context.isHandled()) {
1373 return;
1374 }
1375
1376 InboundPacket pkt = context.inPacket();
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301377 if (pkt == null) {
1378 return;
1379 }
1380
1381 Ethernet ethernet = pkt.parsed();
1382 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
1383 return;
1384 }
1385
1386 IPv4 ipPacket = (IPv4) ethernet.getPayload();
1387 if (ipPacket == null || ipPacket.getProtocol() != IPv4.PROTOCOL_TCP) {
1388 return;
1389 }
1390
1391 TCP tcp = (TCP) ipPacket.getPayload();
1392 if (tcp == null || tcp.getDestinationPort() != PCEP_PORT) {
1393 return;
1394 }
1395
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301396 syncLabelDb(pkt.receivedFrom().deviceId());
1397 }
1398 }
1399
Priyanka B9fa4ed32016-05-27 11:59:24 +05301400 //Computes path from tunnel store and also path failed to setup.
1401 private void callForOptimization() {
1402 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1403 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1404 checkForMasterAndSetupPath(failedPathInfo);
1405 }
1406
1407 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1408 tunnelService.queryTunnel(MPLS).forEach(t -> {
1409 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1410 });
1411 }
1412
1413 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1414 /**
1415 * Master of ingress node will setup the path failed stored in PCE store.
1416 */
1417 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1418 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
1419 failedPathInfo.constraints(), failedPathInfo.lspType())) {
1420 // If computation is success remove that path
1421 pceStore.removeFailedPathInfo(failedPathInfo);
1422 return true;
1423 }
1424 }
1425
1426 return false;
1427 }
1428
1429 //Timer to call global optimization
1430 private class GlobalOptimizationTimer implements Runnable {
1431
1432 public GlobalOptimizationTimer() {
1433 }
1434
1435 @Override
1436 public void run() {
1437 callForOptimization();
1438 }
1439 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301440}