Implemented class for PI match key
Used as table entry ID in P4Runtime devices
Change-Id: I9f35503f118fa6e6a23b59aa6b716273a24ece0a
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
new file mode 100644
index 0000000..c95afb7
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2017-present 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.net.pi.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Collection;
+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 {
+
+ private final ImmutableMap<PiHeaderFieldId, PiFieldMatch> fieldMatches;
+
+ private PiMatchKey(ImmutableMap<PiHeaderFieldId, PiFieldMatch> fieldMatches) {
+ this.fieldMatches = fieldMatches;
+ }
+
+ /**
+ * Returns the collection of field matches of this match key.
+ *
+ * @return collection of field matches
+ */
+ public Collection<PiFieldMatch> fieldMatches() {
+ return fieldMatches.values();
+ }
+
+ /**
+ * If present, returns the field match associated with the given header field identifier.
+ *
+ * @param fieldId field identifier
+ * @return optional field match
+ */
+ public Optional<PiFieldMatch> fieldMatch(PiHeaderFieldId fieldId) {
+ return Optional.ofNullable(fieldMatches.get(fieldId));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PiMatchKey)) {
+ return false;
+ }
+ PiMatchKey that = (PiMatchKey) o;
+ return Objects.equal(fieldMatches, that.fieldMatches);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(fieldMatches);
+ }
+
+ @Override
+ public String toString() {
+ StringJoiner stringFieldMatches = new StringJoiner(", ", "{", "}");
+ this.fieldMatches.values().forEach(f -> stringFieldMatches.add(f.toString()));
+ return stringFieldMatches.toString();
+ }
+
+ /**
+ * Returns a new builder of match keys.
+ *
+ * @return match key builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of match keys.
+ */
+ public static final class Builder {
+
+ private final ImmutableMap.Builder<PiHeaderFieldId, PiFieldMatch> fieldMatchesBuilder = ImmutableMap.builder();
+
+ private Builder() {
+ // hides constructor.
+ }
+
+ /**
+ * Adds one field match to this match key.
+ *
+ * @param fieldMatch field match
+ * @return this
+ */
+ public Builder addFieldMatch(PiFieldMatch fieldMatch) {
+ this.fieldMatchesBuilder.put(fieldMatch.fieldId(), fieldMatch);
+ return this;
+ }
+
+ /**
+ * Adds many field matches to this match key.
+ *
+ * @param fieldMatches collection of field matches
+ * @return this
+ */
+ public Builder addFieldMatches(Collection<PiFieldMatch> fieldMatches) {
+ fieldMatches.forEach(this::addFieldMatch);
+ return this;
+ }
+
+ /**
+ * Creates a new match key.
+ *
+ * @return match key
+ */
+ 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 63e478d..40b2f05 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
@@ -19,11 +19,7 @@
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import java.util.Collection;
-import java.util.Map;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
@@ -39,16 +35,16 @@
private static final double NO_TIMEOUT = -1;
private final PiTableId tableId;
- private final Map<PiHeaderFieldId, PiFieldMatch> fieldMatches;
+ private final PiMatchKey matchKey;
private final PiTableAction tableAction;
private final long cookie;
private final int priority;
private final double timeout;
- private PiTableEntry(PiTableId tableId, Map<PiHeaderFieldId, PiFieldMatch> fieldMatches,
+ private PiTableEntry(PiTableId tableId, PiMatchKey matchKey,
PiTableAction tableAction, long cookie, int priority, double timeout) {
this.tableId = tableId;
- this.fieldMatches = ImmutableMap.copyOf(fieldMatches);
+ this.matchKey = matchKey;
this.tableAction = tableAction;
this.cookie = cookie;
this.priority = priority;
@@ -65,22 +61,12 @@
}
/**
- * Returns an immutable view of the field matches of this table entry.
+ * Returns the match key of this table entry.
*
- * @return collection of field matches
+ * @return match key
*/
- public Collection<PiFieldMatch> fieldMatches() {
- return fieldMatches.values();
- }
-
- /**
- * If present, returns the field match associated with the given header field identifier.
- *
- * @param fieldId field identifier
- * @return optional field match
- */
- public Optional<PiFieldMatch> fieldMatch(PiHeaderFieldId fieldId) {
- return Optional.ofNullable(fieldMatches.get(fieldId));
+ public PiMatchKey matchKey() {
+ return matchKey;
}
/**
@@ -133,20 +119,20 @@
return priority == that.priority &&
Double.compare(that.timeout, timeout) == 0 &&
Objects.equal(tableId, that.tableId) &&
- Objects.equal(fieldMatches, that.fieldMatches) &&
+ Objects.equal(matchKey, that.matchKey) &&
Objects.equal(tableAction, that.tableAction);
}
@Override
public int hashCode() {
- return Objects.hashCode(tableId, fieldMatches, tableAction, priority, timeout);
+ return Objects.hashCode(tableId, matchKey, tableAction, priority, timeout);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("tableId", tableId)
- .add("fieldMatches", fieldMatches)
+ .add("matchKey", matchKey)
.add("tableAction", tableAction)
.add("priority", priority == NO_PRIORITY ? "N/A" : String.valueOf(priority))
.add("timeout", timeout == NO_TIMEOUT ? "PERMANENT" : String.valueOf(timeout))
@@ -165,7 +151,7 @@
public static final class Builder {
private PiTableId tableId;
- private Map<PiHeaderFieldId, PiFieldMatch> fieldMatches = Maps.newHashMap();
+ private PiMatchKey matchKey;
private PiTableAction tableAction;
private long cookie = 0;
private int priority = NO_PRIORITY;
@@ -198,24 +184,13 @@
}
/**
- * Adds one field match to this table entry.
+ * Sets the match key of this table entry.
*
- * @param fieldMatch field match
+ * @param matchKey match key
* @return this
*/
- public Builder withFieldMatch(PiFieldMatch fieldMatch) {
- this.fieldMatches.put(fieldMatch.fieldId(), fieldMatch);
- return this;
- }
-
- /**
- * Adds many field matches to this table entry.
- *
- * @param fieldMatches collection of field matches
- * @return this
- */
- public Builder withFieldMatches(Collection<PiFieldMatch> fieldMatches) {
- fieldMatches.forEach(f -> this.fieldMatches.put(f.fieldId(), f));
+ public Builder withMatchKey(PiMatchKey matchKey) {
+ this.matchKey = matchKey;
return this;
}
@@ -262,7 +237,7 @@
public PiTableEntry build() {
checkNotNull(tableId);
checkNotNull(tableAction);
- return new PiTableEntry(tableId, fieldMatches, tableAction, cookie, priority, timeout);
+ return new PiTableEntry(tableId, matchKey, tableAction, cookie, priority, timeout);
}
}
}
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 0246227..84211e0 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
@@ -93,7 +93,9 @@
fieldMatches.put(piHeaderFieldId, piFieldMatch);
final PiTableEntry piTableEntry = PiTableEntry.builder()
.forTable(piTableId)
- .withFieldMatches(fieldMatches.values())
+ .withMatchKey(PiMatchKey.builder()
+ .addFieldMatches(fieldMatches.values())
+ .build())
.withAction(piAction)
.withCookie(cookie)
.withPriority(priority)
@@ -105,7 +107,7 @@
assertThat(piTableEntry.priority().get(), is(priority));
assertThat(piTableEntry.timeout().get(), is(timeout));
assertThat("Incorrect match param value",
- CollectionUtils.isEqualCollection(piTableEntry.fieldMatches(), fieldMatches.values()));
+ CollectionUtils.isEqualCollection(piTableEntry.matchKey().fieldMatches(), fieldMatches.values()));
assertThat(piTableEntry.action(), is(piAction));
}
}
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
index 8b28b5e..17dce70 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
@@ -41,6 +41,7 @@
import org.onosproject.net.pi.runtime.PiFieldMatch;
import org.onosproject.net.pi.runtime.PiHeaderFieldId;
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
+import org.onosproject.net.pi.runtime.PiMatchKey;
import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
import org.onosproject.net.pi.runtime.PiTableAction;
import org.onosproject.net.pi.runtime.PiTableEntry;
@@ -135,7 +136,9 @@
tableEntryBuilder
.forTable(piTableId)
.withPriority(rule.priority())
- .withFieldMatches(fieldMatches)
+ .withMatchKey(PiMatchKey.builder()
+ .addFieldMatches(fieldMatches)
+ .build())
.withAction(piAction);
if (!rule.isPermanent()) {
diff --git a/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java b/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java
index 894865e..d865c8e 100644
--- a/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java
+++ b/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java
@@ -124,16 +124,16 @@
int numMatchParams = pipeconf.pipelineModel().table(TABLE0).get().matchFields().size();
// parse values stored in entry1
- PiTernaryFieldMatch inPortParam = (PiTernaryFieldMatch) entry1.fieldMatch(IN_PORT_ID).get();
- PiTernaryFieldMatch ethDstParam = (PiTernaryFieldMatch) entry1.fieldMatch(ETH_DST_ID).get();
- PiTernaryFieldMatch ethSrcParam = (PiTernaryFieldMatch) entry1.fieldMatch(ETH_SRC_ID).get();
- PiTernaryFieldMatch ethTypeParam = (PiTernaryFieldMatch) entry1.fieldMatch(ETH_TYPE_ID).get();
+ PiTernaryFieldMatch inPortParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(IN_PORT_ID).get();
+ PiTernaryFieldMatch ethDstParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(ETH_DST_ID).get();
+ PiTernaryFieldMatch ethSrcParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(ETH_SRC_ID).get();
+ PiTernaryFieldMatch ethTypeParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(ETH_TYPE_ID).get();
Optional<Double> expectedTimeout = pipeconf.pipelineModel().table(TABLE0).get().supportsAging()
? Optional.of((double) rule1.timeout()) : Optional.empty();
// check that the number of parameters in the entry is the same as the number of table keys
assertThat("Incorrect number of match parameters",
- entry1.fieldMatches().size(), is(equalTo(numMatchParams)));
+ entry1.matchKey().fieldMatches().size(), is(equalTo(numMatchParams)));
// check that values stored in entry are the same used for the flow rule
assertThat("Incorrect inPort match param value",
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
index 68e1808..5f0ac5f 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
@@ -28,6 +28,7 @@
import org.onosproject.net.pi.runtime.PiFieldMatch;
import org.onosproject.net.pi.runtime.PiHeaderFieldId;
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
+import org.onosproject.net.pi.runtime.PiMatchKey;
import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
import org.onosproject.net.pi.runtime.PiTableAction;
import org.onosproject.net.pi.runtime.PiTableEntry;
@@ -161,7 +162,7 @@
tableEntryMsgBuilder.setAction(encodePiTableAction(piTableEntry.action(), browser));
// Field matches.
- for (PiFieldMatch piFieldMatch : piTableEntry.fieldMatches()) {
+ for (PiFieldMatch piFieldMatch : piTableEntry.matchKey().fieldMatches()) {
tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
}
@@ -190,10 +191,12 @@
// Timeout.
// FIXME: how to decode table entry messages with timeout, given that the timeout value is lost after encoding?
- // Field matches.
+ // Match key for field matches.
+ PiMatchKey.Builder piMatchKeyBuilder = PiMatchKey.builder();
for (FieldMatch fieldMatchMsg : tableEntryMsg.getMatchList()) {
- piTableEntryBuilder.withFieldMatch(decodeFieldMatchMsg(fieldMatchMsg, tableInfo, browser));
+ piMatchKeyBuilder.addFieldMatch(decodeFieldMatchMsg(fieldMatchMsg, tableInfo, browser));
}
+ piTableEntryBuilder.withMatchKey(piMatchKeyBuilder.build());
return piTableEntryBuilder.build();
}
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
index e4f00dc..a33430a 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
@@ -29,6 +29,7 @@
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiActionParamId;
import org.onosproject.net.pi.runtime.PiHeaderFieldId;
+import org.onosproject.net.pi.runtime.PiMatchKey;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
@@ -45,6 +46,7 @@
import static org.hamcrest.Matchers.is;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onlab.util.ImmutableByteSequence.fit;
+import static org.onlab.util.ImmutableByteSequence.ofOnes;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
@@ -94,15 +96,17 @@
private final PiTableEntry piTableEntry = PiTableEntry
.builder()
.forTable(tableId)
- .withFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ImmutableByteSequence.ofOnes(6)))
- .withFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ImmutableByteSequence.ofOnes(6)))
- .withFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ImmutableByteSequence.ofOnes(2)))
- .withFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ImmutableByteSequence.ofOnes(2)))
+ .withMatchKey(PiMatchKey.builder()
+ .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
+ .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
+ .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
+ .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
+ .build())
.withAction(PiAction
- .builder()
- .withId(outActionId)
- .withParameter(new PiActionParam(portParamId, portValue))
- .build())
+ .builder()
+ .withId(outActionId)
+ .withParameter(new PiActionParam(portParamId, portValue))
+ .build())
.withPriority(1)
.withCookie(2)
.build();