blob: 03cdb1e7b01534e223e826eeacfe6ff54ef3e113 [file] [log] [blame]
Andrea Campanellafc1d34c2017-07-18 17:01:41 +02001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Andrea Campanellafc1d34c2017-07-18 17:01:41 +02003 *
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;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020036import static p4.P4RuntimeOuterClass.*;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020037
38/**
39 * Encoder of packet metadata, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
40 */
41final class PacketIOCodec {
42
43 private static final Logger log = getLogger(PacketIOCodec.class);
44
45 private static final String PACKET_OUT = "packet_out";
46
Andrea Campanella288b2732017-07-28 14:16:16 +020047 private static final String PACKET_IN = "packet_in";
48
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020049 // TODO: implement cache of encoded entities.
50
51 private PacketIOCodec() {
52 // hide.
53 }
54
55 /**
56 * Returns a P4Runtime packet out protobuf message, encoded from the given PiPacketOperation
57 * for the given pipeconf. If a PI packet metadata inside the PacketOperation cannot be encoded,
58 * it is skipped, hence the returned PacketOut collection of metadatas might have different
59 * size than the input one.
60 * <p>
61 * Please check the log for an explanation of any error that might have occurred.
62 *
Andrea Campanella288b2732017-07-28 14:16:16 +020063 * @param packet PI packet operation
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020064 * @param pipeconf the pipeconf for the program on the switch
65 * @return a P4Runtime packet out protobuf message
66 * @throws NotFoundException if the browser can't find the packet_out in the given p4Info
67 */
Andrea Campanella288b2732017-07-28 14:16:16 +020068 static PacketOut encodePacketOut(PiPacketOperation packet, PiPipeconf pipeconf)
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020069 throws NotFoundException {
70
71 //Get the P4browser
72 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
73
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020074 //Get the packet out controller packet metadata
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020075 P4InfoOuterClass.ControllerPacketMetadata controllerPacketMetadata =
Carmelo Casconecb0a49c2017-10-03 14:32:23 +020076 browser.controllerPacketMetadatas().getByName(PACKET_OUT);
Andrea Campanella288b2732017-07-28 14:16:16 +020077 PacketOut.Builder packetOutBuilder = PacketOut.newBuilder();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020078
79 //outer controller packet metadata id
80 int controllerPacketMetadataId = controllerPacketMetadata.getPreamble().getId();
81
82 //Add all its metadata to the packet out
83 packetOutBuilder.addAllMetadata(encodePacketMetadata(packet, browser, controllerPacketMetadataId));
84
85 //Set the packet out payload
86 packetOutBuilder.setPayload(ByteString.copyFrom(packet.data().asReadOnlyBuffer()));
87 return packetOutBuilder.build();
88
89 }
90
91 private static List<PacketMetadata> encodePacketMetadata(PiPacketOperation packet,
92 P4InfoBrowser browser, int controllerPacketMetadataId) {
93 return packet.metadatas().stream().map(metadata -> {
94 try {
95 //get each metadata id
96 int metadataId = browser.packetMetadatas(controllerPacketMetadataId)
Carmelo Casconecb0a49c2017-10-03 14:32:23 +020097 .getByName(metadata.id().name()).getId();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020098
99 //Add the metadata id and it's data the packet out
100 return PacketMetadata.newBuilder()
101 .setMetadataId(metadataId)
102 .setValue(ByteString.copyFrom(metadata.value().asReadOnlyBuffer()))
103 .build();
104 } catch (NotFoundException e) {
105 log.error("Cant find metadata with name {} in p4Info file.", metadata.id().name());
106 return null;
107 }
108 }).filter(Objects::nonNull).collect(Collectors.toList());
109 }
110
Andrea Campanella288b2732017-07-28 14:16:16 +0200111 /**
112 * Returns a PiPacketOperation, decoded from the given P4Runtime PacketIn protobuf message
113 * for the given pipeconf. If a PI packet metadata inside the protobuf message cannot be decoded,
114 * it is skipped, hence the returned PiPacketOperation collection of metadatas might have different
115 * size than the input one.
116 * <p>
117 * Please check the log for an explanation of any error that might have occurred.
118 *
119 * @param packetIn the P4Runtime PAcketIn message
120 * @param pipeconf the pipeconf for the program on the switch
121 * @return a PiPacketOperation
122 */
123 static PiPacketOperation decodePacketIn(PacketIn packetIn, PiPipeconf pipeconf) {
124
125 //Get the P4browser
126 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
127
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200128 List<PiPacketMetadata> packetMetadatas;
129 try {
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200130 int controllerPacketMetadataId = browser.controllerPacketMetadatas().getByName(PACKET_IN)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200131 .getPreamble().getId();
132 packetMetadatas = decodePacketMetadataIn(packetIn.getMetadataList(), browser,
133 controllerPacketMetadataId);
134 } catch (NotFoundException e) {
135 log.error("Unable to decode packet metadatas: {}", e.getMessage());
136 packetMetadatas = Collections.emptyList();
137 }
138
Andrea Campanella288b2732017-07-28 14:16:16 +0200139 //Transform the packetIn data
140 ImmutableByteSequence data = copyFrom(packetIn.getPayload().asReadOnlyByteBuffer());
141
142 //Build the PiPacketOperation with all the metadatas.
143 return PiPacketOperation.builder()
144 .withType(PiPacketOperation.Type.PACKET_IN)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200145 .withMetadatas(packetMetadatas)
Andrea Campanella288b2732017-07-28 14:16:16 +0200146 .withData(data)
147 .build();
148 }
149
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200150 private static List<PiPacketMetadata> decodePacketMetadataIn(List<PacketMetadata> packetMetadatas,
151 P4InfoBrowser browser, int controllerPacketMetadataId) {
Andrea Campanella288b2732017-07-28 14:16:16 +0200152 return packetMetadatas.stream().map(packetMetadata -> {
153 try {
154
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200155 int packetMetadataId = packetMetadata.getMetadataId();
156 String packetMetadataName = browser.packetMetadatas(controllerPacketMetadataId)
157 .getById(packetMetadataId).getName();
158
159 PiPacketMetadataId metadataId = PiPacketMetadataId.of(packetMetadataName);
Andrea Campanella288b2732017-07-28 14:16:16 +0200160
161 //Build each metadata.
162 return PiPacketMetadata.builder()
163 .withId(metadataId)
164 .withValue(ImmutableByteSequence.copyFrom(packetMetadata.getValue().asReadOnlyByteBuffer()))
165 .build();
166 } catch (NotFoundException e) {
167 log.error("Cant find metadata with id {} in p4Info file.", packetMetadata.getMetadataId());
168 return null;
169 }
170 }).filter(Objects::nonNull).collect(Collectors.toList());
171 }
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200172
173}