blob: 48baa1751873373ffefd16933bc1422d1ee5bb94 [file] [log] [blame]
/*
* Copyright 2019-present Open Networking Foundation
*
* 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.p4runtime.ctl.codec;
import com.google.protobuf.ByteString;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.pi.model.PiMatchFieldId;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.runtime.PiExactFieldMatch;
import org.onosproject.net.pi.runtime.PiFieldMatch;
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
import org.onosproject.net.pi.runtime.PiOptionalFieldMatch;
import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
import org.onosproject.p4runtime.ctl.utils.P4InfoBrowser;
import p4.config.v1.P4InfoOuterClass;
import p4.v1.P4RuntimeOuterClass;
import static java.lang.String.format;
import static org.onlab.util.ImmutableByteSequence.copyAndFit;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onosproject.p4runtime.ctl.codec.Utils.assertPrefixLen;
import static org.onosproject.p4runtime.ctl.codec.Utils.assertSize;
import static org.onosproject.p4runtime.ctl.codec.Utils.sdnStringUnsupported;
/**
* Codec for P4Runtime FieldMatch. Metadata is expected to be a Preamble for
* P4Info.Table.
*/
public final class FieldMatchCodec
extends AbstractCodec<PiFieldMatch, P4RuntimeOuterClass.FieldMatch,
P4InfoOuterClass.Preamble> {
private static final String VALUE_OF_PREFIX = "value of ";
private static final String MASK_OF_PREFIX = "mask of ";
private static final String HIGH_RANGE_VALUE_OF_PREFIX = "high range value of ";
private static final String LOW_RANGE_VALUE_OF_PREFIX = "low range value of ";
@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 = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
if (!isSdnString) {
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().asReadOnlyBuffer());
ByteString ternaryMask = ByteString.copyFrom(ternaryMatch.mask().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().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().asReadOnlyBuffer());
ByteString rangeLowValue = ByteString.copyFrom(rangeMatch.lowValue().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 = ByteString.copyFrom(optionalMatch.value().asReadOnlyBuffer());
if (!isSdnString) {
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()));
}
}
@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());
}
}
}