blob: e30b9666a359ea9d7e481eef5c11b6e73722f483 [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-Huawei3c2d3eb2016-06-22 09:34:00 +0530153 installLocalLabelRule(dstDeviceId, labelId, dstPort, tunnel.tunnelId(), false,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530154 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) {
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530272
273 checkNotNull(labelRsrcService, LABEL_RESOURCE_SERVICE_NULL);
274 checkNotNull(pceStore, PCE_STORE_NULL);
275
276 Multimap<DeviceId, LabelResource> release = ArrayListMultimap.create();
277 PceccTunnelInfo pceccTunnelInfo = pceStore.getTunnelInfo(tunnel.tunnelId());
278 if (pceccTunnelInfo != null) {
279 List<LspLocalLabelInfo> lspLocalLabelInfoList = pceccTunnelInfo.lspLocalLabelInfoList();
280 if ((lspLocalLabelInfoList != null) && (lspLocalLabelInfoList.size() > 0)) {
281 for (Iterator<LspLocalLabelInfo> iterator = lspLocalLabelInfoList.iterator(); iterator.hasNext();) {
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530282 LspLocalLabelInfo lspLocalLabelInfo = iterator.next();
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530283 DeviceId deviceId = lspLocalLabelInfo.deviceId();
284 LabelResourceId inLabelId = lspLocalLabelInfo.inLabelId();
285 LabelResourceId outLabelId = lspLocalLabelInfo.outLabelId();
286 PortNumber inPort = lspLocalLabelInfo.inPort();
287 PortNumber outPort = lspLocalLabelInfo.outPort();
288
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530289 // Push into device
290 if ((inLabelId != null) && (inPort != null)) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530291 installLocalLabelRule(deviceId, inLabelId, inPort, tunnel.tunnelId(), false,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530292 Long.valueOf(LabelType.IN_LABEL.value), Objective.Operation.REMOVE);
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530293 }
294
295 if ((outLabelId != null) && (outPort != null)) {
Priyanka B4c3b4512016-07-22 11:41:49 +0530296 installLocalLabelRule(deviceId, outLabelId, outPort, tunnel.tunnelId(), false,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530297 Long.valueOf(LabelType.OUT_LABEL.value), Objective.Operation.REMOVE);
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530298 }
299
300 // List is stored from egress to ingress. So, using IN label id to release.
301 // Only one local label is assigned to device (destination node)
302 // and that is used as OUT label for source node.
303 // No need to release label for last node in the list from pool because label was not allocated to
304 // ingress node (source node).
305 if ((iterator.hasNext()) && (inLabelId != null)) {
306 LabelResource labelRsc = new DefaultLabelResource(deviceId, inLabelId);
307 release.put(deviceId, labelRsc);
308 }
309 }
310 }
311
312 // Release from label pool
313 if (!release.isEmpty()) {
314 labelRsrcService.releaseToDevicePool(release);
315 }
316
317 // Remove tunnel info only if tunnel consumer id is not saved.
318 // If tunnel consumer id is saved, this tunnel info will be removed during releasing bandwidth.
319 if (pceccTunnelInfo.tunnelConsumerId() == null) {
320 pceStore.removeTunnelInfo(tunnel.tunnelId());
321 }
322 } else {
323 log.error("Unable to find PCECC tunnel info in store for a tunnel {}.", tunnel.toString());
324 }
325 }
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530326
327 // Install a rule for pushing local labels to the device which is specific to path.
Priyanka B4c3b4512016-07-22 11:41:49 +0530328 private synchronized void installLocalLabelRule(DeviceId deviceId, LabelResourceId labelId,
Avantika-Huaweidbdf7722016-05-21 14:20:31 +0530329 PortNumber portNum, TunnelId tunnelId,
330 Boolean isBos, Long labelType,
331 Objective.Operation type) {
332 checkNotNull(flowObjectiveService);
333 checkNotNull(appId);
334 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
335
336 selectorBuilder.matchMplsLabel(MplsLabel.mplsLabel(labelId.id().intValue()));
337 selectorBuilder.matchInPort(portNum);
338 selectorBuilder.matchTunnelId(Long.parseLong(tunnelId.id()));
339 selectorBuilder.matchMplsBos(isBos);
340 selectorBuilder.matchMetadata(labelType);
341
342 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
343
344 ForwardingObjective.Builder forwardingObjective = DefaultForwardingObjective.builder()
345 .withSelector(selectorBuilder.build())
346 .withTreatment(treatment)
347 .withFlag(ForwardingObjective.Flag.VERSATILE)
348 .fromApp(appId)
349 .makePermanent();
350
351 if (type.equals(Objective.Operation.ADD)) {
352 flowObjectiveService.forward(deviceId, forwardingObjective.add());
353 } else {
354 flowObjectiveService.forward(deviceId, forwardingObjective.remove());
355 }
356 }
Mahesh Poojary Sa4df1aa2016-05-13 08:53:53 +0530357}