Added ability to poll flow counters in BMv2
Also fixed few minor things here and there.
Change-Id: Ib5e6a92de46870f52510cd6fad0cef8da022bb62
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleProgrammable.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleProgrammable.java
index 3f7a3ec..7d78fe3 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleProgrammable.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleProgrammable.java
@@ -48,12 +48,15 @@
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;
+
/**
* Flow rule programmable device behaviour implementation for BMv2.
*/
@@ -65,7 +68,7 @@
// There's no Bmv2 client method to poll flow entries from the device. Use a local store.
// FIXME: this information should be distributed across instances of the cluster.
- private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, FlowEntry>>
+ private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, TimestampedFlowRule>>
ENTRIES_MAP = Maps.newConcurrentMap();
// Cache model objects instead of parsing the JSON each time.
@@ -106,10 +109,28 @@
ENTRIES_MAP.forEach((key, value) -> {
if (key.getLeft() == deviceId && key.getMiddle() == table.name()
&& value != null) {
+ long entryId = value.getKey();
// Filter entries_map for this device and table.
- if (installedEntryIds.contains(value.getKey())) {
+ if (installedEntryIds.contains(entryId)) {
// Entry is installed.
- entryList.add(value.getRight());
+ long bytes = 0L;
+ long packets = 0L;
+ if (table.hasCounters()) {
+ // Read counter values from device.
+ try {
+ Pair<Long, Long> counterValue = deviceClient.readTableEntryCounter(table.name(),
+ entryId);
+ bytes = counterValue.getLeft();
+ packets = counterValue.getRight();
+ } catch (Bmv2RuntimeException e) {
+ LOG.warn("Unable to get counter values for entry {} of table {} of device {}: {}",
+ entryId, table.name(), deviceId, e.toString());
+ }
+ }
+ TimestampedFlowRule tsRule = value.getRight();
+ FlowEntry entry = new DefaultFlowEntry(tsRule.rule(), ADDED,
+ tsRule.lifeInSeconds(), packets, bytes);
+ entryList.add(entry);
} else {
// No such entry on device, can remove from local store.
ENTRIES_MAP.remove(key);
@@ -183,16 +204,14 @@
// Tentatively delete entry before re-adding.
// It might not exist on device due to inconsistencies.
deviceClient.deleteTableEntry(bmv2Entry.tableName(), entryId);
+ value = null;
} catch (Bmv2RuntimeException e) {
// Silently drop exception as we can probably fix this by re-adding the entry.
}
}
// Add entry.
entryId = deviceClient.addTableEntry(bmv2Entry);
- // TODO: evaluate flow entry life, bytes and packets
- FlowEntry flowEntry = new DefaultFlowEntry(
- rule, FlowEntry.FlowEntryState.ADDED, 0, 0, 0);
- value = Pair.of(entryId, flowEntry);
+ value = Pair.of(entryId, new TimestampedFlowRule(rule));
} else {
// Remove entry
if (value == null) {
@@ -258,4 +277,22 @@
private enum Operation {
APPLY, REMOVE
}
+
+ private class TimestampedFlowRule {
+ private final FlowRule rule;
+ private final Date addedDate;
+
+ public TimestampedFlowRule(FlowRule rule) {
+ this.rule = rule;
+ this.addedDate = new Date();
+ }
+
+ public FlowRule rule() {
+ return rule;
+ }
+
+ public long lifeInSeconds() {
+ return (new Date().getTime() - addedDate.getTime()) / 1000;
+ }
+ }
}
\ No newline at end of file
diff --git a/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/model/Bmv2ModelTable.java b/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/model/Bmv2ModelTable.java
index 2dc7e3f..618a49e 100644
--- a/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/model/Bmv2ModelTable.java
+++ b/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/model/Bmv2ModelTable.java
@@ -115,7 +115,7 @@
*
* @return a boolean value
*/
- public boolean hasCunters() {
+ public boolean hasCounters() {
return hasCounters;
}
diff --git a/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/runtime/Bmv2Client.java b/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/runtime/Bmv2Client.java
index d34aa9d..9dcc3ce 100644
--- a/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/runtime/Bmv2Client.java
+++ b/protocols/bmv2/src/main/java/org/onosproject/bmv2/api/runtime/Bmv2Client.java
@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
+import org.apache.commons.lang3.tuple.Pair;
import org.onlab.util.ImmutableByteSequence;
import java.util.Collection;
@@ -132,4 +133,14 @@
* @throws Bmv2RuntimeException if any error occurs
*/
String getJsonConfigMd5() throws Bmv2RuntimeException;
+
+ /**
+ * Returns the counter values for a given table and entry.
+ *
+ * @param tableName a table name
+ * @param entryId an entry id
+ * @return a pair of long values, where the left value is the number of bytes and the right the number of packets
+ * @throws Bmv2RuntimeException if any error occurs
+ */
+ Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException;
}
diff --git a/protocols/bmv2/src/main/java/org/onosproject/bmv2/ctl/Bmv2ThriftClient.java b/protocols/bmv2/src/main/java/org/onosproject/bmv2/ctl/Bmv2ThriftClient.java
index 66229b0..5e6cbd9 100644
--- a/protocols/bmv2/src/main/java/org/onosproject/bmv2/ctl/Bmv2ThriftClient.java
+++ b/protocols/bmv2/src/main/java/org/onosproject/bmv2/ctl/Bmv2ThriftClient.java
@@ -44,6 +44,7 @@
import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam;
import org.onosproject.net.DeviceId;
import org.p4.bmv2.thrift.BmAddEntryOptions;
+import org.p4.bmv2.thrift.BmCounterValue;
import org.p4.bmv2.thrift.BmMatchParam;
import org.p4.bmv2.thrift.BmMatchParamExact;
import org.p4.bmv2.thrift.BmMatchParamLPM;
@@ -477,6 +478,24 @@
}
@Override
+ public Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException {
+
+ LOG.debug("Reading table entry counters... > deviceId={}, tableName={}, entryId={}",
+ deviceId, tableName, entryId);
+
+ try {
+ BmCounterValue counterValue = standardClient.bm_mt_read_counter(CONTEXT_ID, tableName, entryId);
+ LOG.debug("Table entry counters retrieved! > deviceId={}, tableName={}, entryId={}, bytes={}, packets={}",
+ deviceId, tableName, entryId, counterValue.bytes, counterValue.packets);
+ return Pair.of(counterValue.bytes, counterValue.packets);
+ } catch (TException e) {
+ LOG.debug("Exception while reading table counters: {} > deviceId={}, tableName={}, entryId={}",
+ e.toString(), deviceId);
+ throw new Bmv2RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ @Override
public String getJsonConfigMd5() throws Bmv2RuntimeException {
LOG.debug("Getting device config md5... > deviceId={}", deviceId);
diff --git a/protocols/bmv2/src/test/java/org/onosproject/bmv2/api/model/Bmv2ModelTest.java b/protocols/bmv2/src/test/java/org/onosproject/bmv2/api/model/Bmv2ModelTest.java
index 6550ee9..1c51b7e 100644
--- a/protocols/bmv2/src/test/java/org/onosproject/bmv2/api/model/Bmv2ModelTest.java
+++ b/protocols/bmv2/src/test/java/org/onosproject/bmv2/api/model/Bmv2ModelTest.java
@@ -52,7 +52,7 @@
@Test
public void testParse() throws Exception {
Bmv2Model model = Bmv2Model.parse(json);
- Bmv2Model model2 = Bmv2Model.parse(json);
+ Bmv2Model model2 = Bmv2Model.parse(json2);
new EqualsTester()
.addEqualityGroup(model, model2)