Implement support for packetIn through p4Runtime
Change-Id: I92cc1a2bd7edde8916aad61c20d7411f93368612
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DefaultPacketInEvent.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DefaultPacketInEvent.java
index dd2f021..104999b 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DefaultPacketInEvent.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DefaultPacketInEvent.java
@@ -17,16 +17,14 @@
package org.onosproject.p4runtime.ctl;
import com.google.common.base.Objects;
-import org.onlab.util.ImmutableByteSequence;
import org.onosproject.event.AbstractEvent;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.p4runtime.api.P4RuntimeEvent;
import org.onosproject.p4runtime.api.P4RuntimeEventListener;
import org.onosproject.p4runtime.api.P4RuntimeEventSubject;
import org.onosproject.p4runtime.api.P4RuntimePacketIn;
-import java.util.List;
-
import static com.google.common.base.Preconditions.checkNotNull;
/**
@@ -36,9 +34,8 @@
extends AbstractEvent<P4RuntimeEventListener.Type, P4RuntimeEventSubject>
implements P4RuntimeEvent {
- DefaultPacketInEvent(DeviceId deviceId, ImmutableByteSequence data,
- List<ImmutableByteSequence> metadata) {
- super(P4RuntimeEventListener.Type.PACKET_IN, new DefaultPacketIn(deviceId, data, metadata));
+ DefaultPacketInEvent(DeviceId deviceId, PiPacketOperation operation) {
+ super(P4RuntimeEventListener.Type.PACKET_IN, new DefaultPacketIn(deviceId, operation));
}
/**
@@ -47,13 +44,11 @@
private static final class DefaultPacketIn implements P4RuntimePacketIn {
private final DeviceId deviceId;
- private final ImmutableByteSequence data;
- private final List<ImmutableByteSequence> metadata;
+ private final PiPacketOperation operation;
- private DefaultPacketIn(DeviceId deviceId, ImmutableByteSequence data, List<ImmutableByteSequence> metadata) {
+ private DefaultPacketIn(DeviceId deviceId, PiPacketOperation operation) {
this.deviceId = checkNotNull(deviceId);
- this.data = checkNotNull(data);
- this.metadata = checkNotNull(metadata);
+ this.operation = checkNotNull(operation);
}
@Override
@@ -62,13 +57,8 @@
}
@Override
- public ImmutableByteSequence data() {
- return data;
- }
-
- @Override
- public List<ImmutableByteSequence> metadata() {
- return metadata;
+ public PiPacketOperation packetOperation() {
+ return operation;
}
@Override
@@ -81,13 +71,12 @@
}
DefaultPacketIn that = (DefaultPacketIn) o;
return Objects.equal(deviceId, that.deviceId) &&
- Objects.equal(data, that.data) &&
- Objects.equal(metadata, that.metadata);
+ Objects.equal(operation, that.operation);
}
@Override
public int hashCode() {
- return Objects.hashCode(deviceId, data, metadata);
+ return Objects.hashCode(deviceId, operation);
}
}
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index 78a0222..a7d7726 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -16,7 +16,6 @@
package org.onosproject.p4runtime.ctl;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.protobuf.ByteString;
import io.grpc.Context;
@@ -24,10 +23,11 @@
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
-import org.onlab.util.ImmutableByteSequence;
+import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.net.DeviceId;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.runtime.PiPacketOperation;
+import org.onosproject.net.pi.runtime.PiPipeconfService;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
import org.onosproject.p4runtime.api.P4RuntimeClient;
@@ -68,7 +68,6 @@
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
-import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType;
import static org.slf4j.LoggerFactory.getLogger;
@@ -407,13 +406,26 @@
case PACKET:
// Packet-in
PacketIn packetIn = message.getPacket();
- ImmutableByteSequence data = copyFrom(packetIn.getPayload().asReadOnlyByteBuffer());
- ImmutableList.Builder<ImmutableByteSequence> metadataBuilder = ImmutableList.builder();
- packetIn.getMetadataList().stream()
- .map(m -> m.getValue().asReadOnlyByteBuffer())
- .map(ImmutableByteSequence::copyFrom)
- .forEach(metadataBuilder::add);
- P4RuntimeEvent event = new DefaultPacketInEvent(deviceId, data, metadataBuilder.build());
+
+ // Retrieve the pipeconf for the specific device
+ PiPipeconfService pipeconfService = DefaultServiceDirectory.getService(PiPipeconfService.class);
+ if (pipeconfService == null) {
+ throw new IllegalStateException("PiPipeconfService is null. Can't handle packet in.");
+ }
+
+ final PiPipeconf pipeconf;
+ if (pipeconfService.ofDevice(deviceId).isPresent() &&
+ pipeconfService.getPipeconf(pipeconfService.ofDevice(deviceId).get()).isPresent()) {
+ pipeconf = pipeconfService.getPipeconf(pipeconfService.ofDevice(deviceId).get()).get();
+ } else {
+ log.warn("Unable to get the pipeconf of the {}. Can't handle packet in", deviceId);
+ return;
+ }
+ //decode the packet and generate a corresponding p4Runtime event containing the PiPacketOperation
+ P4RuntimeEvent event =
+ new DefaultPacketInEvent(deviceId, PacketIOCodec.decodePacketIn(packetIn, pipeconf));
+
+ //posting the event upwards
controller.postEvent(event);
return;
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java
index 0461154..461cde0 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java
@@ -17,19 +17,24 @@
package org.onosproject.p4runtime.ctl;
import com.google.protobuf.ByteString;
+import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiPacketMetadata;
+import org.onosproject.net.pi.runtime.PiPacketMetadataId;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.slf4j.Logger;
-import p4.P4RuntimeOuterClass;
import p4.config.P4InfoOuterClass;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
-import static org.onosproject.p4runtime.ctl.P4InfoBrowser.*;
+import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onosproject.p4runtime.ctl.P4InfoBrowser.NotFoundException;
import static org.slf4j.LoggerFactory.getLogger;
+import static p4.P4RuntimeOuterClass.PacketIn;
import static p4.P4RuntimeOuterClass.PacketMetadata;
+import static p4.P4RuntimeOuterClass.PacketOut;
/**
* Encoder of packet metadata, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
@@ -40,6 +45,8 @@
private static final String PACKET_OUT = "packet_out";
+ private static final String PACKET_IN = "packet_in";
+
// TODO: implement cache of encoded entities.
private PacketIOCodec() {
@@ -54,12 +61,12 @@
* <p>
* Please check the log for an explanation of any error that might have occurred.
*
- * @param packet PI pakcet operation
+ * @param packet PI packet operation
* @param pipeconf the pipeconf for the program on the switch
* @return a P4Runtime packet out protobuf message
* @throws NotFoundException if the browser can't find the packet_out in the given p4Info
*/
- static P4RuntimeOuterClass.PacketOut encodePacketOut(PiPacketOperation packet, PiPipeconf pipeconf)
+ static PacketOut encodePacketOut(PiPacketOperation packet, PiPipeconf pipeconf)
throws NotFoundException {
//Get the P4browser
@@ -68,7 +75,7 @@
//Get the packet out packet metadata
P4InfoOuterClass.ControllerPacketMetadata controllerPacketMetadata =
browser.controllerPacketMetadatas().getByName(PACKET_OUT);
- P4RuntimeOuterClass.PacketOut.Builder packetOutBuilder = P4RuntimeOuterClass.PacketOut.newBuilder();
+ PacketOut.Builder packetOutBuilder = PacketOut.newBuilder();
//outer controller packet metadata id
int controllerPacketMetadataId = controllerPacketMetadata.getPreamble().getId();
@@ -102,6 +109,55 @@
}).filter(Objects::nonNull).collect(Collectors.toList());
}
- //TODO: add decode packets
+ /**
+ * Returns a PiPacketOperation, decoded from the given P4Runtime PacketIn protobuf message
+ * for the given pipeconf. If a PI packet metadata inside the protobuf message cannot be decoded,
+ * it is skipped, hence the returned PiPacketOperation collection of metadatas might have different
+ * size than the input one.
+ * <p>
+ * Please check the log for an explanation of any error that might have occurred.
+ *
+ * @param packetIn the P4Runtime PAcketIn message
+ * @param pipeconf the pipeconf for the program on the switch
+ * @return a PiPacketOperation
+ */
+ static PiPacketOperation decodePacketIn(PacketIn packetIn, PiPipeconf pipeconf) {
+
+ //Get the P4browser
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ //Transform the packetIn data
+ ImmutableByteSequence data = copyFrom(packetIn.getPayload().asReadOnlyByteBuffer());
+
+ //Build the PiPacketOperation with all the metadatas.
+ return PiPacketOperation.builder()
+ .withType(PiPacketOperation.Type.PACKET_IN)
+ .withMetadatas(decodePacketMetadata(packetIn.getMetadataList(), browser))
+ .withData(data)
+ .build();
+ }
+
+ private static List<PiPacketMetadata> decodePacketMetadata(List<PacketMetadata> packetMetadatas,
+ P4InfoBrowser browser) {
+ return packetMetadatas.stream().map(packetMetadata -> {
+ try {
+
+ int controllerPacketMetadataId = packetMetadata.getMetadataId();
+ //convert id to name through p4Info
+ P4InfoOuterClass.ControllerPacketMetadata metadata =
+ browser.controllerPacketMetadatas().getById(controllerPacketMetadataId);
+ PiPacketMetadataId metadataId = PiPacketMetadataId.of(metadata.getPreamble().getName());
+
+ //Build each metadata.
+ return PiPacketMetadata.builder()
+ .withId(metadataId)
+ .withValue(ImmutableByteSequence.copyFrom(packetMetadata.getValue().asReadOnlyByteBuffer()))
+ .build();
+ } catch (NotFoundException e) {
+ log.error("Cant find metadata with id {} in p4Info file.", packetMetadata.getMetadataId());
+ return null;
+ }
+ }).filter(Objects::nonNull).collect(Collectors.toList());
+ }
}