blob: 2af9bad35f1b8915c5c6628d339a8e54bb6da68b [file] [log] [blame]
Madan Jampanic27b6b22016-02-05 11:36:31 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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
Ray Milkeya6957192017-06-01 13:04:16 -070019import java.util.ArrayList;
20import java.util.HashMap;
21import java.util.List;
22import java.util.Map;
23import java.util.Objects;
24import java.util.Set;
25import java.util.TreeMap;
26import java.util.stream.Collectors;
27
Madan Jampanic27b6b22016-02-05 11:36:31 -080028import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
31import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
33import org.apache.felix.scr.annotations.Service;
Madan Jampanic27b6b22016-02-05 11:36:31 -080034import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.Device;
36import org.onosproject.net.Port;
37import org.onosproject.net.PortNumber;
38import org.onosproject.net.device.DeviceService;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090039import org.onosproject.net.flow.DefaultFlowEntry;
Madan Jampanic27b6b22016-02-05 11:36:31 -080040import org.onosproject.net.flow.DefaultTypedFlowEntry;
41import org.onosproject.net.flow.FlowEntry;
42import org.onosproject.net.flow.FlowRule;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090043import org.onosproject.net.flow.StoredFlowEntry;
Madan Jampanic27b6b22016-02-05 11:36:31 -080044import org.onosproject.net.flow.TypedStoredFlowEntry;
45import org.onosproject.net.flow.instructions.Instruction;
46import org.onosproject.net.statistic.DefaultLoad;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090047import org.onosproject.net.statistic.FlowEntryWithLoad;
Madan Jampanic27b6b22016-02-05 11:36:31 -080048import org.onosproject.net.statistic.FlowStatisticService;
49import org.onosproject.net.statistic.Load;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090050import org.onosproject.net.statistic.PollInterval;
51import org.onosproject.net.statistic.StatisticStore;
Madan Jampanic27b6b22016-02-05 11:36:31 -080052import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;
53import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
Ray Milkeya6957192017-06-01 13:04:16 -070054import org.onosproject.utils.Comparators;
Madan Jampanic27b6b22016-02-05 11:36:31 -080055import org.slf4j.Logger;
56
Ray Milkeya6957192017-06-01 13:04:16 -070057import com.google.common.base.MoreObjects;
58import com.google.common.base.Predicate;
59import com.google.common.collect.ImmutableSet;
Madan Jampanic27b6b22016-02-05 11:36:31 -080060
61import static com.google.common.base.Preconditions.checkNotNull;
62import static org.onosproject.security.AppGuard.checkPermission;
Ray Milkeya6957192017-06-01 13:04:16 -070063import static org.onosproject.security.AppPermission.Type.STATISTIC_READ;
Madan Jampanic27b6b22016-02-05 11:36:31 -080064import static org.slf4j.LoggerFactory.getLogger;
Madan Jampanic27b6b22016-02-05 11:36:31 -080065
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
sivachidambaram subramaniandde26b62017-02-07 16:18:33 +0530282 boolean isAllLiveType = (liveType == null ? true : false); // null is all live type
Madan Jampanic27b6b22016-02-05 11:36:31 -0800283
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900284 Map<FlowRule, FlowEntry> currentMap;
285 Map<FlowRule, FlowEntry> previousMap;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800286
sivachidambaram subramaniandde26b62017-02-07 16:18:33 +0530287 if (isAllLiveType) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900288 currentMap = typedStatistics.currentAll();
289 previousMap = typedStatistics.previousAll();
290 } else {
291 switch (liveType) {
292 case IMMEDIATE:
293 currentMap = typedStatistics.currentImmediate();
294 previousMap = typedStatistics.previousImmediate();
295 break;
296 case SHORT:
297 currentMap = typedStatistics.currentShort();
298 previousMap = typedStatistics.previousShort();
299 break;
300 case MID:
301 currentMap = typedStatistics.currentMid();
302 previousMap = typedStatistics.previousMid();
303 break;
304 case LONG:
305 currentMap = typedStatistics.currentLong();
306 previousMap = typedStatistics.previousLong();
307 break;
308 case UNKNOWN:
309 currentMap = typedStatistics.currentUnknown();
310 previousMap = typedStatistics.previousUnknown();
311 break;
312 default:
313 currentMap = new HashMap<>();
314 previousMap = new HashMap<>();
315 break;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800316 }
317 }
318
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900319 return typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap, isAllInstType, instType);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800320 }
321
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900322 private List<FlowEntryWithLoad> typedFlowEntryLoadByInstInternal(ConnectPoint cp,
323 Map<FlowRule, FlowEntry> currentMap,
324 Map<FlowRule, FlowEntry> previousMap,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800325 boolean isAllInstType,
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900326 Instruction.Type instType) {
327 List<FlowEntryWithLoad> fel = new ArrayList<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800328
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900329 currentMap.values().forEach(fe -> {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800330 if (isAllInstType ||
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900331 fe.treatment().allInstructions().stream().
Madan Jampanic27b6b22016-02-05 11:36:31 -0800332 filter(i -> i.type() == instType).
333 findAny().isPresent()) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900334 long currentBytes = fe.bytes();
335 long previousBytes = previousMap.getOrDefault(fe, new DefaultFlowEntry(fe)).bytes();
336 long liveTypePollInterval = getLiveTypePollInterval(fe.liveType());
Madan Jampanic27b6b22016-02-05 11:36:31 -0800337 Load fLoad = new DefaultLoad(currentBytes, previousBytes, liveTypePollInterval);
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900338 fel.add(new FlowEntryWithLoad(cp, fe, fLoad));
Madan Jampanic27b6b22016-02-05 11:36:31 -0800339 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900340 });
Madan Jampanic27b6b22016-02-05 11:36:31 -0800341
342 return fel;
343 }
344
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900345 private List<FlowEntryWithLoad> loadTopnPortInternal(ConnectPoint cp,
346 FlowEntry.FlowLiveType liveType,
Madan Jampanic27b6b22016-02-05 11:36:31 -0800347 Instruction.Type instType,
348 int topn) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900349 List<FlowEntryWithLoad> fel = loadAllPortInternal(cp, liveType, instType);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800350
351 // Sort with descending order of load
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900352 List<FlowEntryWithLoad> retFel =
353 fel.stream().sorted(Comparators.FLOWENTRY_WITHLOAD_COMPARATOR).
Madan Jampanic27b6b22016-02-05 11:36:31 -0800354 limit(topn).collect(Collectors.toList());
355
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900356 return retFel;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800357 }
358
359 private long aggregateBytesSet(Set<FlowEntry> setFE) {
360 return setFE.stream().mapToLong(FlowEntry::bytes).sum();
361 }
362
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900363 private long aggregateBytesMap(Map<FlowRule, FlowEntry> mapFE) {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800364 return mapFE.values().stream().mapToLong(FlowEntry::bytes).sum();
365 }
366
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900367 private long getLiveTypePollInterval(FlowEntry.FlowLiveType liveType) {
368 // returns the flow live type poll interval value
369 PollInterval pollIntervalInstance = PollInterval.getInstance();
370
371 switch (liveType) {
372 case LONG:
373 return pollIntervalInstance.getLongPollInterval();
374 case MID:
375 return pollIntervalInstance.getMidPollInterval();
376 case SHORT:
377 case IMMEDIATE:
378 default: // UNKNOWN
379 return pollIntervalInstance.getPollInterval();
380 }
381 }
382
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900383 private TypedStoredFlowEntry.FlowLiveType toTypedStoredFlowEntryLiveType(FlowEntry.FlowLiveType liveType) {
384 if (liveType == null) {
385 return null;
386 }
387
388 // convert TypedStoredFlowEntry flow live type to FlowEntry one
389 switch (liveType) {
390 case IMMEDIATE:
391 return TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW;
392 case SHORT:
393 return TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW;
394 case MID:
395 return TypedStoredFlowEntry.FlowLiveType.MID_FLOW;
396 case LONG:
397 return TypedStoredFlowEntry.FlowLiveType.LONG_FLOW;
398 default:
399 return TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW;
400 }
401 }
402
403 private Map<ConnectPoint, List<TypedFlowEntryWithLoad>> toFlowEntryWithLoadMap(
404 Map<ConnectPoint, List<FlowEntryWithLoad>> loadMap) {
405 // convert FlowEntryWithLoad list to TypedFlowEntryWithLoad list
406 Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad =
407 new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
408
409 loadMap.forEach((k, v) -> {
410 List<TypedFlowEntryWithLoad> tfelList =
411 toFlowEntryWithLoad(v);
412 allLoad.put(k, tfelList);
413 });
414
415 return allLoad;
416 }
417
418 private List<TypedFlowEntryWithLoad> toFlowEntryWithLoad(List<FlowEntryWithLoad> loadList) {
419 // convert FlowEntryWithLoad list to TypedFlowEntryWithLoad list
420 List<TypedFlowEntryWithLoad> tfelList = new ArrayList<>();
421 loadList.forEach(fel -> {
422 StoredFlowEntry sfe = fel.storedFlowEntry();
423 TypedStoredFlowEntry.FlowLiveType liveType = toTypedStoredFlowEntryLiveType(sfe.liveType());
424 TypedStoredFlowEntry tfe = new DefaultTypedFlowEntry(sfe, liveType);
425 TypedFlowEntryWithLoad tfel = new TypedFlowEntryWithLoad(fel.connectPoint(), tfe, fel.load());
426 tfelList.add(tfel);
427 });
428
429 return tfelList;
430 }
431
Madan Jampanic27b6b22016-02-05 11:36:31 -0800432 /**
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900433 * Internal data class holding two set of flow entries included flow liveType.
Madan Jampanic27b6b22016-02-05 11:36:31 -0800434 */
435 private static class TypedStatistics {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900436 private final ImmutableSet<FlowEntry> current;
437 private final ImmutableSet<FlowEntry> previous;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800438
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900439 private final Map<FlowRule, FlowEntry> currentAll = new HashMap<>();
440 private final Map<FlowRule, FlowEntry> previousAll = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800441
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900442 private final Map<FlowRule, FlowEntry> currentImmediate = new HashMap<>();
443 private final Map<FlowRule, FlowEntry> previousImmediate = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800444
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900445 private final Map<FlowRule, FlowEntry> currentShort = new HashMap<>();
446 private final Map<FlowRule, FlowEntry> previousShort = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800447
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900448 private final Map<FlowRule, FlowEntry> currentMid = new HashMap<>();
449 private final Map<FlowRule, FlowEntry> previousMid = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800450
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900451 private final Map<FlowRule, FlowEntry> currentLong = new HashMap<>();
452 private final Map<FlowRule, FlowEntry> previousLong = new HashMap<>();
453
454 private final Map<FlowRule, FlowEntry> currentUnknown = new HashMap<>();
455 private final Map<FlowRule, FlowEntry> previousUnknown = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800456
457 public TypedStatistics(Set<FlowEntry> current, Set<FlowEntry> previous) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900458 this.current = ImmutableSet.copyOf(checkNotNull(current));
459 this.previous = ImmutableSet.copyOf(checkNotNull(previous));
Madan Jampanic27b6b22016-02-05 11:36:31 -0800460
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900461 current.forEach(fe -> {
462 switch (fe.liveType()) {
463 case IMMEDIATE:
464 currentImmediate.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800465 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900466 case SHORT:
467 currentShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800468 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900469 case MID:
470 currentMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800471 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900472 case LONG:
473 currentLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800474 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900475 default: // unknown
476 currentUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800477 break;
478 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900479 currentAll.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800480 });
481
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900482 previous.forEach(fe -> {
483 switch (fe.liveType()) {
484 case IMMEDIATE:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800485 if (currentImmediate.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900486 previousImmediate.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800487 } else if (currentShort.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900488 previousShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800489 } else if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900490 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800491 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900492 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800493 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900494 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800495 }
496 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900497 case SHORT:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800498 if (currentShort.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900499 previousShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800500 } else if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900501 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800502 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900503 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800504 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900505 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800506 }
507 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900508 case MID:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800509 if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900510 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800511 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900512 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800513 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900514 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800515 }
516 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900517 case LONG:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800518 if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900519 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800520 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900521 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800522 }
523 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900524 default: // unknown
525 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800526 break;
527 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900528 previousAll.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800529 });
530 }
531
532 /**
533 * Returns flow entries as the current value.
534 *
535 * @return flow entries as the current value
536 */
537 public ImmutableSet<FlowEntry> current() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900538 return current;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800539 }
540
541 /**
542 * Returns flow entries as the previous value.
543 *
544 * @return flow entries as the previous value
545 */
546 public ImmutableSet<FlowEntry> previous() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900547 return previous;
548 }
549
550 public Map<FlowRule, FlowEntry> currentAll() {
551 return currentAll;
552 }
553
554 public Map<FlowRule, FlowEntry> previousAll() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800555 return previousAll;
556 }
557
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900558 public Map<FlowRule, FlowEntry> currentImmediate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800559 return currentImmediate;
560 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900561 public Map<FlowRule, FlowEntry> previousImmediate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800562 return previousImmediate;
563 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900564 public Map<FlowRule, FlowEntry> currentShort() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800565 return currentShort;
566 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900567 public Map<FlowRule, FlowEntry> previousShort() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800568 return previousShort;
569 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900570 public Map<FlowRule, FlowEntry> currentMid() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800571 return currentMid;
572 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900573 public Map<FlowRule, FlowEntry> previousMid() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800574 return previousMid;
575 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900576 public Map<FlowRule, FlowEntry> currentLong() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800577 return currentLong;
578 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900579 public Map<FlowRule, FlowEntry> previousLong() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800580 return previousLong;
581 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900582 public Map<FlowRule, FlowEntry> currentUnknown() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800583 return currentUnknown;
584 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900585 public Map<FlowRule, FlowEntry> previousUnknown() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800586 return previousUnknown;
587 }
588
589 /**
590 * Validates values are not empty.
591 *
592 * @return false if either of the sets is empty. Otherwise, true.
593 */
594 public boolean isValid() {
595 return !(currentAll.isEmpty() || previousAll.isEmpty());
596 }
597
598 @Override
599 public int hashCode() {
600 return Objects.hash(currentAll, previousAll);
601 }
602
603 @Override
604 public boolean equals(Object obj) {
605 if (this == obj) {
606 return true;
607 }
608 if (!(obj instanceof TypedStatistics)) {
609 return false;
610 }
611 final TypedStatistics other = (TypedStatistics) obj;
612 return Objects.equals(this.currentAll, other.currentAll) &&
613 Objects.equals(this.previousAll, other.previousAll);
614 }
615
616 @Override
617 public String toString() {
618 return MoreObjects.toStringHelper(this)
619 .add("current", currentAll)
620 .add("previous", previousAll)
621 .toString();
622 }
623 }
624
625 private void checkLoadValidity(Set<FlowEntry> current, Set<FlowEntry> previous) {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700626 current.forEach(c -> {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800627 FlowEntry f = previous.stream().filter(p -> c.equals(p)).
628 findAny().orElse(null);
629 if (f != null && c.bytes() < f.bytes()) {
630 log.debug("FlowStatisticManager:checkLoadValidity():" +
631 "Error: " + c + " :Previous bytes=" + f.bytes() +
632 " is larger than current bytes=" + c.bytes() + " !!!");
633 }
634 });
635
636 }
637
638 /**
639 * Creates a predicate that checks the instruction type of a flow entry is the same as
640 * the specified instruction type.
641 *
642 * @param instType instruction type to be checked
643 * @return predicate
644 */
645 private static Predicate<FlowEntry> hasInstructionType(Instruction.Type instType) {
646 return new Predicate<FlowEntry>() {
647 @Override
648 public boolean apply(FlowEntry flowEntry) {
649 List<Instruction> allInstructions = flowEntry.treatment().allInstructions();
650
651 return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent();
652 }
653 };
654 }
655
656 /**
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900657 * Creates a predicate that checks the flow type of a flow entry is the same as
658 * the specified live type.
659 *
660 * @param liveType flow live type to be checked
661 * @return predicate
Madan Jampanic27b6b22016-02-05 11:36:31 -0800662 */
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900663 private static Predicate<FlowEntry> hasLiveType(FlowEntry.FlowLiveType liveType) {
664 return flowEntry -> flowEntry.liveType() == liveType;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800665 }
666}