blob: 1287211d26928a19ea08ee3438b3f4c4183a5d55 [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
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
383 //
384 // Deprecated interfaces...
385 //
386 @Override
387 public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
388 TypedStoredFlowEntry.FlowLiveType liveType,
389 Instruction.Type instType) {
390 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
391
392 Map<ConnectPoint, List<FlowEntryWithLoad>> loadMap = loadAllByType(device, type, instType);
393
394 return toFlowEntryWithLoadMap(loadMap);
395 }
396
397 @Override
398 public List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
399 TypedStoredFlowEntry.FlowLiveType liveType,
400 Instruction.Type instType) {
401 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
402
403 List<FlowEntryWithLoad> loadList = loadAllByType(device, pNumber, type, instType);
404
405 return toFlowEntryWithLoad(loadList);
406 }
407
408 @Override
409 public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
410 TypedStoredFlowEntry.FlowLiveType liveType,
411 Instruction.Type instType,
412 int topn) {
413 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
414
415 Map<ConnectPoint, List<FlowEntryWithLoad>> loadMap = loadTopnByType(device, type, instType, topn);
416
417 return toFlowEntryWithLoadMap(loadMap);
418 }
419
420 @Override
421 public List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
422 TypedStoredFlowEntry.FlowLiveType liveType,
423 Instruction.Type instType,
424 int topn) {
425 FlowEntry.FlowLiveType type = toFlowEntryLiveType(liveType);
426
427 List<FlowEntryWithLoad> loadList = loadTopnByType(device, pNumber, type, instType, topn);
428
429 return toFlowEntryWithLoad(loadList);
430 }
431
432 private FlowEntry.FlowLiveType toFlowEntryLiveType(TypedStoredFlowEntry.FlowLiveType liveType) {
433 if (liveType == null) {
434 return null;
435 }
436
437 // convert TypedStoredFlowEntry flow live type to FlowEntry one
438 switch (liveType) {
439 case IMMEDIATE_FLOW:
440 return FlowEntry.FlowLiveType.IMMEDIATE;
441 case SHORT_FLOW:
442 return FlowEntry.FlowLiveType.SHORT;
443 case MID_FLOW:
444 return FlowEntry.FlowLiveType.MID;
445 case LONG_FLOW:
446 return FlowEntry.FlowLiveType.LONG;
447 default:
448 return FlowEntry.FlowLiveType.UNKNOWN;
449 }
450 }
451
452 private TypedStoredFlowEntry.FlowLiveType toTypedStoredFlowEntryLiveType(FlowEntry.FlowLiveType liveType) {
453 if (liveType == null) {
454 return null;
455 }
456
457 // convert TypedStoredFlowEntry flow live type to FlowEntry one
458 switch (liveType) {
459 case IMMEDIATE:
460 return TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW;
461 case SHORT:
462 return TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW;
463 case MID:
464 return TypedStoredFlowEntry.FlowLiveType.MID_FLOW;
465 case LONG:
466 return TypedStoredFlowEntry.FlowLiveType.LONG_FLOW;
467 default:
468 return TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW;
469 }
470 }
471
472 private Map<ConnectPoint, List<TypedFlowEntryWithLoad>> toFlowEntryWithLoadMap(
473 Map<ConnectPoint, List<FlowEntryWithLoad>> loadMap) {
474 // convert FlowEntryWithLoad list to TypedFlowEntryWithLoad list
475 Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad =
476 new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
477
478 loadMap.forEach((k, v) -> {
479 List<TypedFlowEntryWithLoad> tfelList =
480 toFlowEntryWithLoad(v);
481 allLoad.put(k, tfelList);
482 });
483
484 return allLoad;
485 }
486
487 private List<TypedFlowEntryWithLoad> toFlowEntryWithLoad(List<FlowEntryWithLoad> loadList) {
488 // convert FlowEntryWithLoad list to TypedFlowEntryWithLoad list
489 List<TypedFlowEntryWithLoad> tfelList = new ArrayList<>();
490 loadList.forEach(fel -> {
491 StoredFlowEntry sfe = fel.storedFlowEntry();
492 TypedStoredFlowEntry.FlowLiveType liveType = toTypedStoredFlowEntryLiveType(sfe.liveType());
493 TypedStoredFlowEntry tfe = new DefaultTypedFlowEntry(sfe, liveType);
494 TypedFlowEntryWithLoad tfel = new TypedFlowEntryWithLoad(fel.connectPoint(), tfe, fel.load());
495 tfelList.add(tfel);
496 });
497
498 return tfelList;
499 }
500
Madan Jampanic27b6b22016-02-05 11:36:31 -0800501 /**
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900502 * Internal data class holding two set of flow entries included flow liveType.
Madan Jampanic27b6b22016-02-05 11:36:31 -0800503 */
504 private static class TypedStatistics {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900505 private final ImmutableSet<FlowEntry> current;
506 private final ImmutableSet<FlowEntry> previous;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800507
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900508 private final Map<FlowRule, FlowEntry> currentAll = new HashMap<>();
509 private final Map<FlowRule, FlowEntry> previousAll = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800510
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900511 private final Map<FlowRule, FlowEntry> currentImmediate = new HashMap<>();
512 private final Map<FlowRule, FlowEntry> previousImmediate = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800513
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900514 private final Map<FlowRule, FlowEntry> currentShort = new HashMap<>();
515 private final Map<FlowRule, FlowEntry> previousShort = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800516
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900517 private final Map<FlowRule, FlowEntry> currentMid = new HashMap<>();
518 private final Map<FlowRule, FlowEntry> previousMid = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800519
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900520 private final Map<FlowRule, FlowEntry> currentLong = new HashMap<>();
521 private final Map<FlowRule, FlowEntry> previousLong = new HashMap<>();
522
523 private final Map<FlowRule, FlowEntry> currentUnknown = new HashMap<>();
524 private final Map<FlowRule, FlowEntry> previousUnknown = new HashMap<>();
Madan Jampanic27b6b22016-02-05 11:36:31 -0800525
526 public TypedStatistics(Set<FlowEntry> current, Set<FlowEntry> previous) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900527 this.current = ImmutableSet.copyOf(checkNotNull(current));
528 this.previous = ImmutableSet.copyOf(checkNotNull(previous));
Madan Jampanic27b6b22016-02-05 11:36:31 -0800529
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900530 current.forEach(fe -> {
531 switch (fe.liveType()) {
532 case IMMEDIATE:
533 currentImmediate.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800534 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900535 case SHORT:
536 currentShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800537 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900538 case MID:
539 currentMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800540 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900541 case LONG:
542 currentLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800543 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900544 default: // unknown
545 currentUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800546 break;
547 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900548 currentAll.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800549 });
550
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900551 previous.forEach(fe -> {
552 switch (fe.liveType()) {
553 case IMMEDIATE:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800554 if (currentImmediate.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900555 previousImmediate.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800556 } else if (currentShort.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900557 previousShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800558 } else if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900559 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800560 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900561 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800562 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900563 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800564 }
565 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900566 case SHORT:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800567 if (currentShort.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900568 previousShort.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800569 } else if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900570 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800571 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900572 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800573 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900574 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800575 }
576 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900577 case MID:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800578 if (currentMid.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900579 previousMid.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800580 } else if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900581 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800582 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900583 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800584 }
585 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900586 case LONG:
Madan Jampanic27b6b22016-02-05 11:36:31 -0800587 if (currentLong.containsKey(fe)) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900588 previousLong.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800589 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900590 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800591 }
592 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900593 default: // unknown
594 previousUnknown.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800595 break;
596 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900597 previousAll.put(fe, fe);
Madan Jampanic27b6b22016-02-05 11:36:31 -0800598 });
599 }
600
601 /**
602 * Returns flow entries as the current value.
603 *
604 * @return flow entries as the current value
605 */
606 public ImmutableSet<FlowEntry> current() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900607 return current;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800608 }
609
610 /**
611 * Returns flow entries as the previous value.
612 *
613 * @return flow entries as the previous value
614 */
615 public ImmutableSet<FlowEntry> previous() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900616 return previous;
617 }
618
619 public Map<FlowRule, FlowEntry> currentAll() {
620 return currentAll;
621 }
622
623 public Map<FlowRule, FlowEntry> previousAll() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800624 return previousAll;
625 }
626
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900627 public Map<FlowRule, FlowEntry> currentImmediate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800628 return currentImmediate;
629 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900630 public Map<FlowRule, FlowEntry> previousImmediate() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800631 return previousImmediate;
632 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900633 public Map<FlowRule, FlowEntry> currentShort() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800634 return currentShort;
635 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900636 public Map<FlowRule, FlowEntry> previousShort() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800637 return previousShort;
638 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900639 public Map<FlowRule, FlowEntry> currentMid() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800640 return currentMid;
641 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900642 public Map<FlowRule, FlowEntry> previousMid() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800643 return previousMid;
644 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900645 public Map<FlowRule, FlowEntry> currentLong() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800646 return currentLong;
647 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900648 public Map<FlowRule, FlowEntry> previousLong() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800649 return previousLong;
650 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900651 public Map<FlowRule, FlowEntry> currentUnknown() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800652 return currentUnknown;
653 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900654 public Map<FlowRule, FlowEntry> previousUnknown() {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800655 return previousUnknown;
656 }
657
658 /**
659 * Validates values are not empty.
660 *
661 * @return false if either of the sets is empty. Otherwise, true.
662 */
663 public boolean isValid() {
664 return !(currentAll.isEmpty() || previousAll.isEmpty());
665 }
666
667 @Override
668 public int hashCode() {
669 return Objects.hash(currentAll, previousAll);
670 }
671
672 @Override
673 public boolean equals(Object obj) {
674 if (this == obj) {
675 return true;
676 }
677 if (!(obj instanceof TypedStatistics)) {
678 return false;
679 }
680 final TypedStatistics other = (TypedStatistics) obj;
681 return Objects.equals(this.currentAll, other.currentAll) &&
682 Objects.equals(this.previousAll, other.previousAll);
683 }
684
685 @Override
686 public String toString() {
687 return MoreObjects.toStringHelper(this)
688 .add("current", currentAll)
689 .add("previous", previousAll)
690 .toString();
691 }
692 }
693
694 private void checkLoadValidity(Set<FlowEntry> current, Set<FlowEntry> previous) {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700695 current.forEach(c -> {
Madan Jampanic27b6b22016-02-05 11:36:31 -0800696 FlowEntry f = previous.stream().filter(p -> c.equals(p)).
697 findAny().orElse(null);
698 if (f != null && c.bytes() < f.bytes()) {
699 log.debug("FlowStatisticManager:checkLoadValidity():" +
700 "Error: " + c + " :Previous bytes=" + f.bytes() +
701 " is larger than current bytes=" + c.bytes() + " !!!");
702 }
703 });
704
705 }
706
707 /**
708 * Creates a predicate that checks the instruction type of a flow entry is the same as
709 * the specified instruction type.
710 *
711 * @param instType instruction type to be checked
712 * @return predicate
713 */
714 private static Predicate<FlowEntry> hasInstructionType(Instruction.Type instType) {
715 return new Predicate<FlowEntry>() {
716 @Override
717 public boolean apply(FlowEntry flowEntry) {
718 List<Instruction> allInstructions = flowEntry.treatment().allInstructions();
719
720 return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent();
721 }
722 };
723 }
724
725 /**
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900726 * Creates a predicate that checks the flow type of a flow entry is the same as
727 * the specified live type.
728 *
729 * @param liveType flow live type to be checked
730 * @return predicate
Madan Jampanic27b6b22016-02-05 11:36:31 -0800731 */
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900732 private static Predicate<FlowEntry> hasLiveType(FlowEntry.FlowLiveType liveType) {
733 return flowEntry -> flowEntry.liveType() == liveType;
Madan Jampanic27b6b22016-02-05 11:36:31 -0800734 }
735}