1 package org.opendaylight.controller.forwardingrulesmanager.consumer.impl;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.EnumSet;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.List;
12 import java.util.Map.Entry;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
17 import org.opendaylight.controller.clustering.services.CacheConfigException;
18 import org.opendaylight.controller.clustering.services.CacheExistException;
19 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
20 import org.opendaylight.controller.clustering.services.IClusterServices;
21 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
22 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
24 import org.opendaylight.controller.sal.common.util.Rpcs;
25 import org.opendaylight.controller.sal.core.IContainer;
26 import org.opendaylight.controller.sal.core.Node;
27 import org.opendaylight.controller.sal.utils.GlobalConstants;
28 import org.opendaylight.controller.sal.utils.Status;
29 import org.opendaylight.controller.sal.utils.StatusCode;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterAdded;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterRemoved;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterUpdated;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
46 import org.opendaylight.yangtools.concepts.Registration;
47 import org.opendaylight.yangtools.yang.binding.DataObject;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.binding.NotificationListener;
50 import org.opendaylight.yangtools.yang.common.RpcError;
51 import org.opendaylight.yangtools.yang.common.RpcResult;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 public class MeterConsumerImpl implements IForwardingRulesManager {
56 protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
57 private final MeterEventListener meterEventListener = new MeterEventListener();
58 private Registration<NotificationListener> meterListener;
59 private SalMeterService meterService;
60 private MeterDataCommitHandler commitHandler;
62 private ConcurrentMap<MeterKey, Meter> originalSwMeterView;
63 @SuppressWarnings("unused")
64 private ConcurrentMap<MeterKey, Meter> installedSwMeterView;
65 @SuppressWarnings("unused")
66 private ConcurrentMap<Node, List<Meter>> nodeMeters;
67 @SuppressWarnings("unused")
68 private ConcurrentMap<MeterKey, Meter> inactiveMeters;
69 @SuppressWarnings("unused")
70 private IContainer container;
72 private IClusterContainerServices clusterMeterContainerService = null;
75 public MeterConsumerImpl() {
76 InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).child(Meter.class)
78 meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
79 clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
81 container = FRMConsumerImpl.getContainer();
83 if (!(cacheStartup())) {
84 logger.error("Unable to allocate/retrieve meter cache");
85 System.out.println("Unable to allocate/retrieve meter cache");
88 if (null == meterService) {
89 logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
90 System.out.println("Consumer SAL Meter Service is down or NULL.");
94 // For switch/plugin events
95 meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
97 if (null == meterListener) {
98 logger.error("Listener to listen on meter data modifcation events");
99 System.out.println("Listener to listen on meter data modifcation events.");
103 commitHandler = new MeterDataCommitHandler();
104 FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
107 private boolean allocateMeterCaches() {
108 if (this.clusterMeterContainerService == null) {
109 logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
114 clusterMeterContainerService.createCache("frm.originalSwMeterView",
115 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
117 clusterMeterContainerService.createCache("frm.installedSwMeterView",
118 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
120 clusterMeterContainerService.createCache("frm.inactiveMeters",
121 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
123 clusterMeterContainerService.createCache("frm.nodeMeters",
124 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
126 // TODO for cluster mode
128 * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
129 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
130 * IClusterServices.cacheMode.ASYNC));
132 * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
133 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
134 * IClusterServices.cacheMode.ASYNC));
137 } catch (CacheConfigException cce) {
138 logger.error("Meter CacheConfigException");
141 } catch (CacheExistException cce) {
142 logger.error(" Meter CacheExistException");
148 private void nonClusterMeterObjectCreate() {
149 originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
150 installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
151 nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
152 inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
155 @SuppressWarnings({ "unchecked" })
156 private boolean retrieveMeterCaches() {
157 ConcurrentMap<?, ?> map;
159 if (this.clusterMeterContainerService == null) {
160 logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
161 nonClusterMeterObjectCreate();
165 map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
167 originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
169 logger.error("Retrieval of cache(originalSwMeterView) failed");
173 map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
175 installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
177 logger.error("Retrieval of cache(installedSwMeterView) failed");
181 map = clusterMeterContainerService.getCache("frm.inactiveMeters");
183 inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
185 logger.error("Retrieval of cache(inactiveMeters) failed");
189 map = clusterMeterContainerService.getCache("frm.nodeMeters");
191 nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
193 logger.error("Retrieval of cache(nodeMeter) failed");
200 private boolean cacheStartup() {
201 if (allocateMeterCaches()) {
202 if (retrieveMeterCaches()) {
211 * Adds Meter to the southbound plugin and our internal database
216 private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
217 MeterKey meterKey = meterAddDataObject.getKey();
219 if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {
220 if (meterAddDataObject.isInstall()) {
221 AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
223 meterBuilder.setContainerName(meterAddDataObject.getContainerName());
224 meterBuilder.setFlags(meterAddDataObject.getFlags());
225 meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
226 meterBuilder.setMeterId(meterAddDataObject.getMeterId());
227 meterBuilder.setNode(meterAddDataObject.getNode());
228 // originalSwMeterView.put(meterKey, meterAddDataObject);
229 meterService.addMeter(meterBuilder.build());
232 // originalSwMeterView.put(meterKey, meterAddDataObject);
234 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
237 return new Status(StatusCode.SUCCESS);
241 * Update Meter to the southbound plugin and our internal database
247 private Status updateMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
248 MeterKey meterKey = meterUpdateDataObject.getKey();
249 UpdatedMeterBuilder updateMeterBuilder = null;
251 if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) {
253 /* if (originalSwMeterView.containsKey(meterKey)) {
254 originalSwMeterView.remove(meterKey);
255 originalSwMeterView.put(meterKey, meterUpdateDataObject);
258 if (meterUpdateDataObject.isInstall()) {
259 UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
260 updateMeterBuilder = new UpdatedMeterBuilder();
261 updateMeterBuilder.fieldsFrom(meterUpdateDataObject);
262 updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
264 /* if (installedSwMeterView.containsKey(meterKey)) {
265 installedSwMeterView.remove(meterKey);
266 installedSwMeterView.put(meterKey, meterUpdateDataObject);
269 meterService.updateMeter(updateMeterInputBuilder.build());
273 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
276 return new Status(StatusCode.SUCCESS);
280 * Remove Meter to the southbound plugin and our internal database
286 private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
287 MeterKey meterKey = meterRemoveDataObject.getKey();
289 if (null != meterKey && validateMeter(meterRemoveDataObject, FRMUtil.operation.DELETE).isSuccess()) {
290 if (meterRemoveDataObject.isInstall()) {
291 RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
292 meterBuilder.setContainerName(meterRemoveDataObject.getContainerName());
293 meterBuilder.setNode(meterRemoveDataObject.getNode());
294 meterBuilder.setFlags(meterRemoveDataObject.getFlags());
295 meterBuilder.setMeterBandHeaders(meterRemoveDataObject.getMeterBandHeaders());
296 meterBuilder.setMeterId(meterRemoveDataObject.getMeterId());
297 meterBuilder.setNode(meterRemoveDataObject.getNode());
298 // originalSwMeterView.put(meterKey, meterAddDataObject);
299 meterService.removeMeter(meterBuilder.build());
302 // originalSwMeterView.put(meterKey, meterAddDataObject);
304 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
307 return new Status(StatusCode.SUCCESS);
310 public Status validateMeter(Meter meter, FRMUtil.operation operation) {
311 String containerName;
313 Status returnStatus = null;
316 containerName = meter.getContainerName();
318 if (null == containerName) {
319 containerName = GlobalConstants.DEFAULT.toString();
320 } else if (!FRMUtil.isNameValid(containerName)) {
321 logger.error("Container Name is invalid %s" + containerName);
322 returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
326 meterName = meter.getMeterName();
327 if (!FRMUtil.isNameValid(meterName)) {
328 logger.error("Meter Name is invalid %s" + meterName);
329 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
333 /* returnResult = doesMeterEntryExists(meter.getKey(), meterName, containerName);
335 if (FRMUtil.operation.ADD == operation && returnResult) {
336 logger.error("Record with same Meter Name exists");
337 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record exists");
339 } else if (!returnResult) {
340 logger.error("Group record does not exist");
341 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record does not exist");
345 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
346 if (!meter.getFlags().isMeterBurst()) {
347 if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
348 logger.error("Burst size should only be associated when Burst FLAG is set");
349 returnStatus = new Status(StatusCode.BADREQUEST,
350 "Burst size should only be associated when Burst FLAG is set");
356 if (null != returnStatus && !returnStatus.isSuccess()) {
359 BandType setBandType = null;
360 DscpRemark dscpRemark = null;
361 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
362 setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
363 if (setBandType instanceof DscpRemark) {
364 dscpRemark = (DscpRemark) setBandType;
365 if (0 > dscpRemark.getRate()) {
368 } else if (setBandType instanceof Drop) {
369 if (0 < dscpRemark.getPercLevel()) {
370 logger.error("Number of drop Precedence level");
372 } else if (setBandType instanceof Experimenter) {
378 return new Status(StatusCode.SUCCESS);
381 /*private boolean doesMeterEntryExists(MeterKey key, String meterName, String containerName) {
382 if (!originalSwMeterView.containsKey(key)) {
386 for (Entry<MeterKey, Meter> entry : originalSwMeterView.entrySet()) {
387 if (entry.getValue().getMeterName().equals(meterName)) {
388 if (entry.getValue().getContainerName().equals(containerName)) {
396 private final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
398 private final DataModification<InstanceIdentifier<?>, DataObject> modification;
401 public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
405 public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
406 this.modification = modification;
409 Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
410 Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
411 Set<InstanceIdentifier<?>> removals = new HashSet<>();
414 * We create a plan which flows will be added, which will be updated and
415 * which will be removed based on our internal state.
418 void prepareUpdate() {
420 Set<Entry<InstanceIdentifier<?>, DataObject>> addMeter = modification.getCreatedConfigurationData().entrySet();
421 for (Entry<InstanceIdentifier<?>, DataObject> entry : addMeter) {
422 if (entry.getValue() instanceof Meter) {
423 Meter meter = (Meter) entry.getValue();
424 additions.put(entry.getKey(), meter);
429 Set<Entry<InstanceIdentifier<?>, DataObject>> updateMeter = modification.getUpdatedConfigurationData().entrySet();
430 for (Entry<InstanceIdentifier<?>, DataObject> entry : updateMeter) {
431 if (entry.getValue() instanceof Meter) {
432 Meter meter = (Meter) entry.getValue();
433 ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it.
434 if (!additions.containsKey(entry.getKey())) {
435 updates.put(entry.getKey(), meter);
440 removals = modification.getRemovedConfigurationData();
444 * We are OK to go with execution of plan
448 public RpcResult<Void> finish() throws IllegalStateException {
450 RpcResult<Void> rpcStatus = commitToPlugin(this);
451 // We return true if internal transaction is successful.
452 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
458 * We should rollback our preparation
462 public RpcResult<Void> rollback() throws IllegalStateException {
463 // NOOP - we did not modified any internal state during
464 // requestCommit phase
465 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
466 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
472 private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
473 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
475 if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
476 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
479 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
481 if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
482 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
486 for (InstanceIdentifier<?> meterId : transaction.removals) {
487 DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(meterId);
489 if(removeValue instanceof Meter) {
490 if(!removeMeter(meterId, (Meter)removeValue).isSuccess()) {
491 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
496 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
499 private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
501 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
502 DataModification<InstanceIdentifier<?>, DataObject> modification) {
503 // We should verify transaction
504 System.out.println("Coming in MeterDataCommitHandler");
505 InternalTransaction transaction = new InternalTransaction(modification);
506 transaction.prepareUpdate();
511 final class MeterEventListener implements SalMeterListener {
513 List<MeterAdded> addedMeter = new ArrayList<>();
514 List<MeterRemoved> removeMeter = new ArrayList<>();
515 List<MeterUpdated> updatedMeter = new ArrayList<>();
518 public void onMeterAdded(MeterAdded notification) {
519 // TODO Auto-generated method stub
524 public void onMeterRemoved(MeterRemoved notification) {
525 // TODO Auto-generated method stub
530 public void onMeterUpdated(MeterUpdated notification) {
531 // TODO Auto-generated method stub
537 public List<DataObject> get() {
539 List<DataObject> orderedList = new ArrayList<DataObject>();
540 Collection<Meter> meterList = originalSwMeterView.values();
541 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
542 orderedList.add(iterator.next());
548 public DataObject getWithName(String name, Node n) {
549 if (this instanceof MeterConsumerImpl) {
550 Collection<Meter> meterList = originalSwMeterView.values();
551 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
552 Meter meter = iterator.next();
553 if (meter.getNode().equals(n) && meter.getMeterName().equals(name)) {