2 * Copyright IBM Corporation, 2013. All rights reserved.
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
8 package org.opendaylight.controller.md.statistics.manager;
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
14 import java.util.Map.Entry;
15 import java.util.concurrent.TimeUnit;
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;
97 import com.google.common.base.Preconditions;
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
105 public class NodeStatisticsAger {
106 private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsAger.class);
107 private static final int NUMBER_OF_WAIT_CYCLES = 2;
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;
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();
124 public class FlowEntry {
125 private final Short tableId;
126 private final Flow flow;
128 public FlowEntry(Short tableId, Flow flow){
129 this.tableId = tableId;
133 public Short getTableId() {
137 public Flow getFlow() {
142 public int hashCode() {
143 final int prime = 31;
145 result = prime * result + getOuterType().hashCode();
146 result = prime * result + ((flow == null) ? 0 : flow.hashCode());
147 result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
152 public boolean equals(Object obj) {
157 if (getClass() != obj.getClass())
159 FlowEntry other = (FlowEntry) obj;
160 if (!getOuterType().equals(other.getOuterType()))
163 if (other.flow != null)
165 } else if (!flow.equals(other.flow))
167 if (tableId == null) {
168 if (other.tableId != null)
170 } else if (!tableId.equals(other.tableId))
175 private NodeStatisticsAger getOuterType() {
176 return NodeStatisticsAger.this;
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;
187 public NodeConnectorId getNodeConnectorId() {
188 return nodeConnectorId;
190 public QueueId getQueueId() {
194 public int hashCode() {
195 final int prime = 31;
197 result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
198 result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
202 public boolean equals(Object obj) {
209 if (!(obj instanceof QueueEntry)) {
212 QueueEntry other = (QueueEntry) obj;
213 if (nodeConnectorId == null) {
214 if (other.nodeConnectorId != null) {
217 } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
220 if (queueId == null) {
221 if (other.queueId != null) {
224 } else if (!queueId.equals(other.queueId)) {
231 public NodeKey getTargetNodeKey() {
232 return targetNodeKey;
235 public synchronized void updateGroupDescStats(List<GroupDescStats> list){
236 final Long expiryTime = getExpiryTime();
237 final DataModificationTransaction trans = statisticsProvider.startChange();
239 for (GroupDescStats groupDescStats : list) {
240 GroupBuilder groupBuilder = new GroupBuilder();
241 GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
242 groupBuilder.setKey(groupKey);
244 InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
245 .augmentation(FlowCapableNode.class)
246 .child(Group.class,groupKey).toInstance();
248 NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
249 GroupDescBuilder stats = new GroupDescBuilder();
250 stats.fieldsFrom(groupDescStats);
251 groupDesc.setGroupDesc(stats.build());
253 //Update augmented data
254 groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
256 trans.putOperationalData(groupRef, groupBuilder.build());
257 this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
264 public synchronized void updateGroupStats(List<GroupStats> list) {
265 final DataModificationTransaction trans = statisticsProvider.startChange();
267 for(GroupStats groupStats : list) {
268 GroupBuilder groupBuilder = new GroupBuilder();
269 GroupKey groupKey = new GroupKey(groupStats.getGroupId());
270 groupBuilder.setKey(groupKey);
272 InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
273 .augmentation(FlowCapableNode.class)
274 .child(Group.class,groupKey).toInstance();
276 NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
277 GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
278 stats.fieldsFrom(groupStats);
279 groupStatisticsBuilder.setGroupStatistics(stats.build());
281 //Update augmented data
282 groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
283 trans.putOperationalData(groupRef, groupBuilder.build());
285 // FIXME: should we be tracking this data?
291 public synchronized void updateMeterConfigStats(List<MeterConfigStats> list) {
292 final Long expiryTime = getExpiryTime();
293 final DataModificationTransaction trans = statisticsProvider.startChange();
295 for(MeterConfigStats meterConfigStats : list) {
296 MeterBuilder meterBuilder = new MeterBuilder();
297 MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
298 meterBuilder.setKey(meterKey);
300 InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
301 .augmentation(FlowCapableNode.class)
302 .child(Meter.class,meterKey).toInstance();
304 NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
305 MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
306 stats.fieldsFrom(meterConfigStats);
307 meterConfig.setMeterConfigStats(stats.build());
309 //Update augmented data
310 meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
312 trans.putOperationalData(meterRef, meterBuilder.build());
313 this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
320 public synchronized void updateMeterStats(List<MeterStats> list) {
321 final DataModificationTransaction trans = statisticsProvider.startChange();
323 for(MeterStats meterStats : list) {
324 MeterBuilder meterBuilder = new MeterBuilder();
325 MeterKey meterKey = new MeterKey(meterStats.getMeterId());
326 meterBuilder.setKey(meterKey);
328 InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
329 .augmentation(FlowCapableNode.class)
330 .child(Meter.class,meterKey).toInstance();
332 NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
333 MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
334 stats.fieldsFrom(meterStats);
335 meterStatsBuilder.setMeterStatistics(stats.build());
337 //Update augmented data
338 meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
339 trans.putOperationalData(meterRef, meterBuilder.build());
341 // FIXME: should we be tracking this data?
347 public synchronized void updateQueueStats(List<QueueIdAndStatisticsMap> list) {
348 final Long expiryTime = getExpiryTime();
349 final DataModificationTransaction trans = statisticsProvider.startChange();
351 for (QueueIdAndStatisticsMap swQueueStats : list) {
353 QueueEntry queueEntry = new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
355 FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
357 FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
359 queueStatisticsBuilder.fieldsFrom(swQueueStats);
361 queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
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();
370 QueueBuilder queueBuilder = new QueueBuilder();
371 FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
372 queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
373 queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
375 logger.debug("Augmenting queue statistics {} of queue {} to port {}",
377 swQueueStats.getQueueId(),
378 swQueueStats.getNodeConnectorId());
380 trans.putOperationalData(queueRef, queueBuilder.build());
381 this.queuesStatsUpdate.put(queueEntry, expiryTime);
387 public synchronized void updateFlowTableStats(List<FlowTableAndStatisticsMap> list) {
388 final DataModificationTransaction trans = statisticsProvider.startChange();
390 for (FlowTableAndStatisticsMap ftStats : list) {
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();
395 FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
397 FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
398 statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
399 statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
400 statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
402 final FlowTableStatistics stats = statisticsBuilder.build();
403 statisticsDataBuilder.setFlowTableStatistics(stats);
405 logger.debug("Augment flow table statistics: {} for table {} on Node {}",
406 stats,ftStats.getTableId(), targetNodeKey);
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());
413 // FIXME: should we be tracking this data?
419 public synchronized void updateNodeConnectorStats(List<NodeConnectorStatisticsAndPortNumberMap> list) {
420 final DataModificationTransaction trans = statisticsProvider.startChange();
422 for(NodeConnectorStatisticsAndPortNumberMap portStats : list) {
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());
438 //Augment data to the node-connector
439 FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
440 new FlowCapableNodeConnectorStatisticsDataBuilder();
442 statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
444 InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class)
445 .child(Node.class, targetNodeKey)
446 .child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
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());
458 // FIXME: should we be tracking this data?
464 public synchronized void updateAggregateFlowStats(Short tableId, AggregateFlowStatistics flowStats) {
465 if (tableId != null) {
466 final DataModificationTransaction trans = statisticsProvider.startChange();
469 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
470 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
472 AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
473 AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
475 aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
477 logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
478 aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
480 TableBuilder tableBuilder = new TableBuilder();
481 tableBuilder.setKey(new TableKey(tableId));
482 tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
483 trans.putOperationalData(tableRef, tableBuilder.build());
485 // FIXME: should we be tracking this data?
490 public synchronized void updateGroupFeatures(GroupFeatures notification) {
491 final DataModificationTransaction trans = statisticsProvider.startChange();
493 final NodeBuilder nodeData = new NodeBuilder();
494 nodeData.setKey(targetNodeKey);
496 NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
497 GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
498 nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
500 //Update augmented data
501 nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
502 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
504 // FIXME: should we be tracking this data?
508 public synchronized void updateMeterFeatures(MeterFeatures features) {
509 final DataModificationTransaction trans = statisticsProvider.startChange();
511 final NodeBuilder nodeData = new NodeBuilder();
512 nodeData.setKey(targetNodeKey);
514 NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
515 MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
516 nodeMeterFeatures.setMeterFeatures(meterFeature.build());
518 //Update augmented data
519 nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
520 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
522 // FIXME: should we be tracking this data?
526 public synchronized void updateFlowStats(List<FlowAndStatisticsMapList> list) {
527 final Long expiryTime = getExpiryTime();
528 final DataModificationTransaction trans = statisticsProvider.startChange();
530 for(FlowAndStatisticsMapList map : list) {
531 short tableId = map.getTableId();
532 boolean foundOriginalFlow = false;
534 FlowBuilder flowBuilder = new FlowBuilder();
536 FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
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);
560 Flow flowRule = flow.build();
562 FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
563 stats.setByteCount(map.getByteCount());
564 stats.setPacketCount(map.getPacketCount());
565 stats.setDuration(map.getDuration());
567 GenericStatistics flowStats = stats.build();
569 //Augment the data to the flow node
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);
592 flowStatisticsData.setFlowStatistics(flowStatistics.build());
594 logger.debug("Flow : {}",flowRule.toString());
595 logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
597 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
598 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
600 Table table= (Table)trans.readConfigurationData(tableRef);
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
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);
624 trans.putOperationalData(flowRef, flowBuilder.build());
629 table = (Table)trans.readOperationalData(tableRef);
630 if(!foundOriginalFlow && table != null){
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;
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());
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());
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());
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);
687 public synchronized void cleanStaleStatistics(){
688 final DataModificationTransaction trans = this.statisticsProvider.startChange();
689 final long now = System.nanoTime();
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());
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());
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());
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());
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);
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);
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()));
757 InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance();
758 trans.removeOperationalData(nodeMeterConfigStatsAugmentation);
760 InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
761 trans.removeOperationalData(nodeMeterStatisticsAugmentation);
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()));
770 InstanceIdentifier<?> nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance();
771 trans.removeOperationalData(nodeGroupDescStatsAugmentation);
773 InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
774 trans.removeOperationalData(nodeGroupStatisticsAugmentation);