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.Timer;
13 import java.util.TimerTask;
14 import java.util.concurrent.TimeUnit;
16 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
17 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
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.tables.Table;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
59 import com.google.common.base.Preconditions;
62 * This class handles the lifecycle of per-node statistics. It receives data
63 * from StatisticsListener, stores it in the data store and keeps track of
64 * when the data should be removed.
66 * @author avishnoi@in.ibm.com
68 public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
69 private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
71 private static final long STATS_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(15);
72 private static final long FIRST_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(5);
73 private static final int NUMBER_OF_WAIT_CYCLES = 2;
75 private final MultipartMessageManager msgManager;
76 private final InstanceIdentifier<Node> targetNodeIdentifier;
77 private final FlowStatsTracker flowStats;
78 private final FlowTableStatsTracker flowTableStats;
79 private final GroupDescStatsTracker groupDescStats;
80 private final GroupStatsTracker groupStats;
81 private final MeterConfigStatsTracker meterConfigStats;
82 private final MeterStatsTracker meterStats;
83 private final NodeConnectorStatsTracker nodeConnectorStats;
84 private final QueueStatsTracker queueStats;
85 private final DataProviderService dps;
86 private final NodeRef targetNodeRef;
87 private final NodeKey targetNodeKey;
88 private final TimerTask task = new TimerTask() {
91 requestPeriodicStatistics();
92 cleanStaleStatistics();
96 public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
97 final OpendaylightFlowStatisticsService flowStatsService,
98 final OpendaylightFlowTableStatisticsService flowTableStatsService,
99 final OpendaylightGroupStatisticsService groupStatsService,
100 final OpendaylightMeterStatisticsService meterStatsService,
101 final OpendaylightPortStatisticsService portStatsService,
102 final OpendaylightQueueStatisticsService queueStatsService) {
103 this.dps = Preconditions.checkNotNull(dps);
104 this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
105 this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
106 this.targetNodeRef = new NodeRef(targetNodeIdentifier);
108 final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
110 msgManager = new MultipartMessageManager(lifetimeNanos);
111 flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
112 flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
113 groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
114 groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
115 meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
116 meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
117 nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
118 queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
121 public NodeKey getTargetNodeKey() {
122 return targetNodeKey;
126 public InstanceIdentifier<Node> getNodeIdentifier() {
127 return targetNodeIdentifier;
131 public NodeRef getNodeRef() {
132 return targetNodeRef;
136 public DataModificationTransaction startDataModification() {
137 return dps.beginTransaction();
140 public synchronized void updateGroupDescStats(TransactionAware transaction, List<GroupDescStats> list) {
141 if (msgManager.isExpectedTransaction(transaction)) {
142 groupDescStats.updateStats(list);
146 public synchronized void updateGroupStats(TransactionAware transaction, List<GroupStats> list) {
147 if (msgManager.isExpectedTransaction(transaction)) {
148 groupStats.updateStats(list);
152 public synchronized void updateMeterConfigStats(TransactionAware transaction, List<MeterConfigStats> list) {
153 if (msgManager.isExpectedTransaction(transaction)) {
154 meterConfigStats.updateStats(list);
158 public synchronized void updateMeterStats(TransactionAware transaction, List<MeterStats> list) {
159 if (msgManager.isExpectedTransaction(transaction)) {
160 meterStats.updateStats(list);
164 public synchronized void updateQueueStats(TransactionAware transaction, List<QueueIdAndStatisticsMap> list) {
165 if (msgManager.isExpectedTransaction(transaction)) {
166 queueStats.updateStats(list);
170 public synchronized void updateFlowTableStats(TransactionAware transaction, List<FlowTableAndStatisticsMap> list) {
171 if (msgManager.isExpectedTransaction(transaction)) {
172 flowTableStats.updateStats(list);
176 public synchronized void updateNodeConnectorStats(TransactionAware transaction, List<NodeConnectorStatisticsAndPortNumberMap> list) {
177 if (msgManager.isExpectedTransaction(transaction)) {
178 nodeConnectorStats.updateStats(list);
182 public synchronized void updateAggregateFlowStats(TransactionAware transaction, AggregateFlowStatistics flowStats) {
183 final Short tableId = msgManager.isExpectedTableTransaction(transaction);
184 if (tableId != null) {
185 final DataModificationTransaction trans = dps.beginTransaction();
186 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
187 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
189 AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
190 AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
192 aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
194 logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
195 aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
197 TableBuilder tableBuilder = new TableBuilder();
198 tableBuilder.setKey(new TableKey(tableId));
199 tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
200 trans.putOperationalData(tableRef, tableBuilder.build());
206 public synchronized void updateFlowStats(TransactionAware transaction, List<FlowAndStatisticsMapList> list) {
207 if (msgManager.isExpectedTransaction(transaction)) {
208 flowStats.updateStats(list);
212 public synchronized void updateGroupFeatures(GroupFeatures notification) {
213 final DataModificationTransaction trans = dps.beginTransaction();
215 final NodeBuilder nodeData = new NodeBuilder();
216 nodeData.setKey(targetNodeKey);
218 NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
219 GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
220 nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
222 //Update augmented data
223 nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
224 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
226 // FIXME: should we be tracking this data?
230 public synchronized void updateMeterFeatures(MeterFeatures features) {
231 final DataModificationTransaction trans = dps.beginTransaction();
233 final NodeBuilder nodeData = new NodeBuilder();
234 nodeData.setKey(targetNodeKey);
236 NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
237 MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
238 nodeMeterFeatures.setMeterFeatures(meterFeature.build());
240 //Update augmented data
241 nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
242 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
244 // FIXME: should we be tracking this data?
248 public synchronized void cleanStaleStatistics() {
249 final DataModificationTransaction trans = dps.beginTransaction();
250 final long now = System.nanoTime();
252 flowStats.cleanup(trans, now);
253 groupDescStats.cleanup(trans, now);
254 groupStats.cleanup(trans, now);
255 meterConfigStats.cleanup(trans, now);
256 meterStats.cleanup(trans, now);
257 nodeConnectorStats.cleanup(trans, now);
258 queueStats.cleanup(trans, now);
259 msgManager.cleanStaleTransactionIds();
264 public synchronized void requestPeriodicStatistics() {
265 logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
267 flowTableStats.request();
269 // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
270 // comes back -- we do not have any tables anyway.
271 final Collection<TableKey> tables = flowTableStats.getTables();
272 logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
273 for (final TableKey key : tables) {
274 logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
275 flowStats.requestAggregateFlows(key);
278 flowStats.requestAllFlowsAllTables();
279 nodeConnectorStats.request();
280 groupStats.request();
281 groupDescStats.request();
282 meterStats.request();
283 meterConfigStats.request();
284 queueStats.request();
287 public synchronized void start(final Timer timer) {
288 flowStats.start(dps);
289 groupDescStats.start(dps);
290 groupStats.start(dps);
291 meterConfigStats.start(dps);
292 meterStats.start(dps);
293 queueStats.start(dps);
295 timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS);
297 logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS);
299 requestPeriodicStatistics();
303 public synchronized void close() {
306 groupDescStats.close();
308 meterConfigStats.close();
312 logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
316 public void registerTransaction(TransactionId id) {
317 msgManager.recordExpectedTransaction(id);
318 logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey);
322 public void registerTableTransaction(final TransactionId id, final Short table) {
323 msgManager.recordExpectedTableTransaction(id, table);
324 logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table);