use of org.onosproject.net.pi.model.PiMatchFieldId 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.model.PiMatchFieldId in project onos by opennetworkinglab.
the class PiMatchFieldIdTest method testConstructionWithIndex.
/**
* Checks the construction of a PiMatchFieldId object with index.
*/
@Test
public void testConstructionWithIndex() {
final String name = IPV4_HEADER_NAME + DOT + DST_ADDR + "[1]";
final PiMatchFieldId piMatchFieldId = PiMatchFieldId.of(name);
assertThat(piMatchFieldId, is(notNullValue()));
assertThat(piMatchFieldId.id(), is(name));
}
use of org.onosproject.net.pi.model.PiMatchFieldId in project onos by opennetworkinglab.
the class PiMatchFieldIdTest method testConstruction.
/**
* Checks the construction of a PiMatchFieldId object.
*/
@Test
public void testConstruction() {
final String name = IPV4_HEADER_NAME + DOT + DST_ADDR;
final PiMatchFieldId piMatchFieldId = PiMatchFieldId.of(name);
assertThat(piMatchFieldId, is(notNullValue()));
assertThat(piMatchFieldId.id(), is(name));
}
use of org.onosproject.net.pi.model.PiMatchFieldId in project onos by opennetworkinglab.
the class PiTernaryFieldMatchTest method testConstruction.
/**
* Checks the construction of a PiTernaryFieldMatch object.
*/
@Test
public void testConstruction() {
final ImmutableByteSequence value = copyFrom(0x0a01010a);
final ImmutableByteSequence mask = copyFrom(0x00ffffff);
final PiMatchFieldId piMatchField = PiMatchFieldId.of(IPV4_HEADER_NAME + DOT + DST_ADDR);
PiTernaryFieldMatch piTernaryFieldMatch = new PiTernaryFieldMatch(piMatchField, value, mask);
assertThat(piTernaryFieldMatch, is(notNullValue()));
assertThat(piTernaryFieldMatch.value(), is(value));
assertThat(piTernaryFieldMatch.mask(), is(mask));
assertThat(piTernaryFieldMatch.type(), is(PiMatchType.TERNARY));
}
use of org.onosproject.net.pi.model.PiMatchFieldId in project onos by opennetworkinglab.
the class PiOptionalFieldMatchTest method testConstruction.
/**
* Checks the construction of a PiOptionalFieldMatch object.
*/
@Test
public void testConstruction() {
final ImmutableByteSequence value = copyFrom(0x0806);
final PiMatchFieldId piMatchField = PiMatchFieldId.of(ETH_HEADER_NAME + DOT + ETH_TYPE);
PiOptionalFieldMatch piOptionalFieldMatch = new PiOptionalFieldMatch(piMatchField, value);
assertThat(piOptionalFieldMatch, is(notNullValue()));
assertThat(piOptionalFieldMatch.value(), is(value));
assertThat(piOptionalFieldMatch.type(), is(PiMatchType.OPTIONAL));
}
Aggregations