blob: 2e148db95155a6468064585abce8c4e2bdfd01bd [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) {
518 shBwConstraint = new SharedBandwidthConstraint(links, existingBwValue, bwConstraint.bandwidth());
519 constraints.add(shBwConstraint);
520 }
521 } else {
522 constraints = new LinkedList<>();
523 }
524
525 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
526 if (costConstraint != null) {
527 constraints.add(costConstraint);
528 }
529
530 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
531 constraints);
532
533 // NO-PATH
534 if (computedPathSet.isEmpty()) {
535 return false;
536 }
537
538 Builder annotationBuilder = DefaultAnnotations.builder();
539 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530540 if (costType != null) {
541 annotationBuilder.set(COST_TYPE, costType);
542 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530543 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
544 annotationBuilder.set(PCE_INIT, TRUE);
545 annotationBuilder.set(DELEGATE, TRUE);
546 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
547 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
548
549 Path computedPath = computedPathSet.iterator().next();
550 LabelStack labelStack = null;
551 TunnelConsumerId consumerId = null;
552 LspType lspType = LspType.valueOf(lspSigType);
553 long localLspId = 0;
554 if (lspType != WITH_SIGNALLING) {
555 /*
556 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
557 * PCE for non-RSVP signalled LSPs.
558 */
559 localLspId = getNextLocalLspId();
560 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
561
562 if (lspType == SR_WITHOUT_SIGNALLING) {
563 labelStack = srTeHandler.computeLabelStack(computedPath);
564 // Failed to form a label stack.
565 if (labelStack == null) {
566 return false;
567 }
568 }
569 }
570
571 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
572 tunnel.tunnelName(), computedPath,
573 labelStack, annotationBuilder.build());
574
575 // Allocate shared bandwidth.
576 if (bwConstraintValue != 0) {
577 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
578 if (consumerId == null) {
579 return false;
580 }
581 }
582
583 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
584 computedPath);
585
586 if (updatedTunnelId == null) {
587 if (consumerId != null) {
588 resourceService.release(consumerId);
589 }
590 return false;
591 }
592
593 if (consumerId != null) {
594 // Store tunnel consumer id in LSP-Label store.
595 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
596 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
597 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530598 return true;
599 }
600
601 @Override
602 public boolean releasePath(TunnelId tunnelId) {
603 checkNotNull(tunnelId);
604 // 1. Query Tunnel from Tunnel manager.
605 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
606
607 if (tunnel == null) {
608 return false;
609 }
610
611 // 2. Call tunnel service.
612 return tunnelService.downTunnel(appId, tunnel.tunnelId());
613 }
614
615 @Override
616 public Iterable<Tunnel> queryAllPath() {
617 return tunnelService.queryTunnel(MPLS);
618 }
619
620 @Override
621 public Tunnel queryPath(TunnelId tunnelId) {
622 return tunnelService.queryTunnel(tunnelId);
623 }
624
625 /**
626 * Returns the next local LSP identifier to be used either by getting from
627 * freed list if available otherwise generating a new one.
628 *
629 * @return value of local LSP identifier
630 */
631 private short getNextLocalLspId() {
632 // If there is any free id use it. Otherwise generate new id.
633 if (localLspIdFreeList.isEmpty()) {
634 return (short) localLspIdIdGen.getNewId();
635 }
636 Iterator<Short> it = localLspIdFreeList.iterator();
637 Short value = it.next();
638 localLspIdFreeList.remove(value);
639 return value;
640 }
641
Priyanka Bb6963582016-05-20 20:21:20 +0530642 protected class TeConstraintBasedLinkWeight implements LinkWeight {
643
644 private final List<Constraint> constraints;
645
646 /**
647 * Creates a new edge-weight function capable of evaluating links
648 * on the basis of the specified constraints.
649 *
650 * @param constraints path constraints
651 */
652 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
653 if (constraints == null) {
654 this.constraints = Collections.emptyList();
655 } else {
656 this.constraints = ImmutableList.copyOf(constraints);
657 }
658 }
659
660 @Override
661 public double weight(TopologyEdge edge) {
662 if (!constraints.iterator().hasNext()) {
663 //Takes default cost/hopcount as 1 if no constraints specified
664 return 1.0;
665 }
666
667 Iterator<Constraint> it = constraints.iterator();
668 double cost = 1;
669
670 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
671 while (it.hasNext() && cost > 0) {
672 Constraint constraint = it.next();
673 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530674 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
675 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530676 } else {
677 cost = constraint.cost(edge.link(), resourceService::isAvailable);
678 }
679 }
680 return cost;
681 }
682 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530683
Priyanka B3f92c5a2016-05-27 10:14:16 +0530684 //TODO: annotations used for temporarily later projection/network config will be used
685 private class InternalTopologyListener implements TopologyListener {
686 @Override
687 public void event(TopologyEvent event) {
688 event.reasons().forEach(e -> {
689 //If event type is link removed, get the impacted tunnel
690 if (e instanceof LinkEvent) {
691 LinkEvent linkEvent = (LinkEvent) e;
692 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
693 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530694 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530695 // Check whether this ONOS instance is master for ingress device if yes,
696 // recompute and send update
697 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
698 }
699 });
700 }
701 }
702 });
703 }
704 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530705
Priyanka B3f92c5a2016-05-27 10:14:16 +0530706 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
707 /**
708 * Master of ingress node will recompute and also delegation flag must be set.
709 */
710 if (mastershipService.isLocalMaster(src)
711 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
712 LinkedList<Constraint> constraintList = new LinkedList<>();
713
714 if (tunnel.annotations().value(BANDWIDTH) != null) {
715 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
716 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
717 .annotations().value(BANDWIDTH))));
718 constraintList.add(localConst);
719 }
720 if (tunnel.annotations().value(COST_TYPE) != null) {
721 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
722 COST_TYPE))));
723 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530724
725 /*
726 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
727 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
728 */
729 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530730 // If updation fails store in PCE store as failed path
731 // then PCInitiate (Remove)
732 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
733 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
734 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
735 //Release that tunnel calling PCInitiate
736 releasePath(tunnel.tunnelId());
737 }
738 }
739
740 return false;
741 }
742
743 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530744 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
745 SharedBandwidthConstraint shBwConstraint) {
746 checkNotNull(computedPath);
747 checkNotNull(bandwidthConstraint);
748 Resource resource = null;
749 double bwToAllocate = 0;
750
751 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
752
753 /**
754 * Shared bandwidth sub-case : Lesser bandwidth required than original -
755 * No reservation required.
756 */
757 Double additionalBwValue = null;
758 if (shBwConstraint != null) {
759 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
760 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
761 }
762
763 Optional<ResourceAllocation> resAlloc = null;
764 for (Link link : computedPath.links()) {
765 bwToAllocate = 0;
766 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
767 if (additionalBwValue != null) {
768 bwToAllocate = bandwidthConstraint - additionalBwValue;
769 }
770 } else {
771 bwToAllocate = bandwidthConstraint;
772 }
773
774 /**
775 * In shared bandwidth cases, where new BW is lesser than old BW, it
776 * is not required to allocate anything.
777 */
778 if (bwToAllocate != 0) {
779 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
780 .resource(bwToAllocate);
781 resAlloc = resourceService.allocate(consumer, resource);
782
783 // If allocation for any link fails, then release the partially allocated bandwidth.
784 if (!resAlloc.isPresent()) {
785 resourceService.release(consumer);
786 return null;
787 }
788 }
789 }
790
791 /*
792 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
793 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
794 * to who is supposed to store/delete.
795 */
796 return consumer;
797 }
798
799 /*
800 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
801 */
802 private void releaseBandwidth(Tunnel tunnel) {
803 // Between same source and destination, search the tunnel with same symbolic path name.
804 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
805 Tunnel newTunnel = null;
806 for (Tunnel tunnelObj : tunnelQueryResult) {
807 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
808 newTunnel = tunnelObj;
809 break;
810 }
811 }
812
813 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
814 boolean isLinkShared = false;
815 if (newTunnel != null) {
816 for (Link link : tunnel.path().links()) {
817 if (newTunnel.path().links().contains(link)) {
818 isLinkShared = true;
819 break;
820 }
821 }
822 }
823
824 if (isLinkShared) {
825 releaseSharedBandwidth(newTunnel, tunnel);
826 return;
827 }
828
829 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
830 return;
831
832 /*
833 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
834 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
835 * to who is supposed to store/delete.
836 */
837 }
838
839 /**
840 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
841 * allocated in shared mode initially.
842 */
843 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
844 // 1. Release old tunnel's bandwidth.
845 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
846
847 // 2. Release new tunnel's bandwidth
848 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
849 resourceService.release(consumer);
850
851 // 3. Allocate new tunnel's complete bandwidth.
852 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
853 Resource resource;
854
855 for (Link link : newTunnel.path().links()) {
856 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
857 .resource(bandwidth);
858 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530859
860 }
861 }
862
863 /**
864 * Allocates node label to specific device.
865 *
866 * @param specificDevice device to which node label needs to be allocated
867 */
868 public void allocateNodeLabel(Device specificDevice) {
869 checkNotNull(specificDevice, DEVICE_NULL);
870
871 DeviceId deviceId = specificDevice.id();
872
873 // Retrieve lsrId of a specific device
874 if (specificDevice.annotations() == null) {
875 log.debug("Device {} does not have annotations.", specificDevice.toString());
876 return;
877 }
878
879 String lsrId = specificDevice.annotations().value(LSRID);
880 if (lsrId == null) {
881 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
882 return;
883 }
884
885 // Get capability config from netconfig
886 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
887 if (cfg == null) {
888 log.error("Unable to find corresponding capability for a lsrd {} from NetConfig.", lsrId);
889 // Save info. When PCEP session is comes up then allocate node-label
890 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
891 return;
892 }
893
894 // Check whether device has SR-TE Capability
895 if (cfg.labelStackCap()) {
896 if (!srTeHandler.allocateNodeLabel(deviceId, lsrId)) {
897 log.error("Node label allocation for a device id {} has failed.", deviceId.toString());
898 }
899 }
900 }
901
902 /**
903 * Releases node label of a specific device.
904 *
905 * @param specificDevice this device label and lsr-id information will be
906 * released in other existing devices
907 */
908 public void releaseNodeLabel(Device specificDevice) {
909 checkNotNull(specificDevice, DEVICE_NULL);
910
911 DeviceId deviceId = specificDevice.id();
912
913 // Retrieve lsrId of a specific device
914 if (specificDevice.annotations() == null) {
915 log.debug("Device {} does not have annotations.", specificDevice.toString());
916 return;
917 }
918
919 String lsrId = specificDevice.annotations().value(LSRID);
920 if (lsrId == null) {
921 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
922 return;
923 }
924
925 // Get capability config from netconfig
926 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
927 if (cfg == null) {
928 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
929 return;
930 }
931
932 // Check whether device has SR-TE Capability
933 if (cfg.labelStackCap()) {
934 if (!srTeHandler.releaseNodeLabel(deviceId, lsrId)) {
935 log.error("Unable to release node label for a device id {}.", deviceId.toString());
936 }
937 }
938 }
939
940 /**
941 * Allocates adjacency label for a link.
942 *
943 * @param link link
944 */
945 public void allocateAdjacencyLabel(Link link) {
946 checkNotNull(link, LINK_NULL);
947
948 Device specificDevice = deviceService.getDevice(link.src().deviceId());
949 DeviceId deviceId = specificDevice.id();
950
951 // Retrieve lsrId of a specific device
952 if (specificDevice.annotations() == null) {
953 log.debug("Device {} does not have annotations.", specificDevice.toString());
954 return;
955 }
956
957 String lsrId = specificDevice.annotations().value(LSRID);
958 if (lsrId == null) {
959 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
960 return;
961 }
962
963 // Get capability config from netconfig
964 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
965 if (cfg == null) {
966 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
967 // Save info. When PCEP session comes up then allocate adjacency
968 // label
969 if (lsrIdDeviceIdMap.get(lsrId) != null) {
970 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
971 }
972 return;
973 }
974
975 // Check whether device has SR-TE Capability
976 if (cfg.labelStackCap()) {
977 if (!srTeHandler.allocateAdjacencyLabel(link)) {
978 log.error("Unable to allocate adjacency label for a link {}.", link.toString());
979 return;
980 }
981 }
982
983 return;
984 }
985
986 /**
987 * Releases allocated adjacency label of a link.
988 *
989 * @param link link
990 */
991 public void releaseAdjacencyLabel(Link link) {
992 checkNotNull(link, LINK_NULL);
993
994 Device specificDevice = deviceService.getDevice(link.src().deviceId());
995 DeviceId deviceId = specificDevice.id();
996
997 // Retrieve lsrId of a specific device
998 if (specificDevice.annotations() == null) {
999 log.debug("Device {} does not have annotations.", specificDevice.toString());
1000 return;
1001 }
1002
1003 String lsrId = specificDevice.annotations().value(LSRID);
1004 if (lsrId == null) {
1005 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
1006 return;
1007 }
1008
1009 // Get capability config from netconfig
1010 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1011 if (cfg == null) {
1012 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
1013 return;
1014 }
1015
1016 // Check whether device has SR-TE Capability
1017 if (cfg.labelStackCap()) {
1018 if (!srTeHandler.releaseAdjacencyLabel(link)) {
1019 log.error("Unable to release adjacency labels for a link {}.", link.toString());
1020 return;
1021 }
1022 }
1023
1024 return;
1025 }
1026
1027 /*
1028 * Handle device events.
1029 */
1030 private class InternalDeviceListener implements DeviceListener {
1031 @Override
1032 public void event(DeviceEvent event) {
1033 Device specificDevice = (Device) event.subject();
1034 if (specificDevice == null) {
1035 log.error("Unable to find device from device event.");
1036 return;
1037 }
1038
1039 switch (event.type()) {
1040
1041 case DEVICE_ADDED:
1042 // Node-label allocation is being done during Label DB Sync.
1043 // So, when device is detected, no need to do node-label
1044 // allocation.
1045 break;
1046
1047 case DEVICE_REMOVED:
1048 // Release node-label
1049 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1050 releaseNodeLabel(specificDevice);
1051 }
1052 break;
1053
1054 default:
1055 break;
1056 }
1057 }
1058 }
1059
1060 /*
1061 * Handle link events.
1062 */
1063 private class InternalLinkListener implements LinkListener {
1064 @Override
1065 public void event(LinkEvent event) {
1066 Link link = (Link) event.subject();
1067
1068 switch (event.type()) {
1069
1070 case LINK_ADDED:
1071 // Allocate adjacency label
1072 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1073 allocateAdjacencyLabel(link);
1074 }
1075 break;
1076
1077 case LINK_REMOVED:
1078 // Release adjacency label
1079 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1080 releaseAdjacencyLabel(link);
1081 }
1082 break;
1083
1084 default:
1085 break;
1086 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301087 }
1088 }
1089
1090 // Listens on tunnel events.
1091 private class InnerTunnelListener implements TunnelListener {
1092 @Override
1093 public void event(TunnelEvent event) {
1094 // Event gets generated with old tunnel object.
1095 Tunnel tunnel = event.subject();
1096 if (tunnel.type() != MPLS) {
1097 return;
1098 }
1099
1100 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1101 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1102 double bwConstraintValue = 0;
1103 if (tunnelBandwidth != null) {
1104 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1105 }
1106
1107 switch (event.type()) {
1108 case TUNNEL_ADDED:
1109 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1110 String pceInit = tunnel.annotations().value(PCE_INIT);
1111 if (FALSE.equalsIgnoreCase(pceInit)
1112 && bwConstraintValue != 0) {
1113 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1114 }
1115 break;
1116
1117 case TUNNEL_UPDATED:
1118 // Allocate/send labels for basic PCECC tunnels.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301119 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)
1120 && (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER)) {
1121 if (!crHandler.allocateLabel(tunnel)) {
1122 log.error("Unable to allocate labels for a tunnel {}.", tunnel.toString());
1123 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301124 }
1125
1126 if (tunnel.state() == UNSTABLE) {
1127 /*
1128 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1129 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1130 * and setup while global reoptimization.
1131 */
1132
1133 List<Constraint> constraints = new LinkedList<>();
1134 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1135 if (bandwidth != null) {
1136 constraints.add(new BandwidthConstraint(Bandwidth
1137 .bps(Double.parseDouble(bandwidth))));
1138 }
1139
1140 String costType = tunnel.annotations().value(COST_TYPE);
1141 if (costType != null) {
1142 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1143 constraints.add(costConstraint);
1144 }
1145
1146 constraints.add(CapabilityConstraint
1147 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1148
1149 List<Link> links = tunnel.path().links();
1150 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1151 links.get(links.size() - 1).dst().deviceId(),
1152 tunnel.tunnelName().value(), constraints, lspType));
1153 }
1154 break;
1155
1156 case TUNNEL_REMOVED:
1157 if (lspType != WITH_SIGNALLING) {
1158 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1159 }
1160
1161 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
1162 if (bwConstraintValue != 0) {
1163 releaseBandwidth(event.subject());
1164
1165 // Release basic PCECC labels.
1166 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
1167 // Delete stored tunnel consumer id from PCE store (while still retaining label list.)
1168 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
1169 pceccTunnelInfo.tunnelConsumerId(null);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301170 if (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1171 crHandler.releaseLabel(tunnel);
1172 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301173 } else {
1174 pceStore.removeTunnelInfo(tunnel.tunnelId());
1175 }
1176 }
1177 break;
1178
1179 default:
1180 break;
1181
1182 }
1183 return;
1184 }
1185 }
1186
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301187 private class InternalConfigListener implements NetworkConfigListener {
1188
1189 @Override
1190 public void event(NetworkConfigEvent event) {
1191
1192 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED)
1193 && event.configClass().equals(DeviceCapability.class)) {
1194
1195 DeviceId deviceIdLsrId = (DeviceId) event.subject();
1196 String lsrId = deviceIdLsrId.toString();
1197 DeviceId deviceId = lsrIdDeviceIdMap.get(lsrId);
1198 if (deviceId == null) {
1199 log.debug("Unable to find device id for a lsr-id {} from lsr-id and device-id map.", lsrId);
1200 return;
1201 }
1202
1203 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1204 if (cfg == null) {
1205 log.error("Unable to find corresponding capabilty for a lsrd {}.", lsrId);
1206 return;
1207 }
1208
1209 if (cfg.labelStackCap()) {
1210 if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
1211 // Allocate node-label
1212 if (!srTeHandler.allocateNodeLabel(deviceId, lsrId)) {
1213 log.error("Node label allocation for a device id {} has failed.", deviceId.toString());
1214 }
1215
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)) {
1221 log.debug("Unable to allocate adjacency labels for a link {}.", link.toString());
1222 return;
1223 }
1224 }
1225 }
1226 }
1227
1228 // Remove lsrId info from map
1229 lsrIdDeviceIdMap.remove(lsrId);
1230 }
1231 }
1232 }
1233
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301234 private boolean syncLabelDb(DeviceId deviceId) {
1235 checkNotNull(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301236
1237 Device specificDevice = deviceService.getDevice(deviceId);
1238 if (specificDevice == null) {
1239 log.error("Unable to find device for specific device id {}.", deviceId.toString());
1240 return false;
1241 }
1242
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301243 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
1244
1245 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
1246
1247 // Convert from DeviceId to TunnelEndPoint
1248 Device srcDevice = deviceService.getDevice(entry.getKey());
1249
1250 /*
1251 * If there is a slight difference in timing such that if device subsystem has removed the device but PCE
1252 * 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);
1267 }
1268
1269 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 }
1278 }
1279
1280 srTeHandler.advertiseNodeLabelRule(deviceId,
1281 LabelResourceId.labelResourceId(0),
1282 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
1283 Objective.Operation.ADD, true);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301284 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1285 // Allocate node-label to this specific device.
1286 allocateNodeLabel(specificDevice);
1287
1288 // Allocate adjacency label
1289 Set<Link> links = linkService.getDeviceEgressLinks(specificDevice.id());
1290 if (links != null) {
1291 for (Link link : links) {
1292 allocateAdjacencyLabel(link);
1293 }
1294 }
1295 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301296
1297 return true;
1298 }
1299
1300 // Process the packet received.
1301 private class PcepPacketProcessor implements PacketProcessor {
1302 // Process the packet received and in our case initiates the label DB sync.
1303 @Override
1304 public void process(PacketContext context) {
1305 // Stop processing if the packet has been handled, since we
1306 // can't do any more to it.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301307 if (context.isHandled()) {
1308 return;
1309 }
1310
1311 InboundPacket pkt = context.inPacket();
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301312 if (pkt == null) {
1313 return;
1314 }
1315
1316 Ethernet ethernet = pkt.parsed();
1317 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
1318 return;
1319 }
1320
1321 IPv4 ipPacket = (IPv4) ethernet.getPayload();
1322 if (ipPacket == null || ipPacket.getProtocol() != IPv4.PROTOCOL_TCP) {
1323 return;
1324 }
1325
1326 TCP tcp = (TCP) ipPacket.getPayload();
1327 if (tcp == null || tcp.getDestinationPort() != PCEP_PORT) {
1328 return;
1329 }
1330
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301331 syncLabelDb(pkt.receivedFrom().deviceId());
1332 }
1333 }
1334
Priyanka B9fa4ed32016-05-27 11:59:24 +05301335 //Computes path from tunnel store and also path failed to setup.
1336 private void callForOptimization() {
1337 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1338 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1339 checkForMasterAndSetupPath(failedPathInfo);
1340 }
1341
1342 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1343 tunnelService.queryTunnel(MPLS).forEach(t -> {
1344 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1345 });
1346 }
1347
1348 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1349 /**
1350 * Master of ingress node will setup the path failed stored in PCE store.
1351 */
1352 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1353 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
1354 failedPathInfo.constraints(), failedPathInfo.lspType())) {
1355 // If computation is success remove that path
1356 pceStore.removeFailedPathInfo(failedPathInfo);
1357 return true;
1358 }
1359 }
1360
1361 return false;
1362 }
1363
1364 //Timer to call global optimization
1365 private class GlobalOptimizationTimer implements Runnable {
1366
1367 public GlobalOptimizationTimer() {
1368 }
1369
1370 @Override
1371 public void run() {
1372 callForOptimization();
1373 }
1374 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301375}