6515ef31f3996f59bfa45eb9597d22dcfcf8e00f
[onosfw.git] /
1 /*\r
2  * Copyright 2015 Open Networking Laboratory\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package org.onosproject.net.statistic.impl;\r
18 \r
19 import com.google.common.base.MoreObjects;\r
20 import com.google.common.base.Predicate;\r
21 import com.google.common.collect.ImmutableSet;\r
22 import org.apache.felix.scr.annotations.Activate;\r
23 import org.apache.felix.scr.annotations.Component;\r
24 import org.apache.felix.scr.annotations.Deactivate;\r
25 import org.apache.felix.scr.annotations.Reference;\r
26 import org.apache.felix.scr.annotations.ReferenceCardinality;\r
27 import org.apache.felix.scr.annotations.Service;\r
28 import org.onosproject.cli.Comparators;\r
29 import org.onosproject.net.ConnectPoint;\r
30 import org.onosproject.net.Device;\r
31 import org.onosproject.net.Port;\r
32 import org.onosproject.net.PortNumber;\r
33 import org.onosproject.net.device.DeviceService;\r
34 import org.onosproject.net.flow.DefaultTypedFlowEntry;\r
35 import org.onosproject.net.flow.FlowEntry;\r
36 import org.onosproject.net.flow.FlowRule;\r
37 import org.onosproject.net.flow.FlowRuleEvent;\r
38 import org.onosproject.net.flow.FlowRuleListener;\r
39 import org.onosproject.net.flow.FlowRuleService;\r
40 import org.onosproject.net.flow.TypedStoredFlowEntry;\r
41 import org.onosproject.net.flow.instructions.Instruction;\r
42 import org.onosproject.net.statistic.DefaultLoad;\r
43 import org.onosproject.net.statistic.FlowStatisticService;\r
44 import org.onosproject.net.statistic.Load;\r
45 import org.onosproject.net.statistic.FlowStatisticStore;\r
46 import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;\r
47 import org.onosproject.net.statistic.TypedFlowEntryWithLoad;\r
48 \r
49 import org.slf4j.Logger;\r
50 \r
51 import java.util.ArrayList;\r
52 import java.util.HashMap;\r
53 import java.util.List;\r
54 import java.util.Map;\r
55 import java.util.Objects;\r
56 import java.util.Set;\r
57 import java.util.TreeMap;\r
58 import java.util.stream.Collectors;\r
59 \r
60 import static com.google.common.base.Preconditions.checkNotNull;\r
61 import static org.onosproject.security.AppGuard.checkPermission;\r
62 import static org.slf4j.LoggerFactory.getLogger;\r
63 import static org.onosproject.security.AppPermission.Type.*;\r
64 \r
65 /**\r
66  * Provides an implementation of the Flow Statistic Service.\r
67  */\r
68 @Component(immediate = true, enabled = true)\r
69 @Service\r
70 public class FlowStatisticManager implements FlowStatisticService {\r
71     private final Logger log = getLogger(getClass());\r
72 \r
73     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)\r
74     protected FlowRuleService flowRuleService;\r
75 \r
76     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)\r
77     protected FlowStatisticStore flowStatisticStore;\r
78 \r
79     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)\r
80     protected DeviceService deviceService;\r
81 \r
82     private final InternalFlowRuleStatsListener frListener = new InternalFlowRuleStatsListener();\r
83 \r
84     @Activate\r
85     public void activate() {\r
86         flowRuleService.addListener(frListener);\r
87         log.info("Started");\r
88     }\r
89 \r
90     @Deactivate\r
91     public void deactivate() {\r
92         flowRuleService.removeListener(frListener);\r
93         log.info("Stopped");\r
94     }\r
95 \r
96     @Override\r
97     public Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device) {\r
98         checkPermission(STATISTIC_READ);\r
99 \r
100         Map<ConnectPoint, SummaryFlowEntryWithLoad> summaryLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);\r
101 \r
102         if (device == null) {\r
103             return summaryLoad;\r
104         }\r
105 \r
106         List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));\r
107 \r
108         for (Port port : ports) {\r
109             ConnectPoint cp = new ConnectPoint(device.id(), port.number());\r
110             SummaryFlowEntryWithLoad sfe = loadSummaryPortInternal(cp);\r
111             summaryLoad.put(cp, sfe);\r
112         }\r
113 \r
114         return summaryLoad;\r
115     }\r
116 \r
117     @Override\r
118     public SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber) {\r
119         checkPermission(STATISTIC_READ);\r
120 \r
121         ConnectPoint cp = new ConnectPoint(device.id(), pNumber);\r
122         return loadSummaryPortInternal(cp);\r
123     }\r
124 \r
125     @Override\r
126     public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,\r
127                                                                   TypedStoredFlowEntry.FlowLiveType liveType,\r
128                                                                   Instruction.Type instType) {\r
129         checkPermission(STATISTIC_READ);\r
130 \r
131         Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);\r
132 \r
133         if (device == null) {\r
134             return allLoad;\r
135         }\r
136 \r
137         List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));\r
138 \r
139         for (Port port : ports) {\r
140             ConnectPoint cp = new ConnectPoint(device.id(), port.number());\r
141             List<TypedFlowEntryWithLoad> tfel = loadAllPortInternal(cp, liveType, instType);\r
142             allLoad.put(cp, tfel);\r
143         }\r
144 \r
145         return allLoad;\r
146     }\r
147 \r
148     @Override\r
149     public List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,\r
150                                                TypedStoredFlowEntry.FlowLiveType liveType,\r
151                                                Instruction.Type instType) {\r
152         checkPermission(STATISTIC_READ);\r
153 \r
154         ConnectPoint cp = new ConnectPoint(device.id(), pNumber);\r
155         return loadAllPortInternal(cp, liveType, instType);\r
156     }\r
157 \r
158     @Override\r
159     public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,\r
160                                                                    TypedStoredFlowEntry.FlowLiveType liveType,\r
161                                                                    Instruction.Type instType,\r
162                                                                    int topn) {\r
163         checkPermission(STATISTIC_READ);\r
164 \r
165         Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);\r
166 \r
167         if (device == null) {\r
168             return allLoad;\r
169         }\r
170 \r
171         List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));\r
172 \r
173         for (Port port : ports) {\r
174             ConnectPoint cp = new ConnectPoint(device.id(), port.number());\r
175             List<TypedFlowEntryWithLoad> tfel = loadTopnPortInternal(cp, liveType, instType, topn);\r
176             allLoad.put(cp, tfel);\r
177         }\r
178 \r
179         return allLoad;\r
180     }\r
181 \r
182     @Override\r
183     public List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,\r
184                                                 TypedStoredFlowEntry.FlowLiveType liveType,\r
185                                                 Instruction.Type instType,\r
186                                                 int topn) {\r
187         checkPermission(STATISTIC_READ);\r
188 \r
189         ConnectPoint cp = new ConnectPoint(device.id(), pNumber);\r
190         return loadTopnPortInternal(cp, liveType, instType, topn);\r
191     }\r
192 \r
193     private SummaryFlowEntryWithLoad loadSummaryPortInternal(ConnectPoint cp) {\r
194         checkPermission(STATISTIC_READ);\r
195 \r
196         Set<FlowEntry> currentStats;\r
197         Set<FlowEntry> previousStats;\r
198 \r
199         TypedStatistics typedStatistics;\r
200         synchronized (flowStatisticStore) {\r
201              currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);\r
202             if (currentStats == null) {\r
203                 return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());\r
204             }\r
205             previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);\r
206             if (previousStats == null) {\r
207                 return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());\r
208             }\r
209             // copy to local flow entry\r
210             typedStatistics = new TypedStatistics(currentStats, previousStats);\r
211 \r
212             // Check for validity of this stats data\r
213             checkLoadValidity(currentStats, previousStats);\r
214         }\r
215 \r
216         // current and previous set is not empty!\r
217         Set<FlowEntry> currentSet = typedStatistics.current();\r
218         Set<FlowEntry> previousSet = typedStatistics.previous();\r
219         Load totalLoad = new DefaultLoad(aggregateBytesSet(currentSet), aggregateBytesSet(previousSet),\r
220                 TypedFlowEntryWithLoad.avgPollInterval());\r
221 \r
222         Map<FlowRule, TypedStoredFlowEntry> currentMap;\r
223         Map<FlowRule, TypedStoredFlowEntry> previousMap;\r
224 \r
225         currentMap = typedStatistics.currentImmediate();\r
226         previousMap = typedStatistics.previousImmediate();\r
227         Load immediateLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),\r
228                 TypedFlowEntryWithLoad.shortPollInterval());\r
229 \r
230         currentMap = typedStatistics.currentShort();\r
231         previousMap = typedStatistics.previousShort();\r
232         Load shortLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),\r
233                 TypedFlowEntryWithLoad.shortPollInterval());\r
234 \r
235         currentMap = typedStatistics.currentMid();\r
236         previousMap = typedStatistics.previousMid();\r
237         Load midLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),\r
238                 TypedFlowEntryWithLoad.midPollInterval());\r
239 \r
240         currentMap = typedStatistics.currentLong();\r
241         previousMap = typedStatistics.previousLong();\r
242         Load longLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),\r
243                 TypedFlowEntryWithLoad.longPollInterval());\r
244 \r
245         currentMap = typedStatistics.currentUnknown();\r
246         previousMap = typedStatistics.previousUnknown();\r
247         Load unknownLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),\r
248                 TypedFlowEntryWithLoad.avgPollInterval());\r
249 \r
250         return new SummaryFlowEntryWithLoad(cp, totalLoad, immediateLoad, shortLoad, midLoad, longLoad, unknownLoad);\r
251     }\r
252 \r
253     private List<TypedFlowEntryWithLoad> loadAllPortInternal(ConnectPoint cp,\r
254                                                              TypedStoredFlowEntry.FlowLiveType liveType,\r
255                                                              Instruction.Type instType) {\r
256         checkPermission(STATISTIC_READ);\r
257 \r
258         List<TypedFlowEntryWithLoad> retTFEL = new ArrayList<>();\r
259 \r
260         Set<FlowEntry> currentStats;\r
261         Set<FlowEntry> previousStats;\r
262 \r
263         TypedStatistics typedStatistics;\r
264         synchronized (flowStatisticStore) {\r
265             currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);\r
266             if (currentStats == null) {\r
267                 return retTFEL;\r
268             }\r
269             previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);\r
270             if (previousStats == null) {\r
271                 return retTFEL;\r
272             }\r
273             // copy to local flow entry set\r
274             typedStatistics = new TypedStatistics(currentStats, previousStats);\r
275 \r
276             // Check for validity of this stats data\r
277             checkLoadValidity(currentStats, previousStats);\r
278         }\r
279 \r
280         // current and previous set is not empty!\r
281         boolean isAllLiveType = (liveType == null ? true : false); // null is all live type\r
282         boolean isAllInstType = (instType == null ? true : false); // null is all inst type\r
283 \r
284         Map<FlowRule, TypedStoredFlowEntry> currentMap;\r
285         Map<FlowRule, TypedStoredFlowEntry> previousMap;\r
286 \r
287         if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW) {\r
288             currentMap = typedStatistics.currentImmediate();\r
289             previousMap = typedStatistics.previousImmediate();\r
290 \r
291             List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,\r
292                     isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());\r
293             if (fel.size() > 0) {\r
294                 retTFEL.addAll(fel);\r
295             }\r
296         }\r
297 \r
298         if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW) {\r
299             currentMap = typedStatistics.currentShort();\r
300             previousMap = typedStatistics.previousShort();\r
301 \r
302             List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,\r
303                     isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());\r
304             if (fel.size() > 0) {\r
305                 retTFEL.addAll(fel);\r
306             }\r
307         }\r
308 \r
309         if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.MID_FLOW) {\r
310             currentMap = typedStatistics.currentMid();\r
311             previousMap = typedStatistics.previousMid();\r
312 \r
313             List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,\r
314                     isAllInstType, instType, TypedFlowEntryWithLoad.midPollInterval());\r
315             if (fel.size() > 0) {\r
316                 retTFEL.addAll(fel);\r
317             }\r
318         }\r
319 \r
320         if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.LONG_FLOW) {\r
321             currentMap = typedStatistics.currentLong();\r
322             previousMap = typedStatistics.previousLong();\r
323 \r
324             List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,\r
325                     isAllInstType, instType, TypedFlowEntryWithLoad.longPollInterval());\r
326             if (fel.size() > 0) {\r
327                 retTFEL.addAll(fel);\r
328             }\r
329         }\r
330 \r
331         if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW) {\r
332             currentMap = typedStatistics.currentUnknown();\r
333             previousMap = typedStatistics.previousUnknown();\r
334 \r
335             List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,\r
336                     isAllInstType, instType, TypedFlowEntryWithLoad.avgPollInterval());\r
337             if (fel.size() > 0) {\r
338                 retTFEL.addAll(fel);\r
339             }\r
340         }\r
341 \r
342         return retTFEL;\r
343     }\r
344 \r
345     private List<TypedFlowEntryWithLoad> typedFlowEntryLoadByInstInternal(ConnectPoint cp,\r
346                                                                       Map<FlowRule, TypedStoredFlowEntry> currentMap,\r
347                                                                       Map<FlowRule, TypedStoredFlowEntry> previousMap,\r
348                                                                       boolean isAllInstType,\r
349                                                                       Instruction.Type instType,\r
350                                                                       int liveTypePollInterval) {\r
351         List<TypedFlowEntryWithLoad> fel = new ArrayList<>();\r
352 \r
353         for (TypedStoredFlowEntry tfe : currentMap.values()) {\r
354             if (isAllInstType ||\r
355                     tfe.treatment().allInstructions().stream().\r
356                             filter(i -> i.type() == instType).\r
357                             findAny().isPresent()) {\r
358                 long currentBytes = tfe.bytes();\r
359                 long previousBytes = previousMap.getOrDefault(tfe, new DefaultTypedFlowEntry((FlowRule) tfe)).bytes();\r
360                 Load fLoad = new DefaultLoad(currentBytes, previousBytes, liveTypePollInterval);\r
361                 fel.add(new TypedFlowEntryWithLoad(cp, tfe, fLoad));\r
362             }\r
363         }\r
364 \r
365         return fel;\r
366     }\r
367 \r
368     private List<TypedFlowEntryWithLoad> loadTopnPortInternal(ConnectPoint cp,\r
369                                                              TypedStoredFlowEntry.FlowLiveType liveType,\r
370                                                              Instruction.Type instType,\r
371                                                              int topn) {\r
372         List<TypedFlowEntryWithLoad> fel = loadAllPortInternal(cp, liveType, instType);\r
373 \r
374         // Sort with descending order of load\r
375         List<TypedFlowEntryWithLoad> tfel =\r
376                 fel.stream().sorted(Comparators.TYPEFLOWENTRY_WITHLOAD_COMPARATOR).\r
377                         limit(topn).collect(Collectors.toList());\r
378 \r
379         return tfel;\r
380     }\r
381 \r
382     private long aggregateBytesSet(Set<FlowEntry> setFE) {\r
383         return setFE.stream().mapToLong(FlowEntry::bytes).sum();\r
384     }\r
385 \r
386     private long aggregateBytesMap(Map<FlowRule, TypedStoredFlowEntry> mapFE) {\r
387         return mapFE.values().stream().mapToLong(FlowEntry::bytes).sum();\r
388     }\r
389 \r
390     /**\r
391      * Internal data class holding two set of typed flow entries.\r
392      */\r
393     private static class TypedStatistics {\r
394         private final ImmutableSet<FlowEntry> currentAll;\r
395         private final ImmutableSet<FlowEntry> previousAll;\r
396 \r
397         private final Map<FlowRule, TypedStoredFlowEntry> currentImmediate = new HashMap<>();\r
398         private final Map<FlowRule, TypedStoredFlowEntry> previousImmediate = new HashMap<>();\r
399 \r
400         private final Map<FlowRule, TypedStoredFlowEntry> currentShort = new HashMap<>();\r
401         private final Map<FlowRule, TypedStoredFlowEntry> previousShort = new HashMap<>();\r
402 \r
403         private final Map<FlowRule, TypedStoredFlowEntry> currentMid = new HashMap<>();\r
404         private final Map<FlowRule, TypedStoredFlowEntry> previousMid = new HashMap<>();\r
405 \r
406         private final Map<FlowRule, TypedStoredFlowEntry> currentLong = new HashMap<>();\r
407         private final Map<FlowRule, TypedStoredFlowEntry> previousLong = new HashMap<>();\r
408 \r
409         private final Map<FlowRule, TypedStoredFlowEntry> currentUnknown = new HashMap<>();\r
410         private final Map<FlowRule, TypedStoredFlowEntry> previousUnknown = new HashMap<>();\r
411 \r
412         public TypedStatistics(Set<FlowEntry> current, Set<FlowEntry> previous) {\r
413             this.currentAll = ImmutableSet.copyOf(checkNotNull(current));\r
414             this.previousAll = ImmutableSet.copyOf(checkNotNull(previous));\r
415 \r
416             currentAll.forEach(fe -> {\r
417                 TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);\r
418 \r
419                 switch (tfe.flowLiveType()) {\r
420                     case IMMEDIATE_FLOW:\r
421                         currentImmediate.put(fe, tfe);\r
422                         break;\r
423                     case SHORT_FLOW:\r
424                         currentShort.put(fe, tfe);\r
425                         break;\r
426                     case MID_FLOW:\r
427                         currentMid.put(fe, tfe);\r
428                         break;\r
429                     case LONG_FLOW:\r
430                         currentLong.put(fe, tfe);\r
431                         break;\r
432                     default:\r
433                         currentUnknown.put(fe, tfe);\r
434                         break;\r
435                 }\r
436             });\r
437 \r
438             previousAll.forEach(fe -> {\r
439                 TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);\r
440 \r
441                 switch (tfe.flowLiveType()) {\r
442                     case IMMEDIATE_FLOW:\r
443                         if (currentImmediate.containsKey(fe)) {\r
444                             previousImmediate.put(fe, tfe);\r
445                         } else if (currentShort.containsKey(fe)) {\r
446                             previousShort.put(fe, tfe);\r
447                         } else if (currentMid.containsKey(fe)) {\r
448                             previousMid.put(fe, tfe);\r
449                         } else if (currentLong.containsKey(fe)) {\r
450                             previousLong.put(fe, tfe);\r
451                         } else {\r
452                             previousUnknown.put(fe, tfe);\r
453                         }\r
454                         break;\r
455                     case SHORT_FLOW:\r
456                         if (currentShort.containsKey(fe)) {\r
457                             previousShort.put(fe, tfe);\r
458                         } else if (currentMid.containsKey(fe)) {\r
459                             previousMid.put(fe, tfe);\r
460                         } else if (currentLong.containsKey(fe)) {\r
461                             previousLong.put(fe, tfe);\r
462                         } else {\r
463                             previousUnknown.put(fe, tfe);\r
464                         }\r
465                         break;\r
466                     case MID_FLOW:\r
467                         if (currentMid.containsKey(fe)) {\r
468                             previousMid.put(fe, tfe);\r
469                         } else if (currentLong.containsKey(fe)) {\r
470                             previousLong.put(fe, tfe);\r
471                         } else {\r
472                             previousUnknown.put(fe, tfe);\r
473                         }\r
474                         break;\r
475                     case LONG_FLOW:\r
476                         if (currentLong.containsKey(fe)) {\r
477                             previousLong.put(fe, tfe);\r
478                         } else {\r
479                             previousUnknown.put(fe, tfe);\r
480                         }\r
481                         break;\r
482                     default:\r
483                         previousUnknown.put(fe, tfe);\r
484                         break;\r
485                 }\r
486             });\r
487         }\r
488 \r
489         /**\r
490          * Returns flow entries as the current value.\r
491          *\r
492          * @return flow entries as the current value\r
493          */\r
494         public ImmutableSet<FlowEntry> current() {\r
495             return currentAll;\r
496         }\r
497 \r
498         /**\r
499          * Returns flow entries as the previous value.\r
500          *\r
501          * @return flow entries as the previous value\r
502          */\r
503         public ImmutableSet<FlowEntry> previous() {\r
504             return previousAll;\r
505         }\r
506 \r
507         public Map<FlowRule, TypedStoredFlowEntry> currentImmediate() {\r
508             return currentImmediate;\r
509         }\r
510         public Map<FlowRule, TypedStoredFlowEntry> previousImmediate() {\r
511             return previousImmediate;\r
512         }\r
513         public Map<FlowRule, TypedStoredFlowEntry> currentShort() {\r
514             return currentShort;\r
515         }\r
516         public Map<FlowRule, TypedStoredFlowEntry> previousShort() {\r
517             return previousShort;\r
518         }\r
519         public Map<FlowRule, TypedStoredFlowEntry> currentMid() {\r
520             return currentMid;\r
521         }\r
522         public Map<FlowRule, TypedStoredFlowEntry> previousMid() {\r
523             return previousMid;\r
524         }\r
525         public Map<FlowRule, TypedStoredFlowEntry> currentLong() {\r
526             return currentLong;\r
527         }\r
528         public Map<FlowRule, TypedStoredFlowEntry> previousLong() {\r
529             return previousLong;\r
530         }\r
531         public Map<FlowRule, TypedStoredFlowEntry> currentUnknown() {\r
532             return currentUnknown;\r
533         }\r
534         public Map<FlowRule, TypedStoredFlowEntry> previousUnknown() {\r
535             return previousUnknown;\r
536         }\r
537 \r
538         /**\r
539          * Validates values are not empty.\r
540          *\r
541          * @return false if either of the sets is empty. Otherwise, true.\r
542          */\r
543         public boolean isValid() {\r
544             return !(currentAll.isEmpty() || previousAll.isEmpty());\r
545         }\r
546 \r
547         @Override\r
548         public int hashCode() {\r
549             return Objects.hash(currentAll, previousAll);\r
550         }\r
551 \r
552         @Override\r
553         public boolean equals(Object obj) {\r
554             if (this == obj) {\r
555                 return true;\r
556             }\r
557             if (!(obj instanceof TypedStatistics)) {\r
558                 return false;\r
559             }\r
560             final TypedStatistics other = (TypedStatistics) obj;\r
561             return Objects.equals(this.currentAll, other.currentAll) &&\r
562                     Objects.equals(this.previousAll, other.previousAll);\r
563         }\r
564 \r
565         @Override\r
566         public String toString() {\r
567             return MoreObjects.toStringHelper(this)\r
568                     .add("current", currentAll)\r
569                     .add("previous", previousAll)\r
570                     .toString();\r
571         }\r
572     }\r
573 \r
574     private void checkLoadValidity(Set<FlowEntry> current, Set<FlowEntry> previous) {\r
575         current.stream().forEach(c -> {\r
576             FlowEntry f = previous.stream().filter(p -> c.equals(p)).\r
577                     findAny().orElse(null);\r
578             if (f != null && c.bytes() < f.bytes()) {\r
579                 log.debug("FlowStatisticManager:checkLoadValidity():" +\r
580                         "Error: " + c + " :Previous bytes=" + f.bytes() +\r
581                         " is larger than current bytes=" + c.bytes() + " !!!");\r
582             }\r
583         });\r
584 \r
585     }\r
586 \r
587     /**\r
588      * Creates a predicate that checks the instruction type of a flow entry is the same as\r
589      * the specified instruction type.\r
590      *\r
591      * @param instType instruction type to be checked\r
592      * @return predicate\r
593      */\r
594     private static Predicate<FlowEntry> hasInstructionType(Instruction.Type instType) {\r
595         return new Predicate<FlowEntry>() {\r
596             @Override\r
597             public boolean apply(FlowEntry flowEntry) {\r
598                 List<Instruction> allInstructions = flowEntry.treatment().allInstructions();\r
599 \r
600                 return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent();\r
601             }\r
602         };\r
603     }\r
604 \r
605     /**\r
606      * Internal flow rule event listener for FlowStatisticManager.\r
607      */\r
608     private class InternalFlowRuleStatsListener implements FlowRuleListener {\r
609 \r
610         @Override\r
611         public void event(FlowRuleEvent event) {\r
612             FlowRule rule = event.subject();\r
613             switch (event.type()) {\r
614                 case RULE_ADDED:\r
615                     if (rule instanceof FlowEntry) {\r
616                         flowStatisticStore.addFlowStatistic((FlowEntry) rule);\r
617                     }\r
618                     break;\r
619                 case RULE_UPDATED:\r
620                     flowStatisticStore.updateFlowStatistic((FlowEntry) rule);\r
621                     break;\r
622                 case RULE_ADD_REQUESTED:\r
623                     break;\r
624                 case RULE_REMOVE_REQUESTED:\r
625                     break;\r
626                 case RULE_REMOVED:\r
627                     flowStatisticStore.removeFlowStatistic(rule);\r
628                     break;\r
629                 default:\r
630                     log.warn("Unknown flow rule event {}", event);\r
631             }\r
632         }\r
633     }\r
634 }\r