ONOS-6561 BMv2 handshaker via P4Runtime

+ support fort device-specific default pipeconf
+ improvements to P4runtime and gRPC protocol stuff

Change-Id: I8986fce3959df564454ea3d31859860f61eabcae
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineProgrammable.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineProgrammable.java
new file mode 100644
index 0000000..28d4625
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineProgrammable.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.pi.model;
+
+import org.onosproject.net.driver.HandlerBehaviour;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Behavior to program the pipeline of a device.
+ */
+public interface PiPipelineProgrammable extends HandlerBehaviour {
+    /**
+     * Deploys the given pipeconf to the device.
+     *
+     * @param pipeconf pipeconf
+     * @return true if the operation was successful, false otherwise
+     */
+    // TODO: return an explanation of why things went wrong, and the status of the device.
+    CompletableFuture<Boolean> deployPipeconf(PiPipeconf pipeconf);
+
+    /**
+     * Returns the default pipeconf for ths device, to be used when any other pipeconf is not available.
+     *
+     * @return optional pipeconf
+     */
+    Optional<PiPipeconf> getDefaultPipeconf();
+}
diff --git a/drivers/bmv2/BUCK b/drivers/bmv2/BUCK
index ad83ec1..b406b08 100644
--- a/drivers/bmv2/BUCK
+++ b/drivers/bmv2/BUCK
@@ -1,8 +1,32 @@
+GRPC_DEPS = [
+    '//incubator/grpc-dependencies:grpc-core-repkg-1.3.0',
+    '//lib:grpc-protobuf-1.3.0',
+    '//lib:grpc-protobuf-lite-1.3.0',
+    '//lib:grpc-stub-1.3.0',
+    '//lib:grpc-netty-1.3.0',
+    '//lib:grpc-auth-1.3.0',
+    '//lib:google-instrumentation-0.3.0',
+    '//lib:protobuf-java-3.0.2',
+    # Lazily adding all netty-related packages.
+    # Some of them might not be necessary.
+    '//lib:netty',
+    '//lib:netty-buffer',
+    '//lib:netty-codec',
+    '//lib:netty-codec-http',
+    '//lib:netty-codec-http2',
+    '//lib:netty-common',
+    '//lib:netty-handler',
+    '//lib:netty-transport',
+    '//lib:netty-transport-native-epoll',
+    '//lib:netty-resolver',
+]
+
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
-    '//protocols/grpc/api:onos-protocols-grpc-api',
-    '//lib:grpc-core-1.3.0',
-    '//lib:grpc-stub-1.3.0'
+    '//protocols/p4runtime/api:onos-protocols-p4runtime-api',
+    '//incubator/bmv2/model:onos-incubator-bmv2-model',
+    '//incubator/grpc-dependencies:grpc-core-repkg-1.3.0',
+    '//lib:grpc-netty-1.3.0',
 ]
 
 TEST_DEPS = [
@@ -12,11 +36,14 @@
 
 BUNDLES = [
     ':onos-drivers-bmv2',
-    '//lib:grpc-core-1.3.0',
-    '//lib:grpc-stub-1.3.0',
+    '//protocols/p4runtime/proto:onos-protocols-p4runtime-proto',
+    '//protocols/p4runtime/api:onos-protocols-p4runtime-api',
+    '//protocols/p4runtime/ctl:onos-protocols-p4runtime-ctl',
     '//protocols/grpc/api:onos-protocols-grpc-api',
     '//protocols/grpc/ctl:onos-protocols-grpc-ctl',
-]
+    '//protocols/grpc/proto:onos-protocols-grpc-proto',
+    '//incubator/bmv2/model:onos-incubator-bmv2-model',
+] + GRPC_DEPS
 
 osgi_jar_with_tests(
     deps = COMPILE_DEPS,
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultInterpreter.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultInterpreter.java
new file mode 100644
index 0000000..59f0c8c
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultInterpreter.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.bmv2;
+
+import com.google.common.collect.ImmutableBiMap;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipelineInterpreter;
+import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionId;
+import org.onosproject.net.pi.runtime.PiActionParam;
+import org.onosproject.net.pi.runtime.PiActionParamId;
+import org.onosproject.net.pi.runtime.PiHeaderFieldId;
+import org.onosproject.net.pi.runtime.PiTableAction;
+import org.onosproject.net.pi.runtime.PiTableId;
+
+import java.util.Optional;
+
+import static org.onosproject.net.PortNumber.CONTROLLER;
+
+/**
+ * Interpreter implementation for the default pipeconf.
+ */
+public class Bmv2DefaultInterpreter extends AbstractHandlerBehaviour implements PiPipelineInterpreter {
+    private static final String TABLE0 = "table0";
+    private static final String SEND_TO_CPU = "send_to_cpu_0";
+    private static final String PORT = "port";
+    private static final String DROP = "_drop_0";
+    private static final String SET_EGRESS_PORT = "set_egress_port_0";
+
+    private static final PiHeaderFieldId IN_PORT_ID = PiHeaderFieldId.of("standard_metadata", "ingress_port");
+    private static final PiHeaderFieldId ETH_DST_ID = PiHeaderFieldId.of("ethernet_t", "dstAddr");
+    private static final PiHeaderFieldId ETH_SRC_ID = PiHeaderFieldId.of("ethernet_t", "srcAddr");
+    private static final PiHeaderFieldId ETH_TYPE_ID = PiHeaderFieldId.of("ethernet_t", "etherType");
+
+    private static final ImmutableBiMap<Criterion.Type, PiHeaderFieldId> CRITERION_MAP = ImmutableBiMap.of(
+            Criterion.Type.IN_PORT, IN_PORT_ID,
+            Criterion.Type.ETH_DST, ETH_DST_ID,
+            Criterion.Type.ETH_SRC, ETH_SRC_ID,
+            Criterion.Type.ETH_TYPE, ETH_TYPE_ID);
+
+    private static final ImmutableBiMap<Integer, PiTableId> TABLE_MAP = ImmutableBiMap.of(
+            0, PiTableId.of(TABLE0));
+
+    @Override
+    public PiTableAction mapTreatment(TrafficTreatment treatment, PiPipeconf pipeconf) throws PiInterpreterException {
+
+        if (treatment.allInstructions().size() == 0) {
+            // No instructions means drop for us.
+            return actionWithName(DROP);
+        } else if (treatment.allInstructions().size() > 1) {
+            // Otherwise, we understand treatments with only 1 instruction.
+            throw new PiPipelineInterpreter.PiInterpreterException("Treatment has multiple instructions");
+        }
+
+        Instruction instruction = treatment.allInstructions().get(0);
+
+        switch (instruction.type()) {
+            case OUTPUT:
+                Instructions.OutputInstruction outInstruction = (Instructions.OutputInstruction) instruction;
+                PortNumber port = outInstruction.port();
+                if (!port.isLogical()) {
+                    PiAction.builder()
+                            .withId(PiActionId.of(SET_EGRESS_PORT))
+                            .withParameter(new PiActionParam(PiActionParamId.of(PORT),
+                                                             ImmutableByteSequence.copyFrom(port.toLong())))
+                            .build();
+                } else if (port.equals(CONTROLLER)) {
+                    return actionWithName(SEND_TO_CPU);
+                } else {
+                    throw new PiInterpreterException("Egress on logical port not supported: " + port);
+                }
+            case NOACTION:
+                return actionWithName(DROP);
+            default:
+                throw new PiInterpreterException("Instruction type not supported: " + instruction.type().name());
+        }
+    }
+
+    /**
+     * Returns an action instance with no runtime parameters.
+     */
+    private PiAction actionWithName(String name) {
+        return PiAction.builder().withId(PiActionId.of(name)).build();
+    }
+
+    @Override
+    public Optional<PiHeaderFieldId> mapCriterionType(Criterion.Type type) {
+        return Optional.ofNullable(CRITERION_MAP.get(type));
+    }
+
+    @Override
+    public Optional<Criterion.Type> mapPiHeaderFieldId(PiHeaderFieldId headerFieldId) {
+        return Optional.ofNullable(CRITERION_MAP.inverse().get(headerFieldId));
+    }
+
+    @Override
+    public Optional<PiTableId> mapFlowRuleTableId(int flowRuleTableId) {
+        return Optional.ofNullable(TABLE_MAP.get(flowRuleTableId));
+    }
+}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconf.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconf.java
new file mode 100644
index 0000000..ac2dbd7
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconf.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.bmv2;
+
+import com.eclipsesource.json.Json;
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.model.PiPipelineInterpreter;
+import org.onosproject.net.pi.model.PiPipelineModel;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Implementation of the default pipeconf for a BMv2 device.
+ */
+public final class Bmv2DefaultPipeconf implements PiPipeconf {
+
+    private static final String PIPECONF_ID = "bmv2-default-pipeconf";
+    private static final String JSON_PATH = "/default.json";
+    private static final String P4INFO_PATH = "/default.p4info";
+
+    private final PiPipeconfId id;
+    private final PiPipelineModel pipelineModel;
+    private final InputStream jsonConfigStream = this.getClass().getResourceAsStream(JSON_PATH);
+    private final InputStream p4InfoStream = this.getClass().getResourceAsStream(P4INFO_PATH);
+    private final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
+
+    Bmv2DefaultPipeconf() {
+        this.id = new PiPipeconfId(PIPECONF_ID);
+        try {
+            this.pipelineModel = Bmv2PipelineModelParser.parse(
+                    Json.parse(new BufferedReader(new InputStreamReader(jsonConfigStream))).asObject());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        this.behaviours = ImmutableMap.of(
+                PiPipelineInterpreter.class, Bmv2DefaultInterpreter.class
+                // TODO: reuse default single table pipeliner.
+        );
+    }
+
+    @Override
+    public PiPipeconfId id() {
+        return this.id;
+    }
+
+    @Override
+    public PiPipelineModel pipelineModel() {
+        return pipelineModel;
+    }
+
+    @Override
+    public Collection<Class<? extends Behaviour>> behaviours() {
+        return behaviours.keySet();
+    }
+
+    @Override
+    public Optional<Class<? extends Behaviour>> implementation(Class<? extends Behaviour> behaviour) {
+        return Optional.ofNullable(behaviours.get(behaviour));
+    }
+
+    @Override
+    public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
+        return behaviours.containsKey(behaviourClass);
+    }
+
+    @Override
+    public Optional<InputStream> extension(ExtensionType type) {
+
+        switch (type) {
+            case BMV2_JSON:
+                return Optional.of(jsonConfigStream);
+            case P4_INFO_TEXT:
+                return Optional.of(p4InfoStream);
+            default:
+                return Optional.empty();
+        }
+    }
+}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java
index 8774c09..5d74947 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Handshaker.java
@@ -16,17 +16,14 @@
 
 package org.onosproject.drivers.bmv2;
 
-import org.onosproject.grpc.api.GrpcChannelId;
-import org.onosproject.grpc.api.GrpcController;
-import org.onosproject.grpc.api.GrpcServiceId;
-import org.onosproject.grpc.api.GrpcStreamObserverId;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.netty.NettyChannelBuilder;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.device.DeviceHandshaker;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.net.driver.DriverData;
-import org.onosproject.net.key.DeviceKeyId;
-import org.onosproject.net.key.DeviceKeyService;
+import org.onosproject.p4runtime.api.P4RuntimeController;
 import org.slf4j.Logger;
 
 import java.util.concurrent.CompletableFuture;
@@ -34,63 +31,71 @@
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Implementation of the DeviceHandshaker for the BMv2 softswitch.
+ * Implementation of DeviceHandshaker for BMv2.
  */
-//TODO consider abstract class with empty connect method and
-//the implementation into a protected one for reusability.
-//FIXME fill method bodies, used for testing.
 public class Bmv2Handshaker extends AbstractHandlerBehaviour
         implements DeviceHandshaker {
 
     private final Logger log = getLogger(getClass());
 
+    // TODO: consider abstract class with empty connect method and  implementation into a protected one for reusability.
+
     @Override
     public CompletableFuture<Boolean> connect() {
-        GrpcController controller = handler().get(GrpcController.class);
+        return CompletableFuture.supplyAsync(this::doConnect);
+    }
+
+    private boolean doConnect() {
+
+        P4RuntimeController controller = handler().get(P4RuntimeController.class);
+
         DeviceId deviceId = handler().data().deviceId();
-
-        CompletableFuture<Boolean> result = new CompletableFuture<>();
-        DeviceKeyService deviceKeyService = handler().get(DeviceKeyService.class);
+        // DeviceKeyService deviceKeyService = handler().get(DeviceKeyService.class);
         DriverData data = data();
-        //Retrieving information from the driver data.
-        log.info("protocol bmv2, ip {}, port {}, key {}", data.value("p4runtime_ip"),
-                data.value("p4runtime_port"),
-                deviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(data.value("p4runtime_key")))
-                        .asUsernamePassword().username());
 
-        log.info("protocol gnmi, ip {}, port {}, key {}", data.value("gnmi_ip"), data.value("gnmi_port"),
-                deviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(data.value("gnmi_key")))
-                        .asUsernamePassword().username());
-        result.complete(true);
+        String serverAddr = data.value("p4runtime_ip");
+        int serverPort = Integer.valueOf(data.value("p4runtime_port"));
+        int p4DeviceId = Integer.valueOf(data.value("p4runtime_deviceId"));
 
-        //we know we need packet in so we register the observer.
-        GrpcChannelId channelId = GrpcChannelId.of(deviceId, "bmv2");
-        GrpcServiceId serviceId = GrpcServiceId.of(channelId, "p4runtime");
-        GrpcStreamObserverId observerId = GrpcStreamObserverId.of(serviceId,
-                Bmv2PacketProgrammable.class.getSimpleName());
-        controller.addObserver(observerId, new Bmv2PacketInObserverHandler());
-        return result;
+        ManagedChannelBuilder channelBuilder = NettyChannelBuilder
+                .forAddress(serverAddr, serverPort)
+                .usePlaintext(true);
+
+        if (!controller.createClient(deviceId, p4DeviceId, channelBuilder)) {
+            log.warn("Unable to create P4runtime client for {}", deviceId);
+            return false;
+        }
+
+        // TODO: gNMI handling
+
+        return true;
     }
 
     @Override
     public CompletableFuture<Boolean> disconnect() {
-        CompletableFuture<Boolean> result = new CompletableFuture<>();
-        result.complete(true);
-        return result;
+        return CompletableFuture.supplyAsync(() -> {
+            P4RuntimeController controller = handler().get(P4RuntimeController.class);
+            DeviceId deviceId = handler().data().deviceId();
+            controller.removeClient(deviceId);
+            return true;
+        });
     }
 
     @Override
     public CompletableFuture<Boolean> isReachable() {
-        CompletableFuture<Boolean> result = new CompletableFuture<>();
-        result.complete(true);
-        return result;
+        return CompletableFuture.supplyAsync(() -> {
+            P4RuntimeController controller = handler().get(P4RuntimeController.class);
+            DeviceId deviceId = handler().data().deviceId();
+            return controller.isReacheable(deviceId);
+        });
     }
 
     @Override
     public CompletableFuture<MastershipRole> roleChanged(MastershipRole newRole) {
         CompletableFuture<MastershipRole> result = new CompletableFuture<>();
+        log.warn("roleChanged not implemented");
         result.complete(MastershipRole.MASTER);
+        // TODO.
         return result;
     }
-
 }
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketInObserverHandler.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketInObserverHandler.java
deleted file mode 100644
index 3b9e145..0000000
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketInObserverHandler.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.drivers.bmv2;
-
-import io.grpc.ManagedChannel;
-import io.grpc.stub.StreamObserver;
-import org.onosproject.grpc.api.GrpcObserverHandler;
-import org.slf4j.Logger;
-
-import java.util.Optional;
-
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Sample Implementation of a PacketInObserverHandler.
- * TODO refactor and actually use.
- */
-public class Bmv2PacketInObserverHandler implements GrpcObserverHandler {
-
-    private final Logger log = getLogger(getClass());
-
-    //private final AbstractStub asyncStub;
-
-    //FIXME put at object due to p4Runtime compilation problems to be fixed.
-    private StreamObserver<Object> requestStreamObserver;
-
-    @Override
-    public void bindObserver(ManagedChannel channel) {
-
-        //asyncStub = ProtoGeneratedClass.newStub(channel);
-
-        //reqeustStreamObserver = asyncStub.MethodName(new PacketInObserver());
-
-    }
-
-    @Override
-    public Optional<StreamObserver> requestStreamObserver() {
-        return Optional.of(requestStreamObserver);
-    }
-
-    @Override
-    public void removeObserver() {
-        //this should complete the two way streaming
-        requestStreamObserver.onCompleted();
-    }
-
-    private class PacketInObserver implements StreamObserver<Object> {
-
-        @Override
-        public void onNext(Object o) {
-            log.info("onNext: {}", o.toString());
-
-        }
-
-        @Override
-        public void onError(Throwable throwable) {
-
-        }
-
-        @Override
-        public void onCompleted() {
-
-        }
-    }
-}
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 4b76067..7bf2258 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,40 +16,32 @@
 
 package org.onosproject.drivers.bmv2;
 
-import io.grpc.stub.StreamObserver;
-import org.onosproject.grpc.api.GrpcChannelId;
-import org.onosproject.grpc.api.GrpcController;
-import org.onosproject.grpc.api.GrpcObserverHandler;
-import org.onosproject.grpc.api.GrpcServiceId;
-import org.onosproject.grpc.api.GrpcStreamObserverId;
-import org.onosproject.net.DeviceId;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
-import org.onosproject.net.driver.DriverHandler;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketProgrammable;
 
-import java.util.Optional;
-
 /**
  * Packet Programmable behaviour for BMv2 devices.
  */
 public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable {
+
     @Override
     public void emit(OutboundPacket packet) {
-        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));
+        // 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));
     }
 }
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java
new file mode 100644
index 0000000..735c142
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.bmv2;
+
+import org.onlab.util.SharedExecutors;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipelineProgrammable;
+import org.onosproject.p4runtime.api.P4RuntimeClient;
+import org.onosproject.p4runtime.api.P4RuntimeController;
+import org.slf4j.Logger;
+
+import java.io.InputStream;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
+import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the PiPipelineProgrammable for BMv2.
+ */
+public class Bmv2PipelineProgrammable extends AbstractHandlerBehaviour implements PiPipelineProgrammable {
+
+    private static final PiPipeconf DEFAULT_PIPECONF = new Bmv2DefaultPipeconf();
+
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    public CompletableFuture<Boolean> deployPipeconf(PiPipeconf pipeconf) {
+
+        CompletableFuture<Boolean> result = new CompletableFuture<>();
+
+        SharedExecutors.getPoolThreadExecutor().submit(() -> result.complete(doDeployConfig(pipeconf)));
+
+        return result;
+    }
+
+    private boolean doDeployConfig(PiPipeconf pipeconf) {
+
+        P4RuntimeController controller = handler().get(P4RuntimeController.class);
+
+        DeviceId deviceId = handler().data().deviceId();
+
+        if (!controller.hasClient(deviceId)) {
+            log.warn("Unable to find client for {}, aborting pipeconf deploy", deviceId);
+            return false;
+
+        }
+
+        P4RuntimeClient client = controller.getClient(deviceId);
+
+        if (!pipeconf.extension(BMV2_JSON).isPresent()) {
+            log.warn("Missing BMv2 JSON config in pipeconf {}, aborting pipeconf deploy", pipeconf.id());
+            return false;
+        }
+
+        if (!pipeconf.extension(P4_INFO_TEXT).isPresent()) {
+            log.warn("Missing P4Info in pipeconf {}, aborting pipeconf deploy", pipeconf.id());
+            return false;
+        }
+
+        InputStream p4InfoStream = pipeconf.extension(P4_INFO_TEXT).get();
+        InputStream jsonStream = pipeconf.extension(BMV2_JSON).get();
+
+        try {
+            if (!client.setPipelineConfig(p4InfoStream, jsonStream).get()) {
+                log.warn("Unable to deploy pipeconf {} to {}", pipeconf.id(), deviceId);
+                return false;
+            }
+
+            // It would be more logical to have this performed at device handshake, but P4runtime would reject any
+            // command if a P4info has not been set first.
+            if (!client.initStreamChannel().get()) {
+                log.warn("Unable to init stream channel to {}.", deviceId);
+                return false;
+            }
+
+        } catch (InterruptedException | ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+
+        return true;
+    }
+
+    @Override
+    public Optional<PiPipeconf> getDefaultPipeconf() {
+        return Optional.of(DEFAULT_PIPECONF);
+    }
+}
diff --git a/drivers/bmv2/src/main/resources/bmv2-drivers.xml b/drivers/bmv2/src/main/resources/bmv2-drivers.xml
index bc343e0..0120974 100644
--- a/drivers/bmv2/src/main/resources/bmv2-drivers.xml
+++ b/drivers/bmv2/src/main/resources/bmv2-drivers.xml
@@ -20,6 +20,8 @@
                    impl="org.onosproject.drivers.bmv2.Bmv2Handshaker"/>
         <behaviour api="org.onosproject.net.packet.PacketProgrammable"
                    impl="org.onosproject.drivers.bmv2.Bmv2PacketProgrammable"/>
+        <behaviour api="org.onosproject.net.pi.model.PiPipelineProgrammable"
+                   impl="org.onosproject.drivers.bmv2.Bmv2PipelineProgrammable"/>
     </driver>
 </drivers>
 
diff --git a/drivers/bmv2/src/main/resources/default.json b/drivers/bmv2/src/main/resources/default.json
new file mode 100644
index 0000000..3a46dcc
--- /dev/null
+++ b/drivers/bmv2/src/main/resources/default.json
@@ -0,0 +1,2697 @@
+{
+  "program" : "default.p4",
+  "__meta__" : {
+    "version" : [2, 7],
+    "compiler" : "https://github.com/p4lang/p4c"
+  },
+  "header_types" : [
+    {
+      "name" : "scalars_0",
+      "id" : 0,
+      "fields" : [
+        ["tmp", 32, false],
+        ["tmp_0", 32, false]
+      ]
+    },
+    {
+      "name" : "standard_metadata",
+      "id" : 1,
+      "fields" : [
+        ["ingress_port", 9, false],
+        ["egress_spec", 9, false],
+        ["egress_port", 9, false],
+        ["clone_spec", 32, false],
+        ["instance_type", 32, false],
+        ["drop", 1, false],
+        ["recirculate_port", 16, false],
+        ["packet_length", 32, false],
+        ["enq_timestamp", 32, false],
+        ["enq_qdepth", 19, false],
+        ["deq_timedelta", 32, false],
+        ["deq_qdepth", 19, false],
+        ["ingress_global_timestamp", 48, false],
+        ["lf_field_list", 32, false],
+        ["mcast_grp", 16, false],
+        ["resubmit_flag", 1, false],
+        ["egress_rid", 16, false],
+        ["_padding", 5, false]
+      ]
+    },
+    {
+      "name" : "ethernet_t",
+      "id" : 2,
+      "fields" : [
+        ["dstAddr", 48, false],
+        ["srcAddr", 48, false],
+        ["etherType", 16, false]
+      ]
+    },
+    {
+      "name" : "ipv4_t",
+      "id" : 3,
+      "fields" : [
+        ["version", 4, false],
+        ["ihl", 4, false],
+        ["diffserv", 8, false],
+        ["totalLen", 16, false],
+        ["identification", 16, false],
+        ["flags", 3, false],
+        ["fragOffset", 13, false],
+        ["ttl", 8, false],
+        ["protocol", 8, false],
+        ["hdrChecksum", 16, false],
+        ["srcAddr", 32, false],
+        ["dstAddr", 32, false]
+      ]
+    },
+    {
+      "name" : "tcp_t",
+      "id" : 4,
+      "fields" : [
+        ["srcPort", 16, false],
+        ["dstPort", 16, false],
+        ["seqNo", 32, false],
+        ["ackNo", 32, false],
+        ["dataOffset", 4, false],
+        ["res", 3, false],
+        ["ecn", 3, false],
+        ["ctrl", 6, false],
+        ["window", 16, false],
+        ["checksum", 16, false],
+        ["urgentPtr", 16, false]
+      ]
+    },
+    {
+      "name" : "udp_t",
+      "id" : 5,
+      "fields" : [
+        ["srcPort", 16, false],
+        ["dstPort", 16, false],
+        ["length_", 16, false],
+        ["checksum", 16, false]
+      ]
+    },
+    {
+      "name" : "ecmp_metadata_t",
+      "id" : 6,
+      "fields" : [
+        ["groupId", 16, false],
+        ["selector", 16, false]
+      ]
+    },
+    {
+      "name" : "wcmp_meta_t",
+      "id" : 7,
+      "fields" : [
+        ["groupId", 16, false],
+        ["numBits", 8, false],
+        ["selector", 64, false]
+      ]
+    },
+    {
+      "name" : "intrinsic_metadata_t",
+      "id" : 8,
+      "fields" : [
+        ["ingress_global_timestamp", 32, false],
+        ["lf_field_list", 32, false],
+        ["mcast_grp", 16, false],
+        ["egress_rid", 16, false]
+      ]
+    }
+  ],
+  "headers" : [
+    {
+      "name" : "standard_metadata_3",
+      "id" : 0,
+      "header_type" : "standard_metadata",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "standard_metadata_4",
+      "id" : 1,
+      "header_type" : "standard_metadata",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "standard_metadata_5",
+      "id" : 2,
+      "header_type" : "standard_metadata",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "scalars",
+      "id" : 3,
+      "header_type" : "scalars_0",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "standard_metadata",
+      "id" : 4,
+      "header_type" : "standard_metadata",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "ethernet",
+      "id" : 5,
+      "header_type" : "ethernet_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "ipv4",
+      "id" : 6,
+      "header_type" : "ipv4_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "tcp",
+      "id" : 7,
+      "header_type" : "tcp_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "udp",
+      "id" : 8,
+      "header_type" : "udp_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "ecmp_metadata",
+      "id" : 9,
+      "header_type" : "ecmp_metadata_t",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "wcmp_meta",
+      "id" : 10,
+      "header_type" : "wcmp_meta_t",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "intrinsic_metadata",
+      "id" : 11,
+      "header_type" : "intrinsic_metadata_t",
+      "metadata" : true,
+      "pi_omit" : true
+    }
+  ],
+  "header_stacks" : [],
+  "header_union_types" : [],
+  "header_unions" : [],
+  "header_union_stacks" : [],
+  "field_lists" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
+  "enums" : [],
+  "parsers" : [
+    {
+      "name" : "parser",
+      "id" : 0,
+      "init_state" : "start",
+      "parse_states" : [
+        {
+          "name" : "parse_ipv4",
+          "id" : 0,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "ipv4"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "0x06",
+              "mask" : null,
+              "next_state" : "parse_tcp"
+            },
+            {
+              "value" : "0x11",
+              "mask" : null,
+              "next_state" : "parse_udp"
+            },
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : [
+            {
+              "type" : "field",
+              "value" : ["ipv4", "protocol"]
+            }
+          ]
+        },
+        {
+          "name" : "parse_tcp",
+          "id" : 1,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "tcp"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : []
+        },
+        {
+          "name" : "parse_udp",
+          "id" : 2,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "udp"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : []
+        },
+        {
+          "name" : "start",
+          "id" : 3,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "ethernet"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "0x0800",
+              "mask" : null,
+              "next_state" : "parse_ipv4"
+            },
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "etherType"]
+            }
+          ]
+        }
+      ]
+    }
+  ],
+  "deparsers" : [
+    {
+      "name" : "deparser",
+      "id" : 0,
+      "source_info" : {
+        "filename" : "include/parsers.p4",
+        "line" : 43,
+        "column" : 8,
+        "source_fragment" : "DeparserImpl"
+      },
+      "order" : ["ethernet", "ipv4", "udp", "tcp"]
+    }
+  ],
+  "meter_arrays" : [],
+  "counter_arrays" : [
+    {
+      "name" : "table0_counter",
+      "id" : 0,
+      "is_direct" : true,
+      "binding" : "table0"
+    },
+    {
+      "name" : "port_counters_control.egress_port_counter",
+      "id" : 1,
+      "source_info" : {
+        "filename" : "include/port_counters.p4",
+        "line" : 6,
+        "column" : 38,
+        "source_fragment" : "egress_port_counter"
+      },
+      "size" : 254,
+      "is_direct" : false
+    },
+    {
+      "name" : "port_counters_control.ingress_port_counter",
+      "id" : 2,
+      "source_info" : {
+        "filename" : "include/port_counters.p4",
+        "line" : 7,
+        "column" : 38,
+        "source_fragment" : "ingress_port_counter"
+      },
+      "size" : 254,
+      "is_direct" : false
+    }
+  ],
+  "register_arrays" : [],
+  "calculations" : [],
+  "learn_lists" : [],
+  "actions" : [
+    {
+      "name" : "set_egress_port",
+      "id" : 0,
+      "runtime_data" : [
+        {
+          "name" : "port",
+          "bitwidth" : 9
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "ingress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "egress_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "egress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "clone_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "clone_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "instance_type"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "instance_type"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "drop"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "drop"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "recirculate_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "recirculate_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "packet_length"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "packet_length"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "enq_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "enq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "deq_timedelta"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_timedelta"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "deq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "ingress_global_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_global_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "lf_field_list"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "lf_field_list"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "mcast_grp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "mcast_grp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "resubmit_flag"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "resubmit_flag"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "egress_rid"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_rid"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 9,
+            "column" : 4,
+            "source_fragment" : "standard_metadata.egress_spec = port"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "ingress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "egress_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "egress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "clone_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "clone_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "instance_type"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "instance_type"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "drop"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "drop"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "recirculate_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "recirculate_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "packet_length"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "packet_length"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "enq_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "enq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_timedelta"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "deq_timedelta"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "deq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_global_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "ingress_global_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "lf_field_list"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "lf_field_list"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "mcast_grp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "mcast_grp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "resubmit_flag"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "resubmit_flag"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_rid"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_3", "egress_rid"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 8,
+            "column" : 49,
+            "source_fragment" : "standard_metadata, Port port) { ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "send_to_cpu",
+      "id" : 1,
+      "runtime_data" : [],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "ingress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "egress_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "egress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "clone_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "clone_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "instance_type"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "instance_type"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "drop"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "drop"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "recirculate_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "recirculate_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "packet_length"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "packet_length"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "enq_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "enq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "deq_timedelta"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_timedelta"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "deq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "ingress_global_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_global_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "lf_field_list"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "lf_field_list"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "mcast_grp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "mcast_grp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "resubmit_flag"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "resubmit_flag"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "egress_rid"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_rid"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "egress_spec"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x00ff"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 5,
+            "column" : 4,
+            "source_fragment" : "standard_metadata.egress_spec = 9w255"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "ingress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "egress_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "egress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "clone_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "clone_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "instance_type"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "instance_type"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "drop"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "drop"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "recirculate_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "recirculate_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "packet_length"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "packet_length"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "enq_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "enq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_timedelta"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "deq_timedelta"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "deq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_global_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "ingress_global_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "lf_field_list"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "lf_field_list"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "mcast_grp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "mcast_grp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "resubmit_flag"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "resubmit_flag"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_rid"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_4", "egress_rid"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 4,
+            "column" : 45,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "drop",
+      "id" : 2,
+      "runtime_data" : [],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "ingress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "egress_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "egress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "clone_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "clone_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "instance_type"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "instance_type"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "drop"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "drop"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "recirculate_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "recirculate_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "packet_length"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "packet_length"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "enq_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "enq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "deq_timedelta"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_timedelta"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "deq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "ingress_global_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_global_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "lf_field_list"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "lf_field_list"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "mcast_grp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "mcast_grp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "resubmit_flag"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "resubmit_flag"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "egress_rid"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_rid"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "egress_spec"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01ff"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 13,
+            "column" : 4,
+            "source_fragment" : "standard_metadata.egress_spec = 9w511"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "ingress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "egress_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "egress_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "clone_spec"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "clone_spec"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "instance_type"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "instance_type"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "drop"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "drop"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "recirculate_port"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "recirculate_port"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "packet_length"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "packet_length"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "enq_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "enq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "enq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_timedelta"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "deq_timedelta"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "deq_qdepth"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "deq_qdepth"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "ingress_global_timestamp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "ingress_global_timestamp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "lf_field_list"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "lf_field_list"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "mcast_grp"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "mcast_grp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "resubmit_flag"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "resubmit_flag"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_rid"]
+            },
+            {
+              "type" : "field",
+              "value" : ["standard_metadata_5", "egress_rid"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/actions.p4",
+            "line" : 12,
+            "column" : 38,
+            "source_fragment" : "standard_metadata) { ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "NoAction",
+      "id" : 3,
+      "runtime_data" : [],
+      "primitives" : []
+    },
+    {
+      "name" : "act",
+      "id" : 4,
+      "runtime_data" : [],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "&",
+                  "left" : {
+                    "type" : "field",
+                    "value" : ["standard_metadata", "ingress_port"]
+                  },
+                  "right" : {
+                    "type" : "hexstr",
+                    "value" : "0xffffffff"
+                  }
+                }
+              }
+            }
+          ]
+        },
+        {
+          "op" : "count",
+          "parameters" : [
+            {
+              "type" : "counter_array",
+              "value" : "port_counters_control.ingress_port_counter"
+            },
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/port_counters.p4",
+            "line" : 11,
+            "column" : 12,
+            "source_fragment" : "ingress_port_counter.count((bit<32>)standard_metadata.ingress_port)"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp_0"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "&",
+                  "left" : {
+                    "type" : "field",
+                    "value" : ["standard_metadata", "egress_spec"]
+                  },
+                  "right" : {
+                    "type" : "hexstr",
+                    "value" : "0xffffffff"
+                  }
+                }
+              }
+            }
+          ]
+        },
+        {
+          "op" : "count",
+          "parameters" : [
+            {
+              "type" : "counter_array",
+              "value" : "port_counters_control.egress_port_counter"
+            },
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp_0"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/port_counters.p4",
+            "line" : 12,
+            "column" : 12,
+            "source_fragment" : "egress_port_counter.count((bit<32>)standard_metadata.egress_spec)"
+          }
+        }
+      ]
+    }
+  ],
+  "pipelines" : [
+    {
+      "name" : "ingress",
+      "id" : 0,
+      "source_info" : {
+        "filename" : "default.p4",
+        "line" : 10,
+        "column" : 8,
+        "source_fragment" : "ingress"
+      },
+      "init_table" : "table0",
+      "tables" : [
+        {
+          "name" : "table0",
+          "id" : 0,
+          "source_info" : {
+            "filename" : "default.p4",
+            "line" : 13,
+            "column" : 10,
+            "source_fragment" : "table0"
+          },
+          "key" : [
+            {
+              "match_type" : "ternary",
+              "target" : ["standard_metadata", "ingress_port"],
+              "mask" : null
+            },
+            {
+              "match_type" : "ternary",
+              "target" : ["ethernet", "dstAddr"],
+              "mask" : null
+            },
+            {
+              "match_type" : "ternary",
+              "target" : ["ethernet", "srcAddr"],
+              "mask" : null
+            },
+            {
+              "match_type" : "ternary",
+              "target" : ["ethernet", "etherType"],
+              "mask" : null
+            }
+          ],
+          "match_type" : "ternary",
+          "type" : "simple",
+          "max_size" : 1024,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [0, 1, 2, 3],
+          "actions" : ["set_egress_port", "send_to_cpu", "drop", "NoAction"],
+          "base_default_next" : "node_3",
+          "next_tables" : {
+            "set_egress_port" : "node_3",
+            "send_to_cpu" : "node_3",
+            "drop" : "node_3",
+            "NoAction" : "node_3"
+          },
+          "default_entry" : {
+            "action_id" : 3,
+            "action_const" : false,
+            "action_data" : [],
+            "action_entry_const" : false
+          }
+        },
+        {
+          "name" : "tbl_act",
+          "id" : 1,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [4],
+          "actions" : ["act"],
+          "base_default_next" : null,
+          "next_tables" : {
+            "act" : null
+          },
+          "default_entry" : {
+            "action_id" : 4,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        }
+      ],
+      "action_profiles" : [],
+      "conditionals" : [
+        {
+          "name" : "node_3",
+          "id" : 0,
+          "source_info" : {
+            "filename" : "include/port_counters.p4",
+            "line" : 10,
+            "column" : 12,
+            "source_fragment" : "standard_metadata.egress_spec < 254"
+          },
+          "expression" : {
+            "type" : "expression",
+            "value" : {
+              "op" : "<",
+              "left" : {
+                "type" : "field",
+                "value" : ["standard_metadata", "egress_spec"]
+              },
+              "right" : {
+                "type" : "hexstr",
+                "value" : "0x00fe"
+              }
+            }
+          },
+          "false_next" : null,
+          "true_next" : "tbl_act"
+        }
+      ]
+    },
+    {
+      "name" : "egress",
+      "id" : 1,
+      "source_info" : {
+        "filename" : "default.p4",
+        "line" : 36,
+        "column" : 8,
+        "source_fragment" : "egress"
+      },
+      "init_table" : null,
+      "tables" : [],
+      "action_profiles" : [],
+      "conditionals" : []
+    }
+  ],
+  "checksums" : [],
+  "force_arith" : [],
+  "extern_instances" : [],
+  "field_aliases" : [
+    [
+      "queueing_metadata.enq_timestamp",
+      ["standard_metadata", "enq_timestamp"]
+    ],
+    [
+      "queueing_metadata.enq_qdepth",
+      ["standard_metadata", "enq_qdepth"]
+    ],
+    [
+      "queueing_metadata.deq_timedelta",
+      ["standard_metadata", "deq_timedelta"]
+    ],
+    [
+      "queueing_metadata.deq_qdepth",
+      ["standard_metadata", "deq_qdepth"]
+    ],
+    [
+      "intrinsic_metadata.ingress_global_timestamp",
+      ["standard_metadata", "ingress_global_timestamp"]
+    ],
+    [
+      "intrinsic_metadata.lf_field_list",
+      ["standard_metadata", "lf_field_list"]
+    ],
+    [
+      "intrinsic_metadata.mcast_grp",
+      ["standard_metadata", "mcast_grp"]
+    ],
+    [
+      "intrinsic_metadata.resubmit_flag",
+      ["standard_metadata", "resubmit_flag"]
+    ],
+    [
+      "intrinsic_metadata.egress_rid",
+      ["standard_metadata", "egress_rid"]
+    ]
+  ]
+}
\ No newline at end of file
diff --git a/drivers/bmv2/src/main/resources/default.p4info b/drivers/bmv2/src/main/resources/default.p4info
new file mode 100644
index 0000000..bd3649d
--- /dev/null
+++ b/drivers/bmv2/src/main/resources/default.p4info
@@ -0,0 +1,113 @@
+tables {
+  preamble {
+    id: 33617813
+    name: "table0"
+    alias: "table0"
+  }
+  match_fields {
+    id: 1
+    name: "standard_metadata.ingress_port"
+    bitwidth: 9
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 2
+    name: "hdr.ethernet.dstAddr"
+    bitwidth: 48
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 3
+    name: "hdr.ethernet.srcAddr"
+    bitwidth: 48
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 4
+    name: "hdr.ethernet.etherType"
+    bitwidth: 16
+    match_type: TERNARY
+  }
+  action_refs {
+    id: 16794308
+  }
+  action_refs {
+    id: 16829080
+  }
+  action_refs {
+    id: 16793508
+  }
+  action_refs {
+    id: 16800567
+    annotations: "@defaultonly()"
+  }
+  direct_resource_ids: 301990488
+  size: 1024
+  with_entry_timeout: true
+}
+actions {
+  preamble {
+    id: 16794308
+    name: "set_egress_port"
+    alias: "set_egress_port"
+  }
+  params {
+    id: 1
+    name: "port"
+    bitwidth: 9
+  }
+}
+actions {
+  preamble {
+    id: 16829080
+    name: "send_to_cpu"
+    alias: "send_to_cpu"
+  }
+}
+actions {
+  preamble {
+    id: 16793508
+    name: "drop"
+    alias: "drop"
+  }
+}
+actions {
+  preamble {
+    id: 16800567
+    name: "NoAction"
+    alias: "NoAction"
+  }
+}
+counters {
+  preamble {
+    id: 302025528
+    name: "port_counters_control.egress_port_counter"
+    alias: "egress_port_counter"
+  }
+  spec {
+    unit: PACKETS
+  }
+  size: 254
+}
+counters {
+  preamble {
+    id: 301999025
+    name: "port_counters_control.ingress_port_counter"
+    alias: "ingress_port_counter"
+  }
+  spec {
+    unit: PACKETS
+  }
+  size: 254
+}
+direct_counters {
+  preamble {
+    id: 301990488
+    name: "table0_counter"
+    alias: "table0_counter"
+  }
+  spec {
+    unit: PACKETS
+  }
+  direct_table_id: 33617813
+}
diff --git a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcController.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcController.java
index f1e279a..629aad1 100644
--- a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcController.java
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcController.java
@@ -57,7 +57,7 @@
     Optional<GrpcObserverHandler> getObserverManager(GrpcStreamObserverId observerId);
 
     /**
-     * Tries to connect to a specific gRPC device, if the connection is successful
+     * Tries to connect to a specific gRPC server, if the connection is successful
      * returns the ManagedChannel. This method blocks until the channel is setup or a timeout expires.
      * By default the timeout is 20 seconds. If the timeout expires and thus the channel can't be set up
      * a IOException is thrown.
@@ -84,6 +84,15 @@
     Map<GrpcChannelId, ManagedChannel> getChannels();
 
     /**
+     * Returns true if the channel associated with the given identifier is open, i.e. the server is able to successfully
+     * responds to RPCs.
+     *
+     * @param channelId channel identifier
+     * @return true if channel is open, false otherwise.
+     */
+    boolean isChannelOpen(GrpcChannelId channelId);
+
+    /**
      * Returns all ManagedChannels associated to the given device identifier.
      *
      * @param deviceId the device for which we are interested.
diff --git a/protocols/grpc/ctl/BUCK b/protocols/grpc/ctl/BUCK
index 764d980..18e0411 100644
--- a/protocols/grpc/ctl/BUCK
+++ b/protocols/grpc/ctl/BUCK
@@ -1,11 +1,13 @@
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
     '//protocols/grpc/api:onos-protocols-grpc-api',
+    '//protocols/grpc/proto:onos-protocols-grpc-proto',
     '//lib:grpc-core-1.3.0',
     '//lib:grpc-protobuf-1.3.0',
     '//lib:grpc-stub-1.3.0',
     '//lib:grpc-netty-1.3.0',
     '//lib:grpc-auth-1.3.0',
+    '//lib:protobuf-java-3.0.2',
 ]
 
 TEST_DEPS = [
diff --git a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
index 4ce097d..152106a 100644
--- a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
+++ b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
@@ -19,6 +19,8 @@
 import com.google.common.collect.ImmutableSet;
 import io.grpc.ManagedChannel;
 import io.grpc.ManagedChannelBuilder;
+import io.grpc.Status;
+import io.grpc.StatusRuntimeException;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -27,16 +29,20 @@
 import org.onosproject.grpc.api.GrpcController;
 import org.onosproject.grpc.api.GrpcObserverHandler;
 import org.onosproject.grpc.api.GrpcStreamObserverId;
+import org.onosproject.grpc.ctl.dummy.Dummy;
+import org.onosproject.grpc.ctl.dummy.DummyServiceGrpc;
 import org.onosproject.net.DeviceId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Default implementation of the GrpcController.
@@ -45,6 +51,8 @@
 @Service
 public class GrpcControllerImpl implements GrpcController {
 
+    private static final int CONNECTION_TIMEOUT_SECONDS = 20;
+
     public static final Logger log = LoggerFactory
             .getLogger(GrpcControllerImpl.class);
 
@@ -87,18 +95,63 @@
     }
 
     @Override
-    public ManagedChannel connectChannel(GrpcChannelId channelId, ManagedChannelBuilder<?> channelBuilder) {
+    public ManagedChannel connectChannel(GrpcChannelId channelId, ManagedChannelBuilder<?> channelBuilder)
+            throws IOException {
         ManagedChannel channel = channelBuilder.build();
 
-        channel.getState(true);
+        // Forced connection not yet implemented. Use workaround...
+        // channel.getState(true);
+        doDummyMessage(channel);
+
         channelBuilders.put(channelId, channelBuilder);
         channels.put(channelId, channel);
         return channel;
     }
 
+    private void doDummyMessage(ManagedChannel channel) throws IOException {
+        DummyServiceGrpc.DummyServiceBlockingStub dummyStub = DummyServiceGrpc.newBlockingStub(channel)
+                .withDeadlineAfter(CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+        try {
+            dummyStub.sayHello(Dummy.DummyMessageThatNoOneWouldReallyUse.getDefaultInstance());
+        } catch (StatusRuntimeException e) {
+            if (e.getStatus() != Status.UNIMPLEMENTED) {
+                // UNIMPLEMENTED means that server received our message but doesn't know how to handle it.
+                // Hence, channel is open.
+                throw new IOException(e);
+            }
+        }
+    }
+
+    @Override
+    public boolean isChannelOpen(GrpcChannelId channelId) {
+        if (!channels.containsKey(channelId)) {
+            log.warn("Can't check if channel open for unknown channel id {}", channelId);
+            return false;
+        }
+
+        try {
+            doDummyMessage(channels.get(channelId));
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
     @Override
     public void disconnectChannel(GrpcChannelId channelId) {
-        channels.get(channelId).shutdown();
+        if (!channels.containsKey(channelId)) {
+            // Nothing to do.
+            return;
+        }
+        ManagedChannel channel = channels.get(channelId);
+
+        try {
+            channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            log.warn("Channel {} didn't shut down in time.");
+            channel.shutdownNow();
+        }
+
         channels.remove(channelId);
         channelBuilders.remove(channelId);
     }
diff --git a/protocols/grpc/proto/BUCK b/protocols/grpc/proto/BUCK
new file mode 100644
index 0000000..f354b39
--- /dev/null
+++ b/protocols/grpc/proto/BUCK
@@ -0,0 +1,28 @@
+include_defs(
+    '//bucklets/grpc.bucklet'
+)
+
+PROTOC_VER = '3.0.2'
+GRPC_VER = '1.3.0'
+
+
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//incubator/grpc-dependencies:grpc-core-repkg-' + GRPC_VER,
+    '//lib:grpc-stub-' + GRPC_VER,
+    '//lib:grpc-protobuf-' + GRPC_VER,
+    '//lib:protobuf-java-' + PROTOC_VER,
+]
+
+
+grpc_jar(
+    proto_match_patterns = ["*.proto"],
+    proto_paths = ["$ONOS_ROOT/protocols/grpc/proto/"],
+    protoc_version = PROTOC_VER,
+    plugin_version = GRPC_VER,
+    deps = COMPILE_DEPS,
+)
+
+project_config(
+    src_target = ':onos-protocols-grpc-proto'
+)
\ No newline at end of file
diff --git a/protocols/grpc/proto/dummy.proto b/protocols/grpc/proto/dummy.proto
new file mode 100644
index 0000000..d02b5d8
--- /dev/null
+++ b/protocols/grpc/proto/dummy.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+option java_package = "org.onosproject.grpc.ctl.dummy";
+
+package dummy;
+
+service DummyService {
+  rpc SayHello (DummyMessageThatNoOneWouldReallyUse) returns (DummyMessageThatNoOneWouldReallyUse) {}
+}
+
+message DummyMessageThatNoOneWouldReallyUse {
+}
\ No newline at end of file
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeController.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeController.java
index 3b8074f..ecdcb31 100644
--- a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeController.java
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeController.java
@@ -65,4 +65,14 @@
      * @return true if client exists, false otherwise.
      */
     boolean hasClient(DeviceId deviceId);
+
+    /**
+     * Returns true if the P4Runtime server running on the given device is reachable, i.e. the channel is open and the
+     * server is able to respond to RPCs, false otherwise. Reachability can be tested only if a client was previously
+     * created using {@link #createClient(DeviceId, int, ManagedChannelBuilder)}, otherwise this method returns false.
+     *
+     * @param deviceId device identifier.
+     * @return true if a client was created and is able to contact the P4Runtime server, false otherwise.
+     */
+    boolean isReacheable(DeviceId deviceId);
 }
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 e6603ea..35e9726 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
@@ -20,6 +20,7 @@
 import com.google.protobuf.ByteString;
 import com.google.protobuf.ExtensionRegistry;
 import com.google.protobuf.TextFormat;
+import io.grpc.Context;
 import io.grpc.ManagedChannel;
 import io.grpc.Status;
 import io.grpc.StatusRuntimeException;
@@ -64,6 +65,7 @@
     private final P4RuntimeGrpc.P4RuntimeStub asyncStub;
     private ExecutorService executorService;
     private StreamObserver<StreamMessageRequest> streamRequestObserver;
+    private Context.CancellableContext streamContext;
 
 
     P4RuntimeClientImpl(DeviceId deviceId, int p4DeviceId, ManagedChannel channel, P4RuntimeControllerImpl controller,
@@ -74,8 +76,7 @@
         this.executorService = executorService;
         this.blockingStub = P4RuntimeGrpc.newBlockingStub(channel)
                 .withDeadlineAfter(DEADLINE_SECONDS, TimeUnit.SECONDS);
-        this.asyncStub = P4RuntimeGrpc.newStub(channel)
-                .withDeadlineAfter(DEADLINE_SECONDS, TimeUnit.SECONDS);
+        this.asyncStub = P4RuntimeGrpc.newStub(channel);
     }
 
     @Override
@@ -85,21 +86,44 @@
 
     private boolean doInitStreamChannel() {
         if (this.streamRequestObserver == null) {
-            this.streamRequestObserver = this.asyncStub.streamChannel(new StreamChannelResponseObserver());
+
+            streamContext = Context.current().withCancellation();
+            streamContext.run(
+                    () -> streamRequestObserver = asyncStub.streamChannel(new StreamChannelResponseObserver()));
+
             // To listen for packets and other events, we need to start the RPC.
-            // Here we do it by sending an empty packet out.
-            try {
-                this.streamRequestObserver.onNext(StreamMessageRequest.newBuilder()
-                                                          .setPacket(PacketOut.getDefaultInstance())
-                                                          .build());
-            } catch (StatusRuntimeException e) {
-                log.warn("Unable to initialize stream channel for {}: {}", deviceId, e);
+            // Here we do it by sending a master arbitration update.
+            if (!doArbitrationUpdate()) {
+                log.warn("Unable to initialize stream channel for {}", deviceId);
                 return false;
             }
         }
         return true;
     }
 
+    private boolean doArbitrationUpdate() {
+
+        if (streamRequestObserver == null) {
+            log.error("Null request stream observer for {}", deviceId);
+            return false;
+        }
+
+        try {
+            StreamMessageRequest initRequest = StreamMessageRequest
+                    .newBuilder()
+                    .setArbitration(MasterArbitrationUpdate
+                                            .newBuilder()
+                                            .setDeviceId(p4DeviceId)
+                                            .build())
+                    .build();
+            streamRequestObserver.onNext(initRequest);
+            return true;
+        } catch (StatusRuntimeException e) {
+            log.warn("Arbitration update failed for {}: {}", deviceId, e);
+            return false;
+        }
+    }
+
     @Override
     public CompletableFuture<Boolean> setPipelineConfig(InputStream p4info, InputStream targetConfig) {
         return CompletableFuture.supplyAsync(() -> doSetPipelineConfig(p4info, targetConfig), executorService);
@@ -168,12 +192,15 @@
     @Override
     public void shutdown() {
 
-        if (this.streamRequestObserver != null) {
-            this.streamRequestObserver.onError(new StatusRuntimeException(Status.CANCELLED));
-            this.streamRequestObserver.onCompleted();
+        log.info("Shutting down client for {}...", deviceId);
+
+        if (streamRequestObserver != null) {
+            streamRequestObserver.onCompleted();
+            streamContext.cancel(null);
+            streamContext = null;
         }
 
-        this.executorService.shutdownNow();
+        this.executorService.shutdown();
         try {
             executorService.awaitTermination(5, TimeUnit.SECONDS);
         } catch (InterruptedException e) {
@@ -216,12 +243,16 @@
 
         @Override
         public void onError(Throwable throwable) {
-            log.warn("Error on stream channel for {}: {}", deviceId, throwable);
+            log.warn("Error on stream channel for {}: {}", deviceId, Status.fromThrowable(throwable));
+            // FIXME: we might want to recreate the channel.
+            // In general, we want to be robust against any transient error and, if the channel is open, make sure the
+            // stream channel is always on.
         }
 
         @Override
         public void onCompleted() {
-            // TODO: declare the device as disconnected?
+            log.warn("Stream channel for {} has completed", deviceId);
+            // FIXME: same concern as before.
         }
     }
 
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
index cd4151c..06376ca 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
@@ -39,8 +39,8 @@
 
 import java.io.IOException;
 import java.util.Map;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static java.lang.String.format;
@@ -62,10 +62,11 @@
     private final Logger log = getLogger(getClass());
 
     private final NameResolverProvider nameResolverProvider = new DnsNameResolverProvider();
-    private final Map<DeviceId, P4RuntimeClient> clients = Maps.newConcurrentMap();
-    private final Map<DeviceId, GrpcChannelId> channelIds = Maps.newConcurrentMap();
+    private final Map<DeviceId, P4RuntimeClient> clients = Maps.newHashMap();
+    private final Map<DeviceId, GrpcChannelId> channelIds = Maps.newHashMap();
+
     // TODO: should use a cache to delete unused locks.
-    private final Map<DeviceId, Lock> deviceLocks = Maps.newConcurrentMap();
+    private final Map<DeviceId, ReadWriteLock> deviceLocks = Maps.newConcurrentMap();
 
     @Activate
     public void activate() {
@@ -85,8 +86,8 @@
         checkNotNull(deviceId);
         checkNotNull(channelBuilder);
 
-        deviceLocks.putIfAbsent(deviceId, new ReentrantLock());
-        deviceLocks.get(deviceId).lock();
+        deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
+        deviceLocks.get(deviceId).writeLock().lock();
 
         log.info("Creating client for {} (with internal device id {})...", deviceId, p4DeviceId);
 
@@ -97,11 +98,12 @@
                 return doCreateClient(deviceId, p4DeviceId, channelBuilder);
             }
         } finally {
-            deviceLocks.get(deviceId).unlock();
+            deviceLocks.get(deviceId).writeLock().unlock();
         }
     }
 
     private boolean doCreateClient(DeviceId deviceId, int p4DeviceId, ManagedChannelBuilder channelBuilder) {
+
         GrpcChannelId channelId = GrpcChannelId.of(deviceId, "p4runtime");
 
         // Channel defaults.
@@ -127,43 +129,62 @@
     @Override
     public P4RuntimeClient getClient(DeviceId deviceId) {
 
-        deviceLocks.putIfAbsent(deviceId, new ReentrantLock());
-        deviceLocks.get(deviceId).lock();
+        deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
+        deviceLocks.get(deviceId).readLock().lock();
 
         try {
             return clients.get(deviceId);
         } finally {
-            deviceLocks.get(deviceId).unlock();
+            deviceLocks.get(deviceId).readLock().unlock();
         }
     }
 
     @Override
     public void removeClient(DeviceId deviceId) {
 
-        deviceLocks.putIfAbsent(deviceId, new ReentrantLock());
-        deviceLocks.get(deviceId).lock();
+        deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
+        deviceLocks.get(deviceId).writeLock().lock();
 
         try {
             if (clients.containsKey(deviceId)) {
                 clients.get(deviceId).shutdown();
                 grpcController.disconnectChannel(channelIds.get(deviceId));
                 clients.remove(deviceId);
+                channelIds.remove(deviceId);
             }
         } finally {
-            deviceLocks.get(deviceId).unlock();
+            deviceLocks.get(deviceId).writeLock().unlock();
         }
     }
 
     @Override
     public boolean hasClient(DeviceId deviceId) {
 
-        deviceLocks.putIfAbsent(deviceId, new ReentrantLock());
-        deviceLocks.get(deviceId).lock();
+        deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
+        deviceLocks.get(deviceId).readLock().lock();
 
         try {
             return clients.containsKey(deviceId);
         } finally {
-            deviceLocks.get(deviceId).unlock();
+            deviceLocks.get(deviceId).readLock().unlock();
+        }
+    }
+
+    @Override
+    public boolean isReacheable(DeviceId deviceId) {
+
+        deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
+        deviceLocks.get(deviceId).readLock().lock();
+
+        try {
+            if (!clients.containsKey(deviceId)) {
+                log.warn("No client for {}, can't check for reachability", deviceId);
+                return false;
+            }
+
+            return grpcController.isChannelOpen(channelIds.get(deviceId));
+        } finally {
+            deviceLocks.get(deviceId).readLock().unlock();
         }
     }
 
diff --git a/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java b/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
index 1b3c459..ad48e1e 100644
--- a/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
+++ b/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
@@ -60,7 +60,9 @@
 import org.onosproject.net.driver.Driver;
 import org.onosproject.net.driver.DriverData;
 import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.pi.model.PiPipeconf;
 import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.model.PiPipelineProgrammable;
 import org.onosproject.net.pi.runtime.PiPipeconfConfig;
 import org.onosproject.net.pi.runtime.PiPipeconfService;
 import org.onosproject.net.provider.AbstractProvider;
@@ -72,7 +74,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentMap;
@@ -139,12 +140,12 @@
 
     protected ScheduledExecutorService connectionExecutor
             = newScheduledThreadPool(CORE_POOL_SIZE,
-            groupedThreads("onos/generaldeviceprovider-device",
-                    "connection-executor-%d", log));
+                                     groupedThreads("onos/generaldeviceprovider-device",
+                                                    "connection-executor-%d", log));
     protected ScheduledExecutorService portStatsExecutor
             = newScheduledThreadPool(CORE_POOL_SIZE,
-            groupedThreads("onos/generaldeviceprovider-port-stats",
-                    "port-stats-executor-%d", log));
+                                     groupedThreads("onos/generaldeviceprovider-port-stats",
+                                                    "port-stats-executor-%d", log));
 
     protected DeviceProviderService providerService;
     private InternalDeviceListener deviceListener = new InternalDeviceListener();
@@ -239,7 +240,7 @@
             modified.thenAcceptAsync(result -> {
                 if (!result) {
                     log.warn("Your device {} port {} status can't be changed to {}",
-                            deviceId, portNumber, enable);
+                             deviceId, portNumber, enable);
                 }
             });
 
@@ -251,13 +252,13 @@
     private DeviceHandshaker getHandshaker(DeviceId deviceId) {
         Driver driver = getDriver(deviceId);
         return getBehaviour(driver, DeviceHandshaker.class,
-                new DefaultDriverData(driver, deviceId));
+                            new DefaultDriverData(driver, deviceId));
     }
 
     private PortAdmin getPortAdmin(DeviceId deviceId) {
         Driver driver = getDriver(deviceId);
         return getBehaviour(driver, PortAdmin.class,
-                new DefaultDriverData(driver, deviceId));
+                            new DefaultDriverData(driver, deviceId));
 
     }
 
@@ -267,7 +268,7 @@
             driver = driverService.getDriver(deviceId);
         } catch (ItemNotFoundException e) {
             log.debug("Falling back to configuration to fetch driver " +
-                    "for device {}", deviceId);
+                              "for device {}", deviceId);
             driver = driverService.getDriver(
                     cfgService.getConfig(deviceId, BasicDeviceConfig.class).driver());
         }
@@ -298,7 +299,7 @@
 
         if (providerConfig == null || basicDeviceConfig == null) {
             log.error("Configuration is NULL: basic config {}, general provider " +
-                    "config {}", basicDeviceConfig, providerConfig);
+                              "config {}", basicDeviceConfig, providerConfig);
         } else {
             log.info("Connecting to device {} with driver {}", deviceId, basicDeviceConfig.driver());
 
@@ -310,7 +311,7 @@
 
             if (handshaker == null) {
                 log.error("Device {}, with driver {} does not support DeviceHandshaker " +
-                        "behaviour, {}", deviceId, driver.name(), driver.behaviours());
+                                  "behaviour, {}", deviceId, driver.name(), driver.behaviours());
                 return;
             }
             //Storing deviceKeyId and all other config values
@@ -333,13 +334,13 @@
                     ChassisId cid = new ChassisId();
                     SparseAnnotations annotations = DefaultAnnotations.builder()
                             .set(AnnotationKeys.PROTOCOL,
-                                    providerConfig.protocolsInfo().keySet().toString())
+                                 providerConfig.protocolsInfo().keySet().toString())
                             .build();
                     DeviceDescription description =
                             new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH,
-                                    driver.manufacturer(), driver.hwVersion(),
-                                    driver.swVersion(), UNKNOWN,
-                                    cid, false, annotations);
+                                                         driver.manufacturer(), driver.hwVersion(),
+                                                         driver.swVersion(), UNKNOWN,
+                                                         cid, false, annotations);
                     //Empty list of ports
                     List<PortDescription> ports = new ArrayList<>();
 
@@ -354,27 +355,15 @@
                         ports = deviceDiscovery.discoverPortDetails();
                     }
 
-                    Optional<PiPipeconfId> pipeconfId = piPipeconfService.ofDevice(deviceId);
-                    //Apply the Pipeline configuration and then connect the device
-                    if (pipeconfId.isPresent()) {
-                        DeviceDescription finalDescription = description;
-                        List<PortDescription> finalPorts = ports;
-                        piPipeconfService.bindToDevice(pipeconfId.get(), deviceId).whenComplete((success, ex) -> {
-                            if (success) {
-                                advertiseDevice(deviceId, finalDescription, finalPorts);
-                            } else {
-                                log.error("Can't merge driver {} with pipeconf {} for device {}, " +
-                                                "not reporting it to the device manager",
-                                        driver.name(), pipeconfId.get(), deviceId);
-                            }
-                        }).exceptionally(ex -> {
-                            throw new IllegalStateException(ex);
-                        });
-                    } else {
-                        //No other operation is needed, advertise the device to the core.
-                        advertiseDevice(deviceId, description, ports);
+                    if (!handlePipeconf(deviceId, driver, driverData)) {
+                        // Something went wrong during handling of pipeconf.
+                        // We already logged the error.
+                        handshaker.disconnect();
+                        return;
                     }
 
+                    advertiseDevice(deviceId, description, ports);
+
                 } else {
                     log.warn("Can't connect to device {}", deviceId);
                 }
@@ -382,6 +371,66 @@
         }
     }
 
+    /**
+     * Handles the case of a device that is pipeline programmable. Returns true if the operation wa successful and the
+     * device can be registered to the core, false otherwise.
+     */
+    private boolean handlePipeconf(DeviceId deviceId, Driver driver, DriverData driverData) {
+
+        PiPipelineProgrammable pipelineProg = getBehaviour(driver, PiPipelineProgrammable.class,
+                                                           driverData);
+
+        if (pipelineProg == null) {
+            // Device is not pipeline programmable.
+            return true;
+        }
+
+        PiPipeconfId pipeconfId = piPipeconfService.ofDevice(deviceId).orElseGet(() -> {
+            // No pipeconf has been associated with this device.
+            // Check if device driver provides a default one.
+            if (pipelineProg.getDefaultPipeconf().isPresent()) {
+                PiPipeconf defaultPipeconf = pipelineProg.getDefaultPipeconf().get();
+                log.info("Using default pipeconf {} for {}", defaultPipeconf.id(), deviceId);
+                // Register default one if it is not.
+                // TODO: this should be performed at driver loading.
+                if (!piPipeconfService.getPipeconf(defaultPipeconf.id()).isPresent()) {
+                    piPipeconfService.register(defaultPipeconf);
+                }
+                return defaultPipeconf.id();
+            } else {
+                return null;
+            }
+        });
+
+        if (pipeconfId == null) {
+            log.warn("Device {} is pipeline programmable but no pipeconf can be associated to it.", deviceId);
+            return true;
+        }
+
+
+        PiPipeconf pipeconf = piPipeconfService.getPipeconf(pipeconfId).orElseThrow(
+                () -> new IllegalStateException("Pipeconf is not registered: " + pipeconfId)
+        );
+
+
+        try {
+            if (!pipelineProg.deployPipeconf(pipeconf).get()) {
+                log.error("Unable to deploy pipeconf {} to {}, aborting device discovery", pipeconfId, deviceId);
+                return false;
+            }
+
+            if (!piPipeconfService.bindToDevice(pipeconfId, deviceId).get()) {
+                log.error("Unable to merge driver {} for device {} with pipeconf {}, aborting device discovery",
+                          driver.name(), deviceId, pipeconfId);
+                return false;
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            throw new IllegalStateException(e);
+        }
+
+        return true;
+    }
+
     private void advertiseDevice(DeviceId deviceId, DeviceDescription description, List<PortDescription> ports) {
         providerService.deviceConnected(deviceId, description);
         providerService.updatePorts(deviceId, ports);
@@ -454,7 +503,7 @@
                     //If we want to connect a p4runtime device with no pipeline
                     if (event.config().isPresent() &&
                             Collections.disjoint(ImmutableSet.copyOf(event.config().get().node().fieldNames()),
-                                    PIPELINE_CONFIGURABLE_PROTOCOLS)) {
+                                                 PIPELINE_CONFIGURABLE_PROTOCOLS)) {
                         pipelineConfigured.add(deviceId);
                     }
                     deviceConfigured.add(deviceId);
@@ -526,15 +575,15 @@
                 // be available we check and base it on the streaming API (e.g. gNMI)
                 if (deviceService.getDevice(event.subject().id()).
                         is(PortStatisticsDiscovery.class)) {
-                    portStatsExecutor.scheduleAtFixedRate(exceptionSafe(() ->
-                                    updatePortStatistics(event.subject().id())),
+                    portStatsExecutor.scheduleAtFixedRate(
+                            exceptionSafe(() -> updatePortStatistics(event.subject().id())),
                             0, PORT_STATS_PERIOD_SECONDS, TimeUnit.SECONDS);
                     updatePortStatistics(event.subject().id());
                 }
 
             } else if (type.equals(Type.DEVICE_REMOVED)) {
                 connectionExecutor.submit(exceptionSafe(() ->
-                        disconnectDevice(event.subject().id())));
+                                                                disconnectDevice(event.subject().id())));
             }
         }
 
diff --git a/tools/dev/mininet/bmv2.py b/tools/dev/mininet/bmv2.py
index e1d51a5..a0f92d2 100644
--- a/tools/dev/mininet/bmv2.py
+++ b/tools/dev/mininet/bmv2.py
@@ -79,9 +79,13 @@
                         "p4runtime": {
                             "ip": srcIP,
                             "port": self.grpcPort,
+                            "deviceId": self.deviceId,
                             "deviceKeyId": "p4runtime:%s" % onosDeviceId
                         }
                     },
+                    "piPipeconf": {
+                        "piPipeconfId": ""
+                    },
                     "basic": {
                         "driver": "bmv2"
                     }