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() {
92 requestPeriodicStatistics();
93 cleanStaleStatistics();
95 logger.warn("Exception occured while sending statistics request : {}",e);
100 public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
101 final OpendaylightFlowStatisticsService flowStatsService,
102 final OpendaylightFlowTableStatisticsService flowTableStatsService,
103 final OpendaylightGroupStatisticsService groupStatsService,
104 final OpendaylightMeterStatisticsService meterStatsService,
105 final OpendaylightPortStatisticsService portStatsService,
106 final OpendaylightQueueStatisticsService queueStatsService) {
107 this.dps = Preconditions.checkNotNull(dps);
108 this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
109 this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
110 this.targetNodeRef = new NodeRef(targetNodeIdentifier);
112 final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
114 msgManager = new MultipartMessageManager(lifetimeNanos);
115 flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
116 flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
117 groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
118 groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
119 meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
120 meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
121 nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
122 queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
125 public NodeKey getTargetNodeKey() {
126 return targetNodeKey;
130 public InstanceIdentifier<Node> getNodeIdentifier() {
131 return targetNodeIdentifier;
135 public NodeRef getNodeRef() {
136 return targetNodeRef;
140 public DataModificationTransaction startDataModification() {
141 return dps.beginTransaction();
144 public synchronized void updateGroupDescStats(TransactionAware transaction, List<GroupDescStats> list) {
145 if (msgManager.isExpectedTransaction(transaction)) {
146 groupDescStats.updateStats(list);
150 public synchronized void updateGroupStats(TransactionAware transaction, List<GroupStats> list) {
151 if (msgManager.isExpectedTransaction(transaction)) {
152 groupStats.updateStats(list);
156 public synchronized void updateMeterConfigStats(TransactionAware transaction, List<MeterConfigStats> list) {
157 if (msgManager.isExpectedTransaction(transaction)) {
158 meterConfigStats.updateStats(list);
162 public synchronized void updateMeterStats(TransactionAware transaction, List<MeterStats> list) {
163 if (msgManager.isExpectedTransaction(transaction)) {
164 meterStats.updateStats(list);
168 public synchronized void updateQueueStats(TransactionAware transaction, List<QueueIdAndStatisticsMap> list) {
169 if (msgManager.isExpectedTransaction(transaction)) {
170 queueStats.updateStats(list);
174 public synchronized void updateFlowTableStats(TransactionAware transaction, List<FlowTableAndStatisticsMap> list) {
175 if (msgManager.isExpectedTransaction(transaction)) {
176 flowTableStats.updateStats(list);
180 public synchronized void updateNodeConnectorStats(TransactionAware transaction, List<NodeConnectorStatisticsAndPortNumberMap> list) {
181 if (msgManager.isExpectedTransaction(transaction)) {
182 nodeConnectorStats.updateStats(list);
186 public synchronized void updateAggregateFlowStats(TransactionAware transaction, AggregateFlowStatistics flowStats) {
187 final Short tableId = msgManager.isExpectedTableTransaction(transaction);
188 if (tableId != null) {
189 final DataModificationTransaction trans = dps.beginTransaction();
190 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
191 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
193 AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
194 AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
196 aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
198 logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
199 aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
201 TableBuilder tableBuilder = new TableBuilder();
202 tableBuilder.setKey(new TableKey(tableId));
203 tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
204 trans.putOperationalData(tableRef, tableBuilder.build());
210 public synchronized void updateFlowStats(TransactionAware transaction, List<FlowAndStatisticsMapList> list) {
211 if (msgManager.isExpectedTransaction(transaction)) {
212 flowStats.updateStats(list);
216 public synchronized void updateGroupFeatures(GroupFeatures notification) {
217 final DataModificationTransaction trans = dps.beginTransaction();
219 final NodeBuilder nodeData = new NodeBuilder();
220 nodeData.setKey(targetNodeKey);
222 NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
223 GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
224 nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
226 //Update augmented data
227 nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
228 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
230 // FIXME: should we be tracking this data?
234 public synchronized void updateMeterFeatures(MeterFeatures features) {
235 final DataModificationTransaction trans = dps.beginTransaction();
237 final NodeBuilder nodeData = new NodeBuilder();
238 nodeData.setKey(targetNodeKey);
240 NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
241 MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
242 nodeMeterFeatures.setMeterFeatures(meterFeature.build());
244 //Update augmented data
245 nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
246 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
248 // FIXME: should we be tracking this data?
252 public synchronized void cleanStaleStatistics() {
253 final DataModificationTransaction trans = dps.beginTransaction();
254 final long now = System.nanoTime();
256 flowStats.cleanup(trans, now);
257 groupDescStats.cleanup(trans, now);
258 groupStats.cleanup(trans, now);
259 meterConfigStats.cleanup(trans, now);
260 meterStats.cleanup(trans, now);
261 nodeConnectorStats.cleanup(trans, now);
262 queueStats.cleanup(trans, now);
263 msgManager.cleanStaleTransactionIds();
268 public synchronized void requestPeriodicStatistics() {
269 logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
271 flowTableStats.request();
273 // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
274 // comes back -- we do not have any tables anyway.
275 final Collection<TableKey> tables = flowTableStats.getTables();
276 logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
277 for (final TableKey key : tables) {
278 logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
279 flowStats.requestAggregateFlows(key);
282 flowStats.requestAllFlowsAllTables();
283 nodeConnectorStats.request();
284 groupStats.request();
285 groupDescStats.request();
286 meterStats.request();
287 meterConfigStats.request();
288 queueStats.request();
291 public synchronized void start(final Timer timer) {
292 flowStats.start(dps);
293 groupDescStats.start(dps);
294 groupStats.start(dps);
295 meterConfigStats.start(dps);
296 meterStats.start(dps);
297 queueStats.start(dps);
299 timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS);
301 logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS);
303 requestPeriodicStatistics();
307 public synchronized void close() {
310 groupDescStats.close();
312 meterConfigStats.close();
316 logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
320 public void registerTransaction(TransactionId id) {
321 msgManager.recordExpectedTransaction(id);
322 logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey);
326 public void registerTableTransaction(final TransactionId id, final Short table) {
327 msgManager.recordExpectedTableTransaction(id, table);
328 logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table);