Flow stats collection optimization - Flag introduced to stop periodic collection and collect only in 3 scenarios (Flows Add/Delete/Mod, Switch Add/Change, Mastership Change)
Change-Id: I1ad143a416f34135a622818c60dbc97310fe905e
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitchListener.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitchListener.java
index 5ad5a4f..41ec50b 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitchListener.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitchListener.java
@@ -55,4 +55,11 @@
* @param response role reply from the switch
*/
void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response);
+
+ /**
+ * Notify that role of the switch changed to Master.
+ *
+ * @param dpid the switch for which the role is changed
+ */
+ default void roleChangedToMaster(Dpid dpid) {}
}
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
index 8431068..9434c59 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
@@ -340,6 +340,7 @@
}
// perform role transition after clearing messages queue
this.role = RoleState.MASTER;
+ this.agent.roleChangedToMaster(dpid);
}
}
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java
index 4451b19..d6bda5d 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java
@@ -124,4 +124,11 @@
* @param listener the OpenFlow classifier listener
*/
void removeClassifierListener(OpenFlowClassifierListener listener);
+
+ /**
+ * Notify that role of the switch changed to Master.
+ *
+ * @param dpid the switch for which the role is changed
+ */
+ default void roleChangedToMaster(Dpid dpid) {}
}
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
index 9dd52cc..ae5d94e 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -949,6 +949,13 @@
public void removeClassifierListener(OpenFlowClassifierListener listener) {
ofClassifierListener.remove(listener);
}
+
+ @Override
+ public void roleChangedToMaster(Dpid dpid) {
+ for (OpenFlowSwitchListener l : ofSwitchListener) {
+ l.roleChangedToMaster(dpid);
+ }
+ }
}
/**
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
index 638c195..4aa6b21 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
@@ -217,15 +217,21 @@
}
public synchronized void start() {
- // Initially start polling quickly. Then drop down to configured value
log.debug("Starting Stats collection thread for {}", sw.getStringId());
loadCounter = new SlidingWindowCounter(HIGH_WINDOW);
- pauseTask = new PauseTimerTask();
- scheduledPauseTask = executorService.scheduleAtFixedRate(pauseTask, 1 * MS,
- 1 * MS, TimeUnit.MILLISECONDS);
- pollTask = new PollTimerTask();
- scheduledPollTask = executorService.scheduleAtFixedRate(pollTask, 1 * MS,
- pollInterval * MS, TimeUnit.MILLISECONDS);
+ if (pollInterval > 0) {
+ pauseTask = new PauseTimerTask();
+ scheduledPauseTask = executorService.scheduleAtFixedRate(pauseTask, 1 * MS,
+ 1 * MS, TimeUnit.MILLISECONDS);
+ pollTask = new PollTimerTask();
+ // Initially start polling quickly. Then drop down to configured value
+ scheduledPollTask = executorService.scheduleAtFixedRate(pollTask, 1 * MS,
+ pollInterval * MS, TimeUnit.MILLISECONDS);
+ } else {
+ // Trigger the poll only once
+ pollTask = new PollTimerTask();
+ executorService.schedule(pollTask, 0, TimeUnit.MILLISECONDS);
+ }
}
private synchronized void pause() {
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
index c67f2e9..9874234 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
@@ -112,6 +112,7 @@
private long flowMissingXid = NO_FLOW_MISSING_XID;
private FlowRuleService flowRuleService;
+ private boolean pollPeriodically = true;
/**
* Creates a new adaptive collector for the given switch and default cal_and_poll frequency.
@@ -128,6 +129,9 @@
flowRuleService = get(FlowRuleService.class);
initMemberVars(pollInterval);
+ if (pollInterval == -1) {
+ pollPeriodically = false;
+ }
}
/**
@@ -394,27 +398,49 @@
isFirstTimeStart = true;
- // Initially start polling quickly. Then drop down to configured value
calAndShortFlowsTask = new CalAndShortFlowsTask();
- calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- calAndShortFlowsTask,
- 1,
- calAndPollInterval,
- TimeUnit.SECONDS);
-
midFlowsTask = new MidFlowsTask();
- midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- midFlowsTask,
- 1,
- midPollInterval,
- TimeUnit.SECONDS);
-
longFlowsTask = new LongFlowsTask();
- longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- longFlowsTask,
- 1,
- longPollInterval,
- TimeUnit.SECONDS);
+
+ if (pollPeriodically) {
+ // Initially start polling quickly. Then drop down to configured value
+
+ calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ calAndShortFlowsTask,
+ 1,
+ calAndPollInterval,
+ TimeUnit.SECONDS);
+
+
+ midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ midFlowsTask,
+ 1,
+ midPollInterval,
+ TimeUnit.SECONDS);
+
+
+ longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
+ longFlowsTask,
+ 1,
+ longPollInterval,
+ TimeUnit.SECONDS);
+ } else {
+ // Trigger the polls only once
+ adaptiveFlowStatsScheduler.schedule(
+ calAndShortFlowsTask,
+ 0,
+ TimeUnit.SECONDS);
+
+ adaptiveFlowStatsScheduler.schedule(
+ midFlowsTask,
+ 0,
+ TimeUnit.SECONDS);
+
+ adaptiveFlowStatsScheduler.schedule(
+ longFlowsTask,
+ 0,
+ TimeUnit.SECONDS);
+ }
log.info("Started");
}
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index c051c5e..b208b1e 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -105,6 +105,8 @@
import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.ADAPTIVE_FLOW_SAMPLING_DEFAULT;
import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.POLL_FREQUENCY;
import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.POLL_FREQUENCY_DEFAULT;
+import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.POLL_STATS_PERIODICALLY;
+import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.POLL_STATS_PERIODICALLY_DEFAULT;
import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;
@@ -143,6 +145,9 @@
/** Adaptive Flow Sampling is on or off. */
private boolean adaptiveFlowSampling = ADAPTIVE_FLOW_SAMPLING_DEFAULT;
+ /** Poll Stats Periodically ON/OFF. */
+ private boolean pollStatsPeriodically = POLL_STATS_PERIODICALLY_DEFAULT;
+
private FlowRuleProviderService providerService;
private final InternalFlowProvider listener = new InternalFlowProvider();
@@ -203,7 +208,6 @@
try {
String s = get(properties, POLL_FREQUENCY);
newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
-
} catch (NumberFormatException | ClassCastException e) {
newFlowPollFrequency = flowPollFrequency;
}
@@ -212,22 +216,34 @@
flowPollFrequency = newFlowPollFrequency;
adjustRate();
}
-
log.info("Settings: flowPollFrequency={}", flowPollFrequency);
boolean newAdaptiveFlowSampling;
String s = get(properties, ADAPTIVE_FLOW_SAMPLING);
newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
-
if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
// stop previous collector
stopCollectors();
adaptiveFlowSampling = newAdaptiveFlowSampling;
- // create new collectors
- createCollectors();
+ if (pollStatsPeriodically) {
+ // create new collectors
+ createCollectors();
+ }
}
-
log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
+
+ boolean newPollStatsPeriodically;
+ String flag = get(properties, POLL_STATS_PERIODICALLY);
+ newPollStatsPeriodically = isNullOrEmpty(flag) ? pollStatsPeriodically : Boolean.parseBoolean(flag.trim());
+ if (newPollStatsPeriodically != pollStatsPeriodically) {
+ // stop previous collector
+ stopCollectors();
+ pollStatsPeriodically = newPollStatsPeriodically;
+ if (pollStatsPeriodically) {
+ createCollectors();
+ }
+ }
+ log.info("Settings: pollStatsPeriodically={}", pollStatsPeriodically);
}
private Cache<Long, InternalCacheEntry> createBatchCache() {
@@ -325,6 +341,11 @@
if (collector != null) {
collector.recordEvents(events);
}
+
+ if (!pollStatsPeriodically) {
+ log.debug("Triggering Flow/Table Stats, Flow Add/Del/Mod event, switch : {}", dpid.toString());
+ triggerStatsCollection(dpid);
+ }
}
@Override
@@ -419,12 +440,43 @@
recordEvents(dpid, (batch.getOperations().size() + 1));
}
+ private void triggerStatsCollection(Dpid dpid) {
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ if (sw == null) {
+ return;
+ }
+
+ SwitchDataCollector sdc = adaptiveFlowSampling ? afsCollectors.get(dpid) : simpleCollectors.get(dpid);
+ if (sdc == null) {
+ if (adaptiveFlowSampling) {
+ sdc = new NewAdaptiveFlowStatsCollector(driverService, sw, -1);
+ afsCollectors.put(dpid, (NewAdaptiveFlowStatsCollector) sdc);
+ } else {
+ sdc = new FlowStatsCollector(executorService, sw, -1);
+ simpleCollectors.put(dpid, (FlowStatsCollector) sdc);
+ }
+ }
+ sdc.start();
+
+ TableStatisticsCollector tsc = tableStatsCollectors.get(dpid);
+ if (tsc == null) {
+ tsc = new TableStatisticsCollector(executorService, sw, -1);
+ tableStatsCollectors.put(dpid, tsc);
+ }
+ tsc.start();
+ }
+
private class InternalFlowProvider
implements OpenFlowSwitchListener, OpenFlowEventListener {
@Override
public void switchAdded(Dpid dpid) {
- createCollector(controller.getSwitch(dpid));
+ if (pollStatsPeriodically) {
+ createCollector(controller.getSwitch(dpid));
+ } else {
+ log.debug("Triggering Flow/Table Stats, Switch: {} added, ", dpid.toString());
+ triggerStatsCollection(dpid);
+ }
}
@Override
@@ -645,6 +697,14 @@
}
}
+ @Override
+ public void roleChangedToMaster(Dpid dpid) {
+ if (!pollStatsPeriodically) {
+ log.debug("Triggering Flow/Table Stats, Mastership change: {}, ", dpid.toString());
+ triggerStatsCollection(dpid);
+ }
+ }
+
private DriverHandler getDriver(DeviceId devId) {
Driver driver = driverService.getDriver(devId);
DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OsgiPropertyConstants.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OsgiPropertyConstants.java
index 36022e8..26d3515 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OsgiPropertyConstants.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OsgiPropertyConstants.java
@@ -25,8 +25,10 @@
public static final String POLL_FREQUENCY = "flowPollFrequency";
public static final String ADAPTIVE_FLOW_SAMPLING = "adaptiveFlowSampling";
+ public static final String POLL_STATS_PERIODICALLY = "pollStatsPeriodically";
public static final int POLL_FREQUENCY_DEFAULT = 5;
public static final boolean ADAPTIVE_FLOW_SAMPLING_DEFAULT = false;
+ public static final boolean POLL_STATS_PERIODICALLY_DEFAULT = true;
}
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
index 466c91a..f2ddc72 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
@@ -87,11 +87,16 @@
}
public synchronized void start() {
- // Initially start polling quickly. Then drop down to configured value
log.debug("Starting Table Stats collection thread for {}", sw.getStringId());
task = new InternalTimerTask();
- scheduledTask = executorService.scheduleAtFixedRate(task, 1 * MS,
- pollInterval * MS, TimeUnit.MILLISECONDS);
+ if (pollInterval > 0) {
+ // Initially start polling quickly. Then drop down to configured value
+ scheduledTask = executorService.scheduleAtFixedRate(task, 1 * MS,
+ pollInterval * MS, TimeUnit.MILLISECONDS);
+ } else {
+ // Trigger the poll only once
+ executorService.schedule(task, 0, TimeUnit.MILLISECONDS);
+ }
}
public synchronized void stop() {