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).toInstance();
77 meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
78 clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
80 container = FRMConsumerImpl.getContainer();
82 if (!(cacheStartup())) {
83 logger.error("Unable to allocate/retrieve meter cache");
84 System.out.println("Unable to allocate/retrieve meter cache");
87 if (null == meterService) {
88 logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
89 System.out.println("Consumer SAL Meter Service is down or NULL.");
93 // For switch/plugin events
94 meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
96 if (null == meterListener) {
97 logger.error("Listener to listen on meter data modifcation events");
98 System.out.println("Listener to listen on meter data modifcation events.");
102 commitHandler = new MeterDataCommitHandler();
103 FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
106 private boolean allocateMeterCaches() {
107 if (this.clusterMeterContainerService == null) {
108 logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
113 clusterMeterContainerService.createCache("frm.originalSwMeterView",
114 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
116 clusterMeterContainerService.createCache("frm.installedSwMeterView",
117 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
119 clusterMeterContainerService.createCache("frm.inactiveMeters",
120 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
122 clusterMeterContainerService.createCache("frm.nodeMeters",
123 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
125 // TODO for cluster mode
127 * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
128 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
129 * IClusterServices.cacheMode.ASYNC));
131 * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
132 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
133 * IClusterServices.cacheMode.ASYNC));
136 } catch (CacheConfigException cce) {
137 logger.error("Meter CacheConfigException");
140 } catch (CacheExistException cce) {
141 logger.error(" Meter CacheExistException");
147 private void nonClusterMeterObjectCreate() {
148 originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
149 installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
150 nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
151 inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
154 @SuppressWarnings({ "unchecked" })
155 private boolean retrieveMeterCaches() {
156 ConcurrentMap<?, ?> map;
158 if (this.clusterMeterContainerService == null) {
159 logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
160 nonClusterMeterObjectCreate();
164 map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
166 originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
168 logger.error("Retrieval of cache(originalSwMeterView) failed");
172 map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
174 installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
176 logger.error("Retrieval of cache(installedSwMeterView) failed");
180 map = clusterMeterContainerService.getCache("frm.inactiveMeters");
182 inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
184 logger.error("Retrieval of cache(inactiveMeters) failed");
188 map = clusterMeterContainerService.getCache("frm.nodeMeters");
190 nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
192 logger.error("Retrieval of cache(nodeMeter) failed");
199 private boolean cacheStartup() {
200 if (allocateMeterCaches()) {
201 if (retrieveMeterCaches()) {
210 * Adds Meter to the southbound plugin and our internal database
215 private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
216 MeterKey meterKey = meterAddDataObject.getKey();
218 if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {
219 if (meterAddDataObject.isInstall()) {
220 AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
222 meterBuilder.setContainerName(meterAddDataObject.getContainerName());
223 meterBuilder.setFlags(meterAddDataObject.getFlags());
224 meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
225 meterBuilder.setMeterId(meterAddDataObject.getMeterId());
226 meterBuilder.setNode(meterAddDataObject.getNode());
227 // originalSwMeterView.put(meterKey, meterAddDataObject);
228 meterService.addMeter(meterBuilder.build());
231 // originalSwMeterView.put(meterKey, meterAddDataObject);
233 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
236 return new Status(StatusCode.SUCCESS);
240 * Update Meter to the southbound plugin and our internal database
246 private Status updateMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
247 MeterKey meterKey = meterUpdateDataObject.getKey();
248 UpdatedMeterBuilder updateMeterBuilder = null;
250 if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) {
252 /* if (originalSwMeterView.containsKey(meterKey)) {
253 originalSwMeterView.remove(meterKey);
254 originalSwMeterView.put(meterKey, meterUpdateDataObject);
257 if (meterUpdateDataObject.isInstall()) {
258 UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
259 updateMeterBuilder = new UpdatedMeterBuilder();
260 updateMeterBuilder.fieldsFrom(meterUpdateDataObject);
261 updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
263 /* if (installedSwMeterView.containsKey(meterKey)) {
264 installedSwMeterView.remove(meterKey);
265 installedSwMeterView.put(meterKey, meterUpdateDataObject);
268 meterService.updateMeter(updateMeterInputBuilder.build());
272 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
275 return new Status(StatusCode.SUCCESS);
279 * Remove Meter to the southbound plugin and our internal database
285 private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
286 MeterKey meterKey = meterRemoveDataObject.getKey();
288 if (null != meterKey && validateMeter(meterRemoveDataObject, FRMUtil.operation.DELETE).isSuccess()) {
289 if (meterRemoveDataObject.isInstall()) {
290 RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
291 meterBuilder.setContainerName(meterRemoveDataObject.getContainerName());
292 meterBuilder.setNode(meterRemoveDataObject.getNode());
293 meterBuilder.setFlags(meterRemoveDataObject.getFlags());
294 meterBuilder.setMeterBandHeaders(meterRemoveDataObject.getMeterBandHeaders());
295 meterBuilder.setMeterId(meterRemoveDataObject.getMeterId());
296 meterBuilder.setNode(meterRemoveDataObject.getNode());
297 // originalSwMeterView.put(meterKey, meterAddDataObject);
298 meterService.removeMeter(meterBuilder.build());
301 // originalSwMeterView.put(meterKey, meterAddDataObject);
303 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
306 return new Status(StatusCode.SUCCESS);
309 public Status validateMeter(Meter meter, FRMUtil.operation operation) {
310 String containerName;
312 Status returnStatus = null;
315 containerName = meter.getContainerName();
317 if (null == containerName) {
318 containerName = GlobalConstants.DEFAULT.toString();
319 } else if (!FRMUtil.isNameValid(containerName)) {
320 logger.error("Container Name is invalid %s" + containerName);
321 returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
325 meterName = meter.getMeterName();
326 if (!FRMUtil.isNameValid(meterName)) {
327 logger.error("Meter Name is invalid %s" + meterName);
328 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
332 /* returnResult = doesMeterEntryExists(meter.getKey(), meterName, containerName);
334 if (FRMUtil.operation.ADD == operation && returnResult) {
335 logger.error("Record with same Meter Name exists");
336 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record exists");
338 } else if (!returnResult) {
339 logger.error("Group record does not exist");
340 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record does not exist");
344 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
345 if (!meter.getFlags().isMeterBurst()) {
346 if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
347 logger.error("Burst size should only be associated when Burst FLAG is set");
348 returnStatus = new Status(StatusCode.BADREQUEST,
349 "Burst size should only be associated when Burst FLAG is set");
355 if (null != returnStatus && !returnStatus.isSuccess()) {
358 BandType setBandType = null;
359 DscpRemark dscpRemark = null;
360 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
361 setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
362 if (setBandType instanceof DscpRemark) {
363 dscpRemark = (DscpRemark) setBandType;
364 if (0 > dscpRemark.getRate()) {
367 } else if (setBandType instanceof Drop) {
368 if (0 < dscpRemark.getPercLevel()) {
369 logger.error("Number of drop Precedence level");
371 } else if (setBandType instanceof Experimenter) {
377 return new Status(StatusCode.SUCCESS);
380 /*private boolean doesMeterEntryExists(MeterKey key, String meterName, String containerName) {
381 if (!originalSwMeterView.containsKey(key)) {
385 for (Entry<MeterKey, Meter> entry : originalSwMeterView.entrySet()) {
386 if (entry.getValue().getMeterName().equals(meterName)) {
387 if (entry.getValue().getContainerName().equals(containerName)) {
395 private final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
397 private final DataModification<InstanceIdentifier<?>, DataObject> modification;
400 public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
404 public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
405 this.modification = modification;
408 Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
409 Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
410 Set<InstanceIdentifier<?>> removals = new HashSet<>();
413 * We create a plan which flows will be added, which will be updated and
414 * which will be removed based on our internal state.
417 void prepareUpdate() {
419 Set<Entry<InstanceIdentifier<?>, DataObject>> addMeter = modification.getCreatedConfigurationData().entrySet();
420 for (Entry<InstanceIdentifier<?>, DataObject> entry : addMeter) {
421 if (entry.getValue() instanceof Meter) {
422 Meter meter = (Meter) entry.getValue();
423 additions.put(entry.getKey(), meter);
428 Set<Entry<InstanceIdentifier<?>, DataObject>> updateMeter = modification.getUpdatedConfigurationData().entrySet();
429 for (Entry<InstanceIdentifier<?>, DataObject> entry : updateMeter) {
430 if (entry.getValue() instanceof Meter) {
431 Meter meter = (Meter) entry.getValue();
432 ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it.
433 if (!additions.containsKey(entry.getKey())) {
434 updates.put(entry.getKey(), meter);
439 removals = modification.getRemovedConfigurationData();
443 * We are OK to go with execution of plan
447 public RpcResult<Void> finish() throws IllegalStateException {
449 RpcResult<Void> rpcStatus = commitToPlugin(this);
450 // We return true if internal transaction is successful.
451 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
457 * We should rollback our preparation
461 public RpcResult<Void> rollback() throws IllegalStateException {
462 // NOOP - we did not modified any internal state during
463 // requestCommit phase
464 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
465 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
471 private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
472 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
474 if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
475 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
478 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
480 if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
481 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
485 for (InstanceIdentifier<?> meterId : transaction.removals) {
486 DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(meterId);
488 if(removeValue instanceof Meter) {
489 if(!removeMeter(meterId, (Meter)removeValue).isSuccess()) {
490 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
495 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
498 private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
500 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
501 DataModification<InstanceIdentifier<?>, DataObject> modification) {
502 // We should verify transaction
503 System.out.println("Coming in MeterDataCommitHandler");
504 InternalTransaction transaction = new InternalTransaction(modification);
505 transaction.prepareUpdate();
510 final class MeterEventListener implements SalMeterListener {
512 List<MeterAdded> addedMeter = new ArrayList<>();
513 List<MeterRemoved> removeMeter = new ArrayList<>();
514 List<MeterUpdated> updatedMeter = new ArrayList<>();
517 public void onMeterAdded(MeterAdded notification) {
518 // TODO Auto-generated method stub
523 public void onMeterRemoved(MeterRemoved notification) {
524 // TODO Auto-generated method stub
529 public void onMeterUpdated(MeterUpdated notification) {
530 // TODO Auto-generated method stub
536 public List<DataObject> get() {
538 List<DataObject> orderedList = new ArrayList<DataObject>();
539 Collection<Meter> meterList = originalSwMeterView.values();
540 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
541 orderedList.add(iterator.next());
547 public DataObject getWithName(String name, Node n) {
548 if (this instanceof MeterConsumerImpl) {
549 Collection<Meter> meterList = originalSwMeterView.values();
550 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
551 Meter meter = iterator.next();
552 if (meter.getNode().equals(n) && meter.getMeterName().equals(name)) {