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.Collection;
11 import java.util.List;
12 import java.util.concurrent.TimeUnit;
14 import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType;
15 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
16 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 import com.google.common.base.Preconditions;
59 import com.google.common.util.concurrent.FutureCallback;
60 import com.google.common.util.concurrent.Futures;
61 import com.google.common.util.concurrent.ListenableFuture;
64 * This class handles the lifecycle of per-node statistics. It receives data
65 * from StatisticsListener, stores it in the data store and keeps track of
66 * when the data should be removed.
68 * @author avishnoi@in.ibm.com
70 public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
71 private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
72 private static final int NUMBER_OF_WAIT_CYCLES = 2;
74 private final MultipartMessageManager msgManager = new MultipartMessageManager();
75 private final InstanceIdentifier<Node> targetNodeIdentifier;
76 private final FlowStatsTracker flowStats;
77 private final FlowTableStatsTracker flowTableStats;
78 private final GroupDescStatsTracker groupDescStats;
79 private final GroupStatsTracker groupStats;
80 private final MeterConfigStatsTracker meterConfigStats;
81 private final MeterStatsTracker meterStats;
82 private final NodeConnectorStatsTracker nodeConnectorStats;
83 private final QueueStatsTracker queueStats;
84 private final DataProviderService dps;
85 private final NodeRef targetNodeRef;
86 private final NodeKey targetNodeKey;
88 public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
89 final OpendaylightFlowStatisticsService flowStatsService,
90 final OpendaylightFlowTableStatisticsService flowTableStatsService,
91 final OpendaylightGroupStatisticsService groupStatsService,
92 final OpendaylightMeterStatisticsService meterStatsService,
93 final OpendaylightPortStatisticsService portStatsService,
94 final OpendaylightQueueStatisticsService queueStatsService) {
95 this.dps = Preconditions.checkNotNull(dps);
96 this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
97 this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
98 this.targetNodeRef = new NodeRef(targetNodeIdentifier);
100 final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
102 flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
103 flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
104 groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
105 groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
106 meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
107 meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
108 nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
109 queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
112 public NodeKey getTargetNodeKey() {
113 return targetNodeKey;
117 public InstanceIdentifier<Node> getNodeIdentifier() {
118 return targetNodeIdentifier;
122 public NodeRef getNodeRef() {
123 return targetNodeRef;
127 public DataModificationTransaction startDataModification() {
128 return dps.beginTransaction();
131 public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
132 if (msgManager.isExpectedTransaction(transaction, more)) {
133 groupDescStats.updateStats(list);
137 public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
138 if (msgManager.isExpectedTransaction(transaction, more)) {
139 groupStats.updateStats(list);
143 public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
144 if (msgManager.isExpectedTransaction(transaction, more)) {
145 meterConfigStats.updateStats(list);
149 public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
150 if (msgManager.isExpectedTransaction(transaction, more)) {
151 meterStats.updateStats(list);
155 public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
156 if (msgManager.isExpectedTransaction(transaction, more)) {
157 queueStats.updateStats(list);
161 public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
162 if (msgManager.isExpectedTransaction(transaction, more)) {
163 flowTableStats.updateStats(list);
167 public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
168 if (msgManager.isExpectedTransaction(transaction, more)) {
169 nodeConnectorStats.updateStats(list);
173 public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) {
174 final Short tableId = msgManager.isExpectedTableTransaction(transaction, more);
175 if (tableId != null) {
176 final DataModificationTransaction trans = dps.beginTransaction();
177 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
178 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
180 AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
181 AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
183 aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
185 logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
186 aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
188 TableBuilder tableBuilder = new TableBuilder();
189 tableBuilder.setKey(new TableKey(tableId));
190 tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
191 trans.putOperationalData(tableRef, tableBuilder.build());
197 public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List<FlowAndStatisticsMapList> list) {
198 if (msgManager.isExpectedTransaction(transaction, more)) {
199 flowStats.updateStats(list);
203 public synchronized void updateGroupFeatures(GroupFeatures notification) {
204 final DataModificationTransaction trans = dps.beginTransaction();
206 final NodeBuilder nodeData = new NodeBuilder();
207 nodeData.setKey(targetNodeKey);
209 NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
210 GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
211 nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
213 //Update augmented data
214 nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
215 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
217 // FIXME: should we be tracking this data?
221 public synchronized void updateMeterFeatures(MeterFeatures features) {
222 final DataModificationTransaction trans = dps.beginTransaction();
224 final NodeBuilder nodeData = new NodeBuilder();
225 nodeData.setKey(targetNodeKey);
227 NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
228 MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
229 nodeMeterFeatures.setMeterFeatures(meterFeature.build());
231 //Update augmented data
232 nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
233 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
235 // FIXME: should we be tracking this data?
239 public synchronized void cleanStaleStatistics() {
240 final DataModificationTransaction trans = dps.beginTransaction();
241 final long now = System.nanoTime();
243 flowStats.cleanup(trans, now);
244 groupDescStats.cleanup(trans, now);
245 groupStats.cleanup(trans, now);
246 meterConfigStats.cleanup(trans, now);
247 meterStats.cleanup(trans, now);
248 nodeConnectorStats.cleanup(trans, now);
249 queueStats.cleanup(trans, now);
250 msgManager.cleanStaleTransactionIds();
255 public synchronized void requestPeriodicStatistics() {
256 logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
258 flowTableStats.request();
260 // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
261 // comes back -- we do not have any tables anyway.
262 final Collection<TableKey> tables = flowTableStats.getTables();
263 logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
264 for (final TableKey key : tables) {
265 logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
266 flowStats.requestAggregateFlows(key);
269 flowStats.requestAllFlowsAllTables();
270 nodeConnectorStats.request();
271 groupStats.request();
272 groupDescStats.request();
273 meterStats.request();
274 meterConfigStats.request();
275 queueStats.request();
278 public synchronized void start() {
279 flowStats.start(dps);
280 groupDescStats.start(dps);
281 groupStats.start(dps);
282 meterConfigStats.start(dps);
283 meterStats.start(dps);
284 queueStats.start(dps);
286 requestPeriodicStatistics();
290 public synchronized void close() {
292 groupDescStats.close();
294 meterConfigStats.close();
298 logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
302 public void registerTransaction(final ListenableFuture<TransactionId> future, final StatsRequestType type) {
303 Futures.addCallback(future, new FutureCallback<TransactionId>() {
305 public void onSuccess(TransactionId result) {
306 msgManager.recordExpectedTransaction(result, type);
307 logger.debug("Transaction {} for node {} sent successfully", result, targetNodeKey);
311 public void onFailure(Throwable t) {
312 logger.warn("Failed to send statistics request for node {}", targetNodeKey, t);
318 public void registerTableTransaction(final ListenableFuture<TransactionId> future, final Short id) {
319 Futures.addCallback(future, new FutureCallback<TransactionId>() {
321 public void onSuccess(TransactionId result) {
322 msgManager.recordExpectedTableTransaction(result, StatsRequestType.AGGR_FLOW, id);
323 logger.debug("Transaction {} for node {} table {} sent successfully", result, targetNodeKey, id);
327 public void onFailure(Throwable t) {
328 logger.warn("Failed to send table statistics request for node {} table {}", targetNodeKey, id, t);