FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018-present Open Networking Foundation |
| 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 | |
| 17 | package org.onosproject.p4runtime.ctl; |
| 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 | /** |
| 44 | * Encoder/decoder of PI Data entry to P4 Data entry protobuf |
| 45 | * messages, and vice versa. |
| 46 | */ |
| 47 | final class P4DataCodec { |
| 48 | |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 49 | private P4DataCodec() { |
| 50 | // Hides constructor. |
| 51 | } |
| 52 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 53 | private static P4Header encodeHeader(PiHeader piHeader) { |
| 54 | P4Header.Builder builder = P4Header.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 55 | int i = 0; |
| 56 | for (ImmutableByteSequence bitString : piHeader.bitStrings()) { |
| 57 | builder.setBitstrings(i, ByteString.copyFrom(bitString.asArray())); |
| 58 | i++; |
| 59 | } |
| 60 | return builder.setIsValid(piHeader.isValid()).build(); |
| 61 | } |
| 62 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 63 | private static PiHeader decodeHeader(P4Header p4Header) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 64 | List<ImmutableByteSequence> bitStrings = p4Header.getBitstringsList().stream() |
| 65 | .map(bit -> ImmutableByteSequence.copyFrom(bit.asReadOnlyByteBuffer())) |
| 66 | .collect(Collectors.toList()); |
| 67 | |
| 68 | return PiHeader.of(p4Header.getIsValid(), bitStrings); |
| 69 | } |
| 70 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 71 | private static P4HeaderUnion encodeHeaderUnion(PiHeaderUnion headerUnion) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 72 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 73 | P4HeaderUnion.Builder builder = P4HeaderUnion.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 74 | if (headerUnion.isValid()) { |
| 75 | builder.setValidHeader(encodeHeader(headerUnion.header())); |
| 76 | builder.setValidHeaderName(headerUnion.headerName()); |
| 77 | } else { |
| 78 | // An empty string indicates that none of the union members are valid and |
| 79 | // valid_header must therefore be unset. |
| 80 | builder.setValidHeaderName(""); |
| 81 | } |
| 82 | |
| 83 | return builder.build(); |
| 84 | } |
| 85 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 86 | private static PiHeaderUnion decodeHeaderUnion(P4HeaderUnion p4HeaderUnion) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 87 | |
| 88 | return PiHeaderUnion.of(p4HeaderUnion.getValidHeaderName(), |
| 89 | decodeHeader(p4HeaderUnion.getValidHeader())); |
| 90 | } |
| 91 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 92 | private static P4StructLike encodeStruct(PiStruct piStruct) { |
| 93 | P4StructLike.Builder builder = P4StructLike.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 94 | builder.addAllMembers(piStruct.struct().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 95 | .map(P4DataCodec::encodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 96 | .collect(Collectors.toList())); |
| 97 | return builder.build(); |
| 98 | } |
| 99 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 100 | private static PiStruct decodeStruct(P4StructLike p4StructLike) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 101 | |
| 102 | return PiStruct.of(p4StructLike.getMembersList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 103 | .map(P4DataCodec::decodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 104 | .collect(Collectors.toList())); |
| 105 | } |
| 106 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 107 | private static P4StructLike encodeTuple(PiTuple piTuple) { |
| 108 | P4StructLike.Builder builder = P4StructLike.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 109 | builder.addAllMembers(piTuple.tuple().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 110 | .map(P4DataCodec::encodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 111 | .collect(Collectors.toList())); |
| 112 | return builder.build(); |
| 113 | } |
| 114 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 115 | private static PiTuple decodeTuple(P4StructLike p4StructLike) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 116 | |
| 117 | return PiTuple.of(p4StructLike.getMembersList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 118 | .map(P4DataCodec::decodeP4Data) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 119 | .collect(Collectors.toList())); |
| 120 | } |
| 121 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 122 | static P4Data encodeP4Data(PiData piData) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 123 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 124 | P4Data.Builder builder = P4Data.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 125 | switch (piData.type()) { |
| 126 | case BITSTRING: |
| 127 | builder.setBitstring(ByteString.copyFrom(((PiBitString) piData).bitString().asArray())); |
| 128 | break; |
| 129 | case ENUMSTRING: |
| 130 | builder.setEnum(((PiEnumString) piData).enumString()); |
| 131 | break; |
| 132 | case ERRORSTRING: |
| 133 | builder.setError(((PiErrorString) piData).errorString()); |
| 134 | break; |
| 135 | case BOOL: |
| 136 | builder.setBool(((PiBool) piData).bool()); |
| 137 | break; |
| 138 | case STRUCT: |
| 139 | builder.setStruct(encodeStruct((PiStruct) piData)); |
| 140 | break; |
| 141 | case TUPLE: |
| 142 | builder.setTuple(encodeTuple((PiTuple) piData)); |
| 143 | break; |
| 144 | case HEADER: |
| 145 | builder.setHeader(encodeHeader((PiHeader) piData)); |
| 146 | break; |
| 147 | case HEADERSTACK: |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 148 | P4HeaderStack.Builder headerStack = P4HeaderStack.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 149 | int i = 0; |
| 150 | for (PiHeader header : ((PiHeaderStack) piData).headers()) { |
| 151 | headerStack.setEntries(i, encodeHeader(header)); |
| 152 | i++; |
| 153 | } |
| 154 | builder.setHeaderStack(headerStack.build()); |
| 155 | break; |
| 156 | case HEADERUNION: |
| 157 | builder.setHeaderUnion(encodeHeaderUnion((PiHeaderUnion) piData)); |
| 158 | break; |
| 159 | case HEADERUNIONSTACK: |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 160 | P4HeaderUnionStack.Builder headerUnionStack = P4HeaderUnionStack.newBuilder(); |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 161 | int j = 0; |
| 162 | for (PiHeaderUnion headerUnion : ((PiHeaderUnionStack) piData).headerUnions()) { |
| 163 | headerUnionStack.setEntries(j, encodeHeaderUnion(headerUnion)); |
| 164 | j++; |
| 165 | } |
| 166 | builder.setHeaderUnionStack(headerUnionStack.build()); |
| 167 | break; |
| 168 | default: |
| 169 | break; |
| 170 | } |
| 171 | |
| 172 | return builder.build(); |
| 173 | } |
| 174 | |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 175 | static PiData decodeP4Data(P4Data p4Data) { |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 176 | PiData piData = null; |
| 177 | |
| 178 | switch (p4Data.getDataCase()) { |
| 179 | case BITSTRING: |
| 180 | piData = PiBitString.of(ImmutableByteSequence.copyFrom(p4Data.getBitstring().asReadOnlyByteBuffer())); |
| 181 | break; |
| 182 | case BOOL: |
| 183 | piData = PiBool.of(p4Data.getBool()); |
| 184 | break; |
| 185 | case TUPLE: |
| 186 | piData = decodeTuple(p4Data.getTuple()); |
| 187 | break; |
| 188 | case STRUCT: |
| 189 | piData = decodeStruct(p4Data.getStruct()); |
| 190 | break; |
| 191 | case HEADER: |
| 192 | piData = decodeHeader(p4Data.getHeader()); |
| 193 | break; |
| 194 | case HEADER_UNION: |
| 195 | piData = decodeHeaderUnion(p4Data.getHeaderUnion()); |
| 196 | break; |
| 197 | case HEADER_STACK: |
| 198 | piData = PiHeaderStack.of(p4Data.getHeaderStack().getEntriesList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 199 | .map(P4DataCodec::decodeHeader) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 200 | .collect(Collectors.toList())); |
| 201 | break; |
| 202 | case HEADER_UNION_STACK: |
| 203 | piData = PiHeaderUnionStack.of(p4Data.getHeaderUnionStack() |
| 204 | .getEntriesList().stream() |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 205 | .map(P4DataCodec::decodeHeaderUnion) |
FrankWang | ea70de3 | 2018-05-08 15:41:25 +0800 | [diff] [blame] | 206 | .collect(Collectors.toList())); |
| 207 | break; |
| 208 | case ENUM: |
| 209 | piData = PiEnumString.of(p4Data.getEnum()); |
| 210 | break; |
| 211 | case ERROR: |
| 212 | piData = PiErrorString.of(p4Data.getError()); |
| 213 | break; |
| 214 | case DATA_NOT_SET: |
| 215 | break; |
| 216 | default: |
| 217 | break; |
| 218 | } |
| 219 | |
| 220 | return piData; |
| 221 | } |
Carmelo Cascone | 6af4e17 | 2018-06-15 16:01:30 +0200 | [diff] [blame^] | 222 | } |