CORD-13:Table Statistics support along with CLI and REST
Change-Id: Ic7facc73754c4b1e7c9c5a9eecd217f89a67e135
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 949c657..4c38d7a 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
@@ -21,6 +21,7 @@
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -32,6 +33,7 @@
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.CompletedBatchOperation;
+import org.onosproject.net.flow.DefaultTableStatisticsEntry;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
@@ -40,6 +42,7 @@
import org.onosproject.net.flow.FlowRuleProvider;
import org.onosproject.net.flow.FlowRuleProviderRegistry;
import org.onosproject.net.flow.FlowRuleProviderService;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.statistic.DefaultLoad;
@@ -58,6 +61,8 @@
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
+import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
@@ -70,6 +75,7 @@
import java.util.Dictionary;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.Timer;
@@ -121,6 +127,8 @@
// NewAdaptiveFlowStatsCollector Set
private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap();
+ private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
+ private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newHashMap();
/**
* Creates an OpenFlow host provider.
@@ -214,6 +222,9 @@
fsc.start();
simpleCollectors.put(new Dpid(sw.getId()), fsc);
}
+ TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
+ tsc.start();
+ tableStatsCollectors.put(new Dpid(sw.getId()), tsc);
}
private void stopCollectors() {
@@ -225,17 +236,19 @@
simpleCollectors.values().forEach(FlowStatsCollector::stop);
simpleCollectors.clear();
}
+ tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
+ tableStatsCollectors.clear();
}
private void adjustRate() {
DefaultLoad.setPollInterval(flowPollFrequency);
-
if (adaptiveFlowSampling) {
// NewAdaptiveFlowStatsCollector calAndPollInterval
afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
} else {
simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
}
+ tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
}
@Override
@@ -384,6 +397,10 @@
collector.stop();
}
}
+ TableStatisticsCollector tsc = tableStatsCollectors.remove(dpid);
+ if (tsc != null) {
+ tsc.stop();
+ }
}
@Override
@@ -413,6 +430,8 @@
case STATS_REPLY:
if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
+ } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
+ pushTableStatistics(dpid, (OFTableStatsReply) msg);
}
break;
case BARRIER_REPLY:
@@ -473,7 +492,6 @@
private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
- OpenFlowSwitch sw = controller.getSwitch(dpid);
List<FlowEntry> flowEntries = replies.getEntries().stream()
.map(entry -> new FlowEntryBuilder(dpid, entry).build())
@@ -512,6 +530,31 @@
providerService.pushFlowMetrics(did, flowEntries);
}
}
+
+ private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
+
+ DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
+ List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
+ .map(entry -> buildTableStatistics(did, entry))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ providerService.pushTableStatistics(did, tableStatsEntries);
+ }
+
+ private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
+ OFTableStatsEntry ofEntry) {
+ TableStatisticsEntry entry = null;
+ if (ofEntry != null) {
+ entry = new DefaultTableStatisticsEntry(deviceId,
+ ofEntry.getTableId().getValue(),
+ ofEntry.getActiveCount(),
+ ofEntry.getLookupCount().getValue(),
+ ofEntry.getMatchedCount().getValue());
+ }
+
+ return entry;
+
+ }
}
/**
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
new file mode 100644
index 0000000..922a470
--- /dev/null
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.provider.of.flow.impl;
+
+import org.onlab.util.SharedExecutors;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFTableStatsRequest;
+import org.slf4j.Logger;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Collects Table statistics for the specified switch.
+ */
+class TableStatisticsCollector {
+
+ private final Logger log = getLogger(getClass());
+
+ public static final int SECONDS = 1000;
+
+ private final OpenFlowSwitch sw;
+ private Timer timer;
+ private TimerTask task;
+
+ private int pollInterval;
+
+ /**
+ * Creates a new table statistics collector for the given switch and poll frequency.
+ *
+ * @param timer timer to use for scheduling
+ * @param sw switch to pull
+ * @param pollInterval poll frequency in seconds
+ */
+ TableStatisticsCollector(Timer timer, OpenFlowSwitch sw, int pollInterval) {
+ this.timer = timer;
+ this.sw = sw;
+ this.pollInterval = pollInterval;
+ }
+
+ /**
+ * Adjusts poll frequency.
+ *
+ * @param pollInterval poll frequency in seconds
+ */
+ synchronized void adjustPollInterval(int pollInterval) {
+ this.pollInterval = pollInterval;
+ task.cancel();
+ task = new InternalTimerTask();
+ timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000);
+ }
+
+ private class InternalTimerTask extends TimerTask {
+ @Override
+ public void run() {
+ if (sw.getRole() == RoleState.MASTER) {
+ log.trace("Collecting stats for {}", sw.getStringId());
+ OFTableStatsRequest request = sw.factory().buildTableStatsRequest()
+ .build();
+ sw.sendMsg(request);
+ }
+ }
+ }
+
+ 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();
+ SharedExecutors.getTimer().scheduleAtFixedRate(task, 1 * SECONDS,
+ pollInterval * SECONDS);
+ }
+
+ public synchronized void stop() {
+ log.debug("Stopping Table Stats collection thread for {}", sw.getStringId());
+ task.cancel();
+ task = null;
+ }
+
+}