blob: 34ba91e1eec894a07cd7ee15833b7696b457eb8d [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;
Pier Ventref8543d82016-09-28 19:49:33 -070032import org.onosproject.net.resource.Resource;
33import org.onosproject.net.resource.ResourceAllocation;
Yi Tseng535243a2017-05-25 10:08:06 -070034import org.onosproject.net.resource.ResourceConsumer;
Pier Ventref8543d82016-09-28 19:49:33 -070035import 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
Yi Tseng535243a2017-05-25 10:08:06 -0700210 * @param resourceConsumer the resource consumer
Pier Ventref8543d82016-09-28 19:49:33 -0700211 * @param type the encapsulation type
212 * @return the list of links and associated labels
213 */
Yi Tseng535243a2017-05-25 10:08:06 -0700214 public Map<LinkKey, Identifier<?>> assignLabelToLinks(Set<Link> links,
215 ResourceConsumer resourceConsumer,
216 EncapsulationType type) {
Sho SHIMIZU4c7fcdf2016-12-22 11:17:43 -0800217 Set<LinkKey> linkRequest = links.stream()
218 .map(LinkKey::linkKey)
219 .collect(Collectors.toSet());
Pier Ventref8543d82016-09-28 19:49:33 -0700220
221 Map<LinkKey, Identifier<?>> availableIds = findAvailableIDs(linkRequest, type);
222 if (availableIds.isEmpty()) {
223 return Collections.emptyMap();
224 }
225
226 Set<Resource> resources = availableIds.entrySet().stream()
227 .flatMap(x -> Stream.of(
228 Resources.discrete(
229 x.getKey().src().deviceId(),
230 x.getKey().src().port(),
231 x.getValue()
232 ).resource(),
233 Resources.discrete(
234 x.getKey().dst().deviceId(),
235 x.getKey().dst().port(),
236 x.getValue()
237 ).resource()
238 ))
239 .collect(Collectors.toSet());
240
Yi Tseng535243a2017-05-25 10:08:06 -0700241 List<ResourceAllocation> allocations = resourceService.allocate(resourceConsumer,
242 ImmutableList.copyOf(resources));
Pier Ventref8543d82016-09-28 19:49:33 -0700243
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
Yi Tseng535243a2017-05-25 10:08:06 -0700256 * @param resourceConsumer the resource consumer
Pier Ventref8543d82016-09-28 19:49:33 -0700257 * @param type the encapsulation type
258 * @return the list of ports and associated labels
259 */
Yi Tseng535243a2017-05-25 10:08:06 -0700260 public Map<ConnectPoint, Identifier<?>> assignLabelToPorts(Set<Link> links,
261 ResourceConsumer resourceConsumer,
262 EncapsulationType type) {
263 Map<LinkKey, Identifier<?>> allocation = this.assignLabelToLinks(links,
264 resourceConsumer,
265 type);
Pier Ventref8543d82016-09-28 19:49:33 -0700266 if (allocation.isEmpty()) {
267 return Collections.emptyMap();
268 }
269 Map<ConnectPoint, Identifier<?>> finalAllocation = Maps.newHashMap();
Yi Tseng535243a2017-05-25 10:08:06 -0700270 allocation.forEach((link, value) -> {
271 finalAllocation.putIfAbsent(link.src(), value);
272 finalAllocation.putIfAbsent(link.dst(), value);
Pier Ventref8543d82016-09-28 19:49:33 -0700273 });
274 return ImmutableMap.copyOf(finalAllocation);
275 }
276
277 /**
278 * Interface for selection algorithms of the labels.
279 */
280 public interface LabelSelection {
281
282 /**
283 * Picks an element from values using a particular algorithm.
284 *
285 * @param values the values to select from
286 * @return the selected identifier if values are present, null otherwise
287 */
288 Identifier<?> select(Set<Identifier<?>> values);
289
290 }
291
292 /**
293 * Random label selection.
294 */
295 public static class RandomSelection implements LabelSelection {
296
297 /**
298 * Selects an identifier from a given set of values using
299 * the random selection algorithm.
300 *
301 * @param values the values to select from
302 * @return the selected identifier if values are present, null otherwise
303 */
304 @Override
305 public Identifier<?> select(Set<Identifier<?>> values) {
306 if (!values.isEmpty()) {
307 int size = values.size();
308 int index = RandomUtils.nextInt(size);
309 return Iterables.get(values, index);
310 }
311 return null;
312 }
313 }
314
315 /**
316 * First fit label selection.
317 */
318 public static class FirstFitSelection implements LabelSelection {
319
320 /**
321 * Selects an identifier from a given set of values using
322 * the first fir selection algorithm.
323 *
324 * @param values the values to select from
325 * @return the selected identifier if values are present, null otherwise.
326 */
327 @Override
328 public Identifier<?> select(Set<Identifier<?>> values) {
329 if (!values.isEmpty()) {
330 return values.iterator().next();
331 }
332 return null;
333 }
334 }
335
336}