Move flow statistics update handling
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / NodeStatisticsAger.java
1 /*
2  * Copyright IBM Corporation, 2013.  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 package org.opendaylight.controller.md.statistics.manager;
9
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.concurrent.TimeUnit;
16
17 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
92 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
93 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
96
97 import com.google.common.base.Preconditions;
98
99 /**
100  * Main responsibility of this class to clean up all the stale statistics data
101  * associated to Flow,Meter,Group,Queue.
102  * @author avishnoi@in.ibm.com
103  *
104  */
105 public class NodeStatisticsAger {
106     private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsAger.class);
107     private static final int NUMBER_OF_WAIT_CYCLES = 2;
108
109     private final Map<GroupDescStats,Long> groupDescStatsUpdate = new HashMap<>();
110     private final Map<MeterConfigStats,Long> meterConfigStatsUpdate = new HashMap<>();
111     private final Map<FlowEntry,Long> flowStatsUpdate = new HashMap<>();
112     private final Map<QueueEntry,Long> queuesStatsUpdate = new HashMap<>();
113     private final InstanceIdentifier<Node> targetNodeIdentifier;
114     private final StatisticsProvider statisticsProvider;
115     private final NodeKey targetNodeKey;
116     private int unaccountedFlowsCounter = 1;
117
118     public NodeStatisticsAger(StatisticsProvider statisticsProvider, NodeKey nodeKey){
119         this.statisticsProvider = Preconditions.checkNotNull(statisticsProvider);
120         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
121         this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
122     }
123
124     public class FlowEntry {
125         private final Short tableId;
126         private final Flow flow;
127
128         public FlowEntry(Short tableId, Flow flow){
129             this.tableId = tableId;
130             this.flow = flow;
131         }
132
133         public Short getTableId() {
134             return tableId;
135         }
136
137         public Flow getFlow() {
138             return flow;
139         }
140
141         @Override
142         public int hashCode() {
143             final int prime = 31;
144             int result = 1;
145             result = prime * result + getOuterType().hashCode();
146             result = prime * result + ((flow == null) ? 0 : flow.hashCode());
147             result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
148             return result;
149         }
150
151         @Override
152         public boolean equals(Object obj) {
153             if (this == obj)
154                 return true;
155             if (obj == null)
156                 return false;
157             if (getClass() != obj.getClass())
158                 return false;
159             FlowEntry other = (FlowEntry) obj;
160             if (!getOuterType().equals(other.getOuterType()))
161                 return false;
162             if (flow == null) {
163                 if (other.flow != null)
164                     return false;
165             } else if (!flow.equals(other.flow))
166                 return false;
167             if (tableId == null) {
168                 if (other.tableId != null)
169                     return false;
170             } else if (!tableId.equals(other.tableId))
171                 return false;
172             return true;
173         }
174
175         private NodeStatisticsAger getOuterType() {
176             return NodeStatisticsAger.this;
177         }
178     }
179
180     private static final class QueueEntry{
181         private final NodeConnectorId nodeConnectorId;
182         private final QueueId queueId;
183         public QueueEntry(NodeConnectorId ncId, QueueId queueId){
184             this.nodeConnectorId = ncId;
185             this.queueId = queueId;
186         }
187         public NodeConnectorId getNodeConnectorId() {
188             return nodeConnectorId;
189         }
190         public QueueId getQueueId() {
191             return queueId;
192         }
193         @Override
194         public int hashCode() {
195             final int prime = 31;
196             int result = 1;
197             result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
198             result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
199             return result;
200         }
201         @Override
202         public boolean equals(Object obj) {
203             if (this == obj) {
204                 return true;
205             }
206             if (obj == null) {
207                 return false;
208             }
209             if (!(obj instanceof QueueEntry)) {
210                 return false;
211             }
212             QueueEntry other = (QueueEntry) obj;
213             if (nodeConnectorId == null) {
214                 if (other.nodeConnectorId != null) {
215                     return false;
216                 }
217             } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
218                 return false;
219             }
220             if (queueId == null) {
221                 if (other.queueId != null) {
222                     return false;
223                 }
224             } else if (!queueId.equals(other.queueId)) {
225                 return false;
226             }
227             return true;
228         }
229     }
230
231     public NodeKey getTargetNodeKey() {
232         return targetNodeKey;
233     }
234
235     public synchronized void updateGroupDescStats(List<GroupDescStats> list){
236         final Long expiryTime = getExpiryTime();
237         final DataModificationTransaction trans = statisticsProvider.startChange();
238
239         for (GroupDescStats groupDescStats : list) {
240             GroupBuilder groupBuilder = new GroupBuilder();
241             GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
242             groupBuilder.setKey(groupKey);
243
244             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
245                                                                                         .augmentation(FlowCapableNode.class)
246                                                                                         .child(Group.class,groupKey).toInstance();
247
248             NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
249             GroupDescBuilder stats = new GroupDescBuilder();
250             stats.fieldsFrom(groupDescStats);
251             groupDesc.setGroupDesc(stats.build());
252
253             //Update augmented data
254             groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
255
256             trans.putOperationalData(groupRef, groupBuilder.build());
257             this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
258         }
259
260         trans.commit();
261     }
262
263
264     public synchronized void updateGroupStats(List<GroupStats> list) {
265         final DataModificationTransaction trans = statisticsProvider.startChange();
266
267         for(GroupStats groupStats : list) {
268             GroupBuilder groupBuilder = new GroupBuilder();
269             GroupKey groupKey = new GroupKey(groupStats.getGroupId());
270             groupBuilder.setKey(groupKey);
271
272             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
273                                                                                         .augmentation(FlowCapableNode.class)
274                                                                                         .child(Group.class,groupKey).toInstance();
275
276             NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
277             GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
278             stats.fieldsFrom(groupStats);
279             groupStatisticsBuilder.setGroupStatistics(stats.build());
280
281             //Update augmented data
282             groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
283             trans.putOperationalData(groupRef, groupBuilder.build());
284
285             // FIXME: should we be tracking this data?
286         }
287
288         trans.commit();
289     }
290
291     public synchronized void updateMeterConfigStats(List<MeterConfigStats> list) {
292         final Long expiryTime = getExpiryTime();
293         final DataModificationTransaction trans = statisticsProvider.startChange();
294
295         for(MeterConfigStats meterConfigStats : list) {
296             MeterBuilder meterBuilder = new MeterBuilder();
297             MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
298             meterBuilder.setKey(meterKey);
299
300             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
301                                                                                         .augmentation(FlowCapableNode.class)
302                                                                                         .child(Meter.class,meterKey).toInstance();
303
304             NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
305             MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
306             stats.fieldsFrom(meterConfigStats);
307             meterConfig.setMeterConfigStats(stats.build());
308
309             //Update augmented data
310             meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
311
312             trans.putOperationalData(meterRef, meterBuilder.build());
313             this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
314         }
315
316         trans.commit();
317     }
318
319
320     public synchronized void updateMeterStats(List<MeterStats> list) {
321         final DataModificationTransaction trans = statisticsProvider.startChange();
322
323         for(MeterStats meterStats : list) {
324             MeterBuilder meterBuilder = new MeterBuilder();
325             MeterKey meterKey = new MeterKey(meterStats.getMeterId());
326             meterBuilder.setKey(meterKey);
327
328             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
329                                                                                         .augmentation(FlowCapableNode.class)
330                                                                                         .child(Meter.class,meterKey).toInstance();
331
332             NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
333             MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
334             stats.fieldsFrom(meterStats);
335             meterStatsBuilder.setMeterStatistics(stats.build());
336
337             //Update augmented data
338             meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
339             trans.putOperationalData(meterRef, meterBuilder.build());
340
341             // FIXME: should we be tracking this data?
342         }
343
344         trans.commit();
345     }
346
347     public synchronized void updateQueueStats(List<QueueIdAndStatisticsMap> list) {
348         final Long expiryTime = getExpiryTime();
349         final DataModificationTransaction trans = statisticsProvider.startChange();
350
351         for (QueueIdAndStatisticsMap swQueueStats : list) {
352
353             QueueEntry queueEntry = new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
354
355             FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
356
357             FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
358
359             queueStatisticsBuilder.fieldsFrom(swQueueStats);
360
361             queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
362
363             InstanceIdentifier<Queue> queueRef
364                     = InstanceIdentifier.builder(Nodes.class)
365                                         .child(Node.class, targetNodeKey)
366                                         .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
367                                         .augmentation(FlowCapableNodeConnector.class)
368                                         .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
369
370             QueueBuilder queueBuilder = new QueueBuilder();
371             FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
372             queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
373             queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
374
375             logger.debug("Augmenting queue statistics {} of queue {} to port {}",
376                                         qsd,
377                                         swQueueStats.getQueueId(),
378                                         swQueueStats.getNodeConnectorId());
379
380             trans.putOperationalData(queueRef, queueBuilder.build());
381             this.queuesStatsUpdate.put(queueEntry, expiryTime);
382         }
383
384         trans.commit();
385     }
386
387     public synchronized void updateFlowTableStats(List<FlowTableAndStatisticsMap> list) {
388         final DataModificationTransaction trans = statisticsProvider.startChange();
389
390         for (FlowTableAndStatisticsMap ftStats : list) {
391
392             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
393                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
394
395             FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
396
397             FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
398             statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
399             statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
400             statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
401
402             final FlowTableStatistics stats = statisticsBuilder.build();
403             statisticsDataBuilder.setFlowTableStatistics(stats);
404
405             logger.debug("Augment flow table statistics: {} for table {} on Node {}",
406                     stats,ftStats.getTableId(), targetNodeKey);
407
408             TableBuilder tableBuilder = new TableBuilder();
409             tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
410             tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
411             trans.putOperationalData(tableRef, tableBuilder.build());
412
413             // FIXME: should we be tracking this data?
414         }
415
416         trans.commit();
417     }
418
419     public synchronized void updateNodeConnectorStats(List<NodeConnectorStatisticsAndPortNumberMap> list) {
420         final DataModificationTransaction trans = statisticsProvider.startChange();
421
422         for(NodeConnectorStatisticsAndPortNumberMap portStats : list) {
423
424             FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
425                                             = new FlowCapableNodeConnectorStatisticsBuilder();
426             statisticsBuilder.setBytes(portStats.getBytes());
427             statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
428             statisticsBuilder.setDuration(portStats.getDuration());
429             statisticsBuilder.setPackets(portStats.getPackets());
430             statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
431             statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
432             statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
433             statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
434             statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
435             statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
436             statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
437
438             //Augment data to the node-connector
439             FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
440                     new FlowCapableNodeConnectorStatisticsDataBuilder();
441
442             statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
443
444             InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class)
445                     .child(Node.class, targetNodeKey)
446                     .child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
447
448             // FIXME: can we bypass this read?
449             NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef);
450             if(nodeConnector != null){
451                 final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build();
452                 logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString());
453                 NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
454                 nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
455                 trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
456             }
457
458             // FIXME: should we be tracking this data?
459         }
460
461         trans.commit();
462     }
463
464     public synchronized void updateAggregateFlowStats(Short tableId, AggregateFlowStatistics flowStats) {
465         if (tableId != null) {
466             final DataModificationTransaction trans = statisticsProvider.startChange();
467
468
469             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
470                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
471
472             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
473             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
474
475             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
476
477             logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
478                     aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
479
480             TableBuilder tableBuilder = new TableBuilder();
481             tableBuilder.setKey(new TableKey(tableId));
482             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
483             trans.putOperationalData(tableRef, tableBuilder.build());
484
485             // FIXME: should we be tracking this data?
486             trans.commit();
487         }
488     }
489
490     public synchronized void updateGroupFeatures(GroupFeatures notification) {
491         final DataModificationTransaction trans = statisticsProvider.startChange();
492
493         final NodeBuilder nodeData = new NodeBuilder();
494         nodeData.setKey(targetNodeKey);
495
496         NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
497         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
498         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
499
500         //Update augmented data
501         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
502         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
503
504         // FIXME: should we be tracking this data?
505         trans.commit();
506     }
507
508     public synchronized void updateMeterFeatures(MeterFeatures features) {
509         final DataModificationTransaction trans = statisticsProvider.startChange();
510
511         final NodeBuilder nodeData = new NodeBuilder();
512         nodeData.setKey(targetNodeKey);
513
514         NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
515         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
516         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
517
518         //Update augmented data
519         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
520         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
521
522         // FIXME: should we be tracking this data?
523         trans.commit();
524     }
525
526     public synchronized void updateFlowStats(List<FlowAndStatisticsMapList> list) {
527         final Long expiryTime = getExpiryTime();
528         final DataModificationTransaction trans = statisticsProvider.startChange();
529
530         for(FlowAndStatisticsMapList map : list) {
531             short tableId = map.getTableId();
532             boolean foundOriginalFlow = false;
533
534             FlowBuilder flowBuilder = new FlowBuilder();
535
536             FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
537
538             FlowBuilder flow = new FlowBuilder();
539             flow.setContainerName(map.getContainerName());
540             flow.setBufferId(map.getBufferId());
541             flow.setCookie(map.getCookie());
542             flow.setCookieMask(map.getCookieMask());
543             flow.setFlags(map.getFlags());
544             flow.setFlowName(map.getFlowName());
545             flow.setHardTimeout(map.getHardTimeout());
546             if(map.getFlowId() != null)
547                 flow.setId(new FlowId(map.getFlowId().getValue()));
548             flow.setIdleTimeout(map.getIdleTimeout());
549             flow.setInstallHw(map.isInstallHw());
550             flow.setInstructions(map.getInstructions());
551             if(map.getFlowId()!= null)
552                 flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
553             flow.setMatch(map.getMatch());
554             flow.setOutGroup(map.getOutGroup());
555             flow.setOutPort(map.getOutPort());
556             flow.setPriority(map.getPriority());
557             flow.setStrict(map.isStrict());
558             flow.setTableId(tableId);
559
560             Flow flowRule = flow.build();
561
562             FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
563             stats.setByteCount(map.getByteCount());
564             stats.setPacketCount(map.getPacketCount());
565             stats.setDuration(map.getDuration());
566
567             GenericStatistics flowStats = stats.build();
568
569             //Augment the data to the flow node
570
571             FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
572             flowStatistics.setByteCount(flowStats.getByteCount());
573             flowStatistics.setPacketCount(flowStats.getPacketCount());
574             flowStatistics.setDuration(flowStats.getDuration());
575             flowStatistics.setContainerName(map.getContainerName());
576             flowStatistics.setBufferId(map.getBufferId());
577             flowStatistics.setCookie(map.getCookie());
578             flowStatistics.setCookieMask(map.getCookieMask());
579             flowStatistics.setFlags(map.getFlags());
580             flowStatistics.setFlowName(map.getFlowName());
581             flowStatistics.setHardTimeout(map.getHardTimeout());
582             flowStatistics.setIdleTimeout(map.getIdleTimeout());
583             flowStatistics.setInstallHw(map.isInstallHw());
584             flowStatistics.setInstructions(map.getInstructions());
585             flowStatistics.setMatch(map.getMatch());
586             flowStatistics.setOutGroup(map.getOutGroup());
587             flowStatistics.setOutPort(map.getOutPort());
588             flowStatistics.setPriority(map.getPriority());
589             flowStatistics.setStrict(map.isStrict());
590             flowStatistics.setTableId(tableId);
591
592             flowStatisticsData.setFlowStatistics(flowStatistics.build());
593
594             logger.debug("Flow : {}",flowRule.toString());
595             logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
596
597             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
598                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
599
600             Table table= (Table)trans.readConfigurationData(tableRef);
601
602             //TODO: Not a good way to do it, need to figure out better way.
603             //TODO: major issue in any alternate approach is that flow key is incrementally assigned
604             //to the flows stored in data store.
605             // Augment same statistics to all the matching masked flow
606             if(table != null){
607
608                 for(Flow existingFlow : table.getFlow()){
609                     logger.debug("Existing flow in data store : {}",existingFlow.toString());
610                     if(FlowComparator.flowEquals(flowRule,existingFlow)){
611                         InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
612                                 .augmentation(FlowCapableNode.class)
613                                 .child(Table.class, new TableKey(tableId))
614                                 .child(Flow.class,existingFlow.getKey()).toInstance();
615                         flowBuilder.setKey(existingFlow.getKey());
616                         flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
617                         logger.debug("Found matching flow in the datastore, augmenting statistics");
618                         foundOriginalFlow = true;
619                         // Update entry with timestamp of latest response
620                         flow.setKey(existingFlow.getKey());
621                         FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
622                         flowStatsUpdate.put(flowStatsEntry, expiryTime);
623
624                         trans.putOperationalData(flowRef, flowBuilder.build());
625                     }
626                 }
627             }
628
629             table = (Table)trans.readOperationalData(tableRef);
630             if(!foundOriginalFlow && table != null){
631
632                 for(Flow existingFlow : table.getFlow()){
633                     FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
634                     if(augmentedflowStatisticsData != null){
635                         FlowBuilder existingOperationalFlow = new FlowBuilder();
636                         existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
637                         logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
638                         if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
639                             InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
640                                     .augmentation(FlowCapableNode.class)
641                                     .child(Table.class, new TableKey(tableId))
642                                     .child(Flow.class,existingFlow.getKey()).toInstance();
643                             flowBuilder.setKey(existingFlow.getKey());
644                             flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
645                             logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
646                             foundOriginalFlow = true;
647
648                             // Update entry with timestamp of latest response
649                             flow.setKey(existingFlow.getKey());
650                             FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
651                             flowStatsUpdate.put(flowStatsEntry, expiryTime);
652                             trans.putOperationalData(flowRef, flowBuilder.build());
653                             break;
654                         }
655                     }
656                 }
657             }
658             if(!foundOriginalFlow){
659                 String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
660                 this.unaccountedFlowsCounter++;
661                 FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
662                 InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
663                         .augmentation(FlowCapableNode.class)
664                         .child(Table.class, new TableKey(tableId))
665                         .child(Flow.class,newFlowKey).toInstance();
666                 flowBuilder.setKey(newFlowKey);
667                 flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
668                 logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
669                         flowBuilder.build());
670
671                 // Update entry with timestamp of latest response
672                 flow.setKey(newFlowKey);
673                 FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
674                 flowStatsUpdate.put(flowStatsEntry, expiryTime);
675                 trans.putOperationalData(flowRef, flowBuilder.build());
676             }
677         }
678
679         trans.commit();
680     }
681
682     private static Long getExpiryTime(){
683         final long now = System.nanoTime();
684         return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_THREAD_EXECUTION_TIME * NUMBER_OF_WAIT_CYCLES);
685     }
686
687     public synchronized void cleanStaleStatistics(){
688         final DataModificationTransaction trans = this.statisticsProvider.startChange();
689         final long now = System.nanoTime();
690
691         //Clean stale statistics related to group
692         for (Iterator<Entry<GroupDescStats, Long>> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){
693             Entry<GroupDescStats, Long> e = it.next();
694             if (now > e.getValue()) {
695                 cleanGroupStatsFromDataStore(trans, e.getKey());
696                 it.remove();
697             }
698         }
699
700         //Clean stale statistics related to meter
701         for (Iterator<Entry<MeterConfigStats, Long>> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){
702             Entry<MeterConfigStats, Long> e = it.next();
703             if (now > e.getValue()) {
704                 cleanMeterStatsFromDataStore(trans, e.getKey());
705                 it.remove();
706             }
707         }
708
709         //Clean stale statistics related to flow
710         for (Iterator<Entry<FlowEntry, Long>> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){
711             Entry<FlowEntry, Long> e = it.next();
712             if (now > e.getValue()) {
713                 cleanFlowStatsFromDataStore(trans, e.getKey());
714                 it.remove();
715             }
716         }
717
718         //Clean stale statistics related to queue
719         for (Iterator<Entry<QueueEntry, Long>> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){
720             Entry<QueueEntry, Long> e = it.next();
721             if (now > e.getValue()) {
722                 cleanQueueStatsFromDataStore(trans, e.getKey());
723                 it.remove();
724             }
725         }
726
727         trans.commit();
728     }
729
730     private void cleanQueueStatsFromDataStore(DataModificationTransaction trans, QueueEntry queueEntry) {
731         InstanceIdentifier<?> queueRef
732                         = InstanceIdentifier.builder(Nodes.class)
733                                             .child(Node.class, this.targetNodeKey)
734                                             .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId()))
735                                             .augmentation(FlowCapableNodeConnector.class)
736                                             .child(Queue.class, new QueueKey(queueEntry.getQueueId()))
737                                             .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
738         trans.removeOperationalData(queueRef);
739     }
740
741     private void cleanFlowStatsFromDataStore(DataModificationTransaction trans, FlowEntry flowEntry) {
742         InstanceIdentifier<?> flowRef
743                         = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey)
744                                             .augmentation(FlowCapableNode.class)
745                                             .child(Table.class, new TableKey(flowEntry.getTableId()))
746                                             .child(Flow.class,flowEntry.getFlow().getKey())
747                                             .augmentation(FlowStatisticsData.class).toInstance();
748         trans.removeOperationalData(flowRef);
749     }
750
751     private void cleanMeterStatsFromDataStore(DataModificationTransaction trans, MeterConfigStats meterConfigStats) {
752         InstanceIdentifierBuilder<Meter> meterRef
753                         = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
754                                             .augmentation(FlowCapableNode.class)
755                                             .child(Meter.class,new MeterKey(meterConfigStats.getMeterId()));
756
757         InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance();
758         trans.removeOperationalData(nodeMeterConfigStatsAugmentation);
759
760         InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
761         trans.removeOperationalData(nodeMeterStatisticsAugmentation);
762     }
763
764     private void cleanGroupStatsFromDataStore(DataModificationTransaction trans, GroupDescStats groupDescStats) {
765         InstanceIdentifierBuilder<Group> groupRef
766                         = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
767                                             .augmentation(FlowCapableNode.class)
768                                             .child(Group.class,new GroupKey(groupDescStats.getGroupId()));
769
770         InstanceIdentifier<?> nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance();
771         trans.removeOperationalData(nodeGroupDescStatsAugmentation);
772
773         InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
774         trans.removeOperationalData(nodeGroupStatisticsAugmentation);
775     }
776 }