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.flow.service.rev130819.UpdateFlowInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterAdded;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterRemoved;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterUpdated;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
55 import org.opendaylight.yangtools.concepts.Registration;
56 import org.opendaylight.yangtools.yang.binding.DataObject;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.binding.NotificationListener;
59 import org.opendaylight.yangtools.yang.common.RpcError;
60 import org.opendaylight.yangtools.yang.common.RpcResult;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
64 public class MeterConsumerImpl {
65 protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
66 private final MeterEventListener meterEventListener = new MeterEventListener();
67 private Registration<NotificationListener> meterListener;
68 private SalMeterService meterService;
69 private MeterDataCommitHandler commitHandler;
71 public MeterConsumerImpl() {
72 InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).toInstance();
73 meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
75 if (null == meterService) {
76 logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
77 System.out.println("Consumer SAL Meter Service is down or NULL.");
81 // For switch/plugin events
82 meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
84 if (null == meterListener) {
85 logger.error("Listener to listen on meter data modifcation events");
86 System.out.println("Listener to listen on meter data modifcation events.");
90 commitHandler = new MeterDataCommitHandler();
91 FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
95 * Adds Meter to the southbound plugin and our internal database
100 private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
101 MeterKey meterKey = meterAddDataObject.getKey();
103 if (null != meterKey && validateMeter(meterAddDataObject).isSuccess()) {
104 AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
105 meterBuilder.fieldsFrom(meterAddDataObject);
106 meterBuilder.setMeterId(new MeterId(meterAddDataObject.getId()));
107 meterBuilder.setNode(meterAddDataObject.getNode());
108 meterService.addMeter(meterBuilder.build());
110 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
113 return new Status(StatusCode.SUCCESS);
117 * Update Meter to the southbound plugin and our internal database
123 private Status updateMeter(InstanceIdentifier<?> path,
124 Meter updatedMeter, Meter originalMeter) {
125 UpdatedMeterBuilder updateMeterBuilder = null;
127 if (validateMeter(updatedMeter).isSuccess()) {
128 UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
129 updateMeterInputBuilder.setNode(updatedMeter.getNode());
130 updateMeterBuilder = new UpdatedMeterBuilder();
131 updateMeterBuilder.fieldsFrom(updatedMeter);
132 updateMeterBuilder.setMeterId(new MeterId(updatedMeter.getId()));
133 updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
134 OriginalMeterBuilder originalMeterBuilder = new OriginalMeterBuilder(originalMeter);
135 updateMeterInputBuilder.setOriginalMeter(originalMeterBuilder.build());
136 meterService.updateMeter(updateMeterInputBuilder.build());
138 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
141 return new Status(StatusCode.SUCCESS);
145 * Remove Meter to the southbound plugin and our internal database
151 private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
152 MeterKey meterKey = meterRemoveDataObject.getKey();
154 if (null != meterKey && validateMeter(meterRemoveDataObject).isSuccess()) {
155 RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
156 meterBuilder.fieldsFrom(meterRemoveDataObject);
157 meterBuilder.setNode(meterRemoveDataObject.getNode());
158 meterBuilder.setMeterId(new MeterId(meterRemoveDataObject.getId()));
159 meterService.removeMeter(meterBuilder.build());
161 return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
164 return new Status(StatusCode.SUCCESS);
167 public Status validateMeter(Meter meter) {
169 Status returnStatus = null;
172 meterName = meter.getMeterName();
173 if (!FRMUtil.isNameValid(meterName)) {
174 logger.error("Meter Name is invalid %s" + meterName);
175 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
179 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
180 if (null != meter.getFlags() && !meter.getFlags().isMeterBurst()) {
181 if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
182 logger.error("Burst size should only be associated when Burst FLAG is set");
183 returnStatus = new Status(StatusCode.BADREQUEST,
184 "Burst size should only be associated when Burst FLAG is set");
190 if (null != returnStatus && !returnStatus.isSuccess()) {
192 } else if (null != meter.getMeterBandHeaders()) {
193 BandType setBandType = null;
194 DscpRemark dscpRemark = null;
195 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
196 setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
197 if (setBandType instanceof DscpRemark) {
198 dscpRemark = (DscpRemark) setBandType;
199 if (0 > dscpRemark.getRate()) {
202 } else if (setBandType instanceof Drop) {
203 if (0 < dscpRemark.getPercLevel()) {
204 logger.error("Number of drop Precedence level");
206 } else if (setBandType instanceof Experimenter) {
212 return new Status(StatusCode.SUCCESS);
215 private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
216 DataModification<InstanceIdentifier<?>, DataObject> modification = transaction.modification;
217 //get created entries
218 Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
219 modification.getCreatedConfigurationData().entrySet();
221 //get updated entries
222 Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries =
223 new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
225 updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
226 updatedEntries.removeAll(createdEntries);
228 //get removed entries
229 Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
230 modification.getRemovedConfigurationData();
232 for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) {
233 if(entry.getValue() instanceof Meter) {
234 addMeter(entry.getKey(), (Meter)entry.getValue());
238 for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
239 if(entry.getValue() instanceof Meter) {
240 Meter originalMeter = (Meter) modification.getOriginalConfigurationData().get(entry.getKey());
241 Meter updatedMeter = (Meter) entry.getValue();
242 updateMeter(entry.getKey(), originalMeter, updatedMeter);
246 for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
247 DataObject removeValue = modification.getOriginalConfigurationData().get(instanceId);
248 if(removeValue instanceof Meter) {
249 removeMeter(instanceId, (Meter)removeValue);
253 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
256 final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
258 private final DataModification<InstanceIdentifier<?>, DataObject> modification;
261 public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
265 public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
266 this.modification = modification;
270 * We create a plan which flows will be added, which will be updated and
271 * which will be removed based on our internal state.
274 void prepareUpdate() {
279 * We are OK to go with execution of plan
283 public RpcResult<Void> finish() throws IllegalStateException {
285 RpcResult<Void> rpcStatus = commitToPlugin(this);
291 * We should rollback our preparation
295 public RpcResult<Void> rollback() throws IllegalStateException {
296 return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
302 private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
304 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
305 DataModification<InstanceIdentifier<?>, DataObject> modification) {
306 // We should verify transaction
307 InternalTransaction transaction = new InternalTransaction(modification);
308 transaction.prepareUpdate();
313 final class MeterEventListener implements SalMeterListener {
315 List<MeterAdded> addedMeter = new ArrayList<>();
316 List<MeterRemoved> removeMeter = new ArrayList<>();
317 List<MeterUpdated> updatedMeter = new ArrayList<>();
320 public void onMeterAdded(MeterAdded notification) {
321 // TODO Auto-generated method stub
326 public void onMeterRemoved(MeterRemoved notification) {
327 // TODO Auto-generated method stub
332 public void onMeterUpdated(MeterUpdated notification) {
333 // TODO Auto-generated method stub