1 package org.opendaylight.controller.forwardingrulesmanager_mdsal.consumer.impl;
3 import java.util.ArrayList;
4 import java.util.EnumSet;
5 import java.util.HashMap;
6 import java.util.HashSet;
10 import java.util.Map.Entry;
11 import java.util.concurrent.ConcurrentHashMap;
12 import java.util.concurrent.ConcurrentMap;
14 import org.opendaylight.controller.clustering.services.CacheConfigException;
15 import org.opendaylight.controller.clustering.services.CacheExistException;
16 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
17 import org.opendaylight.controller.clustering.services.IClusterServices;
18 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
19 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
20 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
21 import org.opendaylight.controller.sal.common.util.Rpcs;
22 import org.opendaylight.controller.sal.core.IContainer;
23 import org.opendaylight.controller.sal.core.Node;
24 import org.opendaylight.controller.sal.utils.GlobalConstants;
25 import org.opendaylight.controller.sal.utils.Status;
26 import org.opendaylight.controller.sal.utils.StatusCode;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterAdded;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterRemoved;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterUpdated;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
42 import org.opendaylight.yangtools.concepts.Registration;
43 import org.opendaylight.yangtools.yang.binding.DataObject;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.opendaylight.yangtools.yang.binding.NotificationListener;
46 import org.opendaylight.yangtools.yang.common.RpcResult;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 public class MeterConsumerImpl {
51 protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
52 private MeterEventListener meterEventListener = new MeterEventListener();
53 private Registration<NotificationListener> meterListener;
54 private SalMeterService meterService;
55 private MeterDataCommitHandler commitHandler;
57 private ConcurrentMap<MeterKey, Meter> originalSwMeterView;
58 private ConcurrentMap<MeterKey, Meter> installedSwMeterView;
60 private ConcurrentMap<Node, List<Meter>> nodeMeters;
61 private ConcurrentMap<MeterKey, Meter> inactiveMeters;
63 private IClusterContainerServices clusterMeterContainerService = null;
64 private IContainer container;
66 public MeterConsumerImpl() {
67 InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder().node(Meters.class).node(Meter.class).toInstance();
68 meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
69 clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
71 container = FRMConsumerImpl.getContainer();
73 if (!(cacheStartup())) {
74 logger.error("Unable to allocate/retrieve meter cache");
75 System.out.println("Unable to allocate/retrieve meter cache");
78 if (null == meterService) {
79 logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
80 System.out.println("Consumer SAL Meter Service is down or NULL.");
84 // For switch/plugin events
85 meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
87 if (null == meterListener) {
88 logger.error("Listener to listen on meter data modifcation events");
89 System.out.println("Listener to listen on meter data modifcation events.");
93 commitHandler = new MeterDataCommitHandler();
94 FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
97 private boolean allocateMeterCaches() {
98 if (this.clusterMeterContainerService == null) {
99 logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
104 clusterMeterContainerService.createCache("frm.originalSwMeterView",
105 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
107 clusterMeterContainerService.createCache("frm.installedSwMeterView",
108 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
110 clusterMeterContainerService.createCache("frm.inactiveMeters",
111 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
113 clusterMeterContainerService.createCache("frm.nodeMeters",
114 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
116 // TODO for cluster mode
118 * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
119 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
120 * IClusterServices.cacheMode.ASYNC));
122 * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
123 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
124 * IClusterServices.cacheMode.ASYNC));
127 } catch (CacheConfigException cce) {
128 logger.error("Meter CacheConfigException");
131 } catch (CacheExistException cce) {
132 logger.error(" Meter CacheExistException");
138 private void nonClusterMeterObjectCreate() {
139 originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
140 installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
141 nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
142 inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
145 @SuppressWarnings({ "unchecked" })
146 private boolean retrieveMeterCaches() {
147 ConcurrentMap<?, ?> map;
149 if (this.clusterMeterContainerService == null) {
150 logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
151 nonClusterMeterObjectCreate();
155 map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
157 originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
159 logger.error("Retrieval of cache(originalSwMeterView) failed");
163 map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
165 installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
167 logger.error("Retrieval of cache(installedSwMeterView) failed");
171 map = clusterMeterContainerService.getCache("frm.inactiveMeters");
173 inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
175 logger.error("Retrieval of cache(inactiveMeters) failed");
179 map = clusterMeterContainerService.getCache("frm.nodeMeters");
181 nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
183 logger.error("Retrieval of cache(nodeMeter) failed");
190 private boolean cacheStartup() {
191 if (allocateMeterCaches()) {
192 if (retrieveMeterCaches()) {
201 * Adds Meter to the southbound plugin and our internal database
206 private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
207 MeterKey meterKey = meterAddDataObject.getKey();
209 if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {
210 if (meterAddDataObject.isInstall()) {
211 AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
213 meterBuilder.setContainerName(meterAddDataObject.getContainerName());
214 meterBuilder.setFlags(meterAddDataObject.getFlags());
215 meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
216 meterBuilder.setMeterId(meterAddDataObject.getMeterId());
217 meterBuilder.setNode(meterAddDataObject.getNode());
218 originalSwMeterView.put(meterKey, meterAddDataObject);
219 meterService.addMeter(meterBuilder.build());
222 originalSwMeterView.put(meterKey, meterAddDataObject);
225 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
228 return new Status(StatusCode.SUCCESS);
232 * Update Meter to the southbound plugin and our internal database
238 private Status updateMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
239 MeterKey meterKey = meterUpdateDataObject.getKey();
240 UpdatedMeterBuilder updateMeterBuilder = null;
243 if (null != meterKey &&
244 validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) {
246 if (originalSwMeterView.containsKey(meterKey)) {
247 originalSwMeterView.remove(meterKey);
248 originalSwMeterView.put(meterKey, meterUpdateDataObject);
251 if (meterUpdateDataObject.isInstall()) {
252 UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
253 updateMeterBuilder = new UpdatedMeterBuilder();
254 updateMeterBuilder.fieldsFrom(meterUpdateDataObject);
255 updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
257 if (installedSwMeterView.containsKey(meterKey)) {
258 installedSwMeterView.remove(meterKey);
259 installedSwMeterView.put(meterKey, meterUpdateDataObject);
262 meterService.updateMeter(updateMeterInputBuilder.build());
267 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
270 return new Status(StatusCode.SUCCESS);
274 * Remove Meter to the southbound plugin and our internal database
280 private Status RemoveMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
281 MeterKey meterKey = meterUpdateDataObject.getKey();
283 if (null != meterKey &&
284 validateMeter(meterUpdateDataObject, FRMUtil.operation.ADD).isSuccess()) {
285 if (meterUpdateDataObject.isInstall()) {
286 UpdateMeterInputBuilder updateMeterBuilder = new UpdateMeterInputBuilder();
288 installedSwMeterView.put(meterKey, meterUpdateDataObject);
289 meterService.updateMeter(updateMeterBuilder.build());
292 originalSwMeterView.put(meterKey, meterUpdateDataObject);
295 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
298 return new Status(StatusCode.SUCCESS);
301 public Status validateMeter(Meter meter, FRMUtil.operation operation) {
302 String containerName;
304 Status returnStatus = null;
305 boolean returnResult;
308 containerName = meter.getContainerName();
310 if (null == containerName) {
311 containerName = GlobalConstants.DEFAULT.toString();
312 } else if (!FRMUtil.isNameValid(containerName)) {
313 logger.error("Container Name is invalid %s" + containerName);
314 returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
318 meterName = meter.getMeterName();
319 if (!FRMUtil.isNameValid(meterName)) {
320 logger.error("Meter Name is invalid %s" + meterName);
321 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
325 returnResult = doesMeterEntryExists(meter.getKey(), meterName, containerName);
327 if (FRMUtil.operation.ADD == operation && returnResult) {
328 logger.error("Record with same Meter Name exists");
329 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record exists");
331 } else if (!returnResult) {
332 logger.error("Group record does not exist");
333 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record does not exist");
337 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
338 if (!meter.getFlags().isMeterBurst()) {
339 if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
340 logger.error("Burst size should only be associated when Burst FLAG is set");
341 returnStatus = new Status(StatusCode.BADREQUEST,
342 "Burst size should only be associated when Burst FLAG is set");
348 if (null != returnStatus && !returnStatus.isSuccess()) {
351 BandType setBandType = null;
352 DscpRemark dscpRemark = null;
353 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
354 setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
355 if (setBandType instanceof DscpRemark) {
356 dscpRemark = (DscpRemark) setBandType;
357 if (0 > dscpRemark.getRate()) {
360 } else if (setBandType instanceof Drop) {
361 if (0 < dscpRemark.getPercLevel()) {
362 logger.error("Number of drop Precedence level");
364 } else if (setBandType instanceof Experimenter) {
370 return new Status(StatusCode.SUCCESS);
373 private boolean doesMeterEntryExists(MeterKey key, String meterName, String containerName) {
374 if (!originalSwMeterView.containsKey(key)) {
378 for (Entry<MeterKey, Meter> entry : originalSwMeterView.entrySet()) {
379 if (entry.getValue().getMeterName().equals(meterName)) {
380 if (entry.getValue().getContainerName().equals(containerName)) {
388 private RpcResult<Void> commitToPlugin(internalTransaction transaction) {
389 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
391 if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
392 return Rpcs.getRpcResult(false, null, null);
395 for (@SuppressWarnings("unused")
396 Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
398 if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
399 return Rpcs.getRpcResult(false, null, null);
403 for (InstanceIdentifier<?> removal : transaction.removals) {
405 * if (!removeMeter(entry.getKey(),entry.getValue()).isSuccess()) {
406 * return Rpcs.getRpcResult(false, null, null); }
410 return Rpcs.getRpcResult(true, null, null);
413 private final class internalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
415 private final DataModification<InstanceIdentifier<?>, DataObject> modification;
418 public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
422 public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
423 this.modification = modification;
426 Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
427 Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
428 Set<InstanceIdentifier<?>> removals = new HashSet<>();
431 * We create a plan which flows will be added, which will be updated and
432 * which will be removed based on our internal state.
435 void prepareUpdate() {
437 Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
438 for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
439 if (entry.getValue() instanceof Meter) {
440 Meter Meter = (Meter) entry.getValue();
441 preparePutEntry(entry.getKey(), Meter);
446 removals = modification.getRemovedConfigurationData();
449 private void preparePutEntry(InstanceIdentifier<?> key, Meter meter) {
451 Meter original = originalSwMeterView.get(key);
452 if (original != null) {
453 // It is update for us
455 updates.put(key, meter);
457 // It is addition for us
459 additions.put(key, meter);
464 * We are OK to go with execution of plan
468 public RpcResult<Void> finish() throws IllegalStateException {
470 RpcResult<Void> rpcStatus = commitToPlugin(this);
471 // We return true if internal transaction is successful.
472 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
478 * We should rollback our preparation
482 public RpcResult<Void> rollback() throws IllegalStateException {
483 // NOOP - we did not modified any internal state during
484 // requestCommit phase
485 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
486 return Rpcs.getRpcResult(true, null, null);
492 private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
494 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
495 DataModification<InstanceIdentifier<?>, DataObject> modification) {
496 // We should verify transaction
497 System.out.println("Coming in MeterDataCommitHandler");
498 internalTransaction transaction = new internalTransaction(modification);
499 transaction.prepareUpdate();
504 final class MeterEventListener implements SalMeterListener {
506 List<MeterAdded> addedMeter = new ArrayList<>();
507 List<MeterRemoved> removeMeter = new ArrayList<>();
508 List<MeterUpdated> updatedMeter = new ArrayList<>();
511 public void onMeterAdded(MeterAdded notification) {
512 // TODO Auto-generated method stub
517 public void onMeterRemoved(MeterRemoved notification) {
518 // TODO Auto-generated method stub
523 public void onMeterUpdated(MeterUpdated notification) {
524 // TODO Auto-generated method stub