blob: d4d48086ee9c9a915667b88c33cb31e13e05aba6 [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.Executors;
31import java.util.concurrent.ScheduledExecutorService;
32import java.util.concurrent.TimeUnit;
Avantika-Huawei73862d42016-05-12 18:58:06 +053033
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +053034import org.onlab.packet.Ethernet;
35import org.onlab.packet.IPv4;
36
Avantika-Huawei73862d42016-05-12 18:58:06 +053037import org.apache.felix.scr.annotations.Activate;
38import org.apache.felix.scr.annotations.Component;
39import org.apache.felix.scr.annotations.Deactivate;
40import org.apache.felix.scr.annotations.Reference;
41import org.apache.felix.scr.annotations.ReferenceCardinality;
42import org.apache.felix.scr.annotations.Service;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053043import org.onlab.packet.IpAddress;
44import org.onlab.packet.IpPrefix;
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +053045import org.onlab.packet.TCP;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053046import org.onlab.util.Bandwidth;
Avantika-Huawei73862d42016-05-12 18:58:06 +053047import org.onosproject.core.ApplicationId;
48import org.onosproject.core.CoreService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053049import org.onosproject.incubator.net.resource.label.LabelResourceAdminService;
50import org.onosproject.incubator.net.resource.label.LabelResourceId;
51import org.onosproject.incubator.net.resource.label.LabelResourceService;
Avantika-Huawei73862d42016-05-12 18:58:06 +053052import org.onosproject.core.IdGenerator;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053053import org.onosproject.incubator.net.tunnel.DefaultTunnel;
54import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
55import org.onosproject.incubator.net.tunnel.LabelStack;
Avantika-Huawei73862d42016-05-12 18:58:06 +053056import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053057import org.onosproject.incubator.net.tunnel.TunnelEndPoint;
58import org.onosproject.incubator.net.tunnel.TunnelEvent;
Avantika-Huawei73862d42016-05-12 18:58:06 +053059import org.onosproject.incubator.net.tunnel.TunnelId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053060import org.onosproject.incubator.net.tunnel.TunnelListener;
61import org.onosproject.incubator.net.tunnel.TunnelName;
Avantika-Huawei73862d42016-05-12 18:58:06 +053062import org.onosproject.incubator.net.tunnel.TunnelService;
Priyanka B3f92c5a2016-05-27 10:14:16 +053063import org.onosproject.mastership.MastershipService;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053064import org.onosproject.net.config.NetworkConfigEvent;
65import org.onosproject.net.config.NetworkConfigListener;
Avantika-Huawei032a9872016-05-27 22:57:38 +053066import org.onosproject.net.config.NetworkConfigService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053067import org.onosproject.net.DefaultAnnotations;
68import org.onosproject.net.DefaultAnnotations.Builder;
69import org.onosproject.net.Device;
Avantika-Huawei73862d42016-05-12 18:58:06 +053070import org.onosproject.net.DeviceId;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053071import org.onosproject.net.Link;
Priyanka Bb6963582016-05-20 20:21:20 +053072import org.onosproject.net.Path;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053073import org.onosproject.net.device.DeviceEvent;
74import org.onosproject.net.device.DeviceListener;
Priyanka Bb6963582016-05-20 20:21:20 +053075import org.onosproject.net.device.DeviceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053076import org.onosproject.net.flowobjective.FlowObjectiveService;
77import org.onosproject.net.flowobjective.Objective;
78import org.onosproject.net.intent.Constraint;
79import org.onosproject.net.intent.constraint.BandwidthConstraint;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053080import org.onosproject.net.link.LinkListener;
Priyanka B3f92c5a2016-05-27 10:14:16 +053081import org.onosproject.net.link.LinkEvent;
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +053082import org.onosproject.net.link.LinkService;
83import org.onosproject.net.MastershipRole;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053084import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
85import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
86import org.onosproject.pce.pceservice.constraint.CostConstraint;
87import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
88import org.onosproject.net.resource.Resource;
89import org.onosproject.net.resource.ResourceAllocation;
90import org.onosproject.net.resource.ResourceConsumer;
91import org.onosproject.net.resource.ResourceQueryService;
Priyanka Bb6963582016-05-20 20:21:20 +053092import org.onosproject.net.resource.ResourceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053093import org.onosproject.net.resource.Resources;
Priyanka Bb6963582016-05-20 20:21:20 +053094import org.onosproject.net.topology.LinkWeight;
95import org.onosproject.net.topology.PathService;
96import org.onosproject.net.topology.TopologyEdge;
Priyanka B3f92c5a2016-05-27 10:14:16 +053097import org.onosproject.net.topology.TopologyEvent;
98import org.onosproject.net.topology.TopologyListener;
99import org.onosproject.net.topology.TopologyService;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530100import org.onosproject.pce.pceservice.api.PceService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530101import org.onosproject.pce.pcestore.PcePathInfo;
102import org.onosproject.pce.pcestore.PceccTunnelInfo;
103import org.onosproject.pce.pcestore.api.PceStore;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530104import org.onosproject.pcep.api.DeviceCapability;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530105import org.onosproject.store.serializers.KryoNamespaces;
106import org.onosproject.store.service.DistributedSet;
107import org.onosproject.store.service.Serializer;
108import org.onosproject.store.service.StorageService;
109import org.slf4j.Logger;
110import org.slf4j.LoggerFactory;
111
Priyanka Bb6963582016-05-20 20:21:20 +0530112import com.google.common.collect.ImmutableList;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530113import com.google.common.collect.ImmutableSet;
114
115import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
116import static org.onosproject.incubator.net.tunnel.Tunnel.State.INIT;
117import static org.onosproject.incubator.net.tunnel.Tunnel.State.ESTABLISHED;
118import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
119import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
120import static org.onosproject.pce.pceservice.LspType.SR_WITHOUT_SIGNALLING;
121import static org.onosproject.pce.pceservice.LspType.WITHOUT_SIGNALLING_AND_WITHOUT_SR;
122
123import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
124import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
125import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
126import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
127import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
128import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
129import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
130import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
131
132import org.onosproject.net.packet.InboundPacket;
133import org.onosproject.net.packet.PacketContext;
134import org.onosproject.net.packet.PacketProcessor;
135import org.onosproject.net.packet.PacketService;
Priyanka Bb6963582016-05-20 20:21:20 +0530136
Avantika-Huawei73862d42016-05-12 18:58:06 +0530137/**
138 * Implementation of PCE service.
139 */
140@Component(immediate = true)
141@Service
142public class PceManager implements PceService {
143 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
144
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530145 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
146 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
147 private static final String DEVICE_NULL = "Device-cannot be null";
148 private static final String LINK_NULL = "Link-cannot be null";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530149 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530150 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530151 public static final String DEVICE_TYPE = "type";
152 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530153 private static final int PREFIX_LENGTH = 32;
154
155 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
156 private IdGenerator tunnelConsumerIdGen;
157
158 private static final String LSRID = "lsrId";
159 private static final String TRUE = "true";
160 private static final String FALSE = "false";
161 private static final String END_OF_SYNC_IP_PREFIX = "0.0.0.0/32";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530162 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530163
Avantika-Huawei73862d42016-05-12 18:58:06 +0530164 private IdGenerator localLspIdIdGen;
165 protected DistributedSet<Short> localLspIdFreeList;
166
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530167 // LSR-id and device-id mapping for checking capability if L3 device is not
168 // having its capability
169 private Map<String, DeviceId> lsrIdDeviceIdMap = new HashMap<>();
170
Avantika-Huawei73862d42016-05-12 18:58:06 +0530171 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
172 protected CoreService coreService;
173
174 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530175 protected ResourceService resourceService;
176
177 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
178 protected ResourceQueryService resourceQueryService;
179
180 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
181 protected PathService pathService;
182
183 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
184 protected PceStore pceStore;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530187 protected TunnelService tunnelService;
188
189 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
190 protected StorageService storageService;
191
Priyanka Bb6963582016-05-20 20:21:20 +0530192 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530193 protected PacketService packetService;
Priyanka Bb6963582016-05-20 20:21:20 +0530194
195 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
196 protected DeviceService deviceService;
197
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530198 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530199 protected LinkService linkService;
200
201 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530202 protected NetworkConfigService netCfgService;
203
204 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530205 protected LabelResourceAdminService labelRsrcAdminService;
206
207 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
208 protected LabelResourceService labelRsrcService;
209
210 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
211 protected FlowObjectiveService flowObjectiveService;
212
Priyanka B3f92c5a2016-05-27 10:14:16 +0530213 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
214 protected MastershipService mastershipService;
215
216 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
217 protected TopologyService topologyService;
218
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530219 private TunnelListener listener = new InnerTunnelListener();
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530220 private DeviceListener deviceListener = new InternalDeviceListener();
221 private LinkListener linkListener = new InternalLinkListener();
222 private InternalConfigListener cfgListener = new InternalConfigListener();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530223 private BasicPceccHandler crHandler;
224 private PceccSrTeBeHandler srTeHandler;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530225 private ApplicationId appId;
226
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530227 private final PcepPacketProcessor processor = new PcepPacketProcessor();
Priyanka B3f92c5a2016-05-27 10:14:16 +0530228 private final TopologyListener topologyListener = new InternalTopologyListener();
Priyanka B9fa4ed32016-05-27 11:59:24 +0530229 private ScheduledExecutorService executor;
230
231 public static final int INITIAL_DELAY = 30;
232 public static final int PERIODIC_DELAY = 30;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530233
Avantika-Huawei73862d42016-05-12 18:58:06 +0530234 /**
235 * Creates new instance of PceManager.
236 */
237 public PceManager() {
238 }
239
240 @Activate
241 protected void activate() {
242 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530243 crHandler = BasicPceccHandler.getInstance();
244 crHandler.initialize(labelRsrcService, flowObjectiveService, appId, pceStore);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530245
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530246 srTeHandler = PceccSrTeBeHandler.getInstance();
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530247 srTeHandler.initialize(labelRsrcAdminService, labelRsrcService, flowObjectiveService, appId, pceStore,
248 deviceService);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530249
250 tunnelService.addListener(listener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530251 deviceService.addListener(deviceListener);
252 linkService.addListener(linkListener);
253 netCfgService.addListener(cfgListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530254
255 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530256 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
257 localLspIdFreeList = storageService.<Short>setBuilder()
258 .withName("pcepLocalLspIdDeletedList")
259 .withSerializer(Serializer.using(KryoNamespaces.API))
260 .build()
261 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530262
263 packetService.addProcessor(processor, PacketProcessor.director(4));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530264 topologyService.addListener(topologyListener);
Priyanka B9fa4ed32016-05-27 11:59:24 +0530265 executor = Executors.newSingleThreadScheduledExecutor();
266 //Start a timer when the component is up, with initial delay of 30min and periodic delays at 30min
267 executor.scheduleAtFixedRate(new GlobalOptimizationTimer(), INITIAL_DELAY, PERIODIC_DELAY, TimeUnit.MINUTES);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530268
269 // Reserve global node pool
270 if (!srTeHandler.reserveGlobalPool(GLOBAL_LABEL_SPACE_MIN, GLOBAL_LABEL_SPACE_MAX)) {
271 log.debug("Global node pool was already reserved.");
272 }
273
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530274 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530275 }
276
277 @Deactivate
278 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530279 tunnelService.removeListener(listener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530280 deviceService.removeListener(deviceListener);
281 linkService.removeListener(linkListener);
282 netCfgService.removeListener(cfgListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530283 packetService.removeProcessor(processor);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530284 topologyService.removeListener(topologyListener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530285 // Shutdown the thread when component is deactivated
Priyanka B9fa4ed32016-05-27 11:59:24 +0530286 executor.shutdown();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530287 log.info("Stopped");
288 }
289
Priyanka Bb6963582016-05-20 20:21:20 +0530290 /**
291 * Returns an edge-weight capable of evaluating links on the basis of the
292 * specified constraints.
293 *
294 * @param constraints path constraints
295 * @return edge-weight function
296 */
297 private LinkWeight weight(List<Constraint> constraints) {
298 return new TeConstraintBasedLinkWeight(constraints);
299 }
300
301 /**
302 * Computes a path between two devices.
303 *
304 * @param src ingress device
305 * @param dst egress device
306 * @param constraints path constraints
307 * @return computed path based on constraints
308 */
309 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
310 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530311 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530312 }
313 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
314 if (!paths.isEmpty()) {
315 return paths;
316 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530317 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530318 }
319
Avantika-Huawei73862d42016-05-12 18:58:06 +0530320 //[TODO:] handle requests in queue
321 @Override
322 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
323 LspType lspType) {
324 checkNotNull(src);
325 checkNotNull(dst);
326 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530327 checkNotNull(lspType);
328
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530329 // Convert from DeviceId to TunnelEndPoint
330 Device srcDevice = deviceService.getDevice(src);
331 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530332
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530333 if (srcDevice == null || dstDevice == null) {
334 // Device is not known.
335 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
336 return false;
337 }
338
339 // In future projections instead of annotations will be used to fetch LSR ID.
340 String srcLsrId = srcDevice.annotations().value(LSRID);
341 String dstLsrId = dstDevice.annotations().value(LSRID);
342
343 if (srcLsrId == null || dstLsrId == null) {
344 // LSR id is not known.
345 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
346 return false;
347 }
348
Avantika-Huawei032a9872016-05-27 22:57:38 +0530349 // Get device config from netconfig, to ascertain that session with ingress is present.
350 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
351 if (cfg == null) {
352 log.debug("No session to ingress.");
353 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
354 return false;
355 }
356
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530357 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
358 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
359
360 double bwConstraintValue = 0;
361 CostConstraint costConstraint = null;
362 if (constraints != null) {
363 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
364 Iterator<Constraint> iterator = constraints.iterator();
365
366 while (iterator.hasNext()) {
367 Constraint constraint = iterator.next();
368 if (constraint instanceof BandwidthConstraint) {
369 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
370 } else if (constraint instanceof CostConstraint) {
371 costConstraint = (CostConstraint) constraint;
372 }
373 }
374
375 /*
376 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
377 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
378 * function can either return the result of limiting/capability constraint validation or the value of link
379 * cost, depending upon what is the last constraint in the loop.
380 */
381 if (costConstraint != null) {
382 constraints.remove(costConstraint);
383 constraints.add(costConstraint);
384 }
385 } else {
386 constraints = new LinkedList<>();
387 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
388 }
389
390 Set<Path> computedPathSet = computePath(src, dst, constraints);
391
392 // NO-PATH
393 if (computedPathSet.isEmpty()) {
394 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
395 return false;
396 }
397
398 Builder annotationBuilder = DefaultAnnotations.builder();
399 if (bwConstraintValue != 0) {
400 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
401 }
402 if (costConstraint != null) {
403 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
404 }
405 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
406 annotationBuilder.set(PCE_INIT, TRUE);
407 annotationBuilder.set(DELEGATE, TRUE);
408
409 Path computedPath = computedPathSet.iterator().next();
410 LabelStack labelStack = null;
411
412 if (lspType == SR_WITHOUT_SIGNALLING) {
413 labelStack = srTeHandler.computeLabelStack(computedPath);
414 // Failed to form a label stack.
415 if (labelStack == null) {
416 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
417 return false;
418 }
419 }
420
421 if (lspType != WITH_SIGNALLING) {
422 /*
423 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
424 * PCE for non-RSVP signalled LSPs.
425 */
426 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
427 }
428
429 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
430 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
431 TunnelName.tunnelName(tunnelName), computedPath,
432 labelStack, annotationBuilder.build());
433
434 // Allocate bandwidth.
435 TunnelConsumerId consumerId = null;
436 if (bwConstraintValue != 0) {
437 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
438 if (consumerId == null) {
439 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
440 return false;
441 }
442 }
443
444 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
445 if (tunnelId == null) {
446 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
447 if (consumerId != null) {
448 resourceService.release(consumerId);
449 }
450 return false;
451 }
452
453 if (consumerId != null) {
454 // Store tunnel consumer id in LSP-Label store.
455 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
456 pceStore.addTunnelInfo(tunnelId, pceccTunnelInfo);
457 }
458 return true;
459 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530460
461 @Override
462 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
463 checkNotNull(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530464 Set<Path> computedPathSet = null;
465 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530466
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530467 if (tunnel == null) {
468 return false;
469 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530470
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530471 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
472 // Only delegated LSPs can be updated.
473 return false;
474 }
475
476 List<Link> links = tunnel.path().links();
477 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
478 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530479 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530480 SharedBandwidthConstraint shBwConstraint = null;
481 BandwidthConstraint bwConstraint = null;
482 CostConstraint costConstraint = null;
483
484 if (constraints != null) {
485 // Call path computation in shared bandwidth mode.
486 Iterator<Constraint> iterator = constraints.iterator();
487 while (iterator.hasNext()) {
488 Constraint constraint = iterator.next();
489 if (constraint instanceof BandwidthConstraint) {
490 bwConstraint = (BandwidthConstraint) constraint;
491 bwConstraintValue = bwConstraint.bandwidth().bps();
492 } else if (constraint instanceof CostConstraint) {
493 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530494 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530495 }
496 }
497
498 // Remove and keep the cost constraint at the end of the list of constraints.
499 if (costConstraint != null) {
500 constraints.remove(costConstraint);
501 }
502
503 Bandwidth existingBwValue = null;
504 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
505 if (existingBwAnnotation != null) {
506 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
507
508 /*
509 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
510 * has been utilized to create shared bandwidth constraint.
511 */
512 if (bwConstraint != null) {
513 constraints.remove(bwConstraint);
514 }
515 }
516
517 if (existingBwValue != null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530518 if (bwConstraintValue == 0) {
519 bwConstraintValue = existingBwValue.bps();
520 }
521 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
522 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
523 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
524 existingBwValue, existingBwValue);
525
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530526 constraints.add(shBwConstraint);
527 }
528 } else {
529 constraints = new LinkedList<>();
530 }
531
532 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
533 if (costConstraint != null) {
534 constraints.add(costConstraint);
535 }
536
537 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
538 constraints);
539
540 // NO-PATH
541 if (computedPathSet.isEmpty()) {
542 return false;
543 }
544
545 Builder annotationBuilder = DefaultAnnotations.builder();
546 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530547 if (costType != null) {
548 annotationBuilder.set(COST_TYPE, costType);
549 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530550 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
551 annotationBuilder.set(PCE_INIT, TRUE);
552 annotationBuilder.set(DELEGATE, TRUE);
553 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
554 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
555
556 Path computedPath = computedPathSet.iterator().next();
557 LabelStack labelStack = null;
558 TunnelConsumerId consumerId = null;
559 LspType lspType = LspType.valueOf(lspSigType);
560 long localLspId = 0;
561 if (lspType != WITH_SIGNALLING) {
562 /*
563 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
564 * PCE for non-RSVP signalled LSPs.
565 */
566 localLspId = getNextLocalLspId();
567 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
568
569 if (lspType == SR_WITHOUT_SIGNALLING) {
570 labelStack = srTeHandler.computeLabelStack(computedPath);
571 // Failed to form a label stack.
572 if (labelStack == null) {
573 return false;
574 }
575 }
576 }
577
578 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
579 tunnel.tunnelName(), computedPath,
580 labelStack, annotationBuilder.build());
581
582 // Allocate shared bandwidth.
583 if (bwConstraintValue != 0) {
584 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
585 if (consumerId == null) {
586 return false;
587 }
588 }
589
590 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
591 computedPath);
592
593 if (updatedTunnelId == null) {
594 if (consumerId != null) {
595 resourceService.release(consumerId);
596 }
597 return false;
598 }
599
600 if (consumerId != null) {
601 // Store tunnel consumer id in LSP-Label store.
602 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
603 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
604 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530605 return true;
606 }
607
608 @Override
609 public boolean releasePath(TunnelId tunnelId) {
610 checkNotNull(tunnelId);
611 // 1. Query Tunnel from Tunnel manager.
612 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
613
614 if (tunnel == null) {
615 return false;
616 }
617
618 // 2. Call tunnel service.
619 return tunnelService.downTunnel(appId, tunnel.tunnelId());
620 }
621
622 @Override
623 public Iterable<Tunnel> queryAllPath() {
624 return tunnelService.queryTunnel(MPLS);
625 }
626
627 @Override
628 public Tunnel queryPath(TunnelId tunnelId) {
629 return tunnelService.queryTunnel(tunnelId);
630 }
631
632 /**
633 * Returns the next local LSP identifier to be used either by getting from
634 * freed list if available otherwise generating a new one.
635 *
636 * @return value of local LSP identifier
637 */
638 private short getNextLocalLspId() {
639 // If there is any free id use it. Otherwise generate new id.
640 if (localLspIdFreeList.isEmpty()) {
641 return (short) localLspIdIdGen.getNewId();
642 }
643 Iterator<Short> it = localLspIdFreeList.iterator();
644 Short value = it.next();
645 localLspIdFreeList.remove(value);
646 return value;
647 }
648
Priyanka Bb6963582016-05-20 20:21:20 +0530649 protected class TeConstraintBasedLinkWeight implements LinkWeight {
650
651 private final List<Constraint> constraints;
652
653 /**
654 * Creates a new edge-weight function capable of evaluating links
655 * on the basis of the specified constraints.
656 *
657 * @param constraints path constraints
658 */
659 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
660 if (constraints == null) {
661 this.constraints = Collections.emptyList();
662 } else {
663 this.constraints = ImmutableList.copyOf(constraints);
664 }
665 }
666
667 @Override
668 public double weight(TopologyEdge edge) {
669 if (!constraints.iterator().hasNext()) {
670 //Takes default cost/hopcount as 1 if no constraints specified
671 return 1.0;
672 }
673
674 Iterator<Constraint> it = constraints.iterator();
675 double cost = 1;
676
677 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
678 while (it.hasNext() && cost > 0) {
679 Constraint constraint = it.next();
680 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530681 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
682 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530683 } else {
684 cost = constraint.cost(edge.link(), resourceService::isAvailable);
685 }
686 }
687 return cost;
688 }
689 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530690
Priyanka B3f92c5a2016-05-27 10:14:16 +0530691 //TODO: annotations used for temporarily later projection/network config will be used
692 private class InternalTopologyListener implements TopologyListener {
693 @Override
694 public void event(TopologyEvent event) {
695 event.reasons().forEach(e -> {
696 //If event type is link removed, get the impacted tunnel
697 if (e instanceof LinkEvent) {
698 LinkEvent linkEvent = (LinkEvent) e;
699 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
700 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530701 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530702 // Check whether this ONOS instance is master for ingress device if yes,
703 // recompute and send update
704 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
705 }
706 });
707 }
708 }
709 });
710 }
711 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530712
Priyanka B3f92c5a2016-05-27 10:14:16 +0530713 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
714 /**
715 * Master of ingress node will recompute and also delegation flag must be set.
716 */
717 if (mastershipService.isLocalMaster(src)
718 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
719 LinkedList<Constraint> constraintList = new LinkedList<>();
720
721 if (tunnel.annotations().value(BANDWIDTH) != null) {
722 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
723 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
724 .annotations().value(BANDWIDTH))));
725 constraintList.add(localConst);
726 }
727 if (tunnel.annotations().value(COST_TYPE) != null) {
728 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
729 COST_TYPE))));
730 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530731
732 /*
733 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
734 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
735 */
736 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530737 // If updation fails store in PCE store as failed path
738 // then PCInitiate (Remove)
739 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
740 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
741 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
742 //Release that tunnel calling PCInitiate
743 releasePath(tunnel.tunnelId());
744 }
745 }
746
747 return false;
748 }
749
750 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530751 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
752 SharedBandwidthConstraint shBwConstraint) {
753 checkNotNull(computedPath);
754 checkNotNull(bandwidthConstraint);
755 Resource resource = null;
756 double bwToAllocate = 0;
757
758 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
759
760 /**
761 * Shared bandwidth sub-case : Lesser bandwidth required than original -
762 * No reservation required.
763 */
764 Double additionalBwValue = null;
765 if (shBwConstraint != null) {
766 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
767 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
768 }
769
770 Optional<ResourceAllocation> resAlloc = null;
771 for (Link link : computedPath.links()) {
772 bwToAllocate = 0;
773 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
774 if (additionalBwValue != null) {
775 bwToAllocate = bandwidthConstraint - additionalBwValue;
776 }
777 } else {
778 bwToAllocate = bandwidthConstraint;
779 }
780
781 /**
782 * In shared bandwidth cases, where new BW is lesser than old BW, it
783 * is not required to allocate anything.
784 */
785 if (bwToAllocate != 0) {
786 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
787 .resource(bwToAllocate);
788 resAlloc = resourceService.allocate(consumer, resource);
789
790 // If allocation for any link fails, then release the partially allocated bandwidth.
791 if (!resAlloc.isPresent()) {
792 resourceService.release(consumer);
793 return null;
794 }
795 }
796 }
797
798 /*
799 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
800 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
801 * to who is supposed to store/delete.
802 */
803 return consumer;
804 }
805
806 /*
807 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
808 */
809 private void releaseBandwidth(Tunnel tunnel) {
810 // Between same source and destination, search the tunnel with same symbolic path name.
811 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
812 Tunnel newTunnel = null;
813 for (Tunnel tunnelObj : tunnelQueryResult) {
814 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
815 newTunnel = tunnelObj;
816 break;
817 }
818 }
819
820 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
821 boolean isLinkShared = false;
822 if (newTunnel != null) {
823 for (Link link : tunnel.path().links()) {
824 if (newTunnel.path().links().contains(link)) {
825 isLinkShared = true;
826 break;
827 }
828 }
829 }
830
831 if (isLinkShared) {
832 releaseSharedBandwidth(newTunnel, tunnel);
833 return;
834 }
835
836 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
837 return;
838
839 /*
840 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
841 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
842 * to who is supposed to store/delete.
843 */
844 }
845
846 /**
847 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
848 * allocated in shared mode initially.
849 */
850 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
851 // 1. Release old tunnel's bandwidth.
852 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
853
854 // 2. Release new tunnel's bandwidth
855 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
856 resourceService.release(consumer);
857
858 // 3. Allocate new tunnel's complete bandwidth.
859 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
860 Resource resource;
861
862 for (Link link : newTunnel.path().links()) {
863 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
864 .resource(bandwidth);
865 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530866
867 }
868 }
869
870 /**
871 * Allocates node label to specific device.
872 *
873 * @param specificDevice device to which node label needs to be allocated
874 */
875 public void allocateNodeLabel(Device specificDevice) {
876 checkNotNull(specificDevice, DEVICE_NULL);
877
878 DeviceId deviceId = specificDevice.id();
879
880 // Retrieve lsrId of a specific device
881 if (specificDevice.annotations() == null) {
882 log.debug("Device {} does not have annotations.", specificDevice.toString());
883 return;
884 }
885
886 String lsrId = specificDevice.annotations().value(LSRID);
887 if (lsrId == null) {
888 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
889 return;
890 }
891
892 // Get capability config from netconfig
893 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
894 if (cfg == null) {
895 log.error("Unable to find corresponding capability for a lsrd {} from NetConfig.", lsrId);
896 // Save info. When PCEP session is comes up then allocate node-label
897 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
898 return;
899 }
900
901 // Check whether device has SR-TE Capability
902 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530903 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530904 }
905 }
906
907 /**
908 * Releases node label of a specific device.
909 *
910 * @param specificDevice this device label and lsr-id information will be
911 * released in other existing devices
912 */
913 public void releaseNodeLabel(Device specificDevice) {
914 checkNotNull(specificDevice, DEVICE_NULL);
915
916 DeviceId deviceId = specificDevice.id();
917
918 // Retrieve lsrId of a specific device
919 if (specificDevice.annotations() == null) {
920 log.debug("Device {} does not have annotations.", specificDevice.toString());
921 return;
922 }
923
924 String lsrId = specificDevice.annotations().value(LSRID);
925 if (lsrId == null) {
926 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
927 return;
928 }
929
930 // Get capability config from netconfig
931 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
932 if (cfg == null) {
933 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
934 return;
935 }
936
937 // Check whether device has SR-TE Capability
938 if (cfg.labelStackCap()) {
939 if (!srTeHandler.releaseNodeLabel(deviceId, lsrId)) {
940 log.error("Unable to release node label for a device id {}.", deviceId.toString());
941 }
942 }
943 }
944
945 /**
946 * Allocates adjacency label for a link.
947 *
948 * @param link link
949 */
950 public void allocateAdjacencyLabel(Link link) {
951 checkNotNull(link, LINK_NULL);
952
953 Device specificDevice = deviceService.getDevice(link.src().deviceId());
954 DeviceId deviceId = specificDevice.id();
955
956 // Retrieve lsrId of a specific device
957 if (specificDevice.annotations() == null) {
958 log.debug("Device {} does not have annotations.", specificDevice.toString());
959 return;
960 }
961
962 String lsrId = specificDevice.annotations().value(LSRID);
963 if (lsrId == null) {
964 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
965 return;
966 }
967
968 // Get capability config from netconfig
969 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
970 if (cfg == null) {
971 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
972 // Save info. When PCEP session comes up then allocate adjacency
973 // label
974 if (lsrIdDeviceIdMap.get(lsrId) != null) {
975 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
976 }
977 return;
978 }
979
980 // Check whether device has SR-TE Capability
981 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530982 srTeHandler.allocateAdjacencyLabel(link);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530983 }
984
985 return;
986 }
987
988 /**
989 * Releases allocated adjacency label of a link.
990 *
991 * @param link link
992 */
993 public void releaseAdjacencyLabel(Link link) {
994 checkNotNull(link, LINK_NULL);
995
996 Device specificDevice = deviceService.getDevice(link.src().deviceId());
997 DeviceId deviceId = specificDevice.id();
998
999 // Retrieve lsrId of a specific device
1000 if (specificDevice.annotations() == null) {
1001 log.debug("Device {} does not have annotations.", specificDevice.toString());
1002 return;
1003 }
1004
1005 String lsrId = specificDevice.annotations().value(LSRID);
1006 if (lsrId == null) {
1007 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
1008 return;
1009 }
1010
1011 // Get capability config from netconfig
1012 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1013 if (cfg == null) {
1014 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
1015 return;
1016 }
1017
1018 // Check whether device has SR-TE Capability
1019 if (cfg.labelStackCap()) {
1020 if (!srTeHandler.releaseAdjacencyLabel(link)) {
1021 log.error("Unable to release adjacency labels for a link {}.", link.toString());
1022 return;
1023 }
1024 }
1025
1026 return;
1027 }
1028
1029 /*
1030 * Handle device events.
1031 */
1032 private class InternalDeviceListener implements DeviceListener {
1033 @Override
1034 public void event(DeviceEvent event) {
1035 Device specificDevice = (Device) event.subject();
1036 if (specificDevice == null) {
1037 log.error("Unable to find device from device event.");
1038 return;
1039 }
1040
1041 switch (event.type()) {
1042
1043 case DEVICE_ADDED:
1044 // Node-label allocation is being done during Label DB Sync.
1045 // So, when device is detected, no need to do node-label
1046 // allocation.
1047 break;
1048
1049 case DEVICE_REMOVED:
1050 // Release node-label
1051 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1052 releaseNodeLabel(specificDevice);
1053 }
1054 break;
1055
1056 default:
1057 break;
1058 }
1059 }
1060 }
1061
1062 /*
1063 * Handle link events.
1064 */
1065 private class InternalLinkListener implements LinkListener {
1066 @Override
1067 public void event(LinkEvent event) {
1068 Link link = (Link) event.subject();
1069
1070 switch (event.type()) {
1071
1072 case LINK_ADDED:
1073 // Allocate adjacency label
1074 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1075 allocateAdjacencyLabel(link);
1076 }
1077 break;
1078
1079 case LINK_REMOVED:
1080 // Release adjacency label
1081 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1082 releaseAdjacencyLabel(link);
1083 }
1084 break;
1085
1086 default:
1087 break;
1088 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301089 }
1090 }
1091
1092 // Listens on tunnel events.
1093 private class InnerTunnelListener implements TunnelListener {
1094 @Override
1095 public void event(TunnelEvent event) {
1096 // Event gets generated with old tunnel object.
1097 Tunnel tunnel = event.subject();
1098 if (tunnel.type() != MPLS) {
1099 return;
1100 }
1101
1102 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1103 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1104 double bwConstraintValue = 0;
1105 if (tunnelBandwidth != null) {
1106 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1107 }
1108
1109 switch (event.type()) {
1110 case TUNNEL_ADDED:
1111 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1112 String pceInit = tunnel.annotations().value(PCE_INIT);
1113 if (FALSE.equalsIgnoreCase(pceInit)
1114 && bwConstraintValue != 0) {
1115 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1116 }
1117 break;
1118
1119 case TUNNEL_UPDATED:
1120 // Allocate/send labels for basic PCECC tunnels.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301121 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)
1122 && (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER)) {
1123 if (!crHandler.allocateLabel(tunnel)) {
1124 log.error("Unable to allocate labels for a tunnel {}.", tunnel.toString());
1125 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301126 }
1127
1128 if (tunnel.state() == UNSTABLE) {
1129 /*
1130 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1131 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1132 * and setup while global reoptimization.
1133 */
1134
1135 List<Constraint> constraints = new LinkedList<>();
1136 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1137 if (bandwidth != null) {
1138 constraints.add(new BandwidthConstraint(Bandwidth
1139 .bps(Double.parseDouble(bandwidth))));
1140 }
1141
1142 String costType = tunnel.annotations().value(COST_TYPE);
1143 if (costType != null) {
1144 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1145 constraints.add(costConstraint);
1146 }
1147
1148 constraints.add(CapabilityConstraint
1149 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1150
1151 List<Link> links = tunnel.path().links();
1152 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1153 links.get(links.size() - 1).dst().deviceId(),
1154 tunnel.tunnelName().value(), constraints, lspType));
1155 }
1156 break;
1157
1158 case TUNNEL_REMOVED:
1159 if (lspType != WITH_SIGNALLING) {
1160 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1161 }
1162
1163 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
1164 if (bwConstraintValue != 0) {
1165 releaseBandwidth(event.subject());
1166
1167 // Release basic PCECC labels.
1168 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
1169 // Delete stored tunnel consumer id from PCE store (while still retaining label list.)
1170 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
1171 pceccTunnelInfo.tunnelConsumerId(null);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301172 if (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1173 crHandler.releaseLabel(tunnel);
1174 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301175 } else {
1176 pceStore.removeTunnelInfo(tunnel.tunnelId());
1177 }
1178 }
1179 break;
1180
1181 default:
1182 break;
1183
1184 }
1185 return;
1186 }
1187 }
1188
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301189 private class InternalConfigListener implements NetworkConfigListener {
1190
1191 @Override
1192 public void event(NetworkConfigEvent event) {
1193
1194 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED)
1195 && event.configClass().equals(DeviceCapability.class)) {
1196
1197 DeviceId deviceIdLsrId = (DeviceId) event.subject();
1198 String lsrId = deviceIdLsrId.toString();
1199 DeviceId deviceId = lsrIdDeviceIdMap.get(lsrId);
1200 if (deviceId == null) {
1201 log.debug("Unable to find device id for a lsr-id {} from lsr-id and device-id map.", lsrId);
1202 return;
1203 }
1204
1205 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1206 if (cfg == null) {
1207 log.error("Unable to find corresponding capabilty for a lsrd {}.", lsrId);
1208 return;
1209 }
1210
1211 if (cfg.labelStackCap()) {
1212 if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
1213 // Allocate node-label
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301214 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301215
1216 // Allocate adjacency label to links which are
1217 // originated from this specific device id
1218 Set<Link> links = linkService.getDeviceEgressLinks(deviceId);
1219 for (Link link : links) {
1220 if (!srTeHandler.allocateAdjacencyLabel(link)) {
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301221 return;
1222 }
1223 }
1224 }
1225 }
1226
1227 // Remove lsrId info from map
1228 lsrIdDeviceIdMap.remove(lsrId);
1229 }
1230 }
1231 }
1232
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301233 private boolean syncLabelDb(DeviceId deviceId) {
1234 checkNotNull(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301235
1236 Device specificDevice = deviceService.getDevice(deviceId);
1237 if (specificDevice == null) {
1238 log.error("Unable to find device for specific device id {}.", deviceId.toString());
1239 return false;
1240 }
1241
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301242 if (pceStore.getGlobalNodeLabel(deviceId) != null) {
1243 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301244
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301245 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301246
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301247 // Convert from DeviceId to TunnelEndPoint
1248 Device srcDevice = deviceService.getDevice(entry.getKey());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301249
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301250 /*
1251 * If there is a slight difference in timing such that if device subsystem has removed the device but
1252 * PCE store still has it, just ignore such devices.
1253 */
1254 if (srcDevice == null) {
1255 continue;
1256 }
1257
1258 String srcLsrId = srcDevice.annotations().value(LSRID);
1259 if (srcLsrId == null) {
1260 continue;
1261 }
1262
1263 srTeHandler.advertiseNodeLabelRule(deviceId,
1264 entry.getValue(),
1265 IpPrefix.valueOf(IpAddress.valueOf(srcLsrId), PREFIX_LENGTH),
1266 Objective.Operation.ADD, false);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301267 }
1268
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301269 Map<Link, LabelResourceId> adjLabelMap = pceStore.getAdjLabels();
1270 for (Entry<Link, LabelResourceId> entry : adjLabelMap.entrySet()) {
1271 if (entry.getKey().src().deviceId().equals(deviceId)) {
1272 srTeHandler.installAdjLabelRule(deviceId,
1273 entry.getValue(),
1274 entry.getKey().src().port(),
1275 entry.getKey().dst().port(),
1276 Objective.Operation.ADD);
1277 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301278 }
1279 }
1280
1281 srTeHandler.advertiseNodeLabelRule(deviceId,
1282 LabelResourceId.labelResourceId(0),
1283 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
1284 Objective.Operation.ADD, true);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301285
1286 log.debug("End of label DB sync for device {}", deviceId);
1287
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301288 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1289 // Allocate node-label to this specific device.
1290 allocateNodeLabel(specificDevice);
1291
1292 // Allocate adjacency label
1293 Set<Link> links = linkService.getDeviceEgressLinks(specificDevice.id());
1294 if (links != null) {
1295 for (Link link : links) {
1296 allocateAdjacencyLabel(link);
1297 }
1298 }
1299 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301300
1301 return true;
1302 }
1303
1304 // Process the packet received.
1305 private class PcepPacketProcessor implements PacketProcessor {
1306 // Process the packet received and in our case initiates the label DB sync.
1307 @Override
1308 public void process(PacketContext context) {
1309 // Stop processing if the packet has been handled, since we
1310 // can't do any more to it.
Avantika-Huawei3524d852016-06-04 20:44:13 +05301311 log.debug("Received trigger for label DB sync.");
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301312 if (context.isHandled()) {
1313 return;
1314 }
1315
1316 InboundPacket pkt = context.inPacket();
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301317 if (pkt == null) {
1318 return;
1319 }
1320
1321 Ethernet ethernet = pkt.parsed();
1322 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
1323 return;
1324 }
1325
1326 IPv4 ipPacket = (IPv4) ethernet.getPayload();
1327 if (ipPacket == null || ipPacket.getProtocol() != IPv4.PROTOCOL_TCP) {
1328 return;
1329 }
1330
1331 TCP tcp = (TCP) ipPacket.getPayload();
1332 if (tcp == null || tcp.getDestinationPort() != PCEP_PORT) {
1333 return;
1334 }
1335
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301336 syncLabelDb(pkt.receivedFrom().deviceId());
1337 }
1338 }
1339
Priyanka B9fa4ed32016-05-27 11:59:24 +05301340 //Computes path from tunnel store and also path failed to setup.
1341 private void callForOptimization() {
1342 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1343 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1344 checkForMasterAndSetupPath(failedPathInfo);
1345 }
1346
1347 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1348 tunnelService.queryTunnel(MPLS).forEach(t -> {
1349 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1350 });
1351 }
1352
1353 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1354 /**
1355 * Master of ingress node will setup the path failed stored in PCE store.
1356 */
1357 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1358 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
1359 failedPathInfo.constraints(), failedPathInfo.lspType())) {
1360 // If computation is success remove that path
1361 pceStore.removeFailedPathInfo(failedPathInfo);
1362 return true;
1363 }
1364 }
1365
1366 return false;
1367 }
1368
1369 //Timer to call global optimization
1370 private class GlobalOptimizationTimer implements Runnable {
1371
1372 public GlobalOptimizationTimer() {
1373 }
1374
1375 @Override
1376 public void run() {
1377 callForOptimization();
1378 }
1379 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301380}