blob: f77a9ea1ba2bb7530bf8907a567440079da2b6bf [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;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090028import org.onosproject.utils.Comparators;
Madan Jampanic27b6b22016-02-05 11:36:31 -080029import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.Device;
31import org.onosproject.net.Port;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.device.DeviceService;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090034import org.onosproject.net.flow.DefaultFlowEntry;
Madan Jampanic27b6b22016-02-05 11:36:31 -080035import org.onosproject.net.flow.DefaultTypedFlowEntry;
36import org.onosproject.net.flow.FlowEntry;
37import org.onosproject.net.flow.FlowRule;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090038import org.onosproject.net.flow.StoredFlowEntry;
Madan Jampanic27b6b22016-02-05 11:36:31 -080039import org.onosproject.net.flow.TypedStoredFlowEntry;
40import org.onosproject.net.flow.instructions.Instruction;
41import org.onosproject.net.statistic.DefaultLoad;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090042import org.onosproject.net.statistic.FlowEntryWithLoad;
Madan Jampanic27b6b22016-02-05 11:36:31 -080043import org.onosproject.net.statistic.FlowStatisticService;
44import org.onosproject.net.statistic.Load;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090045import org.onosproject.net.statistic.PollInterval;
46import org.onosproject.net.statistic.StatisticStore;
Madan Jampanic27b6b22016-02-05 11:36:31 -080047import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;
48import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
49
50import org.slf4j.Logger;
51
52import java.util.ArrayList;
53import java.util.HashMap;
54import java.util.List;
55import java.util.Map;
56import java.util.Objects;
57import java.util.Set;
58import java.util.TreeMap;
59import java.util.stream.Collectors;
60
61import static com.google.common.base.Preconditions.checkNotNull;
62import static org.onosproject.security.AppGuard.checkPermission;
63import static org.slf4j.LoggerFactory.getLogger;
64import static org.onosproject.security.AppPermission.Type.*;
65
66/**
67 * Provides an implementation of the Flow Statistic Service.
68 */
Sho SHIMIZU5c396e32016-08-12 15:19:12 -070069@Component(immediate = true)
Madan Jampanic27b6b22016-02-05 11:36:31 -080070@Service
71public class FlowStatisticManager implements FlowStatisticService {
72 private final Logger log = getLogger(getClass());
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090075 protected StatisticStore statisticStore;
Madan Jampanic27b6b22016-02-05 11:36:31 -080076
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected DeviceService deviceService;
79
Madan Jampanic27b6b22016-02-05 11:36:31 -080080 @Activate
81 public void activate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -080082 log.info("Started");
83 }
84
85 @Deactivate
86 public void deactivate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -080087 log.info("Stopped");
88 }
89
90 @Override
91 public Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device) {
92 checkPermission(STATISTIC_READ);
93
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090094 Map<ConnectPoint, SummaryFlowEntryWithLoad> summaryLoad =
95 new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
Madan Jampanic27b6b22016-02-05 11:36:31 -080096
97 if (device == null) {
98 return summaryLoad;
99 }
100
101 List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
102
103 for (Port port : ports) {
104 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
105 SummaryFlowEntryWithLoad sfe = loadSummaryPortInternal(cp);
106 summaryLoad.put(cp, sfe);
107 }
108
109 return summaryLoad;
110 }
111
112 @Override
113 public SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber) {
114 checkPermission(STATISTIC_READ);
115
116 ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
117 return loadSummaryPortInternal(cp);
118 }
119
120 @Override
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900121 public Map<ConnectPoint, List<FlowEntryWithLoad>> loadAllByType(Device device,
122 FlowEntry.FlowLiveType liveType,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800123 Instruction.Type instType) {
124 checkPermission(STATISTIC_READ);
125
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900126 Map<ConnectPoint, List<FlowEntryWithLoad>> allLoad =
127 new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800128
129 if (device == null) {
130 return allLoad;
131 }
132
133 List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
134
135 for (Port port : ports) {
136 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900137 List<FlowEntryWithLoad> fel = loadAllPortInternal(cp, liveType, instType);
138 allLoad.put(cp, fel);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800139 }
140
141 return allLoad;
142 }
143
144 @Override
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900145 public List<FlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
146 FlowEntry.FlowLiveType liveType,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800147 Instruction.Type instType) {
148 checkPermission(STATISTIC_READ);
149
150 ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
151 return loadAllPortInternal(cp, liveType, instType);
152 }
153
154 @Override
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900155 public Map<ConnectPoint, List<FlowEntryWithLoad>> loadTopnByType(Device device,
156 FlowEntry.FlowLiveType liveType,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800157 Instruction.Type instType,
158 int topn) {
159 checkPermission(STATISTIC_READ);
160
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900161 Map<ConnectPoint, List<FlowEntryWithLoad>> allLoad =
162 new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800163
164 if (device == null) {
165 return allLoad;
166 }
167
168 List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
169
170 for (Port port : ports) {
171 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900172 List<FlowEntryWithLoad> fel = loadTopnPortInternal(cp, liveType, instType, topn);
173 allLoad.put(cp, fel);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800174 }
175
176 return allLoad;
177 }
178
179 @Override
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900180 public List<FlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
181 FlowEntry.FlowLiveType liveType,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800182 Instruction.Type instType,
183 int topn) {
184 checkPermission(STATISTIC_READ);
185
186 ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
187 return loadTopnPortInternal(cp, liveType, instType, topn);
188 }
189
190 private SummaryFlowEntryWithLoad loadSummaryPortInternal(ConnectPoint cp) {
191 checkPermission(STATISTIC_READ);
192
193 Set<FlowEntry> currentStats;
194 Set<FlowEntry> previousStats;
195
196 TypedStatistics typedStatistics;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900197 synchronized (statisticStore) {
198 currentStats = statisticStore.getCurrentStatistic(cp);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800199 if (currentStats == null) {
200 return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
201 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900202 previousStats = statisticStore.getPreviousStatistic(cp);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800203 if (previousStats == null) {
204 return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
205 }
206 // copy to local flow entry
207 typedStatistics = new TypedStatistics(currentStats, previousStats);
208
209 // Check for validity of this stats data
210 checkLoadValidity(currentStats, previousStats);
211 }
212
213 // current and previous set is not empty!
214 Set<FlowEntry> currentSet = typedStatistics.current();
215 Set<FlowEntry> previousSet = typedStatistics.previous();
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900216 PollInterval pollIntervalInstance = PollInterval.getInstance();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800217
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900218 // We assume that default pollInterval is flowPollFrequency in case adaptiveFlowSampling is true or false
219 Load totalLoad = new DefaultLoad(aggregateBytesSet(currentSet), aggregateBytesSet(previousSet),
220 pollIntervalInstance.getPollInterval());
221
222 Map<FlowRule, FlowEntry> currentMap;
223 Map<FlowRule, FlowEntry> previousMap;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800224
225 currentMap = typedStatistics.currentImmediate();
226 previousMap = typedStatistics.previousImmediate();
227 Load immediateLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900228 pollIntervalInstance.getPollInterval());
Madan Jampanic27b6b22016-02-05 11:36:31 -0800229
230 currentMap = typedStatistics.currentShort();
231 previousMap = typedStatistics.previousShort();
232 Load shortLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900233 pollIntervalInstance.getPollInterval());
Madan Jampanic27b6b22016-02-05 11:36:31 -0800234
235 currentMap = typedStatistics.currentMid();
236 previousMap = typedStatistics.previousMid();
237 Load midLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900238 pollIntervalInstance.getMidPollInterval());
Madan Jampanic27b6b22016-02-05 11:36:31 -0800239
240 currentMap = typedStatistics.currentLong();
241 previousMap = typedStatistics.previousLong();
242 Load longLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900243 pollIntervalInstance.getLongPollInterval());
Madan Jampanic27b6b22016-02-05 11:36:31 -0800244
245 currentMap = typedStatistics.currentUnknown();
246 previousMap = typedStatistics.previousUnknown();
247 Load unknownLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900248 pollIntervalInstance.getPollInterval());
Madan Jampanic27b6b22016-02-05 11:36:31 -0800249
250 return new SummaryFlowEntryWithLoad(cp, totalLoad, immediateLoad, shortLoad, midLoad, longLoad, unknownLoad);
251 }
252
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900253 private List<FlowEntryWithLoad> loadAllPortInternal(ConnectPoint cp,
254 FlowEntry.FlowLiveType liveType,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800255 Instruction.Type instType) {
256 checkPermission(STATISTIC_READ);
257
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900258 List<FlowEntryWithLoad> retFel = new ArrayList<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800259
260 Set<FlowEntry> currentStats;
261 Set<FlowEntry> previousStats;
262
263 TypedStatistics typedStatistics;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900264 synchronized (statisticStore) {
265 currentStats = statisticStore.getCurrentStatistic(cp);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800266 if (currentStats == null) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900267 return retFel;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800268 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900269 previousStats = statisticStore.getPreviousStatistic(cp);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800270 if (previousStats == null) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900271 return retFel;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800272 }
273 // copy to local flow entry set
274 typedStatistics = new TypedStatistics(currentStats, previousStats);
275
276 // Check for validity of this stats data
277 checkLoadValidity(currentStats, previousStats);
278 }
279
280 // current and previous set is not empty!
Madan Jampanic27b6b22016-02-05 11:36:31 -0800281 boolean isAllInstType = (instType == null ? true : false); // null is all inst type
282
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900283 Map<FlowRule, FlowEntry> currentMap;
284 Map<FlowRule, FlowEntry> previousMap;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800285
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900286 if (isAllInstType) {
287 currentMap = typedStatistics.currentAll();
288 previousMap = typedStatistics.previousAll();
289 } else {
290 switch (liveType) {
291 case IMMEDIATE:
292 currentMap = typedStatistics.currentImmediate();
293 previousMap = typedStatistics.previousImmediate();
294 break;
295 case SHORT:
296 currentMap = typedStatistics.currentShort();
297 previousMap = typedStatistics.previousShort();
298 break;
299 case MID:
300 currentMap = typedStatistics.currentMid();
301 previousMap = typedStatistics.previousMid();
302 break;
303 case LONG:
304 currentMap = typedStatistics.currentLong();
305 previousMap = typedStatistics.previousLong();
306 break;
307 case UNKNOWN:
308 currentMap = typedStatistics.currentUnknown();
309 previousMap = typedStatistics.previousUnknown();
310 break;
311 default:
312 currentMap = new HashMap<>();
313 previousMap = new HashMap<>();
314 break;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800315 }
316 }
317
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900318 return typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap, isAllInstType, instType);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800319 }
320
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900321 private List<FlowEntryWithLoad> typedFlowEntryLoadByInstInternal(ConnectPoint cp,
322 Map<FlowRule, FlowEntry> currentMap,
323 Map<FlowRule, FlowEntry> previousMap,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800324 boolean isAllInstType,
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900325 Instruction.Type instType) {
326 List<FlowEntryWithLoad> fel = new ArrayList<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800327
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900328 currentMap.values().forEach(fe -> {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800329 if (isAllInstType ||
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900330 fe.treatment().allInstructions().stream().
Madan Jampanic27b6b22016-02-05 11:36:31 -0800331 filter(i -> i.type() == instType).
332 findAny().isPresent()) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900333 long currentBytes = fe.bytes();
334 long previousBytes = previousMap.getOrDefault(fe, new DefaultFlowEntry(fe)).bytes();
335 long liveTypePollInterval = getLiveTypePollInterval(fe.liveType());
Madan Jampanic27b6b22016-02-05 11:36:31 -0800336 Load fLoad = new DefaultLoad(currentBytes, previousBytes, liveTypePollInterval);
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900337 fel.add(new FlowEntryWithLoad(cp, fe, fLoad));
Madan Jampanic27b6b22016-02-05 11:36:31 -0800338 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900339 });
Madan Jampanic27b6b22016-02-05 11:36:31 -0800340
341 return fel;
342 }
343
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900344 private List<FlowEntryWithLoad> loadTopnPortInternal(ConnectPoint cp,
345 FlowEntry.FlowLiveType liveType,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800346 Instruction.Type instType,
347 int topn) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900348 List<FlowEntryWithLoad> fel = loadAllPortInternal(cp, liveType, instType);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800349
350 // Sort with descending order of load
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900351 List<FlowEntryWithLoad> retFel =
352 fel.stream().sorted(Comparators.FLOWENTRY_WITHLOAD_COMPARATOR).
Madan Jampanic27b6b22016-02-05 11:36:31 -0800353 limit(topn).collect(Collectors.toList());
354
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900355 return retFel;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800356 }
357
358 private long aggregateBytesSet(Set<FlowEntry> setFE) {
359 return setFE.stream().mapToLong(FlowEntry::bytes).sum();
360 }
361
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900362 private long aggregateBytesMap(Map<FlowRule, FlowEntry> mapFE) {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800363 return mapFE.values().stream().mapToLong(FlowEntry::bytes).sum();
364 }
365
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900366 private long getLiveTypePollInterval(FlowEntry.FlowLiveType liveType) {
367 // returns the flow live type poll interval value
368 PollInterval pollIntervalInstance = PollInterval.getInstance();
369
370 switch (liveType) {
371 case LONG:
372 return pollIntervalInstance.getLongPollInterval();
373 case MID:
374 return pollIntervalInstance.getMidPollInterval();
375 case SHORT:
376 case IMMEDIATE:
377 default: // UNKNOWN
378 return pollIntervalInstance.getPollInterval();
379 }
380 }
381
382 //
383 // Deprecated interfaces...
384 //
385 @Override
386 public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
387 TypedStoredFlowEntry.FlowLiveType liveType,
388 Instruction.Type instType) {
389 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
390
391 Map<ConnectPoint, List<FlowEntryWithLoad>> loadMap = loadAllByType(device, type, instType);
392
393 return toFlowEntryWithLoadMap(loadMap);
394 }
395
396 @Override
397 public List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
398 TypedStoredFlowEntry.FlowLiveType liveType,
399 Instruction.Type instType) {
400 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
401
402 List<FlowEntryWithLoad> loadList = loadAllByType(device, pNumber, type, instType);
403
404 return toFlowEntryWithLoad(loadList);
405 }
406
407 @Override
408 public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
409 TypedStoredFlowEntry.FlowLiveType liveType,
410 Instruction.Type instType,
411 int topn) {
412 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
413
414 Map<ConnectPoint, List<FlowEntryWithLoad>> loadMap = loadTopnByType(device, type, instType, topn);
415
416 return toFlowEntryWithLoadMap(loadMap);
417 }
418
419 @Override
420 public List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
421 TypedStoredFlowEntry.FlowLiveType liveType,
422 Instruction.Type instType,
423 int topn) {
424 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
425
426 List<FlowEntryWithLoad> loadList = loadTopnByType(device, pNumber, type, instType, topn);
427
428 return toFlowEntryWithLoad(loadList);
429 }
430
431 private FlowEntry.FlowLiveType toFlowEntryLiveType(TypedStoredFlowEntry.FlowLiveType liveType) {
432 if (liveType == null) {
433 return null;
434 }
435
436 // convert TypedStoredFlowEntry flow live type to FlowEntry one
437 switch (liveType) {
438 case IMMEDIATE_FLOW:
439 return FlowEntry.FlowLiveType.IMMEDIATE;
440 case SHORT_FLOW:
441 return FlowEntry.FlowLiveType.SHORT;
442 case MID_FLOW:
443 return FlowEntry.FlowLiveType.MID;
444 case LONG_FLOW:
445 return FlowEntry.FlowLiveType.LONG;
446 default:
447 return FlowEntry.FlowLiveType.UNKNOWN;
448 }
449 }
450
451 private TypedStoredFlowEntry.FlowLiveType toTypedStoredFlowEntryLiveType(FlowEntry.FlowLiveType liveType) {
452 if (liveType == null) {
453 return null;
454 }
455
456 // convert TypedStoredFlowEntry flow live type to FlowEntry one
457 switch (liveType) {
458 case IMMEDIATE:
459 return TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW;
460 case SHORT:
461 return TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW;
462 case MID:
463 return TypedStoredFlowEntry.FlowLiveType.MID_FLOW;
464 case LONG:
465 return TypedStoredFlowEntry.FlowLiveType.LONG_FLOW;
466 default:
467 return TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW;
468 }
469 }
470
471 private Map<ConnectPoint, List<TypedFlowEntryWithLoad>> toFlowEntryWithLoadMap(
472 Map<ConnectPoint, List<FlowEntryWithLoad>> loadMap) {
473 // convert FlowEntryWithLoad list to TypedFlowEntryWithLoad list
474 Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad =
475 new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
476
477 loadMap.forEach((k, v) -> {
478 List<TypedFlowEntryWithLoad> tfelList =
479 toFlowEntryWithLoad(v);
480 allLoad.put(k, tfelList);
481 });
482
483 return allLoad;
484 }
485
486 private List<TypedFlowEntryWithLoad> toFlowEntryWithLoad(List<FlowEntryWithLoad> loadList) {
487 // convert FlowEntryWithLoad list to TypedFlowEntryWithLoad list
488 List<TypedFlowEntryWithLoad> tfelList = new ArrayList<>();
489 loadList.forEach(fel -> {
490 StoredFlowEntry sfe = fel.storedFlowEntry();
491 TypedStoredFlowEntry.FlowLiveType liveType = toTypedStoredFlowEntryLiveType(sfe.liveType());
492 TypedStoredFlowEntry tfe = new DefaultTypedFlowEntry(sfe, liveType);
493 TypedFlowEntryWithLoad tfel = new TypedFlowEntryWithLoad(fel.connectPoint(), tfe, fel.load());
494 tfelList.add(tfel);
495 });
496
497 return tfelList;
498 }
499
Madan Jampanic27b6b22016-02-05 11:36:31 -0800500 /**
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900501 * Internal data class holding two set of flow entries included flow liveType.
Madan Jampanic27b6b22016-02-05 11:36:31 -0800502 */
503 private static class TypedStatistics {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900504 private final ImmutableSet<FlowEntry> current;
505 private final ImmutableSet<FlowEntry> previous;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800506
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900507 private final Map<FlowRule, FlowEntry> currentAll = new HashMap<>();
508 private final Map<FlowRule, FlowEntry> previousAll = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800509
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900510 private final Map<FlowRule, FlowEntry> currentImmediate = new HashMap<>();
511 private final Map<FlowRule, FlowEntry> previousImmediate = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800512
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900513 private final Map<FlowRule, FlowEntry> currentShort = new HashMap<>();
514 private final Map<FlowRule, FlowEntry> previousShort = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800515
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900516 private final Map<FlowRule, FlowEntry> currentMid = new HashMap<>();
517 private final Map<FlowRule, FlowEntry> previousMid = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800518
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900519 private final Map<FlowRule, FlowEntry> currentLong = new HashMap<>();
520 private final Map<FlowRule, FlowEntry> previousLong = new HashMap<>();
521
522 private final Map<FlowRule, FlowEntry> currentUnknown = new HashMap<>();
523 private final Map<FlowRule, FlowEntry> previousUnknown = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800524
525 public TypedStatistics(Set<FlowEntry> current, Set<FlowEntry> previous) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900526 this.current = ImmutableSet.copyOf(checkNotNull(current));
527 this.previous = ImmutableSet.copyOf(checkNotNull(previous));
Madan Jampanic27b6b22016-02-05 11:36:31 -0800528
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900529 current.forEach(fe -> {
530 switch (fe.liveType()) {
531 case IMMEDIATE:
532 currentImmediate.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800533 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900534 case SHORT:
535 currentShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800536 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900537 case MID:
538 currentMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800539 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900540 case LONG:
541 currentLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800542 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900543 default: // unknown
544 currentUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800545 break;
546 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900547 currentAll.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800548 });
549
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900550 previous.forEach(fe -> {
551 switch (fe.liveType()) {
552 case IMMEDIATE:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800553 if (currentImmediate.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900554 previousImmediate.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800555 } else if (currentShort.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900556 previousShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800557 } else if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900558 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800559 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900560 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800561 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900562 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800563 }
564 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900565 case SHORT:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800566 if (currentShort.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900567 previousShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800568 } else if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900569 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800570 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900571 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800572 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900573 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800574 }
575 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900576 case MID:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800577 if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900578 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800579 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900580 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800581 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900582 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800583 }
584 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900585 case LONG:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800586 if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900587 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800588 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900589 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800590 }
591 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900592 default: // unknown
593 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800594 break;
595 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900596 previousAll.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800597 });
598 }
599
600 /**
601 * Returns flow entries as the current value.
602 *
603 * @return flow entries as the current value
604 */
605 public ImmutableSet<FlowEntry> current() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900606 return current;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800607 }
608
609 /**
610 * Returns flow entries as the previous value.
611 *
612 * @return flow entries as the previous value
613 */
614 public ImmutableSet<FlowEntry> previous() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900615 return previous;
616 }
617
618 public Map<FlowRule, FlowEntry> currentAll() {
619 return currentAll;
620 }
621
622 public Map<FlowRule, FlowEntry> previousAll() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800623 return previousAll;
624 }
625
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900626 public Map<FlowRule, FlowEntry> currentImmediate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800627 return currentImmediate;
628 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900629 public Map<FlowRule, FlowEntry> previousImmediate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800630 return previousImmediate;
631 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900632 public Map<FlowRule, FlowEntry> currentShort() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800633 return currentShort;
634 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900635 public Map<FlowRule, FlowEntry> previousShort() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800636 return previousShort;
637 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900638 public Map<FlowRule, FlowEntry> currentMid() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800639 return currentMid;
640 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900641 public Map<FlowRule, FlowEntry> previousMid() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800642 return previousMid;
643 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900644 public Map<FlowRule, FlowEntry> currentLong() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800645 return currentLong;
646 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900647 public Map<FlowRule, FlowEntry> previousLong() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800648 return previousLong;
649 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900650 public Map<FlowRule, FlowEntry> currentUnknown() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800651 return currentUnknown;
652 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900653 public Map<FlowRule, FlowEntry> previousUnknown() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800654 return previousUnknown;
655 }
656
657 /**
658 * Validates values are not empty.
659 *
660 * @return false if either of the sets is empty. Otherwise, true.
661 */
662 public boolean isValid() {
663 return !(currentAll.isEmpty() || previousAll.isEmpty());
664 }
665
666 @Override
667 public int hashCode() {
668 return Objects.hash(currentAll, previousAll);
669 }
670
671 @Override
672 public boolean equals(Object obj) {
673 if (this == obj) {
674 return true;
675 }
676 if (!(obj instanceof TypedStatistics)) {
677 return false;
678 }
679 final TypedStatistics other = (TypedStatistics) obj;
680 return Objects.equals(this.currentAll, other.currentAll) &&
681 Objects.equals(this.previousAll, other.previousAll);
682 }
683
684 @Override
685 public String toString() {
686 return MoreObjects.toStringHelper(this)
687 .add("current", currentAll)
688 .add("previous", previousAll)
689 .toString();
690 }
691 }
692
693 private void checkLoadValidity(Set<FlowEntry> current, Set<FlowEntry> previous) {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700694 current.forEach(c -> {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800695 FlowEntry f = previous.stream().filter(p -> c.equals(p)).
696 findAny().orElse(null);
697 if (f != null && c.bytes() < f.bytes()) {
698 log.debug("FlowStatisticManager:checkLoadValidity():" +
699 "Error: " + c + " :Previous bytes=" + f.bytes() +
700 " is larger than current bytes=" + c.bytes() + " !!!");
701 }
702 });
703
704 }
705
706 /**
707 * Creates a predicate that checks the instruction type of a flow entry is the same as
708 * the specified instruction type.
709 *
710 * @param instType instruction type to be checked
711 * @return predicate
712 */
713 private static Predicate<FlowEntry> hasInstructionType(Instruction.Type instType) {
714 return new Predicate<FlowEntry>() {
715 @Override
716 public boolean apply(FlowEntry flowEntry) {
717 List<Instruction> allInstructions = flowEntry.treatment().allInstructions();
718
719 return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent();
720 }
721 };
722 }
723
724 /**
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900725 * Creates a predicate that checks the flow type of a flow entry is the same as
726 * the specified live type.
727 *
728 * @param liveType flow live type to be checked
729 * @return predicate
Madan Jampanic27b6b22016-02-05 11:36:31 -0800730 */
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900731 private static Predicate<FlowEntry> hasLiveType(FlowEntry.FlowLiveType liveType) {
732 return flowEntry -> flowEntry.liveType() == liveType;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800733 }
734}