Merge "BUG-5839: Removing groups and meters on being stale-marked"
[openflowplugin.git] / applications / forwardingrules-manager / src / main / java / org / opendaylight / openflowplugin / applications / frm / impl / FlowNodeReconciliationImpl.java
1 /**
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.applications.frm.impl;
10
11 import java.util.concurrent.atomic.AtomicInteger;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.Lists;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.ListIterator;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.concurrent.Callable;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
28 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
31 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
34 import org.opendaylight.openflowplugin.applications.frm.FlowNodeReconciliation;
35 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesManager;
36 import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.StaleMeter;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.StaleMeterKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.StaleFlow;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.StaleFlowKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.StaleGroup;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.StaleGroupKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
67 import org.opendaylight.yangtools.concepts.ListenerRegistration;
68 import org.opendaylight.yangtools.yang.binding.DataObject;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74
75 /**
76  * forwardingrules-manager
77  * org.opendaylight.openflowplugin.applications.frm
78  *
79  * FlowNode Reconciliation Listener
80  * Reconciliation for a new FlowNode
81  *
82  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
83  *
84  * Created: Jun 13, 2014
85  */
86 public class FlowNodeReconciliationImpl implements FlowNodeReconciliation {
87
88     private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconciliationImpl.class);
89
90     private final DataBroker dataBroker;
91
92     private final ForwardingRulesManager provider;
93     public static final String SEPARATOR = ":";
94
95     private ListenerRegistration<DataChangeListener> listenerRegistration;
96
97     public FlowNodeReconciliationImpl (final ForwardingRulesManager manager, final DataBroker db) {
98         this.provider = Preconditions.checkNotNull(manager, "ForwardingRulesManager can not be null!");
99         dataBroker = Preconditions.checkNotNull(db, "DataBroker can not be null!");
100         /* Build Path */
101         final InstanceIdentifier<FlowCapableNode> flowNodeWildCardIdentifier = InstanceIdentifier.create(Nodes.class)
102                 .child(Node.class).augmentation(FlowCapableNode.class);
103
104         SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(ForwardingRulesManagerImpl.STARTUP_LOOP_TICK,
105                 ForwardingRulesManagerImpl.STARTUP_LOOP_MAX_RETRIES);
106         try {
107             listenerRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataChangeListener>>() {
108                 @Override
109                 public ListenerRegistration<DataChangeListener> call() throws Exception {
110                     return db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
111                             flowNodeWildCardIdentifier, FlowNodeReconciliationImpl.this, DataChangeScope.BASE);
112                 }
113             });
114         } catch (Exception e) {
115             LOG.warn("data listener registration failed: {}", e.getMessage());
116             LOG.debug("data listener registration failed.. ", e);
117             throw new IllegalStateException("FlowNodeReconciliation startup fail! System needs restart.", e);
118         }
119     }
120
121     @Override
122     public void close() {
123         if (listenerRegistration != null) {
124             try {
125                 listenerRegistration.close();
126             } catch (Exception e) {
127                 LOG.warn("Error by stop FRM FlowNodeReconilListener: {}", e.getMessage());
128                 LOG.debug("Error by stop FRM FlowNodeReconilListener..", e);
129             }
130             listenerRegistration = null;
131         }
132     }
133
134     @Override
135     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
136         Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
137         /* All DataObjects for create */
138         final Set<InstanceIdentifier<?>>  createdData = changeEvent.getCreatedData() != null
139                 ? changeEvent.getCreatedData().keySet() : Collections.<InstanceIdentifier<?>> emptySet();
140         /* All DataObjects for remove */
141         final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
142                 ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
143         /* All updated DataObjects */
144         final Map<InstanceIdentifier<?>, DataObject> updateData = changeEvent.getUpdatedData() != null
145                 ? changeEvent.getUpdatedData() : Collections.<InstanceIdentifier<?>, DataObject>emptyMap();
146
147         for (InstanceIdentifier<?> entryKey : removeData) {
148             final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
149                     .firstIdentifierOf(FlowCapableNode.class);
150             if ( ! nodeIdent.isWildcarded()) {
151                 flowNodeDisconnected(nodeIdent);
152             }
153         }
154         for (InstanceIdentifier<?> entryKey : createdData) {
155             final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
156                     .firstIdentifierOf(FlowCapableNode.class);
157             if ( ! nodeIdent.isWildcarded()) {
158                 flowNodeConnected(nodeIdent);
159             }
160         }
161
162         // FIXME: just a hack to cover DS/operational dirty start
163         // if all conventional ways failed and there is update
164         if (removeData.isEmpty() && createdData.isEmpty() && updateData.size() == 1) {
165             for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : updateData.entrySet()) {
166                 // and only if this update covers top element (flow-capable-node)
167                 if (FlowCapableNode.class.equals(entry.getKey().getTargetType())) {
168                     final InstanceIdentifier<FlowCapableNode> nodeIdent = entry.getKey()
169                             .firstIdentifierOf(FlowCapableNode.class);
170                     if (!nodeIdent.isWildcarded()) {
171                         // then force registration to local node cache and reconcile
172                         flowNodeConnected(nodeIdent, true);
173                     }
174                 }
175             }
176         }
177     }
178
179     @Override
180     public void flowNodeDisconnected(InstanceIdentifier<FlowCapableNode> disconnectedNode) {
181         provider.unregistrateNode(disconnectedNode);
182     }
183
184     @Override
185     public void flowNodeConnected(InstanceIdentifier<FlowCapableNode> connectedNode) {
186         flowNodeConnected(connectedNode, false);
187     }
188
189     private void flowNodeConnected(InstanceIdentifier<FlowCapableNode> connectedNode, boolean force) {
190         if (force || !provider.isNodeActive(connectedNode)) {
191             provider.registrateNewNode(connectedNode);
192
193             if(!provider.isNodeOwner(connectedNode)) { return; }
194
195             if (provider.getConfiguration().isStaleMarkingEnabled()) {
196                 LOG.info("Stale-Marking is ENABLED and proceeding with deletion of stale-marked entities on switch {}",
197                         connectedNode.toString());
198                 reconciliationPreProcess(connectedNode);
199             }
200             reconciliation(connectedNode);
201         }
202     }
203
204     private void reconciliation(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
205
206         String sNode = nodeIdent.firstKeyOf(Node.class, NodeKey.class).getId().getValue();
207         long nDpId = getDpnIdFromNodeName(sNode);
208
209         ReadOnlyTransaction trans = provider.getReadTranaction();
210         Optional<FlowCapableNode> flowNode = Optional.absent();
211
212         AtomicInteger counter = new AtomicInteger();
213         //initialize the counter
214         counter.set(0);
215         try {
216             flowNode = trans.read(LogicalDatastoreType.CONFIGURATION, nodeIdent).get();
217         }
218         catch (Exception e) {
219             LOG.error("Fail with read Config/DS for Node {} !", nodeIdent, e);
220         }
221
222         if (flowNode.isPresent()) {
223             /* Tables - have to be pushed before groups */
224             // CHECK if while pusing the update, updateTableInput can be null to emulate a table add
225             List<TableFeatures> tableList = flowNode.get().getTableFeatures() != null
226                     ? flowNode.get().getTableFeatures() : Collections.<TableFeatures> emptyList() ;
227             for (TableFeatures tableFeaturesItem : tableList) {
228                 TableFeaturesKey tableKey = tableFeaturesItem.getKey();
229                 KeyedInstanceIdentifier<TableFeatures, TableFeaturesKey> tableFeaturesII
230                     = nodeIdent.child(TableFeatures.class, new TableFeaturesKey(tableKey.getTableId()));
231                         provider.getTableFeaturesCommiter().update(tableFeaturesII, tableFeaturesItem, null, nodeIdent);
232             }
233
234             /* Groups - have to be first */
235                 List<Group> groups = flowNode.get().getGroup() != null
236                         ? flowNode.get().getGroup() : Collections.<Group>emptyList();
237                 List<Group> toBeInstalledGroups = new ArrayList<>();
238                 toBeInstalledGroups.addAll(groups);
239                 List<Long> alreadyInstalledGroupids = new ArrayList<>();
240                 //new list for suspected groups pointing to ports .. when the ports come up late
241                 List<Group> suspectedGroups = new ArrayList<>();
242
243                 while ((!(toBeInstalledGroups.isEmpty()) || !(suspectedGroups.isEmpty())) &&
244                         (counter.get()<=provider.getConfiguration().getReconciliationRetryCount())) { //also check if the counter has not crossed the threshold
245
246                     if(toBeInstalledGroups.isEmpty() && ! suspectedGroups.isEmpty()){
247                         LOG.error("These Groups are pointing to node-connectors that are not up yet {}",suspectedGroups.toString());
248                         toBeInstalledGroups.addAll(suspectedGroups);
249                         break;
250                     }
251
252                     ListIterator<Group> iterator = toBeInstalledGroups.listIterator();
253                     while (iterator.hasNext()) {
254                         Group group = iterator.next();
255                         boolean okToInstall = true;
256                         for (Bucket bucket : group.getBuckets().getBucket()) {
257                             for (Action action : bucket.getAction()) {
258                                //chained-port
259                                 if (action.getAction().getImplementedInterface().getName()
260                                         .equals("org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase")){
261                                     String nodeConnectorUri = ((OutputActionCase)(action.getAction()))
262                                             .getOutputAction().getOutputNodeConnector().getValue();
263
264                                     LOG.warn("Installing the group for node connector {}",nodeConnectorUri);
265
266                                     //check if the nodeconnector is there in the multimap
267                                     boolean isPresent = provider.getFlowNodeConnectorInventoryTranslatorImpl()
268                                             .isNodeConnectorUpdated(nDpId, nodeConnectorUri);
269                                     //if yes set okToInstall = true
270
271                                     if(isPresent){
272                                        break;
273                                     }//else put it in a different list and still set okToInstall = true
274                                     else {
275                                         suspectedGroups.add(group);
276                                         LOG.error("Not yet received the node-connector updated for {} " +
277                                                 "for the group with id {}",nodeConnectorUri,group.getGroupId().toString());
278                                          break;
279                                     }
280
281
282                                 }
283                                 //chained groups
284                                 else if (action.getAction().getImplementedInterface().getName()
285                                         .equals("org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase")) {
286                                     Long groupId = ((GroupActionCase) (action.getAction())).getGroupAction().getGroupId();
287                                     if (!alreadyInstalledGroupids.contains(groupId)) {
288                                         okToInstall = false;
289                                         break;
290                                     }
291                                 }
292                             }
293                             if (!okToInstall){
294                                 //increment retry counter value
295                                 counter.incrementAndGet();
296                                 break;
297                             }
298
299
300
301                         }
302
303
304                         if (okToInstall) {
305                             final KeyedInstanceIdentifier<Group, GroupKey> groupIdent =
306                                     nodeIdent.child(Group.class, group.getKey());
307                             this.provider.getGroupCommiter().add(groupIdent, group, nodeIdent);
308                             alreadyInstalledGroupids.add(group.getGroupId().getValue());
309                             iterator.remove();
310                             // resetting the counter to zero
311                             counter.set(0);
312                         }
313                     }
314                 }
315
316             /* installation of suspected groups*/
317             if(!toBeInstalledGroups.isEmpty()){
318                 for(Group group :toBeInstalledGroups){
319                     LOG.error("Installing the group {} finally although the port is not up after checking for {} times "
320                             ,group.getGroupId().toString(),provider.getConfiguration().getReconciliationRetryCount());
321                     final KeyedInstanceIdentifier<Group, GroupKey> groupIdent =
322                             nodeIdent.child(Group.class, group.getKey());
323                     this.provider.getGroupCommiter().add(groupIdent, group, nodeIdent);
324                 }
325             }
326             /* Meters */
327             List<Meter> meters = flowNode.get().getMeter() != null
328                     ? flowNode.get().getMeter() : Collections.<Meter> emptyList();
329             for (Meter meter : meters) {
330                 final KeyedInstanceIdentifier<Meter, MeterKey> meterIdent =
331                         nodeIdent.child(Meter.class, meter.getKey());
332                 this.provider.getMeterCommiter().add(meterIdent, meter, nodeIdent);
333             }
334             /* Flows */
335             List<Table> tables = flowNode.get().getTable() != null
336                     ? flowNode.get().getTable() : Collections.<Table> emptyList();
337             for (Table table : tables) {
338                 final KeyedInstanceIdentifier<Table, TableKey> tableIdent =
339                         nodeIdent.child(Table.class, table.getKey());
340                 List<Flow> flows = table.getFlow() != null ? table.getFlow() : Collections.<Flow> emptyList();
341                 for (Flow flow : flows) {
342                     final KeyedInstanceIdentifier<Flow, FlowKey> flowIdent =
343                             tableIdent.child(Flow.class, flow.getKey());
344                     this.provider.getFlowCommiter().add(flowIdent, flow, nodeIdent);
345                 }
346             }
347         }
348         /* clean transaction */
349         trans.close();
350     }
351         private long getDpnIdFromNodeName(String nodeName) {
352         String dpId = nodeName.substring(nodeName.lastIndexOf(SEPARATOR) + 1);
353                 return Long.parseLong(dpId);
354         }
355
356     private void reconciliationPreProcess(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
357
358
359         List<InstanceIdentifier<StaleFlow>> staleFlowsToBeBulkDeleted = Lists.newArrayList();
360         List<InstanceIdentifier<StaleGroup>> staleGroupsToBeBulkDeleted = Lists.newArrayList();
361         List<InstanceIdentifier<StaleMeter>> staleMetersToBeBulkDeleted = Lists.newArrayList();
362
363
364         ReadOnlyTransaction trans = provider.getReadTranaction();
365         Optional<FlowCapableNode> flowNode = Optional.absent();
366
367         try {
368             flowNode = trans.read(LogicalDatastoreType.CONFIGURATION, nodeIdent).get();
369         }
370         catch (Exception e) {
371             LOG.error("Reconciliation Pre-Processing Fail with read Config/DS for Node {} !", nodeIdent, e);
372         }
373
374         if (flowNode.isPresent()) {
375
376             LOG.debug("Proceeding with deletion of stale-marked Flows on switch {} using Openflow interface",
377                     nodeIdent.toString());
378             /* Stale-Flows - Stale-marked Flows have to be removed first for safety */
379             List<Table> tables = flowNode.get().getTable() != null
380                     ? flowNode.get().getTable() : Collections.<Table> emptyList();
381             for (Table table : tables) {
382                 final KeyedInstanceIdentifier<Table, TableKey> tableIdent =
383                         nodeIdent.child(Table.class, table.getKey());
384                 List<StaleFlow> staleFlows = table.getStaleFlow() != null ? table.getStaleFlow() : Collections.<StaleFlow> emptyList();
385                 for (StaleFlow staleFlow : staleFlows) {
386
387                     FlowBuilder flowBuilder = new FlowBuilder(staleFlow);
388                     Flow toBeDeletedFlow = flowBuilder.setId(staleFlow.getId()).build();
389
390                     final KeyedInstanceIdentifier<Flow, FlowKey> flowIdent =
391                             tableIdent.child(Flow.class, toBeDeletedFlow.getKey());
392
393
394                     this.provider.getFlowCommiter().remove(flowIdent, toBeDeletedFlow, nodeIdent);
395
396                     staleFlowsToBeBulkDeleted.add(getStaleFlowInstanceIdentifier(staleFlow, nodeIdent));
397                 }
398             }
399
400
401             LOG.debug("Proceeding with deletion of stale-marked Groups for switch {} using Openflow interface",
402                     nodeIdent.toString());
403
404             // TODO: Should we collate the futures of RPC-calls to be sure that groups are Flows are fully deleted
405             // before attempting to delete groups - just in case there are references
406
407             /* Stale-marked Groups - Can be deleted after flows */
408             List<StaleGroup> staleGroups = flowNode.get().getStaleGroup() != null
409                     ? flowNode.get().getStaleGroup() : Collections.<StaleGroup> emptyList();
410             for (StaleGroup staleGroup : staleGroups) {
411
412                 GroupBuilder groupBuilder = new GroupBuilder(staleGroup);
413                 Group toBeDeletedGroup = groupBuilder.setGroupId(staleGroup.getGroupId()).build();
414
415                 final KeyedInstanceIdentifier<Group, GroupKey> groupIdent =
416                         nodeIdent.child(Group.class, toBeDeletedGroup.getKey());
417
418                 this.provider.getGroupCommiter().remove(groupIdent, toBeDeletedGroup, nodeIdent);
419
420                 staleGroupsToBeBulkDeleted.add(getStaleGroupInstanceIdentifier(staleGroup, nodeIdent));
421             }
422
423             LOG.debug("Proceeding with deletion of stale-marked Meters for switch {} using Openflow interface",
424                     nodeIdent.toString());
425             /* Stale-marked Meters - can be deleted anytime - so least priority */
426             List<StaleMeter> staleMeters = flowNode.get().getStaleMeter() != null
427                     ? flowNode.get().getStaleMeter() : Collections.<StaleMeter> emptyList();
428
429             for (StaleMeter staleMeter : staleMeters) {
430
431                 MeterBuilder meterBuilder = new MeterBuilder(staleMeter);
432                 Meter toBeDeletedMeter = meterBuilder.setMeterId(staleMeter.getMeterId()).build();
433
434                 final KeyedInstanceIdentifier<Meter, MeterKey> meterIdent =
435                         nodeIdent.child(Meter.class, toBeDeletedMeter.getKey());
436
437
438                 this.provider.getMeterCommiter().remove(meterIdent, toBeDeletedMeter, nodeIdent);
439
440                 staleMetersToBeBulkDeleted.add(getStaleMeterInstanceIdentifier(staleMeter, nodeIdent));
441             }
442
443         }
444         /* clean transaction */
445         trans.close();
446
447         LOG.debug("Deleting all stale-marked flows/groups/meters of for switch {} in Configuration DS",
448                 nodeIdent.toString());
449                 // Now, do the bulk deletions
450                 deleteDSStaleFlows(staleFlowsToBeBulkDeleted);
451         deleteDSStaleGroups(staleGroupsToBeBulkDeleted);
452         deleteDSStaleMeters(staleMetersToBeBulkDeleted);
453
454     }
455
456
457     private void deleteDSStaleFlows(List<InstanceIdentifier<StaleFlow>> flowsForBulkDelete){
458         ImmutableList.Builder<InstanceIdentifier<StaleFlow>> builder = ImmutableList.builder();
459         ImmutableList<InstanceIdentifier<StaleFlow>> bulkDelFlows = builder.addAll(flowsForBulkDelete.iterator()).build();
460
461         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
462
463         for (InstanceIdentifier<StaleFlow> staleFlowIId : flowsForBulkDelete){
464             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, staleFlowIId);
465         }
466
467         CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTransaction.submit();
468         handleStaleEntityDeletionResultFuture(submitFuture);
469     }
470
471     private void deleteDSStaleGroups(List<InstanceIdentifier<StaleGroup>> groupsForBulkDelete){
472         ImmutableList.Builder<InstanceIdentifier<StaleGroup>> builder = ImmutableList.builder();
473         ImmutableList<InstanceIdentifier<StaleGroup>> bulkDelGroups = builder.addAll(groupsForBulkDelete.iterator()).build();
474
475         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
476
477         for (InstanceIdentifier<StaleGroup> staleGroupIId : groupsForBulkDelete){
478             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, staleGroupIId);
479         }
480
481         CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTransaction.submit();
482         handleStaleEntityDeletionResultFuture(submitFuture);
483
484     }
485
486     private void deleteDSStaleMeters(List<InstanceIdentifier<StaleMeter>> metersForBulkDelete){
487         ImmutableList.Builder<InstanceIdentifier<StaleMeter>> builder = ImmutableList.builder();
488         ImmutableList<InstanceIdentifier<StaleMeter>> bulkDelGroups = builder.addAll(metersForBulkDelete.iterator()).build();
489
490         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
491
492         for (InstanceIdentifier<StaleMeter> staleMeterIId : metersForBulkDelete){
493             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, staleMeterIId);
494         }
495
496         CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTransaction.submit();
497         handleStaleEntityDeletionResultFuture(submitFuture);
498
499
500     }
501
502
503     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.StaleFlow> getStaleFlowInstanceIdentifier(StaleFlow staleFlow, InstanceIdentifier<FlowCapableNode> nodeIdent) {
504         return nodeIdent
505                 .child(Table.class, new TableKey(staleFlow.getTableId()))
506                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.StaleFlow.class,
507                         new StaleFlowKey(new FlowId(staleFlow.getId())));
508     }
509
510     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.StaleGroup> getStaleGroupInstanceIdentifier(StaleGroup staleGroup, InstanceIdentifier<FlowCapableNode> nodeIdent) {
511         return nodeIdent
512                 .child(StaleGroup.class, new StaleGroupKey(new GroupId(staleGroup.getGroupId())));
513     }
514
515
516     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.StaleMeter> getStaleMeterInstanceIdentifier(StaleMeter staleMeter, InstanceIdentifier<FlowCapableNode> nodeIdent) {
517         return nodeIdent
518                 .child(StaleMeter.class, new StaleMeterKey(new MeterId(staleMeter.getMeterId())));
519     }
520
521
522     private void handleStaleEntityDeletionResultFuture(CheckedFuture<Void, TransactionCommitFailedException> submitFuture) {
523         Futures.addCallback(submitFuture, new FutureCallback<Void>() {
524             @Override
525             public void onSuccess(Void result) { LOG.debug("Stale entity removal success");
526             }
527
528             @Override
529             public void onFailure(Throwable t) {
530                 LOG.error("Stale entity removal failed {}", t);
531             }
532         });
533
534     }
535
536
537
538
539
540 }
541