blob: c2299ef72208624704e7711410cc6383e463b06b [file] [log] [blame]
Marc De Leenheer1afa2a02015-05-13 09:18:07 -07001/*
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 */
16package org.onosproject.store.resource.impl;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
24import org.onlab.util.KryoNamespace;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.Port;
27import org.onosproject.net.device.DeviceService;
28import org.onosproject.net.intent.IntentId;
Brian O'Connor6de2e202015-05-21 14:30:41 -070029import org.onosproject.net.resource.device.DeviceResourceStore;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070030import org.onosproject.store.serializers.KryoNamespaces;
31import org.onosproject.store.service.ConsistentMap;
32import org.onosproject.store.service.Serializer;
33import org.onosproject.store.service.StorageService;
34import org.onosproject.store.service.TransactionContext;
35import org.onosproject.store.service.TransactionalMap;
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -070036import org.onosproject.store.service.Versioned;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070037import org.slf4j.Logger;
38
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070039import java.util.Collections;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070040import java.util.HashSet;
41import java.util.Set;
42
43import static com.google.common.base.Preconditions.checkArgument;
44import static org.slf4j.LoggerFactory.getLogger;
45import static com.google.common.base.Preconditions.checkNotNull;
46
47/**
48 * Store that manages device resources using Copycat-backed TransactionalMaps.
49 */
50@Component(immediate = true, enabled = true)
51@Service
52public class ConsistentDeviceResourceStore implements DeviceResourceStore {
53 private final Logger log = getLogger(getClass());
54
55 private static final String PORT_ALLOCATIONS = "PortAllocations";
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070056 private static final String INTENT_MAPPING = "IntentMapping";
Ayaka Koshibebcb02372015-06-01 10:56:42 -070057 private static final String INTENT_ALLOCATIONS = "PortIntentAllocations";
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070058
59 private static final Serializer SERIALIZER = Serializer.using(
60 new KryoNamespace.Builder().register(KryoNamespaces.API).build());
61
62 private ConsistentMap<Port, IntentId> portAllocMap;
63 private ConsistentMap<IntentId, Set<Port>> intentAllocMap;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070064 private ConsistentMap<IntentId, Set<IntentId>> intentMapping;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070065
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected StorageService storageService;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected DeviceService deviceService;
71
72 @Activate
73 public void activate() {
74 portAllocMap = storageService.<Port, IntentId>consistentMapBuilder()
75 .withName(PORT_ALLOCATIONS)
76 .withSerializer(SERIALIZER)
77 .build();
78 intentAllocMap = storageService.<IntentId, Set<Port>>consistentMapBuilder()
79 .withName(INTENT_ALLOCATIONS)
80 .withSerializer(SERIALIZER)
81 .build();
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070082 intentMapping = storageService.<IntentId, Set<IntentId>>consistentMapBuilder()
83 .withName(INTENT_MAPPING)
84 .withSerializer(SERIALIZER)
85 .build();
Marc De Leenheer1afa2a02015-05-13 09:18:07 -070086 log.info("Started");
87 }
88
89 @Deactivate
90 public void deactivate() {
91 log.info("Stopped");
92 }
93
94 private TransactionalMap<Port, IntentId> getPortAllocs(TransactionContext tx) {
95 return tx.getTransactionalMap(PORT_ALLOCATIONS, SERIALIZER);
96 }
97
98 private TransactionalMap<IntentId, Set<Port>> getIntentAllocs(TransactionContext tx) {
99 return tx.getTransactionalMap(INTENT_ALLOCATIONS, SERIALIZER);
100 }
101
102 private TransactionContext getTxContext() {
103 return storageService.transactionContextBuilder().build();
104 }
105
106 @Override
107 public Set<Port> getFreePorts(DeviceId deviceId) {
108 checkNotNull(deviceId);
109
110 Set<Port> freePorts = new HashSet<>();
111 for (Port port : deviceService.getPorts(deviceId)) {
112 if (!portAllocMap.containsKey(port)) {
113 freePorts.add(port);
114 }
115 }
116
117 return freePorts;
118 }
119
120 @Override
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700121 public boolean allocatePorts(Set<Port> ports, IntentId intentId) {
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700122 checkNotNull(ports);
123 checkArgument(ports.size() > 0);
124 checkNotNull(intentId);
125
126 TransactionContext tx = getTxContext();
127 tx.begin();
128 try {
129 TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
130 for (Port port : ports) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700131 if (portAllocs.putIfAbsent(port, intentId) != null) {
132 throw new Exception("Port already allocated " + port.toString());
133 }
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700134 }
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700135
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700136 TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
137 intentAllocs.put(intentId, ports);
138 tx.commit();
139 } catch (Exception e) {
140 log.error("Exception thrown, rolling back", e);
141 tx.abort();
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700142 return false;
143 }
144
145 return true;
146 }
147
148 @Override
149 public Set<Port> getAllocations(IntentId intentId) {
150 if (!intentAllocMap.containsKey(intentId)) {
151 Collections.emptySet();
152 }
153
154 return intentAllocMap.get(intentId).value();
155 }
156
157 @Override
158 public IntentId getAllocations(Port port) {
159 if (!portAllocMap.containsKey(port)) {
160 return null;
161 }
162
163 return portAllocMap.get(port).value();
164 }
165
166 @Override
167 public Set<IntentId> getMapping(IntentId intentId) {
168 return intentMapping.get(intentId).value();
169 }
170
171 @Override
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700172 public boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId) {
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700173 Versioned<Set<IntentId>> versionedIntents = intentMapping.get(keyIntentId);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700174
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700175
176 if (versionedIntents == null) {
177 intentMapping.put(keyIntentId, Collections.singleton(valIntentId));
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700178 } else {
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700179 versionedIntents.value().add(valIntentId);
180 intentMapping.put(keyIntentId, versionedIntents.value());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700181 }
182
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700183 return true;
184 }
185
186 @Override
Marc De Leenheer9f7d1892015-05-30 13:22:24 -0700187 public void releaseMapping(IntentId intentId) {
188 for (IntentId intent : intentMapping.keySet()) {
189 // TODO: optimize by checking for identical src & dst
190 Set<IntentId> mapping = intentMapping.get(intent).value();
191 if (mapping.remove(intentId)) {
192 return;
193 }
194 }
195 }
196
197 @Override
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700198 public boolean releasePorts(IntentId intentId) {
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700199 checkNotNull(intentId);
200
201 TransactionContext tx = getTxContext();
202 tx.begin();
203 try {
204 TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
205 Set<Port> ports = intentAllocs.get(intentId);
206 intentAllocs.remove(intentId);
207
208 TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
209 for (Port port : ports) {
210 portAllocs.remove(port);
211 }
212 } catch (Exception e) {
213 log.error("Exception thrown, rolling back", e);
214 tx.abort();
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700215 return false;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700216 }
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700217
218 return true;
Marc De Leenheer1afa2a02015-05-13 09:18:07 -0700219 }
220}