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