use of org.onosproject.net.pi.runtime.PiFieldMatch in project onos by opennetworkinglab.
the class PiFlowRuleTranslatorImpl method translateFieldMatches.
/**
* Builds a collection of PI field matches out of the given selector,
* optionally using the given interpreter. The field matches returned are
* guaranteed to be compatible for the given table model.
*/
private static Collection<PiFieldMatch> translateFieldMatches(PiPipelineInterpreter interpreter, TrafficSelector selector, PiTableModel tableModel) throws PiTranslationException {
Map<PiMatchFieldId, PiFieldMatch> fieldMatches = Maps.newHashMap();
// If present, find a PiCriterion and get its field matches as a map. Otherwise, use an empty map.
Map<PiMatchFieldId, PiFieldMatch> piCriterionFields = selector.criteria().stream().filter(c -> c.type().equals(PROTOCOL_INDEPENDENT)).map(c -> (PiCriterion) c).findFirst().map(PiCriterion::fieldMatches).map(c -> {
Map<PiMatchFieldId, PiFieldMatch> fieldMap = Maps.newHashMap();
c.forEach(fieldMatch -> fieldMap.put(fieldMatch.fieldId(), fieldMatch));
return fieldMap;
}).orElse(Maps.newHashMap());
Set<Criterion> translatedCriteria = Sets.newHashSet();
Set<Criterion> ignoredCriteria = Sets.newHashSet();
Set<PiMatchFieldId> usedPiCriterionFields = Sets.newHashSet();
Set<PiMatchFieldId> ignoredPiCriterionFields = Sets.newHashSet();
Map<PiMatchFieldId, Criterion> criterionMap = Maps.newHashMap();
if (interpreter != null) {
// NOTE: if two criterion types map to the same match field ID, and
// those two criterion types are present in the selector, this won't
// work. This is unlikely to happen since those cases should be
// mutually exclusive:
// e.g. ICMPV6_TYPE -> metadata.my_normalized_icmp_type
// ICMPV4_TYPE -> metadata.my_normalized_icmp_type
// A packet can be either ICMPv6 or ICMPv4 but not both.
selector.criteria().stream().map(Criterion::type).filter(t -> t != PROTOCOL_INDEPENDENT).forEach(t -> {
PiMatchFieldId mfid = interpreter.mapCriterionType(t).orElse(null);
if (mfid != null) {
if (criterionMap.containsKey(mfid)) {
log.warn("Detected criterion mapping " + "conflict for PiMatchFieldId {}", mfid);
}
criterionMap.put(mfid, selector.getCriterion(t));
}
});
}
for (PiMatchFieldModel fieldModel : tableModel.matchFields()) {
PiMatchFieldId fieldId = fieldModel.id();
int bitWidth = fieldModel.bitWidth();
Criterion criterion = criterionMap.get(fieldId);
if (!piCriterionFields.containsKey(fieldId) && criterion == null) {
// Can ignore if match is ternary-like, as it means "don't care".
switch(fieldModel.matchType()) {
case TERNARY:
case LPM:
case RANGE:
case OPTIONAL:
// Skip field.
break;
default:
throw new PiTranslationException(format("No value found for required match field '%s'", fieldId));
}
// Next field.
continue;
}
PiFieldMatch fieldMatch = 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);
translatedCriteria.add(criterion);
} catch (PiTranslationException ex) {
// Ignore exception if the same field was found in PiCriterion.
if (piCriterionFields.containsKey(fieldId)) {
ignoredCriteria.add(criterion);
} else {
throw ex;
}
}
}
if (piCriterionFields.containsKey(fieldId)) {
// Field was found in PiCriterion.
if (fieldMatch != null) {
// Throw exception only if we are trying to match on different values of the same field...
if (!fieldMatch.equals(piCriterionFields.get(fieldId))) {
throw new PiTranslationException(format("Duplicate match field '%s': instance translated from criterion '%s' is different to " + "what found in PiCriterion.", fieldId, criterion.type()));
}
ignoredPiCriterionFields.add(fieldId);
} else {
fieldMatch = piCriterionFields.get(fieldId);
fieldMatch = typeCheckFieldMatch(fieldMatch, fieldModel);
usedPiCriterionFields.add(fieldId);
}
}
fieldMatches.put(fieldId, fieldMatch);
}
// Check if all criteria have been translated.
StringJoiner skippedCriteriaJoiner = new StringJoiner(", ");
selector.criteria().stream().filter(c -> !c.type().equals(PROTOCOL_INDEPENDENT)).filter(c -> !translatedCriteria.contains(c) && !ignoredCriteria.contains(c)).forEach(c -> skippedCriteriaJoiner.add(c.type().name()));
if (skippedCriteriaJoiner.length() > 0) {
throw new PiTranslationException(format("The following criteria cannot be translated for table '%s': %s", tableModel.id(), skippedCriteriaJoiner.toString()));
}
// Check if all fields found in PiCriterion have been used.
StringJoiner skippedPiFieldsJoiner = new StringJoiner(", ");
piCriterionFields.keySet().stream().filter(k -> !usedPiCriterionFields.contains(k) && !ignoredPiCriterionFields.contains(k)).forEach(k -> skippedPiFieldsJoiner.add(k.id()));
if (skippedPiFieldsJoiner.length() > 0) {
throw new PiTranslationException(format("The following PiCriterion field matches are not supported in table '%s': %s", tableModel.id(), skippedPiFieldsJoiner.toString()));
}
return fieldMatches.values();
}
use of org.onosproject.net.pi.runtime.PiFieldMatch in project onos by opennetworkinglab.
the class FieldMatchCodec method encode.
@Override
public P4RuntimeOuterClass.FieldMatch encode(PiFieldMatch piFieldMatch, P4InfoOuterClass.Preamble tablePreamble, PiPipeconf pipeconf, P4InfoBrowser browser) throws CodecException, P4InfoBrowser.NotFoundException {
P4RuntimeOuterClass.FieldMatch.Builder messageBuilder = P4RuntimeOuterClass.FieldMatch.newBuilder();
// FIXME: check how field names for stacked headers are constructed in P4Runtime.
String fieldName = piFieldMatch.fieldId().id();
P4InfoOuterClass.MatchField matchFieldInfo = browser.matchFields(tablePreamble.getId()).getByName(fieldName);
String entityName = format("field match '%s' of table '%s'", matchFieldInfo.getName(), tablePreamble.getName());
int fieldId = matchFieldInfo.getId();
int fieldBitwidth = matchFieldInfo.getBitwidth();
boolean isSdnString = browser.isTypeString(matchFieldInfo.getTypeName());
messageBuilder.setFieldId(fieldId);
switch(piFieldMatch.type()) {
case EXACT:
PiExactFieldMatch fieldMatch = (PiExactFieldMatch) piFieldMatch;
ByteString exactValue;
if (isSdnString) {
exactValue = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
} else {
exactValue = ByteString.copyFrom(fieldMatch.value().canonical().asReadOnlyBuffer());
assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
}
return messageBuilder.setExact(P4RuntimeOuterClass.FieldMatch.Exact.newBuilder().setValue(exactValue).build()).build();
case TERNARY:
PiTernaryFieldMatch ternaryMatch = (PiTernaryFieldMatch) piFieldMatch;
ByteString ternaryValue = ByteString.copyFrom(ternaryMatch.value().canonical().asReadOnlyBuffer());
ByteString ternaryMask = ByteString.copyFrom(ternaryMatch.mask().canonical().asReadOnlyBuffer());
if (isSdnString) {
sdnStringUnsupported(entityName, piFieldMatch.type());
}
assertSize(VALUE_OF_PREFIX + entityName, ternaryValue, fieldBitwidth);
assertSize(MASK_OF_PREFIX + entityName, ternaryMask, fieldBitwidth);
return messageBuilder.setTernary(P4RuntimeOuterClass.FieldMatch.Ternary.newBuilder().setValue(ternaryValue).setMask(ternaryMask).build()).build();
case LPM:
PiLpmFieldMatch lpmMatch = (PiLpmFieldMatch) piFieldMatch;
ByteString lpmValue = ByteString.copyFrom(lpmMatch.value().canonical().asReadOnlyBuffer());
int lpmPrefixLen = lpmMatch.prefixLength();
if (isSdnString) {
sdnStringUnsupported(entityName, piFieldMatch.type());
}
assertSize(VALUE_OF_PREFIX + entityName, lpmValue, fieldBitwidth);
assertPrefixLen(entityName, lpmPrefixLen, fieldBitwidth);
return messageBuilder.setLpm(P4RuntimeOuterClass.FieldMatch.LPM.newBuilder().setValue(lpmValue).setPrefixLen(lpmPrefixLen).build()).build();
case RANGE:
PiRangeFieldMatch rangeMatch = (PiRangeFieldMatch) piFieldMatch;
ByteString rangeHighValue = ByteString.copyFrom(rangeMatch.highValue().canonical().asReadOnlyBuffer());
ByteString rangeLowValue = ByteString.copyFrom(rangeMatch.lowValue().canonical().asReadOnlyBuffer());
if (isSdnString) {
sdnStringUnsupported(entityName, piFieldMatch.type());
}
assertSize(HIGH_RANGE_VALUE_OF_PREFIX + entityName, rangeHighValue, fieldBitwidth);
assertSize(LOW_RANGE_VALUE_OF_PREFIX + entityName, rangeLowValue, fieldBitwidth);
return messageBuilder.setRange(P4RuntimeOuterClass.FieldMatch.Range.newBuilder().setHigh(rangeHighValue).setLow(rangeLowValue).build()).build();
case OPTIONAL:
PiOptionalFieldMatch optionalMatch = (PiOptionalFieldMatch) piFieldMatch;
ByteString optionalValue;
if (isSdnString) {
optionalValue = ByteString.copyFrom(optionalMatch.value().asReadOnlyBuffer());
} else {
optionalValue = ByteString.copyFrom(optionalMatch.value().canonical().asReadOnlyBuffer());
assertSize(VALUE_OF_PREFIX + entityName, optionalValue, fieldBitwidth);
}
return messageBuilder.setOptional(P4RuntimeOuterClass.FieldMatch.Optional.newBuilder().setValue(optionalValue).build()).build();
default:
throw new CodecException(format("Building of match type %s not implemented", piFieldMatch.type()));
}
}
use of org.onosproject.net.pi.runtime.PiFieldMatch in project onos by opennetworkinglab.
the class FieldMatchCodec method decode.
@Override
public PiFieldMatch decode(P4RuntimeOuterClass.FieldMatch message, P4InfoOuterClass.Preamble tablePreamble, PiPipeconf pipeconf, P4InfoBrowser browser) throws CodecException, P4InfoBrowser.NotFoundException {
final P4InfoOuterClass.MatchField matchField = browser.matchFields(tablePreamble.getId()).getById(message.getFieldId());
final int fieldBitwidth = matchField.getBitwidth();
final PiMatchFieldId headerFieldId = PiMatchFieldId.of(matchField.getName());
final boolean isSdnString = browser.isTypeString(matchField.getTypeName());
final P4RuntimeOuterClass.FieldMatch.FieldMatchTypeCase typeCase = message.getFieldMatchTypeCase();
try {
switch(typeCase) {
case EXACT:
P4RuntimeOuterClass.FieldMatch.Exact exactFieldMatch = message.getExact();
final ImmutableByteSequence exactValue;
if (isSdnString) {
exactValue = copyFrom(new String(exactFieldMatch.getValue().toByteArray()));
} else {
exactValue = copyAndFit(exactFieldMatch.getValue().asReadOnlyByteBuffer(), fieldBitwidth);
}
return new PiExactFieldMatch(headerFieldId, exactValue);
case TERNARY:
P4RuntimeOuterClass.FieldMatch.Ternary ternaryFieldMatch = message.getTernary();
ImmutableByteSequence ternaryValue = copyAndFit(ternaryFieldMatch.getValue().asReadOnlyByteBuffer(), fieldBitwidth);
ImmutableByteSequence ternaryMask = copyAndFit(ternaryFieldMatch.getMask().asReadOnlyByteBuffer(), fieldBitwidth);
return new PiTernaryFieldMatch(headerFieldId, ternaryValue, ternaryMask);
case LPM:
P4RuntimeOuterClass.FieldMatch.LPM lpmFieldMatch = message.getLpm();
ImmutableByteSequence lpmValue = copyAndFit(lpmFieldMatch.getValue().asReadOnlyByteBuffer(), fieldBitwidth);
int lpmPrefixLen = lpmFieldMatch.getPrefixLen();
return new PiLpmFieldMatch(headerFieldId, lpmValue, lpmPrefixLen);
case RANGE:
P4RuntimeOuterClass.FieldMatch.Range rangeFieldMatch = message.getRange();
ImmutableByteSequence rangeHighValue = copyAndFit(rangeFieldMatch.getHigh().asReadOnlyByteBuffer(), fieldBitwidth);
ImmutableByteSequence rangeLowValue = copyAndFit(rangeFieldMatch.getLow().asReadOnlyByteBuffer(), fieldBitwidth);
return new PiRangeFieldMatch(headerFieldId, rangeLowValue, rangeHighValue);
case OPTIONAL:
P4RuntimeOuterClass.FieldMatch.Optional optionalFieldMatch = message.getOptional();
final ImmutableByteSequence optionalValue;
if (isSdnString) {
optionalValue = copyFrom(new String(optionalFieldMatch.getValue().toByteArray()));
} else {
optionalValue = copyAndFit(optionalFieldMatch.getValue().asReadOnlyByteBuffer(), fieldBitwidth);
}
return new PiOptionalFieldMatch(headerFieldId, optionalValue);
default:
throw new CodecException(format("Decoding of field match type '%s' not implemented", typeCase.name()));
}
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
throw new CodecException(e.getMessage());
}
}
use of org.onosproject.net.pi.runtime.PiFieldMatch in project up4 by omec-project.
the class Up4TranslatorUtil method getFieldPrefix.
static Ip4Prefix getFieldPrefix(PiTableEntry entry, PiMatchFieldId fieldId) {
Optional<PiFieldMatch> optField = entry.matchKey().fieldMatch(fieldId);
if (optField.isEmpty()) {
return null;
}
PiLpmFieldMatch field = (PiLpmFieldMatch) optField.get();
Ip4Address address = Ip4Address.valueOf(field.value().asArray());
return Ip4Prefix.valueOf(address, field.prefixLength());
}
use of org.onosproject.net.pi.runtime.PiFieldMatch in project up4 by omec-project.
the class Up4TranslatorUtil method getFieldRangeShort.
static Range<Short> getFieldRangeShort(PiTableEntry entry, PiMatchFieldId fieldId) {
Optional<PiFieldMatch> optField = entry.matchKey().fieldMatch(fieldId);
if (optField.isEmpty()) {
return null;
}
PiRangeFieldMatch field = (PiRangeFieldMatch) optField.get();
return Range.closed(byteSeqToShort(field.lowValue()), byteSeqToShort(field.highValue()));
}
Aggregations