blob: a06fe7a011da4b208fea753aa8a966aa82779fef [file] [log] [blame]
Andrea Campanellafc1d34c2017-07-18 17:01:41 +02001/*
2 * Copyright 2017-present Open Networking Laboratory
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
17package org.onosproject.p4runtime.ctl;
18
19import com.google.protobuf.ByteString;
Andrea Campanella288b2732017-07-28 14:16:16 +020020import org.onlab.util.ImmutableByteSequence;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020021import org.onosproject.net.pi.model.PiPipeconf;
Andrea Campanella288b2732017-07-28 14:16:16 +020022import org.onosproject.net.pi.runtime.PiPacketMetadata;
23import org.onosproject.net.pi.runtime.PiPacketMetadataId;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020024import org.onosproject.net.pi.runtime.PiPacketOperation;
25import org.slf4j.Logger;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020026import p4.config.P4InfoOuterClass;
27
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020028import java.util.Collections;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020029import java.util.List;
30import java.util.Objects;
31import java.util.stream.Collectors;
32
Andrea Campanella288b2732017-07-28 14:16:16 +020033import static org.onlab.util.ImmutableByteSequence.copyFrom;
34import static org.onosproject.p4runtime.ctl.P4InfoBrowser.NotFoundException;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020035import static org.slf4j.LoggerFactory.getLogger;
Andrea Campanella288b2732017-07-28 14:16:16 +020036import static p4.P4RuntimeOuterClass.PacketIn;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020037import static p4.P4RuntimeOuterClass.PacketMetadata;
Andrea Campanella288b2732017-07-28 14:16:16 +020038import static p4.P4RuntimeOuterClass.PacketOut;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020039
40/**
41 * Encoder of packet metadata, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
42 */
43final class PacketIOCodec {
44
45 private static final Logger log = getLogger(PacketIOCodec.class);
46
47 private static final String PACKET_OUT = "packet_out";
48
Andrea Campanella288b2732017-07-28 14:16:16 +020049 private static final String PACKET_IN = "packet_in";
50
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020051 // TODO: implement cache of encoded entities.
52
53 private PacketIOCodec() {
54 // hide.
55 }
56
57 /**
58 * Returns a P4Runtime packet out protobuf message, encoded from the given PiPacketOperation
59 * for the given pipeconf. If a PI packet metadata inside the PacketOperation cannot be encoded,
60 * it is skipped, hence the returned PacketOut collection of metadatas might have different
61 * size than the input one.
62 * <p>
63 * Please check the log for an explanation of any error that might have occurred.
64 *
Andrea Campanella288b2732017-07-28 14:16:16 +020065 * @param packet PI packet operation
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020066 * @param pipeconf the pipeconf for the program on the switch
67 * @return a P4Runtime packet out protobuf message
68 * @throws NotFoundException if the browser can't find the packet_out in the given p4Info
69 */
Andrea Campanella288b2732017-07-28 14:16:16 +020070 static PacketOut encodePacketOut(PiPacketOperation packet, PiPipeconf pipeconf)
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020071 throws NotFoundException {
72
73 //Get the P4browser
74 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
75
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020076 //Get the packet out controller packet metadata
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020077 P4InfoOuterClass.ControllerPacketMetadata controllerPacketMetadata =
78 browser.controllerPacketMetadatas().getByName(PACKET_OUT);
Andrea Campanella288b2732017-07-28 14:16:16 +020079 PacketOut.Builder packetOutBuilder = PacketOut.newBuilder();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020080
81 //outer controller packet metadata id
82 int controllerPacketMetadataId = controllerPacketMetadata.getPreamble().getId();
83
84 //Add all its metadata to the packet out
85 packetOutBuilder.addAllMetadata(encodePacketMetadata(packet, browser, controllerPacketMetadataId));
86
87 //Set the packet out payload
88 packetOutBuilder.setPayload(ByteString.copyFrom(packet.data().asReadOnlyBuffer()));
89 return packetOutBuilder.build();
90
91 }
92
93 private static List<PacketMetadata> encodePacketMetadata(PiPacketOperation packet,
94 P4InfoBrowser browser, int controllerPacketMetadataId) {
95 return packet.metadatas().stream().map(metadata -> {
96 try {
97 //get each metadata id
98 int metadataId = browser.packetMetadatas(controllerPacketMetadataId)
99 .getByName(metadata.id().name()).getId();
100
101 //Add the metadata id and it's data the packet out
102 return PacketMetadata.newBuilder()
103 .setMetadataId(metadataId)
104 .setValue(ByteString.copyFrom(metadata.value().asReadOnlyBuffer()))
105 .build();
106 } catch (NotFoundException e) {
107 log.error("Cant find metadata with name {} in p4Info file.", metadata.id().name());
108 return null;
109 }
110 }).filter(Objects::nonNull).collect(Collectors.toList());
111 }
112
Andrea Campanella288b2732017-07-28 14:16:16 +0200113 /**
114 * Returns a PiPacketOperation, decoded from the given P4Runtime PacketIn protobuf message
115 * for the given pipeconf. If a PI packet metadata inside the protobuf message cannot be decoded,
116 * it is skipped, hence the returned PiPacketOperation collection of metadatas might have different
117 * size than the input one.
118 * <p>
119 * Please check the log for an explanation of any error that might have occurred.
120 *
121 * @param packetIn the P4Runtime PAcketIn message
122 * @param pipeconf the pipeconf for the program on the switch
123 * @return a PiPacketOperation
124 */
125 static PiPacketOperation decodePacketIn(PacketIn packetIn, PiPipeconf pipeconf) {
126
127 //Get the P4browser
128 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
129
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200130 List<PiPacketMetadata> packetMetadatas;
131 try {
132 int controllerPacketMetadataId = browser.controllerPacketMetadatas().getByName(PACKET_IN)
133 .getPreamble().getId();
134 packetMetadatas = decodePacketMetadataIn(packetIn.getMetadataList(), browser,
135 controllerPacketMetadataId);
136 } catch (NotFoundException e) {
137 log.error("Unable to decode packet metadatas: {}", e.getMessage());
138 packetMetadatas = Collections.emptyList();
139 }
140
Andrea Campanella288b2732017-07-28 14:16:16 +0200141 //Transform the packetIn data
142 ImmutableByteSequence data = copyFrom(packetIn.getPayload().asReadOnlyByteBuffer());
143
144 //Build the PiPacketOperation with all the metadatas.
145 return PiPacketOperation.builder()
146 .withType(PiPacketOperation.Type.PACKET_IN)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200147 .withMetadatas(packetMetadatas)
Andrea Campanella288b2732017-07-28 14:16:16 +0200148 .withData(data)
149 .build();
150 }
151
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200152 private static List<PiPacketMetadata> decodePacketMetadataIn(List<PacketMetadata> packetMetadatas,
153 P4InfoBrowser browser, int controllerPacketMetadataId) {
Andrea Campanella288b2732017-07-28 14:16:16 +0200154 return packetMetadatas.stream().map(packetMetadata -> {
155 try {
156
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200157 int packetMetadataId = packetMetadata.getMetadataId();
158 String packetMetadataName = browser.packetMetadatas(controllerPacketMetadataId)
159 .getById(packetMetadataId).getName();
160
161 PiPacketMetadataId metadataId = PiPacketMetadataId.of(packetMetadataName);
Andrea Campanella288b2732017-07-28 14:16:16 +0200162
163 //Build each metadata.
164 return PiPacketMetadata.builder()
165 .withId(metadataId)
166 .withValue(ImmutableByteSequence.copyFrom(packetMetadata.getValue().asReadOnlyByteBuffer()))
167 .build();
168 } catch (NotFoundException e) {
169 log.error("Cant find metadata with id {} in p4Info file.", packetMetadata.getMetadataId());
170 return null;
171 }
172 }).filter(Objects::nonNull).collect(Collectors.toList());
173 }
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200174
175}