ONOS-7001 Support for direct counters
Currently Bmv2 returns UNKNOWN error when reading direct counters.
Change-Id: I834d7b5a8627181c6888500545e1bdbfe9af8dc1
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
index 6b93f5d..738996f 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
@@ -24,6 +24,7 @@
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiCounterId;
import org.onosproject.net.pi.runtime.PiHeaderFieldId;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiTableId;
@@ -88,6 +89,15 @@
throws PiInterpreterException;
/**
+ * Returns a protocol-independent direct counter identifier for the given table, if present. If not present, it
+ * means that the given table does not support direct counters.
+ *
+ * @param piTableId table identifier
+ * @return optional direct counter identifier
+ */
+ Optional<PiCounterId> mapTableCounter(PiTableId piTableId);
+
+ /**
* Returns a collection of packet operations equivalent to the given OutboundPacket.
*
* @param packet a ONOS outbound packet
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellId.java
index d762f23..cd88d2a 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellId.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellId.java
@@ -16,77 +16,22 @@
package org.onosproject.net.pi.runtime;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
-import org.onlab.util.Identifier;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
/**
- * Identifier of a counter cell of a protocol-independent pipeline.
+ * Identifier of a counter cell in a protocol-independent pipeline.
*/
-@Beta
-public final class PiCounterCellId extends Identifier<String> {
-
- private final PiCounterId counterId;
- private final long index;
-
- private PiCounterCellId(PiCounterId counterId, long index) {
- super(counterId.id() + "[" + index + "]");
- this.counterId = counterId;
- this.index = index;
- }
+public interface PiCounterCellId {
/**
- * Returns a counter cell identifier for the given counter identifier and index.
- *
- * @param counterId counter identifier
- * @param index index
- * @return counter cell identifier
- */
- public static PiCounterCellId of(PiCounterId counterId, long index) {
- checkNotNull(counterId);
- checkArgument(index >= 0, "Index must be a positive integer");
- return new PiCounterCellId(counterId, index);
- }
-
- /**
- * Returns the counter identifier of this cell.
+ * Returns the identifier of the counter instance where this cell is contained.
*
* @return counter identifier
*/
- public PiCounterId counterId() {
- return counterId;
- }
+ PiCounterId counterId();
/**
- * Returns the index of this cell.
+ * Returns the type of counter identified.
*
- * @return cell index
+ * @return counter type
*/
- public long index() {
- return index;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof PiCounterCellId)) {
- return false;
- }
- if (!super.equals(o)) {
- return false;
- }
- PiCounterCellId that = (PiCounterCellId) o;
- return index == that.index &&
- Objects.equal(counterId, that.counterId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(super.hashCode(), counterId, index);
- }
+ PiCounterType type();
}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterId.java
index 6fcd55e..dcc7c02 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterId.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterId.java
@@ -17,7 +17,7 @@
package org.onosproject.net.pi.runtime;
import com.google.common.annotations.Beta;
-import org.onlab.util.Identifier;
+import com.google.common.base.Objects;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -26,22 +26,28 @@
* Identifier of a counter of a protocol-independent pipeline.
*/
@Beta
-public final class PiCounterId extends Identifier<String> {
+public final class PiCounterId {
- private PiCounterId(String name) {
- super(name);
+ private final String name;
+ private final PiCounterType type;
+
+ private PiCounterId(String name, PiCounterType type) {
+ this.name = name;
+ this.type = type;
}
/**
- * Returns a counter identifier for the given name.
+ * Returns a counter identifier for the given name and type.
*
* @param name counter name
+ * @param type counter type
* @return counter identifier
*/
- public static PiCounterId of(String name) {
+ public static PiCounterId of(String name, PiCounterType type) {
checkNotNull(name);
- checkArgument(!name.isEmpty(), "Name name can't be empty");
- return new PiCounterId(name);
+ checkNotNull(type);
+ checkArgument(!name.isEmpty(), "Name can't be empty");
+ return new PiCounterId(name, type);
}
/**
@@ -50,6 +56,38 @@
* @return counter name
*/
public String name() {
- return this.identifier;
+ return this.name;
+ }
+
+ /**
+ * Returns the type of the counter.
+ *
+ * @return counter type
+ */
+ public PiCounterType type() {
+ return this.type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PiCounterId)) {
+ return false;
+ }
+ PiCounterId that = (PiCounterId) o;
+ return Objects.equal(name, that.name) &&
+ type == that.type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, type);
+ }
+
+ @Override
+ public String toString() {
+ return type.name().toLowerCase() + ":" + name;
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterType.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterType.java
new file mode 100644
index 0000000..b4a709a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterType.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.net.pi.runtime;
+
+/**
+ * Type of counter in a protocol-independent pipeline.
+ */
+public enum PiCounterType {
+ /**
+ * Identifies a counter associated to a match-action table, where cells are directly associated to table entries.
+ */
+ DIRECT,
+
+ /**
+ * Identifies a counter not associated with any other resource.
+ */
+ INDIRECT
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiDirectCounterCellId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiDirectCounterCellId.java
new file mode 100644
index 0000000..26ae363
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiDirectCounterCellId.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.net.pi.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.String.format;
+import static org.onosproject.net.pi.runtime.PiCounterType.DIRECT;
+
+/**
+ * Identifier of a direct counter cell of a protocol-independent pipeline.
+ */
+@Beta
+public final class PiDirectCounterCellId implements PiCounterCellId {
+
+ private final PiCounterId counterId;
+ private final PiTableEntry tableEntry;
+
+ private PiDirectCounterCellId(PiCounterId counterId, PiTableEntry tableEntry) {
+ this.counterId = counterId;
+ this.tableEntry = tableEntry;
+ }
+
+ /**
+ * Returns a direct counter cell identifier for the given counter identifier and table entry.
+ *
+ * @param counterId counter identifier
+ * @param tableEntry table entry
+ * @return direct counter cell identifier
+ */
+ public static PiDirectCounterCellId of(PiCounterId counterId, PiTableEntry tableEntry) {
+ checkNotNull(counterId);
+ checkNotNull(tableEntry);
+ checkArgument(counterId.type() == DIRECT, "Counter ID must be of type DIRECT");
+ return new PiDirectCounterCellId(counterId, tableEntry);
+ }
+
+ /**
+ * Returns the table entry associated with this cell identifier.
+ *
+ * @return cell table entry
+ */
+ public PiTableEntry tableEntry() {
+ return tableEntry;
+ }
+
+ @Override
+ public PiCounterId counterId() {
+ return counterId;
+ }
+
+ @Override
+ public PiCounterType type() {
+ return DIRECT;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PiDirectCounterCellId)) {
+ return false;
+ }
+ PiDirectCounterCellId that = (PiDirectCounterCellId) o;
+ return Objects.equal(counterId, that.counterId) &&
+ Objects.equal(tableEntry, that.tableEntry);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(counterId, tableEntry);
+ }
+
+ @Override
+ public String toString() {
+ return format("%s[{%s}]", counterId, tableEntry);
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiIndirectCounterCellId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiIndirectCounterCellId.java
new file mode 100644
index 0000000..6f3f73a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiIndirectCounterCellId.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.net.pi.runtime;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.pi.runtime.PiCounterType.INDIRECT;
+
+/**
+ * Identifier of an indirect counter cell in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiIndirectCounterCellId extends Identifier<String> implements PiCounterCellId {
+
+ private final PiCounterId counterId;
+ private final long index;
+
+ private PiIndirectCounterCellId(PiCounterId counterId, long index) {
+ super(counterId.toString() + "[" + index + "]");
+ this.counterId = counterId;
+ this.index = index;
+ }
+
+ /**
+ * Returns a counter cell identifier for the given counter identifier and index.
+ *
+ * @param counterId counter identifier
+ * @param index index
+ * @return counter cell identifier
+ */
+ public static PiIndirectCounterCellId of(PiCounterId counterId, long index) {
+ checkNotNull(counterId);
+ checkArgument(counterId.type() == INDIRECT, "Counter ID must be of type INDIRECT");
+ checkArgument(index >= 0, "Index must be a positive integer");
+ return new PiIndirectCounterCellId(counterId, index);
+ }
+
+ /**
+ * Returns the index of this cell.
+ *
+ * @return cell index
+ */
+ public long index() {
+ return index;
+ }
+
+ @Override
+ public PiCounterId counterId() {
+ return counterId;
+ }
+
+ @Override
+ public PiCounterType type() {
+ return INDIRECT;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java
index 91cabfd..e2e8c3d 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java
@@ -24,14 +24,14 @@
import java.util.Optional;
import java.util.StringJoiner;
-import static com.google.common.base.Preconditions.checkArgument;
-
/**
* Representation of all field matches of an entry of a match+action table of a protocol-independent pipeline.
*/
@Beta
public final class PiMatchKey {
+ public static final PiMatchKey EMPTY = builder().build();
+
private final ImmutableMap<PiHeaderFieldId, PiFieldMatch> fieldMatches;
private PiMatchKey(ImmutableMap<PiHeaderFieldId, PiFieldMatch> fieldMatches) {
@@ -130,7 +130,6 @@
*/
public PiMatchKey build() {
ImmutableMap<PiHeaderFieldId, PiFieldMatch> fieldMatches = fieldMatchesBuilder.build();
- checkArgument(fieldMatches.size() > 0, "Field matches cannot be empty");
return new PiMatchKey(fieldMatches);
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
index b0192fd..6a5f75b 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
@@ -31,6 +31,8 @@
@Beta
public final class PiTableEntry {
+ public static final PiTableEntry EMTPY = new PiTableEntry();
+
private static final int NO_PRIORITY = -1;
private static final double NO_TIMEOUT = -1;
@@ -41,6 +43,15 @@
private final int priority;
private final double timeout;
+ private PiTableEntry() {
+ this.tableId = null;
+ this.matchKey = null;
+ this.tableAction = null;
+ this.cookie = 0;
+ this.priority = NO_PRIORITY;
+ this.timeout = NO_TIMEOUT;
+ }
+
private PiTableEntry(PiTableId tableId, PiMatchKey matchKey,
PiTableAction tableAction, long cookie, int priority, double timeout) {
this.tableId = tableId;
diff --git a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiTableEntryTest.java b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiTableEntryTest.java
index 505dba3..6caa63c 100644
--- a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiTableEntryTest.java
+++ b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiTableEntryTest.java
@@ -27,29 +27,27 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
-import static org.onosproject.net.pi.runtime.PiConstantsTest.DROP;
-import static org.onosproject.net.pi.runtime.PiConstantsTest.DST_ADDR;
-import static org.onosproject.net.pi.runtime.PiConstantsTest.IPV4_HEADER_NAME;
+import static org.onosproject.net.pi.runtime.PiConstantsTest.*;
/**
* Unit tests for PiTableEntry class.
*/
public class PiTableEntryTest {
- final PiTableEntry piTableEntry1 = PiTableEntry.builder()
+ private final PiTableEntry piTableEntry1 = PiTableEntry.builder()
.forTable(PiTableId.of("Table10"))
.withCookie(0xac)
.withPriority(10)
.withAction(PiAction.builder().withId(PiActionId.of(DROP)).build())
.withTimeout(100)
.build();
- final PiTableEntry sameAsPiTableEntry1 = PiTableEntry.builder()
+ private final PiTableEntry sameAsPiTableEntry1 = PiTableEntry.builder()
.forTable(PiTableId.of("Table10"))
.withCookie(0xac)
.withPriority(10)
.withAction(PiAction.builder().withId(PiActionId.of(DROP)).build())
.withTimeout(100)
.build();
- final PiTableEntry piTableEntry2 = PiTableEntry.builder()
+ private final PiTableEntry piTableEntry2 = PiTableEntry.builder()
.forTable(PiTableId.of("Table20"))
.withCookie(0xac)
.withPriority(10)
@@ -77,6 +75,16 @@
}
/**
+ * Tests equality of the empty table entry.
+ */
+ @Test
+ public void testEmptyEquals() {
+ new EqualsTester()
+ .addEqualityGroup(PiTableEntry.EMTPY, PiTableEntry.EMTPY)
+ .testEquals();
+ }
+
+ /**
* Tests creation of a DefaultFlowRule using a FlowRule constructor.
*/
@Test