blob: 3ed670d3ddbe4866de0158bbcb6c7f5bb3551c06 [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
26import org.onosproject.incubator.net.resource.label.DefaultLabelResource;
27import org.onosproject.incubator.net.resource.label.LabelResource;
28import org.onosproject.incubator.net.resource.label.LabelResourceId;
29import org.onosproject.incubator.net.resource.label.LabelResourceService;
30import org.onosproject.incubator.net.tunnel.Tunnel;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.PortNumber;
33import org.onosproject.pce.pcestore.api.PceStore;
34import org.onosproject.pce.pcestore.api.LspLocalLabelInfo;
35import org.onosproject.pce.pcestore.PceccTunnelInfo;
36import org.onosproject.pce.pcestore.DefaultLspLocalLabelInfo;
37import org.onosproject.net.Link;
38
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import com.google.common.collect.ArrayListMultimap;
43import com.google.common.collect.Multimap;
44
45/**
46 * Basic PCECC handler.
47 * In Basic PCECC, after path computation will configure IN and OUT label to nodes.
48 * [X]OUT---link----IN[Y]OUT---link-----IN[Z] where X, Y and Z are nodes.
49 * For generating labels, will go thorough links in the path from Egress to Ingress.
50 * In each link, will take label from destination node local pool as IN label,
51 * and assign this label as OUT label to source node.
52 */
53public final class BasicPceccHandler {
54 private static final Logger log = LoggerFactory.getLogger(BasicPceccHandler.class);
55
56 private static final String LABEL_RESOURCE_SERVICE_NULL = "Label Resource Service cannot be null";
57 private static final String PCE_STORE_NULL = "PCE Store cannot be null";
58 private static BasicPceccHandler crHandlerInstance = null;
59 private LabelResourceService labelRsrcService;
60 private PceStore pceStore;
61
62 /**
63 * Initializes default values.
64 */
65 private BasicPceccHandler() {
66 }
67
68 /**
69 * Returns single instance of this class.
70 *
71 * @return this class single instance
72 */
73 public static BasicPceccHandler getInstance() {
74 if (crHandlerInstance == null) {
75 crHandlerInstance = new BasicPceccHandler();
76 }
77 return crHandlerInstance;
78 }
79
80 /**
81 * Initialization of label manager and pce store.
82 *
83 * @param labelRsrcService label resource service
84 * @param pceStore pce label store
85 */
86 public void initialize(LabelResourceService labelRsrcService, PceStore pceStore) {
87 this.labelRsrcService = labelRsrcService;
88 this.pceStore = pceStore;
89 }
90
91 /**
92 * Allocates labels from local resource pool and configure these (IN and OUT) labels into devices.
93 *
94 * @param tunnel tunnel between ingress to egress
95 * @return success or failure
96 */
97 public boolean allocateLabel(Tunnel tunnel) {
98 long applyNum = 1;
99 boolean isLastLabelToPush = false;
100 Collection<LabelResource> labelRscList;
101
102 checkNotNull(labelRsrcService, LABEL_RESOURCE_SERVICE_NULL);
103 checkNotNull(pceStore, PCE_STORE_NULL);
104
105 List<Link> linkList = tunnel.path().links();
106 if ((linkList != null) && (linkList.size() > 0)) {
107 // Sequence through reverse order to push local labels into devices
108 // Generation of labels from egress to ingress
109 for (ListIterator iterator = linkList.listIterator(linkList.size()); iterator.hasPrevious();) {
110 Link link = (Link) iterator.previous();
111 DeviceId dstDeviceId = link.dst().deviceId();
112 DeviceId srcDeviceId = link.src().deviceId();
113 labelRscList = labelRsrcService.applyFromDevicePool(dstDeviceId, applyNum);
114 if ((labelRscList != null) && (labelRscList.size() > 0)) {
115 // Link label value is taken from destination device local pool.
116 // [X]OUT---link----IN[Y]OUT---link-----IN[Z] where X, Y and Z are nodes.
117 // Link label value is used as OUT and IN for both ends
118 // (source and destination devices) of the link.
119 // Currently only one label is allocated to a device (destination device).
120 // So, no need to iterate through list
121 Iterator<LabelResource> labelIterator = labelRscList.iterator();
122 DefaultLabelResource defaultLabelResource = (DefaultLabelResource) labelIterator.next();
123 LabelResourceId labelId = defaultLabelResource.labelResourceId();
124 log.debug("Allocated local label: " + labelId.toString()
125 + "to device: " + defaultLabelResource.deviceId().toString());
126 PortNumber dstPort = link.dst().port();
127
128 // Check whether this is last link label to push
129 if (!iterator.hasPrevious()) {
130 isLastLabelToPush = true;
131 }
132
133 // Push into destination device
134 //TODO: uncomment below lines once installLocalLabelRule() method is ready
135 // Destination device IN port is link.dst().port()
136 //installLocalLabelRule(dstDeviceId, labelId, dstPort, tunnel.tunnelId(), isLastLabelToPush,
137 // LabelType.IN, Objective.Operation.ADD);
138
139 // Push into source device
140 //TODO: uncomment below lines once installLocalLabelRule() method is ready
141 // Source device OUT port will be link.dst().port(). Means its remote port used to send packet.
142 //installLocalLabelRule(srcDeviceId, labelId, dstPort, tunnel.tunnelId(), isLastLabelToPush,
143 // LabelType.OUT, Objective.Operation.ADD);
144
145 // Add or update pcecc tunnel info in pce store.
146 updatePceccTunnelInfoInStore(srcDeviceId, dstDeviceId, labelId, dstPort,
147 tunnel, isLastLabelToPush);
148 } else {
149 log.error("Unable to allocate label to device id {}.", dstDeviceId.toString());
150 releaseLabel(tunnel);
151 return false;
152 }
153 }
154 } else {
155 log.error("Tunnel {} is having empty links.", tunnel.toString());
156 return false;
157 }
158
159 return true;
160 }
161
162 /**
163 * Updates list of local labels of PCECC tunnel info in pce store.
164 *
165 * @param srcDeviceId source device in a link
166 * @param dstDeviceId destination device in a link
167 * @param labelId label id of a link
168 * @param dstPort destination device port number of a link
169 * @param tunnel tunnel
170 * @param isLastLabelToPush indicates this is the last label to push in Basic PCECC case
171 */
172 public void updatePceccTunnelInfoInStore(DeviceId srcDeviceId, DeviceId dstDeviceId, LabelResourceId labelId,
173 PortNumber dstPort, Tunnel tunnel, boolean isLastLabelToPush) {
174 // First try to retrieve device from store and update its label id if it is exists,
175 // otherwise add it
176 boolean dstDeviceUpdated = false;
177 boolean srcDeviceUpdated = false;
178
179 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
180 List<LspLocalLabelInfo> lspLabelInfoList;
181 if (pceccTunnelInfo != null) {
182 lspLabelInfoList = pceccTunnelInfo.lspLocalLabelInfoList();
183 if ((lspLabelInfoList != null) && (lspLabelInfoList.size() > 0)) {
184 for (int i = 0; i < lspLabelInfoList.size(); ++i) {
185 LspLocalLabelInfo lspLocalLabelInfo =
186 (DefaultLspLocalLabelInfo) lspLabelInfoList.get(i);
187 LspLocalLabelInfo.Builder lspLocalLabelInfoBuilder = null;
188 if (dstDeviceId.equals(lspLocalLabelInfo.deviceId())) {
189 lspLocalLabelInfoBuilder = DefaultLspLocalLabelInfo.builder(lspLocalLabelInfo);
190 lspLocalLabelInfoBuilder.inLabelId(labelId);
191 // Destination device IN port will be link destination port
192 lspLocalLabelInfoBuilder.inPort(dstPort);
193 dstDeviceUpdated = true;
194 } else if (srcDeviceId.equals(lspLocalLabelInfo.deviceId())) {
195 lspLocalLabelInfoBuilder = DefaultLspLocalLabelInfo.builder(lspLocalLabelInfo);
196 lspLocalLabelInfoBuilder.outLabelId(labelId);
197 // Source device OUT port will be link destination (remote) port
198 lspLocalLabelInfoBuilder.outPort(dstPort);
199 srcDeviceUpdated = true;
200 }
201
202 // Update
203 if ((lspLocalLabelInfoBuilder != null) && (dstDeviceUpdated || srcDeviceUpdated)) {
204 lspLabelInfoList.set(i, lspLocalLabelInfoBuilder.build());
205 }
206 }
207 }
208 }
209
210 // If it is not found in store then add it to store
211 if (!dstDeviceUpdated || !srcDeviceUpdated) {
212 // If tunnel info itself not available then create new one, otherwise add node to list.
213 if (pceccTunnelInfo == null) {
214 pceccTunnelInfo = new PceccTunnelInfo();
215 lspLabelInfoList = new LinkedList<>();
216 } else {
217 lspLabelInfoList = pceccTunnelInfo.lspLocalLabelInfoList();
218 if (lspLabelInfoList == null) {
219 lspLabelInfoList = new LinkedList<>();
220 }
221 }
222
223 if (!dstDeviceUpdated) {
224 LspLocalLabelInfo lspLocalLabelInfo = DefaultLspLocalLabelInfo.builder()
225 .deviceId(dstDeviceId)
226 .inLabelId(labelId)
227 .outLabelId(null)
228 .inPort(dstPort) // Destination device IN port will be link destination port
229 .outPort(null)
230 .build();
231 lspLabelInfoList.add(lspLocalLabelInfo);
232 }
233
234 if (!srcDeviceUpdated) {
235 LspLocalLabelInfo lspLocalLabelInfo = DefaultLspLocalLabelInfo.builder()
236 .deviceId(srcDeviceId)
237 .inLabelId(null)
238 .outLabelId(labelId)
239 .inPort(null)
240 .outPort(dstPort) // Source device OUT port will be link destination (remote) port
241 .build();
242 lspLabelInfoList.add(lspLocalLabelInfo);
243 }
244
245 pceccTunnelInfo.lspLocalLabelInfoList(lspLabelInfoList);
246 pceStore.addTunnelInfo(tunnel.tunnelId(), pceccTunnelInfo);
247 }
248 }
249
250 /**
251 * Deallocates unused labels to device pools.
252 *
253 * @param tunnel tunnel between ingress to egress
254 */
255 public void releaseLabel(Tunnel tunnel) {
256 boolean isLastLabelToPush = false;
257
258 checkNotNull(labelRsrcService, LABEL_RESOURCE_SERVICE_NULL);
259 checkNotNull(pceStore, PCE_STORE_NULL);
260
261 Multimap<DeviceId, LabelResource> release = ArrayListMultimap.create();
262 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
263 if (pceccTunnelInfo != null) {
264 List<LspLocalLabelInfo> lspLocalLabelInfoList = pceccTunnelInfo.lspLocalLabelInfoList();
265 if ((lspLocalLabelInfoList != null) && (lspLocalLabelInfoList.size() > 0)) {
266 for (Iterator<LspLocalLabelInfo> iterator = lspLocalLabelInfoList.iterator(); iterator.hasNext();) {
267 LspLocalLabelInfo lspLocalLabelInfo = (DefaultLspLocalLabelInfo) iterator.next();
268 DeviceId deviceId = lspLocalLabelInfo.deviceId();
269 LabelResourceId inLabelId = lspLocalLabelInfo.inLabelId();
270 LabelResourceId outLabelId = lspLocalLabelInfo.outLabelId();
271 PortNumber inPort = lspLocalLabelInfo.inPort();
272 PortNumber outPort = lspLocalLabelInfo.outPort();
273
274 // Check whether this is last link label to push
275 if (!iterator.hasNext()) {
276 isLastLabelToPush = true;
277 }
278
279 // Push into device
280 if ((inLabelId != null) && (inPort != null)) {
281 //TODO: uncomment below lines once installLocalLabelRule() method is ready
282 //installLocalLabelRule(deviceId, inLabelId, inPort, tunnelId, isLastLabelToPush,
283 // LabelType.IN, Objective.Operation.REMOVE);
284 }
285
286 if ((outLabelId != null) && (outPort != null)) {
287 //TODO: uncomment below lines once installLocalLabelRule() method is ready
288 //installLocalLabelRule(deviceId, outLabelId, outPort, tunnelId, isLastLabelToPush,
289 // LabelType.OUT, Objective.Operation.REMOVE);
290 }
291
292 // List is stored from egress to ingress. So, using IN label id to release.
293 // Only one local label is assigned to device (destination node)
294 // and that is used as OUT label for source node.
295 // No need to release label for last node in the list from pool because label was not allocated to
296 // ingress node (source node).
297 if ((iterator.hasNext()) && (inLabelId != null)) {
298 LabelResource labelRsc = new DefaultLabelResource(deviceId, inLabelId);
299 release.put(deviceId, labelRsc);
300 }
301 }
302 }
303
304 // Release from label pool
305 if (!release.isEmpty()) {
306 labelRsrcService.releaseToDevicePool(release);
307 }
308
309 // Remove tunnel info only if tunnel consumer id is not saved.
310 // If tunnel consumer id is saved, this tunnel info will be removed during releasing bandwidth.
311 if (pceccTunnelInfo.tunnelConsumerId() == null) {
312 pceStore.removeTunnelInfo(tunnel.tunnelId());
313 }
314 } else {
315 log.error("Unable to find PCECC tunnel info in store for a tunnel {}.", tunnel.toString());
316 }
317 }
318}