1 package org.opendaylight.controller.forwardingrulesmanager.consumer.impl;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.EnumSet;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.Iterator;
11 import java.util.Map.Entry;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.ConcurrentMap;
16 import org.opendaylight.controller.clustering.services.CacheConfigException;
17 import org.opendaylight.controller.clustering.services.CacheExistException;
18 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
19 import org.opendaylight.controller.clustering.services.IClusterServices;
20 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
21 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
23 import org.opendaylight.controller.sal.common.util.Rpcs;
24 import org.opendaylight.controller.sal.core.IContainer;
25 import org.opendaylight.controller.sal.core.Node;
26 import org.opendaylight.controller.sal.utils.GlobalConstants;
27 import org.opendaylight.controller.sal.utils.Status;
28 import org.opendaylight.controller.sal.utils.StatusCode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterAdded;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterRemoved;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterUpdated;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
44 import org.opendaylight.yangtools.concepts.Registration;
45 import org.opendaylight.yangtools.yang.binding.DataObject;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.opendaylight.yangtools.yang.binding.NotificationListener;
48 import org.opendaylight.yangtools.yang.common.RpcResult;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 public class MeterConsumerImpl implements IForwardingRulesManager {
53 protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
54 private final MeterEventListener meterEventListener = new MeterEventListener();
55 private Registration<NotificationListener> meterListener;
56 private SalMeterService meterService;
57 private MeterDataCommitHandler commitHandler;
59 private ConcurrentMap<MeterKey, Meter> originalSwMeterView;
60 private ConcurrentMap<MeterKey, Meter> installedSwMeterView;
62 private ConcurrentMap<Node, List<Meter>> nodeMeters;
63 private ConcurrentMap<MeterKey, Meter> inactiveMeters;
65 private IClusterContainerServices clusterMeterContainerService = null;
66 private IContainer container;
68 public MeterConsumerImpl() {
69 InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder().node(Meters.class)
70 .node(Meter.class).toInstance();
71 meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
72 clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
74 container = FRMConsumerImpl.getContainer();
76 if (!(cacheStartup())) {
77 logger.error("Unable to allocate/retrieve meter cache");
78 System.out.println("Unable to allocate/retrieve meter cache");
81 if (null == meterService) {
82 logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
83 System.out.println("Consumer SAL Meter Service is down or NULL.");
87 // For switch/plugin events
88 meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
90 if (null == meterListener) {
91 logger.error("Listener to listen on meter data modifcation events");
92 System.out.println("Listener to listen on meter data modifcation events.");
96 commitHandler = new MeterDataCommitHandler();
97 FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
100 private boolean allocateMeterCaches() {
101 if (this.clusterMeterContainerService == null) {
102 logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
107 clusterMeterContainerService.createCache("frm.originalSwMeterView",
108 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
110 clusterMeterContainerService.createCache("frm.installedSwMeterView",
111 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
113 clusterMeterContainerService.createCache("frm.inactiveMeters",
114 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
116 clusterMeterContainerService.createCache("frm.nodeMeters",
117 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
119 // TODO for cluster mode
121 * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
122 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
123 * IClusterServices.cacheMode.ASYNC));
125 * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
126 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
127 * IClusterServices.cacheMode.ASYNC));
130 } catch (CacheConfigException cce) {
131 logger.error("Meter CacheConfigException");
134 } catch (CacheExistException cce) {
135 logger.error(" Meter CacheExistException");
141 private void nonClusterMeterObjectCreate() {
142 originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
143 installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
144 nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
145 inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
148 @SuppressWarnings({ "unchecked" })
149 private boolean retrieveMeterCaches() {
150 ConcurrentMap<?, ?> map;
152 if (this.clusterMeterContainerService == null) {
153 logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
154 nonClusterMeterObjectCreate();
158 map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
160 originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
162 logger.error("Retrieval of cache(originalSwMeterView) failed");
166 map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
168 installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
170 logger.error("Retrieval of cache(installedSwMeterView) failed");
174 map = clusterMeterContainerService.getCache("frm.inactiveMeters");
176 inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
178 logger.error("Retrieval of cache(inactiveMeters) failed");
182 map = clusterMeterContainerService.getCache("frm.nodeMeters");
184 nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
186 logger.error("Retrieval of cache(nodeMeter) failed");
193 private boolean cacheStartup() {
194 if (allocateMeterCaches()) {
195 if (retrieveMeterCaches()) {
204 * Adds Meter to the southbound plugin and our internal database
209 private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
210 MeterKey meterKey = meterAddDataObject.getKey();
212 if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {
213 if (meterAddDataObject.isInstall()) {
214 AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
216 meterBuilder.setContainerName(meterAddDataObject.getContainerName());
217 meterBuilder.setFlags(meterAddDataObject.getFlags());
218 meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
219 meterBuilder.setMeterId(meterAddDataObject.getMeterId());
220 meterBuilder.setNode(meterAddDataObject.getNode());
221 originalSwMeterView.put(meterKey, meterAddDataObject);
222 meterService.addMeter(meterBuilder.build());
225 originalSwMeterView.put(meterKey, meterAddDataObject);
227 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
230 return new Status(StatusCode.SUCCESS);
234 * Update Meter to the southbound plugin and our internal database
240 private Status updateMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
241 MeterKey meterKey = meterUpdateDataObject.getKey();
242 UpdatedMeterBuilder updateMeterBuilder = null;
244 if (null != meterKey && 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());
266 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
269 return new Status(StatusCode.SUCCESS);
273 * Remove Meter to the southbound plugin and our internal database
279 private Status RemoveMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
280 MeterKey meterKey = meterUpdateDataObject.getKey();
282 if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.ADD).isSuccess()) {
283 if (meterUpdateDataObject.isInstall()) {
284 UpdateMeterInputBuilder updateMeterBuilder = new UpdateMeterInputBuilder();
286 installedSwMeterView.put(meterKey, meterUpdateDataObject);
287 meterService.updateMeter(updateMeterBuilder.build());
290 originalSwMeterView.put(meterKey, meterUpdateDataObject);
292 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
295 return new Status(StatusCode.SUCCESS);
298 public Status validateMeter(Meter meter, FRMUtil.operation operation) {
299 String containerName;
301 Status returnStatus = null;
302 boolean returnResult;
305 containerName = meter.getContainerName();
307 if (null == containerName) {
308 containerName = GlobalConstants.DEFAULT.toString();
309 } else if (!FRMUtil.isNameValid(containerName)) {
310 logger.error("Container Name is invalid %s" + containerName);
311 returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
315 meterName = meter.getMeterName();
316 if (!FRMUtil.isNameValid(meterName)) {
317 logger.error("Meter Name is invalid %s" + meterName);
318 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
322 returnResult = doesMeterEntryExists(meter.getKey(), meterName, containerName);
324 if (FRMUtil.operation.ADD == operation && returnResult) {
325 logger.error("Record with same Meter Name exists");
326 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record exists");
328 } else if (!returnResult) {
329 logger.error("Group record does not exist");
330 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record does not exist");
334 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
335 if (!meter.getFlags().isMeterBurst()) {
336 if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
337 logger.error("Burst size should only be associated when Burst FLAG is set");
338 returnStatus = new Status(StatusCode.BADREQUEST,
339 "Burst size should only be associated when Burst FLAG is set");
345 if (null != returnStatus && !returnStatus.isSuccess()) {
348 BandType setBandType = null;
349 DscpRemark dscpRemark = null;
350 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
351 setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
352 if (setBandType instanceof DscpRemark) {
353 dscpRemark = (DscpRemark) setBandType;
354 if (0 > dscpRemark.getRate()) {
357 } else if (setBandType instanceof Drop) {
358 if (0 < dscpRemark.getPercLevel()) {
359 logger.error("Number of drop Precedence level");
361 } else if (setBandType instanceof Experimenter) {
367 return new Status(StatusCode.SUCCESS);
370 private boolean doesMeterEntryExists(MeterKey key, String meterName, String containerName) {
371 if (!originalSwMeterView.containsKey(key)) {
375 for (Entry<MeterKey, Meter> entry : originalSwMeterView.entrySet()) {
376 if (entry.getValue().getMeterName().equals(meterName)) {
377 if (entry.getValue().getContainerName().equals(containerName)) {
385 private RpcResult<Void> commitToPlugin(internalTransaction transaction) {
386 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
388 if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
389 return Rpcs.getRpcResult(false, null, null);
392 for (@SuppressWarnings("unused")
393 Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
395 if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
396 return Rpcs.getRpcResult(false, null, null);
400 for (InstanceIdentifier<?> removal : transaction.removals) {
402 * if (!removeMeter(entry.getKey(),entry.getValue()).isSuccess()) {
403 * return Rpcs.getRpcResult(false, null, null); }
407 return Rpcs.getRpcResult(true, null, null);
410 private final class internalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
412 private final DataModification<InstanceIdentifier<?>, DataObject> modification;
415 public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
419 public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
420 this.modification = modification;
423 Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
424 Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
425 Set<InstanceIdentifier<?>> removals = new HashSet<>();
428 * We create a plan which flows will be added, which will be updated and
429 * which will be removed based on our internal state.
432 void prepareUpdate() {
434 Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
435 for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
436 if (entry.getValue() instanceof Meter) {
437 Meter Meter = (Meter) entry.getValue();
438 preparePutEntry(entry.getKey(), Meter);
443 removals = modification.getRemovedConfigurationData();
446 private void preparePutEntry(InstanceIdentifier<?> key, Meter meter) {
448 Meter original = originalSwMeterView.get(key);
449 if (original != null) {
450 // It is update for us
452 updates.put(key, meter);
454 // It is addition for us
456 additions.put(key, meter);
461 * We are OK to go with execution of plan
465 public RpcResult<Void> finish() throws IllegalStateException {
467 RpcResult<Void> rpcStatus = commitToPlugin(this);
468 // We return true if internal transaction is successful.
469 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
475 * We should rollback our preparation
479 public RpcResult<Void> rollback() throws IllegalStateException {
480 // NOOP - we did not modified any internal state during
481 // requestCommit phase
482 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
483 return Rpcs.getRpcResult(true, null, null);
489 private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
491 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
492 DataModification<InstanceIdentifier<?>, DataObject> modification) {
493 // We should verify transaction
494 System.out.println("Coming in MeterDataCommitHandler");
495 internalTransaction transaction = new internalTransaction(modification);
496 transaction.prepareUpdate();
501 final class MeterEventListener implements SalMeterListener {
503 List<MeterAdded> addedMeter = new ArrayList<>();
504 List<MeterRemoved> removeMeter = new ArrayList<>();
505 List<MeterUpdated> updatedMeter = new ArrayList<>();
508 public void onMeterAdded(MeterAdded notification) {
509 // TODO Auto-generated method stub
514 public void onMeterRemoved(MeterRemoved notification) {
515 // TODO Auto-generated method stub
520 public void onMeterUpdated(MeterUpdated notification) {
521 // TODO Auto-generated method stub
527 public List<DataObject> get() {
529 List<DataObject> orderedList = new ArrayList<DataObject>();
530 Collection<Meter> meterList = originalSwMeterView.values();
531 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
532 orderedList.add(iterator.next());
538 public DataObject getWithName(String name, Node n) {
539 if (this instanceof MeterConsumerImpl) {
540 Collection<Meter> meterList = originalSwMeterView.values();
541 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
542 Meter meter = iterator.next();
543 if (meter.getNode().equals(n) && meter.getMeterName().equals(name)) {