blob: 4a0b3acfbc656f92c3bd6112215c2a89e51a8307 [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 B4c3b4512016-07-22 11:41:49 +0530512 if (bwConstraintValue == 0 && 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);
529 }
530
531 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
532 constraints);
533
534 // NO-PATH
535 if (computedPathSet.isEmpty()) {
536 return false;
537 }
538
539 Builder annotationBuilder = DefaultAnnotations.builder();
540 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530541 if (costType != null) {
542 annotationBuilder.set(COST_TYPE, costType);
543 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530544 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
545 annotationBuilder.set(PCE_INIT, TRUE);
546 annotationBuilder.set(DELEGATE, TRUE);
547 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
548 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
549
550 Path computedPath = computedPathSet.iterator().next();
551 LabelStack labelStack = null;
552 TunnelConsumerId consumerId = null;
553 LspType lspType = LspType.valueOf(lspSigType);
554 long localLspId = 0;
555 if (lspType != WITH_SIGNALLING) {
556 /*
557 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
558 * PCE for non-RSVP signalled LSPs.
559 */
560 localLspId = getNextLocalLspId();
561 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
562
563 if (lspType == SR_WITHOUT_SIGNALLING) {
564 labelStack = srTeHandler.computeLabelStack(computedPath);
565 // Failed to form a label stack.
566 if (labelStack == null) {
567 return false;
568 }
569 }
570 }
571
572 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
573 tunnel.tunnelName(), computedPath,
574 labelStack, annotationBuilder.build());
575
576 // Allocate shared bandwidth.
577 if (bwConstraintValue != 0) {
578 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
579 if (consumerId == null) {
580 return false;
581 }
582 }
583
584 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
585 computedPath);
586
587 if (updatedTunnelId == null) {
588 if (consumerId != null) {
589 resourceService.release(consumerId);
590 }
591 return false;
592 }
593
594 if (consumerId != null) {
595 // Store tunnel consumer id in LSP-Label store.
596 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
597 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
598 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530599
600 // For CR cases, download labels and send update message.
601 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
602 Tunnel tunnelForlabelDownload = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null,
603 updatedTunnelId, tunnel.tunnelName(), computedPath,
604 labelStack, annotationBuilder.build());
605
606 if (!crHandler.allocateLabel(tunnelForlabelDownload)) {
607 log.error("Unable to allocate labels for the tunnel {}.", tunnel.toString());
608 }
609 }
610
Avantika-Huawei73862d42016-05-12 18:58:06 +0530611 return true;
612 }
613
614 @Override
615 public boolean releasePath(TunnelId tunnelId) {
616 checkNotNull(tunnelId);
617 // 1. Query Tunnel from Tunnel manager.
618 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
619
620 if (tunnel == null) {
621 return false;
622 }
623
Priyanka B4c3b4512016-07-22 11:41:49 +0530624 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
625 // Release basic PCECC labels.
626 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
627 crHandler.releaseLabel(tunnel);
628 }
629
Avantika-Huawei73862d42016-05-12 18:58:06 +0530630 // 2. Call tunnel service.
631 return tunnelService.downTunnel(appId, tunnel.tunnelId());
632 }
633
634 @Override
635 public Iterable<Tunnel> queryAllPath() {
636 return tunnelService.queryTunnel(MPLS);
637 }
638
639 @Override
640 public Tunnel queryPath(TunnelId tunnelId) {
641 return tunnelService.queryTunnel(tunnelId);
642 }
643
644 /**
645 * Returns the next local LSP identifier to be used either by getting from
646 * freed list if available otherwise generating a new one.
647 *
648 * @return value of local LSP identifier
649 */
Priyanka B4c3b4512016-07-22 11:41:49 +0530650 private synchronized short getNextLocalLspId() {
Avantika-Huawei73862d42016-05-12 18:58:06 +0530651 // If there is any free id use it. Otherwise generate new id.
652 if (localLspIdFreeList.isEmpty()) {
653 return (short) localLspIdIdGen.getNewId();
654 }
655 Iterator<Short> it = localLspIdFreeList.iterator();
656 Short value = it.next();
657 localLspIdFreeList.remove(value);
658 return value;
659 }
660
Priyanka Bb6963582016-05-20 20:21:20 +0530661 protected class TeConstraintBasedLinkWeight implements LinkWeight {
662
663 private final List<Constraint> constraints;
664
665 /**
666 * Creates a new edge-weight function capable of evaluating links
667 * on the basis of the specified constraints.
668 *
669 * @param constraints path constraints
670 */
671 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
672 if (constraints == null) {
673 this.constraints = Collections.emptyList();
674 } else {
675 this.constraints = ImmutableList.copyOf(constraints);
676 }
677 }
678
679 @Override
680 public double weight(TopologyEdge edge) {
681 if (!constraints.iterator().hasNext()) {
682 //Takes default cost/hopcount as 1 if no constraints specified
683 return 1.0;
684 }
685
686 Iterator<Constraint> it = constraints.iterator();
687 double cost = 1;
688
689 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
690 while (it.hasNext() && cost > 0) {
691 Constraint constraint = it.next();
692 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530693 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
694 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530695 } else {
696 cost = constraint.cost(edge.link(), resourceService::isAvailable);
697 }
698 }
699 return cost;
700 }
701 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530702
Priyanka B3f92c5a2016-05-27 10:14:16 +0530703 //TODO: annotations used for temporarily later projection/network config will be used
704 private class InternalTopologyListener implements TopologyListener {
705 @Override
706 public void event(TopologyEvent event) {
707 event.reasons().forEach(e -> {
708 //If event type is link removed, get the impacted tunnel
709 if (e instanceof LinkEvent) {
710 LinkEvent linkEvent = (LinkEvent) e;
711 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
712 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530713 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530714 // Check whether this ONOS instance is master for ingress device if yes,
715 // recompute and send update
716 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
717 }
718 });
719 }
720 }
721 });
722 }
723 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530724
Priyanka B3f92c5a2016-05-27 10:14:16 +0530725 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
726 /**
727 * Master of ingress node will recompute and also delegation flag must be set.
728 */
729 if (mastershipService.isLocalMaster(src)
730 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
731 LinkedList<Constraint> constraintList = new LinkedList<>();
732
733 if (tunnel.annotations().value(BANDWIDTH) != null) {
734 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
735 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
736 .annotations().value(BANDWIDTH))));
737 constraintList.add(localConst);
738 }
739 if (tunnel.annotations().value(COST_TYPE) != null) {
740 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
741 COST_TYPE))));
742 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530743
744 /*
745 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
746 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
747 */
748 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530749 // If updation fails store in PCE store as failed path
750 // then PCInitiate (Remove)
751 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
752 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
753 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
754 //Release that tunnel calling PCInitiate
755 releasePath(tunnel.tunnelId());
756 }
757 }
758
759 return false;
760 }
761
762 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530763 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
764 SharedBandwidthConstraint shBwConstraint) {
765 checkNotNull(computedPath);
766 checkNotNull(bandwidthConstraint);
767 Resource resource = null;
768 double bwToAllocate = 0;
769
770 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
771
772 /**
773 * Shared bandwidth sub-case : Lesser bandwidth required than original -
774 * No reservation required.
775 */
776 Double additionalBwValue = null;
777 if (shBwConstraint != null) {
778 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
779 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
780 }
781
782 Optional<ResourceAllocation> resAlloc = null;
783 for (Link link : computedPath.links()) {
784 bwToAllocate = 0;
785 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
786 if (additionalBwValue != null) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530787 bwToAllocate = additionalBwValue;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530788 }
789 } else {
790 bwToAllocate = bandwidthConstraint;
791 }
792
793 /**
794 * In shared bandwidth cases, where new BW is lesser than old BW, it
795 * is not required to allocate anything.
796 */
797 if (bwToAllocate != 0) {
798 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
799 .resource(bwToAllocate);
800 resAlloc = resourceService.allocate(consumer, resource);
801
802 // If allocation for any link fails, then release the partially allocated bandwidth.
803 if (!resAlloc.isPresent()) {
804 resourceService.release(consumer);
805 return null;
806 }
807 }
808 }
809
810 /*
811 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
812 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
813 * to who is supposed to store/delete.
814 */
815 return consumer;
816 }
817
818 /*
819 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
820 */
821 private void releaseBandwidth(Tunnel tunnel) {
822 // Between same source and destination, search the tunnel with same symbolic path name.
823 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
824 Tunnel newTunnel = null;
825 for (Tunnel tunnelObj : tunnelQueryResult) {
826 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
827 newTunnel = tunnelObj;
828 break;
829 }
830 }
831
832 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
833 boolean isLinkShared = false;
834 if (newTunnel != null) {
835 for (Link link : tunnel.path().links()) {
836 if (newTunnel.path().links().contains(link)) {
837 isLinkShared = true;
838 break;
839 }
840 }
841 }
842
843 if (isLinkShared) {
844 releaseSharedBandwidth(newTunnel, tunnel);
845 return;
846 }
847
848 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
849 return;
850
851 /*
852 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
853 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
854 * to who is supposed to store/delete.
855 */
856 }
857
858 /**
859 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
860 * allocated in shared mode initially.
861 */
862 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
863 // 1. Release old tunnel's bandwidth.
864 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
865
Priyanka B4c3b4512016-07-22 11:41:49 +0530866 // 2. Release new tunnel's bandwidth, if new tunnel bandwidth is allocated
867 if (pceStore.getTunnelInfo(newTunnel.tunnelId()) == null) {
868 //If bandwidth for new tunnel is not allocated i,e 0 then no need to allocate
869 return;
870 }
871
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530872 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
873 resourceService.release(consumer);
874
875 // 3. Allocate new tunnel's complete bandwidth.
876 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
877 Resource resource;
878
879 for (Link link : newTunnel.path().links()) {
880 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
881 .resource(bandwidth);
882 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530883
884 }
885 }
886
887 /**
888 * Allocates node label to specific device.
889 *
890 * @param specificDevice device to which node label needs to be allocated
891 */
892 public void allocateNodeLabel(Device specificDevice) {
893 checkNotNull(specificDevice, DEVICE_NULL);
894
895 DeviceId deviceId = specificDevice.id();
896
897 // Retrieve lsrId of a specific device
898 if (specificDevice.annotations() == null) {
899 log.debug("Device {} does not have annotations.", specificDevice.toString());
900 return;
901 }
902
903 String lsrId = specificDevice.annotations().value(LSRID);
904 if (lsrId == null) {
905 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
906 return;
907 }
908
909 // Get capability config from netconfig
910 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
911 if (cfg == null) {
912 log.error("Unable to find corresponding capability for a lsrd {} from NetConfig.", lsrId);
913 // Save info. When PCEP session is comes up then allocate node-label
914 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
915 return;
916 }
917
918 // Check whether device has SR-TE Capability
919 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530920 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530921 }
922 }
923
924 /**
925 * Releases node label of a specific device.
926 *
927 * @param specificDevice this device label and lsr-id information will be
928 * released in other existing devices
929 */
930 public void releaseNodeLabel(Device specificDevice) {
931 checkNotNull(specificDevice, DEVICE_NULL);
932
933 DeviceId deviceId = specificDevice.id();
934
935 // Retrieve lsrId of a specific device
936 if (specificDevice.annotations() == null) {
937 log.debug("Device {} does not have annotations.", specificDevice.toString());
938 return;
939 }
940
941 String lsrId = specificDevice.annotations().value(LSRID);
942 if (lsrId == null) {
943 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
944 return;
945 }
946
947 // Get capability config from netconfig
948 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
949 if (cfg == null) {
950 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
951 return;
952 }
953
954 // Check whether device has SR-TE Capability
955 if (cfg.labelStackCap()) {
956 if (!srTeHandler.releaseNodeLabel(deviceId, lsrId)) {
957 log.error("Unable to release node label for a device id {}.", deviceId.toString());
958 }
959 }
960 }
961
962 /**
963 * Allocates adjacency label for a link.
964 *
965 * @param link link
966 */
967 public void allocateAdjacencyLabel(Link link) {
968 checkNotNull(link, LINK_NULL);
969
970 Device specificDevice = deviceService.getDevice(link.src().deviceId());
971 DeviceId deviceId = specificDevice.id();
972
973 // Retrieve lsrId of a specific device
974 if (specificDevice.annotations() == null) {
975 log.debug("Device {} does not have annotations.", specificDevice.toString());
976 return;
977 }
978
979 String lsrId = specificDevice.annotations().value(LSRID);
980 if (lsrId == null) {
981 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
982 return;
983 }
984
985 // Get capability config from netconfig
986 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
987 if (cfg == null) {
988 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
989 // Save info. When PCEP session comes up then allocate adjacency
990 // label
991 if (lsrIdDeviceIdMap.get(lsrId) != null) {
992 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
993 }
994 return;
995 }
996
997 // Check whether device has SR-TE Capability
998 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530999 srTeHandler.allocateAdjacencyLabel(link);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301000 }
1001
1002 return;
1003 }
1004
1005 /**
1006 * Releases allocated adjacency label of a link.
1007 *
1008 * @param link link
1009 */
1010 public void releaseAdjacencyLabel(Link link) {
1011 checkNotNull(link, LINK_NULL);
1012
1013 Device specificDevice = deviceService.getDevice(link.src().deviceId());
1014 DeviceId deviceId = specificDevice.id();
1015
1016 // Retrieve lsrId of a specific device
1017 if (specificDevice.annotations() == null) {
1018 log.debug("Device {} does not have annotations.", specificDevice.toString());
1019 return;
1020 }
1021
1022 String lsrId = specificDevice.annotations().value(LSRID);
1023 if (lsrId == null) {
1024 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
1025 return;
1026 }
1027
1028 // Get capability config from netconfig
1029 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1030 if (cfg == null) {
1031 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
1032 return;
1033 }
1034
1035 // Check whether device has SR-TE Capability
1036 if (cfg.labelStackCap()) {
1037 if (!srTeHandler.releaseAdjacencyLabel(link)) {
1038 log.error("Unable to release adjacency labels for a link {}.", link.toString());
1039 return;
1040 }
1041 }
1042
1043 return;
1044 }
1045
1046 /*
1047 * Handle device events.
1048 */
1049 private class InternalDeviceListener implements DeviceListener {
1050 @Override
1051 public void event(DeviceEvent event) {
1052 Device specificDevice = (Device) event.subject();
1053 if (specificDevice == null) {
1054 log.error("Unable to find device from device event.");
1055 return;
1056 }
1057
1058 switch (event.type()) {
1059
1060 case DEVICE_ADDED:
1061 // Node-label allocation is being done during Label DB Sync.
1062 // So, when device is detected, no need to do node-label
1063 // allocation.
Avantika-Huawei28b53752016-06-23 17:04:49 +05301064 String lsrId = specificDevice.annotations().value(LSRID);
1065 if (lsrId != null) {
1066 pceStore.addLsrIdDevice(lsrId, specificDevice.id());
1067
1068 // Search in failed DB sync store. If found, trigger label DB sync.
1069 DeviceId pccDeviceId = DeviceId.deviceId(lsrId);
1070 if (pceStore.hasPccLsr(pccDeviceId)) {
1071 log.debug("Continue to perform label DB sync for device {}.", pccDeviceId.toString());
1072 syncLabelDb(pccDeviceId);
1073 pceStore.removePccLsr(pccDeviceId);
1074 }
1075 }
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301076 break;
1077
1078 case DEVICE_REMOVED:
1079 // Release node-label
1080 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1081 releaseNodeLabel(specificDevice);
1082 }
Avantika-Huawei28b53752016-06-23 17:04:49 +05301083
1084 if (specificDevice.annotations().value(LSRID) != null) {
1085 pceStore.removeLsrIdDevice(specificDevice.annotations().value(LSRID));
1086 }
1087
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301088 break;
1089
1090 default:
1091 break;
1092 }
1093 }
1094 }
1095
1096 /*
1097 * Handle link events.
1098 */
1099 private class InternalLinkListener implements LinkListener {
1100 @Override
1101 public void event(LinkEvent event) {
1102 Link link = (Link) event.subject();
1103
1104 switch (event.type()) {
1105
1106 case LINK_ADDED:
1107 // Allocate adjacency label
1108 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1109 allocateAdjacencyLabel(link);
1110 }
1111 break;
1112
1113 case LINK_REMOVED:
1114 // Release adjacency label
1115 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1116 releaseAdjacencyLabel(link);
1117 }
1118 break;
1119
1120 default:
1121 break;
1122 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301123 }
1124 }
1125
1126 // Listens on tunnel events.
1127 private class InnerTunnelListener implements TunnelListener {
1128 @Override
1129 public void event(TunnelEvent event) {
1130 // Event gets generated with old tunnel object.
1131 Tunnel tunnel = event.subject();
1132 if (tunnel.type() != MPLS) {
1133 return;
1134 }
1135
1136 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1137 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1138 double bwConstraintValue = 0;
1139 if (tunnelBandwidth != null) {
1140 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1141 }
1142
1143 switch (event.type()) {
1144 case TUNNEL_ADDED:
1145 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1146 String pceInit = tunnel.annotations().value(PCE_INIT);
1147 if (FALSE.equalsIgnoreCase(pceInit)
1148 && bwConstraintValue != 0) {
1149 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1150 }
1151 break;
1152
1153 case TUNNEL_UPDATED:
1154 // Allocate/send labels for basic PCECC tunnels.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301155 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)
1156 && (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER)) {
1157 if (!crHandler.allocateLabel(tunnel)) {
1158 log.error("Unable to allocate labels for a tunnel {}.", tunnel.toString());
1159 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301160 }
1161
Priyanka B4c3b4512016-07-22 11:41:49 +05301162 //In CR case, release labels when new tunnel for it is updated.
1163 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR && tunnel.state() == ACTIVE
1164 && mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1165 Collection<Tunnel> tunnels = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
1166
1167 for (Tunnel t : tunnels) {
1168 if (tunnel.annotations().value(PLSP_ID).equals(t.annotations().value(PLSP_ID))
1169 && !tunnel.annotations().value(LOCAL_LSP_ID)
1170 .equals(t.annotations().value(LOCAL_LSP_ID))) {
1171 // Release basic PCECC labels.
1172 crHandler.releaseLabel(t);
1173 break;
1174 }
1175 }
1176 }
1177
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301178 if (tunnel.state() == UNSTABLE) {
1179 /*
1180 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1181 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1182 * and setup while global reoptimization.
1183 */
1184
1185 List<Constraint> constraints = new LinkedList<>();
1186 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1187 if (bandwidth != null) {
1188 constraints.add(new BandwidthConstraint(Bandwidth
1189 .bps(Double.parseDouble(bandwidth))));
1190 }
1191
1192 String costType = tunnel.annotations().value(COST_TYPE);
1193 if (costType != null) {
1194 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1195 constraints.add(costConstraint);
1196 }
1197
1198 constraints.add(CapabilityConstraint
1199 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1200
1201 List<Link> links = tunnel.path().links();
1202 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1203 links.get(links.size() - 1).dst().deviceId(),
1204 tunnel.tunnelName().value(), constraints, lspType));
1205 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301206
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301207 break;
1208
1209 case TUNNEL_REMOVED:
1210 if (lspType != WITH_SIGNALLING) {
1211 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1212 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301213 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
Priyanka B4c3b4512016-07-22 11:41:49 +05301214 if (Float.parseFloat(tunnel.annotations().value(BANDWIDTH)) != 0
1215 && mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1216 releaseBandwidth(tunnel);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301217 }
Priyanka B4c3b4512016-07-22 11:41:49 +05301218
1219 if (pceStore.getTunnelInfo(tunnel.tunnelId()) != null) {
1220 pceStore.removeTunnelInfo(tunnel.tunnelId());
1221 }
1222
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301223 break;
1224
1225 default:
1226 break;
1227
1228 }
1229 return;
1230 }
1231 }
1232
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301233 private class InternalConfigListener implements NetworkConfigListener {
1234
1235 @Override
1236 public void event(NetworkConfigEvent event) {
1237
1238 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED)
1239 && event.configClass().equals(DeviceCapability.class)) {
1240
1241 DeviceId deviceIdLsrId = (DeviceId) event.subject();
1242 String lsrId = deviceIdLsrId.toString();
1243 DeviceId deviceId = lsrIdDeviceIdMap.get(lsrId);
1244 if (deviceId == null) {
1245 log.debug("Unable to find device id for a lsr-id {} from lsr-id and device-id map.", lsrId);
1246 return;
1247 }
1248
1249 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1250 if (cfg == null) {
1251 log.error("Unable to find corresponding capabilty for a lsrd {}.", lsrId);
1252 return;
1253 }
1254
1255 if (cfg.labelStackCap()) {
1256 if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
1257 // Allocate node-label
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301258 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301259
1260 // Allocate adjacency label to links which are
1261 // originated from this specific device id
1262 Set<Link> links = linkService.getDeviceEgressLinks(deviceId);
1263 for (Link link : links) {
1264 if (!srTeHandler.allocateAdjacencyLabel(link)) {
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301265 return;
1266 }
1267 }
1268 }
1269 }
1270
1271 // Remove lsrId info from map
1272 lsrIdDeviceIdMap.remove(lsrId);
1273 }
1274 }
1275 }
1276
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301277 private boolean syncLabelDb(DeviceId deviceId) {
1278 checkNotNull(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301279
Avantika-Huawei28b53752016-06-23 17:04:49 +05301280 DeviceId actualDevcieId = pceStore.getLsrIdDevice(deviceId.toString());
1281 if (actualDevcieId == null) {
1282 log.error("Device not available {}.", deviceId.toString());
1283 pceStore.addPccLsr(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301284 return false;
1285 }
1286
Avantika-Huawei28b53752016-06-23 17:04:49 +05301287 Device specificDevice = deviceService.getDevice(actualDevcieId);
1288 if (specificDevice == null) {
1289 log.error("Unable to find device for specific device id {}.", actualDevcieId.toString());
1290 return false;
1291 }
1292
1293 if (pceStore.getGlobalNodeLabel(actualDevcieId) != null) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301294 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301295
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301296 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301297
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301298 // Convert from DeviceId to TunnelEndPoint
1299 Device srcDevice = deviceService.getDevice(entry.getKey());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301300
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301301 /*
1302 * If there is a slight difference in timing such that if device subsystem has removed the device but
1303 * PCE store still has it, just ignore such devices.
1304 */
1305 if (srcDevice == null) {
1306 continue;
1307 }
1308
1309 String srcLsrId = srcDevice.annotations().value(LSRID);
1310 if (srcLsrId == null) {
1311 continue;
1312 }
1313
Avantika-Huawei28b53752016-06-23 17:04:49 +05301314 srTeHandler.advertiseNodeLabelRule(actualDevcieId,
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301315 entry.getValue(),
1316 IpPrefix.valueOf(IpAddress.valueOf(srcLsrId), PREFIX_LENGTH),
1317 Objective.Operation.ADD, false);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301318 }
1319
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301320 Map<Link, LabelResourceId> adjLabelMap = pceStore.getAdjLabels();
1321 for (Entry<Link, LabelResourceId> entry : adjLabelMap.entrySet()) {
Avantika-Huawei28b53752016-06-23 17:04:49 +05301322 if (entry.getKey().src().deviceId().equals(actualDevcieId)) {
1323 srTeHandler.installAdjLabelRule(actualDevcieId,
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301324 entry.getValue(),
1325 entry.getKey().src().port(),
1326 entry.getKey().dst().port(),
1327 Objective.Operation.ADD);
1328 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301329 }
1330 }
1331
Avantika-Huawei28b53752016-06-23 17:04:49 +05301332 srTeHandler.advertiseNodeLabelRule(actualDevcieId,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301333 LabelResourceId.labelResourceId(0),
1334 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
1335 Objective.Operation.ADD, true);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301336
Avantika-Huawei28b53752016-06-23 17:04:49 +05301337 log.debug("End of label DB sync for device {}", actualDevcieId);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301338
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301339 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1340 // Allocate node-label to this specific device.
1341 allocateNodeLabel(specificDevice);
1342
1343 // Allocate adjacency label
1344 Set<Link> links = linkService.getDeviceEgressLinks(specificDevice.id());
1345 if (links != null) {
1346 for (Link link : links) {
1347 allocateAdjacencyLabel(link);
1348 }
1349 }
1350 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301351
1352 return true;
1353 }
1354
1355 // Process the packet received.
1356 private class PcepPacketProcessor implements PacketProcessor {
1357 // Process the packet received and in our case initiates the label DB sync.
1358 @Override
1359 public void process(PacketContext context) {
1360 // Stop processing if the packet has been handled, since we
1361 // can't do any more to it.
Avantika-Huawei3524d852016-06-04 20:44:13 +05301362 log.debug("Received trigger for label DB sync.");
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301363 if (context.isHandled()) {
1364 return;
1365 }
1366
1367 InboundPacket pkt = context.inPacket();
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301368 if (pkt == null) {
1369 return;
1370 }
1371
1372 Ethernet ethernet = pkt.parsed();
1373 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
1374 return;
1375 }
1376
1377 IPv4 ipPacket = (IPv4) ethernet.getPayload();
1378 if (ipPacket == null || ipPacket.getProtocol() != IPv4.PROTOCOL_TCP) {
1379 return;
1380 }
1381
1382 TCP tcp = (TCP) ipPacket.getPayload();
1383 if (tcp == null || tcp.getDestinationPort() != PCEP_PORT) {
1384 return;
1385 }
1386
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301387 syncLabelDb(pkt.receivedFrom().deviceId());
1388 }
1389 }
1390
Priyanka B9fa4ed32016-05-27 11:59:24 +05301391 //Computes path from tunnel store and also path failed to setup.
1392 private void callForOptimization() {
1393 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1394 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1395 checkForMasterAndSetupPath(failedPathInfo);
1396 }
1397
1398 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1399 tunnelService.queryTunnel(MPLS).forEach(t -> {
1400 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1401 });
1402 }
1403
1404 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1405 /**
1406 * Master of ingress node will setup the path failed stored in PCE store.
1407 */
1408 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1409 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
1410 failedPathInfo.constraints(), failedPathInfo.lspType())) {
1411 // If computation is success remove that path
1412 pceStore.removeFailedPathInfo(failedPathInfo);
1413 return true;
1414 }
1415 }
1416
1417 return false;
1418 }
1419
1420 //Timer to call global optimization
1421 private class GlobalOptimizationTimer implements Runnable {
1422
1423 public GlobalOptimizationTimer() {
1424 }
1425
1426 @Override
1427 public void run() {
1428 callForOptimization();
1429 }
1430 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301431}