blob: 732a0b3b8bee7639dd31b400b84d4bdd96b5dd72 [file] [log] [blame]
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +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;
19
20import java.util.Collection;
21import java.util.Iterator;
22import java.util.List;
23import java.util.ListIterator;
24import java.util.LinkedList;
25
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053026import org.onlab.packet.MplsLabel;
27import org.onosproject.core.ApplicationId;
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +053028import org.onosproject.incubator.net.resource.label.DefaultLabelResource;
29import org.onosproject.incubator.net.resource.label.LabelResource;
30import org.onosproject.incubator.net.resource.label.LabelResourceId;
31import org.onosproject.incubator.net.resource.label.LabelResourceService;
32import org.onosproject.incubator.net.tunnel.Tunnel;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053033import org.onosproject.incubator.net.tunnel.TunnelId;
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +053034import org.onosproject.net.DeviceId;
35import org.onosproject.net.PortNumber;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053036import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
40import org.onosproject.net.flowobjective.DefaultForwardingObjective;
41import org.onosproject.net.flowobjective.FlowObjectiveService;
42import org.onosproject.net.flowobjective.ForwardingObjective;
43import org.onosproject.net.flowobjective.Objective;
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +053044import org.onosproject.pce.pcestore.api.PceStore;
45import org.onosproject.pce.pcestore.api.LspLocalLabelInfo;
46import org.onosproject.pce.pcestore.PceccTunnelInfo;
47import org.onosproject.pce.pcestore.DefaultLspLocalLabelInfo;
48import org.onosproject.net.Link;
49
50import org.slf4j.Logger;
51import org.slf4j.LoggerFactory;
52
53import com.google.common.collect.ArrayListMultimap;
54import com.google.common.collect.Multimap;
55
56/**
57 * Basic PCECC handler.
58 * In Basic PCECC, after path computation will configure IN and OUT label to nodes.
59 * [X]OUT---link----IN[Y]OUT---link-----IN[Z] where X, Y and Z are nodes.
60 * For generating labels, will go thorough links in the path from Egress to Ingress.
61 * In each link, will take label from destination node local pool as IN label,
62 * and assign this label as OUT label to source node.
63 */
64public final class BasicPceccHandler {
65 private static final Logger log = LoggerFactory.getLogger(BasicPceccHandler.class);
66
67 private static final String LABEL_RESOURCE_SERVICE_NULL = "Label Resource Service cannot be null";
68 private static final String PCE_STORE_NULL = "PCE Store cannot be null";
69 private static BasicPceccHandler crHandlerInstance = null;
70 private LabelResourceService labelRsrcService;
71 private PceStore pceStore;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +053072 private FlowObjectiveService flowObjectiveService;
73 private ApplicationId appId;
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +053074
75 /**
76 * Initializes default values.
77 */
78 private BasicPceccHandler() {
79 }
80
81 /**
82 * Returns single instance of this class.
83 *
84 * @return this class single instance
85 */
86 public static BasicPceccHandler getInstance() {
87 if (crHandlerInstance == null) {
88 crHandlerInstance = new BasicPceccHandler();
89 }
90 return crHandlerInstance;
91 }
92
93 /**
94 * Initialization of label manager and pce store.
95 *
96 * @param labelRsrcService label resource service
Mahesh Poojary Huaweie2d87ff2016-05-27 12:37:46 +053097 * @param flowObjectiveService flow objective service to push device label information
98 * @param appId applicaton id
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +053099 * @param pceStore pce label store
100 */
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530101 public void initialize(LabelResourceService labelRsrcService, FlowObjectiveService flowObjectiveService,
102 ApplicationId appId, PceStore pceStore) {
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530103 this.labelRsrcService = labelRsrcService;
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530104 this.flowObjectiveService = flowObjectiveService;
105 this.appId = appId;
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530106 this.pceStore = pceStore;
107 }
108
109 /**
110 * Allocates labels from local resource pool and configure these (IN and OUT) labels into devices.
111 *
112 * @param tunnel tunnel between ingress to egress
113 * @return success or failure
114 */
115 public boolean allocateLabel(Tunnel tunnel) {
116 long applyNum = 1;
117 boolean isLastLabelToPush = false;
118 Collection<LabelResource> labelRscList;
119
120 checkNotNull(labelRsrcService, LABEL_RESOURCE_SERVICE_NULL);
121 checkNotNull(pceStore, PCE_STORE_NULL);
122
123 List<Link> linkList = tunnel.path().links();
124 if ((linkList != null) && (linkList.size() > 0)) {
125 // Sequence through reverse order to push local labels into devices
126 // Generation of labels from egress to ingress
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530127 for (ListIterator<Link> iterator = linkList.listIterator(linkList.size()); iterator.hasPrevious();) {
128 Link link = iterator.previous();
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530129 DeviceId dstDeviceId = link.dst().deviceId();
130 DeviceId srcDeviceId = link.src().deviceId();
131 labelRscList = labelRsrcService.applyFromDevicePool(dstDeviceId, applyNum);
132 if ((labelRscList != null) && (labelRscList.size() > 0)) {
133 // Link label value is taken from destination device local pool.
134 // [X]OUT---link----IN[Y]OUT---link-----IN[Z] where X, Y and Z are nodes.
135 // Link label value is used as OUT and IN for both ends
136 // (source and destination devices) of the link.
137 // Currently only one label is allocated to a device (destination device).
138 // So, no need to iterate through list
139 Iterator<LabelResource> labelIterator = labelRscList.iterator();
140 DefaultLabelResource defaultLabelResource = (DefaultLabelResource) labelIterator.next();
141 LabelResourceId labelId = defaultLabelResource.labelResourceId();
142 log.debug("Allocated local label: " + labelId.toString()
143 + "to device: " + defaultLabelResource.deviceId().toString());
144 PortNumber dstPort = link.dst().port();
145
146 // Check whether this is last link label to push
147 if (!iterator.hasPrevious()) {
148 isLastLabelToPush = true;
149 }
150
151 // Push into destination device
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530152 // Destination device IN port is link.dst().port()
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530153 installLocalLabelRule(dstDeviceId, labelId, dstPort, tunnel.tunnelId(), isLastLabelToPush,
154 Long.valueOf(LabelType.IN_LABEL.value), Objective.Operation.ADD);
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530155
156 // Push into source device
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530157 // Source device OUT port will be link.dst().port(). Means its remote port used to send packet.
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530158 installLocalLabelRule(srcDeviceId, labelId, dstPort, tunnel.tunnelId(), isLastLabelToPush,
159 Long.valueOf(LabelType.OUT_LABEL.value), Objective.Operation.ADD);
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530160
161 // Add or update pcecc tunnel info in pce store.
162 updatePceccTunnelInfoInStore(srcDeviceId, dstDeviceId, labelId, dstPort,
163 tunnel, isLastLabelToPush);
164 } else {
165 log.error("Unable to allocate label to device id {}.", dstDeviceId.toString());
166 releaseLabel(tunnel);
167 return false;
168 }
169 }
170 } else {
171 log.error("Tunnel {} is having empty links.", tunnel.toString());
172 return false;
173 }
174
175 return true;
176 }
177
178 /**
179 * Updates list of local labels of PCECC tunnel info in pce store.
180 *
181 * @param srcDeviceId source device in a link
182 * @param dstDeviceId destination device in a link
183 * @param labelId label id of a link
184 * @param dstPort destination device port number of a link
185 * @param tunnel tunnel
186 * @param isLastLabelToPush indicates this is the last label to push in Basic PCECC case
187 */
188 public void updatePceccTunnelInfoInStore(DeviceId srcDeviceId, DeviceId dstDeviceId, LabelResourceId labelId,
189 PortNumber dstPort, Tunnel tunnel, boolean isLastLabelToPush) {
190 // First try to retrieve device from store and update its label id if it is exists,
191 // otherwise add it
192 boolean dstDeviceUpdated = false;
193 boolean srcDeviceUpdated = false;
194
195 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
196 List<LspLocalLabelInfo> lspLabelInfoList;
197 if (pceccTunnelInfo != null) {
198 lspLabelInfoList = pceccTunnelInfo.lspLocalLabelInfoList();
199 if ((lspLabelInfoList != null) && (lspLabelInfoList.size() > 0)) {
200 for (int i = 0; i < lspLabelInfoList.size(); ++i) {
201 LspLocalLabelInfo lspLocalLabelInfo =
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530202 lspLabelInfoList.get(i);
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530203 LspLocalLabelInfo.Builder lspLocalLabelInfoBuilder = null;
204 if (dstDeviceId.equals(lspLocalLabelInfo.deviceId())) {
205 lspLocalLabelInfoBuilder = DefaultLspLocalLabelInfo.builder(lspLocalLabelInfo);
206 lspLocalLabelInfoBuilder.inLabelId(labelId);
207 // Destination device IN port will be link destination port
208 lspLocalLabelInfoBuilder.inPort(dstPort);
209 dstDeviceUpdated = true;
210 } else if (srcDeviceId.equals(lspLocalLabelInfo.deviceId())) {
211 lspLocalLabelInfoBuilder = DefaultLspLocalLabelInfo.builder(lspLocalLabelInfo);
212 lspLocalLabelInfoBuilder.outLabelId(labelId);
213 // Source device OUT port will be link destination (remote) port
214 lspLocalLabelInfoBuilder.outPort(dstPort);
215 srcDeviceUpdated = true;
216 }
217
218 // Update
219 if ((lspLocalLabelInfoBuilder != null) && (dstDeviceUpdated || srcDeviceUpdated)) {
220 lspLabelInfoList.set(i, lspLocalLabelInfoBuilder.build());
221 }
222 }
223 }
224 }
225
226 // If it is not found in store then add it to store
227 if (!dstDeviceUpdated || !srcDeviceUpdated) {
228 // If tunnel info itself not available then create new one, otherwise add node to list.
229 if (pceccTunnelInfo == null) {
230 pceccTunnelInfo = new PceccTunnelInfo();
231 lspLabelInfoList = new LinkedList<>();
232 } else {
233 lspLabelInfoList = pceccTunnelInfo.lspLocalLabelInfoList();
234 if (lspLabelInfoList == null) {
235 lspLabelInfoList = new LinkedList<>();
236 }
237 }
238
239 if (!dstDeviceUpdated) {
240 LspLocalLabelInfo lspLocalLabelInfo = DefaultLspLocalLabelInfo.builder()
241 .deviceId(dstDeviceId)
242 .inLabelId(labelId)
243 .outLabelId(null)
244 .inPort(dstPort) // Destination device IN port will be link destination port
245 .outPort(null)
246 .build();
247 lspLabelInfoList.add(lspLocalLabelInfo);
248 }
249
250 if (!srcDeviceUpdated) {
251 LspLocalLabelInfo lspLocalLabelInfo = DefaultLspLocalLabelInfo.builder()
252 .deviceId(srcDeviceId)
253 .inLabelId(null)
254 .outLabelId(labelId)
255 .inPort(null)
256 .outPort(dstPort) // Source device OUT port will be link destination (remote) port
257 .build();
258 lspLabelInfoList.add(lspLocalLabelInfo);
259 }
260
261 pceccTunnelInfo.lspLocalLabelInfoList(lspLabelInfoList);
262 pceStore.addTunnelInfo(tunnel.tunnelId(), pceccTunnelInfo);
263 }
264 }
265
266 /**
267 * Deallocates unused labels to device pools.
268 *
269 * @param tunnel tunnel between ingress to egress
270 */
271 public void releaseLabel(Tunnel tunnel) {
272 boolean isLastLabelToPush = false;
273
274 checkNotNull(labelRsrcService, LABEL_RESOURCE_SERVICE_NULL);
275 checkNotNull(pceStore, PCE_STORE_NULL);
276
277 Multimap<DeviceId, LabelResource> release = ArrayListMultimap.create();
278 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
279 if (pceccTunnelInfo != null) {
280 List<LspLocalLabelInfo> lspLocalLabelInfoList = pceccTunnelInfo.lspLocalLabelInfoList();
281 if ((lspLocalLabelInfoList != null) && (lspLocalLabelInfoList.size() > 0)) {
282 for (Iterator<LspLocalLabelInfo> iterator = lspLocalLabelInfoList.iterator(); iterator.hasNext();) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530283 LspLocalLabelInfo lspLocalLabelInfo = iterator.next();
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530284 DeviceId deviceId = lspLocalLabelInfo.deviceId();
285 LabelResourceId inLabelId = lspLocalLabelInfo.inLabelId();
286 LabelResourceId outLabelId = lspLocalLabelInfo.outLabelId();
287 PortNumber inPort = lspLocalLabelInfo.inPort();
288 PortNumber outPort = lspLocalLabelInfo.outPort();
289
290 // Check whether this is last link label to push
291 if (!iterator.hasNext()) {
292 isLastLabelToPush = true;
293 }
294
295 // Push into device
296 if ((inLabelId != null) && (inPort != null)) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530297 installLocalLabelRule(deviceId, inLabelId, inPort, tunnel.tunnelId(), isLastLabelToPush,
298 Long.valueOf(LabelType.IN_LABEL.value), Objective.Operation.REMOVE);
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530299 }
300
301 if ((outLabelId != null) && (outPort != null)) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530302 installLocalLabelRule(deviceId, outLabelId, outPort, tunnel.tunnelId(), isLastLabelToPush,
303 Long.valueOf(LabelType.OUT_LABEL.value), Objective.Operation.REMOVE);
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530304 }
305
306 // List is stored from egress to ingress. So, using IN label id to release.
307 // Only one local label is assigned to device (destination node)
308 // and that is used as OUT label for source node.
309 // No need to release label for last node in the list from pool because label was not allocated to
310 // ingress node (source node).
311 if ((iterator.hasNext()) && (inLabelId != null)) {
312 LabelResource labelRsc = new DefaultLabelResource(deviceId, inLabelId);
313 release.put(deviceId, labelRsc);
314 }
315 }
316 }
317
318 // Release from label pool
319 if (!release.isEmpty()) {
320 labelRsrcService.releaseToDevicePool(release);
321 }
322
323 // Remove tunnel info only if tunnel consumer id is not saved.
324 // If tunnel consumer id is saved, this tunnel info will be removed during releasing bandwidth.
325 if (pceccTunnelInfo.tunnelConsumerId() == null) {
326 pceStore.removeTunnelInfo(tunnel.tunnelId());
327 }
328 } else {
329 log.error("Unable to find PCECC tunnel info in store for a tunnel {}.", tunnel.toString());
330 }
331 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530332
333 // Install a rule for pushing local labels to the device which is specific to path.
334 private void installLocalLabelRule(DeviceId deviceId, LabelResourceId labelId,
335 PortNumber portNum, TunnelId tunnelId,
336 Boolean isBos, Long labelType,
337 Objective.Operation type) {
338 checkNotNull(flowObjectiveService);
339 checkNotNull(appId);
340 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
341
342 selectorBuilder.matchMplsLabel(MplsLabel.mplsLabel(labelId.id().intValue()));
343 selectorBuilder.matchInPort(portNum);
344 selectorBuilder.matchTunnelId(Long.parseLong(tunnelId.id()));
345 selectorBuilder.matchMplsBos(isBos);
346 selectorBuilder.matchMetadata(labelType);
347
348 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
349
350 ForwardingObjective.Builder forwardingObjective = DefaultForwardingObjective.builder()
351 .withSelector(selectorBuilder.build())
352 .withTreatment(treatment)
353 .withFlag(ForwardingObjective.Flag.VERSATILE)
354 .fromApp(appId)
355 .makePermanent();
356
357 if (type.equals(Objective.Operation.ADD)) {
358 flowObjectiveService.forward(deviceId, forwardingObjective.add());
359 } else {
360 flowObjectiveService.forward(deviceId, forwardingObjective.remove());
361 }
362 }
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530363}