FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 1 | /* |
Carmelo Cascone | 4c289b7 | 2019-01-22 15:30:45 -0800 | [diff] [blame] | 2 | * Copyright 2019-present Open Networking Foundation |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Carmelo Cascone | 4c289b7 | 2019-01-22 15:30:45 -0800 | [diff] [blame] | 17 | package org.onosproject.p4runtime.ctl.codec; |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 18 | |
| 19 | import com.google.protobuf.ByteString; |
| 20 | import org.onlab.util.ImmutableByteSequence; |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 21 | import org.onosproject.net.pi.model.PiData; |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 22 | import org.onosproject.net.pi.runtime.data.PiBitString; |
| 23 | import org.onosproject.net.pi.runtime.data.PiBool; |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 24 | import org.onosproject.net.pi.runtime.data.PiEnumString; |
| 25 | import org.onosproject.net.pi.runtime.data.PiErrorString; |
| 26 | import org.onosproject.net.pi.runtime.data.PiHeader; |
| 27 | import org.onosproject.net.pi.runtime.data.PiHeaderStack; |
| 28 | import org.onosproject.net.pi.runtime.data.PiHeaderUnion; |
| 29 | import org.onosproject.net.pi.runtime.data.PiHeaderUnionStack; |
| 30 | import org.onosproject.net.pi.runtime.data.PiStruct; |
| 31 | import org.onosproject.net.pi.runtime.data.PiTuple; |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 32 | |
| 33 | import java.util.List; |
| 34 | import java.util.stream.Collectors; |
| 35 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 36 | import static p4.v1.P4DataOuterClass.P4Data; |
| 37 | import static p4.v1.P4DataOuterClass.P4Header; |
| 38 | import static p4.v1.P4DataOuterClass.P4HeaderStack; |
| 39 | import static p4.v1.P4DataOuterClass.P4HeaderUnion; |
| 40 | import static p4.v1.P4DataOuterClass.P4HeaderUnionStack; |
| 41 | import static p4.v1.P4DataOuterClass.P4StructLike; |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 42 | |
| 43 | /** |
Carmelo Cascone | 4c289b7 | 2019-01-22 15:30:45 -0800 | [diff] [blame] | 44 | * Encoder/decoder of PI Data entry to P4 Data entry protobuf messages, and vice |
| 45 | * versa. |
| 46 | * <p> |
| 47 | * TODO: implement codec for each P4Data type using AbstractP4RuntimeCodec. |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 48 | */ |
| 49 | final class P4DataCodec { |
| 50 | |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 51 | private P4DataCodec() { |
| 52 | // Hides constructor. |
| 53 | } |
| 54 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 55 | private static P4Header encodeHeader(PiHeader piHeader) { |
| 56 | P4Header.Builder builder = P4Header.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 57 | int i = 0; |
| 58 | for (ImmutableByteSequence bitString : piHeader.bitStrings()) { |
| 59 | builder.setBitstrings(i, ByteString.copyFrom(bitString.asArray())); |
| 60 | i++; |
| 61 | } |
| 62 | return builder.setIsValid(piHeader.isValid()).build(); |
| 63 | } |
| 64 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 65 | private static PiHeader decodeHeader(P4Header p4Header) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 66 | List<ImmutableByteSequence> bitStrings = p4Header.getBitstringsList().stream() |
| 67 | .map(bit -> ImmutableByteSequence.copyFrom(bit.asReadOnlyByteBuffer())) |
| 68 | .collect(Collectors.toList()); |
| 69 | |
| 70 | return PiHeader.of(p4Header.getIsValid(), bitStrings); |
| 71 | } |
| 72 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 73 | private static P4HeaderUnion encodeHeaderUnion(PiHeaderUnion headerUnion) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 74 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 75 | P4HeaderUnion.Builder builder = P4HeaderUnion.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 76 | if (headerUnion.isValid()) { |
| 77 | builder.setValidHeader(encodeHeader(headerUnion.header())); |
| 78 | builder.setValidHeaderName(headerUnion.headerName()); |
| 79 | } else { |
| 80 | // An empty string indicates that none of the union members are valid and |
| 81 | // valid_header must therefore be unset. |
| 82 | builder.setValidHeaderName(""); |
| 83 | } |
| 84 | |
| 85 | return builder.build(); |
| 86 | } |
| 87 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 88 | private static PiHeaderUnion decodeHeaderUnion(P4HeaderUnion p4HeaderUnion) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 89 | |
| 90 | return PiHeaderUnion.of(p4HeaderUnion.getValidHeaderName(), |
| 91 | decodeHeader(p4HeaderUnion.getValidHeader())); |
| 92 | } |
| 93 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 94 | private static P4StructLike encodeStruct(PiStruct piStruct) { |
| 95 | P4StructLike.Builder builder = P4StructLike.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 96 | builder.addAllMembers(piStruct.struct().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 97 | .map(P4DataCodec::encodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 98 | .collect(Collectors.toList())); |
| 99 | return builder.build(); |
| 100 | } |
| 101 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 102 | private static PiStruct decodeStruct(P4StructLike p4StructLike) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 103 | |
| 104 | return PiStruct.of(p4StructLike.getMembersList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 105 | .map(P4DataCodec::decodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 106 | .collect(Collectors.toList())); |
| 107 | } |
| 108 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 109 | private static P4StructLike encodeTuple(PiTuple piTuple) { |
| 110 | P4StructLike.Builder builder = P4StructLike.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 111 | builder.addAllMembers(piTuple.tuple().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 112 | .map(P4DataCodec::encodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 113 | .collect(Collectors.toList())); |
| 114 | return builder.build(); |
| 115 | } |
| 116 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 117 | private static PiTuple decodeTuple(P4StructLike p4StructLike) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 118 | |
| 119 | return PiTuple.of(p4StructLike.getMembersList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 120 | .map(P4DataCodec::decodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 121 | .collect(Collectors.toList())); |
| 122 | } |
| 123 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 124 | static P4Data encodeP4Data(PiData piData) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 125 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 126 | P4Data.Builder builder = P4Data.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 127 | switch (piData.type()) { |
| 128 | case BITSTRING: |
| 129 | builder.setBitstring(ByteString.copyFrom(((PiBitString) piData).bitString().asArray())); |
| 130 | break; |
| 131 | case ENUMSTRING: |
| 132 | builder.setEnum(((PiEnumString) piData).enumString()); |
| 133 | break; |
| 134 | case ERRORSTRING: |
| 135 | builder.setError(((PiErrorString) piData).errorString()); |
| 136 | break; |
| 137 | case BOOL: |
| 138 | builder.setBool(((PiBool) piData).bool()); |
| 139 | break; |
| 140 | case STRUCT: |
| 141 | builder.setStruct(encodeStruct((PiStruct) piData)); |
| 142 | break; |
| 143 | case TUPLE: |
| 144 | builder.setTuple(encodeTuple((PiTuple) piData)); |
| 145 | break; |
| 146 | case HEADER: |
| 147 | builder.setHeader(encodeHeader((PiHeader) piData)); |
| 148 | break; |
| 149 | case HEADERSTACK: |
Carmelo Cascone | 4c289b7 | 2019-01-22 15:30:45 -0800 | [diff] [blame] | 150 | P4HeaderStack.Builder headerStack = P4HeaderStack.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 151 | int i = 0; |
| 152 | for (PiHeader header : ((PiHeaderStack) piData).headers()) { |
| 153 | headerStack.setEntries(i, encodeHeader(header)); |
| 154 | i++; |
| 155 | } |
| 156 | builder.setHeaderStack(headerStack.build()); |
| 157 | break; |
| 158 | case HEADERUNION: |
| 159 | builder.setHeaderUnion(encodeHeaderUnion((PiHeaderUnion) piData)); |
| 160 | break; |
| 161 | case HEADERUNIONSTACK: |
Carmelo Cascone | 4c289b7 | 2019-01-22 15:30:45 -0800 | [diff] [blame] | 162 | P4HeaderUnionStack.Builder headerUnionStack = P4HeaderUnionStack.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 163 | int j = 0; |
| 164 | for (PiHeaderUnion headerUnion : ((PiHeaderUnionStack) piData).headerUnions()) { |
| 165 | headerUnionStack.setEntries(j, encodeHeaderUnion(headerUnion)); |
| 166 | j++; |
| 167 | } |
| 168 | builder.setHeaderUnionStack(headerUnionStack.build()); |
| 169 | break; |
| 170 | default: |
| 171 | break; |
| 172 | } |
| 173 | |
| 174 | return builder.build(); |
| 175 | } |
| 176 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 177 | static PiData decodeP4Data(P4Data p4Data) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 178 | PiData piData = null; |
| 179 | |
| 180 | switch (p4Data.getDataCase()) { |
| 181 | case BITSTRING: |
| 182 | piData = PiBitString.of(ImmutableByteSequence.copyFrom(p4Data.getBitstring().asReadOnlyByteBuffer())); |
| 183 | break; |
| 184 | case BOOL: |
| 185 | piData = PiBool.of(p4Data.getBool()); |
| 186 | break; |
| 187 | case TUPLE: |
| 188 | piData = decodeTuple(p4Data.getTuple()); |
| 189 | break; |
| 190 | case STRUCT: |
| 191 | piData = decodeStruct(p4Data.getStruct()); |
| 192 | break; |
| 193 | case HEADER: |
| 194 | piData = decodeHeader(p4Data.getHeader()); |
| 195 | break; |
| 196 | case HEADER_UNION: |
| 197 | piData = decodeHeaderUnion(p4Data.getHeaderUnion()); |
| 198 | break; |
| 199 | case HEADER_STACK: |
| 200 | piData = PiHeaderStack.of(p4Data.getHeaderStack().getEntriesList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 201 | .map(P4DataCodec::decodeHeader) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 202 | .collect(Collectors.toList())); |
| 203 | break; |
| 204 | case HEADER_UNION_STACK: |
| 205 | piData = PiHeaderUnionStack.of(p4Data.getHeaderUnionStack() |
| 206 | .getEntriesList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 207 | .map(P4DataCodec::decodeHeaderUnion) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 208 | .collect(Collectors.toList())); |
| 209 | break; |
| 210 | case ENUM: |
| 211 | piData = PiEnumString.of(p4Data.getEnum()); |
| 212 | break; |
| 213 | case ERROR: |
| 214 | piData = PiErrorString.of(p4Data.getError()); |
| 215 | break; |
| 216 | case DATA_NOT_SET: |
| 217 | break; |
| 218 | default: |
| 219 | break; |
| 220 | } |
| 221 | |
| 222 | return piData; |
| 223 | } |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame] | 224 | } |