[ONOS-6750]Implement BMv2 PacketProgrammable
Change-Id: Iad3de3eeda764b4942c6db68d25191d2f4946809
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java
index a37a13f..50a0f9e 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java
@@ -35,7 +35,7 @@
@Beta
public final class PiPacketOperation {
- enum Type {
+ public enum Type {
/**
* Represents a packet out.
*/
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java
index 7bf2258..c4dc2b4 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java
@@ -16,32 +16,72 @@
package org.onosproject.drivers.bmv2;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketProgrammable;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipelineInterpreter;
+import org.onosproject.net.pi.runtime.PiPacketOperation;
+import org.onosproject.net.pi.runtime.PiPipeconfService;
+import org.onosproject.p4runtime.api.P4RuntimeClient;
+import org.onosproject.p4runtime.api.P4RuntimeController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.onosproject.net.pi.runtime.PiPacketOperation.Type.PACKET_OUT;
/**
* Packet Programmable behaviour for BMv2 devices.
*/
public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable {
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Override
public void emit(OutboundPacket packet) {
- // TODO: implement using P4runtime client.
- // DriverHandler handler = handler();
- // GrpcController controller = handler.get(GrpcController.class);
- // DeviceId deviceId = handler.data().deviceId();
- // GrpcChannelId channelId = GrpcChannelId.of(deviceId, "bmv2");
- // GrpcServiceId serviceId = GrpcServiceId.of(channelId, "p4runtime");
- // GrpcStreamObserverId observerId = GrpcStreamObserverId.of(serviceId,
- // this.getClass().getSimpleName());
- // Optional<GrpcObserverHandler> manager = controller.getObserverManager(observerId);
- // if (!manager.isPresent()) {
- // //this is the first time the behaviour is called
- // controller.addObserver(observerId, new Bmv2PacketInObserverHandler());
- // }
- // //other already registered the observer for us.
- // Optional<StreamObserver> observer = manager.get().requestStreamObserver();
- // observer.ifPresent(objectStreamObserver -> objectStreamObserver.onNext(packet));
+
+ DeviceId deviceId = handler().data().deviceId();
+ P4RuntimeController controller = handler().get(P4RuntimeController.class);
+ if (!controller.hasClient(deviceId)) {
+ log.warn("Unable to find client for {}, aborting the sending packet", deviceId);
+ return;
+ }
+
+ P4RuntimeClient client = controller.getClient(deviceId);
+ PiPipeconfService piPipeconfService = handler().get(PiPipeconfService.class);
+
+ final PiPipeconf pipeconf;
+ if (piPipeconfService.ofDevice(deviceId).isPresent() &&
+ piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).isPresent()) {
+ pipeconf = piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).get();
+ } else {
+ log.warn("Unable to get the pipeconf of the {}", deviceId);
+ return;
+ }
+
+ DeviceService deviceService = handler().get(DeviceService.class);
+ Device device = deviceService.getDevice(deviceId);
+ final PiPipelineInterpreter interpreter = device.is(PiPipelineInterpreter.class)
+ ? device.as(PiPipelineInterpreter.class) : null;
+ if (interpreter == null) {
+ log.warn("Device {} unable to instantiate interpreter of pipeconf {}", deviceId, pipeconf.id());
+ return;
+ }
+
+ try {
+ PiPacketOperation piPacketOperation = PiPacketOperation
+ .builder()
+ .withType(PACKET_OUT)
+ .withData(ImmutableByteSequence.copyFrom(packet.data()))
+ .withMetadatas(interpreter.mapOutboundPacket(packet, pipeconf))
+ .build();
+ client.packetOut(piPacketOperation, pipeconf);
+ } catch (PiPipelineInterpreter.PiInterpreterException e) {
+ log.error("Interpreter of pipeconf {} was unable to translate outbound packet: {}",
+ pipeconf.id(), e.getMessage());
+ }
}
}