blob: 551bf5cc14365d8076654dec265868a3f33bff09 [file] [log] [blame]
/*
* Copyright 2018-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;
import com.google.protobuf.ByteString;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.pi.model.PiData;
import org.onosproject.net.pi.runtime.data.PiBitString;
import org.onosproject.net.pi.runtime.data.PiBool;
import org.onosproject.net.pi.runtime.data.PiEnumString;
import org.onosproject.net.pi.runtime.data.PiErrorString;
import org.onosproject.net.pi.runtime.data.PiHeader;
import org.onosproject.net.pi.runtime.data.PiHeaderStack;
import org.onosproject.net.pi.runtime.data.PiHeaderUnion;
import org.onosproject.net.pi.runtime.data.PiHeaderUnionStack;
import org.onosproject.net.pi.runtime.data.PiStruct;
import org.onosproject.net.pi.runtime.data.PiTuple;
import java.util.List;
import java.util.stream.Collectors;
import static p4.v1.P4DataOuterClass.P4Data;
import static p4.v1.P4DataOuterClass.P4Header;
import static p4.v1.P4DataOuterClass.P4HeaderStack;
import static p4.v1.P4DataOuterClass.P4HeaderUnion;
import static p4.v1.P4DataOuterClass.P4HeaderUnionStack;
import static p4.v1.P4DataOuterClass.P4StructLike;
/**
* Encoder/decoder of PI Data entry to P4 Data entry protobuf
* messages, and vice versa.
*/
final class P4DataCodec {
private P4DataCodec() {
// Hides constructor.
}
private static P4Header encodeHeader(PiHeader piHeader) {
P4Header.Builder builder = P4Header.newBuilder();
int i = 0;
for (ImmutableByteSequence bitString : piHeader.bitStrings()) {
builder.setBitstrings(i, ByteString.copyFrom(bitString.asArray()));
i++;
}
return builder.setIsValid(piHeader.isValid()).build();
}
private static PiHeader decodeHeader(P4Header p4Header) {
List<ImmutableByteSequence> bitStrings = p4Header.getBitstringsList().stream()
.map(bit -> ImmutableByteSequence.copyFrom(bit.asReadOnlyByteBuffer()))
.collect(Collectors.toList());
return PiHeader.of(p4Header.getIsValid(), bitStrings);
}
private static P4HeaderUnion encodeHeaderUnion(PiHeaderUnion headerUnion) {
P4HeaderUnion.Builder builder = P4HeaderUnion.newBuilder();
if (headerUnion.isValid()) {
builder.setValidHeader(encodeHeader(headerUnion.header()));
builder.setValidHeaderName(headerUnion.headerName());
} else {
// An empty string indicates that none of the union members are valid and
// valid_header must therefore be unset.
builder.setValidHeaderName("");
}
return builder.build();
}
private static PiHeaderUnion decodeHeaderUnion(P4HeaderUnion p4HeaderUnion) {
return PiHeaderUnion.of(p4HeaderUnion.getValidHeaderName(),
decodeHeader(p4HeaderUnion.getValidHeader()));
}
private static P4StructLike encodeStruct(PiStruct piStruct) {
P4StructLike.Builder builder = P4StructLike.newBuilder();
builder.addAllMembers(piStruct.struct().stream()
.map(P4DataCodec::encodeP4Data)
.collect(Collectors.toList()));
return builder.build();
}
private static PiStruct decodeStruct(P4StructLike p4StructLike) {
return PiStruct.of(p4StructLike.getMembersList().stream()
.map(P4DataCodec::decodeP4Data)
.collect(Collectors.toList()));
}
private static P4StructLike encodeTuple(PiTuple piTuple) {
P4StructLike.Builder builder = P4StructLike.newBuilder();
builder.addAllMembers(piTuple.tuple().stream()
.map(P4DataCodec::encodeP4Data)
.collect(Collectors.toList()));
return builder.build();
}
private static PiTuple decodeTuple(P4StructLike p4StructLike) {
return PiTuple.of(p4StructLike.getMembersList().stream()
.map(P4DataCodec::decodeP4Data)
.collect(Collectors.toList()));
}
static P4Data encodeP4Data(PiData piData) {
P4Data.Builder builder = P4Data.newBuilder();
switch (piData.type()) {
case BITSTRING:
builder.setBitstring(ByteString.copyFrom(((PiBitString) piData).bitString().asArray()));
break;
case ENUMSTRING:
builder.setEnum(((PiEnumString) piData).enumString());
break;
case ERRORSTRING:
builder.setError(((PiErrorString) piData).errorString());
break;
case BOOL:
builder.setBool(((PiBool) piData).bool());
break;
case STRUCT:
builder.setStruct(encodeStruct((PiStruct) piData));
break;
case TUPLE:
builder.setTuple(encodeTuple((PiTuple) piData));
break;
case HEADER:
builder.setHeader(encodeHeader((PiHeader) piData));
break;
case HEADERSTACK:
P4HeaderStack.Builder headerStack = P4HeaderStack.newBuilder();
int i = 0;
for (PiHeader header : ((PiHeaderStack) piData).headers()) {
headerStack.setEntries(i, encodeHeader(header));
i++;
}
builder.setHeaderStack(headerStack.build());
break;
case HEADERUNION:
builder.setHeaderUnion(encodeHeaderUnion((PiHeaderUnion) piData));
break;
case HEADERUNIONSTACK:
P4HeaderUnionStack.Builder headerUnionStack = P4HeaderUnionStack.newBuilder();
int j = 0;
for (PiHeaderUnion headerUnion : ((PiHeaderUnionStack) piData).headerUnions()) {
headerUnionStack.setEntries(j, encodeHeaderUnion(headerUnion));
j++;
}
builder.setHeaderUnionStack(headerUnionStack.build());
break;
default:
break;
}
return builder.build();
}
static PiData decodeP4Data(P4Data p4Data) {
PiData piData = null;
switch (p4Data.getDataCase()) {
case BITSTRING:
piData = PiBitString.of(ImmutableByteSequence.copyFrom(p4Data.getBitstring().asReadOnlyByteBuffer()));
break;
case BOOL:
piData = PiBool.of(p4Data.getBool());
break;
case TUPLE:
piData = decodeTuple(p4Data.getTuple());
break;
case STRUCT:
piData = decodeStruct(p4Data.getStruct());
break;
case HEADER:
piData = decodeHeader(p4Data.getHeader());
break;
case HEADER_UNION:
piData = decodeHeaderUnion(p4Data.getHeaderUnion());
break;
case HEADER_STACK:
piData = PiHeaderStack.of(p4Data.getHeaderStack().getEntriesList().stream()
.map(P4DataCodec::decodeHeader)
.collect(Collectors.toList()));
break;
case HEADER_UNION_STACK:
piData = PiHeaderUnionStack.of(p4Data.getHeaderUnionStack()
.getEntriesList().stream()
.map(P4DataCodec::decodeHeaderUnion)
.collect(Collectors.toList()));
break;
case ENUM:
piData = PiEnumString.of(p4Data.getEnum());
break;
case ERROR:
piData = PiErrorString.of(p4Data.getError());
break;
case DATA_NOT_SET:
break;
default:
break;
}
return piData;
}
}