Rejuvenate (to some extent) the basic pipeconf

- Use auto-generated BasicConstants
- Implement own pipeliner that maps to table0 (will remove soon
interpreter mapping for index table IDs)

Change-Id: I19fd2091605edc0efbe62134e1ad8e3336089cde
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicConstants.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicConstants.java
index 0a4e7d9..c36a77e 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicConstants.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicConstants.java
@@ -23,89 +23,78 @@
 import org.onosproject.net.pi.model.PiCounterId;
 import org.onosproject.net.pi.model.PiMatchFieldId;
 import org.onosproject.net.pi.model.PiTableId;
-
 /**
- * Constants for the basic.p4 program.
+ * Constants for basic pipeline.
  */
 public final class BasicConstants {
 
-    // TODO: constants could be auto-generated starting from the P4info.
-
-    public static final String DOT = ".";
-    private static final String INGRESS = "ingress";
-    public static final String EGRESS = "egress";
-    private static final String TABLE0_CTRL = INGRESS + DOT + "table0_control";
-    private static final String WCMP_CTRL = INGRESS + DOT + "wcmp_control";
-    private static final String PORT_COUNT_INGRESS_CTRL = INGRESS + DOT + "port_counters_ingress";
-    private static final String PORT_COUNT_EGRESS_CTRL = EGRESS + DOT + "port_counters_egress";
-    public static final String HDR = "hdr";
-    public static final String ETHERNET = "ethernet";
-    public static final String IPV4 = "ipv4";
-    public static final String LOCAL_METADATA = "local_metadata";
-    public static final String STANDARD_METADATA = "standard_metadata";
+    // hide default constructor
+    private BasicConstants() {
+    }
 
     // Header field IDs
-
-    public static final PiMatchFieldId HDR_IN_PORT_ID =
-            PiMatchFieldId.of(STANDARD_METADATA + DOT + "ingress_port");
-    public static final PiMatchFieldId HDR_ETH_DST_ID =
-            PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "dst_addr");
-    public static final PiMatchFieldId HDR_ETH_SRC_ID =
-            PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "src_addr");
-    public static final PiMatchFieldId HDR_ETH_TYPE_ID =
-            PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "ether_type");
-    public static final PiMatchFieldId HDR_IPV4_DST_ID =
-            PiMatchFieldId.of(HDR + DOT + IPV4 + DOT + "dst_addr");
-    public static final PiMatchFieldId HDR_IPV4_SRC_ID =
-            PiMatchFieldId.of(HDR + DOT + IPV4 + DOT + "src_addr");
-    public static final PiMatchFieldId HDR_NEXT_HOP_ID =
-            PiMatchFieldId.of(LOCAL_METADATA + DOT + "next_hop_id");
-    public static final PiMatchFieldId HDR_SELECTOR_ID =
-            PiMatchFieldId.of(LOCAL_METADATA + DOT + "selector");
+    public static final PiMatchFieldId HDR_HDR_IPV4_PROTOCOL =
+            PiMatchFieldId.of("hdr.ipv4.protocol");
+    public static final PiMatchFieldId HDR_HDR_IPV4_SRC_ADDR =
+            PiMatchFieldId.of("hdr.ipv4.src_addr");
+    public static final PiMatchFieldId HDR_HDR_ETHERNET_ETHER_TYPE =
+            PiMatchFieldId.of("hdr.ethernet.ether_type");
+    public static final PiMatchFieldId HDR_HDR_ETHERNET_SRC_ADDR =
+            PiMatchFieldId.of("hdr.ethernet.src_addr");
+    public static final PiMatchFieldId HDR_LOCAL_METADATA_L4_DST_PORT =
+            PiMatchFieldId.of("local_metadata.l4_dst_port");
+    public static final PiMatchFieldId HDR_LOCAL_METADATA_L4_SRC_PORT =
+            PiMatchFieldId.of("local_metadata.l4_src_port");
+    public static final PiMatchFieldId HDR_STANDARD_METADATA_INGRESS_PORT =
+            PiMatchFieldId.of("standard_metadata.ingress_port");
+    public static final PiMatchFieldId HDR_HDR_IPV4_DST_ADDR =
+            PiMatchFieldId.of("hdr.ipv4.dst_addr");
+    public static final PiMatchFieldId HDR_LOCAL_METADATA_NEXT_HOP_ID =
+            PiMatchFieldId.of("local_metadata.next_hop_id");
+    public static final PiMatchFieldId HDR_HDR_ETHERNET_DST_ADDR =
+            PiMatchFieldId.of("hdr.ethernet.dst_addr");
     // Table IDs
-    public static final PiTableId TBL_TABLE0_ID =
-            PiTableId.of(TABLE0_CTRL + DOT + "table0");
-    public static final PiTableId TBL_WCMP_TABLE_ID =
-            PiTableId.of(WCMP_CTRL + DOT + "wcmp_table");
-    // Counter IDs
-    public static final PiCounterId CNT_EGRESS_PORT_COUNTER_ID =
-            PiCounterId.of(PORT_COUNT_EGRESS_CTRL + DOT + "egress_port_counter");
-    public static final PiCounterId CNT_INGRESS_PORT_COUNTER_ID =
-            PiCounterId.of(PORT_COUNT_INGRESS_CTRL + DOT + "ingress_port_counter");
-    public static final PiCounterId CNT_TABLE0_ID =
-            PiCounterId.of(TABLE0_CTRL + DOT + "table0_counter");
-    public static final PiCounterId CNT_WCMP_TABLE_ID =
-            PiCounterId.of(WCMP_CTRL + DOT + "wcmp_table_counter");
+    public static final PiTableId INGRESS_WCMP_CONTROL_WCMP_TABLE =
+            PiTableId.of("ingress.wcmp_control.wcmp_table");
+    public static final PiTableId INGRESS_HOST_METER_CONTROL_HOST_METER_TABLE =
+            PiTableId.of("ingress.host_meter_control.host_meter_table");
+    public static final PiTableId INGRESS_TABLE0_CONTROL_TABLE0 =
+            PiTableId.of("ingress.table0_control.table0");
+    // Indirect Counter IDs
+    public static final PiCounterId EGRESS_PORT_COUNTERS_EGRESS_EGRESS_PORT_COUNTER =
+            PiCounterId.of("egress.port_counters_egress.egress_port_counter");
+    public static final PiCounterId INGRESS_PORT_COUNTERS_INGRESS_INGRESS_PORT_COUNTER =
+            PiCounterId.of("ingress.port_counters_ingress.ingress_port_counter");
+    // Direct Counter IDs
+    public static final PiCounterId INGRESS_WCMP_CONTROL_WCMP_TABLE_COUNTER =
+            PiCounterId.of("ingress.wcmp_control.wcmp_table_counter");
+    public static final PiCounterId INGRESS_TABLE0_CONTROL_TABLE0_COUNTER =
+            PiCounterId.of("ingress.table0_control.table0_counter");
     // Action IDs
-    public static final PiActionId ACT_NOACTION_ID =
-            PiActionId.of("NoAction");
-    public static final PiActionId ACT_DROP_ID =
-            PiActionId.of("_drop");
-    public static final PiActionId ACT_SET_EGRESS_PORT_TABLE0_ID =
-            PiActionId.of(TABLE0_CTRL + DOT + "set_egress_port");
-    public static final PiActionId ACT_SET_EGRESS_PORT_WCMP_ID =
-            PiActionId.of(WCMP_CTRL + DOT + "set_egress_port");
-    public static final PiActionId ACT_SET_NEXT_HOP_ID =
-            PiActionId.of(TABLE0_CTRL + DOT + "set_next_hop_id");
-    public static final PiActionId ACT_SEND_TO_CPU_ID =
-            PiActionId.of(TABLE0_CTRL + DOT + "send_to_cpu");
+    public static final PiActionId INGRESS_TABLE0_CONTROL_SEND_TO_CPU =
+            PiActionId.of("ingress.table0_control.send_to_cpu");
+    public static final PiActionId NO_ACTION = PiActionId.of("NoAction");
+    public static final PiActionId INGRESS_WCMP_CONTROL_SET_EGRESS_PORT =
+            PiActionId.of("ingress.wcmp_control.set_egress_port");
+    public static final PiActionId INGRESS_TABLE0_CONTROL_SET_NEXT_HOP_ID =
+            PiActionId.of("ingress.table0_control.set_next_hop_id");
+    public static final PiActionId INGRESS_TABLE0_CONTROL_SET_EGRESS_PORT =
+            PiActionId.of("ingress.table0_control.set_egress_port");
+    public static final PiActionId DROP = PiActionId.of("_drop");
+    public static final PiActionId INGRESS_HOST_METER_CONTROL_READ_METER =
+            PiActionId.of("ingress.host_meter_control.read_meter");
     // Action Param IDs
-    public static final PiActionParamId ACT_PRM_PORT_ID =
-            PiActionParamId.of("port");
-    public static final PiActionParamId ACT_PRM_NEXT_HOP_ID =
+    public static final PiActionParamId PORT = PiActionParamId.of("port");
+    public static final PiActionParamId NEXT_HOP_ID =
             PiActionParamId.of("next_hop_id");
     // Action Profile IDs
-    public static final PiActionProfileId ACT_PRF_WCMP_SELECTOR_ID =
-            PiActionProfileId.of(WCMP_CTRL + DOT + "wcmp_selector");
+    public static final PiActionProfileId INGRESS_WCMP_CONTROL_WCMP_SELECTOR =
+            PiActionProfileId.of("ingress.wcmp_control.wcmp_selector");
     // Packet Metadata IDs
-    public static final PiControlMetadataId PKT_META_EGRESS_PORT_ID =
-            PiControlMetadataId.of("egress_port");
-    public static final PiControlMetadataId PKT_META_INGRESS_PORT_ID =
+    public static final PiControlMetadataId PADDING =
+            PiControlMetadataId.of("_padding");
+    public static final PiControlMetadataId INGRESS_PORT =
             PiControlMetadataId.of("ingress_port");
-    // Bitwidths
-    public static final int PORT_BITWIDTH = 9;
-
-    private BasicConstants() {
-        // Hides constructor.
-    }
+    public static final PiControlMetadataId EGRESS_PORT =
+            PiControlMetadataId.of("egress_port");
 }
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java
index 15474f4..56a95fa 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java
@@ -32,10 +32,10 @@
 import org.onosproject.net.packet.DefaultInboundPacket;
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.pi.model.PiActionId;
 import org.onosproject.net.pi.model.PiMatchFieldId;
 import org.onosproject.net.pi.model.PiPipelineInterpreter;
 import org.onosproject.net.pi.model.PiTableId;
-import org.onosproject.net.pi.model.PiActionId;
 import org.onosproject.net.pi.runtime.PiAction;
 import org.onosproject.net.pi.runtime.PiActionParam;
 import org.onosproject.net.pi.runtime.PiControlMetadata;
@@ -54,23 +54,22 @@
 import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
 import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
-import static org.onosproject.pipelines.basic.BasicConstants.ACT_DROP_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.ACT_NOACTION_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.ACT_PRM_PORT_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.ACT_SEND_TO_CPU_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.ACT_SET_EGRESS_PORT_TABLE0_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.ACT_SET_EGRESS_PORT_WCMP_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.HDR_ETH_DST_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.HDR_ETH_SRC_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.HDR_ETH_TYPE_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.HDR_IN_PORT_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.HDR_IPV4_DST_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.HDR_IPV4_SRC_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.PKT_META_EGRESS_PORT_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.PKT_META_INGRESS_PORT_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.PORT_BITWIDTH;
-import static org.onosproject.pipelines.basic.BasicConstants.TBL_TABLE0_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.TBL_WCMP_TABLE_ID;
+import static org.onosproject.pipelines.basic.BasicConstants.DROP;
+import static org.onosproject.pipelines.basic.BasicConstants.EGRESS_PORT;
+import static org.onosproject.pipelines.basic.BasicConstants.HDR_HDR_ETHERNET_DST_ADDR;
+import static org.onosproject.pipelines.basic.BasicConstants.HDR_HDR_ETHERNET_ETHER_TYPE;
+import static org.onosproject.pipelines.basic.BasicConstants.HDR_HDR_ETHERNET_SRC_ADDR;
+import static org.onosproject.pipelines.basic.BasicConstants.HDR_HDR_IPV4_DST_ADDR;
+import static org.onosproject.pipelines.basic.BasicConstants.HDR_HDR_IPV4_SRC_ADDR;
+import static org.onosproject.pipelines.basic.BasicConstants.HDR_STANDARD_METADATA_INGRESS_PORT;
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_PORT;
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_TABLE0_CONTROL_SEND_TO_CPU;
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_TABLE0_CONTROL_SET_EGRESS_PORT;
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_TABLE0_CONTROL_TABLE0;
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_WCMP_CONTROL_SET_EGRESS_PORT;
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_WCMP_CONTROL_WCMP_TABLE;
+import static org.onosproject.pipelines.basic.BasicConstants.NO_ACTION;
+import static org.onosproject.pipelines.basic.BasicConstants.PORT;
 
 /**
  * Interpreter implementation for basic.p4.
@@ -78,27 +77,24 @@
 public class BasicInterpreterImpl extends AbstractHandlerBehaviour
         implements PiPipelineInterpreter {
 
-    private static final ImmutableBiMap<Integer, PiTableId> TABLE_MAP =
-            new ImmutableBiMap.Builder<Integer, PiTableId>()
-                    .put(0, TBL_TABLE0_ID)
-                    .build();
+    private static final int PORT_BITWIDTH = 9;
 
     private static final ImmutableBiMap<Criterion.Type, PiMatchFieldId> CRITERION_MAP =
             new ImmutableBiMap.Builder<Criterion.Type, PiMatchFieldId>()
-                    .put(Criterion.Type.IN_PORT, HDR_IN_PORT_ID)
-                    .put(Criterion.Type.ETH_DST, HDR_ETH_DST_ID)
-                    .put(Criterion.Type.ETH_SRC, HDR_ETH_SRC_ID)
-                    .put(Criterion.Type.ETH_TYPE, HDR_ETH_TYPE_ID)
-                    .put(Criterion.Type.IPV4_SRC, HDR_IPV4_SRC_ID)
-                    .put(Criterion.Type.IPV4_DST, HDR_IPV4_DST_ID)
+                    .put(Criterion.Type.IN_PORT, HDR_STANDARD_METADATA_INGRESS_PORT)
+                    .put(Criterion.Type.ETH_DST, HDR_HDR_ETHERNET_DST_ADDR)
+                    .put(Criterion.Type.ETH_SRC, HDR_HDR_ETHERNET_SRC_ADDR)
+                    .put(Criterion.Type.ETH_TYPE, HDR_HDR_ETHERNET_ETHER_TYPE)
+                    .put(Criterion.Type.IPV4_SRC, HDR_HDR_IPV4_SRC_ADDR)
+                    .put(Criterion.Type.IPV4_DST, HDR_HDR_IPV4_DST_ADDR)
                     .build();
 
     @Override
     public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId)
             throws PiInterpreterException {
-        if (treatment.allInstructions().size() == 0) {
+        if (treatment.allInstructions().isEmpty()) {
             // No actions means drop.
-            return PiAction.builder().withId(ACT_DROP_ID).build();
+            return PiAction.builder().withId(DROP).build();
         } else if (treatment.allInstructions().size() > 1) {
             // We understand treatments with only 1 instruction.
             throw new PiInterpreterException("Treatment has multiple instructions");
@@ -107,16 +103,16 @@
         Instruction instruction = treatment.allInstructions().get(0);
         switch (instruction.type()) {
             case OUTPUT:
-                if (piTableId == TBL_TABLE0_ID) {
-                    return outputPiAction((OutputInstruction) instruction, ACT_SET_EGRESS_PORT_TABLE0_ID);
-                } else if (piTableId == TBL_WCMP_TABLE_ID) {
-                    return outputPiAction((OutputInstruction) instruction, ACT_SET_EGRESS_PORT_WCMP_ID);
+                if (piTableId.equals(INGRESS_TABLE0_CONTROL_TABLE0)) {
+                    return outputPiAction((OutputInstruction) instruction, INGRESS_TABLE0_CONTROL_SET_EGRESS_PORT);
+                } else if (piTableId.equals(INGRESS_WCMP_CONTROL_WCMP_TABLE)) {
+                    return outputPiAction((OutputInstruction) instruction, INGRESS_WCMP_CONTROL_SET_EGRESS_PORT);
                 } else {
                     throw new PiInterpreterException(
                             "Output instruction not supported in table " + piTableId);
                 }
             case NOACTION:
-                return PiAction.builder().withId(ACT_NOACTION_ID).build();
+                return PiAction.builder().withId(NO_ACTION).build();
             default:
                 throw new PiInterpreterException(format(
                         "Instruction type '%s' not supported", instruction.type()));
@@ -127,17 +123,12 @@
             throws PiInterpreterException {
         PortNumber port = outInstruction.port();
         if (!port.isLogical()) {
-            try {
-                return PiAction.builder()
-                        .withId(piActionId)
-                        .withParameter(new PiActionParam(ACT_PRM_PORT_ID,
-                                                         copyFrom(port.toLong()).fit(PORT_BITWIDTH)))
-                        .build();
-            } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
-                throw new PiInterpreterException(e.getMessage());
-            }
+            return PiAction.builder()
+                    .withId(piActionId)
+                    .withParameter(new PiActionParam(PORT, port.toLong()))
+                    .build();
         } else if (port.equals(CONTROLLER)) {
-            return PiAction.builder().withId(ACT_SEND_TO_CPU_ID).build();
+            return PiAction.builder().withId(INGRESS_TABLE0_CONTROL_SEND_TO_CPU).build();
         } else {
             throw new PiInterpreterException(format(
                     "Egress on logical port '%s' not supported", port));
@@ -196,7 +187,7 @@
 
         // Returns the ingress port packet metadata.
         Optional<PiControlMetadata> packetMetadata = packetIn.metadatas()
-                .stream().filter(m -> m.id().equals(PKT_META_INGRESS_PORT_ID))
+                .stream().filter(m -> m.id().equals(INGRESS_PORT))
                 .findFirst();
 
         if (packetMetadata.isPresent()) {
@@ -208,7 +199,7 @@
         } else {
             throw new PiInterpreterException(format(
                     "Missing metadata '%s' in packet-in received from '%s': %s",
-                    PKT_META_INGRESS_PORT_ID, packetIn.deviceId(), packetIn));
+                    INGRESS_PORT, packetIn.deviceId(), packetIn));
         }
     }
 
@@ -226,7 +217,7 @@
     private PiControlMetadata createPacketMetadata(long portNumber) throws PiInterpreterException {
         try {
             return PiControlMetadata.builder()
-                    .withId(PKT_META_EGRESS_PORT_ID)
+                    .withId(EGRESS_PORT)
                     .withValue(copyFrom(portNumber).fit(PORT_BITWIDTH))
                     .build();
         } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
@@ -247,11 +238,11 @@
 
     @Override
     public Optional<PiTableId> mapFlowRuleTableId(int flowRuleTableId) {
-        return Optional.ofNullable(TABLE_MAP.get(flowRuleTableId));
+        return Optional.empty();
     }
 
     @Override
     public Optional<Integer> mapPiTableId(PiTableId piTableId) {
-        return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
+        return Optional.empty();
     }
 }
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicPipelinerImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicPipelinerImpl.java
new file mode 100644
index 0000000..9fc532b
--- /dev/null
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicPipelinerImpl.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2018-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.pipelines.basic;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.NextGroup;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_TABLE0_CONTROL_TABLE0;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Pipeliner implementation for basic.p4 that maps all forwarding objectives to
+ * table0. All other types of objectives are not supported.
+ */
+public class BasicPipelinerImpl extends AbstractHandlerBehaviour implements Pipeliner {
+
+    private final Logger log = getLogger(getClass());
+
+    private FlowRuleService flowRuleService;
+    private DeviceId deviceId;
+
+
+    @Override
+    public void init(DeviceId deviceId, PipelinerContext context) {
+        this.deviceId = deviceId;
+        this.flowRuleService = context.directory().get(FlowRuleService.class);
+
+    }
+
+    @Override
+    public void filter(FilteringObjective obj) {
+        obj.context().ifPresent(c -> c.onError(obj, ObjectiveError.UNSUPPORTED));
+    }
+
+    @Override
+    public void forward(ForwardingObjective obj) {
+        if (obj.treatment() == null) {
+            obj.context().ifPresent(c -> c.onError(obj, ObjectiveError.UNSUPPORTED));
+        }
+
+        // Simply create an equivalent FlowRule for table 0.
+        final FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .forTable(INGRESS_TABLE0_CONTROL_TABLE0)
+                .forDevice(deviceId)
+                .withSelector(obj.selector())
+                .fromApp(obj.appId())
+                .withPriority(obj.priority())
+                .withTreatment(obj.treatment());
+
+        if (obj.permanent()) {
+            ruleBuilder.makePermanent();
+        } else {
+            ruleBuilder.makeTemporary(obj.timeout());
+        }
+
+        switch (obj.op()) {
+            case ADD:
+                flowRuleService.applyFlowRules(ruleBuilder.build());
+                break;
+            case REMOVE:
+                flowRuleService.removeFlowRules(ruleBuilder.build());
+                break;
+            default:
+                log.warn("Unknown operation {}", obj.op());
+        }
+
+        obj.context().ifPresent(c -> c.onSuccess(obj));
+    }
+
+    @Override
+    public void next(NextObjective obj) {
+        obj.context().ifPresent(c -> c.onError(obj, ObjectiveError.UNSUPPORTED));
+    }
+
+    @Override
+    public List<String> getNextMappings(NextGroup nextGroup) {
+        // We do not use nextObjectives or groups.
+        return Collections.emptyList();
+    }
+}
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/EcmpConstants.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/EcmpConstants.java
deleted file mode 100644
index 1671d0a..0000000
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/EcmpConstants.java
+++ /dev/null
@@ -1,31 +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.pipelines.basic;
-
-import org.onosproject.net.pi.model.PiTableId;
-
-/**
- * Constants for the ecmp.p4 program.
- */
-public final class EcmpConstants {
-
-    public static final PiTableId TBL_ECMP_TABLE_ID = PiTableId.of("ecmp_table");
-
-    private EcmpConstants() {
-        // Hides constructor.
-    }
-}
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/EcmpInterpreterImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/EcmpInterpreterImpl.java
deleted file mode 100644
index d103cdb..0000000
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/EcmpInterpreterImpl.java
+++ /dev/null
@@ -1,46 +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.pipelines.basic;
-
-import com.google.common.collect.ImmutableBiMap;
-import org.onosproject.net.pi.model.PiTableId;
-
-import java.util.Optional;
-
-import static org.onosproject.pipelines.basic.BasicConstants.TBL_TABLE0_ID;
-import static org.onosproject.pipelines.basic.EcmpConstants.TBL_ECMP_TABLE_ID;
-
-/**
- * Interpreter implementation for ecmp.p4.
- */
-public class EcmpInterpreterImpl extends BasicInterpreterImpl {
-
-    private static final ImmutableBiMap<Integer, PiTableId> TABLE_MAP = new ImmutableBiMap.Builder<Integer, PiTableId>()
-            .put(0, TBL_TABLE0_ID)
-            .put(1, TBL_ECMP_TABLE_ID)
-            .build();
-
-    @Override
-    public Optional<Integer> mapPiTableId(PiTableId piTableId) {
-        return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
-    }
-
-    @Override
-    public Optional<PiTableId> mapFlowRuleTableId(int flowRuleTableId) {
-        return Optional.ofNullable(TABLE_MAP.get(flowRuleTableId));
-    }
-}
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntConstants.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntConstants.java
index 7dc6411..312a0b4 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntConstants.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntConstants.java
@@ -22,8 +22,6 @@
 import org.onosproject.net.pi.model.PiMatchFieldId;
 import org.onosproject.net.pi.model.PiTableId;
 
-import static org.onosproject.pipelines.basic.BasicConstants.*;
-
 /**
  * Constants for INT pipeline.
  */
@@ -33,6 +31,11 @@
     private IntConstants() {
     }
 
+    private static final String HDR = "hdr";
+    private static final String DOT = ".";
+    private static final String STANDARD_METADATA = "standard_metadata";
+    private static final String LOCAL_METADATA = "local_metadata";
+
     // Strings
     private static final String EGRESS = "egress";
     private static final String CTRL_SET_SOURCE_SINK = EGRESS + DOT + "process_set_source_sink";
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntProgrammableImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntProgrammableImpl.java
index 6a363f2..4f2cb1d 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntProgrammableImpl.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/IntProgrammableImpl.java
@@ -199,7 +199,7 @@
 
         // process_set_source_sink.tb_set_source for each host-facing port
         PiCriterion ingressCriterion = PiCriterion.builder()
-                .matchExact(BasicConstants.HDR_IN_PORT_ID, port.toLong())
+                .matchExact(BasicConstants.HDR_STANDARD_METADATA_INGRESS_PORT, port.toLong())
                 .build();
         TrafficSelector srcSelector = DefaultTrafficSelector.builder()
                 .matchPi(ingressCriterion)
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PipeconfLoader.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PipeconfLoader.java
index 90b5925..feb7359 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PipeconfLoader.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PipeconfLoader.java
@@ -23,7 +23,6 @@
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.onosproject.core.CoreService;
-import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
 import org.onosproject.inbandtelemetry.api.IntProgrammable;
 import org.onosproject.net.behaviour.Pipeliner;
 import org.onosproject.net.device.PortStatisticsDiscovery;
@@ -89,7 +88,7 @@
                 .withId(BASIC_PIPECONF_ID)
                 .withPipelineModel(parseP4Info(p4InfoUrl))
                 .addBehaviour(PiPipelineInterpreter.class, BasicInterpreterImpl.class)
-                .addBehaviour(Pipeliner.class, DefaultSingleTablePipeline.class)
+                .addBehaviour(Pipeliner.class, BasicPipelinerImpl.class)
                 .addBehaviour(PortStatisticsDiscovery.class, PortStatisticsDiscoveryImpl.class)
                 .addExtension(P4_INFO_TEXT, p4InfoUrl)
                 .addExtension(BMV2_JSON, jsonUrl)
@@ -108,7 +107,7 @@
                 .withId(INT_PIPECONF_ID)
                 .withPipelineModel(parseP4Info(p4InfoUrl))
                 .addBehaviour(PiPipelineInterpreter.class, BasicInterpreterImpl.class)
-                .addBehaviour(Pipeliner.class, DefaultSingleTablePipeline.class)
+                .addBehaviour(Pipeliner.class, BasicPipelinerImpl.class)
                 .addBehaviour(PortStatisticsDiscovery.class, PortStatisticsDiscoveryImpl.class)
                 .addBehaviour(IntProgrammable.class, IntProgrammableImpl.class)
                 .addExtension(P4_INFO_TEXT, p4InfoUrl)
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java
index 0e39230..0057293 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/PortStatisticsDiscoveryImpl.java
@@ -44,8 +44,8 @@
 import java.util.stream.Collectors;
 
 import static org.onosproject.net.pi.model.PiCounterType.INDIRECT;
-import static org.onosproject.pipelines.basic.BasicConstants.CNT_EGRESS_PORT_COUNTER_ID;
-import static org.onosproject.pipelines.basic.BasicConstants.CNT_INGRESS_PORT_COUNTER_ID;
+import static org.onosproject.pipelines.basic.BasicConstants.EGRESS_PORT_COUNTERS_EGRESS_EGRESS_PORT_COUNTER;
+import static org.onosproject.pipelines.basic.BasicConstants.INGRESS_PORT_COUNTERS_INGRESS_INGRESS_PORT_COUNTER;
 
 /**
  * Implementation of the PortStatisticsBehaviour for basic.p4.
@@ -63,7 +63,7 @@
      * @return counter ID
      */
     public PiCounterId ingressCounterId() {
-        return CNT_INGRESS_PORT_COUNTER_ID;
+        return INGRESS_PORT_COUNTERS_INGRESS_INGRESS_PORT_COUNTER;
     }
 
     /**
@@ -72,7 +72,7 @@
      * @return counter ID
      */
     public PiCounterId egressCounterId() {
-        return CNT_EGRESS_PORT_COUNTER_ID;
+        return EGRESS_PORT_COUNTERS_EGRESS_EGRESS_PORT_COUNTER;
     }
 
     @Override
diff --git a/pipelines/basic/src/main/resources/Makefile b/pipelines/basic/src/main/resources/Makefile
index ca8430b..2ea393e 100644
--- a/pipelines/basic/src/main/resources/Makefile
+++ b/pipelines/basic/src/main/resources/Makefile
@@ -1,4 +1,4 @@
-all: basic int
+all: basic int constants
 
 basic: basic.p4
 	p4c-bm2-ss --arch v1model -o p4c-out/bmv2/basic.json \
@@ -10,5 +10,10 @@
 		--p4runtime-file p4c-out/bmv2/int.p4info \
 		--p4runtime-format text int.p4
 
+constants:
+	onos-gen-p4-constants \
+		-o $(ONOS_ROOT)/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicConstants.java \
+		basic p4c-out/bmv2/basic.p4info
+
 clean:
 	rm -rf p4c-out/bmv2/*
diff --git a/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json b/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json
index f0efbe5..9d68d47 100644
--- a/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json
+++ b/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json
@@ -6,11 +6,11 @@
       "fields" : [
         ["tmp", 32, false],
         ["tmp_0", 32, false],
-        ["port_meters_ingress_ingress_color_0", 8, false],
-        ["host_meter_control_meter_tag_0", 8, false],
+        ["port_meters_ingress_ingress_color", 8, false],
+        ["host_meter_control_meter_tag", 8, false],
         ["tmp_1", 32, false],
         ["tmp_2", 32, false],
-        ["port_meters_egress_egress_color_0", 8, false],
+        ["port_meters_egress_egress_color", 8, false],
         ["local_metadata_t.l4_src_port", 16, false],
         ["local_metadata_t.l4_dst_port", 16, false],
         ["local_metadata_t.next_hop_id", 16, false]
@@ -459,7 +459,7 @@
       "type" : "bytes",
       "size" : 1024,
       "binding" : "ingress.host_meter_control.host_meter_table",
-      "result_target" : ["scalars", "host_meter_control_meter_tag_0"]
+      "result_target" : ["scalars", "host_meter_control_meter_tag"]
     },
     {
       "name" : "egress.port_meters_egress.egress_port_meter",
@@ -864,7 +864,7 @@
             },
             {
               "type" : "field",
-              "value" : ["scalars", "port_meters_ingress_ingress_color_0"]
+              "value" : ["scalars", "port_meters_ingress_ingress_color"]
             }
           ],
           "source_info" : {
@@ -927,7 +927,7 @@
           "parameters" : [
             {
               "type" : "field",
-              "value" : ["scalars", "host_meter_control_meter_tag_0"]
+              "value" : ["scalars", "host_meter_control_meter_tag"]
             },
             {
               "type" : "hexstr",
@@ -1078,7 +1078,7 @@
             },
             {
               "type" : "field",
-              "value" : ["scalars", "port_meters_egress_egress_color_0"]
+              "value" : ["scalars", "port_meters_egress_egress_color"]
             }
           ],
           "source_info" : {
@@ -1470,7 +1470,7 @@
               "op" : "==",
               "left" : {
                 "type" : "field",
-                "value" : ["scalars", "port_meters_ingress_ingress_color_0"]
+                "value" : ["scalars", "port_meters_ingress_ingress_color"]
               },
               "right" : {
                 "type" : "hexstr",
@@ -1522,7 +1522,7 @@
               "op" : "==",
               "left" : {
                 "type" : "field",
-                "value" : ["scalars", "host_meter_control_meter_tag_0"]
+                "value" : ["scalars", "host_meter_control_meter_tag"]
               },
               "right" : {
                 "type" : "hexstr",
@@ -1659,7 +1659,7 @@
               "op" : "==",
               "left" : {
                 "type" : "field",
-                "value" : ["scalars", "port_meters_egress_egress_color_0"]
+                "value" : ["scalars", "port_meters_egress_egress_color"]
               },
               "right" : {
                 "type" : "hexstr",
diff --git a/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.p4info b/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.p4info
index 4dc3701..a017ca2 100644
--- a/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.p4info
+++ b/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.p4info
@@ -73,7 +73,6 @@
   const_default_action_id: 16784184
   direct_resource_ids: 318816189
   size: 1024
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -95,7 +94,6 @@
   }
   direct_resource_ids: 352337889
   size: 1024
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -119,7 +117,6 @@
   implementation_id: 285253634
   direct_resource_ids: 318811794
   size: 1024
-  idle_timeout_behavior: NO_TIMEOUT
 }
 actions {
   preamble {
@@ -239,6 +236,28 @@
   }
   direct_table_id: 33594717
 }
+meters {
+  preamble {
+    id: 335581151
+    name: "ingress.port_meters_ingress.ingress_port_meter"
+    alias: "ingress_port_meter"
+  }
+  spec {
+    unit: BYTES
+  }
+  size: 511
+}
+meters {
+  preamble {
+    id: 335569641
+    name: "egress.port_meters_egress.egress_port_meter"
+    alias: "egress_port_meter"
+  }
+  spec {
+    unit: BYTES
+  }
+  size: 511
+}
 direct_meters {
   preamble {
     id: 352337889
diff --git a/pipelines/basic/src/main/resources/p4c-out/bmv2/int.p4info b/pipelines/basic/src/main/resources/p4c-out/bmv2/int.p4info
index 101e2bb..f280ea7 100644
--- a/pipelines/basic/src/main/resources/p4c-out/bmv2/int.p4info
+++ b/pipelines/basic/src/main/resources/p4c-out/bmv2/int.p4info
@@ -73,7 +73,6 @@
   const_default_action_id: 16784184
   direct_resource_ids: 318816189
   size: 1024
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -142,7 +141,6 @@
   }
   direct_resource_ids: 318829828
   size: 256
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -165,7 +163,6 @@
   }
   direct_resource_ids: 318811186
   size: 256
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -206,7 +203,6 @@
   }
   direct_resource_ids: 318796349
   size: 1024
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -223,7 +219,6 @@
   }
   direct_resource_ids: 318803385
   size: 2
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -291,7 +286,6 @@
   }
   direct_resource_ids: 318805102
   size: 16
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {
@@ -359,7 +353,6 @@
   }
   direct_resource_ids: 318775631
   size: 16
-  idle_timeout_behavior: NO_TIMEOUT
 }
 tables {
   preamble {