use of org.onosproject.net.pi.service.PiTranslationException in project onos by opennetworkinglab.
the class P4RuntimeReplicationGroupProgrammable method processGroupOp.
private void processGroupOp(Group pdGroup, GroupOperation.Type opType) {
final PiPreEntry preEntry;
try {
preEntry = translator.translate(pdGroup, pipeconf);
} catch (PiTranslationException e) {
log.warn("Unable to translate replication group, aborting {} operation: {} [{}]", opType, e.getMessage(), pdGroup);
return;
}
final PiPreEntryHandle handle = (PiPreEntryHandle) preEntry.handle(deviceId);
final PiPreEntry entryOnDevice = mirror.get(handle) == null ? null : mirror.get(handle).entry();
final Lock lock = STRIPED_LOCKS.get(handle);
lock.lock();
try {
processPreEntry(handle, preEntry, entryOnDevice, pdGroup, opType);
} finally {
lock.unlock();
}
}
use of org.onosproject.net.pi.service.PiTranslationException in project onos by opennetworkinglab.
the class PiReplicationGroupTranslatorImpl method translate.
/**
* Returns a PI PRE entry equivalent to the given group, for the given
* pipeconf and device.
* <p>
* The passed group is expected to have type {@link GroupDescription.Type#ALL}
* or {@link GroupDescription.Type#CLONE}.
*
* @param group group
* @param pipeconf pipeconf
* @param device device
* @return PI PRE entry
* @throws PiTranslationException if the group cannot be translated
*/
static PiPreEntry translate(Group group, PiPipeconf pipeconf, Device device) throws PiTranslationException {
checkNotNull(group);
final List<OutputInstruction> outInstructions = Lists.newArrayList();
int truncateMaxLen = PiCloneSessionEntry.DO_NOT_TRUNCATE;
for (GroupBucket bucket : group.buckets().buckets()) {
int numInstructionsInBucket = bucket.treatment().allInstructions().size();
List<OutputInstruction> outputs = getInstructions(bucket, Instruction.Type.OUTPUT, OutputInstruction.class);
List<TruncateInstruction> truncates = getInstructions(bucket, Instruction.Type.TRUNCATE, TruncateInstruction.class);
if (outputs.size() != 1) {
throw new PiTranslationException("support only groups with just one OUTPUT instruction per bucket");
}
outInstructions.add(outputs.get(0));
if (truncates.size() != 0) {
if (group.type() != GroupDescription.Type.CLONE) {
throw new PiTranslationException("only CLONE group support truncate instruction");
}
if (truncates.size() != 1) {
throw new PiTranslationException("support only groups with just one TRUNCATE instruction per bucket");
}
int truncateInstMaxLen = truncates.get(0).maxLen();
if (truncateMaxLen != PiCloneSessionEntry.DO_NOT_TRUNCATE && truncateMaxLen != truncateInstMaxLen) {
throw new PiTranslationException("all TRUNCATE instruction must be the same in a CLONE group");
}
truncateMaxLen = truncateInstMaxLen;
} else if (truncateMaxLen != PiCloneSessionEntry.DO_NOT_TRUNCATE) {
// No truncate instruction found in this bucket, but previous bucket contains one.
throw new PiTranslationException("all TRUNCATE instruction must be the same in a CLONE group");
}
if (numInstructionsInBucket != outputs.size() + truncates.size()) {
throw new PiTranslationException("bucket contains unsupported instruction(s)");
}
}
switch(group.type()) {
case ALL:
return PiMulticastGroupEntry.builder().withGroupId(group.id().id()).addReplicas(getReplicas(outInstructions, device)).build();
case CLONE:
return PiCloneSessionEntry.builder().withSessionId(group.id().id()).addReplicas(getReplicas(outInstructions, device)).withMaxPacketLengthBytes(truncateMaxLen).build();
default:
throw new PiTranslationException(format("group type %s not supported", group.type()));
}
}
use of org.onosproject.net.pi.service.PiTranslationException in project onos by opennetworkinglab.
the class PiFlowRuleTranslatorImpl method typeCheckFieldMatch.
private static PiFieldMatch typeCheckFieldMatch(PiFieldMatch fieldMatch, PiMatchFieldModel fieldModel) throws PiTranslationException {
// Check parameter type and size
if (!fieldModel.matchType().equals(fieldMatch.type())) {
throw new PiTranslationException(format("Wrong match type for field '%s', expected %s, but found %s", fieldMatch.fieldId(), fieldModel.matchType().name(), fieldMatch.type().name()));
}
// Check if the arbitrary bit width is supported
if (!fieldModel.hasBitWidth() && !fieldModel.matchType().equals(PiMatchType.EXACT) && !fieldModel.matchType().equals(PiMatchType.OPTIONAL)) {
throw new PiTranslationException(format("Arbitrary bit width for field '%s' and match type %s is not supported", fieldMatch.fieldId(), fieldModel.matchType().name()));
}
int modelBitWidth = fieldModel.bitWidth();
try {
switch(fieldModel.matchType()) {
case EXACT:
PiExactFieldMatch exactField = (PiExactFieldMatch) fieldMatch;
return new PiExactFieldMatch(fieldMatch.fieldId(), fieldModel.hasBitWidth() ? exactField.value().fit(modelBitWidth) : exactField.value());
case TERNARY:
PiTernaryFieldMatch ternField = (PiTernaryFieldMatch) fieldMatch;
ImmutableByteSequence ternMask = ternField.mask().fit(modelBitWidth);
ImmutableByteSequence ternValue = ternField.value().fit(modelBitWidth).bitwiseAnd(ternMask);
return new PiTernaryFieldMatch(fieldMatch.fieldId(), ternValue, ternMask);
case LPM:
PiLpmFieldMatch lpmfield = (PiLpmFieldMatch) fieldMatch;
if (lpmfield.prefixLength() > modelBitWidth) {
throw new PiTranslationException(format("Invalid prefix length for LPM field '%s', found %d but field has bit-width %d", fieldMatch.fieldId(), lpmfield.prefixLength(), modelBitWidth));
}
ImmutableByteSequence lpmValue = lpmfield.value().fit(modelBitWidth);
ImmutableByteSequence lpmMask = prefixOnes(lpmValue.size(), lpmfield.prefixLength());
lpmValue = lpmValue.bitwiseAnd(lpmMask);
return new PiLpmFieldMatch(fieldMatch.fieldId(), lpmValue, lpmfield.prefixLength());
case RANGE:
return new PiRangeFieldMatch(fieldMatch.fieldId(), ((PiRangeFieldMatch) fieldMatch).lowValue().fit(modelBitWidth), ((PiRangeFieldMatch) fieldMatch).highValue().fit(modelBitWidth));
case OPTIONAL:
PiOptionalFieldMatch optionalField = (PiOptionalFieldMatch) fieldMatch;
return new PiOptionalFieldMatch(fieldMatch.fieldId(), fieldModel.hasBitWidth() ? optionalField.value().fit(modelBitWidth) : optionalField.value());
default:
// Should never be here.
throw new IllegalArgumentException("Unrecognized match type " + fieldModel.matchType().name());
}
} catch (ByteSequenceTrimException e) {
throw new PiTranslationException(format("Size mismatch for field %s: %s", fieldMatch.fieldId(), e.getMessage()));
}
}
use of org.onosproject.net.pi.service.PiTranslationException 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.service.PiTranslationException in project onos by opennetworkinglab.
the class P4RuntimeActionGroupProgrammable method processPdGroup.
private void processPdGroup(Group pdGroup, GroupOperation.Type opType) {
// Translate.
final PiActionProfileGroup piGroup;
try {
piGroup = groupTranslator.translate(pdGroup, pipeconf);
} catch (PiTranslationException e) {
log.warn("Unable to translate group, aborting {} operation: {} [{}]", opType, e.getMessage(), pdGroup);
return;
}
final Operation operation = opType.equals(GroupOperation.Type.DELETE) ? Operation.REMOVE : Operation.APPLY;
final PiActionProfileGroupHandle handle = piGroup.handle(deviceId);
// Update translation store.
if (operation.equals(Operation.APPLY)) {
groupTranslator.learn(handle, new PiTranslatedEntity<>(pdGroup, piGroup, handle));
} else {
groupTranslator.forget(handle);
}
// Submit write and forget about it.
asyncWritePiGroup(piGroup, handle, operation);
}
Aggregations