Support arbitrary bit width action parameter and match field
This commit goes into the direction of supporting user-defined types in P4Runtime.
The modification is focusing on supporting fields and params with arbitrary bit width, that is the
case of using a String with the p4runtime_translation annotation on the user-defined type.
Change-Id: I7db7a6d97211378ff78ab4f1b3734a0bec4558e6
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiActionParamModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiActionParamModel.java
index 284d2b2..ff504be 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiActionParamModel.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiActionParamModel.java
@@ -33,8 +33,17 @@
/**
* Return the size in bits of this action parameter.
+ * It returns -1 if the bit width of the action parameters is not predefined.
*
- * @return size in bits
+ * @return size in bits, -1 if not predefined
*/
int bitWidth();
+
+ /**
+ * Return true is the action parameters has a predefined bit width.
+ * It returns false if it can have arbitrary bit width.
+ *
+ * @return True if the action parameter has predefined bit width, false otherwise
+ */
+ boolean hasBitWidth();
}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiMatchFieldModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiMatchFieldModel.java
index 57d817a..16020ce 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiMatchFieldModel.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiMatchFieldModel.java
@@ -33,12 +33,21 @@
/**
* Returns the number of bits matched by this field.
+ * It returns -1 if the bit width of the match field is not predefined.
*
- * @return number of bits
+ * @return number of bits, -1 in case it is not predefined
*/
int bitWidth();
/**
+ * Return true is the match field has a predefined bit width.
+ * It returns false if it can have arbitrary bit width.
+ *
+ * @return True if the match field has predefined bit width, false otherwise
+ */
+ boolean hasBitWidth();
+
+ /**
* Returns the type of match applied to this field.
*
* @return a match type
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
index 3647427..8350549 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
@@ -277,7 +277,9 @@
"Not such parameter '%s' for action '%s'", param.id(), actionModel)));
try {
newActionBuilder.withParameter(new PiActionParam(param.id(),
- param.value().fit(paramModel.bitWidth())));
+ paramModel.hasBitWidth() ?
+ param.value().fit(paramModel.bitWidth()) :
+ param.value()));
} catch (ByteSequenceTrimException e) {
throw new PiTranslationException(format(
"Size mismatch for parameter '%s' of action '%s': %s",
@@ -372,7 +374,8 @@
PiFieldMatch fieldMatch = null;
- if (criterion != null) {
+ // TODO: we currently do not support fields with arbitrary bit width
+ if (criterion != null && fieldModel.hasBitWidth()) {
// Criterion mapping is possible for this field id.
try {
fieldMatch = translateCriterion(criterion, fieldId, fieldModel.matchType(), bitWidth);
@@ -458,8 +461,12 @@
try {
switch (fieldModel.matchType()) {
case EXACT:
+ // TODO: arbitrary bit width is supported only for the EXACT match case.
+ PiExactFieldMatch exactField = (PiExactFieldMatch) fieldMatch;
return new PiExactFieldMatch(fieldMatch.fieldId(),
- ((PiExactFieldMatch) fieldMatch).value().fit(modelBitWidth));
+ fieldModel.hasBitWidth() ?
+ exactField.value().fit(modelBitWidth) :
+ exactField.value());
case TERNARY:
PiTernaryFieldMatch ternField = (PiTernaryFieldMatch) fieldMatch;
ImmutableByteSequence ternMask = ternField.mask().fit(modelBitWidth);
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java
index 1c1f0a5..b862808 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java
@@ -25,6 +25,7 @@
* Implementation of PiActionParamModel for P4Runtime.
*/
final class P4ActionParamModel implements PiActionParamModel {
+ static final int BIT_WIDTH_UNDEFINED = -1;
private final PiActionParamId id;
private final int bitWidth;
@@ -45,6 +46,11 @@
}
@Override
+ public boolean hasBitWidth() {
+ return bitWidth != BIT_WIDTH_UNDEFINED;
+ }
+
+ @Override
public int hashCode() {
return Objects.hash(id, bitWidth);
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
index d5bf2e6..ef28ff9 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
@@ -62,6 +62,7 @@
import p4.config.v1.P4InfoOuterClass.MeterSpec;
import p4.config.v1.P4InfoOuterClass.P4Info;
import p4.config.v1.P4InfoOuterClass.Table;
+import p4.config.v1.P4Types;
import java.io.IOException;
import java.io.InputStream;
@@ -174,7 +175,9 @@
tableFieldMapBuilder.put(
fieldId,
new P4MatchFieldModel(fieldId,
- fieldMsg.getBitwidth(),
+ isFieldString(p4info, fieldMsg.getTypeName().getName()) ?
+ P4MatchFieldModel.BIT_WIDTH_UNDEFINED :
+ fieldMsg.getBitwidth(),
mapMatchFieldType(fieldMsg.getMatchType())));
}
@@ -369,8 +372,11 @@
actionMsg.getParamsList().forEach(paramMsg -> {
final PiActionParamId paramId = PiActionParamId.of(paramMsg.getName());
paramMapBuilder.put(paramId,
- new P4ActionParamModel(PiActionParamId.of(paramMsg.getName()),
- paramMsg.getBitwidth()));
+ new P4ActionParamModel(
+ PiActionParamId.of(paramMsg.getName()),
+ isFieldString(p4info, paramMsg.getTypeName().getName()) ?
+ P4ActionParamModel.BIT_WIDTH_UNDEFINED :
+ paramMsg.getBitwidth()));
});
actionMap.put(
actionMsg.getPreamble().getId(),
@@ -464,4 +470,11 @@
.findFirst()
.orElse(null);
}
+
+ private static boolean isFieldString(P4Info p4info, String fieldTypeName) {
+ P4Types.P4TypeInfo p4TypeInfo = p4info.getTypeInfo();
+ return p4TypeInfo.containsNewTypes(fieldTypeName) &&
+ p4TypeInfo.getNewTypesOrThrow(fieldTypeName).hasTranslatedType() &&
+ p4TypeInfo.getNewTypesOrThrow(fieldTypeName).getTranslatedType().hasSdnString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java
index f3b5ddc..47e2192 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java
@@ -26,6 +26,7 @@
* Implementation of PiMatchFieldModel for P4Runtime.
*/
final class P4MatchFieldModel implements PiMatchFieldModel {
+ static final int BIT_WIDTH_UNDEFINED = -1;
private final PiMatchFieldId id;
private final int bitWidth;
@@ -48,6 +49,11 @@
}
@Override
+ public boolean hasBitWidth() {
+ return bitWidth != BIT_WIDTH_UNDEFINED;
+ }
+
+ @Override
public PiMatchType matchType() {
return matchType;
}
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionParamModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionParamModelTest.java
index 035465c..c98d401 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionParamModelTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionParamModelTest.java
@@ -41,6 +41,15 @@
private final P4ActionParamModel actionParamModel3 = new P4ActionParamModel(piActionParamId, BIT_WIDTH_64);
+ private final P4ActionParamModel actionParamModel4 = new
+ P4ActionParamModel(piActionParamId, P4ActionParamModel.BIT_WIDTH_UNDEFINED);
+
+ private final P4ActionParamModel sameAsActionParamModel4 =
+ new P4ActionParamModel(sameAsPiActionParamId, P4ActionParamModel.BIT_WIDTH_UNDEFINED);
+
+ private final P4ActionParamModel actionParamModel5 =
+ new P4ActionParamModel(piActionParamId2, P4ActionParamModel.BIT_WIDTH_UNDEFINED);
+
/**
@@ -58,8 +67,10 @@
public void testEquals() {
new EqualsTester()
.addEqualityGroup(actionParamModel, sameAsActionParamModel)
+ .addEqualityGroup(actionParamModel4, sameAsActionParamModel4)
.addEqualityGroup(actionParamModel2)
.addEqualityGroup(actionParamModel3)
+ .addEqualityGroup(actionParamModel5)
.testEquals();
}
}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4MatchFieldModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4MatchFieldModelTest.java
index 448dcc5..86a0e66 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4MatchFieldModelTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4MatchFieldModelTest.java
@@ -42,6 +42,14 @@
private static final P4MatchFieldModel P4_MATCH_FIELD_MODEL_2 =
new P4MatchFieldModel(PI_MATCH_FIELD_ID_2, BIT_WIDTH_2, PI_MATCH_TYPE_2);
+ private static final P4MatchFieldModel P4_MATCH_FIELD_MODEL_3 =
+ new P4MatchFieldModel(PI_MATCH_FIELD_ID_1, P4MatchFieldModel.BIT_WIDTH_UNDEFINED, PI_MATCH_TYPE_1);
+ private static final P4MatchFieldModel SAME_AS_P4_MATCH_FIELD_MODEL_3 =
+ new P4MatchFieldModel(PI_MATCH_FIELD_ID_1, P4MatchFieldModel.BIT_WIDTH_UNDEFINED, PI_MATCH_TYPE_1);
+
+ private static final P4MatchFieldModel P4_MATCH_FIELD_MODEL_4 =
+ new P4MatchFieldModel(PI_MATCH_FIELD_ID_2, P4MatchFieldModel.BIT_WIDTH_UNDEFINED, PI_MATCH_TYPE_2);
+
/**
* Checks that the P4MatchFieldModel class is immutable.
*/
@@ -57,7 +65,9 @@
public void testEquals() {
new EqualsTester()
.addEqualityGroup(P4_MATCH_FIELD_MODEL_1, SAME_AS_P4_MATCH_FIELD_MODEL_1)
+ .addEqualityGroup(P4_MATCH_FIELD_MODEL_3, SAME_AS_P4_MATCH_FIELD_MODEL_3)
.addEqualityGroup(P4_MATCH_FIELD_MODEL_2)
+ .addEqualityGroup(P4_MATCH_FIELD_MODEL_4)
.testEquals();
}
}
\ No newline at end of file
diff --git a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/ActionCodec.java b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/ActionCodec.java
index 3ae46c9..69b31a8 100644
--- a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/ActionCodec.java
+++ b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/ActionCodec.java
@@ -48,8 +48,11 @@
final P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId)
.getByName(p.id().toString());
final ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
- assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
- paramValue, paramInfo.getBitwidth());
+ if (!browser.isTypeString(paramInfo.getTypeName())) {
+ // Check size only if the param type is not a sdn_string
+ assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
+ paramValue, paramInfo.getBitwidth());
+ }
actionMsgBuilder.addParams(P4RuntimeOuterClass.Action.Param.newBuilder()
.setParamId(paramInfo.getId())
.setValue(paramValue)
diff --git a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/FieldMatchCodec.java b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/FieldMatchCodec.java
index f289d5d..5e2ec43 100644
--- a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/FieldMatchCodec.java
+++ b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/FieldMatchCodec.java
@@ -71,7 +71,10 @@
case EXACT:
PiExactFieldMatch fieldMatch = (PiExactFieldMatch) piFieldMatch;
ByteString exactValue = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
- assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
+ // We support string only for EXACT match (via p4runtime_translation)
+ if (!browser.isTypeString(matchFieldInfo.getTypeName())) {
+ assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
+ }
return messageBuilder.setExact(
P4RuntimeOuterClass.FieldMatch.Exact
.newBuilder()
diff --git a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/utils/P4InfoBrowser.java b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/utils/P4InfoBrowser.java
index 29cddff..0b5e610 100644
--- a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/utils/P4InfoBrowser.java
+++ b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/utils/P4InfoBrowser.java
@@ -30,6 +30,7 @@
import p4.config.v1.P4InfoOuterClass.P4Info;
import p4.config.v1.P4InfoOuterClass.Preamble;
import p4.config.v1.P4InfoOuterClass.Table;
+import p4.config.v1.P4Types;
import java.util.Map;
@@ -55,6 +56,7 @@
private final Map<Integer, EntityBrowser<MatchField>> matchFields = Maps.newHashMap();
private final Map<Integer, EntityBrowser<ControllerPacketMetadata.Metadata>> ctrlPktMetadatasMetadata =
Maps.newHashMap();
+ private final Map<String, Boolean> isTypeString = Maps.newHashMap();
/**
* Creates a new browser for the given P4Info.
@@ -116,6 +118,12 @@
entity.getMetadataList().forEach(m -> metadataBrowser.add(m.getName(), null, m.getId(), m));
ctrlPktMetadatasMetadata.put(ctrlPktMetadataId, metadataBrowser);
});
+ p4info.getTypeInfo().getNewTypesMap().forEach(
+ (s, p4NewTypeSpec) ->
+ isTypeString.put(s,
+ p4NewTypeSpec.hasTranslatedType()
+ && p4NewTypeSpec.getTranslatedType().hasSdnString()
+ ));
}
/**
@@ -231,6 +239,17 @@
}
/**
+ * Checks if the given type name is a sdn_string.
+ *
+ * @param typeName Type name to check
+ * @return True if the given type name is a sdn_string, false otherwise
+ */
+ public boolean isTypeString(P4Types.P4NamedType typeName) {
+ return isTypeString.containsKey(typeName.getName())
+ && isTypeString.get(typeName.getName());
+ }
+
+ /**
* Browser of P4Info entities.
*
* @param <T> protobuf message type