blob: 2cce14c7abad6cd13e0a7600704a1499d21b2e2e [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
yoonseon94672112017-01-31 13:46:21 -0800219 private class InternalMeterProviderService
220 extends AbstractVirtualProviderService<VirtualMeterProvider>
221 implements VirtualMeterProviderService {
222
223 /**
224 * Creates a provider service on behalf of the specified provider.
225 */
226 protected InternalMeterProviderService() {
227 Set<ProviderId> providerIds =
228 providerRegistryService.getProvidersByService(this);
229 ProviderId providerId = providerIds.stream().findFirst().get();
230 VirtualMeterProvider provider = (VirtualMeterProvider)
231 providerRegistryService.getProvider(providerId);
232 setProvider(provider);
233 }
234
235 @Override
236 public void meterOperationFailed(MeterOperation operation,
237 MeterFailReason reason) {
238 store.failedMeter(networkId(), operation, reason);
239 }
240
241 @Override
242 public void pushMeterMetrics(DeviceId deviceId, Collection<Meter> meterEntries) {
243 //FIXME: FOLLOWING CODE CANNOT BE TESTED UNTIL SOMETHING THAT
244 //FIXME: IMPLEMENTS METERS EXISTS
245 Map<Pair<DeviceId, MeterId>, Meter> storedMeterMap =
246 store.getAllMeters(networkId()).stream()
247 .collect(Collectors.toMap(m -> Pair.of(m.deviceId(), m.id()), Function.identity()));
248
249 meterEntries.stream()
250 .filter(m -> storedMeterMap.remove(Pair.of(m.deviceId(), m.id())) != null)
251 .forEach(m -> store.updateMeterState(networkId(), m));
252
253 storedMeterMap.values().forEach(m -> {
254 if (m.state() == MeterState.PENDING_ADD) {
255 provider().performMeterOperation(networkId(), m.deviceId(),
256 new MeterOperation(m,
257 MeterOperation.Type.MODIFY));
258 } else if (m.state() == MeterState.PENDING_REMOVE) {
259 store.deleteMeterNow(networkId(), m);
260 }
261 });
262 }
263
264 @Override
265 public void pushMeterFeatures(DeviceId deviceId, MeterFeatures meterfeatures) {
266 store.storeMeterFeatures(networkId(), meterfeatures);
267 }
268
269 @Override
270 public void deleteMeterFeatures(DeviceId deviceId) {
271 store.deleteMeterFeatures(networkId(), deviceId);
272 }
273 }
274
275 private class InternalMeterStoreDelegate implements MeterStoreDelegate {
276
277 @Override
278 public void notify(MeterEvent event) {
279 DeviceId deviceId = event.subject().deviceId();
280 VirtualMeterProvider p = innerProviderService.provider();
281
282 switch (event.type()) {
283 case METER_ADD_REQ:
284 p.performMeterOperation(networkId(), deviceId,
285 new MeterOperation(event.subject(),
286 MeterOperation.Type.ADD));
287 break;
288 case METER_REM_REQ:
289 p.performMeterOperation(networkId(), deviceId,
290 new MeterOperation(event.subject(),
291 MeterOperation.Type.REMOVE));
292 break;
293 default:
294 log.warn("Unknown meter event {}", event.type());
295 }
296 }
297 }
298}