blob: 76f6e3f134abb800e8cebb5ed40a522b1aeda829 [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;
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530119import static org.onosproject.incubator.net.tunnel.Tunnel.State.FAILED;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530120import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
121import static org.onosproject.pce.pceservice.LspType.SR_WITHOUT_SIGNALLING;
122import static org.onosproject.pce.pceservice.LspType.WITHOUT_SIGNALLING_AND_WITHOUT_SR;
123
124import static org.onosproject.pce.pceservice.PcepAnnotationKeys.BANDWIDTH;
125import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LOCAL_LSP_ID;
126import static org.onosproject.pce.pceservice.PcepAnnotationKeys.LSP_SIG_TYPE;
127import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCE_INIT;
128import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PLSP_ID;
129import static org.onosproject.pce.pceservice.PcepAnnotationKeys.PCC_TUNNEL_ID;
130import static org.onosproject.pce.pceservice.PcepAnnotationKeys.DELEGATE;
131import static org.onosproject.pce.pceservice.PcepAnnotationKeys.COST_TYPE;
132
133import org.onosproject.net.packet.InboundPacket;
134import org.onosproject.net.packet.PacketContext;
135import org.onosproject.net.packet.PacketProcessor;
136import org.onosproject.net.packet.PacketService;
Priyanka Bb6963582016-05-20 20:21:20 +0530137
Avantika-Huawei73862d42016-05-12 18:58:06 +0530138/**
139 * Implementation of PCE service.
140 */
141@Component(immediate = true)
142@Service
143public class PceManager implements PceService {
144 private static final Logger log = LoggerFactory.getLogger(PceManager.class);
145
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530146 public static final long GLOBAL_LABEL_SPACE_MIN = 4097;
147 public static final long GLOBAL_LABEL_SPACE_MAX = 5121;
148 private static final String DEVICE_NULL = "Device-cannot be null";
149 private static final String LINK_NULL = "Link-cannot be null";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530150 public static final String PCE_SERVICE_APP = "org.onosproject.pce";
Avantika-Huawei73862d42016-05-12 18:58:06 +0530151 private static final String LOCAL_LSP_ID_GEN_TOPIC = "pcep-local-lsp-id";
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530152 public static final String DEVICE_TYPE = "type";
153 public static final String L3_DEVICE = "L3";
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530154 private static final int PREFIX_LENGTH = 32;
155
156 private static final String TUNNEL_CONSUMER_ID_GEN_TOPIC = "pcep-tunnel-consumer-id";
157 private IdGenerator tunnelConsumerIdGen;
158
159 private static final String LSRID = "lsrId";
160 private static final String TRUE = "true";
161 private static final String FALSE = "false";
162 private static final String END_OF_SYNC_IP_PREFIX = "0.0.0.0/32";
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530163 public static final int PCEP_PORT = 4189;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530164
Avantika-Huawei73862d42016-05-12 18:58:06 +0530165 private IdGenerator localLspIdIdGen;
166 protected DistributedSet<Short> localLspIdFreeList;
167
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530168 // LSR-id and device-id mapping for checking capability if L3 device is not
169 // having its capability
170 private Map<String, DeviceId> lsrIdDeviceIdMap = new HashMap<>();
171
Avantika-Huawei73862d42016-05-12 18:58:06 +0530172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
173 protected CoreService coreService;
174
175 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530176 protected ResourceService resourceService;
177
178 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
179 protected ResourceQueryService resourceQueryService;
180
181 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
182 protected PathService pathService;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
185 protected PceStore pceStore;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei73862d42016-05-12 18:58:06 +0530188 protected TunnelService tunnelService;
189
190 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
191 protected StorageService storageService;
192
Priyanka Bb6963582016-05-20 20:21:20 +0530193 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530194 protected PacketService packetService;
Priyanka Bb6963582016-05-20 20:21:20 +0530195
196 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
197 protected DeviceService deviceService;
198
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530199 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530200 protected LinkService linkService;
201
202 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huawei032a9872016-05-27 22:57:38 +0530203 protected NetworkConfigService netCfgService;
204
205 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530206 protected LabelResourceAdminService labelRsrcAdminService;
207
208 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
209 protected LabelResourceService labelRsrcService;
210
211 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
212 protected FlowObjectiveService flowObjectiveService;
213
Priyanka B3f92c5a2016-05-27 10:14:16 +0530214 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
215 protected MastershipService mastershipService;
216
217 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
218 protected TopologyService topologyService;
219
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530220 private TunnelListener listener = new InnerTunnelListener();
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530221 private DeviceListener deviceListener = new InternalDeviceListener();
222 private LinkListener linkListener = new InternalLinkListener();
223 private InternalConfigListener cfgListener = new InternalConfigListener();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530224 private BasicPceccHandler crHandler;
225 private PceccSrTeBeHandler srTeHandler;
Avantika-Huawei73862d42016-05-12 18:58:06 +0530226 private ApplicationId appId;
227
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530228 private final PcepPacketProcessor processor = new PcepPacketProcessor();
Priyanka B3f92c5a2016-05-27 10:14:16 +0530229 private final TopologyListener topologyListener = new InternalTopologyListener();
Priyanka B9fa4ed32016-05-27 11:59:24 +0530230 private ScheduledExecutorService executor;
231
232 public static final int INITIAL_DELAY = 30;
233 public static final int PERIODIC_DELAY = 30;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530234
Avantika-Huawei73862d42016-05-12 18:58:06 +0530235 /**
236 * Creates new instance of PceManager.
237 */
238 public PceManager() {
239 }
240
241 @Activate
242 protected void activate() {
243 appId = coreService.registerApplication(PCE_SERVICE_APP);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530244 crHandler = BasicPceccHandler.getInstance();
245 crHandler.initialize(labelRsrcService, flowObjectiveService, appId, pceStore);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530246
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530247 srTeHandler = PceccSrTeBeHandler.getInstance();
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530248 srTeHandler.initialize(labelRsrcAdminService, labelRsrcService, flowObjectiveService, appId, pceStore,
249 deviceService);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530250
251 tunnelService.addListener(listener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530252 deviceService.addListener(deviceListener);
253 linkService.addListener(linkListener);
254 netCfgService.addListener(cfgListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530255
256 tunnelConsumerIdGen = coreService.getIdGenerator(TUNNEL_CONSUMER_ID_GEN_TOPIC);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530257 localLspIdIdGen = coreService.getIdGenerator(LOCAL_LSP_ID_GEN_TOPIC);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530258 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530259 localLspIdFreeList = storageService.<Short>setBuilder()
260 .withName("pcepLocalLspIdDeletedList")
261 .withSerializer(Serializer.using(KryoNamespaces.API))
262 .build()
263 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530264
265 packetService.addProcessor(processor, PacketProcessor.director(4));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530266 topologyService.addListener(topologyListener);
Priyanka B9fa4ed32016-05-27 11:59:24 +0530267 executor = Executors.newSingleThreadScheduledExecutor();
268 //Start a timer when the component is up, with initial delay of 30min and periodic delays at 30min
269 executor.scheduleAtFixedRate(new GlobalOptimizationTimer(), INITIAL_DELAY, PERIODIC_DELAY, TimeUnit.MINUTES);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530270
271 // Reserve global node pool
272 if (!srTeHandler.reserveGlobalPool(GLOBAL_LABEL_SPACE_MIN, GLOBAL_LABEL_SPACE_MAX)) {
273 log.debug("Global node pool was already reserved.");
274 }
275
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530276 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530277 }
278
279 @Deactivate
280 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530281 tunnelService.removeListener(listener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530282 deviceService.removeListener(deviceListener);
283 linkService.removeListener(linkListener);
284 netCfgService.removeListener(cfgListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530285 packetService.removeProcessor(processor);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530286 topologyService.removeListener(topologyListener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530287 // Shutdown the thread when component is deactivated
Priyanka B9fa4ed32016-05-27 11:59:24 +0530288 executor.shutdown();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530289 log.info("Stopped");
290 }
291
Priyanka Bb6963582016-05-20 20:21:20 +0530292 /**
293 * Returns an edge-weight capable of evaluating links on the basis of the
294 * specified constraints.
295 *
296 * @param constraints path constraints
297 * @return edge-weight function
298 */
299 private LinkWeight weight(List<Constraint> constraints) {
300 return new TeConstraintBasedLinkWeight(constraints);
301 }
302
303 /**
304 * Computes a path between two devices.
305 *
306 * @param src ingress device
307 * @param dst egress device
308 * @param constraints path constraints
309 * @return computed path based on constraints
310 */
311 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
312 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530313 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530314 }
315 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
316 if (!paths.isEmpty()) {
317 return paths;
318 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530319 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530320 }
321
Avantika-Huawei73862d42016-05-12 18:58:06 +0530322 //[TODO:] handle requests in queue
323 @Override
324 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
325 LspType lspType) {
326 checkNotNull(src);
327 checkNotNull(dst);
328 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530329 checkNotNull(lspType);
330
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530331 // Convert from DeviceId to TunnelEndPoint
332 Device srcDevice = deviceService.getDevice(src);
333 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530334
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530335 if (srcDevice == null || dstDevice == null) {
336 // Device is not known.
337 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
338 return false;
339 }
340
341 // In future projections instead of annotations will be used to fetch LSR ID.
342 String srcLsrId = srcDevice.annotations().value(LSRID);
343 String dstLsrId = dstDevice.annotations().value(LSRID);
344
345 if (srcLsrId == null || dstLsrId == null) {
346 // LSR id is not known.
347 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
348 return false;
349 }
350
Avantika-Huawei032a9872016-05-27 22:57:38 +0530351 // Get device config from netconfig, to ascertain that session with ingress is present.
352 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
353 if (cfg == null) {
354 log.debug("No session to ingress.");
355 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
356 return false;
357 }
358
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530359 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
360 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
361
362 double bwConstraintValue = 0;
363 CostConstraint costConstraint = null;
364 if (constraints != null) {
365 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
366 Iterator<Constraint> iterator = constraints.iterator();
367
368 while (iterator.hasNext()) {
369 Constraint constraint = iterator.next();
370 if (constraint instanceof BandwidthConstraint) {
371 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
372 } else if (constraint instanceof CostConstraint) {
373 costConstraint = (CostConstraint) constraint;
374 }
375 }
376
377 /*
378 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
379 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
380 * function can either return the result of limiting/capability constraint validation or the value of link
381 * cost, depending upon what is the last constraint in the loop.
382 */
383 if (costConstraint != null) {
384 constraints.remove(costConstraint);
385 constraints.add(costConstraint);
386 }
387 } else {
388 constraints = new LinkedList<>();
389 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
390 }
391
392 Set<Path> computedPathSet = computePath(src, dst, constraints);
393
394 // NO-PATH
395 if (computedPathSet.isEmpty()) {
396 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
397 return false;
398 }
399
400 Builder annotationBuilder = DefaultAnnotations.builder();
401 if (bwConstraintValue != 0) {
402 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
403 }
404 if (costConstraint != null) {
405 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
406 }
407 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
408 annotationBuilder.set(PCE_INIT, TRUE);
409 annotationBuilder.set(DELEGATE, TRUE);
410
411 Path computedPath = computedPathSet.iterator().next();
412 LabelStack labelStack = null;
413
414 if (lspType == SR_WITHOUT_SIGNALLING) {
415 labelStack = srTeHandler.computeLabelStack(computedPath);
416 // Failed to form a label stack.
417 if (labelStack == null) {
418 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
419 return false;
420 }
421 }
422
423 if (lspType != WITH_SIGNALLING) {
424 /*
425 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
426 * PCE for non-RSVP signalled LSPs.
427 */
428 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
429 }
430
431 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
432 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
433 TunnelName.tunnelName(tunnelName), computedPath,
434 labelStack, annotationBuilder.build());
435
436 // Allocate bandwidth.
437 TunnelConsumerId consumerId = null;
438 if (bwConstraintValue != 0) {
439 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
440 if (consumerId == null) {
441 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
442 return false;
443 }
444 }
445
446 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
447 if (tunnelId == null) {
448 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
449 if (consumerId != null) {
450 resourceService.release(consumerId);
451 }
452 return false;
453 }
454
455 if (consumerId != null) {
456 // Store tunnel consumer id in LSP-Label store.
457 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
458 pceStore.addTunnelInfo(tunnelId, pceccTunnelInfo);
459 }
460 return true;
461 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530462
463 @Override
464 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
465 checkNotNull(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530466 Set<Path> computedPathSet = null;
467 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530468
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530469 if (tunnel == null) {
470 return false;
471 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530472
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530473 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
474 // Only delegated LSPs can be updated.
475 return false;
476 }
477
478 List<Link> links = tunnel.path().links();
479 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
480 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530481 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530482 SharedBandwidthConstraint shBwConstraint = null;
483 BandwidthConstraint bwConstraint = null;
484 CostConstraint costConstraint = null;
485
486 if (constraints != null) {
487 // Call path computation in shared bandwidth mode.
488 Iterator<Constraint> iterator = constraints.iterator();
489 while (iterator.hasNext()) {
490 Constraint constraint = iterator.next();
491 if (constraint instanceof BandwidthConstraint) {
492 bwConstraint = (BandwidthConstraint) constraint;
493 bwConstraintValue = bwConstraint.bandwidth().bps();
494 } else if (constraint instanceof CostConstraint) {
495 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530496 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530497 }
498 }
499
500 // Remove and keep the cost constraint at the end of the list of constraints.
501 if (costConstraint != null) {
502 constraints.remove(costConstraint);
503 }
504
505 Bandwidth existingBwValue = null;
506 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
507 if (existingBwAnnotation != null) {
508 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
509
510 /*
511 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
512 * has been utilized to create shared bandwidth constraint.
513 */
514 if (bwConstraint != null) {
515 constraints.remove(bwConstraint);
516 }
517 }
518
519 if (existingBwValue != null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530520 if (bwConstraintValue == 0) {
521 bwConstraintValue = existingBwValue.bps();
522 }
523 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
524 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
525 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
526 existingBwValue, existingBwValue);
527
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530528 constraints.add(shBwConstraint);
529 }
530 } else {
531 constraints = new LinkedList<>();
532 }
533
534 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
535 if (costConstraint != null) {
536 constraints.add(costConstraint);
537 }
538
539 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
540 constraints);
541
542 // NO-PATH
543 if (computedPathSet.isEmpty()) {
544 return false;
545 }
546
547 Builder annotationBuilder = DefaultAnnotations.builder();
548 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530549 if (costType != null) {
550 annotationBuilder.set(COST_TYPE, costType);
551 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530552 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
553 annotationBuilder.set(PCE_INIT, TRUE);
554 annotationBuilder.set(DELEGATE, TRUE);
555 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
556 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
557
558 Path computedPath = computedPathSet.iterator().next();
559 LabelStack labelStack = null;
560 TunnelConsumerId consumerId = null;
561 LspType lspType = LspType.valueOf(lspSigType);
562 long localLspId = 0;
563 if (lspType != WITH_SIGNALLING) {
564 /*
565 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
566 * PCE for non-RSVP signalled LSPs.
567 */
568 localLspId = getNextLocalLspId();
569 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
570
571 if (lspType == SR_WITHOUT_SIGNALLING) {
572 labelStack = srTeHandler.computeLabelStack(computedPath);
573 // Failed to form a label stack.
574 if (labelStack == null) {
575 return false;
576 }
577 }
578 }
579
580 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
581 tunnel.tunnelName(), computedPath,
582 labelStack, annotationBuilder.build());
583
584 // Allocate shared bandwidth.
585 if (bwConstraintValue != 0) {
586 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
587 if (consumerId == null) {
588 return false;
589 }
590 }
591
592 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
593 computedPath);
594
595 if (updatedTunnelId == null) {
596 if (consumerId != null) {
597 resourceService.release(consumerId);
598 }
599 return false;
600 }
601
602 if (consumerId != null) {
603 // Store tunnel consumer id in LSP-Label store.
604 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
605 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
606 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +0530607
608 // For CR cases, download labels and send update message.
609 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
610 Tunnel tunnelForlabelDownload = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null,
611 updatedTunnelId, tunnel.tunnelName(), computedPath,
612 labelStack, annotationBuilder.build());
613
614 if (!crHandler.allocateLabel(tunnelForlabelDownload)) {
615 log.error("Unable to allocate labels for the tunnel {}.", tunnel.toString());
616 }
617 }
618
Avantika-Huawei73862d42016-05-12 18:58:06 +0530619 return true;
620 }
621
622 @Override
623 public boolean releasePath(TunnelId tunnelId) {
624 checkNotNull(tunnelId);
625 // 1. Query Tunnel from Tunnel manager.
626 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
627
628 if (tunnel == null) {
629 return false;
630 }
631
632 // 2. Call tunnel service.
633 return tunnelService.downTunnel(appId, tunnel.tunnelId());
634 }
635
636 @Override
637 public Iterable<Tunnel> queryAllPath() {
638 return tunnelService.queryTunnel(MPLS);
639 }
640
641 @Override
642 public Tunnel queryPath(TunnelId tunnelId) {
643 return tunnelService.queryTunnel(tunnelId);
644 }
645
646 /**
647 * Returns the next local LSP identifier to be used either by getting from
648 * freed list if available otherwise generating a new one.
649 *
650 * @return value of local LSP identifier
651 */
652 private short getNextLocalLspId() {
653 // If there is any free id use it. Otherwise generate new id.
654 if (localLspIdFreeList.isEmpty()) {
655 return (short) localLspIdIdGen.getNewId();
656 }
657 Iterator<Short> it = localLspIdFreeList.iterator();
658 Short value = it.next();
659 localLspIdFreeList.remove(value);
660 return value;
661 }
662
Priyanka Bb6963582016-05-20 20:21:20 +0530663 protected class TeConstraintBasedLinkWeight implements LinkWeight {
664
665 private final List<Constraint> constraints;
666
667 /**
668 * Creates a new edge-weight function capable of evaluating links
669 * on the basis of the specified constraints.
670 *
671 * @param constraints path constraints
672 */
673 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
674 if (constraints == null) {
675 this.constraints = Collections.emptyList();
676 } else {
677 this.constraints = ImmutableList.copyOf(constraints);
678 }
679 }
680
681 @Override
682 public double weight(TopologyEdge edge) {
683 if (!constraints.iterator().hasNext()) {
684 //Takes default cost/hopcount as 1 if no constraints specified
685 return 1.0;
686 }
687
688 Iterator<Constraint> it = constraints.iterator();
689 double cost = 1;
690
691 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
692 while (it.hasNext() && cost > 0) {
693 Constraint constraint = it.next();
694 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530695 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
696 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530697 } else {
698 cost = constraint.cost(edge.link(), resourceService::isAvailable);
699 }
700 }
701 return cost;
702 }
703 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530704
Priyanka B3f92c5a2016-05-27 10:14:16 +0530705 //TODO: annotations used for temporarily later projection/network config will be used
706 private class InternalTopologyListener implements TopologyListener {
707 @Override
708 public void event(TopologyEvent event) {
709 event.reasons().forEach(e -> {
710 //If event type is link removed, get the impacted tunnel
711 if (e instanceof LinkEvent) {
712 LinkEvent linkEvent = (LinkEvent) e;
713 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
714 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530715 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530716 // Check whether this ONOS instance is master for ingress device if yes,
717 // recompute and send update
718 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
719 }
720 });
721 }
722 }
723 });
724 }
725 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530726
Priyanka B3f92c5a2016-05-27 10:14:16 +0530727 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
728 /**
729 * Master of ingress node will recompute and also delegation flag must be set.
730 */
731 if (mastershipService.isLocalMaster(src)
732 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
733 LinkedList<Constraint> constraintList = new LinkedList<>();
734
735 if (tunnel.annotations().value(BANDWIDTH) != null) {
736 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
737 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
738 .annotations().value(BANDWIDTH))));
739 constraintList.add(localConst);
740 }
741 if (tunnel.annotations().value(COST_TYPE) != null) {
742 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
743 COST_TYPE))));
744 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530745
746 /*
747 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
748 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
749 */
750 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530751 // If updation fails store in PCE store as failed path
752 // then PCInitiate (Remove)
753 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
754 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
755 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
756 //Release that tunnel calling PCInitiate
757 releasePath(tunnel.tunnelId());
758 }
759 }
760
761 return false;
762 }
763
764 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530765 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
766 SharedBandwidthConstraint shBwConstraint) {
767 checkNotNull(computedPath);
768 checkNotNull(bandwidthConstraint);
769 Resource resource = null;
770 double bwToAllocate = 0;
771
772 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
773
774 /**
775 * Shared bandwidth sub-case : Lesser bandwidth required than original -
776 * No reservation required.
777 */
778 Double additionalBwValue = null;
779 if (shBwConstraint != null) {
780 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
781 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
782 }
783
784 Optional<ResourceAllocation> resAlloc = null;
785 for (Link link : computedPath.links()) {
786 bwToAllocate = 0;
787 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
788 if (additionalBwValue != null) {
789 bwToAllocate = bandwidthConstraint - additionalBwValue;
790 }
791 } else {
792 bwToAllocate = bandwidthConstraint;
793 }
794
795 /**
796 * In shared bandwidth cases, where new BW is lesser than old BW, it
797 * is not required to allocate anything.
798 */
799 if (bwToAllocate != 0) {
800 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
801 .resource(bwToAllocate);
802 resAlloc = resourceService.allocate(consumer, resource);
803
804 // If allocation for any link fails, then release the partially allocated bandwidth.
805 if (!resAlloc.isPresent()) {
806 resourceService.release(consumer);
807 return null;
808 }
809 }
810 }
811
812 /*
813 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
814 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
815 * to who is supposed to store/delete.
816 */
817 return consumer;
818 }
819
820 /*
821 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
822 */
823 private void releaseBandwidth(Tunnel tunnel) {
824 // Between same source and destination, search the tunnel with same symbolic path name.
825 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
826 Tunnel newTunnel = null;
827 for (Tunnel tunnelObj : tunnelQueryResult) {
828 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
829 newTunnel = tunnelObj;
830 break;
831 }
832 }
833
834 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
835 boolean isLinkShared = false;
836 if (newTunnel != null) {
837 for (Link link : tunnel.path().links()) {
838 if (newTunnel.path().links().contains(link)) {
839 isLinkShared = true;
840 break;
841 }
842 }
843 }
844
845 if (isLinkShared) {
846 releaseSharedBandwidth(newTunnel, tunnel);
847 return;
848 }
849
850 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
851 return;
852
853 /*
854 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
855 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
856 * to who is supposed to store/delete.
857 */
858 }
859
860 /**
861 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
862 * allocated in shared mode initially.
863 */
864 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
865 // 1. Release old tunnel's bandwidth.
866 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
867
868 // 2. Release new tunnel's bandwidth
869 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
870 resourceService.release(consumer);
871
872 // 3. Allocate new tunnel's complete bandwidth.
873 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
874 Resource resource;
875
876 for (Link link : newTunnel.path().links()) {
877 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
878 .resource(bandwidth);
879 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530880
881 }
882 }
883
884 /**
885 * Allocates node label to specific device.
886 *
887 * @param specificDevice device to which node label needs to be allocated
888 */
889 public void allocateNodeLabel(Device specificDevice) {
890 checkNotNull(specificDevice, DEVICE_NULL);
891
892 DeviceId deviceId = specificDevice.id();
893
894 // Retrieve lsrId of a specific device
895 if (specificDevice.annotations() == null) {
896 log.debug("Device {} does not have annotations.", specificDevice.toString());
897 return;
898 }
899
900 String lsrId = specificDevice.annotations().value(LSRID);
901 if (lsrId == null) {
902 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
903 return;
904 }
905
906 // Get capability config from netconfig
907 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
908 if (cfg == null) {
909 log.error("Unable to find corresponding capability for a lsrd {} from NetConfig.", lsrId);
910 // Save info. When PCEP session is comes up then allocate node-label
911 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
912 return;
913 }
914
915 // Check whether device has SR-TE Capability
916 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530917 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530918 }
919 }
920
921 /**
922 * Releases node label of a specific device.
923 *
924 * @param specificDevice this device label and lsr-id information will be
925 * released in other existing devices
926 */
927 public void releaseNodeLabel(Device specificDevice) {
928 checkNotNull(specificDevice, DEVICE_NULL);
929
930 DeviceId deviceId = specificDevice.id();
931
932 // Retrieve lsrId of a specific device
933 if (specificDevice.annotations() == null) {
934 log.debug("Device {} does not have annotations.", specificDevice.toString());
935 return;
936 }
937
938 String lsrId = specificDevice.annotations().value(LSRID);
939 if (lsrId == null) {
940 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
941 return;
942 }
943
944 // Get capability config from netconfig
945 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
946 if (cfg == null) {
947 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
948 return;
949 }
950
951 // Check whether device has SR-TE Capability
952 if (cfg.labelStackCap()) {
953 if (!srTeHandler.releaseNodeLabel(deviceId, lsrId)) {
954 log.error("Unable to release node label for a device id {}.", deviceId.toString());
955 }
956 }
957 }
958
959 /**
960 * Allocates adjacency label for a link.
961 *
962 * @param link link
963 */
964 public void allocateAdjacencyLabel(Link link) {
965 checkNotNull(link, LINK_NULL);
966
967 Device specificDevice = deviceService.getDevice(link.src().deviceId());
968 DeviceId deviceId = specificDevice.id();
969
970 // Retrieve lsrId of a specific device
971 if (specificDevice.annotations() == null) {
972 log.debug("Device {} does not have annotations.", specificDevice.toString());
973 return;
974 }
975
976 String lsrId = specificDevice.annotations().value(LSRID);
977 if (lsrId == null) {
978 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
979 return;
980 }
981
982 // Get capability config from netconfig
983 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
984 if (cfg == null) {
985 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
986 // Save info. When PCEP session comes up then allocate adjacency
987 // label
988 if (lsrIdDeviceIdMap.get(lsrId) != null) {
989 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
990 }
991 return;
992 }
993
994 // Check whether device has SR-TE Capability
995 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530996 srTeHandler.allocateAdjacencyLabel(link);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530997 }
998
999 return;
1000 }
1001
1002 /**
1003 * Releases allocated adjacency label of a link.
1004 *
1005 * @param link link
1006 */
1007 public void releaseAdjacencyLabel(Link link) {
1008 checkNotNull(link, LINK_NULL);
1009
1010 Device specificDevice = deviceService.getDevice(link.src().deviceId());
1011 DeviceId deviceId = specificDevice.id();
1012
1013 // Retrieve lsrId of a specific device
1014 if (specificDevice.annotations() == null) {
1015 log.debug("Device {} does not have annotations.", specificDevice.toString());
1016 return;
1017 }
1018
1019 String lsrId = specificDevice.annotations().value(LSRID);
1020 if (lsrId == null) {
1021 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
1022 return;
1023 }
1024
1025 // Get capability config from netconfig
1026 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1027 if (cfg == null) {
1028 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
1029 return;
1030 }
1031
1032 // Check whether device has SR-TE Capability
1033 if (cfg.labelStackCap()) {
1034 if (!srTeHandler.releaseAdjacencyLabel(link)) {
1035 log.error("Unable to release adjacency labels for a link {}.", link.toString());
1036 return;
1037 }
1038 }
1039
1040 return;
1041 }
1042
1043 /*
1044 * Handle device events.
1045 */
1046 private class InternalDeviceListener implements DeviceListener {
1047 @Override
1048 public void event(DeviceEvent event) {
1049 Device specificDevice = (Device) event.subject();
1050 if (specificDevice == null) {
1051 log.error("Unable to find device from device event.");
1052 return;
1053 }
1054
1055 switch (event.type()) {
1056
1057 case DEVICE_ADDED:
1058 // Node-label allocation is being done during Label DB Sync.
1059 // So, when device is detected, no need to do node-label
1060 // allocation.
Avantika-Huawei28b53752016-06-23 17:04:49 +05301061 String lsrId = specificDevice.annotations().value(LSRID);
1062 if (lsrId != null) {
1063 pceStore.addLsrIdDevice(lsrId, specificDevice.id());
1064
1065 // Search in failed DB sync store. If found, trigger label DB sync.
1066 DeviceId pccDeviceId = DeviceId.deviceId(lsrId);
1067 if (pceStore.hasPccLsr(pccDeviceId)) {
1068 log.debug("Continue to perform label DB sync for device {}.", pccDeviceId.toString());
1069 syncLabelDb(pccDeviceId);
1070 pceStore.removePccLsr(pccDeviceId);
1071 }
1072 }
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301073 break;
1074
1075 case DEVICE_REMOVED:
1076 // Release node-label
1077 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1078 releaseNodeLabel(specificDevice);
1079 }
Avantika-Huawei28b53752016-06-23 17:04:49 +05301080
1081 if (specificDevice.annotations().value(LSRID) != null) {
1082 pceStore.removeLsrIdDevice(specificDevice.annotations().value(LSRID));
1083 }
1084
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301085 break;
1086
1087 default:
1088 break;
1089 }
1090 }
1091 }
1092
1093 /*
1094 * Handle link events.
1095 */
1096 private class InternalLinkListener implements LinkListener {
1097 @Override
1098 public void event(LinkEvent event) {
1099 Link link = (Link) event.subject();
1100
1101 switch (event.type()) {
1102
1103 case LINK_ADDED:
1104 // Allocate adjacency label
1105 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1106 allocateAdjacencyLabel(link);
1107 }
1108 break;
1109
1110 case LINK_REMOVED:
1111 // Release adjacency label
1112 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1113 releaseAdjacencyLabel(link);
1114 }
1115 break;
1116
1117 default:
1118 break;
1119 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301120 }
1121 }
1122
1123 // Listens on tunnel events.
1124 private class InnerTunnelListener implements TunnelListener {
1125 @Override
1126 public void event(TunnelEvent event) {
1127 // Event gets generated with old tunnel object.
1128 Tunnel tunnel = event.subject();
1129 if (tunnel.type() != MPLS) {
1130 return;
1131 }
1132
1133 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1134 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1135 double bwConstraintValue = 0;
1136 if (tunnelBandwidth != null) {
1137 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1138 }
1139
1140 switch (event.type()) {
1141 case TUNNEL_ADDED:
1142 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1143 String pceInit = tunnel.annotations().value(PCE_INIT);
1144 if (FALSE.equalsIgnoreCase(pceInit)
1145 && bwConstraintValue != 0) {
1146 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1147 }
1148 break;
1149
1150 case TUNNEL_UPDATED:
1151 // Allocate/send labels for basic PCECC tunnels.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301152 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)
1153 && (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER)) {
1154 if (!crHandler.allocateLabel(tunnel)) {
1155 log.error("Unable to allocate labels for a tunnel {}.", tunnel.toString());
1156 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301157 }
1158
1159 if (tunnel.state() == UNSTABLE) {
1160 /*
1161 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1162 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1163 * and setup while global reoptimization.
1164 */
1165
1166 List<Constraint> constraints = new LinkedList<>();
1167 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1168 if (bandwidth != null) {
1169 constraints.add(new BandwidthConstraint(Bandwidth
1170 .bps(Double.parseDouble(bandwidth))));
1171 }
1172
1173 String costType = tunnel.annotations().value(COST_TYPE);
1174 if (costType != null) {
1175 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1176 constraints.add(costConstraint);
1177 }
1178
1179 constraints.add(CapabilityConstraint
1180 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1181
1182 List<Link> links = tunnel.path().links();
1183 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1184 links.get(links.size() - 1).dst().deviceId(),
1185 tunnel.tunnelName().value(), constraints, lspType));
1186 }
Avantika-Huawei3c2d3eb2016-06-22 09:34:00 +05301187
1188 if (tunnel.state() == FAILED) {
1189 // Check whether this ONOS instance is master, if yes, recompute and send update.
1190 checkForMasterAndUpdateTunnel(tunnel.path().src().deviceId(), tunnel);
1191 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301192 break;
1193
1194 case TUNNEL_REMOVED:
1195 if (lspType != WITH_SIGNALLING) {
1196 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1197 }
1198
1199 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
1200 if (bwConstraintValue != 0) {
1201 releaseBandwidth(event.subject());
1202
1203 // Release basic PCECC labels.
1204 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
1205 // Delete stored tunnel consumer id from PCE store (while still retaining label list.)
1206 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
1207 pceccTunnelInfo.tunnelConsumerId(null);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301208 if (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1209 crHandler.releaseLabel(tunnel);
1210 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301211 } else {
1212 pceStore.removeTunnelInfo(tunnel.tunnelId());
1213 }
1214 }
1215 break;
1216
1217 default:
1218 break;
1219
1220 }
1221 return;
1222 }
1223 }
1224
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301225 private class InternalConfigListener implements NetworkConfigListener {
1226
1227 @Override
1228 public void event(NetworkConfigEvent event) {
1229
1230 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED)
1231 && event.configClass().equals(DeviceCapability.class)) {
1232
1233 DeviceId deviceIdLsrId = (DeviceId) event.subject();
1234 String lsrId = deviceIdLsrId.toString();
1235 DeviceId deviceId = lsrIdDeviceIdMap.get(lsrId);
1236 if (deviceId == null) {
1237 log.debug("Unable to find device id for a lsr-id {} from lsr-id and device-id map.", lsrId);
1238 return;
1239 }
1240
1241 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1242 if (cfg == null) {
1243 log.error("Unable to find corresponding capabilty for a lsrd {}.", lsrId);
1244 return;
1245 }
1246
1247 if (cfg.labelStackCap()) {
1248 if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
1249 // Allocate node-label
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301250 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301251
1252 // Allocate adjacency label to links which are
1253 // originated from this specific device id
1254 Set<Link> links = linkService.getDeviceEgressLinks(deviceId);
1255 for (Link link : links) {
1256 if (!srTeHandler.allocateAdjacencyLabel(link)) {
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301257 return;
1258 }
1259 }
1260 }
1261 }
1262
1263 // Remove lsrId info from map
1264 lsrIdDeviceIdMap.remove(lsrId);
1265 }
1266 }
1267 }
1268
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301269 private boolean syncLabelDb(DeviceId deviceId) {
1270 checkNotNull(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301271
Avantika-Huawei28b53752016-06-23 17:04:49 +05301272 DeviceId actualDevcieId = pceStore.getLsrIdDevice(deviceId.toString());
1273 if (actualDevcieId == null) {
1274 log.error("Device not available {}.", deviceId.toString());
1275 pceStore.addPccLsr(deviceId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301276 return false;
1277 }
1278
Avantika-Huawei28b53752016-06-23 17:04:49 +05301279 Device specificDevice = deviceService.getDevice(actualDevcieId);
1280 if (specificDevice == null) {
1281 log.error("Unable to find device for specific device id {}.", actualDevcieId.toString());
1282 return false;
1283 }
1284
1285 if (pceStore.getGlobalNodeLabel(actualDevcieId) != null) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301286 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301287
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301288 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301289
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301290 // Convert from DeviceId to TunnelEndPoint
1291 Device srcDevice = deviceService.getDevice(entry.getKey());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301292
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301293 /*
1294 * If there is a slight difference in timing such that if device subsystem has removed the device but
1295 * PCE store still has it, just ignore such devices.
1296 */
1297 if (srcDevice == null) {
1298 continue;
1299 }
1300
1301 String srcLsrId = srcDevice.annotations().value(LSRID);
1302 if (srcLsrId == null) {
1303 continue;
1304 }
1305
Avantika-Huawei28b53752016-06-23 17:04:49 +05301306 srTeHandler.advertiseNodeLabelRule(actualDevcieId,
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301307 entry.getValue(),
1308 IpPrefix.valueOf(IpAddress.valueOf(srcLsrId), PREFIX_LENGTH),
1309 Objective.Operation.ADD, false);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301310 }
1311
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301312 Map<Link, LabelResourceId> adjLabelMap = pceStore.getAdjLabels();
1313 for (Entry<Link, LabelResourceId> entry : adjLabelMap.entrySet()) {
Avantika-Huawei28b53752016-06-23 17:04:49 +05301314 if (entry.getKey().src().deviceId().equals(actualDevcieId)) {
1315 srTeHandler.installAdjLabelRule(actualDevcieId,
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301316 entry.getValue(),
1317 entry.getKey().src().port(),
1318 entry.getKey().dst().port(),
1319 Objective.Operation.ADD);
1320 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301321 }
1322 }
1323
Avantika-Huawei28b53752016-06-23 17:04:49 +05301324 srTeHandler.advertiseNodeLabelRule(actualDevcieId,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301325 LabelResourceId.labelResourceId(0),
1326 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
1327 Objective.Operation.ADD, true);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301328
Avantika-Huawei28b53752016-06-23 17:04:49 +05301329 log.debug("End of label DB sync for device {}", actualDevcieId);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301330
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301331 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1332 // Allocate node-label to this specific device.
1333 allocateNodeLabel(specificDevice);
1334
1335 // Allocate adjacency label
1336 Set<Link> links = linkService.getDeviceEgressLinks(specificDevice.id());
1337 if (links != null) {
1338 for (Link link : links) {
1339 allocateAdjacencyLabel(link);
1340 }
1341 }
1342 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301343
1344 return true;
1345 }
1346
1347 // Process the packet received.
1348 private class PcepPacketProcessor implements PacketProcessor {
1349 // Process the packet received and in our case initiates the label DB sync.
1350 @Override
1351 public void process(PacketContext context) {
1352 // Stop processing if the packet has been handled, since we
1353 // can't do any more to it.
Avantika-Huawei3524d852016-06-04 20:44:13 +05301354 log.debug("Received trigger for label DB sync.");
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301355 if (context.isHandled()) {
1356 return;
1357 }
1358
1359 InboundPacket pkt = context.inPacket();
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301360 if (pkt == null) {
1361 return;
1362 }
1363
1364 Ethernet ethernet = pkt.parsed();
1365 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
1366 return;
1367 }
1368
1369 IPv4 ipPacket = (IPv4) ethernet.getPayload();
1370 if (ipPacket == null || ipPacket.getProtocol() != IPv4.PROTOCOL_TCP) {
1371 return;
1372 }
1373
1374 TCP tcp = (TCP) ipPacket.getPayload();
1375 if (tcp == null || tcp.getDestinationPort() != PCEP_PORT) {
1376 return;
1377 }
1378
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301379 syncLabelDb(pkt.receivedFrom().deviceId());
1380 }
1381 }
1382
Priyanka B9fa4ed32016-05-27 11:59:24 +05301383 //Computes path from tunnel store and also path failed to setup.
1384 private void callForOptimization() {
1385 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1386 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1387 checkForMasterAndSetupPath(failedPathInfo);
1388 }
1389
1390 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1391 tunnelService.queryTunnel(MPLS).forEach(t -> {
1392 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1393 });
1394 }
1395
1396 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1397 /**
1398 * Master of ingress node will setup the path failed stored in PCE store.
1399 */
1400 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1401 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
1402 failedPathInfo.constraints(), failedPathInfo.lspType())) {
1403 // If computation is success remove that path
1404 pceStore.removeFailedPathInfo(failedPathInfo);
1405 return true;
1406 }
1407 }
1408
1409 return false;
1410 }
1411
1412 //Timer to call global optimization
1413 private class GlobalOptimizationTimer implements Runnable {
1414
1415 public GlobalOptimizationTimer() {
1416 }
1417
1418 @Override
1419 public void run() {
1420 callForOptimization();
1421 }
1422 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301423}