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.net.Inet4Address;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.List;
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;
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
121 public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener,
122 OpendaylightMeterStatisticsListener,
123 OpendaylightFlowStatisticsListener,
124 OpendaylightPortStatisticsListener,
125 OpendaylightFlowTableStatisticsListener,
126 OpendaylightQueueStatisticsListener{
128 private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
130 private final StatisticsProvider statisticsManager;
131 private final MultipartMessageManager messageManager;
133 private int unaccountedFlowsCounter = 1;
139 public StatisticsUpdateCommiter(final StatisticsProvider manager){
141 this.statisticsManager = manager;
142 this.messageManager = this.statisticsManager.getMultipartMessageManager();
145 public StatisticsProvider getStatisticsManager(){
146 return statisticsManager;
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()))
155 final NodeKey key = new NodeKey(notification.getId());
157 //Add statistics to local cache
158 this.statisticsManager.getStatisticsAger(notification.getId()).updateMeterConfigStats(notification.getMeterConfigStats());
160 //Publish data to configuration data store
161 List<MeterConfigStats> meterConfigStatsList = notification.getMeterConfigStats();
162 DataModificationTransaction it = this.statisticsManager.startChange();
164 for(MeterConfigStats meterConfigStats : meterConfigStatsList){
165 MeterBuilder meterBuilder = new MeterBuilder();
166 MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
167 meterBuilder.setKey(meterKey);
169 InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
170 .augmentation(FlowCapableNode.class)
171 .child(Meter.class,meterKey).toInstance();
173 NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
174 MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
175 stats.fieldsFrom(meterConfigStats);
176 meterConfig.setMeterConfigStats(stats.build());
178 //Update augmented data
179 meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
180 it.putOperationalData(meterRef, meterBuilder.build());
186 public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
188 //Check if response is for the request statistics-manager sent.
189 if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
192 final NodeKey key = new NodeKey(notification.getId());
194 //Publish data to configuration data store
195 List<MeterStats> meterStatsList = notification.getMeterStats();
196 DataModificationTransaction it = this.statisticsManager.startChange();
198 for(MeterStats meterStats : meterStatsList){
200 MeterBuilder meterBuilder = new MeterBuilder();
201 MeterKey meterKey = new MeterKey(meterStats.getMeterId());
202 meterBuilder.setKey(meterKey);
204 InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
205 .augmentation(FlowCapableNode.class)
206 .child(Meter.class,meterKey).toInstance();
208 NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
209 MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
210 stats.fieldsFrom(meterStats);
211 meterStatsBuilder.setMeterStatistics(stats.build());
213 //Update augmented data
214 meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
215 it.putOperationalData(meterRef, meterBuilder.build());
221 public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
223 //Check if response is for the request statistics-manager sent.
224 if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
227 final NodeKey key = new NodeKey(notification.getId());
229 //Add statistics to local cache
230 this.statisticsManager.getStatisticsAger(key.getId()).updateGroupDescStats(notification.getGroupDescStats());
232 //Publish data to configuration data store
233 List<GroupDescStats> groupDescStatsList = notification.getGroupDescStats();
234 DataModificationTransaction it = this.statisticsManager.startChange();
236 for(GroupDescStats groupDescStats : groupDescStatsList){
238 GroupBuilder groupBuilder = new GroupBuilder();
239 GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
240 groupBuilder.setKey(groupKey);
242 InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
243 .augmentation(FlowCapableNode.class)
244 .child(Group.class,groupKey).toInstance();
246 NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
247 GroupDescBuilder stats = new GroupDescBuilder();
248 stats.fieldsFrom(groupDescStats);
249 groupDesc.setGroupDesc(stats.build());
251 //Update augmented data
252 groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
254 it.putOperationalData(groupRef, groupBuilder.build());
260 public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
262 //Check if response is for the request statistics-manager sent.
263 if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
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();
271 for(GroupStats groupStats : groupStatsList){
273 GroupBuilder groupBuilder = new GroupBuilder();
274 GroupKey groupKey = new GroupKey(groupStats.getGroupId());
275 groupBuilder.setKey(groupKey);
277 InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
278 .augmentation(FlowCapableNode.class)
279 .child(Group.class,groupKey).toInstance();
281 NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
282 GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
283 stats.fieldsFrom(groupStats);
284 groupStatisticsBuilder.setGroupStatistics(stats.build());
286 //Update augmented data
287 groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
288 it.putOperationalData(groupRef, groupBuilder.build());
294 public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) {
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());
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);
308 final NodeBuilder nodeData = new NodeBuilder();
309 nodeData.setKey(key);
311 NodeMeterFeaturesBuilder nodeMeterFeatures= new NodeMeterFeaturesBuilder();
312 nodeMeterFeatures.setMeterFeatures(meterFeature.build());
314 //Update augmented data
315 nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
317 InstanceIdentifier<? extends Object> refValue = ref.getValue();
318 it.putOperationalData(refValue, nodeData.build());
323 public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) {
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());
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);
336 final NodeBuilder nodeData = new NodeBuilder();
337 nodeData.setKey(key);
339 NodeGroupFeaturesBuilder nodeGroupFeatures= new NodeGroupFeaturesBuilder();
340 nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
342 //Update augmented data
343 nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
345 InstanceIdentifier<? extends Object> refValue = ref.getValue();
346 it.putOperationalData(refValue, nodeData.build());
351 public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) {
353 //Check if response is for the request statistics-manager sent.
354 if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
357 sucLogger.debug("Received flow stats update : {}",notification.toString());
359 final NodeKey key = new NodeKey(notification.getId());
360 final NodeStatisticsAger nsa = this.statisticsManager.getStatisticsAger(key.getId());
361 DataModificationTransaction it = this.statisticsManager.startChange();
363 for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){
364 short tableId = map.getTableId();
367 boolean foundOriginalFlow = false;
369 FlowBuilder flowBuilder = new FlowBuilder();
371 FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
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);
395 Flow flowRule = flow.build();
397 FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
398 stats.setByteCount(map.getByteCount());
399 stats.setPacketCount(map.getPacketCount());
400 stats.setDuration(map.getDuration());
402 GenericStatistics flowStats = stats.build();
404 //Augment the data to the flow node
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);
427 flowStatisticsData.setFlowStatistics(flowStatistics.build());
429 sucLogger.debug("Flow : {}",flowRule.toString());
430 sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
432 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
433 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
435 Table table= (Table)it.readConfigurationData(tableRef);
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
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);
459 it.putOperationalData(flowRef, flowBuilder.build());
464 table= (Table)it.readOperationalData(tableRef);
465 if(!foundOriginalFlow && table != null){
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;
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);
488 it.putOperationalData(flowRef, flowBuilder.build());
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());
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);
511 it.putOperationalData(flowRef, flowBuilder.build());
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()))
523 NodeKey key = new NodeKey(notification.getId());
525 Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId());
528 DataModificationTransaction it = this.statisticsManager.startChange();
530 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
531 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
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());
540 sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key);
542 TableBuilder tableBuilder = new TableBuilder();
543 tableBuilder.setKey(new TableKey(tableId));
544 tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
545 it.putOperationalData(tableRef, tableBuilder.build());
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()))
557 NodeKey key = new NodeKey(notification.getId());
559 List<NodeConnectorStatisticsAndPortNumberMap> portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap();
560 DataModificationTransaction it = this.statisticsManager.startChange();
562 for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){
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());
578 //Augment data to the node-connector
579 FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
580 new FlowCapableNodeConnectorStatisticsDataBuilder();
582 statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
584 InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
586 NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef);
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());
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()))
604 NodeKey key = new NodeKey(notification.getId());
606 List<FlowTableAndStatisticsMap> flowTablesStatsList = notification.getFlowTableAndStatisticsMap();
607 DataModificationTransaction it = this.statisticsManager.startChange();
609 for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){
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();
614 FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
616 FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
617 statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
618 statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
619 statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
621 statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build());
623 sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key);
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());
634 public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
636 //Check if response is for the request statistics-manager sent.
637 if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
640 NodeKey key = new NodeKey(notification.getId());
642 //Add statistics to local cache
643 NodeStatisticsAger nsa = this.statisticsManager.getStatisticsAger(key.getId());
645 List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
646 DataModificationTransaction it = this.statisticsManager.startChange();
648 for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
650 QueueEntry queueEntry = nsa.new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
651 nsa.updateQueueStats(queueEntry);
653 FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
655 FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
657 queueStatisticsBuilder.fieldsFrom(swQueueStats);
659 queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
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();
668 QueueBuilder queueBuilder = new QueueBuilder();
669 queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
670 queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
672 sucLogger.debug("Augmenting queue statistics {} of queue {} to port {}"
673 ,queueStatisticsDataBuilder.build().toString(),
674 swQueueStats.getQueueId(),
675 swQueueStats.getNodeConnectorId());
677 it.putOperationalData(queueRef, queueBuilder.build());
682 private static NodeRef getNodeRef(NodeKey nodeKey){
683 InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
684 return new NodeRef(builder.toInstance());
687 public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
688 if (statsFlow.getClass() != storedFlow.getClass()) {
691 if (statsFlow.getContainerName()== null) {
692 if (storedFlow.getContainerName()!= null) {
695 } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
698 if (statsFlow.getMatch()== null) {
699 if (storedFlow.getMatch() != null) {
702 } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
703 else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
706 if (storedFlow.getPriority() == null) {
707 if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
710 } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
713 if (statsFlow.getTableId() == null) {
714 if (storedFlow.getTableId() != null) {
717 } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
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
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.
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.
748 public static boolean matchEquals(Match statsFlow, Match storedFlow) {
749 if (statsFlow == storedFlow) {
752 if (storedFlow.getClass() != statsFlow.getClass()) {
755 if (storedFlow.getEthernetMatch() == null) {
756 if (statsFlow.getEthernetMatch() != null) {
759 } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) {
762 if (storedFlow.getIcmpv4Match()== null) {
763 if (statsFlow.getIcmpv4Match() != null) {
766 } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) {
769 if (storedFlow.getIcmpv6Match() == null) {
770 if (statsFlow.getIcmpv6Match() != null) {
773 } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) {
776 if (storedFlow.getInPhyPort() == null) {
777 if (statsFlow.getInPhyPort() != null) {
780 } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) {
783 if (storedFlow.getInPort()== null) {
784 if (statsFlow.getInPort() != null) {
787 } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) {
790 if (storedFlow.getIpMatch()== null) {
791 if (statsFlow.getIpMatch() != null) {
794 } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) {
797 if (storedFlow.getLayer3Match()== null) {
798 if (statsFlow.getLayer3Match() != null) {
801 } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) {
804 if (storedFlow.getLayer4Match()== null) {
805 if (statsFlow.getLayer4Match() != null) {
808 } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) {
811 if (storedFlow.getMetadata() == null) {
812 if (statsFlow.getMetadata() != null) {
815 } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) {
818 if (storedFlow.getProtocolMatchFields() == null) {
819 if (statsFlow.getProtocolMatchFields() != null) {
822 } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) {
825 if (storedFlow.getTunnel()== null) {
826 if (statsFlow.getTunnel() != null) {
829 } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) {
832 if (storedFlow.getVlanMatch()== null) {
833 if (statsFlow.getVlanMatch() != null) {
836 } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) {
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;
849 verdict = compareNullSafe(
850 storedIpv4Match.getIpv4Destination(), statsIpv4Match.getIpv4Destination());
853 verdict = compareNullSafe(
854 statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source());
857 Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
858 if (nullCheckOut != null) {
859 verdict = nullCheckOut;
861 verdict = storedLayer3Match.equals(statsLayer3Match);
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)){
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;
894 * TODO: why don't we use the default Ipv4Prefix.equals()?
896 * @param statsIpAddress
897 * @param storedIpAddress
898 * @return true if IPv4prefixes equals
900 private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) {
901 IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
902 IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
904 if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
907 if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){
913 private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
914 return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
917 private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
918 return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
922 * Method return integer version of ip address. Converted int will be mask if
925 private static IntegerIpAddress StrIpToIntIp(String ipAddresss){
927 String[] parts = ipAddresss.split("/");
928 String ip = parts[0];
931 if (parts.length < 2) {
934 prefix = Integer.parseInt(parts[1]);
937 IntegerIpAddress integerIpAddress = null;
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);
946 int mask = 0xffffffff << 32 - prefix;
948 integerIpAddress = new IntegerIpAddress(ipInt, mask);
949 } catch (UnknownHostException e){
950 sucLogger.error("Failed to determine host IP address by name: {}", e.getMessage(), e);
953 return integerIpAddress;
956 static class IntegerIpAddress{
959 public IntegerIpAddress(int ip, int mask) {
966 public int getMask() {