Handle openflowplugin returning null
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / NodeStatisticsHandler.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.Collection;
11 import java.util.List;
12 import java.util.concurrent.TimeUnit;
13
14 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
15 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import com.google.common.base.Preconditions;
58
59 /**
60  * This class handles the lifecycle of per-node statistics. It receives data
61  * from StatisticsListener, stores it in the data store and keeps track of
62  * when the data should be removed.
63  *
64  * @author avishnoi@in.ibm.com
65  */
66 public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
67     private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
68     private static final int NUMBER_OF_WAIT_CYCLES = 2;
69
70     private final MultipartMessageManager msgManager = new MultipartMessageManager();
71     private final InstanceIdentifier<Node> targetNodeIdentifier;
72     private final FlowStatsTracker flowStats;
73     private final FlowTableStatsTracker flowTableStats;
74     private final GroupDescStatsTracker groupDescStats;
75     private final GroupStatsTracker groupStats;
76     private final MeterConfigStatsTracker meterConfigStats;
77     private final MeterStatsTracker meterStats;
78     private final NodeConnectorStatsTracker nodeConnectorStats;
79     private final QueueStatsTracker queueStats;
80     private final DataProviderService dps;
81     private final NodeRef targetNodeRef;
82     private final NodeKey targetNodeKey;
83
84     public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
85             final OpendaylightFlowStatisticsService flowStatsService,
86             final OpendaylightFlowTableStatisticsService flowTableStatsService,
87             final OpendaylightGroupStatisticsService groupStatsService,
88             final OpendaylightMeterStatisticsService meterStatsService,
89             final OpendaylightPortStatisticsService portStatsService,
90             final OpendaylightQueueStatisticsService queueStatsService) {
91         this.dps = Preconditions.checkNotNull(dps);
92         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
93         this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
94         this.targetNodeRef = new NodeRef(targetNodeIdentifier);
95
96         final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
97
98         flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
99         flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
100         groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
101         groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
102         meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
103         meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
104         nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
105         queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
106     }
107
108     public NodeKey getTargetNodeKey() {
109         return targetNodeKey;
110     }
111
112     @Override
113     public InstanceIdentifier<Node> getNodeIdentifier() {
114         return targetNodeIdentifier;
115     }
116
117     @Override
118     public NodeRef getNodeRef() {
119         return targetNodeRef;
120     }
121
122     @Override
123     public DataModificationTransaction startDataModification() {
124         return dps.beginTransaction();
125     }
126
127     public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
128         if (msgManager.isExpectedTransaction(transaction, more)) {
129             groupDescStats.updateStats(list);
130         }
131     }
132
133     public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
134         if (msgManager.isExpectedTransaction(transaction, more)) {
135             groupStats.updateStats(list);
136         }
137     }
138
139     public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
140         if (msgManager.isExpectedTransaction(transaction, more)) {
141             meterConfigStats.updateStats(list);
142         }
143     }
144
145     public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
146         if (msgManager.isExpectedTransaction(transaction, more)) {
147             meterStats.updateStats(list);
148         }
149     }
150
151     public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
152         if (msgManager.isExpectedTransaction(transaction, more)) {
153             queueStats.updateStats(list);
154         }
155     }
156
157     public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
158         if (msgManager.isExpectedTransaction(transaction, more)) {
159             flowTableStats.updateStats(list);
160         }
161     }
162
163     public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
164         if (msgManager.isExpectedTransaction(transaction, more)) {
165             nodeConnectorStats.updateStats(list);
166         }
167     }
168
169     public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) {
170         final Short tableId = msgManager.isExpectedTableTransaction(transaction, more);
171         if (tableId != null) {
172             final DataModificationTransaction trans = dps.beginTransaction();
173             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
174                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
175
176             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
177             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
178
179             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
180
181             logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
182                     aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
183
184             TableBuilder tableBuilder = new TableBuilder();
185             tableBuilder.setKey(new TableKey(tableId));
186             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
187             trans.putOperationalData(tableRef, tableBuilder.build());
188
189             trans.commit();
190         }
191     }
192
193     public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List<FlowAndStatisticsMapList> list) {
194         if (msgManager.isExpectedTransaction(transaction, more)) {
195             flowStats.updateStats(list);
196         }
197     }
198
199     public synchronized void updateGroupFeatures(GroupFeatures notification) {
200         final DataModificationTransaction trans = dps.beginTransaction();
201
202         final NodeBuilder nodeData = new NodeBuilder();
203         nodeData.setKey(targetNodeKey);
204
205         NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
206         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
207         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
208
209         //Update augmented data
210         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
211         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
212
213         // FIXME: should we be tracking this data?
214         trans.commit();
215     }
216
217     public synchronized void updateMeterFeatures(MeterFeatures features) {
218         final DataModificationTransaction trans = dps.beginTransaction();
219
220         final NodeBuilder nodeData = new NodeBuilder();
221         nodeData.setKey(targetNodeKey);
222
223         NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
224         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
225         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
226
227         //Update augmented data
228         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
229         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
230
231         // FIXME: should we be tracking this data?
232         trans.commit();
233     }
234
235     public synchronized void cleanStaleStatistics() {
236         final DataModificationTransaction trans = dps.beginTransaction();
237         final long now = System.nanoTime();
238
239         flowStats.cleanup(trans, now);
240         groupDescStats.cleanup(trans, now);
241         groupStats.cleanup(trans, now);
242         meterConfigStats.cleanup(trans, now);
243         meterStats.cleanup(trans, now);
244         nodeConnectorStats.cleanup(trans, now);
245         queueStats.cleanup(trans, now);
246         msgManager.cleanStaleTransactionIds();
247
248         trans.commit();
249     }
250
251     public synchronized void requestPeriodicStatistics() {
252         logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
253
254         flowTableStats.request();
255
256         // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
257         //        comes back -- we do not have any tables anyway.
258         final Collection<TableKey> tables = flowTableStats.getTables();
259         logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
260         for (final TableKey key : tables) {
261             logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
262             flowStats.requestAggregateFlows(key);
263         }
264
265         flowStats.requestAllFlowsAllTables();
266         nodeConnectorStats.request();
267         groupStats.request();
268         groupDescStats.request();
269         meterStats.request();
270         meterConfigStats.request();
271         queueStats.request();
272     }
273
274     public synchronized void start() {
275         flowStats.start(dps);
276         groupDescStats.start(dps);
277         groupStats.start(dps);
278         meterConfigStats.start(dps);
279         meterStats.start(dps);
280         queueStats.start(dps);
281
282         requestPeriodicStatistics();
283     }
284
285     @Override
286     public synchronized void close() {
287         flowStats.close();
288         groupDescStats.close();
289         groupStats.close();
290         meterConfigStats.close();
291         meterStats.close();
292         queueStats.close();
293
294         logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
295     }
296
297     @Override
298     public void registerTransaction(TransactionId id) {
299         msgManager.recordExpectedTransaction(id);
300         logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey);
301     }
302
303     @Override
304     public void registerTableTransaction(final TransactionId id, final Short table) {
305         msgManager.recordExpectedTableTransaction(id, table);
306         logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table);
307     }
308 }