Move statistics request functions into trackers
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / FlowStatsTracker.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 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder;
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.flow.and.statistics.map.list.FlowAndStatisticsMapList;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import com.google.common.base.Preconditions;
34 import com.google.common.util.concurrent.ListenableFuture;
35
36 final class FlowStatsTracker extends AbstractStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
37     private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class);
38     private final OpendaylightFlowStatisticsService flowStatsService;
39     private int unaccountedFlowsCounter = 1;
40
41     FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, long lifetimeNanos) {
42         super(context, lifetimeNanos);
43         this.flowStatsService = Preconditions.checkNotNull(flowStatsService);
44     }
45
46     @Override
47     protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) {
48         InstanceIdentifier<?> flowRef = getNodeIdentifierBuilder()
49                             .augmentation(FlowCapableNode.class)
50                             .child(Table.class, new TableKey(item.getTableId()))
51                             .child(Flow.class,item.getFlow().getKey())
52                             .augmentation(FlowStatisticsData.class).toInstance();
53         trans.removeOperationalData(flowRef);
54     }
55
56     @Override
57     protected FlowStatsEntry updateSingleStat(DataModificationTransaction trans, FlowAndStatisticsMapList map) {
58         short tableId = map.getTableId();
59
60         FlowBuilder flowBuilder = new FlowBuilder();
61
62         FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
63
64         FlowBuilder flow = new FlowBuilder();
65         flow.setContainerName(map.getContainerName());
66         flow.setBufferId(map.getBufferId());
67         flow.setCookie(map.getCookie());
68         flow.setCookieMask(map.getCookieMask());
69         flow.setFlags(map.getFlags());
70         flow.setFlowName(map.getFlowName());
71         flow.setHardTimeout(map.getHardTimeout());
72         if(map.getFlowId() != null)
73             flow.setId(new FlowId(map.getFlowId().getValue()));
74         flow.setIdleTimeout(map.getIdleTimeout());
75         flow.setInstallHw(map.isInstallHw());
76         flow.setInstructions(map.getInstructions());
77         if(map.getFlowId()!= null)
78             flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
79         flow.setMatch(map.getMatch());
80         flow.setOutGroup(map.getOutGroup());
81         flow.setOutPort(map.getOutPort());
82         flow.setPriority(map.getPriority());
83         flow.setStrict(map.isStrict());
84         flow.setTableId(tableId);
85
86         Flow flowRule = flow.build();
87
88         FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
89         stats.setByteCount(map.getByteCount());
90         stats.setPacketCount(map.getPacketCount());
91         stats.setDuration(map.getDuration());
92
93         GenericStatistics flowStats = stats.build();
94
95         //Augment the data to the flow node
96
97         FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
98         flowStatistics.setByteCount(flowStats.getByteCount());
99         flowStatistics.setPacketCount(flowStats.getPacketCount());
100         flowStatistics.setDuration(flowStats.getDuration());
101         flowStatistics.setContainerName(map.getContainerName());
102         flowStatistics.setBufferId(map.getBufferId());
103         flowStatistics.setCookie(map.getCookie());
104         flowStatistics.setCookieMask(map.getCookieMask());
105         flowStatistics.setFlags(map.getFlags());
106         flowStatistics.setFlowName(map.getFlowName());
107         flowStatistics.setHardTimeout(map.getHardTimeout());
108         flowStatistics.setIdleTimeout(map.getIdleTimeout());
109         flowStatistics.setInstallHw(map.isInstallHw());
110         flowStatistics.setInstructions(map.getInstructions());
111         flowStatistics.setMatch(map.getMatch());
112         flowStatistics.setOutGroup(map.getOutGroup());
113         flowStatistics.setOutPort(map.getOutPort());
114         flowStatistics.setPriority(map.getPriority());
115         flowStatistics.setStrict(map.isStrict());
116         flowStatistics.setTableId(tableId);
117
118         flowStatisticsData.setFlowStatistics(flowStatistics.build());
119
120         logger.debug("Flow : {}",flowRule.toString());
121         logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
122
123         InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
124                 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
125
126         //TODO: Not a good way to do it, need to figure out better way.
127         //TODO: major issue in any alternate approach is that flow key is incrementally assigned
128         //to the flows stored in data store.
129         // Augment same statistics to all the matching masked flow
130         Table table= (Table)trans.readConfigurationData(tableRef);
131         if(table != null){
132             for(Flow existingFlow : table.getFlow()){
133                 logger.debug("Existing flow in data store : {}",existingFlow.toString());
134                 if(FlowComparator.flowEquals(flowRule,existingFlow)){
135                     InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
136                             .augmentation(FlowCapableNode.class)
137                             .child(Table.class, new TableKey(tableId))
138                             .child(Flow.class,existingFlow.getKey()).toInstance();
139                     flowBuilder.setKey(existingFlow.getKey());
140                     flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
141                     logger.debug("Found matching flow in the datastore, augmenting statistics");
142                     // Update entry with timestamp of latest response
143                     flow.setKey(existingFlow.getKey());
144                     FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
145                     trans.putOperationalData(flowRef, flowBuilder.build());
146                     return flowStatsEntry;
147                 }
148             }
149         }
150
151         table = (Table)trans.readOperationalData(tableRef);
152         if(table != null){
153             for(Flow existingFlow : table.getFlow()){
154                 FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
155                 if(augmentedflowStatisticsData != null){
156                     FlowBuilder existingOperationalFlow = new FlowBuilder();
157                     existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
158                     logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
159                     if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
160                         InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
161                                 .augmentation(FlowCapableNode.class)
162                                 .child(Table.class, new TableKey(tableId))
163                                 .child(Flow.class,existingFlow.getKey()).toInstance();
164                         flowBuilder.setKey(existingFlow.getKey());
165                         flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
166                         logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
167                         // Update entry with timestamp of latest response
168                         flow.setKey(existingFlow.getKey());
169                         FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
170                         trans.putOperationalData(flowRef, flowBuilder.build());
171                         return flowStatsEntry;
172                     }
173                 }
174             }
175         }
176
177         String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
178         this.unaccountedFlowsCounter++;
179         FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
180         InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
181                     .child(Table.class, new TableKey(tableId))
182                     .child(Flow.class,newFlowKey).toInstance();
183         flowBuilder.setKey(newFlowKey);
184         flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
185         logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
186                     flowBuilder.build());
187
188         // Update entry with timestamp of latest response
189         flow.setKey(newFlowKey);
190         FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
191         trans.putOperationalData(flowRef, flowBuilder.build());
192         return flowStatsEntry;
193     }
194
195     public ListenableFuture<TransactionId> requestAllFlowsAllTables() {
196         final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
197         input.setNode(getNodeRef());
198
199         return requestHelper(flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()));
200     }
201
202     public ListenableFuture<TransactionId> requestAggregateFlows(final TableKey key) {
203         GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input =
204                 new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
205
206         input.setNode(getNodeRef());
207         input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(key.getId()));
208         return requestHelper(flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()));
209     }
210
211     public ListenableFuture<TransactionId> requestFlow(final Flow flow) {
212         final GetFlowStatisticsFromFlowTableInputBuilder input =
213                 new GetFlowStatisticsFromFlowTableInputBuilder(flow);
214         input.setNode(getNodeRef());
215
216         return requestHelper(flowStatsService.getFlowStatisticsFromFlowTable(input.build()));
217     }
218 }