58b446cf124d59ca85652747c360d37c40f2b316
[onosfw.git] /
1 /*
2  * Copyright 2014-2015 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 package org.onosproject.store.trivial;
17
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 import org.apache.felix.scr.annotations.Activate;
26 import org.apache.felix.scr.annotations.Component;
27 import org.apache.felix.scr.annotations.Deactivate;
28 import org.apache.felix.scr.annotations.Service;
29 import org.onlab.util.Bandwidth;
30 import org.onlab.util.PositionalParameterStringFormatter;
31 import org.onosproject.net.AnnotationKeys;
32 import org.onosproject.net.Annotations;
33 import org.onosproject.net.Link;
34 import org.onosproject.net.intent.IntentId;
35 import org.onosproject.net.resource.link.BandwidthResource;
36 import org.onosproject.net.resource.link.BandwidthResourceAllocation;
37 import org.onosproject.net.resource.link.LambdaResource;
38 import org.onosproject.net.resource.link.LambdaResourceAllocation;
39 import org.onosproject.net.resource.link.LinkResourceAllocations;
40 import org.onosproject.net.resource.link.LinkResourceEvent;
41 import org.onosproject.net.resource.link.LinkResourceStore;
42 import org.onosproject.net.resource.ResourceAllocation;
43 import org.onosproject.net.resource.ResourceAllocationException;
44 import org.onosproject.net.resource.ResourceType;
45 import org.slf4j.Logger;
46
47 import com.google.common.collect.ImmutableList;
48
49 import static com.google.common.base.Preconditions.checkNotNull;
50 import static com.google.common.base.Preconditions.checkState;
51 import static org.slf4j.LoggerFactory.getLogger;
52
53 /**
54  * Manages link resources using trivial in-memory structures implementation.
55  */
56 @Component(immediate = true)
57 @Service
58 public class SimpleLinkResourceStore implements LinkResourceStore {
59     private static final BandwidthResource DEFAULT_BANDWIDTH = new BandwidthResource(Bandwidth.mbps(1_000));
60     private final Logger log = getLogger(getClass());
61
62     private Map<IntentId, LinkResourceAllocations> linkResourceAllocationsMap;
63     private Map<Link, Set<LinkResourceAllocations>> allocatedResources;
64     private Map<Link, Set<ResourceAllocation>> freeResources;
65
66     @Activate
67     public void activate() {
68         linkResourceAllocationsMap = new HashMap<>();
69         allocatedResources = new HashMap<>();
70         freeResources = new HashMap<>();
71
72         log.info("Started");
73     }
74
75     @Deactivate
76     public void deactivate() {
77         log.info("Stopped");
78     }
79
80     /**
81      * Returns free resources for a given link obtaining from topology
82      * information.
83      *
84      * @param link the target link
85      * @return free resources
86      */
87     private synchronized Set<ResourceAllocation> readOriginalFreeResources(Link link) {
88         Annotations annotations = link.annotations();
89         Set<ResourceAllocation> allocations = new HashSet<>();
90
91         try {
92             int waves = Integer.parseInt(annotations.value(AnnotationKeys.OPTICAL_WAVES));
93             for (int i = 1; i <= waves; i++) {
94                 allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
95             }
96         } catch (NumberFormatException e) {
97             log.debug("No optical.wave annotation on link %s", link);
98         }
99
100         BandwidthResource bandwidth = DEFAULT_BANDWIDTH;
101         try {
102             bandwidth = new BandwidthResource(
103                     Bandwidth.mbps((Double.parseDouble(annotations.value(AnnotationKeys.BANDWIDTH)))));
104         } catch (NumberFormatException e) {
105             log.debug("No bandwidth annotation on link %s", link);
106         }
107         allocations.add(
108                 new BandwidthResourceAllocation(bandwidth));
109         return allocations;
110     }
111
112     /**
113      * Finds and returns {@link BandwidthResourceAllocation} object from a given
114      * set.
115      *
116      * @param freeRes a set of ResourceAllocation object.
117      * @return {@link BandwidthResourceAllocation} object if found, otherwise
118      *         {@link BandwidthResourceAllocation} object with 0 bandwidth
119      *
120      */
121     private synchronized BandwidthResourceAllocation getBandwidth(
122             Set<ResourceAllocation> freeRes) {
123         for (ResourceAllocation res : freeRes) {
124             if (res.type() == ResourceType.BANDWIDTH) {
125                 return (BandwidthResourceAllocation) res;
126             }
127         }
128         return new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(0)));
129     }
130
131     /**
132      * Subtracts given resources from free resources for given link.
133      *
134      * @param link the target link
135      * @param allocations the resources to be subtracted
136      */
137     private synchronized void subtractFreeResources(Link link,
138             LinkResourceAllocations allocations) {
139         // TODO Use lock or version for updating freeResources.
140         checkNotNull(link);
141         Set<ResourceAllocation> freeRes = new HashSet<>(getFreeResources(link));
142         Set<ResourceAllocation> subRes = allocations.getResourceAllocation(link);
143         for (ResourceAllocation res : subRes) {
144             switch (res.type()) {
145             case BANDWIDTH:
146                 BandwidthResourceAllocation ba = getBandwidth(freeRes);
147                 double requestedBandwidth =
148                         ((BandwidthResourceAllocation) res).bandwidth().toDouble();
149                 double newBandwidth = ba.bandwidth().toDouble() - requestedBandwidth;
150                 if (newBandwidth < 0.0) {
151                     throw new ResourceAllocationException(
152                             PositionalParameterStringFormatter.format(
153                             "Unable to allocate bandwidth for link {} "
154                             + "requested amount is {} current allocation is {}",
155                                     link,
156                                     requestedBandwidth,
157                                     ba));
158                 }
159                 freeRes.remove(ba);
160                 freeRes.add(new BandwidthResourceAllocation(
161                         new BandwidthResource(Bandwidth.bps(newBandwidth))));
162                 break;
163             case LAMBDA:
164                 final boolean lambdaAvailable = freeRes.remove(res);
165                 if (!lambdaAvailable) {
166                     int requestedLambda =
167                             ((LambdaResourceAllocation) res).lambda().toInt();
168                     throw new ResourceAllocationException(
169                             PositionalParameterStringFormatter.format(
170                                     "Unable to allocate lambda for link {} lambda is {}",
171                                     link,
172                                     requestedLambda));
173                 }
174                 break;
175             default:
176                 break;
177             }
178         }
179         freeResources.put(link, freeRes);
180
181     }
182
183     /**
184      * Adds given resources to free resources for given link.
185      *
186      * @param link the target link
187      * @param allocations the resources to be added
188      */
189     private synchronized void addFreeResources(Link link,
190             LinkResourceAllocations allocations) {
191         // TODO Use lock or version for updating freeResources.
192         Set<ResourceAllocation> freeRes = new HashSet<>(getFreeResources(link));
193         Set<ResourceAllocation> addRes = allocations.getResourceAllocation(link);
194         for (ResourceAllocation res : addRes) {
195             switch (res.type()) {
196             case BANDWIDTH:
197                 BandwidthResourceAllocation ba = getBandwidth(freeRes);
198                 double requestedBandwidth =
199                         ((BandwidthResourceAllocation) res).bandwidth().toDouble();
200                 double newBandwidth = ba.bandwidth().toDouble() + requestedBandwidth;
201                 freeRes.remove(ba);
202                 freeRes.add(new BandwidthResourceAllocation(
203                         new BandwidthResource(Bandwidth.bps(newBandwidth))));
204                 break;
205             case LAMBDA:
206                 checkState(freeRes.add(res));
207                 break;
208             default:
209                 break;
210             }
211         }
212         freeResources.put(link, freeRes);
213     }
214
215     @Override
216     public synchronized Set<ResourceAllocation> getFreeResources(Link link) {
217         checkNotNull(link);
218         Set<ResourceAllocation> freeRes = freeResources.get(link);
219         if (freeRes == null) {
220             freeRes = readOriginalFreeResources(link);
221         }
222
223         return freeRes;
224     }
225
226     @Override
227     public synchronized void allocateResources(LinkResourceAllocations allocations) {
228         checkNotNull(allocations);
229         linkResourceAllocationsMap.put(allocations.intentId(), allocations);
230         for (Link link : allocations.links()) {
231             subtractFreeResources(link, allocations);
232             Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
233             if (linkAllocs == null) {
234                 linkAllocs = new HashSet<>();
235             }
236             linkAllocs.add(allocations);
237             allocatedResources.put(link, linkAllocs);
238         }
239     }
240
241     @Override
242     public synchronized LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
243         checkNotNull(allocations);
244         linkResourceAllocationsMap.remove(allocations.intentId());
245         for (Link link : allocations.links()) {
246             addFreeResources(link, allocations);
247             Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
248             if (linkAllocs == null) {
249                 log.error("Missing resource allocation.");
250             } else {
251                 linkAllocs.remove(allocations);
252             }
253             allocatedResources.put(link, linkAllocs);
254         }
255
256         final List<LinkResourceAllocations> releasedResources =
257                 ImmutableList.of(allocations);
258
259         return new LinkResourceEvent(
260                 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
261                 releasedResources);
262     }
263
264     @Override
265     public synchronized LinkResourceAllocations getAllocations(IntentId intentId) {
266         checkNotNull(intentId);
267         return linkResourceAllocationsMap.get(intentId);
268     }
269
270     @Override
271     public synchronized Iterable<LinkResourceAllocations> getAllocations(Link link) {
272         checkNotNull(link);
273         Set<LinkResourceAllocations> result = allocatedResources.get(link);
274         if (result == null) {
275             result = Collections.emptySet();
276         }
277         return Collections.unmodifiableSet(result);
278     }
279
280     @Override
281     public synchronized Iterable<LinkResourceAllocations> getAllocations() {
282         return Collections.unmodifiableCollection(linkResourceAllocationsMap.values());
283     }
284
285
286 }