3266e96c5b787ab78120054baac5e8c2f2719737
[onosfw.git] /
1 /*
2  * Copyright 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.resource.impl;
17
18 import org.apache.felix.scr.annotations.Activate;
19 import org.apache.felix.scr.annotations.Component;
20 import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.apache.felix.scr.annotations.Service;
24 import org.onosproject.net.DeviceId;
25 import org.onosproject.net.Port;
26 import org.onosproject.net.device.DeviceService;
27 import org.onosproject.net.intent.IntentId;
28 import org.onosproject.net.resource.device.DeviceResourceStore;
29 import org.onosproject.store.serializers.KryoNamespaces;
30 import org.onosproject.store.service.ConsistentMap;
31 import org.onosproject.store.service.Serializer;
32 import org.onosproject.store.service.StorageService;
33 import org.onosproject.store.service.TransactionContext;
34 import org.onosproject.store.service.TransactionalMap;
35 import org.onosproject.store.service.Versioned;
36 import org.slf4j.Logger;
37
38 import java.util.Collections;
39 import java.util.HashSet;
40 import java.util.Set;
41
42 import static com.google.common.base.Preconditions.checkArgument;
43 import static org.slf4j.LoggerFactory.getLogger;
44 import static com.google.common.base.Preconditions.checkNotNull;
45
46 /**
47  * Store that manages device resources using Copycat-backed TransactionalMaps.
48  */
49 @Component(immediate = true, enabled = true)
50 @Service
51 public class ConsistentDeviceResourceStore implements DeviceResourceStore {
52     private final Logger log = getLogger(getClass());
53
54     private static final String PORT_ALLOCATIONS = "PortAllocations";
55     private static final String INTENT_MAPPING = "IntentMapping";
56     private static final String INTENT_ALLOCATIONS = "PortIntentAllocations";
57
58     private static final Serializer SERIALIZER = Serializer.using(KryoNamespaces.API);
59
60     private ConsistentMap<Port, IntentId> portAllocMap;
61     private ConsistentMap<IntentId, Set<Port>> intentAllocMap;
62     private ConsistentMap<IntentId, Set<IntentId>> intentMapping;
63
64     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65     protected StorageService storageService;
66
67     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68     protected DeviceService deviceService;
69
70     @Activate
71     public void activate() {
72         portAllocMap = storageService.<Port, IntentId>consistentMapBuilder()
73                 .withName(PORT_ALLOCATIONS)
74                 .withSerializer(SERIALIZER)
75                 .build();
76         intentAllocMap = storageService.<IntentId, Set<Port>>consistentMapBuilder()
77                 .withName(INTENT_ALLOCATIONS)
78                 .withSerializer(SERIALIZER)
79                 .build();
80         intentMapping = storageService.<IntentId, Set<IntentId>>consistentMapBuilder()
81                 .withName(INTENT_MAPPING)
82                 .withSerializer(SERIALIZER)
83                 .build();
84         log.info("Started");
85     }
86
87     @Deactivate
88     public void deactivate() {
89         log.info("Stopped");
90     }
91
92     private TransactionalMap<Port, IntentId> getPortAllocs(TransactionContext tx) {
93         return tx.getTransactionalMap(PORT_ALLOCATIONS, SERIALIZER);
94     }
95
96     private TransactionalMap<IntentId, Set<Port>> getIntentAllocs(TransactionContext tx) {
97         return tx.getTransactionalMap(INTENT_ALLOCATIONS, SERIALIZER);
98     }
99
100     private TransactionContext getTxContext() {
101         return storageService.transactionContextBuilder().build();
102     }
103
104     @Override
105     public Set<Port> getFreePorts(DeviceId deviceId) {
106         checkNotNull(deviceId);
107
108         Set<Port> freePorts = new HashSet<>();
109         for (Port port : deviceService.getPorts(deviceId)) {
110             if (!portAllocMap.containsKey(port)) {
111                 freePorts.add(port);
112             }
113         }
114
115         return freePorts;
116     }
117
118     @Override
119     public boolean allocatePorts(Set<Port> ports, IntentId intentId) {
120         checkNotNull(ports);
121         checkArgument(ports.size() > 0);
122         checkNotNull(intentId);
123
124         TransactionContext tx = getTxContext();
125         tx.begin();
126         try {
127             TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
128             for (Port port : ports) {
129                 if (portAllocs.putIfAbsent(port, intentId) != null) {
130                     throw new Exception("Port already allocated " + port.toString());
131                 }
132             }
133
134             TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
135             intentAllocs.put(intentId, ports);
136             tx.commit();
137         } catch (Exception e) {
138             log.error("Exception thrown, rolling back", e);
139             tx.abort();
140             return false;
141         }
142
143         return true;
144     }
145
146     @Override
147     public Set<Port> getAllocations(IntentId intentId) {
148         if (!intentAllocMap.containsKey(intentId)) {
149             Collections.emptySet();
150         }
151
152         return intentAllocMap.get(intentId).value();
153     }
154
155     @Override
156     public IntentId getAllocations(Port port) {
157         if (!portAllocMap.containsKey(port)) {
158             return null;
159         }
160
161         return portAllocMap.get(port).value();
162     }
163
164     @Override
165     public Set<IntentId> getMapping(IntentId intentId) {
166         Versioned<Set<IntentId>> result = intentMapping.get(intentId);
167
168         if (result != null) {
169             return result.value();
170         }
171
172         return null;
173     }
174
175     @Override
176     public boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId) {
177         Versioned<Set<IntentId>> versionedIntents = intentMapping.get(keyIntentId);
178
179         if (versionedIntents == null) {
180             Set<IntentId> newSet = new HashSet<>();
181             newSet.add(valIntentId);
182             intentMapping.put(keyIntentId, newSet);
183         } else {
184             versionedIntents.value().add(valIntentId);
185         }
186
187         return true;
188     }
189
190     @Override
191     public void releaseMapping(IntentId intentId) {
192         for (IntentId intent : intentMapping.keySet()) {
193             // TODO: optimize by checking for identical src & dst
194             Set<IntentId> mapping = intentMapping.get(intent).value();
195             if (mapping.remove(intentId)) {
196                 return;
197             }
198         }
199     }
200
201     @Override
202     public boolean releasePorts(IntentId intentId) {
203         checkNotNull(intentId);
204
205         TransactionContext tx = getTxContext();
206         tx.begin();
207         try {
208             TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
209             Set<Port> ports = intentAllocs.get(intentId);
210             intentAllocs.remove(intentId);
211
212             TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
213             for (Port port : ports) {
214                 portAllocs.remove(port);
215             }
216             tx.commit();
217         } catch (Exception e) {
218             log.error("Exception thrown, rolling back", e);
219             tx.abort();
220             return false;
221         }
222
223         return true;
224     }
225 }