Centralize NodeStatisticsAger creation
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / StatisticsUpdateCommiter.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.net.Inet4Address;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.List;
14
15 import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.FlowEntry;
16 import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.QueueEntry;
17 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
108 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
109 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
110 import org.slf4j.Logger;
111 import org.slf4j.LoggerFactory;
112
113 /**
114  * Class implement statistics manager related listener interface and augment all the
115  * received statistics data to data stores.
116  * TODO: Need to add error message listener and clean-up the associated tx id
117  * if it exists in the tx-id cache.
118  * @author vishnoianil
119  *
120  */
121 public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener,
122         OpendaylightMeterStatisticsListener,
123         OpendaylightFlowStatisticsListener,
124         OpendaylightPortStatisticsListener,
125         OpendaylightFlowTableStatisticsListener,
126         OpendaylightQueueStatisticsListener{
127
128     private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
129
130     private final StatisticsProvider statisticsManager;
131     private final MultipartMessageManager messageManager;
132
133     private int unaccountedFlowsCounter = 1;
134
135     /**
136      * default ctor
137      * @param manager
138      */
139     public StatisticsUpdateCommiter(final StatisticsProvider manager){
140
141         this.statisticsManager = manager;
142         this.messageManager = this.statisticsManager.getMultipartMessageManager();
143     }
144
145     public StatisticsProvider getStatisticsManager(){
146         return statisticsManager;
147     }
148
149     @Override
150     public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) {
151         //Check if response is for the request statistics-manager sent.
152         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
153             return;
154
155         final NodeKey key = new NodeKey(notification.getId());
156
157         //Add statistics to local cache
158         this.statisticsManager.getStatisticsAger(notification.getId()).updateMeterConfigStats(notification.getMeterConfigStats());
159
160         //Publish data to configuration data store
161         List<MeterConfigStats> meterConfigStatsList = notification.getMeterConfigStats();
162         DataModificationTransaction it = this.statisticsManager.startChange();
163
164         for(MeterConfigStats meterConfigStats : meterConfigStatsList){
165             MeterBuilder meterBuilder = new MeterBuilder();
166             MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
167             meterBuilder.setKey(meterKey);
168
169             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
170                                                                                         .augmentation(FlowCapableNode.class)
171                                                                                         .child(Meter.class,meterKey).toInstance();
172
173             NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
174             MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
175             stats.fieldsFrom(meterConfigStats);
176             meterConfig.setMeterConfigStats(stats.build());
177
178             //Update augmented data
179             meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
180             it.putOperationalData(meterRef, meterBuilder.build());
181         }
182         it.commit();
183     }
184
185     @Override
186     public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
187
188         //Check if response is for the request statistics-manager sent.
189         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
190             return;
191
192         final NodeKey key = new NodeKey(notification.getId());
193
194         //Publish data to configuration data store
195         List<MeterStats> meterStatsList = notification.getMeterStats();
196         DataModificationTransaction it = this.statisticsManager.startChange();
197
198         for(MeterStats meterStats : meterStatsList){
199
200             MeterBuilder meterBuilder = new MeterBuilder();
201             MeterKey meterKey = new MeterKey(meterStats.getMeterId());
202             meterBuilder.setKey(meterKey);
203
204             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
205                                                                                         .augmentation(FlowCapableNode.class)
206                                                                                         .child(Meter.class,meterKey).toInstance();
207
208             NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
209             MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
210             stats.fieldsFrom(meterStats);
211             meterStatsBuilder.setMeterStatistics(stats.build());
212
213             //Update augmented data
214             meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
215             it.putOperationalData(meterRef, meterBuilder.build());
216         }
217         it.commit();
218     }
219
220     @Override
221     public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
222
223         //Check if response is for the request statistics-manager sent.
224         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
225             return;
226
227         final NodeKey key = new NodeKey(notification.getId());
228
229         //Add statistics to local cache
230         this.statisticsManager.getStatisticsAger(key.getId()).updateGroupDescStats(notification.getGroupDescStats());
231
232         //Publish data to configuration data store
233         List<GroupDescStats> groupDescStatsList = notification.getGroupDescStats();
234         DataModificationTransaction it = this.statisticsManager.startChange();
235
236         for(GroupDescStats groupDescStats : groupDescStatsList){
237
238             GroupBuilder groupBuilder = new GroupBuilder();
239             GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
240             groupBuilder.setKey(groupKey);
241
242             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
243                                                                                         .augmentation(FlowCapableNode.class)
244                                                                                         .child(Group.class,groupKey).toInstance();
245
246             NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
247             GroupDescBuilder stats = new GroupDescBuilder();
248             stats.fieldsFrom(groupDescStats);
249             groupDesc.setGroupDesc(stats.build());
250
251             //Update augmented data
252             groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
253
254             it.putOperationalData(groupRef, groupBuilder.build());
255         }
256         it.commit();
257     }
258
259     @Override
260     public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
261
262         //Check if response is for the request statistics-manager sent.
263         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
264             return;
265
266         //Publish data to configuration data store
267         NodeKey key = new NodeKey(notification.getId());
268         List<GroupStats> groupStatsList = notification.getGroupStats();
269         DataModificationTransaction it = this.statisticsManager.startChange();
270
271         for(GroupStats groupStats : groupStatsList){
272
273             GroupBuilder groupBuilder = new GroupBuilder();
274             GroupKey groupKey = new GroupKey(groupStats.getGroupId());
275             groupBuilder.setKey(groupKey);
276
277             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
278                                                                                         .augmentation(FlowCapableNode.class)
279                                                                                         .child(Group.class,groupKey).toInstance();
280
281             NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
282             GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
283             stats.fieldsFrom(groupStats);
284             groupStatisticsBuilder.setGroupStatistics(stats.build());
285
286             //Update augmented data
287             groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
288             it.putOperationalData(groupRef, groupBuilder.build());
289         }
290         it.commit();
291     }
292
293     @Override
294     public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) {
295
296         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder();
297         meterFeature.setMeterBandSupported(notification.getMeterBandSupported());
298         meterFeature.setMeterCapabilitiesSupported(notification.getMeterCapabilitiesSupported());
299         meterFeature.setMaxBands(notification.getMaxBands());
300         meterFeature.setMaxColor(notification.getMaxColor());
301         meterFeature.setMaxMeter(notification.getMaxMeter());
302
303         //Publish data to configuration data store
304         DataModificationTransaction it = this.statisticsManager.startChange();
305         NodeKey key = new NodeKey(notification.getId());
306         NodeRef ref = getNodeRef(key);
307
308         final NodeBuilder nodeData = new NodeBuilder();
309         nodeData.setKey(key);
310
311         NodeMeterFeaturesBuilder nodeMeterFeatures= new NodeMeterFeaturesBuilder();
312         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
313
314         //Update augmented data
315         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
316
317         InstanceIdentifier<? extends Object> refValue = ref.getValue();
318         it.putOperationalData(refValue, nodeData.build());
319         it.commit();
320     }
321
322     @Override
323     public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) {
324
325         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder();
326         groupFeatures.setActions(notification.getActions());
327         groupFeatures.setGroupCapabilitiesSupported(notification.getGroupCapabilitiesSupported());
328         groupFeatures.setGroupTypesSupported(notification.getGroupTypesSupported());
329         groupFeatures.setMaxGroups(notification.getMaxGroups());
330
331         //Publish data to configuration data store
332         DataModificationTransaction it = this.statisticsManager.startChange();
333         NodeKey key = new NodeKey(notification.getId());
334         NodeRef ref = getNodeRef(key);
335
336         final NodeBuilder nodeData = new NodeBuilder();
337         nodeData.setKey(key);
338
339         NodeGroupFeaturesBuilder nodeGroupFeatures= new NodeGroupFeaturesBuilder();
340         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
341
342         //Update augmented data
343         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
344
345         InstanceIdentifier<? extends Object> refValue = ref.getValue();
346         it.putOperationalData(refValue, nodeData.build());
347         it.commit();
348     }
349
350     @Override
351     public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) {
352
353         //Check if response is for the request statistics-manager sent.
354         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
355             return;
356
357         sucLogger.debug("Received flow stats update : {}",notification.toString());
358
359         final NodeKey key = new NodeKey(notification.getId());
360         final NodeStatisticsAger nsa =  this.statisticsManager.getStatisticsAger(key.getId());
361         DataModificationTransaction it = this.statisticsManager.startChange();
362
363         for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){
364             short tableId = map.getTableId();
365
366
367             boolean foundOriginalFlow = false;
368
369             FlowBuilder flowBuilder = new FlowBuilder();
370
371             FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
372
373             FlowBuilder flow = new FlowBuilder();
374             flow.setContainerName(map.getContainerName());
375             flow.setBufferId(map.getBufferId());
376             flow.setCookie(map.getCookie());
377             flow.setCookieMask(map.getCookieMask());
378             flow.setFlags(map.getFlags());
379             flow.setFlowName(map.getFlowName());
380             flow.setHardTimeout(map.getHardTimeout());
381             if(map.getFlowId() != null)
382                 flow.setId(new FlowId(map.getFlowId().getValue()));
383             flow.setIdleTimeout(map.getIdleTimeout());
384             flow.setInstallHw(map.isInstallHw());
385             flow.setInstructions(map.getInstructions());
386             if(map.getFlowId()!= null)
387                 flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
388             flow.setMatch(map.getMatch());
389             flow.setOutGroup(map.getOutGroup());
390             flow.setOutPort(map.getOutPort());
391             flow.setPriority(map.getPriority());
392             flow.setStrict(map.isStrict());
393             flow.setTableId(tableId);
394
395             Flow flowRule = flow.build();
396
397             FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
398             stats.setByteCount(map.getByteCount());
399             stats.setPacketCount(map.getPacketCount());
400             stats.setDuration(map.getDuration());
401
402             GenericStatistics flowStats = stats.build();
403
404             //Augment the data to the flow node
405
406             FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
407             flowStatistics.setByteCount(flowStats.getByteCount());
408             flowStatistics.setPacketCount(flowStats.getPacketCount());
409             flowStatistics.setDuration(flowStats.getDuration());
410             flowStatistics.setContainerName(map.getContainerName());
411             flowStatistics.setBufferId(map.getBufferId());
412             flowStatistics.setCookie(map.getCookie());
413             flowStatistics.setCookieMask(map.getCookieMask());
414             flowStatistics.setFlags(map.getFlags());
415             flowStatistics.setFlowName(map.getFlowName());
416             flowStatistics.setHardTimeout(map.getHardTimeout());
417             flowStatistics.setIdleTimeout(map.getIdleTimeout());
418             flowStatistics.setInstallHw(map.isInstallHw());
419             flowStatistics.setInstructions(map.getInstructions());
420             flowStatistics.setMatch(map.getMatch());
421             flowStatistics.setOutGroup(map.getOutGroup());
422             flowStatistics.setOutPort(map.getOutPort());
423             flowStatistics.setPriority(map.getPriority());
424             flowStatistics.setStrict(map.isStrict());
425             flowStatistics.setTableId(tableId);
426
427             flowStatisticsData.setFlowStatistics(flowStatistics.build());
428
429             sucLogger.debug("Flow : {}",flowRule.toString());
430             sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
431
432             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
433                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
434
435             Table table= (Table)it.readConfigurationData(tableRef);
436
437             //TODO: Not a good way to do it, need to figure out better way.
438             //TODO: major issue in any alternate approach is that flow key is incrementally assigned
439             //to the flows stored in data store.
440             // Augment same statistics to all the matching masked flow
441             if(table != null){
442
443                 for(Flow existingFlow : table.getFlow()){
444                     sucLogger.debug("Existing flow in data store : {}",existingFlow.toString());
445                     if(flowEquals(flowRule,existingFlow)){
446                         InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
447                                 .augmentation(FlowCapableNode.class)
448                                 .child(Table.class, new TableKey(tableId))
449                                 .child(Flow.class,existingFlow.getKey()).toInstance();
450                         flowBuilder.setKey(existingFlow.getKey());
451                         flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
452                         sucLogger.debug("Found matching flow in the datastore, augmenting statistics");
453                         foundOriginalFlow = true;
454                         // Update entry with timestamp of latest response
455                         flow.setKey(existingFlow.getKey());
456                         FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
457                         nsa.updateFlowStats(flowStatsEntry);
458
459                         it.putOperationalData(flowRef, flowBuilder.build());
460                     }
461                 }
462             }
463
464             table= (Table)it.readOperationalData(tableRef);
465             if(!foundOriginalFlow && table != null){
466
467                 for(Flow existingFlow : table.getFlow()){
468                     FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
469                     if(augmentedflowStatisticsData != null){
470                         FlowBuilder existingOperationalFlow = new FlowBuilder();
471                         existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
472                         sucLogger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
473                         if(flowEquals(flowRule,existingOperationalFlow.build())){
474                             InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
475                                     .augmentation(FlowCapableNode.class)
476                                     .child(Table.class, new TableKey(tableId))
477                                     .child(Flow.class,existingFlow.getKey()).toInstance();
478                             flowBuilder.setKey(existingFlow.getKey());
479                             flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
480                             sucLogger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
481                             foundOriginalFlow = true;
482
483                             // Update entry with timestamp of latest response
484                             flow.setKey(existingFlow.getKey());
485                             FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
486                             nsa.updateFlowStats(flowStatsEntry);
487
488                             it.putOperationalData(flowRef, flowBuilder.build());
489                             break;
490                         }
491                     }
492                 }
493             }
494             if(!foundOriginalFlow){
495                 String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
496                 this.unaccountedFlowsCounter++;
497                 FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
498                 InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
499                         .augmentation(FlowCapableNode.class)
500                         .child(Table.class, new TableKey(tableId))
501                         .child(Flow.class,newFlowKey).toInstance();
502                 flowBuilder.setKey(newFlowKey);
503                 flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
504                 sucLogger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",flowBuilder.build());
505
506                 // Update entry with timestamp of latest response
507                 flow.setKey(newFlowKey);
508                 FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
509                 nsa.updateFlowStats(flowStatsEntry);
510
511                 it.putOperationalData(flowRef, flowBuilder.build());
512             }
513         }
514         it.commit();
515     }
516
517     @Override
518     public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
519         //Check if response is for the request statistics-manager sent.
520         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
521             return;
522
523         NodeKey key = new NodeKey(notification.getId());
524
525         Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId());
526         if(tableId != null){
527
528             DataModificationTransaction it = this.statisticsManager.startChange();
529
530             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
531                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
532
533             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
534             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder();
535             aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount());
536             aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount());
537             aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount());
538             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
539
540             sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key);
541
542             TableBuilder tableBuilder = new TableBuilder();
543             tableBuilder.setKey(new TableKey(tableId));
544             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
545             it.putOperationalData(tableRef, tableBuilder.build());
546             it.commit();
547
548         }
549     }
550
551     @Override
552     public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
553         //Check if response is for the request statistics-manager sent.
554         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
555             return;
556
557         NodeKey key = new NodeKey(notification.getId());
558
559         List<NodeConnectorStatisticsAndPortNumberMap> portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap();
560         DataModificationTransaction it = this.statisticsManager.startChange();
561
562         for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){
563
564             FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
565                                             = new FlowCapableNodeConnectorStatisticsBuilder();
566             statisticsBuilder.setBytes(portStats.getBytes());
567             statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
568             statisticsBuilder.setDuration(portStats.getDuration());
569             statisticsBuilder.setPackets(portStats.getPackets());
570             statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
571             statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
572             statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
573             statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
574             statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
575             statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
576             statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
577
578             //Augment data to the node-connector
579             FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
580                     new FlowCapableNodeConnectorStatisticsDataBuilder();
581
582             statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
583
584             InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
585
586             NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef);
587
588             if(nodeConnector != null){
589                 sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString());
590                 NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
591                 nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build());
592                 it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
593             }
594         }
595         it.commit();
596     }
597
598     @Override
599     public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
600         //Check if response is for the request statistics-manager sent.
601         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
602             return;
603
604         NodeKey key = new NodeKey(notification.getId());
605
606         List<FlowTableAndStatisticsMap> flowTablesStatsList = notification.getFlowTableAndStatisticsMap();
607         DataModificationTransaction it = this.statisticsManager.startChange();
608
609         for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){
610
611             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
612                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
613
614             FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
615
616             FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
617             statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
618             statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
619             statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
620
621             statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build());
622
623             sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key);
624
625             TableBuilder tableBuilder = new TableBuilder();
626             tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
627             tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
628             it.putOperationalData(tableRef, tableBuilder.build());
629         }
630         it.commit();
631     }
632
633     @Override
634     public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
635
636         //Check if response is for the request statistics-manager sent.
637         if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
638             return;
639
640         NodeKey key = new NodeKey(notification.getId());
641
642         //Add statistics to local cache
643         NodeStatisticsAger nsa = this.statisticsManager.getStatisticsAger(key.getId());
644
645         List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
646         DataModificationTransaction it = this.statisticsManager.startChange();
647
648         for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
649
650             QueueEntry queueEntry = nsa.new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
651             nsa.updateQueueStats(queueEntry);
652
653             FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
654
655             FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
656
657             queueStatisticsBuilder.fieldsFrom(swQueueStats);
658
659             queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
660
661             InstanceIdentifier<Queue> queueRef
662                     = InstanceIdentifier.builder(Nodes.class)
663                                         .child(Node.class, key)
664                                         .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
665                                         .augmentation(FlowCapableNodeConnector.class)
666                                         .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
667
668             QueueBuilder queueBuilder = new QueueBuilder();
669             queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
670             queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
671
672             sucLogger.debug("Augmenting queue statistics {} of queue {} to port {}"
673                                         ,queueStatisticsDataBuilder.build().toString(),
674                                         swQueueStats.getQueueId(),
675                                         swQueueStats.getNodeConnectorId());
676
677             it.putOperationalData(queueRef, queueBuilder.build());
678         }
679         it.commit();
680     }
681
682     private static NodeRef getNodeRef(NodeKey nodeKey){
683         InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
684         return new NodeRef(builder.toInstance());
685     }
686
687     public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
688         if (statsFlow.getClass() != storedFlow.getClass()) {
689             return false;
690         }
691         if (statsFlow.getContainerName()== null) {
692             if (storedFlow.getContainerName()!= null) {
693                 return false;
694             }
695         } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
696             return false;
697         }
698         if (statsFlow.getMatch()== null) {
699             if (storedFlow.getMatch() != null) {
700                 return false;
701             }
702         } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
703         else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
704             return false;
705         }
706         if (storedFlow.getPriority() == null) {
707             if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
708                 return false;
709             }
710         } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
711             return false;
712         }
713         if (statsFlow.getTableId() == null) {
714             if (storedFlow.getTableId() != null) {
715                 return false;
716             }
717         } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
718             return false;
719         }
720         return true;
721     }
722
723     /**
724      * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
725      * Flow installation process has three steps
726      * 1) Store flow in config data store
727      * 2) and send it to plugin for installation
728      * 3) Flow gets installed in switch
729      *
730      * The flow user wants to install and what finally gets installed in switch can be slightly different.
731      * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch
732      * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch
733      * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip
734      * while comparing two ip addresses.
735      *
736      * Sometimes when user don't provide few values that is required by flow installation request, like
737      * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending
738      * request to the switch. So when statistics manager gets flow statistics, it gets the default value.
739      * But the flow stored in config data store don't have those defaults value. I included those checks
740      * in the customer flow/match equal function.
741      *
742      *
743      * @param statsFlow
744      * @param storedFlow
745      * @return
746      */
747
748     public static boolean matchEquals(Match statsFlow, Match storedFlow) {
749         if (statsFlow == storedFlow) {
750             return true;
751         }
752         if (storedFlow.getClass() != statsFlow.getClass()) {
753             return false;
754         }
755         if (storedFlow.getEthernetMatch() == null) {
756             if (statsFlow.getEthernetMatch() != null) {
757                 return false;
758             }
759         } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) {
760             return false;
761         }
762         if (storedFlow.getIcmpv4Match()== null) {
763             if (statsFlow.getIcmpv4Match() != null) {
764                 return false;
765             }
766         } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) {
767             return false;
768         }
769         if (storedFlow.getIcmpv6Match() == null) {
770             if (statsFlow.getIcmpv6Match() != null) {
771                 return false;
772             }
773         } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) {
774             return false;
775         }
776         if (storedFlow.getInPhyPort() == null) {
777             if (statsFlow.getInPhyPort() != null) {
778                 return false;
779             }
780         } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) {
781             return false;
782         }
783         if (storedFlow.getInPort()== null) {
784             if (statsFlow.getInPort() != null) {
785                 return false;
786             }
787         } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) {
788             return false;
789         }
790         if (storedFlow.getIpMatch()== null) {
791             if (statsFlow.getIpMatch() != null) {
792                 return false;
793             }
794         } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) {
795             return false;
796         }
797         if (storedFlow.getLayer3Match()== null) {
798             if (statsFlow.getLayer3Match() != null) {
799                     return false;
800             }
801         } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) {
802             return false;
803         }
804         if (storedFlow.getLayer4Match()== null) {
805             if (statsFlow.getLayer4Match() != null) {
806                 return false;
807             }
808         } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) {
809             return false;
810         }
811         if (storedFlow.getMetadata() == null) {
812             if (statsFlow.getMetadata() != null) {
813                 return false;
814             }
815         } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) {
816             return false;
817         }
818         if (storedFlow.getProtocolMatchFields() == null) {
819             if (statsFlow.getProtocolMatchFields() != null) {
820                 return false;
821             }
822         } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) {
823             return false;
824         }
825         if (storedFlow.getTunnel()== null) {
826             if (statsFlow.getTunnel() != null) {
827                 return false;
828             }
829         } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) {
830             return false;
831         }
832         if (storedFlow.getVlanMatch()== null) {
833             if (statsFlow.getVlanMatch() != null) {
834                 return false;
835             }
836         } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) {
837             return false;
838         }
839         return true;
840     }
841
842     protected static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){
843         boolean verdict = true;
844         if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){
845             Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
846             Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
847
848             if (verdict) {
849                 verdict = compareNullSafe(
850                         storedIpv4Match.getIpv4Destination(), statsIpv4Match.getIpv4Destination());
851             }
852             if (verdict) {
853                 verdict = compareNullSafe(
854                         statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source());
855             }
856         } else {
857             Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
858             if (nullCheckOut != null) {
859                 verdict = nullCheckOut;
860             } else {
861                 verdict = storedLayer3Match.equals(statsLayer3Match);
862             }
863         }
864
865         return verdict;
866     }
867
868     private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) {
869         boolean verdict = true;
870         Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4);
871         if (checkDestNullValuesOut != null) {
872             verdict = checkDestNullValuesOut;
873         } else if(!IpAddressEquals(statsIpv4, storedIpv4)){
874             verdict = false;
875         }
876
877         return verdict;
878     }
879
880     private static Boolean checkNullValues(Object v1, Object v2) {
881         Boolean verdict = null;
882         if (v1 == null && v2 != null) {
883             verdict = Boolean.FALSE;
884         } else if (v1 != null && v2 == null) {
885             verdict = Boolean.FALSE;
886         } else if (v1 == null && v2 == null) {
887             verdict = Boolean.TRUE;
888         }
889
890         return verdict;
891     }
892
893     /**
894      * TODO: why don't we use the default Ipv4Prefix.equals()?
895      *
896      * @param statsIpAddress
897      * @param storedIpAddress
898      * @return true if IPv4prefixes equals
899      */
900     private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) {
901         IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
902         IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
903
904         if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
905             return true;
906         }
907         if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){
908             return true;
909         }
910         return false;
911     }
912
913     private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
914         return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) ==  (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
915     }
916
917     private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
918         return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
919     }
920
921     /**
922      * Method return integer version of ip address. Converted int will be mask if
923      * mask specified
924      */
925     private static IntegerIpAddress StrIpToIntIp(String ipAddresss){
926
927         String[] parts = ipAddresss.split("/");
928         String ip = parts[0];
929         int prefix;
930
931         if (parts.length < 2) {
932             prefix = 32;
933         } else {
934             prefix = Integer.parseInt(parts[1]);
935         }
936
937         IntegerIpAddress integerIpAddress = null;
938         try {
939             Inet4Address addr = (Inet4Address) InetAddress.getByName(ip);
940             byte[] addrBytes = addr.getAddress();
941             int ipInt = ((addrBytes[0] & 0xFF) << 24) |
942                     ((addrBytes[1] & 0xFF) << 16) |
943                     ((addrBytes[2] & 0xFF) << 8)  |
944                     ((addrBytes[3] & 0xFF) << 0);
945
946             int mask = 0xffffffff << 32 - prefix;
947
948             integerIpAddress = new IntegerIpAddress(ipInt, mask);
949         } catch (UnknownHostException e){
950             sucLogger.error("Failed to determine host IP address by name: {}", e.getMessage(), e);
951         }
952
953         return integerIpAddress;
954     }
955
956     static class IntegerIpAddress{
957         int ip;
958         int mask;
959         public IntegerIpAddress(int ip, int mask) {
960             this.ip = ip;
961             this.mask = mask;
962         }
963         public int getIp() {
964             return ip;
965         }
966         public int getMask() {
967             return mask;
968         }
969     }
970 }
971