blob: c67f2e995acd9e621b3a773f69469858cf64cd67 [file] [log] [blame]
Brian O'Connor8c685362015-12-05 15:27:27 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Brian O'Connor8c685362015-12-05 15:27:27 -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.provider.of.flow.impl;
18
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090019import com.google.common.collect.Iterables;
20import org.onlab.osgi.DefaultServiceDirectory;
21import org.onosproject.net.DeviceId;
Charles Chan14967c22015-12-07 11:11:50 -080022import org.onosproject.net.driver.DriverService;
Brian O'Connor8c685362015-12-05 15:27:27 -080023import org.onosproject.net.flow.FlowEntry;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090024import org.onosproject.net.flow.FlowRuleService;
Brian O'Connor8c685362015-12-05 15:27:27 -080025import org.onosproject.net.flow.StoredFlowEntry;
Brian O'Connor8c685362015-12-05 15:27:27 -080026import org.onosproject.net.flow.instructions.Instruction;
27import org.onosproject.net.flow.instructions.Instructions;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090028import org.onosproject.net.statistic.DefaultLoad;
29import org.onosproject.net.statistic.PollInterval;
30import org.onosproject.openflow.controller.Dpid;
Brian O'Connor8c685362015-12-05 15:27:27 -080031import org.onosproject.openflow.controller.OpenFlowSwitch;
32import org.onosproject.openflow.controller.RoleState;
33import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
34import org.projectfloodlight.openflow.protocol.match.Match;
35import org.projectfloodlight.openflow.types.OFPort;
36import org.projectfloodlight.openflow.types.TableId;
37import org.slf4j.Logger;
38
Brian O'Connor8c685362015-12-05 15:27:27 -080039import java.util.Optional;
Brian O'Connor8c685362015-12-05 15:27:27 -080040import java.util.concurrent.Executors;
41import java.util.concurrent.ScheduledExecutorService;
42import java.util.concurrent.ScheduledFuture;
43import java.util.concurrent.TimeUnit;
44
45import static com.google.common.base.Preconditions.checkNotNull;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090046import static java.lang.Thread.sleep;
Brian O'Connor8c685362015-12-05 15:27:27 -080047import static org.onlab.util.Tools.groupedThreads;
Brian O'Connor8c685362015-12-05 15:27:27 -080048import static org.slf4j.LoggerFactory.getLogger;
49
50/**
51 * Efficiently and adaptively collects flow statistics for the specified switch.
52 */
Thomas Vachuskaa394b952016-06-14 15:02:09 -070053public class NewAdaptiveFlowStatsCollector implements SwitchDataCollector {
Brian O'Connor8c685362015-12-05 15:27:27 -080054 private final Logger log = getLogger(getClass());
55
Jonathan Hart84f4f312016-03-03 08:17:11 -080056 private static final String CHECK_AND_MOVE_LOG =
57 "checkAndMoveLiveFlowInternal: flowId={}, state={}, afterLiveType={}"
58 + ", liveTime={}, life={}, bytes={}, packets={}, fromLastSeen={}"
59 + ", priority={}, selector={}, treatment={} dpid={}";
60
61 private static final String CHECK_AND_MOVE_COUNT_LOG =
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090062 "checkAndMoveLiveFlowAll: Total Flow_Count={}, "
Jonathan Hart84f4f312016-03-03 08:17:11 -080063 + ", IMMEDIATE_FLOW_Count={}, SHORT_FLOW_Count={}"
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090064 + ", MID_FLOW_Count={}, LONG_FLOW_Count={}, UNKNOWN_FLOW_Count={}";
Jonathan Hart84f4f312016-03-03 08:17:11 -080065
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090066 private static final int SLEEP_LOOP_COUNT = 10;
67 private static final int SLEEP_MS = 100;
Jonathan Hart84f4f312016-03-03 08:17:11 -080068
Charles Chan14967c22015-12-07 11:11:50 -080069 private final DriverService driverService;
Brian O'Connor8c685362015-12-05 15:27:27 -080070 private final OpenFlowSwitch sw;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +090071 private final DeviceId did;
Brian O'Connor8c685362015-12-05 15:27:27 -080072
73 private ScheduledExecutorService adaptiveFlowStatsScheduler =
HIGUCHI Yutad9e01052016-04-14 09:31:42 -070074 Executors.newScheduledThreadPool(4, groupedThreads("onos/flow", "device-stats-collector-%d", log));
Brian O'Connor8c685362015-12-05 15:27:27 -080075 private ScheduledFuture<?> calAndShortFlowsThread;
76 private ScheduledFuture<?> midFlowsThread;
77 private ScheduledFuture<?> longFlowsThread;
78
79 // Task that calculates all flowEntries' FlowLiveType and collects stats IMMEDIATE flows every calAndPollInterval
80 private CalAndShortFlowsTask calAndShortFlowsTask;
81 // Task that collects stats MID flows every 2*calAndPollInterval
82 private MidFlowsTask midFlowsTask;
83 // Task that collects stats LONG flows every 3*calAndPollInterval
84 private LongFlowsTask longFlowsTask;
85
86 private static final int CAL_AND_POLL_TIMES = 1; // must be always 0
87 private static final int MID_POLL_TIMES = 2; // variable greater or equal than 1
88 private static final int LONG_POLL_TIMES = 3; // variable greater or equal than MID_POLL_TIMES
89 //TODO: make ENTIRE_POLL_TIMES configurable with enable or disable
90 // must be variable greater or equal than common multiple of MID_POLL_TIMES and LONG_POLL_TIMES
91 private static final int ENTIRE_POLL_TIMES = 6;
92
93 private static final int DEFAULT_CAL_AND_POLL_FREQUENCY = 5;
94 private static final int MIN_CAL_AND_POLL_FREQUENCY = 2;
95 private static final int MAX_CAL_AND_POLL_FREQUENCY = 60;
96
97 private int calAndPollInterval; // CAL_AND_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
98 private int midPollInterval; // MID_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
99 private int longPollInterval; // LONG_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
100 // only used for checking condition at each task if it collects entire flows from a given switch or not
101 private int entirePollInterval; // ENTIRE_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
102
103 // Number of call count of each Task,
104 // for undoing collection except only entire flows collecting task in CalAndShortFlowsTask
105 private int callCountCalAndShortFlowsTask = 0; // increased CAL_AND_POLL_TIMES whenever Task is called
106 private int callCountMidFlowsTask = 0; // increased MID_POLL_TIMES whenever Task is called
107 private int callCountLongFlowsTask = 0; // increased LONG_POLL_TIMES whenever Task is called
108
Brian O'Connor8c685362015-12-05 15:27:27 -0800109 private boolean isFirstTimeStart = true;
110
111 public static final long NO_FLOW_MISSING_XID = (-1);
112 private long flowMissingXid = NO_FLOW_MISSING_XID;
113
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900114 private FlowRuleService flowRuleService;
115
Brian O'Connor8c685362015-12-05 15:27:27 -0800116 /**
117 * Creates a new adaptive collector for the given switch and default cal_and_poll frequency.
118 *
Thomas Vachuska708d3032016-02-18 11:11:46 -0800119 * @param driverService driver service reference
120 * @param sw switch to pull
121 * @param pollInterval cal and immediate poll frequency in seconds
Brian O'Connor8c685362015-12-05 15:27:27 -0800122 */
Thomas Vachuska708d3032016-02-18 11:11:46 -0800123 NewAdaptiveFlowStatsCollector(DriverService driverService, OpenFlowSwitch sw, int pollInterval) {
Charles Chan14967c22015-12-07 11:11:50 -0800124 this.driverService = driverService;
Brian O'Connor8c685362015-12-05 15:27:27 -0800125 this.sw = sw;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900126 this.did = DeviceId.deviceId(Dpid.uri(sw.getId()));
127
128 flowRuleService = get(FlowRuleService.class);
129
Brian O'Connor8c685362015-12-05 15:27:27 -0800130 initMemberVars(pollInterval);
131 }
132
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900133 /**
134 * Returns the reference to the implementation of the specified service.
135 *
136 * @param serviceClass service class
137 * @param <T> type of service
138 * @return service implementation
139 * @throws org.onlab.osgi.ServiceNotFoundException if service is unavailable
140 */
141 private static <T> T get(Class<T> serviceClass) {
142 return DefaultServiceDirectory.getService(serviceClass);
143 }
144
Brian O'Connor8c685362015-12-05 15:27:27 -0800145 // check calAndPollInterval validity and set all pollInterval values and finally initialize each task call count
146 private void initMemberVars(int pollInterval) {
147 if (pollInterval < MIN_CAL_AND_POLL_FREQUENCY) {
148 this.calAndPollInterval = MIN_CAL_AND_POLL_FREQUENCY;
149 } else if (pollInterval >= MAX_CAL_AND_POLL_FREQUENCY) {
150 this.calAndPollInterval = MAX_CAL_AND_POLL_FREQUENCY;
151 } else {
152 this.calAndPollInterval = pollInterval;
153 }
154
155 calAndPollInterval = CAL_AND_POLL_TIMES * calAndPollInterval;
156 midPollInterval = MID_POLL_TIMES * calAndPollInterval;
157 longPollInterval = LONG_POLL_TIMES * calAndPollInterval;
158 entirePollInterval = ENTIRE_POLL_TIMES * calAndPollInterval;
159
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900160 // Set the PollInterval values for statistic manager and others usage
161 DefaultLoad.setPollInterval(calAndPollInterval);
162
163 PollInterval pollInterval1Instance = PollInterval.getInstance();
164
165 pollInterval1Instance.setPollInterval(calAndPollInterval);
166 pollInterval1Instance.setMidPollInterval(midPollInterval);
167 pollInterval1Instance.setLongPollInterval(longPollInterval);
168 pollInterval1Instance.setEntirePollInterval(entirePollInterval);
169
Brian O'Connor8c685362015-12-05 15:27:27 -0800170 callCountCalAndShortFlowsTask = 0;
171 callCountMidFlowsTask = 0;
172 callCountLongFlowsTask = 0;
173
174 flowMissingXid = NO_FLOW_MISSING_XID;
175 }
176
177 /**
178 * Adjusts adaptive poll frequency.
179 *
180 * @param pollInterval poll frequency in seconds
181 */
182 synchronized void adjustCalAndPollInterval(int pollInterval) {
183 initMemberVars(pollInterval);
184
185 if (calAndShortFlowsThread != null) {
186 calAndShortFlowsThread.cancel(false);
187 }
188 if (midFlowsThread != null) {
189 midFlowsThread.cancel(false);
190 }
191 if (longFlowsThread != null) {
192 longFlowsThread.cancel(false);
193 }
194
195 calAndShortFlowsTask = new CalAndShortFlowsTask();
196 calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
197 calAndShortFlowsTask,
198 0,
199 calAndPollInterval,
200 TimeUnit.SECONDS);
201
202 midFlowsTask = new MidFlowsTask();
203 midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
204 midFlowsTask,
205 0,
206 midPollInterval,
207 TimeUnit.SECONDS);
208
209 longFlowsTask = new LongFlowsTask();
210 longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
211 longFlowsTask,
212 0,
213 longPollInterval,
214 TimeUnit.SECONDS);
215
Jonathan Hart84f4f312016-03-03 08:17:11 -0800216 log.debug("calAndPollInterval={} is adjusted", calAndPollInterval);
Brian O'Connor8c685362015-12-05 15:27:27 -0800217 }
218
219 private class CalAndShortFlowsTask implements Runnable {
220 @Override
221 public void run() {
222 if (sw.getRole() == RoleState.MASTER) {
223 log.trace("CalAndShortFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
224
225 if (isFirstTimeStart) {
226 // isFirstTimeStart, get entire flow stats from a given switch sw
227 log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats at first time start for {}",
228 sw.getStringId());
229 ofFlowStatsRequestAllSend();
230
231 callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES;
232 isFirstTimeStart = false;
Palash Kala948ac4b2017-05-17 13:13:06 +0900233 } else if (callCountCalAndShortFlowsTask >= ENTIRE_POLL_TIMES) {
Brian O'Connor8c685362015-12-05 15:27:27 -0800234 // entire_poll_times, get entire flow stats from a given switch sw
235 log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats for {}", sw.getStringId());
236 ofFlowStatsRequestAllSend();
237
238 callCountCalAndShortFlowsTask = CAL_AND_POLL_TIMES;
239 //TODO: check flows deleted in switch, but exist in controller flow table, then remove them
240 //
241 } else {
242 calAndShortFlowsTaskInternal();
243 callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES;
244 }
245 }
246 }
247 }
248
249 // send openflow flow stats request message with getting all flow entries to a given switch sw
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900250 private synchronized void ofFlowStatsRequestAllSend() {
Brian O'Connor8c685362015-12-05 15:27:27 -0800251 OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest()
252 .setMatch(sw.factory().matchWildcardAll())
253 .setTableId(TableId.ALL)
254 .setOutPort(OFPort.NO_MASK)
255 .build();
256
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900257 // set the request xid to check the reply in OpenFlowRuleProvider
258 // After processing the reply of this request message,
259 // this must be set to NO_FLOW_MISSING_XID(-1) by provider
260 setFlowMissingXid(request.getXid());
261 log.debug("ofFlowStatsRequestAllSend: request={}, dpid={}",
Jonathan Hart84f4f312016-03-03 08:17:11 -0800262 request.toString(), sw.getStringId());
Brian O'Connor8c685362015-12-05 15:27:27 -0800263
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900264 sw.sendMsg(request);
Brian O'Connor8c685362015-12-05 15:27:27 -0800265 }
266
267 // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw
268 private void ofFlowStatsRequestFlowSend(FlowEntry fe) {
269 // set find match
270 Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(),
Charles Chan14967c22015-12-07 11:11:50 -0800271 Optional.of(driverService)).buildMatch();
Brian O'Connor8c685362015-12-05 15:27:27 -0800272 // set find tableId
273 TableId tableId = TableId.of(fe.tableId());
274 // set output port
275 Instruction ins = fe.treatment().allInstructions().stream()
276 .filter(i -> (i.type() == Instruction.Type.OUTPUT))
277 .findFirst()
278 .orElse(null);
279 OFPort ofPort = OFPort.NO_MASK;
280 if (ins != null) {
281 Instructions.OutputInstruction out = (Instructions.OutputInstruction) ins;
282 ofPort = OFPort.of((int) ((out.port().toLong())));
283 }
284
285 OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest()
286 .setMatch(match)
287 .setTableId(tableId)
288 .setOutPort(ofPort)
289 .build();
290
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900291 // Wait for 1 second until the FlowRuleProvider finishes to process FlowStatReply message
292 int loop = 0;
293 boolean interrupted = false;
294 while (!interrupted && getFlowMissingXid() != NO_FLOW_MISSING_XID) {
295 if (loop++ < SLEEP_LOOP_COUNT) {
296 log.debug("ofFlowStatsRequestFlowSend: previous FlowStatsRequestAll (xid={})" +
297 " does not be processed yet, do sleep for {} ms, for {}",
298 getFlowMissingXid(),
299 SLEEP_MS,
300 sw.getStringId());
301 try {
302 sleep(SLEEP_MS);
303 } catch (InterruptedException ie) {
304 log.debug("ofFlowStatsRequestFlowSend: Interrupted Exception = {}, for {}",
305 ie.toString(),
306 sw.getStringId());
307 // for exiting while loop gracefully
308 interrupted = true;
Ray Milkey5c7d4882018-02-05 14:50:39 -0800309 Thread.currentThread().interrupt();
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900310 }
311 } else {
312 log.debug("ofFlowStatsRequestFlowSend: previous FlowStatsRequestAll (xid={})" +
313 " does not be processed yet, for {} ms," +
314 " just set xid with NO_FLOW_MISSING_XID, for {}",
315 getFlowMissingXid(),
316 loop * SLEEP_MS,
317 sw.getStringId());
Brian O'Connor8c685362015-12-05 15:27:27 -0800318
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900319 setFlowMissingXid(NO_FLOW_MISSING_XID);
320 break;
321 }
Brian O'Connor8c685362015-12-05 15:27:27 -0800322 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900323
324 sw.sendMsg(request);
325
Brian O'Connor8c685362015-12-05 15:27:27 -0800326 }
327
328 private void calAndShortFlowsTaskInternal() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900329 checkAndMoveLiveFlowAll();
Brian O'Connor8c685362015-12-05 15:27:27 -0800330
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900331 ofFlowStatsRequestInternal(FlowEntry.FlowLiveType.SHORT);
332 }
333
334 private void ofFlowStatsRequestInternal(FlowEntry.FlowLiveType liveType) {
335
336 Iterable<FlowEntry> flowEntries =
337 flowRuleService.getFlowEntriesByLiveType(did, liveType);
338
339 flowEntries.forEach(fe -> {
Brian O'Connor8c685362015-12-05 15:27:27 -0800340 ofFlowStatsRequestFlowSend(fe);
341 });
342 }
343
344 private class MidFlowsTask implements Runnable {
345 @Override
346 public void run() {
347 if (sw.getRole() == RoleState.MASTER) {
348 log.trace("MidFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
349
350 // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw
Palash Kala948ac4b2017-05-17 13:13:06 +0900351 if (callCountMidFlowsTask >= ENTIRE_POLL_TIMES) {
Brian O'Connor8c685362015-12-05 15:27:27 -0800352 callCountMidFlowsTask = MID_POLL_TIMES;
353 } else {
354 midFlowsTaskInternal();
355 callCountMidFlowsTask += MID_POLL_TIMES;
356 }
357 }
358 }
359 }
360
361 private void midFlowsTaskInternal() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900362 ofFlowStatsRequestInternal(FlowEntry.FlowLiveType.MID);
Brian O'Connor8c685362015-12-05 15:27:27 -0800363 }
364
365 private class LongFlowsTask implements Runnable {
366 @Override
367 public void run() {
368 if (sw.getRole() == RoleState.MASTER) {
369 log.trace("LongFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
370
371 // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw
Palash Kala948ac4b2017-05-17 13:13:06 +0900372 if (callCountLongFlowsTask >= ENTIRE_POLL_TIMES) {
Brian O'Connor8c685362015-12-05 15:27:27 -0800373 callCountLongFlowsTask = LONG_POLL_TIMES;
374 } else {
375 longFlowsTaskInternal();
376 callCountLongFlowsTask += LONG_POLL_TIMES;
377 }
378 }
379 }
380 }
381
382 private void longFlowsTaskInternal() {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900383 ofFlowStatsRequestInternal(FlowEntry.FlowLiveType.LONG);
Brian O'Connor8c685362015-12-05 15:27:27 -0800384 }
385
386 /**
Jonathan Hart84f4f312016-03-03 08:17:11 -0800387 * Starts adaptive flow statistic collection.
Brian O'Connor8c685362015-12-05 15:27:27 -0800388 */
389 public synchronized void start() {
390 log.debug("Starting AdaptiveStats collection thread for {}", sw.getStringId());
391 callCountCalAndShortFlowsTask = 0;
392 callCountMidFlowsTask = 0;
393 callCountLongFlowsTask = 0;
394
395 isFirstTimeStart = true;
396
397 // Initially start polling quickly. Then drop down to configured value
398 calAndShortFlowsTask = new CalAndShortFlowsTask();
399 calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
400 calAndShortFlowsTask,
401 1,
402 calAndPollInterval,
403 TimeUnit.SECONDS);
404
405 midFlowsTask = new MidFlowsTask();
406 midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
407 midFlowsTask,
408 1,
409 midPollInterval,
410 TimeUnit.SECONDS);
411
412 longFlowsTask = new LongFlowsTask();
413 longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
414 longFlowsTask,
415 1,
416 longPollInterval,
417 TimeUnit.SECONDS);
418
419 log.info("Started");
420 }
421
422 /**
Jonathan Hart84f4f312016-03-03 08:17:11 -0800423 * Stops adaptive flow statistic collection.
Brian O'Connor8c685362015-12-05 15:27:27 -0800424 */
425 public synchronized void stop() {
426 log.debug("Stopping AdaptiveStats collection thread for {}", sw.getStringId());
427 if (calAndShortFlowsThread != null) {
428 calAndShortFlowsThread.cancel(true);
429 }
430 if (midFlowsThread != null) {
431 midFlowsThread.cancel(true);
432 }
433 if (longFlowsThread != null) {
434 longFlowsThread.cancel(true);
435 }
436
437 adaptiveFlowStatsScheduler.shutdownNow();
438
439 isFirstTimeStart = false;
440
441 log.info("Stopped");
442 }
443
444 /**
Jonathan Hart84f4f312016-03-03 08:17:11 -0800445 * Returns flowMissingXid that indicates the execution of flowMissing process or not(NO_FLOW_MISSING_XID(-1)).
Brian O'Connor8c685362015-12-05 15:27:27 -0800446 *
447 * @return xid of missing flow
448 */
449 public long getFlowMissingXid() {
450 return flowMissingXid;
451 }
452
453 /**
Jonathan Hart84f4f312016-03-03 08:17:11 -0800454 * Sets flowMissingXid, namely OFFlowStatsRequest match any ALL message Id.
Brian O'Connor8c685362015-12-05 15:27:27 -0800455 *
456 * @param flowMissingXid the OFFlowStatsRequest message Id
Brian O'Connor8c685362015-12-05 15:27:27 -0800457 */
458 public void setFlowMissingXid(long flowMissingXid) {
459 this.flowMissingXid = flowMissingXid;
460 }
461
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900462 /**
463 * Calculates the flow live type.
464 *
465 * @param life the flow life time in seconds
466 * @return computed flow live type
467 */
468 public FlowEntry.FlowLiveType calFlowLiveType(long life) {
469 if (life < 0) {
470 return FlowEntry.FlowLiveType.UNKNOWN;
471 } else if (life < calAndPollInterval) {
472 return FlowEntry.FlowLiveType.IMMEDIATE;
473 } else if (life < midPollInterval) {
474 return FlowEntry.FlowLiveType.SHORT;
475 } else if (life < longPollInterval) {
476 return FlowEntry.FlowLiveType.MID;
477 } else { // >= longPollInterval
478 return FlowEntry.FlowLiveType.LONG;
479 }
480 }
Brian O'Connor8c685362015-12-05 15:27:27 -0800481
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900482 /**
483 * Calculates and set the flow live type.
484 * It maybe called pushFlowMetrics of FlowRuleService for the ReplyFlowStat message
485 * at the first time and every entire polling time.
486 *
487 * @param fe the flow entry rule
488 * @return computed flow live type
489 */
490 public FlowEntry.FlowLiveType calAndSetFlowLiveType(StoredFlowEntry fe) {
491 checkNotNull(fe);
Brian O'Connor8c685362015-12-05 15:27:27 -0800492
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900493 long life = fe.life();
Brian O'Connor8c685362015-12-05 15:27:27 -0800494
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900495 if (life < 0) {
496 fe.setLiveType(FlowEntry.FlowLiveType.UNKNOWN);
497 } else if (life < calAndPollInterval) {
498 fe.setLiveType(FlowEntry.FlowLiveType.IMMEDIATE);
499 } else if (life < midPollInterval) {
500 fe.setLiveType(FlowEntry.FlowLiveType.SHORT);
501 } else if (life < longPollInterval) {
502 fe.setLiveType(FlowEntry.FlowLiveType.MID);
503 } else { // >= longPollInterval
504 fe.setLiveType(FlowEntry.FlowLiveType.LONG);
Brian O'Connor8c685362015-12-05 15:27:27 -0800505 }
506
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900507 return fe.liveType();
508 }
Brian O'Connor8c685362015-12-05 15:27:27 -0800509
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900510 /**
511 * Check and move live type for all type flow entries in table at every calAndPollInterval time.
512 *
513 */
514 private void checkAndMoveLiveFlowAll() {
Brian O'Connor8c685362015-12-05 15:27:27 -0800515
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900516 Iterable<FlowEntry> flowEntries = flowRuleService.getFlowEntries(did);
Brian O'Connor8c685362015-12-05 15:27:27 -0800517
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900518 flowEntries.forEach(fe -> {
519 checkAndMoveLiveFlowInternal((StoredFlowEntry) fe);
520 });
Brian O'Connor8c685362015-12-05 15:27:27 -0800521
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900522 // print table counts for debug
523 if (log.isDebugEnabled()) {
524 Iterable<FlowEntry> fes;
525 synchronized (this) {
526 long totalFlowCount = flowRuleService.getFlowRuleCount();
527 fes = flowRuleService.getFlowEntriesByLiveType(
528 did, FlowEntry.FlowLiveType.IMMEDIATE);
529 long immediateFlowCount = Iterables.size(fes);
530 fes = flowRuleService.getFlowEntriesByLiveType(
531 did, FlowEntry.FlowLiveType.SHORT);
532 long shortFlowCount = Iterables.size(fes);
533 fes = flowRuleService.getFlowEntriesByLiveType(
534 did, FlowEntry.FlowLiveType.MID);
535 long midFlowCount = Iterables.size(fes);
536 fes = flowRuleService.getFlowEntriesByLiveType(
537 did, FlowEntry.FlowLiveType.LONG);
538 long longFlowCount = Iterables.size(fes);
539 fes = flowRuleService.getFlowEntriesByLiveType(
540 did, FlowEntry.FlowLiveType.UNKNOWN);
541 long unknownFlowCount = Iterables.size(fes);
Brian O'Connor8c685362015-12-05 15:27:27 -0800542
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900543 log.trace(CHECK_AND_MOVE_COUNT_LOG, totalFlowCount,
544 immediateFlowCount, shortFlowCount, midFlowCount, longFlowCount, unknownFlowCount);
Brian O'Connor8c685362015-12-05 15:27:27 -0800545
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900546 if (immediateFlowCount < 0) {
547 log.error("Immediate flow count is negative");
Jonathan Hart84f4f312016-03-03 08:17:11 -0800548 }
Brian O'Connor8c685362015-12-05 15:27:27 -0800549 }
550 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900551 log.trace("checkAndMoveLiveFlowAll, AdaptiveStats for {}", sw.getStringId());
552 }
Brian O'Connor8c685362015-12-05 15:27:27 -0800553
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900554 // check and set the flow live type based on current time
555 private boolean checkAndMoveLiveFlowInternal(StoredFlowEntry fe) {
556 long fromLastSeen = ((System.currentTimeMillis() - fe.lastSeen()) / 1000);
557 // fe.life() unit is SECOND!
558 long liveTime = fe.life() + fromLastSeen;
Brian O'Connor8c685362015-12-05 15:27:27 -0800559
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900560 FlowEntry.FlowLiveType oldLiveType = fe.liveType();
Brian O'Connor8c685362015-12-05 15:27:27 -0800561
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900562 switch (fe.liveType()) {
563 case IMMEDIATE:
564 if (liveTime >= calAndPollInterval) {
565 fe.setLiveType(FlowEntry.FlowLiveType.SHORT);
Jonathan Hart84f4f312016-03-03 08:17:11 -0800566 }
567 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900568 case SHORT:
569 if (liveTime >= midPollInterval) {
570 fe.setLiveType(FlowEntry.FlowLiveType.MID);
Jonathan Hart84f4f312016-03-03 08:17:11 -0800571 }
572 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900573 case MID:
Jonathan Hart84f4f312016-03-03 08:17:11 -0800574 if (liveTime >= longPollInterval) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900575 fe.setLiveType(FlowEntry.FlowLiveType.LONG);
Jonathan Hart84f4f312016-03-03 08:17:11 -0800576 }
577 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900578 case LONG:
Jonathan Hart84f4f312016-03-03 08:17:11 -0800579 if (fromLastSeen > entirePollInterval) {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900580 log.trace("checkAndMoveLiveFlowInternal, flow may be already removed at switch.");
Brian O'Connor8c685362015-12-05 15:27:27 -0800581 return false;
Jonathan Hart84f4f312016-03-03 08:17:11 -0800582 }
583 break;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900584 case UNKNOWN: // Unknown live type is calculated and set with correct flow live type here.
585 calAndSetFlowLiveType(fe);
586 break;
Jonathan Hart84f4f312016-03-03 08:17:11 -0800587 default:
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900588 // Error Live Type
589 log.error("checkAndMoveLiveFlowInternal, Unknown Live Type error!"
590 + " AdaptiveStats collection thread for {}",
591 sw.getStringId());
Jonathan Hart84f4f312016-03-03 08:17:11 -0800592 return false;
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900593 }
Brian O'Connor8c685362015-12-05 15:27:27 -0800594
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900595 if (log.isTraceEnabled()) {
596 log.trace(CHECK_AND_MOVE_LOG, fe.id(), fe.state(), fe.liveType(),
Jonathan Hart84f4f312016-03-03 08:17:11 -0800597 liveTime, fe.life(), fe.bytes(), fe.packets(), fromLastSeen,
598 fe.priority(), fe.selector().criteria(), fe.treatment(),
599 sw.getStringId());
Brian O'Connor8c685362015-12-05 15:27:27 -0800600 }
601
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900602 return true;
Brian O'Connor8c685362015-12-05 15:27:27 -0800603 }
604}