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