blob: c0326b63c11d6205304bd55ce864206bdf8db55c [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);
Avantika-Huaweif849aab2016-06-21 22:29:15 +0530257 localLspIdIdGen.getNewId(); // To prevent 0, the 1st value generated from being used in protocol.
Avantika-Huawei73862d42016-05-12 18:58:06 +0530258 localLspIdFreeList = storageService.<Short>setBuilder()
259 .withName("pcepLocalLspIdDeletedList")
260 .withSerializer(Serializer.using(KryoNamespaces.API))
261 .build()
262 .asDistributedSet();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530263
264 packetService.addProcessor(processor, PacketProcessor.director(4));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530265 topologyService.addListener(topologyListener);
Priyanka B9fa4ed32016-05-27 11:59:24 +0530266 executor = Executors.newSingleThreadScheduledExecutor();
267 //Start a timer when the component is up, with initial delay of 30min and periodic delays at 30min
268 executor.scheduleAtFixedRate(new GlobalOptimizationTimer(), INITIAL_DELAY, PERIODIC_DELAY, TimeUnit.MINUTES);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530269
270 // Reserve global node pool
271 if (!srTeHandler.reserveGlobalPool(GLOBAL_LABEL_SPACE_MIN, GLOBAL_LABEL_SPACE_MAX)) {
272 log.debug("Global node pool was already reserved.");
273 }
274
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530275 log.info("Started");
Avantika-Huawei73862d42016-05-12 18:58:06 +0530276 }
277
278 @Deactivate
279 protected void deactivate() {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530280 tunnelService.removeListener(listener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530281 deviceService.removeListener(deviceListener);
282 linkService.removeListener(linkListener);
283 netCfgService.removeListener(cfgListener);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530284 packetService.removeProcessor(processor);
Priyanka B3f92c5a2016-05-27 10:14:16 +0530285 topologyService.removeListener(topologyListener);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530286 // Shutdown the thread when component is deactivated
Priyanka B9fa4ed32016-05-27 11:59:24 +0530287 executor.shutdown();
Avantika-Huawei73862d42016-05-12 18:58:06 +0530288 log.info("Stopped");
289 }
290
Priyanka Bb6963582016-05-20 20:21:20 +0530291 /**
292 * Returns an edge-weight capable of evaluating links on the basis of the
293 * specified constraints.
294 *
295 * @param constraints path constraints
296 * @return edge-weight function
297 */
298 private LinkWeight weight(List<Constraint> constraints) {
299 return new TeConstraintBasedLinkWeight(constraints);
300 }
301
302 /**
303 * Computes a path between two devices.
304 *
305 * @param src ingress device
306 * @param dst egress device
307 * @param constraints path constraints
308 * @return computed path based on constraints
309 */
310 protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
311 if (pathService == null) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530312 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530313 }
314 Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
315 if (!paths.isEmpty()) {
316 return paths;
317 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530318 return ImmutableSet.of();
Priyanka Bb6963582016-05-20 20:21:20 +0530319 }
320
Avantika-Huawei73862d42016-05-12 18:58:06 +0530321 //[TODO:] handle requests in queue
322 @Override
323 public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
324 LspType lspType) {
325 checkNotNull(src);
326 checkNotNull(dst);
327 checkNotNull(tunnelName);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530328 checkNotNull(lspType);
329
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530330 // Convert from DeviceId to TunnelEndPoint
331 Device srcDevice = deviceService.getDevice(src);
332 Device dstDevice = deviceService.getDevice(dst);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530333
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530334 if (srcDevice == null || dstDevice == null) {
335 // Device is not known.
336 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
337 return false;
338 }
339
340 // In future projections instead of annotations will be used to fetch LSR ID.
341 String srcLsrId = srcDevice.annotations().value(LSRID);
342 String dstLsrId = dstDevice.annotations().value(LSRID);
343
344 if (srcLsrId == null || dstLsrId == null) {
345 // LSR id is not known.
346 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
347 return false;
348 }
349
Avantika-Huawei032a9872016-05-27 22:57:38 +0530350 // Get device config from netconfig, to ascertain that session with ingress is present.
351 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
352 if (cfg == null) {
353 log.debug("No session to ingress.");
354 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
355 return false;
356 }
357
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530358 TunnelEndPoint srcEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(srcLsrId));
359 TunnelEndPoint dstEndPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dstLsrId));
360
361 double bwConstraintValue = 0;
362 CostConstraint costConstraint = null;
363 if (constraints != null) {
364 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
365 Iterator<Constraint> iterator = constraints.iterator();
366
367 while (iterator.hasNext()) {
368 Constraint constraint = iterator.next();
369 if (constraint instanceof BandwidthConstraint) {
370 bwConstraintValue = ((BandwidthConstraint) constraint).bandwidth().bps();
371 } else if (constraint instanceof CostConstraint) {
372 costConstraint = (CostConstraint) constraint;
373 }
374 }
375
376 /*
377 * Add cost at the end of the list of constraints. The path computation algorithm also computes cumulative
378 * cost. The function which checks the limiting/capability constraints also returns per link cost. This
379 * function can either return the result of limiting/capability constraint validation or the value of link
380 * cost, depending upon what is the last constraint in the loop.
381 */
382 if (costConstraint != null) {
383 constraints.remove(costConstraint);
384 constraints.add(costConstraint);
385 }
386 } else {
387 constraints = new LinkedList<>();
388 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspType.name())));
389 }
390
391 Set<Path> computedPathSet = computePath(src, dst, constraints);
392
393 // NO-PATH
394 if (computedPathSet.isEmpty()) {
395 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
396 return false;
397 }
398
399 Builder annotationBuilder = DefaultAnnotations.builder();
400 if (bwConstraintValue != 0) {
401 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
402 }
403 if (costConstraint != null) {
404 annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
405 }
406 annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
407 annotationBuilder.set(PCE_INIT, TRUE);
408 annotationBuilder.set(DELEGATE, TRUE);
409
410 Path computedPath = computedPathSet.iterator().next();
411 LabelStack labelStack = null;
412
413 if (lspType == SR_WITHOUT_SIGNALLING) {
414 labelStack = srTeHandler.computeLabelStack(computedPath);
415 // Failed to form a label stack.
416 if (labelStack == null) {
417 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
418 return false;
419 }
420 }
421
422 if (lspType != WITH_SIGNALLING) {
423 /*
424 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
425 * PCE for non-RSVP signalled LSPs.
426 */
427 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
428 }
429
430 // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
431 Tunnel tunnel = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
432 TunnelName.tunnelName(tunnelName), computedPath,
433 labelStack, annotationBuilder.build());
434
435 // Allocate bandwidth.
436 TunnelConsumerId consumerId = null;
437 if (bwConstraintValue != 0) {
438 consumerId = reserveBandwidth(computedPath, bwConstraintValue, null);
439 if (consumerId == null) {
440 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
441 return false;
442 }
443 }
444
445 TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
446 if (tunnelId == null) {
447 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType));
448 if (consumerId != null) {
449 resourceService.release(consumerId);
450 }
451 return false;
452 }
453
454 if (consumerId != null) {
455 // Store tunnel consumer id in LSP-Label store.
456 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
457 pceStore.addTunnelInfo(tunnelId, pceccTunnelInfo);
458 }
459 return true;
460 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530461
462 @Override
463 public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
464 checkNotNull(tunnelId);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530465 Set<Path> computedPathSet = null;
466 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
Avantika-Huawei73862d42016-05-12 18:58:06 +0530467
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530468 if (tunnel == null) {
469 return false;
470 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530471
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530472 if (tunnel.type() != MPLS || FALSE.equalsIgnoreCase(tunnel.annotations().value(DELEGATE))) {
473 // Only delegated LSPs can be updated.
474 return false;
475 }
476
477 List<Link> links = tunnel.path().links();
478 String lspSigType = tunnel.annotations().value(LSP_SIG_TYPE);
479 double bwConstraintValue = 0;
Priyanka B3f92c5a2016-05-27 10:14:16 +0530480 String costType = null;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530481 SharedBandwidthConstraint shBwConstraint = null;
482 BandwidthConstraint bwConstraint = null;
483 CostConstraint costConstraint = null;
484
485 if (constraints != null) {
486 // Call path computation in shared bandwidth mode.
487 Iterator<Constraint> iterator = constraints.iterator();
488 while (iterator.hasNext()) {
489 Constraint constraint = iterator.next();
490 if (constraint instanceof BandwidthConstraint) {
491 bwConstraint = (BandwidthConstraint) constraint;
492 bwConstraintValue = bwConstraint.bandwidth().bps();
493 } else if (constraint instanceof CostConstraint) {
494 costConstraint = (CostConstraint) constraint;
Avantika-Huawei032a9872016-05-27 22:57:38 +0530495 costType = costConstraint.type().name();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530496 }
497 }
498
499 // Remove and keep the cost constraint at the end of the list of constraints.
500 if (costConstraint != null) {
501 constraints.remove(costConstraint);
502 }
503
504 Bandwidth existingBwValue = null;
505 String existingBwAnnotation = tunnel.annotations().value(BANDWIDTH);
506 if (existingBwAnnotation != null) {
507 existingBwValue = Bandwidth.bps(Double.parseDouble(existingBwAnnotation));
508
509 /*
510 * The computation is a shared bandwidth constraint based, so need to remove bandwidth constraint which
511 * has been utilized to create shared bandwidth constraint.
512 */
513 if (bwConstraint != null) {
514 constraints.remove(bwConstraint);
515 }
516 }
517
518 if (existingBwValue != null) {
Priyanka B4c3cef02016-06-14 20:27:53 +0530519 if (bwConstraintValue == 0) {
520 bwConstraintValue = existingBwValue.bps();
521 }
522 //If bandwidth constraints not specified , take existing bandwidth for shared bandwidth calculation
523 shBwConstraint = bwConstraint != null ? new SharedBandwidthConstraint(links,
524 existingBwValue, bwConstraint.bandwidth()) : new SharedBandwidthConstraint(links,
525 existingBwValue, existingBwValue);
526
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530527 constraints.add(shBwConstraint);
528 }
529 } else {
530 constraints = new LinkedList<>();
531 }
532
533 constraints.add(CapabilityConstraint.of(CapabilityType.valueOf(lspSigType)));
534 if (costConstraint != null) {
535 constraints.add(costConstraint);
536 }
537
538 computedPathSet = computePath(links.get(0).src().deviceId(), links.get(links.size() - 1).dst().deviceId(),
539 constraints);
540
541 // NO-PATH
542 if (computedPathSet.isEmpty()) {
543 return false;
544 }
545
546 Builder annotationBuilder = DefaultAnnotations.builder();
547 annotationBuilder.set(BANDWIDTH, String.valueOf(bwConstraintValue));
Priyanka B3f92c5a2016-05-27 10:14:16 +0530548 if (costType != null) {
549 annotationBuilder.set(COST_TYPE, costType);
550 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530551 annotationBuilder.set(LSP_SIG_TYPE, lspSigType);
552 annotationBuilder.set(PCE_INIT, TRUE);
553 annotationBuilder.set(DELEGATE, TRUE);
554 annotationBuilder.set(PLSP_ID, tunnel.annotations().value(PLSP_ID));
555 annotationBuilder.set(PCC_TUNNEL_ID, tunnel.annotations().value(PCC_TUNNEL_ID));
556
557 Path computedPath = computedPathSet.iterator().next();
558 LabelStack labelStack = null;
559 TunnelConsumerId consumerId = null;
560 LspType lspType = LspType.valueOf(lspSigType);
561 long localLspId = 0;
562 if (lspType != WITH_SIGNALLING) {
563 /*
564 * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
565 * PCE for non-RSVP signalled LSPs.
566 */
567 localLspId = getNextLocalLspId();
568 annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(localLspId));
569
570 if (lspType == SR_WITHOUT_SIGNALLING) {
571 labelStack = srTeHandler.computeLabelStack(computedPath);
572 // Failed to form a label stack.
573 if (labelStack == null) {
574 return false;
575 }
576 }
577 }
578
579 Tunnel updatedTunnel = new DefaultTunnel(null, tunnel.src(), tunnel.dst(), MPLS, INIT, null, null,
580 tunnel.tunnelName(), computedPath,
581 labelStack, annotationBuilder.build());
582
583 // Allocate shared bandwidth.
584 if (bwConstraintValue != 0) {
585 consumerId = reserveBandwidth(computedPath, bwConstraintValue, shBwConstraint);
586 if (consumerId == null) {
587 return false;
588 }
589 }
590
591 TunnelId updatedTunnelId = tunnelService.setupTunnel(appId, links.get(0).src().deviceId(), updatedTunnel,
592 computedPath);
593
594 if (updatedTunnelId == null) {
595 if (consumerId != null) {
596 resourceService.release(consumerId);
597 }
598 return false;
599 }
600
601 if (consumerId != null) {
602 // Store tunnel consumer id in LSP-Label store.
603 PceccTunnelInfo pceccTunnelInfo = new PceccTunnelInfo(null, consumerId);
604 pceStore.addTunnelInfo(updatedTunnelId, pceccTunnelInfo);
605 }
Avantika-Huawei73862d42016-05-12 18:58:06 +0530606 return true;
607 }
608
609 @Override
610 public boolean releasePath(TunnelId tunnelId) {
611 checkNotNull(tunnelId);
612 // 1. Query Tunnel from Tunnel manager.
613 Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
614
615 if (tunnel == null) {
616 return false;
617 }
618
619 // 2. Call tunnel service.
620 return tunnelService.downTunnel(appId, tunnel.tunnelId());
621 }
622
623 @Override
624 public Iterable<Tunnel> queryAllPath() {
625 return tunnelService.queryTunnel(MPLS);
626 }
627
628 @Override
629 public Tunnel queryPath(TunnelId tunnelId) {
630 return tunnelService.queryTunnel(tunnelId);
631 }
632
633 /**
634 * Returns the next local LSP identifier to be used either by getting from
635 * freed list if available otherwise generating a new one.
636 *
637 * @return value of local LSP identifier
638 */
639 private short getNextLocalLspId() {
640 // If there is any free id use it. Otherwise generate new id.
641 if (localLspIdFreeList.isEmpty()) {
642 return (short) localLspIdIdGen.getNewId();
643 }
644 Iterator<Short> it = localLspIdFreeList.iterator();
645 Short value = it.next();
646 localLspIdFreeList.remove(value);
647 return value;
648 }
649
Priyanka Bb6963582016-05-20 20:21:20 +0530650 protected class TeConstraintBasedLinkWeight implements LinkWeight {
651
652 private final List<Constraint> constraints;
653
654 /**
655 * Creates a new edge-weight function capable of evaluating links
656 * on the basis of the specified constraints.
657 *
658 * @param constraints path constraints
659 */
660 public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
661 if (constraints == null) {
662 this.constraints = Collections.emptyList();
663 } else {
664 this.constraints = ImmutableList.copyOf(constraints);
665 }
666 }
667
668 @Override
669 public double weight(TopologyEdge edge) {
670 if (!constraints.iterator().hasNext()) {
671 //Takes default cost/hopcount as 1 if no constraints specified
672 return 1.0;
673 }
674
675 Iterator<Constraint> it = constraints.iterator();
676 double cost = 1;
677
678 //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
679 while (it.hasNext() && cost > 0) {
680 Constraint constraint = it.next();
681 if (constraint instanceof CapabilityConstraint) {
Avantika-Huawei032a9872016-05-27 22:57:38 +0530682 cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService,
683 netCfgService) ? 1 : -1;
Priyanka Bb6963582016-05-20 20:21:20 +0530684 } else {
685 cost = constraint.cost(edge.link(), resourceService::isAvailable);
686 }
687 }
688 return cost;
689 }
690 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530691
Priyanka B3f92c5a2016-05-27 10:14:16 +0530692 //TODO: annotations used for temporarily later projection/network config will be used
693 private class InternalTopologyListener implements TopologyListener {
694 @Override
695 public void event(TopologyEvent event) {
696 event.reasons().forEach(e -> {
697 //If event type is link removed, get the impacted tunnel
698 if (e instanceof LinkEvent) {
699 LinkEvent linkEvent = (LinkEvent) e;
700 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
701 tunnelService.queryTunnel(MPLS).forEach(t -> {
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +0530702 if (t.path().links().contains((e.subject()))) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530703 // Check whether this ONOS instance is master for ingress device if yes,
704 // recompute and send update
705 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
706 }
707 });
708 }
709 }
710 });
711 }
712 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530713
Priyanka B3f92c5a2016-05-27 10:14:16 +0530714 private boolean checkForMasterAndUpdateTunnel(DeviceId src, Tunnel tunnel) {
715 /**
716 * Master of ingress node will recompute and also delegation flag must be set.
717 */
718 if (mastershipService.isLocalMaster(src)
719 && Boolean.valueOf(tunnel.annotations().value(DELEGATE)) != null) {
720 LinkedList<Constraint> constraintList = new LinkedList<>();
721
722 if (tunnel.annotations().value(BANDWIDTH) != null) {
723 //Requested bandwidth will be same as previous allocated bandwidth for the tunnel
724 BandwidthConstraint localConst = new BandwidthConstraint(Bandwidth.bps(Double.parseDouble(tunnel
725 .annotations().value(BANDWIDTH))));
726 constraintList.add(localConst);
727 }
728 if (tunnel.annotations().value(COST_TYPE) != null) {
729 constraintList.add(CostConstraint.of(CostConstraint.Type.valueOf(tunnel.annotations().value(
730 COST_TYPE))));
731 }
Priyanka B9fa4ed32016-05-27 11:59:24 +0530732
733 /*
734 * If tunnel was UP after recomputation failed then store failed path in PCE store send PCIntiate(remove)
735 * and If tunnel is failed and computation fails nothing to do because tunnel status will be same[Failed]
736 */
737 if (!updatePath(tunnel.tunnelId(), constraintList) && !tunnel.state().equals(Tunnel.State.FAILED)) {
Priyanka B3f92c5a2016-05-27 10:14:16 +0530738 // If updation fails store in PCE store as failed path
739 // then PCInitiate (Remove)
740 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
741 .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
742 LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
743 //Release that tunnel calling PCInitiate
744 releasePath(tunnel.tunnelId());
745 }
746 }
747
748 return false;
749 }
750
751 // Allocates the bandwidth locally for PCECC tunnels.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530752 private TunnelConsumerId reserveBandwidth(Path computedPath, double bandwidthConstraint,
753 SharedBandwidthConstraint shBwConstraint) {
754 checkNotNull(computedPath);
755 checkNotNull(bandwidthConstraint);
756 Resource resource = null;
757 double bwToAllocate = 0;
758
759 TunnelConsumerId consumer = TunnelConsumerId.valueOf(tunnelConsumerIdGen.getNewId());
760
761 /**
762 * Shared bandwidth sub-case : Lesser bandwidth required than original -
763 * No reservation required.
764 */
765 Double additionalBwValue = null;
766 if (shBwConstraint != null) {
767 additionalBwValue = ((bandwidthConstraint - shBwConstraint.sharedBwValue().bps()) <= 0) ? null
768 : (bandwidthConstraint - shBwConstraint.sharedBwValue().bps());
769 }
770
771 Optional<ResourceAllocation> resAlloc = null;
772 for (Link link : computedPath.links()) {
773 bwToAllocate = 0;
774 if ((shBwConstraint != null) && (shBwConstraint.links().contains(link))) {
775 if (additionalBwValue != null) {
776 bwToAllocate = bandwidthConstraint - additionalBwValue;
777 }
778 } else {
779 bwToAllocate = bandwidthConstraint;
780 }
781
782 /**
783 * In shared bandwidth cases, where new BW is lesser than old BW, it
784 * is not required to allocate anything.
785 */
786 if (bwToAllocate != 0) {
787 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
788 .resource(bwToAllocate);
789 resAlloc = resourceService.allocate(consumer, resource);
790
791 // If allocation for any link fails, then release the partially allocated bandwidth.
792 if (!resAlloc.isPresent()) {
793 resourceService.release(consumer);
794 return null;
795 }
796 }
797 }
798
799 /*
800 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
801 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
802 * to who is supposed to store/delete.
803 */
804 return consumer;
805 }
806
807 /*
808 * Deallocates the bandwidth which is reserved locally for PCECC tunnels.
809 */
810 private void releaseBandwidth(Tunnel tunnel) {
811 // Between same source and destination, search the tunnel with same symbolic path name.
812 Collection<Tunnel> tunnelQueryResult = tunnelService.queryTunnel(tunnel.src(), tunnel.dst());
813 Tunnel newTunnel = null;
814 for (Tunnel tunnelObj : tunnelQueryResult) {
815 if (tunnel.tunnelName().value().equals(tunnelObj.tunnelName().value())) {
816 newTunnel = tunnelObj;
817 break;
818 }
819 }
820
821 // Even if one link is shared, the bandwidth release should happen based on shared mechanism.
822 boolean isLinkShared = false;
823 if (newTunnel != null) {
824 for (Link link : tunnel.path().links()) {
825 if (newTunnel.path().links().contains(link)) {
826 isLinkShared = true;
827 break;
828 }
829 }
830 }
831
832 if (isLinkShared) {
833 releaseSharedBandwidth(newTunnel, tunnel);
834 return;
835 }
836
837 resourceService.release(pceStore.getTunnelInfo(tunnel.tunnelId()).tunnelConsumerId());
838 return;
839
840 /*
841 * Note: Storing of tunnel consumer id is done by caller of bandwidth reservation function. So deleting tunnel
842 * consumer id should be done by caller of bandwidth releasing function. This will prevent ambiguities related
843 * to who is supposed to store/delete.
844 */
845 }
846
847 /**
848 * Re-allocates the bandwidth for the tunnel for which the bandwidth was
849 * allocated in shared mode initially.
850 */
851 private synchronized void releaseSharedBandwidth(Tunnel newTunnel, Tunnel oldTunnel) {
852 // 1. Release old tunnel's bandwidth.
853 resourceService.release(pceStore.getTunnelInfo(oldTunnel.tunnelId()).tunnelConsumerId());
854
855 // 2. Release new tunnel's bandwidth
856 ResourceConsumer consumer = pceStore.getTunnelInfo(newTunnel.tunnelId()).tunnelConsumerId();
857 resourceService.release(consumer);
858
859 // 3. Allocate new tunnel's complete bandwidth.
860 double bandwidth = Double.parseDouble(newTunnel.annotations().value(BANDWIDTH));
861 Resource resource;
862
863 for (Link link : newTunnel.path().links()) {
864 resource = Resources.continuous(link.src().deviceId(), link.src().port(), Bandwidth.class)
865 .resource(bandwidth);
866 resourceService.allocate(consumer, resource); // Reusing new tunnel's TunnelConsumerId intentionally.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530867
868 }
869 }
870
871 /**
872 * Allocates node label to specific device.
873 *
874 * @param specificDevice device to which node label needs to be allocated
875 */
876 public void allocateNodeLabel(Device specificDevice) {
877 checkNotNull(specificDevice, DEVICE_NULL);
878
879 DeviceId deviceId = specificDevice.id();
880
881 // Retrieve lsrId of a specific device
882 if (specificDevice.annotations() == null) {
883 log.debug("Device {} does not have annotations.", specificDevice.toString());
884 return;
885 }
886
887 String lsrId = specificDevice.annotations().value(LSRID);
888 if (lsrId == null) {
889 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
890 return;
891 }
892
893 // Get capability config from netconfig
894 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
895 if (cfg == null) {
896 log.error("Unable to find corresponding capability for a lsrd {} from NetConfig.", lsrId);
897 // Save info. When PCEP session is comes up then allocate node-label
898 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
899 return;
900 }
901
902 // Check whether device has SR-TE Capability
903 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530904 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530905 }
906 }
907
908 /**
909 * Releases node label of a specific device.
910 *
911 * @param specificDevice this device label and lsr-id information will be
912 * released in other existing devices
913 */
914 public void releaseNodeLabel(Device specificDevice) {
915 checkNotNull(specificDevice, DEVICE_NULL);
916
917 DeviceId deviceId = specificDevice.id();
918
919 // Retrieve lsrId of a specific device
920 if (specificDevice.annotations() == null) {
921 log.debug("Device {} does not have annotations.", specificDevice.toString());
922 return;
923 }
924
925 String lsrId = specificDevice.annotations().value(LSRID);
926 if (lsrId == null) {
927 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
928 return;
929 }
930
931 // Get capability config from netconfig
932 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
933 if (cfg == null) {
934 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
935 return;
936 }
937
938 // Check whether device has SR-TE Capability
939 if (cfg.labelStackCap()) {
940 if (!srTeHandler.releaseNodeLabel(deviceId, lsrId)) {
941 log.error("Unable to release node label for a device id {}.", deviceId.toString());
942 }
943 }
944 }
945
946 /**
947 * Allocates adjacency label for a link.
948 *
949 * @param link link
950 */
951 public void allocateAdjacencyLabel(Link link) {
952 checkNotNull(link, LINK_NULL);
953
954 Device specificDevice = deviceService.getDevice(link.src().deviceId());
955 DeviceId deviceId = specificDevice.id();
956
957 // Retrieve lsrId of a specific device
958 if (specificDevice.annotations() == null) {
959 log.debug("Device {} does not have annotations.", specificDevice.toString());
960 return;
961 }
962
963 String lsrId = specificDevice.annotations().value(LSRID);
964 if (lsrId == null) {
965 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
966 return;
967 }
968
969 // Get capability config from netconfig
970 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
971 if (cfg == null) {
972 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
973 // Save info. When PCEP session comes up then allocate adjacency
974 // label
975 if (lsrIdDeviceIdMap.get(lsrId) != null) {
976 lsrIdDeviceIdMap.put(lsrId, specificDevice.id());
977 }
978 return;
979 }
980
981 // Check whether device has SR-TE Capability
982 if (cfg.labelStackCap()) {
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530983 srTeHandler.allocateAdjacencyLabel(link);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +0530984 }
985
986 return;
987 }
988
989 /**
990 * Releases allocated adjacency label of a link.
991 *
992 * @param link link
993 */
994 public void releaseAdjacencyLabel(Link link) {
995 checkNotNull(link, LINK_NULL);
996
997 Device specificDevice = deviceService.getDevice(link.src().deviceId());
998 DeviceId deviceId = specificDevice.id();
999
1000 // Retrieve lsrId of a specific device
1001 if (specificDevice.annotations() == null) {
1002 log.debug("Device {} does not have annotations.", specificDevice.toString());
1003 return;
1004 }
1005
1006 String lsrId = specificDevice.annotations().value(LSRID);
1007 if (lsrId == null) {
1008 log.debug("Unable to retrieve lsr-id of a device {}.", specificDevice.toString());
1009 return;
1010 }
1011
1012 // Get capability config from netconfig
1013 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1014 if (cfg == null) {
1015 log.error("Unable to find corresponding capabilty for a lsrd {} from NetConfig.", lsrId);
1016 return;
1017 }
1018
1019 // Check whether device has SR-TE Capability
1020 if (cfg.labelStackCap()) {
1021 if (!srTeHandler.releaseAdjacencyLabel(link)) {
1022 log.error("Unable to release adjacency labels for a link {}.", link.toString());
1023 return;
1024 }
1025 }
1026
1027 return;
1028 }
1029
1030 /*
1031 * Handle device events.
1032 */
1033 private class InternalDeviceListener implements DeviceListener {
1034 @Override
1035 public void event(DeviceEvent event) {
1036 Device specificDevice = (Device) event.subject();
1037 if (specificDevice == null) {
1038 log.error("Unable to find device from device event.");
1039 return;
1040 }
1041
1042 switch (event.type()) {
1043
1044 case DEVICE_ADDED:
1045 // Node-label allocation is being done during Label DB Sync.
1046 // So, when device is detected, no need to do node-label
1047 // allocation.
1048 break;
1049
1050 case DEVICE_REMOVED:
1051 // Release node-label
1052 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1053 releaseNodeLabel(specificDevice);
1054 }
1055 break;
1056
1057 default:
1058 break;
1059 }
1060 }
1061 }
1062
1063 /*
1064 * Handle link events.
1065 */
1066 private class InternalLinkListener implements LinkListener {
1067 @Override
1068 public void event(LinkEvent event) {
1069 Link link = (Link) event.subject();
1070
1071 switch (event.type()) {
1072
1073 case LINK_ADDED:
1074 // Allocate adjacency label
1075 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1076 allocateAdjacencyLabel(link);
1077 }
1078 break;
1079
1080 case LINK_REMOVED:
1081 // Release adjacency label
1082 if (mastershipService.getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
1083 releaseAdjacencyLabel(link);
1084 }
1085 break;
1086
1087 default:
1088 break;
1089 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301090 }
1091 }
1092
1093 // Listens on tunnel events.
1094 private class InnerTunnelListener implements TunnelListener {
1095 @Override
1096 public void event(TunnelEvent event) {
1097 // Event gets generated with old tunnel object.
1098 Tunnel tunnel = event.subject();
1099 if (tunnel.type() != MPLS) {
1100 return;
1101 }
1102
1103 LspType lspType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
1104 String tunnelBandwidth = tunnel.annotations().value(BANDWIDTH);
1105 double bwConstraintValue = 0;
1106 if (tunnelBandwidth != null) {
1107 bwConstraintValue = Double.parseDouble(tunnelBandwidth);
1108 }
1109
1110 switch (event.type()) {
1111 case TUNNEL_ADDED:
1112 // Allocate bandwidth for non-initiated, delegated LSPs with non-zero bandwidth (learned LSPs).
1113 String pceInit = tunnel.annotations().value(PCE_INIT);
1114 if (FALSE.equalsIgnoreCase(pceInit)
1115 && bwConstraintValue != 0) {
1116 reserveBandwidth(tunnel.path(), bwConstraintValue, null);
1117 }
1118 break;
1119
1120 case TUNNEL_UPDATED:
1121 // Allocate/send labels for basic PCECC tunnels.
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301122 if ((tunnel.state() == ESTABLISHED) && (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR)
1123 && (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER)) {
1124 if (!crHandler.allocateLabel(tunnel)) {
1125 log.error("Unable to allocate labels for a tunnel {}.", tunnel.toString());
1126 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301127 }
1128
1129 if (tunnel.state() == UNSTABLE) {
1130 /*
1131 * During LSP DB sync if PCC doesn't report LSP which was PCE initiated, it's state is turned into
1132 * unstable so that it can be setup again. Add into failed path store so that it can be recomputed
1133 * and setup while global reoptimization.
1134 */
1135
1136 List<Constraint> constraints = new LinkedList<>();
1137 String bandwidth = tunnel.annotations().value(BANDWIDTH);
1138 if (bandwidth != null) {
1139 constraints.add(new BandwidthConstraint(Bandwidth
1140 .bps(Double.parseDouble(bandwidth))));
1141 }
1142
1143 String costType = tunnel.annotations().value(COST_TYPE);
1144 if (costType != null) {
1145 CostConstraint costConstraint = new CostConstraint(CostConstraint.Type.valueOf(costType));
1146 constraints.add(costConstraint);
1147 }
1148
1149 constraints.add(CapabilityConstraint
1150 .of(CapabilityType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE))));
1151
1152 List<Link> links = tunnel.path().links();
1153 pceStore.addFailedPathInfo(new PcePathInfo(links.get(0).src().deviceId(),
1154 links.get(links.size() - 1).dst().deviceId(),
1155 tunnel.tunnelName().value(), constraints, lspType));
1156 }
1157 break;
1158
1159 case TUNNEL_REMOVED:
1160 if (lspType != WITH_SIGNALLING) {
1161 localLspIdFreeList.add(Short.valueOf(tunnel.annotations().value(LOCAL_LSP_ID)));
1162 }
1163
1164 // If not zero bandwidth, and delegated (initiated LSPs will also be delegated).
1165 if (bwConstraintValue != 0) {
1166 releaseBandwidth(event.subject());
1167
1168 // Release basic PCECC labels.
1169 if (lspType == WITHOUT_SIGNALLING_AND_WITHOUT_SR) {
1170 // Delete stored tunnel consumer id from PCE store (while still retaining label list.)
1171 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
1172 pceccTunnelInfo.tunnelConsumerId(null);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301173 if (mastershipService.getLocalRole(tunnel.path().src().deviceId()) == MastershipRole.MASTER) {
1174 crHandler.releaseLabel(tunnel);
1175 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301176 } else {
1177 pceStore.removeTunnelInfo(tunnel.tunnelId());
1178 }
1179 }
1180 break;
1181
1182 default:
1183 break;
1184
1185 }
1186 return;
1187 }
1188 }
1189
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301190 private class InternalConfigListener implements NetworkConfigListener {
1191
1192 @Override
1193 public void event(NetworkConfigEvent event) {
1194
1195 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED)
1196 && event.configClass().equals(DeviceCapability.class)) {
1197
1198 DeviceId deviceIdLsrId = (DeviceId) event.subject();
1199 String lsrId = deviceIdLsrId.toString();
1200 DeviceId deviceId = lsrIdDeviceIdMap.get(lsrId);
1201 if (deviceId == null) {
1202 log.debug("Unable to find device id for a lsr-id {} from lsr-id and device-id map.", lsrId);
1203 return;
1204 }
1205
1206 DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(lsrId), DeviceCapability.class);
1207 if (cfg == null) {
1208 log.error("Unable to find corresponding capabilty for a lsrd {}.", lsrId);
1209 return;
1210 }
1211
1212 if (cfg.labelStackCap()) {
1213 if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
1214 // Allocate node-label
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301215 srTeHandler.allocateNodeLabel(deviceId, lsrId);
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301216
1217 // Allocate adjacency label to links which are
1218 // originated from this specific device id
1219 Set<Link> links = linkService.getDeviceEgressLinks(deviceId);
1220 for (Link link : links) {
1221 if (!srTeHandler.allocateAdjacencyLabel(link)) {
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301222 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-Huaweifc10dca2016-06-10 16:13:55 +05301243 if (pceStore.getGlobalNodeLabel(deviceId) != null) {
1244 Map<DeviceId, LabelResourceId> globalNodeLabelMap = pceStore.getGlobalNodeLabels();
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301245
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301246 for (Entry<DeviceId, LabelResourceId> entry : globalNodeLabelMap.entrySet()) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301247
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301248 // Convert from DeviceId to TunnelEndPoint
1249 Device srcDevice = deviceService.getDevice(entry.getKey());
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301250
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301251 /*
1252 * If there is a slight difference in timing such that if device subsystem has removed the device but
1253 * PCE store still has it, just ignore such devices.
1254 */
1255 if (srcDevice == null) {
1256 continue;
1257 }
1258
1259 String srcLsrId = srcDevice.annotations().value(LSRID);
1260 if (srcLsrId == null) {
1261 continue;
1262 }
1263
1264 srTeHandler.advertiseNodeLabelRule(deviceId,
1265 entry.getValue(),
1266 IpPrefix.valueOf(IpAddress.valueOf(srcLsrId), PREFIX_LENGTH),
1267 Objective.Operation.ADD, false);
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301268 }
1269
Avantika-Huaweifc10dca2016-06-10 16:13:55 +05301270 Map<Link, LabelResourceId> adjLabelMap = pceStore.getAdjLabels();
1271 for (Entry<Link, LabelResourceId> entry : adjLabelMap.entrySet()) {
1272 if (entry.getKey().src().deviceId().equals(deviceId)) {
1273 srTeHandler.installAdjLabelRule(deviceId,
1274 entry.getValue(),
1275 entry.getKey().src().port(),
1276 entry.getKey().dst().port(),
1277 Objective.Operation.ADD);
1278 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301279 }
1280 }
1281
1282 srTeHandler.advertiseNodeLabelRule(deviceId,
1283 LabelResourceId.labelResourceId(0),
1284 IpPrefix.valueOf(END_OF_SYNC_IP_PREFIX),
1285 Objective.Operation.ADD, true);
Avantika-Huawei3524d852016-06-04 20:44:13 +05301286
1287 log.debug("End of label DB sync for device {}", deviceId);
1288
Mahesh Poojary Huawei1d17cad2016-06-02 12:53:41 +05301289 if (mastershipService.getLocalRole(specificDevice.id()) == MastershipRole.MASTER) {
1290 // Allocate node-label to this specific device.
1291 allocateNodeLabel(specificDevice);
1292
1293 // Allocate adjacency label
1294 Set<Link> links = linkService.getDeviceEgressLinks(specificDevice.id());
1295 if (links != null) {
1296 for (Link link : links) {
1297 allocateAdjacencyLabel(link);
1298 }
1299 }
1300 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301301
1302 return true;
1303 }
1304
1305 // Process the packet received.
1306 private class PcepPacketProcessor implements PacketProcessor {
1307 // Process the packet received and in our case initiates the label DB sync.
1308 @Override
1309 public void process(PacketContext context) {
1310 // Stop processing if the packet has been handled, since we
1311 // can't do any more to it.
Avantika-Huawei3524d852016-06-04 20:44:13 +05301312 log.debug("Received trigger for label DB sync.");
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301313 if (context.isHandled()) {
1314 return;
1315 }
1316
1317 InboundPacket pkt = context.inPacket();
Avantika-Huaweid1e36bd2016-05-26 12:47:16 +05301318 if (pkt == null) {
1319 return;
1320 }
1321
1322 Ethernet ethernet = pkt.parsed();
1323 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
1324 return;
1325 }
1326
1327 IPv4 ipPacket = (IPv4) ethernet.getPayload();
1328 if (ipPacket == null || ipPacket.getProtocol() != IPv4.PROTOCOL_TCP) {
1329 return;
1330 }
1331
1332 TCP tcp = (TCP) ipPacket.getPayload();
1333 if (tcp == null || tcp.getDestinationPort() != PCEP_PORT) {
1334 return;
1335 }
1336
Avantika-Huaweidbdf7722016-05-21 14:20:31 +05301337 syncLabelDb(pkt.receivedFrom().deviceId());
1338 }
1339 }
1340
Priyanka B9fa4ed32016-05-27 11:59:24 +05301341 //Computes path from tunnel store and also path failed to setup.
1342 private void callForOptimization() {
1343 //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
1344 for (PcePathInfo failedPathInfo : pceStore.getFailedPathInfos()) {
1345 checkForMasterAndSetupPath(failedPathInfo);
1346 }
1347
1348 //Recompute the LSPs for which it was delegated [LSPs stored in tunnel store]
1349 tunnelService.queryTunnel(MPLS).forEach(t -> {
1350 checkForMasterAndUpdateTunnel(t.path().src().deviceId(), t);
1351 });
1352 }
1353
1354 private boolean checkForMasterAndSetupPath(PcePathInfo failedPathInfo) {
1355 /**
1356 * Master of ingress node will setup the path failed stored in PCE store.
1357 */
1358 if (mastershipService.isLocalMaster(failedPathInfo.src())) {
1359 if (setupPath(failedPathInfo.src(), failedPathInfo.dst(), failedPathInfo.name(),
1360 failedPathInfo.constraints(), failedPathInfo.lspType())) {
1361 // If computation is success remove that path
1362 pceStore.removeFailedPathInfo(failedPathInfo);
1363 return true;
1364 }
1365 }
1366
1367 return false;
1368 }
1369
1370 //Timer to call global optimization
1371 private class GlobalOptimizationTimer implements Runnable {
1372
1373 public GlobalOptimizationTimer() {
1374 }
1375
1376 @Override
1377 public void run() {
1378 callForOptimization();
1379 }
1380 }
Avantika-Huawei73862d42016-05-12 18:58:06 +05301381}