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