blob: c150e26a3e9013a653eddb2bd748cfbe40510e3c [file] [log] [blame]
Pier Ventref8543d82016-09-28 19:49:33 -07001/*
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 */
16
17package org.onosproject.net.resource.impl;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.Iterables;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
24import org.apache.commons.lang.math.RandomUtils;
25import org.onlab.packet.MplsLabel;
26import org.onlab.packet.VlanId;
27import org.onlab.util.Identifier;
28import org.onosproject.net.ConnectPoint;
29import org.onosproject.net.EncapsulationType;
30import org.onosproject.net.Link;
31import org.onosproject.net.LinkKey;
32import org.onosproject.net.intent.IntentId;
33import org.onosproject.net.resource.Resource;
34import org.onosproject.net.resource.ResourceAllocation;
35import org.onosproject.net.resource.ResourceService;
36import org.onosproject.net.resource.Resources;
37
Yuta HIGUCHI1f722032016-12-03 13:56:50 -080038import static com.google.common.base.Preconditions.checkNotNull;
39
Pier Ventref8543d82016-09-28 19:49:33 -070040import java.util.Collections;
41import java.util.List;
42import java.util.Map;
43import java.util.Set;
44import java.util.stream.Collectors;
45import java.util.stream.Stream;
46
47/**
48 * Helper class which interacts with the ResourceService and provides
49 * a unified API to allocate MPLS labels and VLAN Ids.
50 */
51public final class LabelAllocator {
52
53 private enum Behavior {
54 /**
55 * Random selection.
56 */
57 RANDOM,
58 /**
59 * First fit selection.
60 */
61 FIRST_FIT
62 }
63
64 private static final Behavior[] BEHAVIORS = Behavior.values();
65
66 private ResourceService resourceService;
67 private LabelSelection labelSelection;
68
69 /**
70 * Creates a new label allocator. Random is the
71 * default behavior.
72 *
73 * @param rs the resource service
74 */
75 public LabelAllocator(ResourceService rs) {
Yuta HIGUCHI1f722032016-12-03 13:56:50 -080076 this.resourceService = checkNotNull(rs);
Pier Ventref8543d82016-09-28 19:49:33 -070077 this.labelSelection = this.getLabelSelection(Behavior.RANDOM);
78 }
79
80 /**
81 * Checks if a given string is a valid Behavior.
82 *
83 * @param value the string to check
84 * @return true if value is a valid Behavior, false otherwise
85 */
86 public static boolean isInEnum(String value) {
87 for (Behavior b : BEHAVIORS) {
88 if (b.name().equals(value)) {
89 return true;
90 }
91 }
92 return false;
93 }
94
95 /**
96 * Changes the selection behavior.
97 *
98 * @param type the behavior type
99 */
100 public void setLabelSelection(String type) {
101 if (isInEnum(type)) {
102 this.labelSelection = this.getLabelSelection(type);
103 }
104 }
105
106 /**
107 * Retrieves the label selection behavior.
108 *
109 * @return the label selection behavior in use
110 */
111 public LabelSelection getLabelSelection() {
112 return this.labelSelection;
113 }
114
115 /**
116 * Returns the label selection behavior, given a behavior type.
117 *
118 * @param type the behavior type
119 * @return the label selection behavior in use
120 */
121 private LabelSelection getLabelSelection(String type) {
122 Behavior behavior = Behavior.valueOf(type);
123 return this.getLabelSelection(behavior);
124 }
125
126 /**
127 * Creates a new LabelSelection. Random is
128 * the default label selection behavior.
129 *
130 * @param type the behavior type
131 * @return the object implementing the behavior
132 */
133 private LabelSelection getLabelSelection(Behavior type) {
134 LabelSelection selection = null;
135 switch (type) {
136 case FIRST_FIT:
137 selection = new FirstFitSelection();
138 break;
139 case RANDOM:
140 default:
141 selection = new RandomSelection();
142 break;
143 }
144 return selection;
145 }
146
147 /**
148 * Looks for available Ids.
149 *
150 * @param links the links where to look for Ids
151 * @param type the encapsulation type
152 * @return the mappings between key and id
153 */
154 private Map<LinkKey, Identifier<?>> findAvailableIDs(Set<LinkKey> links, EncapsulationType type) {
155
156 Map<LinkKey, Identifier<?>> ids = Maps.newHashMap();
157 for (LinkKey link : links) {
158 Set<Identifier<?>> availableIDsatSrc = getAvailableIDs(link.src(), type);
159 Set<Identifier<?>> availableIDsatDst = getAvailableIDs(link.dst(), type);
160 Set<Identifier<?>> common = Sets.intersection(availableIDsatSrc, availableIDsatDst);
161 if (common.isEmpty()) {
162 continue;
163 }
164 Identifier<?> selected = labelSelection.select(common);
165 if (selected == null) {
166 continue;
167 }
168 ids.put(link, selected);
169 }
170 return ids;
171 }
172
173 /**
174 * Looks for available Ids associated to the given connection point.
175 *
176 * @param cp the connection point
177 * @param type the type of Id
178 * @return the set of available Ids
179 */
180 private Set<Identifier<?>> getAvailableIDs(ConnectPoint cp, EncapsulationType type) {
181 return resourceService.getAvailableResourceValues(
182 Resources.discrete(cp.deviceId(), cp.port()).id(), getEncapsulationClass(type)
183 );
184 }
185
186 /**
187 * Method to map the encapsulation type to identifier class.
188 * VLAN is the default encapsulation.
189 *
190 * @param type the type of encapsulation
191 * @return the id class
192 */
193 private Class getEncapsulationClass(EncapsulationType type) {
194 Class idType;
195 switch (type) {
196 case MPLS:
197 idType = MplsLabel.class;
198 break;
199 case VLAN:
200 default:
201 idType = VlanId.class;
202 }
203 return idType;
204 }
205
206 /**
207 * Allocates labels and associates them to links.
208 *
209 * @param links the links where labels will be allocated
210 * @param id the intent Id
211 * @param type the encapsulation type
212 * @return the list of links and associated labels
213 */
214 public Map<LinkKey, Identifier<?>> assignLabelToLinks(Set<Link> links, IntentId id, EncapsulationType type) {
215
216 Set<LinkKey> linkRequest = Sets.newHashSet();
217
218 links.forEach(link -> {
219 linkRequest.add(LinkKey.linkKey(link));
220 });
221
222 Map<LinkKey, Identifier<?>> availableIds = findAvailableIDs(linkRequest, type);
223 if (availableIds.isEmpty()) {
224 return Collections.emptyMap();
225 }
226
227 Set<Resource> resources = availableIds.entrySet().stream()
228 .flatMap(x -> Stream.of(
229 Resources.discrete(
230 x.getKey().src().deviceId(),
231 x.getKey().src().port(),
232 x.getValue()
233 ).resource(),
234 Resources.discrete(
235 x.getKey().dst().deviceId(),
236 x.getKey().dst().port(),
237 x.getValue()
238 ).resource()
239 ))
240 .collect(Collectors.toSet());
241
242 List<ResourceAllocation> allocations = resourceService.allocate(id, ImmutableList.copyOf(resources));
243
244 if (allocations.isEmpty()) {
245 return Collections.emptyMap();
246 }
247
248 return ImmutableMap.copyOf(availableIds);
249 }
250
251 /**
252 * Allocates labels and associates them to source
253 * and destination ports of a link.
254 *
255 * @param links the links on which labels will be reserved
256 * @param id the intent Id
257 * @param type the encapsulation type
258 * @return the list of ports and associated labels
259 */
260 public Map<ConnectPoint, Identifier<?>> assignLabelToPorts(Set<Link> links, IntentId id, EncapsulationType type) {
261 Map<LinkKey, Identifier<?>> allocation = this.assignLabelToLinks(links, id, type);
262 if (allocation.isEmpty()) {
263 return Collections.emptyMap();
264 }
265 Map<ConnectPoint, Identifier<?>> finalAllocation = Maps.newHashMap();
266 allocation.forEach((key, value) -> {
267 finalAllocation.putIfAbsent(key.src(), value);
268 finalAllocation.putIfAbsent(key.dst(), value);
269 });
270 return ImmutableMap.copyOf(finalAllocation);
271 }
272
273 /**
274 * Interface for selection algorithms of the labels.
275 */
276 public interface LabelSelection {
277
278 /**
279 * Picks an element from values using a particular algorithm.
280 *
281 * @param values the values to select from
282 * @return the selected identifier if values are present, null otherwise
283 */
284 Identifier<?> select(Set<Identifier<?>> values);
285
286 }
287
288 /**
289 * Random label selection.
290 */
291 public static class RandomSelection implements LabelSelection {
292
293 /**
294 * Selects an identifier from a given set of values using
295 * the random selection algorithm.
296 *
297 * @param values the values to select from
298 * @return the selected identifier if values are present, null otherwise
299 */
300 @Override
301 public Identifier<?> select(Set<Identifier<?>> values) {
302 if (!values.isEmpty()) {
303 int size = values.size();
304 int index = RandomUtils.nextInt(size);
305 return Iterables.get(values, index);
306 }
307 return null;
308 }
309 }
310
311 /**
312 * First fit label selection.
313 */
314 public static class FirstFitSelection implements LabelSelection {
315
316 /**
317 * Selects an identifier from a given set of values using
318 * the first fir selection algorithm.
319 *
320 * @param values the values to select from
321 * @return the selected identifier if values are present, null otherwise.
322 */
323 @Override
324 public Identifier<?> select(Set<Identifier<?>> values) {
325 if (!values.isEmpty()) {
326 return values.iterator().next();
327 }
328 return null;
329 }
330 }
331
332}