blob: 726e09258ff6942e7df80c632028e2206ad386fc [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;
Carmelo Cascone87892e22017-11-13 16:01:29 -080021import org.onosproject.net.DeviceId;
22import org.onosproject.net.pi.model.PiControlMetadataId;
23import org.onosproject.net.pi.model.PiPacketOperationType;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020024import org.onosproject.net.pi.model.PiPipeconf;
Carmelo Cascone87892e22017-11-13 16:01:29 -080025import org.onosproject.net.pi.runtime.PiControlMetadata;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020026import org.onosproject.net.pi.runtime.PiPacketOperation;
27import org.slf4j.Logger;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020028import p4.config.v1.P4InfoOuterClass;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020029
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020030import java.util.Collections;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020031import java.util.List;
32import java.util.Objects;
33import java.util.stream.Collectors;
34
Andrea Campanella288b2732017-07-28 14:16:16 +020035import static org.onlab.util.ImmutableByteSequence.copyFrom;
36import static org.onosproject.p4runtime.ctl.P4InfoBrowser.NotFoundException;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020037import static org.slf4j.LoggerFactory.getLogger;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020038import static p4.v1.P4RuntimeOuterClass.PacketIn;
39import static p4.v1.P4RuntimeOuterClass.PacketMetadata;
40import static p4.v1.P4RuntimeOuterClass.PacketOut;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020041
42/**
43 * Encoder of packet metadata, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
44 */
45final class PacketIOCodec {
46
47 private static final Logger log = getLogger(PacketIOCodec.class);
48
49 private static final String PACKET_OUT = "packet_out";
50
Andrea Campanella288b2732017-07-28 14:16:16 +020051 private static final String PACKET_IN = "packet_in";
52
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020053 // TODO: implement cache of encoded entities.
54
55 private PacketIOCodec() {
56 // hide.
57 }
58
59 /**
Carmelo Cascone87892e22017-11-13 16:01:29 -080060 * Returns a P4Runtime packet out protobuf message, encoded from the given PiPacketOperation for the given pipeconf.
61 * If a PI packet metadata inside the PacketOperation cannot be encoded, it is skipped, hence the returned PacketOut
62 * collection of metadatas might have different size than the input one.
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020063 * <p>
64 * Please check the log for an explanation of any error that might have occurred.
65 *
Andrea Campanella288b2732017-07-28 14:16:16 +020066 * @param packet PI packet operation
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020067 * @param pipeconf the pipeconf for the program on the switch
68 * @return a P4Runtime packet out protobuf message
69 * @throws NotFoundException if the browser can't find the packet_out in the given p4Info
70 */
Andrea Campanella288b2732017-07-28 14:16:16 +020071 static PacketOut encodePacketOut(PiPacketOperation packet, PiPipeconf pipeconf)
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020072 throws NotFoundException {
73
74 //Get the P4browser
75 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
76
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020077 //Get the packet out controller packet metadata
Carmelo Cascone87892e22017-11-13 16:01:29 -080078 P4InfoOuterClass.ControllerPacketMetadata controllerControlMetadata =
Carmelo Casconecb0a49c2017-10-03 14:32:23 +020079 browser.controllerPacketMetadatas().getByName(PACKET_OUT);
Andrea Campanella288b2732017-07-28 14:16:16 +020080 PacketOut.Builder packetOutBuilder = PacketOut.newBuilder();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020081
82 //outer controller packet metadata id
Carmelo Cascone87892e22017-11-13 16:01:29 -080083 int controllerControlMetadataId = controllerControlMetadata.getPreamble().getId();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020084
85 //Add all its metadata to the packet out
Carmelo Cascone87892e22017-11-13 16:01:29 -080086 packetOutBuilder.addAllMetadata(encodeControlMetadata(packet, browser, controllerControlMetadataId));
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020087
88 //Set the packet out payload
89 packetOutBuilder.setPayload(ByteString.copyFrom(packet.data().asReadOnlyBuffer()));
90 return packetOutBuilder.build();
91
92 }
93
Carmelo Cascone87892e22017-11-13 16:01:29 -080094 private static List<PacketMetadata> encodeControlMetadata(PiPacketOperation packet,
95 P4InfoBrowser browser, int controllerControlMetadataId) {
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020096 return packet.metadatas().stream().map(metadata -> {
97 try {
98 //get each metadata id
Carmelo Cascone87892e22017-11-13 16:01:29 -080099 int metadataId = browser.packetMetadatas(controllerControlMetadataId)
100 .getByName(metadata.id().toString()).getId();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200101
102 //Add the metadata id and it's data the packet out
103 return PacketMetadata.newBuilder()
104 .setMetadataId(metadataId)
105 .setValue(ByteString.copyFrom(metadata.value().asReadOnlyBuffer()))
106 .build();
107 } catch (NotFoundException e) {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800108 log.error("Cant find metadata with name {} in p4Info file.", metadata.id());
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200109 return null;
110 }
111 }).filter(Objects::nonNull).collect(Collectors.toList());
112 }
113
Andrea Campanella288b2732017-07-28 14:16:16 +0200114 /**
Carmelo Cascone87892e22017-11-13 16:01:29 -0800115 * Returns a PiPacketOperation, decoded from the given P4Runtime PacketIn protobuf message for the given pipeconf
116 * and device ID. If a PI packet metadata inside the protobuf message cannot be decoded, it is skipped, hence the
117 * returned PiPacketOperation collection of metadatas might have different size than the input one.
Andrea Campanella288b2732017-07-28 14:16:16 +0200118 * <p>
119 * Please check the log for an explanation of any error that might have occurred.
120 *
Carmelo Cascone87892e22017-11-13 16:01:29 -0800121 * @param packetIn the P4Runtime PacketIn message
Andrea Campanella288b2732017-07-28 14:16:16 +0200122 * @param pipeconf the pipeconf for the program on the switch
Carmelo Cascone87892e22017-11-13 16:01:29 -0800123 * @param deviceId the deviceId that originated the PacketIn message
Andrea Campanella288b2732017-07-28 14:16:16 +0200124 * @return a PiPacketOperation
125 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800126 static PiPacketOperation decodePacketIn(PacketIn packetIn, PiPipeconf pipeconf, DeviceId deviceId) {
Andrea Campanella288b2732017-07-28 14:16:16 +0200127
128 //Get the P4browser
129 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
130
Carmelo Cascone87892e22017-11-13 16:01:29 -0800131 List<PiControlMetadata> packetMetadatas;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200132 try {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800133 int controllerControlMetadataId = browser.controllerPacketMetadatas().getByName(PACKET_IN)
134 .getPreamble().getId();
135 packetMetadatas = decodeControlMetadataIn(packetIn.getMetadataList(), browser,
136 controllerControlMetadataId);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200137 } catch (NotFoundException e) {
138 log.error("Unable to decode packet metadatas: {}", e.getMessage());
139 packetMetadatas = Collections.emptyList();
140 }
141
Andrea Campanella288b2732017-07-28 14:16:16 +0200142 //Transform the packetIn data
143 ImmutableByteSequence data = copyFrom(packetIn.getPayload().asReadOnlyByteBuffer());
144
145 //Build the PiPacketOperation with all the metadatas.
146 return PiPacketOperation.builder()
Carmelo Cascone87892e22017-11-13 16:01:29 -0800147 .forDevice(deviceId)
148 .withType(PiPacketOperationType.PACKET_IN)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200149 .withMetadatas(packetMetadatas)
Andrea Campanella288b2732017-07-28 14:16:16 +0200150 .withData(data)
151 .build();
152 }
153
Carmelo Cascone87892e22017-11-13 16:01:29 -0800154 private static List<PiControlMetadata> decodeControlMetadataIn(List<PacketMetadata> packetMetadatas,
155 P4InfoBrowser browser,
156 int controllerControlMetadataId) {
Andrea Campanella288b2732017-07-28 14:16:16 +0200157 return packetMetadatas.stream().map(packetMetadata -> {
158 try {
159
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200160 int packetMetadataId = packetMetadata.getMetadataId();
Carmelo Cascone87892e22017-11-13 16:01:29 -0800161 String packetMetadataName = browser.packetMetadatas(controllerControlMetadataId)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200162 .getById(packetMetadataId).getName();
163
Carmelo Cascone87892e22017-11-13 16:01:29 -0800164 PiControlMetadataId metadataId = PiControlMetadataId.of(packetMetadataName);
Andrea Campanella288b2732017-07-28 14:16:16 +0200165
166 //Build each metadata.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800167 return PiControlMetadata.builder()
Andrea Campanella288b2732017-07-28 14:16:16 +0200168 .withId(metadataId)
169 .withValue(ImmutableByteSequence.copyFrom(packetMetadata.getValue().asReadOnlyByteBuffer()))
170 .build();
171 } catch (NotFoundException e) {
172 log.error("Cant find metadata with id {} in p4Info file.", packetMetadata.getMetadataId());
173 return null;
174 }
175 }).filter(Objects::nonNull).collect(Collectors.toList());
176 }
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200177
178}