blob: 9ec530b8aafaaa1820668bdd40e85e4edec0a4b6 [file] [log] [blame]
yoonseon94672112017-01-31 13:46:21 -08001/*
Thomas Vachuska52f2cd12018-11-08 21:20:04 -08002 * Copyright 2018-present Open Networking Foundation
yoonseon94672112017-01-31 13:46:21 -08003 *
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.incubator.net.virtual.impl;
18
19import com.google.common.collect.Maps;
20import org.apache.commons.lang3.tuple.Pair;
21import org.onlab.util.TriConsumer;
22import org.onosproject.incubator.net.virtual.NetworkId;
23import org.onosproject.incubator.net.virtual.VirtualNetworkMeterStore;
24import org.onosproject.incubator.net.virtual.VirtualNetworkService;
25import org.onosproject.incubator.net.virtual.event.AbstractVirtualListenerManager;
26import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProviderService;
27import org.onosproject.incubator.net.virtual.provider.VirtualMeterProvider;
28import org.onosproject.incubator.net.virtual.provider.VirtualMeterProviderService;
29import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.meter.DefaultMeter;
32import org.onosproject.net.meter.Meter;
33import org.onosproject.net.meter.MeterEvent;
34import org.onosproject.net.meter.MeterFailReason;
35import org.onosproject.net.meter.MeterFeatures;
36import org.onosproject.net.meter.MeterFeaturesKey;
37import org.onosproject.net.meter.MeterId;
38import org.onosproject.net.meter.MeterKey;
39import org.onosproject.net.meter.MeterListener;
40import org.onosproject.net.meter.MeterOperation;
41import org.onosproject.net.meter.MeterRequest;
42import org.onosproject.net.meter.MeterService;
43import org.onosproject.net.meter.MeterState;
44import org.onosproject.net.meter.MeterStoreDelegate;
45import org.onosproject.net.meter.MeterStoreResult;
46import org.onosproject.net.provider.ProviderId;
47import org.onosproject.store.service.AtomicCounter;
48import org.onosproject.store.service.StorageService;
49import org.slf4j.Logger;
50
51import java.util.Collection;
52import java.util.Map;
53import java.util.Set;
54import java.util.function.Function;
55import java.util.stream.Collectors;
56
57import static org.slf4j.LoggerFactory.getLogger;
58
59public class VirtualNetworkMeterManager
60 extends AbstractVirtualListenerManager<MeterEvent, MeterListener>
61 implements MeterService {
62
63 private static final String METERCOUNTERIDENTIFIER = "meter-id-counter-%s";
64 private final Logger log = getLogger(getClass());
65
66 protected StorageService coreStorageService;
67
68 protected VirtualNetworkMeterStore store;
69 private final MeterStoreDelegate storeDelegate = new InternalMeterStoreDelegate();
70
71 private VirtualProviderRegistryService providerRegistryService;
72 private InternalMeterProviderService innerProviderService;
73
74 private Map<DeviceId, AtomicCounter> meterIdCounters
75 = Maps.newConcurrentMap();
76
77 private TriConsumer<MeterRequest, MeterStoreResult, Throwable> onComplete;
78
79 /**
80 * Creates a new VirtualNetworkMeterManager object.
81 *
82 * @param manager virtual network manager service
83 * @param networkId a virtual network identifier
84 */
85 public VirtualNetworkMeterManager(VirtualNetworkService manager,
86 NetworkId networkId) {
87 super(manager, networkId, MeterEvent.class);
88
89 coreStorageService = serviceDirectory.get(StorageService.class);
90 providerRegistryService =
91 serviceDirectory.get(VirtualProviderRegistryService.class);
92
93 store = serviceDirectory.get(VirtualNetworkMeterStore.class);
94 store.setDelegate(networkId, this.storeDelegate);
95
96 innerProviderService = new InternalMeterProviderService();
97 providerRegistryService.registerProviderService(networkId(), innerProviderService);
98
99
100 onComplete = (request, result, error) -> {
101 request.context().ifPresent(c -> {
102 if (error != null) {
103 c.onError(request, MeterFailReason.UNKNOWN);
104 } else {
105 if (result.reason().isPresent()) {
106 c.onError(request, result.reason().get());
107 } else {
108 c.onSuccess(request);
109 }
110 }
111 });
112
113 };
114
115 log.info("Started");
116 }
117
118 @Override
119 public Meter submit(MeterRequest request) {
120
121 MeterId id = allocateMeterId(request.deviceId());
122
123 Meter.Builder mBuilder = DefaultMeter.builder()
124 .forDevice(request.deviceId())
125 .fromApp(request.appId())
126 .withBands(request.bands())
127 .withId(id)
128 .withUnit(request.unit());
129
130 if (request.isBurst()) {
131 mBuilder.burst();
132 }
133 DefaultMeter m = (DefaultMeter) mBuilder.build();
134 m.setState(MeterState.PENDING_ADD);
135 store.storeMeter(networkId(), m).whenComplete((result, error) ->
136 onComplete.accept(request, result, error));
137 return m;
138 }
139
140 @Override
141 public void withdraw(MeterRequest request, MeterId meterId) {
142 Meter.Builder mBuilder = DefaultMeter.builder()
143 .forDevice(request.deviceId())
144 .fromApp(request.appId())
145 .withBands(request.bands())
146 .withId(meterId)
147 .withUnit(request.unit());
148
149 if (request.isBurst()) {
150 mBuilder.burst();
151 }
152
153 DefaultMeter m = (DefaultMeter) mBuilder.build();
154 m.setState(MeterState.PENDING_REMOVE);
155 store.deleteMeter(networkId(), m).whenComplete((result, error) ->
156 onComplete.accept(request, result, error));
157 }
158
159 @Override
160 public Meter getMeter(DeviceId deviceId, MeterId id) {
161 MeterKey key = MeterKey.key(deviceId, id);
162 return store.getMeter(networkId(), key);
163 }
164
165 @Override
166 public Collection<Meter> getMeters(DeviceId deviceId) {
167 return store.getAllMeters(networkId()).stream()
168 .filter(m -> m.deviceId().equals(deviceId)).collect(Collectors.toList());
169 }
170
171 @Override
172 public Collection<Meter> getAllMeters() {
173 return store.getAllMeters(networkId());
174 }
175
176 private long queryMeters(DeviceId device) {
177 //FIXME: how to decide maximum number of meters per virtual device?
178 return 1;
179 }
180
181 private AtomicCounter allocateCounter(DeviceId deviceId) {
182 return coreStorageService
183 .getAtomicCounter(String.format(METERCOUNTERIDENTIFIER, deviceId));
184 }
185
Pier Luigibdcd9672017-10-13 13:54:48 +0200186 public MeterId allocateMeterId(DeviceId deviceId) {
yoonseon94672112017-01-31 13:46:21 -0800187 long maxMeters = store.getMaxMeters(networkId(), MeterFeaturesKey.key(deviceId));
188 if (maxMeters == 0L) {
189 // MeterFeatures couldn't be retrieved, trying with queryMeters
190 maxMeters = queryMeters(deviceId);
191 }
192
193 if (maxMeters == 0L) {
194 throw new IllegalStateException("Meters not supported by device " + deviceId);
195 }
196
197 final long mmeters = maxMeters;
198 long id = meterIdCounters.compute(deviceId, (k, v) -> {
199 if (v == null) {
200 return allocateCounter(k);
201 }
202 if (v.get() >= mmeters) {
203 throw new IllegalStateException("Maximum number of meters " +
204 meterIdCounters.get(deviceId).get() +
205 " reached for device " + deviceId +
206 " virtual network " + networkId());
207 }
208 return v;
209 }).incrementAndGet();
210
211 return MeterId.meterId(id);
212 }
213
Pier Luigibdcd9672017-10-13 13:54:48 +0200214 @Override
215 public void freeMeterId(DeviceId deviceId, MeterId meterId) {
216 // Do nothing
217 }
218
Andrea Campanella23250502020-05-13 15:36:57 +0200219 @Override
220 public void purgeMeters(DeviceId deviceId) {
221 // Do nothing
222 }
223
yoonseon94672112017-01-31 13:46:21 -0800224 private class InternalMeterProviderService
225 extends AbstractVirtualProviderService<VirtualMeterProvider>
226 implements VirtualMeterProviderService {
227
228 /**
229 * Creates a provider service on behalf of the specified provider.
230 */
231 protected InternalMeterProviderService() {
232 Set<ProviderId> providerIds =
233 providerRegistryService.getProvidersByService(this);
234 ProviderId providerId = providerIds.stream().findFirst().get();
235 VirtualMeterProvider provider = (VirtualMeterProvider)
236 providerRegistryService.getProvider(providerId);
237 setProvider(provider);
238 }
239
240 @Override
241 public void meterOperationFailed(MeterOperation operation,
242 MeterFailReason reason) {
243 store.failedMeter(networkId(), operation, reason);
244 }
245
246 @Override
247 public void pushMeterMetrics(DeviceId deviceId, Collection<Meter> meterEntries) {
248 //FIXME: FOLLOWING CODE CANNOT BE TESTED UNTIL SOMETHING THAT
249 //FIXME: IMPLEMENTS METERS EXISTS
250 Map<Pair<DeviceId, MeterId>, Meter> storedMeterMap =
251 store.getAllMeters(networkId()).stream()
252 .collect(Collectors.toMap(m -> Pair.of(m.deviceId(), m.id()), Function.identity()));
253
254 meterEntries.stream()
255 .filter(m -> storedMeterMap.remove(Pair.of(m.deviceId(), m.id())) != null)
256 .forEach(m -> store.updateMeterState(networkId(), m));
257
258 storedMeterMap.values().forEach(m -> {
259 if (m.state() == MeterState.PENDING_ADD) {
260 provider().performMeterOperation(networkId(), m.deviceId(),
261 new MeterOperation(m,
262 MeterOperation.Type.MODIFY));
263 } else if (m.state() == MeterState.PENDING_REMOVE) {
264 store.deleteMeterNow(networkId(), m);
265 }
266 });
267 }
268
269 @Override
270 public void pushMeterFeatures(DeviceId deviceId, MeterFeatures meterfeatures) {
271 store.storeMeterFeatures(networkId(), meterfeatures);
272 }
273
274 @Override
275 public void deleteMeterFeatures(DeviceId deviceId) {
276 store.deleteMeterFeatures(networkId(), deviceId);
277 }
278 }
279
280 private class InternalMeterStoreDelegate implements MeterStoreDelegate {
281
282 @Override
283 public void notify(MeterEvent event) {
284 DeviceId deviceId = event.subject().deviceId();
285 VirtualMeterProvider p = innerProviderService.provider();
286
287 switch (event.type()) {
288 case METER_ADD_REQ:
289 p.performMeterOperation(networkId(), deviceId,
290 new MeterOperation(event.subject(),
291 MeterOperation.Type.ADD));
292 break;
293 case METER_REM_REQ:
294 p.performMeterOperation(networkId(), deviceId,
295 new MeterOperation(event.subject(),
296 MeterOperation.Type.REMOVE));
297 break;
298 default:
299 log.warn("Unknown meter event {}", event.type());
300 }
301 }
302 }
303}