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.MeterId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
47 import org.opendaylight.yangtools.concepts.Registration;
48 import org.opendaylight.yangtools.yang.binding.DataObject;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.opendaylight.yangtools.yang.binding.NotificationListener;
51 import org.opendaylight.yangtools.yang.common.RpcError;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 public class MeterConsumerImpl implements IForwardingRulesManager {
57 protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
58 private final MeterEventListener meterEventListener = new MeterEventListener();
59 private Registration<NotificationListener> meterListener;
60 private SalMeterService meterService;
61 private MeterDataCommitHandler commitHandler;
63 private ConcurrentMap<MeterKey, Meter> originalSwMeterView;
64 @SuppressWarnings("unused")
65 private ConcurrentMap<MeterKey, Meter> installedSwMeterView;
66 @SuppressWarnings("unused")
67 private ConcurrentMap<Node, List<Meter>> nodeMeters;
68 @SuppressWarnings("unused")
69 private ConcurrentMap<MeterKey, Meter> inactiveMeters;
70 @SuppressWarnings("unused")
71 private IContainer container;
72 private IClusterContainerServices clusterMeterContainerService = null;
74 public MeterConsumerImpl() {
75 InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).toInstance();
76 meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
77 clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
78 container = FRMConsumerImpl.getContainer();
80 if (!(cacheStartup())) {
81 logger.error("Unable to allocate/retrieve meter cache");
82 System.out.println("Unable to allocate/retrieve meter cache");
85 if (null == meterService) {
86 logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
87 System.out.println("Consumer SAL Meter Service is down or NULL.");
91 // For switch/plugin events
92 meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
94 if (null == meterListener) {
95 logger.error("Listener to listen on meter data modifcation events");
96 System.out.println("Listener to listen on meter data modifcation events.");
100 commitHandler = new MeterDataCommitHandler();
101 FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
104 private boolean allocateMeterCaches() {
105 if (this.clusterMeterContainerService == null) {
106 logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
111 clusterMeterContainerService.createCache("frm.originalSwMeterView",
112 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
114 clusterMeterContainerService.createCache("frm.installedSwMeterView",
115 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
117 clusterMeterContainerService.createCache("frm.inactiveMeters",
118 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
120 clusterMeterContainerService.createCache("frm.nodeMeters",
121 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
123 // TODO for cluster mode
125 * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
126 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
127 * IClusterServices.cacheMode.ASYNC));
129 * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
130 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
131 * IClusterServices.cacheMode.ASYNC));
134 } catch (CacheConfigException cce) {
135 logger.error("Meter CacheConfigException");
138 } catch (CacheExistException cce) {
139 logger.error(" Meter CacheExistException");
145 private void nonClusterMeterObjectCreate() {
146 originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
147 installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
148 nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
149 inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
152 @SuppressWarnings({ "unchecked" })
153 private boolean retrieveMeterCaches() {
154 ConcurrentMap<?, ?> map;
156 if (this.clusterMeterContainerService == null) {
157 logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
158 nonClusterMeterObjectCreate();
162 map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
164 originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
166 logger.error("Retrieval of cache(originalSwMeterView) failed");
170 map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
172 installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
174 logger.error("Retrieval of cache(installedSwMeterView) failed");
178 map = clusterMeterContainerService.getCache("frm.inactiveMeters");
180 inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
182 logger.error("Retrieval of cache(inactiveMeters) failed");
186 map = clusterMeterContainerService.getCache("frm.nodeMeters");
188 nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
190 logger.error("Retrieval of cache(nodeMeter) failed");
197 private boolean cacheStartup() {
198 if (allocateMeterCaches()) {
199 if (retrieveMeterCaches()) {
208 * Adds Meter to the southbound plugin and our internal database
213 private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
214 MeterKey meterKey = meterAddDataObject.getKey();
216 if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {
217 AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
218 meterBuilder.setContainerName(meterAddDataObject.getContainerName());
219 meterBuilder.setFlags(meterAddDataObject.getFlags());
220 meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
221 meterBuilder.setMeterId(new MeterId(meterAddDataObject.getId()));
222 meterBuilder.setNode(meterAddDataObject.getNode());
223 meterService.addMeter(meterBuilder.build());
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;
242 if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) { UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
243 updateMeterBuilder = new UpdatedMeterBuilder();
244 updateMeterBuilder.fieldsFrom(meterUpdateDataObject);
245 updateMeterBuilder.setMeterId(new MeterId(meterUpdateDataObject.getId()));
247 updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
248 meterService.updateMeter(updateMeterInputBuilder.build());
250 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
253 return new Status(StatusCode.SUCCESS);
257 * Remove Meter to the southbound plugin and our internal database
263 private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
264 MeterKey meterKey = meterRemoveDataObject.getKey();
266 if (null != meterKey && validateMeter(meterRemoveDataObject, FRMUtil.operation.DELETE).isSuccess()) {
267 RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
268 meterBuilder.setContainerName(meterRemoveDataObject.getContainerName());
269 meterBuilder.setNode(meterRemoveDataObject.getNode());
270 meterBuilder.setFlags(meterRemoveDataObject.getFlags());
271 meterBuilder.setMeterBandHeaders(meterRemoveDataObject.getMeterBandHeaders());
272 meterBuilder.setMeterId(new MeterId(meterRemoveDataObject.getId()));
273 meterBuilder.setNode(meterRemoveDataObject.getNode());
274 meterService.removeMeter(meterBuilder.build());
276 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
279 return new Status(StatusCode.SUCCESS);
282 public Status validateMeter(Meter meter, FRMUtil.operation operation) {
283 String containerName;
285 Status returnStatus = null;
288 containerName = meter.getContainerName();
290 if (null == containerName) {
291 containerName = GlobalConstants.DEFAULT.toString();
292 } else if (!FRMUtil.isNameValid(containerName)) {
293 logger.error("Container Name is invalid %s" + containerName);
294 returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
298 meterName = meter.getMeterName();
299 if (!FRMUtil.isNameValid(meterName)) {
300 logger.error("Meter Name is invalid %s" + meterName);
301 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
305 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
306 if (!meter.getFlags().isMeterBurst()) {
307 if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
308 logger.error("Burst size should only be associated when Burst FLAG is set");
309 returnStatus = new Status(StatusCode.BADREQUEST,
310 "Burst size should only be associated when Burst FLAG is set");
316 if (null != returnStatus && !returnStatus.isSuccess()) {
319 BandType setBandType = null;
320 DscpRemark dscpRemark = null;
321 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
322 setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
323 if (setBandType instanceof DscpRemark) {
324 dscpRemark = (DscpRemark) setBandType;
325 if (0 > dscpRemark.getRate()) {
328 } else if (setBandType instanceof Drop) {
329 if (0 < dscpRemark.getPercLevel()) {
330 logger.error("Number of drop Precedence level");
332 } else if (setBandType instanceof Experimenter) {
338 return new Status(StatusCode.SUCCESS);
341 final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
343 private final DataModification<InstanceIdentifier<?>, DataObject> modification;
346 public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
350 public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
351 this.modification = modification;
354 Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
355 Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
356 Set<InstanceIdentifier<?>> removals = new HashSet<>();
359 * We create a plan which flows will be added, which will be updated and
360 * which will be removed based on our internal state.
363 void prepareUpdate() {
365 Set<Entry<InstanceIdentifier<?>, DataObject>> addMeter = modification.getCreatedConfigurationData().entrySet();
366 for (Entry<InstanceIdentifier<?>, DataObject> entry : addMeter) {
367 if (entry.getValue() instanceof Meter) {
368 Meter meter = (Meter) entry.getValue();
369 additions.put(entry.getKey(), meter);
374 Set<Entry<InstanceIdentifier<?>, DataObject>> updateMeter = modification.getUpdatedConfigurationData().entrySet();
375 for (Entry<InstanceIdentifier<?>, DataObject> entry : updateMeter) {
376 if (entry.getValue() instanceof Meter) {
377 Meter meter = (Meter) entry.getValue();
378 ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it.
379 if (!additions.containsKey(entry.getKey())) {
380 updates.put(entry.getKey(), meter);
385 removals = modification.getRemovedConfigurationData();
389 * We are OK to go with execution of plan
393 public RpcResult<Void> finish() throws IllegalStateException {
395 RpcResult<Void> rpcStatus = commitToPlugin(this);
396 // We return true if internal transaction is successful.
397 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
403 * We should rollback our preparation
407 public RpcResult<Void> rollback() throws IllegalStateException {
408 // NOOP - we did not modified any internal state during
409 // requestCommit phase
410 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
411 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
417 private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
418 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
420 if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
421 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
424 for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
426 if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
427 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
431 for (InstanceIdentifier<?> meterId : transaction.removals) {
432 DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(meterId);
434 if(removeValue instanceof Meter) {
435 if(!removeMeter(meterId, (Meter)removeValue).isSuccess()) {
436 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
441 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
444 private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
446 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
447 DataModification<InstanceIdentifier<?>, DataObject> modification) {
448 // We should verify transaction
449 InternalTransaction transaction = new InternalTransaction(modification);
450 transaction.prepareUpdate();
455 final class MeterEventListener implements SalMeterListener {
457 List<MeterAdded> addedMeter = new ArrayList<>();
458 List<MeterRemoved> removeMeter = new ArrayList<>();
459 List<MeterUpdated> updatedMeter = new ArrayList<>();
462 public void onMeterAdded(MeterAdded notification) {
463 // TODO Auto-generated method stub
468 public void onMeterRemoved(MeterRemoved notification) {
469 // TODO Auto-generated method stub
474 public void onMeterUpdated(MeterUpdated notification) {
475 // TODO Auto-generated method stub
481 public List<DataObject> get() {
483 List<DataObject> orderedList = new ArrayList<DataObject>();
484 Collection<Meter> meterList = originalSwMeterView.values();
485 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
486 orderedList.add(iterator.next());
492 public DataObject getWithName(String name, Node n) {
493 if (this instanceof MeterConsumerImpl) {
494 Collection<Meter> meterList = originalSwMeterView.values();
495 for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
496 Meter meter = iterator.next();
497 if (meter.getNode().equals(n) && meter.getMeterName().equals(name)) {