blob: 461cde020a585b74809e2edb5b62d7d596749713 [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
28import java.util.List;
29import java.util.Objects;
30import java.util.stream.Collectors;
31
Andrea Campanella288b2732017-07-28 14:16:16 +020032import static org.onlab.util.ImmutableByteSequence.copyFrom;
33import static org.onosproject.p4runtime.ctl.P4InfoBrowser.NotFoundException;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020034import static org.slf4j.LoggerFactory.getLogger;
Andrea Campanella288b2732017-07-28 14:16:16 +020035import static p4.P4RuntimeOuterClass.PacketIn;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020036import static p4.P4RuntimeOuterClass.PacketMetadata;
Andrea Campanella288b2732017-07-28 14:16:16 +020037import static p4.P4RuntimeOuterClass.PacketOut;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020038
39/**
40 * Encoder of packet metadata, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
41 */
42final class PacketIOCodec {
43
44 private static final Logger log = getLogger(PacketIOCodec.class);
45
46 private static final String PACKET_OUT = "packet_out";
47
Andrea Campanella288b2732017-07-28 14:16:16 +020048 private static final String PACKET_IN = "packet_in";
49
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020050 // TODO: implement cache of encoded entities.
51
52 private PacketIOCodec() {
53 // hide.
54 }
55
56 /**
57 * Returns a P4Runtime packet out protobuf message, encoded from the given PiPacketOperation
58 * for the given pipeconf. If a PI packet metadata inside the PacketOperation cannot be encoded,
59 * it is skipped, hence the returned PacketOut collection of metadatas might have different
60 * size than the input one.
61 * <p>
62 * Please check the log for an explanation of any error that might have occurred.
63 *
Andrea Campanella288b2732017-07-28 14:16:16 +020064 * @param packet PI packet operation
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020065 * @param pipeconf the pipeconf for the program on the switch
66 * @return a P4Runtime packet out protobuf message
67 * @throws NotFoundException if the browser can't find the packet_out in the given p4Info
68 */
Andrea Campanella288b2732017-07-28 14:16:16 +020069 static PacketOut encodePacketOut(PiPacketOperation packet, PiPipeconf pipeconf)
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020070 throws NotFoundException {
71
72 //Get the P4browser
73 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
74
75 //Get the packet out packet metadata
76 P4InfoOuterClass.ControllerPacketMetadata controllerPacketMetadata =
77 browser.controllerPacketMetadatas().getByName(PACKET_OUT);
Andrea Campanella288b2732017-07-28 14:16:16 +020078 PacketOut.Builder packetOutBuilder = PacketOut.newBuilder();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020079
80 //outer controller packet metadata id
81 int controllerPacketMetadataId = controllerPacketMetadata.getPreamble().getId();
82
83 //Add all its metadata to the packet out
84 packetOutBuilder.addAllMetadata(encodePacketMetadata(packet, browser, controllerPacketMetadataId));
85
86 //Set the packet out payload
87 packetOutBuilder.setPayload(ByteString.copyFrom(packet.data().asReadOnlyBuffer()));
88 return packetOutBuilder.build();
89
90 }
91
92 private static List<PacketMetadata> encodePacketMetadata(PiPacketOperation packet,
93 P4InfoBrowser browser, int controllerPacketMetadataId) {
94 return packet.metadatas().stream().map(metadata -> {
95 try {
96 //get each metadata id
97 int metadataId = browser.packetMetadatas(controllerPacketMetadataId)
98 .getByName(metadata.id().name()).getId();
99
100 //Add the metadata id and it's data the packet out
101 return PacketMetadata.newBuilder()
102 .setMetadataId(metadataId)
103 .setValue(ByteString.copyFrom(metadata.value().asReadOnlyBuffer()))
104 .build();
105 } catch (NotFoundException e) {
106 log.error("Cant find metadata with name {} in p4Info file.", metadata.id().name());
107 return null;
108 }
109 }).filter(Objects::nonNull).collect(Collectors.toList());
110 }
111
Andrea Campanella288b2732017-07-28 14:16:16 +0200112 /**
113 * Returns a PiPacketOperation, decoded from the given P4Runtime PacketIn protobuf message
114 * for the given pipeconf. If a PI packet metadata inside the protobuf message cannot be decoded,
115 * it is skipped, hence the returned PiPacketOperation collection of metadatas might have different
116 * size than the input one.
117 * <p>
118 * Please check the log for an explanation of any error that might have occurred.
119 *
120 * @param packetIn the P4Runtime PAcketIn message
121 * @param pipeconf the pipeconf for the program on the switch
122 * @return a PiPacketOperation
123 */
124 static PiPacketOperation decodePacketIn(PacketIn packetIn, PiPipeconf pipeconf) {
125
126 //Get the P4browser
127 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
128
129 //Transform the packetIn data
130 ImmutableByteSequence data = copyFrom(packetIn.getPayload().asReadOnlyByteBuffer());
131
132 //Build the PiPacketOperation with all the metadatas.
133 return PiPacketOperation.builder()
134 .withType(PiPacketOperation.Type.PACKET_IN)
135 .withMetadatas(decodePacketMetadata(packetIn.getMetadataList(), browser))
136 .withData(data)
137 .build();
138 }
139
140 private static List<PiPacketMetadata> decodePacketMetadata(List<PacketMetadata> packetMetadatas,
141 P4InfoBrowser browser) {
142 return packetMetadatas.stream().map(packetMetadata -> {
143 try {
144
145 int controllerPacketMetadataId = packetMetadata.getMetadataId();
146 //convert id to name through p4Info
147 P4InfoOuterClass.ControllerPacketMetadata metadata =
148 browser.controllerPacketMetadatas().getById(controllerPacketMetadataId);
149 PiPacketMetadataId metadataId = PiPacketMetadataId.of(metadata.getPreamble().getName());
150
151 //Build each metadata.
152 return PiPacketMetadata.builder()
153 .withId(metadataId)
154 .withValue(ImmutableByteSequence.copyFrom(packetMetadata.getValue().asReadOnlyByteBuffer()))
155 .build();
156 } catch (NotFoundException e) {
157 log.error("Cant find metadata with id {} in p4Info file.", packetMetadata.getMetadataId());
158 return null;
159 }
160 }).filter(Objects::nonNull).collect(Collectors.toList());
161 }
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200162
163}