ONOS-7058 Refactored default pipeconfs in new pipelines directory

- Minimal refactoring of P4 programs
- Removed symlinks to BMv2 JSON/P4Info
- Bumped p4c commit (which fixes known parser bug)
- Renamed "default" pipeconf to "basic" (ONOS-6818)

Change-Id: I319f8b142ab22dba9b15457e28cd62d17f78a423
diff --git a/drivers/bmv2/BUCK b/drivers/bmv2/BUCK
index d9b09bb..c8224f5 100644
--- a/drivers/bmv2/BUCK
+++ b/drivers/bmv2/BUCK
@@ -9,6 +9,7 @@
     '//drivers/p4runtime:onos-drivers-p4runtime',
     '//incubator/grpc-dependencies:grpc-core-repkg-' + GRPC_VER,
     '//lib:grpc-netty-' + GRPC_VER,
+    '//pipelines/basic:onos-pipelines-basic',
 ]
 
 BUNDLES = [
@@ -29,5 +30,6 @@
     included_bundles = BUNDLES,
     required_apps = [
         'org.onosproject.drivers.p4runtime',
+        'org.onosproject.pipelines.basic',
     ],
 )
\ No newline at end of file
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
deleted file mode 100644
index 448da71..0000000
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * 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.onosproject.bmv2.model.Bmv2PipelineModelParser;
-import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
-import org.onosproject.drivers.p4runtime.DefaultP4Interpreter;
-import org.onosproject.drivers.p4runtime.DefaultP4PortStatisticsDiscovery;
-import org.onosproject.net.behaviour.Pipeliner;
-import org.onosproject.net.device.PortStatisticsDiscovery;
-import org.onosproject.net.pi.model.DefaultPiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconfId;
-import org.onosproject.net.pi.model.PiPipelineInterpreter;
-
-import java.net.URL;
-
-import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
-import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
-
-/**
- * Factory of pipeconf implementation for the default.p4 program on BMv2.
- */
-public final class Bmv2DefaultPipeconfFactory {
-
-    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 static final PiPipeconf PIPECONF = buildPipeconf();
-
-    private Bmv2DefaultPipeconfFactory() {
-        // Hides constructor.
-    }
-
-    public static PiPipeconf get() {
-        return PIPECONF;
-    }
-
-    private static PiPipeconf buildPipeconf() {
-
-        final URL jsonUrl = Bmv2DefaultPipeconfFactory.class.getResource(JSON_PATH);
-        final URL p4InfoUrl = Bmv2DefaultPipeconfFactory.class.getResource(P4INFO_PATH);
-        return DefaultPiPipeconf.builder()
-                .withId(new PiPipeconfId(PIPECONF_ID))
-                .withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
-                .addBehaviour(PiPipelineInterpreter.class, DefaultP4Interpreter.class)
-                .addBehaviour(Pipeliner.class, DefaultSingleTablePipeline.class)
-                .addBehaviour(PortStatisticsDiscovery.class, DefaultP4PortStatisticsDiscovery.class)
-                .addExtension(P4_INFO_TEXT, p4InfoUrl)
-                .addExtension(BMV2_JSON, jsonUrl)
-                .build();
-    }
-}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DriversLoader.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DriversLoader.java
index ff4f2d9..8ee87d4 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DriversLoader.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DriversLoader.java
@@ -17,10 +17,7 @@
 package org.onosproject.drivers.bmv2;
 
 import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onosproject.net.driver.AbstractDriverLoader;
-import org.onosproject.net.pi.runtime.PiPipeconfService;
 
 /**
  * Loader for P4Runtime device drivers.
@@ -28,22 +25,7 @@
 @Component(immediate = true)
 public class Bmv2DriversLoader extends AbstractDriverLoader {
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected PiPipeconfService pipeconfService;
-
     public Bmv2DriversLoader() {
         super("/bmv2-drivers.xml");
     }
-
-    @Override
-    public void activate() {
-        pipeconfService.register(Bmv2DefaultPipeconfFactory.get());
-        super.activate();
-    }
-
-    @Override
-    public void deactivate() {
-        pipeconfService.remove(Bmv2DefaultPipeconfFactory.get().id());
-        super.deactivate();
-    }
 }
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
index 0eef5ed..bf88238 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PipelineProgrammable.java
@@ -23,6 +23,7 @@
 import org.onosproject.net.pi.model.PiPipelineProgrammable;
 import org.onosproject.p4runtime.api.P4RuntimeClient;
 import org.onosproject.p4runtime.api.P4RuntimeController;
+import org.onosproject.pipelines.basic.PipeconfLoader;
 import org.slf4j.Logger;
 
 import java.util.Optional;
@@ -37,8 +38,6 @@
  */
 public class Bmv2PipelineProgrammable extends AbstractHandlerBehaviour implements PiPipelineProgrammable {
 
-    private static final PiPipeconf DEFAULT_PIPECONF = Bmv2DefaultPipeconfFactory.get();
-
     private final Logger log = getLogger(getClass());
 
     @Override
@@ -87,6 +86,6 @@
 
     @Override
     public Optional<PiPipeconf> getDefaultPipeconf() {
-        return Optional.of(DEFAULT_PIPECONF);
+        return Optional.of(PipeconfLoader.BASIC_PIPECONF);
     }
 }
diff --git a/drivers/bmv2/src/main/resources/default.json b/drivers/bmv2/src/main/resources/default.json
deleted file mode 120000
index c5028d8..0000000
--- a/drivers/bmv2/src/main/resources/default.json
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../tools/test/p4src/p4-16/p4c-out/default.json
\ No newline at end of file
diff --git a/drivers/bmv2/src/main/resources/default.p4info b/drivers/bmv2/src/main/resources/default.p4info
deleted file mode 120000
index 8f71cbe..0000000
--- a/drivers/bmv2/src/main/resources/default.p4info
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../tools/test/p4src/p4-16/p4c-out/default.p4info
\ No newline at end of file
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
deleted file mode 100644
index f716a63..0000000
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * 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.p4runtime;
-
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableList;
-import org.onlab.packet.DeserializationException;
-import org.onlab.packet.Ethernet;
-import org.onlab.util.ImmutableByteSequence;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
-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.flow.instructions.PiInstruction;
-import org.onosproject.net.packet.DefaultInboundPacket;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.OutboundPacket;
-import org.onosproject.net.pi.model.PiHeaderFieldModel;
-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 org.onosproject.net.pi.model.PiTableModel;
-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.PiCounterId;
-import org.onosproject.net.pi.runtime.PiCounterType;
-import org.onosproject.net.pi.runtime.PiHeaderFieldId;
-import org.onosproject.net.pi.runtime.PiPacketMetadata;
-import org.onosproject.net.pi.runtime.PiPacketMetadataId;
-import org.onosproject.net.pi.runtime.PiPacketOperation;
-import org.onosproject.net.pi.runtime.PiPipeconfService;
-import org.onosproject.net.pi.runtime.PiTableId;
-
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-
-import static java.lang.String.format;
-import static java.util.stream.Collectors.toList;
-import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
-import static org.onosproject.net.PortNumber.CONTROLLER;
-import static org.onosproject.net.PortNumber.FLOOD;
-import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
-import static org.onosproject.net.pi.runtime.PiPacketOperation.Type.PACKET_OUT;
-
-/**
- * Implementation of an interpreter that can be used for any P4 program based on default.p4 (i.e. those under
- * onos/tools/test/p4src).
- */
-public class DefaultP4Interpreter extends AbstractHandlerBehaviour implements PiPipelineInterpreter {
-
-    // FIXME: Should move this class out of the p4runtime drivers.
-    // e.g. in a dedicated onos/pipeconf directory, along with any related P4 source code.
-
-    public static final String TABLE0 = "table0";
-    public static final String TABLE0_COUNTER = "table0_counter";
-    public static final String ECMP = "ecmp";
-    public static final String SEND_TO_CPU = "send_to_cpu";
-    public static final String PORT = "port";
-    public static final String DROP = "_drop";
-    public static final String SET_EGRESS_PORT = "set_egress_port";
-    public static final String EGRESS_PORT = "egress_port";
-    public static final String INGRESS_PORT = "ingress_port";
-
-    private static final PiTableId TABLE0_ID = PiTableId.of(TABLE0);
-    private static final PiTableId ECMP_ID = PiTableId.of(ECMP);
-
-    protected static final PiHeaderFieldId ETH_DST_ID = PiHeaderFieldId.of("ethernet", "dstAddr");
-    protected static final PiHeaderFieldId ETH_SRC_ID = PiHeaderFieldId.of("ethernet", "srcAddr");
-    protected static final PiHeaderFieldId ETH_TYPE_ID = PiHeaderFieldId.of("ethernet", "etherType");
-
-    private static final ImmutableBiMap<Integer, PiTableId> TABLE_MAP = ImmutableBiMap.of(
-            0, TABLE0_ID,
-            1, ECMP_ID);
-
-    private static final ImmutableBiMap<PiTableId, PiCounterId> TABLE_COUNTER_MAP = ImmutableBiMap.of(
-            TABLE0_ID, PiCounterId.of(TABLE0_COUNTER, PiCounterType.DIRECT));
-
-    private boolean targetAttributesInitialized = false;
-
-    /*
-    The following attributes are target-specific, i.e. they might change from one target to another.
-     */
-    private ImmutableBiMap<Criterion.Type, PiHeaderFieldId> criterionMap;
-    private int portFieldBitWidth;
-
-    /**
-     * Populates target-specific attributes based on this device's pipeline model.
-     */
-    private synchronized void initTargetSpecificAttributes() {
-        if (targetAttributesInitialized) {
-            return;
-        }
-
-        DeviceId deviceId = this.handler().data().deviceId();
-        PiPipeconfService pipeconfService = this.handler().get(PiPipeconfService.class);
-        PiPipeconfId pipeconfId = pipeconfService.ofDevice(deviceId)
-                .orElseThrow(() -> new RuntimeException(format(
-                        "Unable to get current pipeconf for device %s", this.data().deviceId())));
-        PiPipeconf pipeconf = pipeconfService.getPipeconf(pipeconfId)
-                .orElseThrow(() -> new RuntimeException(format(
-                        "Pipeconf %s is not registered", pipeconfId)));
-        PiPipelineModel model = pipeconf.pipelineModel();
-
-        this.portFieldBitWidth = extractPortFieldBitWidth(model);
-        this.criterionMap = new ImmutableBiMap.Builder<Criterion.Type, PiHeaderFieldId>()
-                .put(Criterion.Type.IN_PORT, extractInPortFieldId(model))
-                .put(Criterion.Type.ETH_DST, ETH_DST_ID)
-                .put(Criterion.Type.ETH_SRC, ETH_SRC_ID)
-                .put(Criterion.Type.ETH_TYPE, ETH_TYPE_ID)
-                .build();
-
-        this.targetAttributesInitialized = true;
-    }
-
-    private static PiHeaderFieldId extractInPortFieldId(PiPipelineModel model) {
-        /*
-        For the targets we currently support, the field name is "ingress_port", but we miss the header name, which is
-        target-specific. We know table0 defines that field as a match key, we look for it and we get the header name.
-         */
-        PiTableModel tableModel = model.table(TABLE0).orElseThrow(() -> new RuntimeException(format(
-                "No such table '%s' in pipeline model", TABLE0)));
-        PiHeaderFieldModel fieldModel = tableModel.matchFields().stream()
-                .filter(m -> m.field().type().name().equals(INGRESS_PORT))
-                .findFirst()
-                .orElseThrow(() -> new RuntimeException(format(
-                        "No such match field in table '%s' with name '%s'", TABLE0, INGRESS_PORT)))
-                .field();
-        return PiHeaderFieldId.of(fieldModel.header().name(), INGRESS_PORT);
-    }
-
-    private static int extractPortFieldBitWidth(PiPipelineModel model) {
-        /*
-        Get it form the set_egress_port action parameters.
-         */
-        return model
-                .action(SET_EGRESS_PORT).orElseThrow(() -> new RuntimeException(format(
-                        "No such action '%s' in pipeline model", SET_EGRESS_PORT)))
-                .param(PORT).orElseThrow(() -> new RuntimeException(format(
-                        "No such parameter '%s' of action '%s' in pipeline model", PORT, SET_EGRESS_PORT)))
-                .bitWidth();
-    }
-
-
-    @Override
-    public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId) throws PiInterpreterException {
-        initTargetSpecificAttributes();
-        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;
-                return outputPiAction(outInstruction);
-            case PROTOCOL_INDEPENDENT:
-                PiInstruction piInstruction = (PiInstruction) instruction;
-                return (PiAction) piInstruction.action();
-            case NOACTION:
-                return actionWithName(DROP);
-            default:
-                throw new PiInterpreterException(format("Instruction type '%s' not supported", instruction.type()));
-        }
-    }
-
-    private PiAction outputPiAction(Instructions.OutputInstruction outInstruction) throws PiInterpreterException {
-        PortNumber port = outInstruction.port();
-        if (!port.isLogical()) {
-            try {
-                return PiAction.builder()
-                        .withId(PiActionId.of(SET_EGRESS_PORT))
-                        .withParameter(new PiActionParam(PiActionParamId.of(PORT),
-                                                         fit(copyFrom(port.toLong()), portFieldBitWidth)))
-                        .build();
-            } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
-                throw new PiInterpreterException(e.getMessage());
-            }
-        } else if (port.equals(CONTROLLER)) {
-            return actionWithName(SEND_TO_CPU);
-        } else {
-            throw new PiInterpreterException(format("Egress on logical port '%s' not supported", port));
-        }
-    }
-
-    @Override
-    public Optional<PiCounterId> mapTableCounter(PiTableId piTableId) {
-        return Optional.ofNullable(TABLE_COUNTER_MAP.get(piTableId));
-    }
-
-    @Override
-    public Collection<PiPacketOperation> mapOutboundPacket(OutboundPacket packet)
-            throws PiInterpreterException {
-        TrafficTreatment treatment = packet.treatment();
-
-        // default.p4 supports only OUTPUT instructions.
-        List<Instructions.OutputInstruction> outInstructions = treatment.allInstructions()
-                .stream()
-                .filter(i -> i.type().equals(OUTPUT))
-                .map(i -> (Instructions.OutputInstruction) i)
-                .collect(toList());
-
-        if (treatment.allInstructions().size() != outInstructions.size()) {
-            // There are other instructions that are not of type OUTPUT.
-            throw new PiInterpreterException("Treatment not supported: " + treatment);
-        }
-
-        ImmutableList.Builder<PiPacketOperation> builder = ImmutableList.builder();
-        for (Instructions.OutputInstruction outInst : outInstructions) {
-            if (outInst.port().isLogical() && !outInst.port().equals(FLOOD)) {
-                throw new PiInterpreterException(format("Output on logical port '%s' not supported", outInst.port()));
-            } else if (outInst.port().equals(FLOOD)) {
-                // Since default.p4 does not support flooding, we create a packet operation for each switch port.
-                for (Port port : handler().get(DeviceService.class).getPorts(packet.sendThrough())) {
-                    builder.add(createPiPacketOperation(packet.data(), port.number().toLong()));
-                }
-            } else {
-                builder.add(createPiPacketOperation(packet.data(), outInst.port().toLong()));
-            }
-        }
-        return builder.build();
-    }
-
-    @Override
-    public InboundPacket mapInboundPacket(DeviceId deviceId, PiPacketOperation packetIn)
-            throws PiInterpreterException {
-        // Assuming that the packet is ethernet, which is fine since default.p4 can deparse only ethernet packets.
-        Ethernet ethPkt;
-        try {
-            ethPkt = Ethernet.deserializer().deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
-        } catch (DeserializationException dex) {
-            throw new PiInterpreterException(dex.getMessage());
-        }
-
-        // Returns the ingress port packet metadata.
-        Optional<PiPacketMetadata> packetMetadata = packetIn.metadatas()
-                .stream().filter(metadata -> metadata.id().name().equals(INGRESS_PORT))
-                .findFirst();
-
-        if (packetMetadata.isPresent()) {
-            ImmutableByteSequence portByteSequence = packetMetadata.get().value();
-            short s = portByteSequence.asReadOnlyBuffer().getShort();
-            ConnectPoint receivedFrom = new ConnectPoint(deviceId, PortNumber.portNumber(s));
-            ByteBuffer rawData = ByteBuffer.wrap(packetIn.data().asArray());
-            return new DefaultInboundPacket(receivedFrom, ethPkt, rawData);
-        } else {
-            throw new PiInterpreterException(format(
-                    "Missing metadata '%s' in packet-in received from '%s': %s", INGRESS_PORT, deviceId, packetIn));
-        }
-    }
-
-    private PiPacketOperation createPiPacketOperation(ByteBuffer data, long portNumber) throws PiInterpreterException {
-        PiPacketMetadata metadata = createPacketMetadata(portNumber);
-        return PiPacketOperation.builder()
-                .withType(PACKET_OUT)
-                .withData(copyFrom(data))
-                .withMetadatas(ImmutableList.of(metadata))
-                .build();
-    }
-
-    private PiPacketMetadata createPacketMetadata(long portNumber) throws PiInterpreterException {
-        initTargetSpecificAttributes();
-        try {
-            return PiPacketMetadata.builder()
-                    .withId(PiPacketMetadataId.of(EGRESS_PORT))
-                    .withValue(fit(copyFrom(portNumber), portFieldBitWidth))
-                    .build();
-        } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
-            throw new PiInterpreterException(format("Port number %d too big, %s", portNumber, e.getMessage()));
-        }
-    }
-
-    /**
-     * 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) {
-        initTargetSpecificAttributes();
-        return Optional.ofNullable(criterionMap.get(type));
-    }
-
-    @Override
-    public Optional<Criterion.Type> mapPiHeaderFieldId(PiHeaderFieldId headerFieldId) {
-        initTargetSpecificAttributes();
-        return Optional.ofNullable(criterionMap.inverse().get(headerFieldId));
-    }
-
-    @Override
-    public Optional<PiTableId> mapFlowRuleTableId(int flowRuleTableId) {
-        return Optional.ofNullable(TABLE_MAP.get(flowRuleTableId));
-    }
-
-    @Override
-    public Optional<Integer> mapPiTableId(PiTableId piTableId) {
-        return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
-    }
-}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
deleted file mode 100644
index b2b3760..0000000
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * 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.p4runtime;
-
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.onosproject.net.device.DefaultPortStatistics;
-import org.onosproject.net.device.PortStatistics;
-import org.onosproject.net.device.PortStatisticsDiscovery;
-import org.onosproject.net.pi.runtime.PiCounterCellData;
-import org.onosproject.net.pi.runtime.PiCounterCellId;
-import org.onosproject.net.pi.runtime.PiCounterId;
-import org.onosproject.net.pi.runtime.PiIndirectCounterCellId;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.stream.Collectors;
-
-import static org.onosproject.net.pi.runtime.PiCounterType.INDIRECT;
-
-/**
- * Implementation of a PortStatisticsBehaviour that can be used for any P4 program based on default.p4 (i.e. those
- * under onos/tools/test/p4src).
- */
-public class DefaultP4PortStatisticsDiscovery extends AbstractP4RuntimeHandlerBehaviour
-        implements PortStatisticsDiscovery {
-
-    // FIXME: hard-coding the scope here will break support for the P4_14 version of the program.
-    // With P4_14, counter names in the generated P4Info won't have any scope.
-    // A solution could be that of dynamically building counter IDs based on the P4Info (as in DefaultP4Interpreter).
-    private static final String DEFAULT_SCOPE = "port_counters_control";
-    private static final PiCounterId DEFAULT_INGRESS_COUNTER_ID = PiCounterId.of(DEFAULT_SCOPE,
-                                                                                 "ingress_port_counter",
-                                                                                 INDIRECT);
-    private static final PiCounterId DEFAULT_EGRESS_COUNTER_ID = PiCounterId.of(DEFAULT_SCOPE,
-                                                                                "egress_port_counter",
-                                                                                INDIRECT);
-
-    /**
-     * Returns the ID of the ingress port counter.
-     *
-     * @return counter ID
-     */
-    public PiCounterId ingressCounterId() {
-        return DEFAULT_INGRESS_COUNTER_ID;
-    }
-
-    /**
-     * Returns the ID of the egress port counter.
-     *
-     * @return counter ID
-     */
-    public PiCounterId egressCounterId() {
-        return DEFAULT_EGRESS_COUNTER_ID;
-    }
-
-    @Override
-    public Collection<PortStatistics> discoverPortStatistics() {
-
-        if (!super.setupBehaviour()) {
-            return Collections.emptyList();
-        }
-
-        Map<Long, DefaultPortStatistics.Builder> portStatBuilders = Maps.newHashMap();
-
-        deviceService.getPorts(deviceId)
-                .forEach(p -> portStatBuilders.put(p.number().toLong(),
-                                                   DefaultPortStatistics.builder()
-                                                           .setPort(p.number())
-                                                           .setDeviceId(deviceId)));
-
-        Set<PiCounterCellId> counterCellIds = Sets.newHashSet();
-        portStatBuilders.keySet().forEach(p -> {
-            // Counter cell/index = port number.
-            counterCellIds.add(PiIndirectCounterCellId.of(ingressCounterId(), p));
-            counterCellIds.add(PiIndirectCounterCellId.of(egressCounterId(), p));
-        });
-
-        Collection<PiCounterCellData> counterEntryResponse;
-        try {
-            counterEntryResponse = client.readCounterCells(counterCellIds, pipeconf).get();
-        } catch (InterruptedException | ExecutionException e) {
-            log.warn("Exception while reading port counters from {}: {}", deviceId, e.toString());
-            log.debug("", e);
-            return Collections.emptyList();
-        }
-
-        counterEntryResponse.forEach(counterData -> {
-            if (counterData.cellId().type() != INDIRECT) {
-                log.warn("Invalid counter data type {}, skipping", counterData.cellId().type());
-                return;
-            }
-            PiIndirectCounterCellId indCellId = (PiIndirectCounterCellId) counterData.cellId();
-            if (!portStatBuilders.containsKey(indCellId.index())) {
-                log.warn("Unrecognized counter index {}, skipping", counterData);
-                return;
-            }
-            DefaultPortStatistics.Builder statsBuilder = portStatBuilders.get(indCellId.index());
-            if (counterData.cellId().counterId().equals(ingressCounterId())) {
-                statsBuilder.setPacketsReceived(counterData.packets());
-                statsBuilder.setBytesReceived(counterData.bytes());
-            } else if (counterData.cellId().counterId().equals(egressCounterId())) {
-                statsBuilder.setPacketsSent(counterData.packets());
-                statsBuilder.setBytesSent(counterData.bytes());
-            } else {
-                log.warn("Unrecognized counter ID {}, skipping", counterData);
-            }
-        });
-
-        return portStatBuilders
-                .values()
-                .stream()
-                .map(DefaultPortStatistics.Builder::build)
-                .collect(Collectors.toList());
-    }
-}