ONOS-6464 interfaces for protocol-independence (PI)

And also ONOS-6553, implementation of table entry classes

Change-Id: Ia7146b1bb0aac794e19b3fd8150c042e7ec70535
diff --git a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java
index a8aba57..f4ea830 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java
@@ -21,7 +21,7 @@
  */
 public interface Criterion {
 
-    static final String SEPARATOR = ":";
+    String SEPARATOR = ":";
 
     /**
      * Types of fields to which the selection criterion may apply.
@@ -217,6 +217,9 @@
         /** ODU (Optical channel Data Unit) signal type. */
         ODU_SIGTYPE,
 
+        /** Protocol-independent. */
+        PROTOCOL_INDEPENDENT,
+
         /** Extension criterion. */
         EXTENSION,
 
diff --git a/core/api/src/main/java/org/onosproject/net/flow/criteria/PiCriterion.java b/core/api/src/main/java/org/onosproject/net/flow/criteria/PiCriterion.java
new file mode 100644
index 0000000..ab05f26
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/criteria/PiCriterion.java
@@ -0,0 +1,80 @@
+/*
+ * 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.flow.criteria;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onosproject.net.pi.runtime.PiFieldMatch;
+
+import java.util.Collection;
+import java.util.StringJoiner;
+
+/**
+ * Protocol-indepedent criterion.
+ */
+@Beta
+public final class PiCriterion implements Criterion {
+
+    private final Collection<PiFieldMatch> fieldMatches;
+
+    /**
+     * Creates a new protocol-independent criterion for the given match fields.
+     *
+     * @param fieldMatches fields to match
+     */
+    PiCriterion(Collection<PiFieldMatch> fieldMatches) {
+        this.fieldMatches = fieldMatches;
+    }
+
+    /**
+     * Returns the match parameters map of this selector.
+     *
+     * @return a match parameter map
+     */
+    public Collection<PiFieldMatch> fieldMatches() {
+        return fieldMatches;
+    }
+
+    @Override
+    public Type type() {
+        return Type.PROTOCOL_INDEPENDENT;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiCriterion that = (PiCriterion) o;
+        return Objects.equal(fieldMatches, that.fieldMatches);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(fieldMatches);
+    }
+
+    @Override
+    public String toString() {
+        StringJoiner stringParams = new StringJoiner(", ", "{", "}");
+        fieldMatches.forEach(f -> stringParams.add(f.toString()));
+        return stringParams.toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
index 5c0353a..1aeb1d2 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
@@ -89,6 +89,11 @@
         L4MODIFICATION,
 
         /**
+         * Signifies that a protocol-independent instruction will be used.
+         */
+        PROTOCOL_INDEPENDENT,
+
+        /**
          * Signifies that an extension instruction will be used.
          */
         EXTENSION
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/PiInstruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/PiInstruction.java
new file mode 100644
index 0000000..da6230a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/PiInstruction.java
@@ -0,0 +1,76 @@
+/*
+ * 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.flow.instructions;
+
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onosproject.net.pi.runtime.PiTableAction;
+
+/**
+ * Representation of a protocol-independent instruction.
+ */
+@Beta
+public final class PiInstruction implements Instruction {
+
+    private final PiTableAction tableAction;
+
+    /**
+     * Creates a new instruction with the given protocol-independent table action.
+     *
+     * @param tableAction a protocol-independent action
+     */
+    PiInstruction(PiTableAction tableAction) {
+        this.tableAction = tableAction;
+    }
+
+    /**
+     * Returns the protocol-independent table action defined by this instruction.
+     *
+     * @return an action
+     */
+    public PiTableAction action() {
+        return tableAction;
+    }
+
+    @Override
+    public Type type() {
+        return Type.PROTOCOL_INDEPENDENT;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiInstruction that = (PiInstruction) o;
+        return Objects.equal(tableAction, that.tableAction);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(tableAction);
+    }
+
+    @Override
+    public String toString() {
+        return tableAction.toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiActionModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiActionModel.java
new file mode 100644
index 0000000..775c3d8
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiActionModel.java
@@ -0,0 +1,51 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Model of an action with runtime parameters in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiActionModel {
+    /**
+     * Returns the name of this action.
+     *
+     * @return a string value
+     */
+    String name();
+
+    /**
+     * Returns the model of this action's parameter defined by the given name, if present.
+     *
+     * @param name action name
+     * @return action parameter model
+     */
+    Optional<PiActionParamModel> param(String name);
+
+    /**
+     * Returns the list of action parameter models, ordered according to the same action parameters
+     * defined in the pipeline model.
+     *
+     * @return list of action parameter models
+     */
+    List<PiActionParamModel> params();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiActionParamModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiActionParamModel.java
new file mode 100644
index 0000000..ff6d4de
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiActionParamModel.java
@@ -0,0 +1,39 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Model of an action parameter in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiActionParamModel {
+    /**
+     * Returns the name of this action parameter.
+     *
+     * @return a string value
+     */
+    String name();
+
+    /**
+     * Return the bit width of this action parameter.
+     *
+     * @return an integer value
+     */
+    int bitWidth();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderFieldModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderFieldModel.java
new file mode 100644
index 0000000..c52a71d
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderFieldModel.java
@@ -0,0 +1,39 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Model of a header's field instance in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiHeaderFieldModel {
+    /**
+     * Returns the header instance of this field instance.
+     *
+     * @return a header instance
+     */
+    PiHeaderModel header();
+
+    /**
+     * Returns the type of this header's field instance.
+     *
+     * @return a field type value
+     */
+    PiHeaderFieldTypeModel type();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderFieldTypeModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderFieldTypeModel.java
new file mode 100644
index 0000000..0a3854e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderFieldTypeModel.java
@@ -0,0 +1,39 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Model of a header's field type in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiHeaderFieldTypeModel {
+    /**
+     * Returns the name of this header type field.
+     *
+     * @return a string value
+     */
+    String name();
+
+    /**
+     * Returns the bit width of this header type field.
+     *
+     * @return an integer value
+     */
+    int bitWidth();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderModel.java
new file mode 100644
index 0000000..28148c1
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderModel.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Model of a header instance in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiHeaderModel {
+    /**
+     * Returns the type of this header instance.
+     *
+     * @return a header type value
+     */
+    PiHeaderTypeModel type();
+
+    /**
+     * Returns true if this header instance is a metadata, false elsewhere.
+     *
+     * @return a boolean value
+     */
+    boolean isMetadata();
+
+    /**
+     * Returns the index of this header w.r.t. to other headers of the same type.
+     * Index 0 points to the first instance of the header, 1 the second one, etc.
+     * Helpful when dealing with stacked headers. e.g. to match on the second MPLS label.
+     *
+     * @return a non-negative integer value
+     */
+    default int index() {
+        return 0;
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderTypeModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderTypeModel.java
new file mode 100644
index 0000000..d35f78a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiHeaderTypeModel.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Model of a header type in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiHeaderTypeModel {
+
+    /**
+     * Returns the name of this header type.
+     *
+     * @return name
+     */
+    String name();
+
+    /**
+     * Returns the field type model defined by the given name, if present.
+     *
+     * @param fieldName field name
+     * @return optional field type model
+     */
+    Optional<PiHeaderFieldTypeModel> field(String fieldName);
+
+    /**
+     * Returns a list of field type models for this header type, ordered according to the same
+     * order of header fields as defined in the pipeline model.
+     *
+     * @return list of field type models
+     */
+    List<PiHeaderFieldTypeModel> fields();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiMatchType.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiMatchType.java
new file mode 100644
index 0000000..d88852b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiMatchType.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Match types in a protocol-independent pipeline.
+ */
+@Beta
+public enum PiMatchType {
+    /**
+     * Exact match type.
+     */
+    EXACT,
+    /**
+     * Ternary match type.
+     */
+    TERNARY,
+    /**
+     * Longest-prefix match type.
+     */
+    LPM,
+    /**
+     * Valid match type.
+     */
+    VALID,
+    /**
+     * Range match type.
+     */
+    RANGE
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
new file mode 100644
index 0000000..385c490
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
@@ -0,0 +1,95 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import org.onosproject.net.driver.Behaviour;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Configuration of a protocol-independent pipeline that includes a pipeline model, a collection of
+ * pipeline-specific behaviours implementation, and extensions.
+ */
+@Beta
+public interface PiPipeconf {
+
+    /**
+     * Returns the identifier of this pipeline configuration.
+     *
+     * @return a identifier
+     */
+    PiPipeconfId id();
+
+    /**
+     * Returns the pipeline model.
+     *
+     * @return a pipeline model
+     */
+    PiPipelineModel pipelineModel();
+
+    /**
+     * Returns all pipeline-specific behaviours defined by this configuration.
+     *
+     * @return a collection of behaviours
+     */
+    Collection<Class<? extends Behaviour>> behaviours();
+
+    /**
+     * Returns the implementation class for the given behaviour, if present.
+     *
+     * @param behaviour behaviour interface
+     * @return implementation class
+     */
+    Optional<Class<? extends Behaviour>> implementation(Class<? extends Behaviour> behaviour);
+
+    /**
+     * Indicates whether or not the pipeconf supports the specified class of behaviour.
+     *
+     * @param behaviourClass behaviour class
+     * @return true if behaviour is supported
+     */
+    boolean hasBehaviour(Class<? extends Behaviour> behaviourClass);
+
+    /**
+     * Returns, if present, an arbitrary sequence of bytes representing a device-specific or control
+     * protocol-specific extension of this configuration. For example, if requesting a
+     * target-specific P4 binary, this will return the same bytes produced by the P4 compiler.
+     *
+     * @param type extension type
+     * @return extension bytes
+     */
+    // FIXME: this is a sloppy way of handling extensions.
+    Optional<ByteBuffer> extension(ExtensionType type);
+
+    /**
+     * Type of extension of a protocol-independent pipeline configuration.
+     */
+    enum ExtensionType {
+        /**
+         * The P4Info as returned by the p4c compiler (in binary format).
+         */
+        P4_INFO_BINARY,
+
+        /**
+         * BMv2 JSON configuration.
+         */
+        BMV2_JSON
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconfId.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconfId.java
new file mode 100644
index 0000000..fccf9a7
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconfId.java
@@ -0,0 +1,36 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+
+/**
+ * An identifier of a protocol-independent pipeline configuration.
+ */
+@Beta
+public final class PiPipeconfId extends Identifier<String> {
+
+    /**
+     * Creates a pipeline configuration identifier.
+     *
+     * @param pipeconfId configuration identifier
+     */
+    public PiPipeconfId(String pipeconfId) {
+        super(pipeconfId);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
new file mode 100644
index 0000000..443c15b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.pi.runtime.PiHeaderFieldId;
+import org.onosproject.net.pi.runtime.PiTableAction;
+
+import java.util.Optional;
+
+/**
+ * An interpreter of a protocol-independent pipeline.
+ */
+@Beta
+public interface PiPipelineInterpreter extends HandlerBehaviour {
+
+    /**
+     * Returns the protocol-independent header field identifier that is equivalent to the given
+     * criterion type, if present. If not present, it means that the given criterion type is not
+     * supported by this interpreter.
+     *
+     * @param type criterion type
+     * @return optional header field identifier
+     */
+    Optional<PiHeaderFieldId> mapCriterionType(Criterion.Type type);
+
+    /**
+     * Returns the criterion type that is equivalent to the given protocol-independent header field
+     * identifier, if present. If not present, it means that the given field identifier is not
+     * supported by this interpreter.
+     *
+     * @param headerFieldId header field identifier
+     * @return optional criterion type
+     */
+    Optional<Criterion.Type> mapPiHeaderFieldId(PiHeaderFieldId headerFieldId);
+
+    /**
+     * Returns a table action of a protocol-independent pipeline that is functionally equivalent to
+     * the given ONOS traffic treatment for the given pipeline configuration.
+     *
+     * @param treatment a ONOS traffic treatment
+     * @param pipeconf  a pipeline configuration
+     * @return a table action object
+     * @throws PiInterpreterException if the treatment cannot be mapped to any table action
+     */
+    PiTableAction mapTreatment(TrafficTreatment treatment, PiPipeconf pipeconf)
+            throws PiInterpreterException;
+
+    /**
+     * Signals that an error was encountered while executing the interpreter.
+     */
+    @Beta
+    class PiInterpreterException extends Exception {
+        public PiInterpreterException(String message) {
+            super(message);
+        }
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineModel.java
new file mode 100644
index 0000000..7a9b5bf
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineModel.java
@@ -0,0 +1,89 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Model of a protocol-independent pipeline.
+ */
+@Beta
+public interface PiPipelineModel {
+
+    /**
+     * Returns the header type associated with the given name, if present.
+     *
+     * @param name string value
+     * @return optional header type model
+     */
+    Optional<PiHeaderTypeModel> headerType(String name);
+
+    /**
+     * Returns the collection of all header types defined by this pipeline model.
+     *
+     * @return collection of header types
+     */
+    Collection<PiHeaderTypeModel> headerTypes();
+
+    /**
+     * Returns the header instance associated with the given name, if present.
+     *
+     * @param name string value
+     * @return optional header instance model
+     */
+    Optional<PiHeaderModel> header(String name);
+
+    /**
+     * Returns the collection of all header instance models defined by this pipeline model.
+     *
+     * @return collection of header types
+     */
+    Collection<PiHeaderModel> headers();
+
+    /**
+     * Returns the action model associated with the given name, if present.
+     *
+     * @param name string value
+     * @return optional action model
+     */
+    Optional<PiActionModel> action(String name);
+
+    /**
+     * Returns the collection of all action models defined by this pipeline model.
+     *
+     * @return collection of actions
+     */
+    Collection<PiActionModel> actions();
+
+    /**
+     * Returns the table model associated with the given name, if present.
+     *
+     * @param name string value
+     * @return optional table model
+     */
+    Optional<PiTableModel> table(String name);
+
+    /**
+     * Returns the collection of all table models defined by this pipeline model.
+     *
+     * @return collection of actions
+     */
+    Collection<PiTableModel> tables();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiTableMatchFieldModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiTableMatchFieldModel.java
new file mode 100644
index 0000000..bc69a86
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiTableMatchFieldModel.java
@@ -0,0 +1,39 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Model of a table match field in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiTableMatchFieldModel {
+    /**
+     * Returns the match type of this key.
+     *
+     * @return a match type
+     */
+    PiMatchType matchType();
+
+    /**
+     * Returns the header field instance matched by this key.
+     *
+     * @return a header field value
+     */
+    PiHeaderFieldModel field();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiTableModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiTableModel.java
new file mode 100644
index 0000000..420b5f6
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiTableModel.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.util.Collection;
+
+/**
+ * Model of a match+action table in a protocol-independent pipeline.
+ */
+@Beta
+public interface PiTableModel {
+
+    /**
+     * Returns the name of this table.
+     *
+     * @return a string value
+     */
+    String name();
+
+    /**
+     * Returns the maximum number of entries supported by this table.
+     *
+     * @return an integer value
+     */
+    int maxSize();
+
+    /**
+     * Returns true if this table has counters, false otherwise.
+     *
+     * @return a boolean value
+     */
+    boolean hasCounters();
+
+    /**
+     * Returns true if this table supports aging, false otherwise.
+     *
+     * @return a boolean value
+     */
+    boolean supportsAging();
+
+    /**
+     * Returns the collection of match fields supported by this table.
+     *
+     * @return a collection of match field models
+     */
+    Collection<PiTableMatchFieldModel> matchFields();
+
+    /**
+     * Returns the actions supported by this table.
+     *
+     * @return a collection of action models
+     */
+    Collection<PiActionModel> actions();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/package-info.java b/core/api/src/main/java/org/onosproject/net/pi/model/package-info.java
new file mode 100644
index 0000000..eabd18d
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Base abstractions of a protocol-independent packet forwarding pipeline.
+ */
+package org.onosproject.net.pi.model;
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiAction.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiAction.java
new file mode 100644
index 0000000..24a7fbe
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiAction.java
@@ -0,0 +1,111 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import org.onlab.util.ImmutableByteSequence;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.StringJoiner;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Instance of an action, and its runtime parameters, of a table entry in a protocol-independent
+ * pipeline.
+ */
+@Beta
+public final class PiAction implements PiTableAction {
+
+    private final PiActionId actionId;
+    private final List<ImmutableByteSequence> runtimeParams;
+
+    /**
+     * Creates a new action instance for the given action identifier and runtime parameters.
+     *
+     * @param actionId      action identifier
+     * @param runtimeParams list of runtime parameters
+     */
+    public PiAction(PiActionId actionId, List<ImmutableByteSequence> runtimeParams) {
+        this.actionId = checkNotNull(actionId);
+        this.runtimeParams = ImmutableList.copyOf(checkNotNull(runtimeParams));
+    }
+
+    /**
+     * Creates a new action instance for the given action identifier, with no runtime parameters.
+     *
+     * @param actionId action identifier
+     */
+    public PiAction(PiActionId actionId) {
+        this(actionId, Collections.emptyList());
+    }
+
+    @Override
+    public Type type() {
+        return Type.ACTION;
+    }
+
+    /**
+     * Return the identifier of this action.
+     *
+     * @return action identifier
+     */
+    public PiActionId id() {
+        return actionId;
+    }
+
+    /**
+     * Returns an immutable view of the list of parameters of this action.
+     * Return an empty list if the action doesn't take any runtime parameters.
+     *
+     * @return list of byte sequences
+     */
+    public List<ImmutableByteSequence> parameters() {
+        return runtimeParams;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiAction piAction = (PiAction) o;
+        return Objects.equal(actionId, piAction.actionId) &&
+                Objects.equal(runtimeParams, piAction.runtimeParams);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(actionId, runtimeParams);
+    }
+
+    @Override
+    public String toString() {
+        StringJoiner stringParams = new StringJoiner(", ", "(", ")");
+        this.parameters().forEach(p -> stringParams.add(p.toString()));
+        return MoreObjects.toStringHelper(this)
+                .addValue(this.id().toString() + stringParams.toString())
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionId.java
new file mode 100644
index 0000000..ae17071
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionId.java
@@ -0,0 +1,36 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+
+/**
+ * Identifier of an action of a match+action table in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiActionId extends Identifier<String> {
+
+    /**
+     * Creates an action identifier.
+     *
+     * @param name action name
+     */
+    public PiActionId(String name) {
+        super(name);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiExactFieldMatch.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiExactFieldMatch.java
new file mode 100644
index 0000000..50bffa6
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiExactFieldMatch.java
@@ -0,0 +1,83 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.pi.model.PiMatchType;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Exact field match in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiExactFieldMatch extends PiFieldMatch {
+
+    private final ImmutableByteSequence value;
+
+    /**
+     * Creates an exact field match.
+     *
+     * @param fieldId field identifier
+     * @param value   value
+     */
+    public PiExactFieldMatch(PiHeaderFieldId fieldId, ImmutableByteSequence value) {
+        super(fieldId);
+        this.value = checkNotNull(value);
+        checkArgument(value.size() > 0, "Value can't have size 0");
+    }
+
+    @Override
+    public PiMatchType type() {
+        return PiMatchType.EXACT;
+    }
+
+    /**
+     * Returns the byte sequence value to be matched.
+     *
+     * @return an immutable byte sequence
+     */
+    public ImmutableByteSequence value() {
+        return value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiExactFieldMatch that = (PiExactFieldMatch) o;
+        return Objects.equal(this.fieldId(), that.fieldId()) &&
+                Objects.equal(value, that.value);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.fieldId(), value);
+    }
+
+    @Override
+    public String toString() {
+        return this.fieldId().toString() + "=" + value.toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiFieldMatch.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiFieldMatch.java
new file mode 100644
index 0000000..04d66c4
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiFieldMatch.java
@@ -0,0 +1,56 @@
+/*
+ * 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.runtime;
+
+import org.onosproject.net.pi.model.PiMatchType;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Header's field match in a protocol-independent pipeline.
+ */
+public abstract class PiFieldMatch {
+
+    private final PiHeaderFieldId fieldId;
+
+    /**
+     * Creates a new field match for the given header field identifier.
+     *
+     * @param fieldId field identifier.
+     */
+    PiFieldMatch(PiHeaderFieldId fieldId) {
+        this.fieldId = checkNotNull(fieldId);
+    }
+
+
+    /**
+     * Returns the identifier of the field to be matched.
+     *
+     * @return a header field ID value
+     */
+    public final PiHeaderFieldId fieldId() {
+        return fieldId;
+    }
+
+    /**
+     * Returns the type of match to be performed.
+     *
+     * @return a match type value
+     */
+    public abstract PiMatchType type();
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiFlowRuleTranslationService.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiFlowRuleTranslationService.java
new file mode 100644
index 0000000..93d8e0c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiFlowRuleTranslationService.java
@@ -0,0 +1,55 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.pi.model.PiPipeconf;
+
+/**
+ * A service to translate ONOS flow rules to table entries of a protocol-independent pipeline.
+ */
+@Beta
+public interface PiFlowRuleTranslationService {
+
+    /**
+     * Returns a table entry equivalent to the given flow rule for the given protocol-independent
+     * pipeline configuration.
+     *
+     * @param rule     a flow rule
+     * @param pipeconf a pipeline configuration
+     * @return a table entry
+     * @throws PiFlowRuleTranslationException if the flow rule cannot be translated
+     */
+    PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf)
+            throws PiFlowRuleTranslationException;
+
+    /**
+     * Signals that an error was encountered while translating flow rule.
+     */
+    class PiFlowRuleTranslationException extends Exception {
+
+        /**
+         * Creates a new exception with the given message.
+         *
+         * @param message a message
+         */
+        public PiFlowRuleTranslationException(String message) {
+            super(message);
+        }
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHeaderFieldId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHeaderFieldId.java
new file mode 100644
index 0000000..5566202
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHeaderFieldId.java
@@ -0,0 +1,86 @@
+/*
+ * 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.runtime;
+
+import org.onlab.util.Identifier;
+
+/**
+ * Identifier of a packet's header field.
+ */
+public final class PiHeaderFieldId extends Identifier<String> {
+
+    private final String headerName;
+    private final String fieldName;
+    private final int index;
+
+    /**
+     * Creates a new header field identifier for the given header name, field name and index.
+     * <p>
+     * Index represents the position of this header in the packet w.r.t. to other headers of the
+     * same type. Index 0 points to the first instance of the header, 1 the second one, etc. Helpful
+     * when dealing with stacked headers, e.g. to match on the second MPLS label.
+     *
+     * @param headerName header name
+     * @param fieldName  field name
+     * @param index      index
+     */
+    public PiHeaderFieldId(String headerName, String fieldName, int index) {
+        super(headerName +
+                      (index > 0 ? "[" + String.valueOf(index) + "]" : "") +
+                      "." + fieldName);
+        this.headerName = headerName;
+        this.fieldName = fieldName;
+        this.index = index;
+    }
+
+    /**
+     * Creates a new header field identifier for the given header name and field name.
+     *
+     * @param headerName header name
+     * @param fieldName  field name
+     */
+    public PiHeaderFieldId(String headerName, String fieldName) {
+        this(headerName, fieldName, 0);
+    }
+
+    /**
+     * Returns the name of the header.
+     *
+     * @return a string value
+     */
+    public String headerName() {
+        return headerName;
+    }
+
+    /**
+     * Returns the name of the field.
+     *
+     * @return a string value
+     */
+    public String fieldName() {
+        return fieldName;
+    }
+
+    /**
+     * Returns the index of this header.
+     *
+     * @return an integer value.
+     */
+    public int index() {
+        return index;
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiLpmFieldMatch.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiLpmFieldMatch.java
new file mode 100644
index 0000000..d97e1d9
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiLpmFieldMatch.java
@@ -0,0 +1,98 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.pi.model.PiMatchType;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Longest-prefix field match in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiLpmFieldMatch extends PiFieldMatch {
+
+    private final ImmutableByteSequence value;
+    private final int prefixLength;
+
+    /**
+     * Creates a new LPM field match.
+     *
+     * @param fieldId      field identifier
+     * @param value        value
+     * @param prefixLength prefix length
+     */
+    public PiLpmFieldMatch(PiHeaderFieldId fieldId, ImmutableByteSequence value, int prefixLength) {
+        super(fieldId);
+        this.value = checkNotNull(value);
+        this.prefixLength = prefixLength;
+        checkArgument(value.size() > 0, "Value must have non-zero size");
+        checkArgument(prefixLength >= 0, "Prefix length must be a non-negative integer");
+    }
+
+    @Override
+    public PiMatchType type() {
+        return PiMatchType.LPM;
+    }
+
+    /**
+     * Returns the value matched by this field.
+     *
+     * @return a byte sequence value
+     */
+    public ImmutableByteSequence value() {
+        return value;
+    }
+
+    /**
+     * Returns the prefix length to be matched.
+     *
+     * @return an integer value
+     */
+    public int prefixLength() {
+        return prefixLength;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiLpmFieldMatch that = (PiLpmFieldMatch) o;
+        return prefixLength == that.prefixLength &&
+                Objects.equal(value, that.value) &&
+                Objects.equal(this.fieldId(), that.fieldId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.fieldId(), value, prefixLength);
+    }
+
+    @Override
+    public String toString() {
+        return this.fieldId().toString() + '=' + value.toString()
+                + '/' + String.valueOf(prefixLength);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPipeconfService.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPipeconfService.java
new file mode 100644
index 0000000..c037eb6
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPipeconfService.java
@@ -0,0 +1,78 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
+
+import java.util.Optional;
+
+/**
+ * A service to manage the configurations of protocol-independent pipelines.
+ */
+@Beta
+public interface PiPipeconfService {
+
+    // TODO: we might want to extend ListenerService to support the broadcasting of PipeconfEvent.
+
+    /**
+     * Registers the given pipeconf.
+     *
+     * @param pipeconf a pipeconf
+     * @throws IllegalStateException if the same pipeconf identifier is already registered.
+     */
+    void register(PiPipeconf pipeconf) throws IllegalStateException;
+
+    /**
+     * Returns all pipeconfs registered.
+     *
+     * @return a collection of pipeconfs
+     */
+    Iterable<PiPipeconf> getPipeconfs();
+
+    /**
+     * Returns the pipeconf instance associated with the given identifier, if present.
+     * If not present, it means that no pipeconf with such identifier has been registered so far.
+     *
+     * @param id a pipeconf identifier
+     * @return an optional pipeconf
+     */
+    Optional<PiPipeconf> getPipeconf(PiPipeconfId id);
+
+    /**
+     * Binds the given pipeconf to the given infrastructure device. As a result of this method call,
+     * if the given pipeconf exposes any pipeline-specific behaviours, those will be merged to the
+     * device's driver.
+     *
+     * @param deviceId a device identifier
+     * @param pipeconf a pipeconf identifier
+     */
+    // TODO: This service doesn't make any effort in deploying the configuration to the device.
+    // Someone else should do that.
+    void bindToDevice(PiPipeconfId pipeconf, DeviceId deviceId);
+
+    /**
+     * Returns the pipeconf identifier currently associated with the given device identifier, if
+     * present. If not present, it means no pipeconf has been associated with that device so far.
+     *
+     * @param deviceId device identifier
+     * @return an optional pipeconf identifier
+     */
+    Optional<PiPipeconfId> ofDevice(DeviceId deviceId);
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiRangeFieldMatch.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiRangeFieldMatch.java
new file mode 100644
index 0000000..c4cf8d7
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiRangeFieldMatch.java
@@ -0,0 +1,98 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.pi.model.PiMatchType;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Range field match in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiRangeFieldMatch extends PiFieldMatch {
+
+    private final ImmutableByteSequence lowValue;
+    private final ImmutableByteSequence highValue;
+
+    /**
+     * Creates a new range field match for the given low and high value.
+     *
+     * @param fieldId   field identifier
+     * @param lowValue  low value
+     * @param highValue high value
+     */
+    public PiRangeFieldMatch(PiHeaderFieldId fieldId, ImmutableByteSequence lowValue,
+                             ImmutableByteSequence highValue) {
+        super(fieldId);
+        this.lowValue = checkNotNull(lowValue);
+        this.highValue = checkNotNull(highValue);
+        checkArgument(lowValue.size() == highValue.size() && lowValue.size() > 0,
+                      "Low and high values must have the same non-zero size.");
+    }
+
+    @Override
+    public PiMatchType type() {
+        return PiMatchType.RANGE;
+    }
+
+    /**
+     * Returns the low value of this range field match.
+     *
+     * @return low value
+     */
+    public ImmutableByteSequence lowValue() {
+        return lowValue;
+    }
+
+    /**
+     * Returns the high value of this range field match.
+     *
+     * @return high value
+     */
+    public ImmutableByteSequence highValue() {
+        return highValue;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiRangeFieldMatch that = (PiRangeFieldMatch) o;
+        return Objects.equal(this.fieldId(), that.fieldId()) &&
+                Objects.equal(lowValue, that.lowValue) &&
+                Objects.equal(highValue, that.highValue);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.fieldId(), lowValue, highValue);
+    }
+
+    @Override
+    public String toString() {
+        return this.fieldId().toString() + '=' + lowValue.toString() + "--" + highValue.toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableAction.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableAction.java
new file mode 100644
index 0000000..a4d4038
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableAction.java
@@ -0,0 +1,52 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * An action that can be executed as a consequence of a match in a match+action table of a protocol-independent
+ * pipeline.
+ */
+@Beta
+public interface PiTableAction {
+
+    /**
+     * Type of this action.
+     *
+     * @return a type
+     */
+    Type type();
+
+    enum Type {
+        /**
+         * Simple action with runtime parameters set by the control plane.
+         */
+        ACTION,
+
+        // TODO: in P4Runtime a table action can be any of the following 3.
+        // How to represent action profiles?
+        /* message TableAction {
+              oneof type {
+                Action action = 1;
+                uint32 action_profile_member_id = 2;
+                uint32 action_profile_group_id = 3;
+              }
+            }
+        */
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
new file mode 100644
index 0000000..741fc04
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
@@ -0,0 +1,253 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Table entry in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiTableEntry {
+
+    private static final int NO_PRIORITY = -1;
+    private static final double NO_TIMEOUT = -1;
+
+    private final PiTableId tableId;
+    private final Collection<PiFieldMatch> fieldMatches;
+    private final PiTableAction tableAction;
+    private final long cookie;
+    private final int priority;
+    private final double timeout;
+
+    private PiTableEntry(PiTableId tableId, Map<PiHeaderFieldId, PiFieldMatch> fieldMatches,
+                         PiTableAction tableAction, long cookie, int priority, double timeout) {
+        this.tableId = tableId;
+        this.fieldMatches = ImmutableSet.copyOf(fieldMatches.values());
+        this.tableAction = tableAction;
+        this.cookie = cookie;
+        this.priority = priority;
+        this.timeout = timeout;
+    }
+
+    /**
+     * Returns the table where this entry is installed.
+     *
+     * @return table identifier
+     */
+    public PiTableId table() {
+        return tableId;
+    }
+
+    /**
+     * Returns an immutable view of the field matches of this table entry.
+     *
+     * @return collection of field matches
+     */
+    public Collection<PiFieldMatch> fieldMatches() {
+        return fieldMatches;
+    }
+
+    /**
+     * Returns the action of this table entry.
+     *
+     * @return action
+     */
+    public PiTableAction action() {
+        return tableAction;
+    }
+
+    /**
+     * Returns the cookie of this table entry.
+     *
+     * @return cookie
+     */
+    public long cookie() {
+        return cookie;
+    }
+
+    /**
+     * Returns the priority of this table entry, if present.
+     * If the priority value is not present, then this table entry has no explicit priority.
+     *
+     * @return optional priority
+     */
+    public Optional<Integer> priority() {
+        return priority == NO_PRIORITY ? Optional.empty() : Optional.of(priority);
+    }
+
+    /**
+     * Returns the timeout in seconds of this table entry, if present.
+     * If the timeout value is not present, then this table entry is meant to be permanent.
+     *
+     * @return optional timeout value in seconds
+     */
+    public Optional<Double> timeout() {
+        return timeout == NO_TIMEOUT ? Optional.empty() : Optional.of(timeout);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiTableEntry that = (PiTableEntry) o;
+        return priority == that.priority &&
+                Double.compare(that.timeout, timeout) == 0 &&
+                Objects.equal(tableId, that.tableId) &&
+                Objects.equal(fieldMatches, that.fieldMatches) &&
+                Objects.equal(tableAction, that.tableAction);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(tableId, fieldMatches, tableAction, priority, timeout);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("tableId", tableId)
+                .add("fieldMatches", fieldMatches)
+                .add("tableAction", tableAction)
+                .add("priority", priority == NO_PRIORITY ? "N/A" : String.valueOf(priority))
+                .add("timeout", timeout == NO_TIMEOUT ? "PERMANENT" : String.valueOf(timeout))
+                .toString();
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static final class Builder {
+
+        private PiTableId tableId;
+        private Map<PiHeaderFieldId, PiFieldMatch> fieldMatches = Maps.newHashMap();
+        private PiTableAction tableAction;
+        private long cookie = 0;
+        private int priority = NO_PRIORITY;
+        private double timeout = NO_TIMEOUT;
+
+        private Builder() {
+            // Hides constructor.
+        }
+
+        /**
+         * Sets the table identifier for this entry.
+         *
+         * @param tableId table identifier
+         * @return this
+         */
+        Builder forTable(PiTableId tableId) {
+            this.tableId = checkNotNull(tableId);
+            return this;
+        }
+
+        /**
+         * Sets the action of this table entry.
+         *
+         * @param tableAction table action
+         * @return this
+         */
+        Builder withAction(PiTableAction tableAction) {
+            this.tableAction = checkNotNull(tableAction);
+            return this;
+        }
+
+        /**
+         * Adds one field match to this table entry.
+         *
+         * @param fieldMatch field match
+         * @return this
+         */
+        Builder withFieldMatch(PiFieldMatch fieldMatch) {
+            this.fieldMatches.put(fieldMatch.fieldId(), fieldMatch);
+            return this;
+        }
+
+        /**
+         * Adds many field matches to this table entry.
+         *
+         * @param fieldMatches collection of field matches
+         * @return this
+         */
+        Builder withFieldMatches(Collection<PiFieldMatch> fieldMatches) {
+            fieldMatches.forEach(f -> this.fieldMatches.put(f.fieldId(), f));
+            return this;
+        }
+
+        /**
+         * Sets the cookie, i.e. a controller-specific metadata.
+         *
+         * @param cookie cookie
+         * @return this
+         */
+        Builder withCookie(long cookie) {
+            this.cookie = cookie;
+            return this;
+        }
+
+        /**
+         * Sets the priority of this table entry.
+         *
+         * @param priority priority
+         * @return this
+         */
+        Builder withPriority(int priority) {
+            checkArgument(priority >= 0, "Priority must be a positive integer.");
+            this.priority = priority;
+            return this;
+        }
+
+        /**
+         * Sets the timeout of this table entry.
+         *
+         * @param seconds timeout in seconds
+         * @return this
+         */
+        Builder withTimeout(double seconds) {
+            checkArgument(seconds > 0, "Timeout must be greater than zero.");
+            this.timeout = seconds;
+            return this;
+        }
+
+        /**
+         * Builds the table entry.
+         *
+         * @return a new table entry
+         */
+        PiTableEntry build() {
+            checkNotNull(tableId);
+            checkNotNull(tableAction);
+            return new PiTableEntry(tableId, fieldMatches, tableAction, cookie, priority, timeout);
+        }
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableId.java
new file mode 100644
index 0000000..c062500
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableId.java
@@ -0,0 +1,78 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.Identifier;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Identifier of a table in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiTableId extends Identifier<String> {
+
+    private final String scope;
+    private final String name;
+
+    /**
+     * Creates a new table identifier for the given scope and table name.
+     *
+     * @param scope table scope
+     * @param name  table name
+     */
+    public PiTableId(String scope, String name) {
+        super(checkNotNull(scope) + '.' + checkNotNull(name));
+        this.scope = scope;
+        this.name = name;
+    }
+
+    /**
+     * Creates a new table identifier for the given table name.
+     *
+     * @param name table name
+     */
+    public PiTableId(String name) {
+        super(checkNotNull(name));
+        this.name = name;
+        this.scope = null;
+    }
+
+
+    /**
+     * Returns the name of this table.
+     *
+     * @return table name
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Returns the scope of this table, if present.
+     *
+     * @return optional scope
+     */
+    public Optional<String> scope() {
+        return Optional.ofNullable(scope);
+    }
+
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTernaryFieldMatch.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTernaryFieldMatch.java
new file mode 100644
index 0000000..cd98d20
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTernaryFieldMatch.java
@@ -0,0 +1,98 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.pi.model.PiMatchType;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Ternary field match in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiTernaryFieldMatch extends PiFieldMatch {
+
+    private final ImmutableByteSequence value;
+    private final ImmutableByteSequence mask;
+
+    /**
+     * Creates a new ternary field match.
+     *
+     * @param fieldId field identifier
+     * @param value value
+     * @param mask  mask
+     */
+    public PiTernaryFieldMatch(PiHeaderFieldId fieldId, ImmutableByteSequence value,
+                               ImmutableByteSequence mask) {
+        super(fieldId);
+        this.value = checkNotNull(value);
+        this.mask = checkNotNull(mask);
+        checkArgument(value.size() == mask.size() && value.size() > 0,
+                      "Value and mask must have same non-zero size");
+    }
+
+    @Override
+    public PiMatchType type() {
+        return PiMatchType.TERNARY;
+    }
+
+    /**
+     * Returns the value matched by this field.
+     *
+     * @return an immutable byte sequence
+     */
+    public ImmutableByteSequence value() {
+        return value;
+    }
+
+    /**
+     * Returns the mask used to match this field.
+     *
+     * @return an immutable byte sequence
+     */
+    public ImmutableByteSequence mask() {
+        return mask;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiTernaryFieldMatch that = (PiTernaryFieldMatch) o;
+        return Objects.equal(this.fieldId(), that.fieldId()) &&
+                Objects.equal(value, that.value) &&
+                Objects.equal(mask, that.mask);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.fieldId(), value, mask);
+    }
+
+    @Override
+    public String toString() {
+        return this.fieldId().toString() + '=' + value.toString() + "&&&" + mask.toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiValidFieldMatch.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiValidFieldMatch.java
new file mode 100644
index 0000000..ef716a2
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiValidFieldMatch.java
@@ -0,0 +1,78 @@
+/*
+ * 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.runtime;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onosproject.net.pi.model.PiMatchType;
+
+/**
+ * A valid field match in a protocol-independent pipeline.
+ */
+@Beta
+public final class PiValidFieldMatch extends PiFieldMatch {
+
+    private final boolean isValid;
+
+    /**
+     * Creates a new valid field match.
+     *
+     * @param fieldId field identifier
+     * @param isValid validity flag
+     */
+    public PiValidFieldMatch(PiHeaderFieldId fieldId, boolean isValid) {
+        super(fieldId);
+        this.isValid = isValid;
+    }
+
+    @Override
+    public final PiMatchType type() {
+        return PiMatchType.VALID;
+    }
+
+    /**
+     * Returns the boolean flag of this valid match parameter.
+     *
+     * @return valid match flag
+     */
+    public boolean isValid() {
+        return isValid;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiValidFieldMatch that = (PiValidFieldMatch) o;
+        return Objects.equal(this.fieldId(), that.fieldId()) &&
+                isValid == that.isValid;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.fieldId(), isValid);
+    }
+
+    @Override
+    public String toString() {
+        return this.fieldId().toString() + '=' + (isValid ? "VALID" : "NOT_VALID");
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/package-info.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/package-info.java
new file mode 100644
index 0000000..f92f905
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Base abstractions fot runtime control of a protocol-independent pipeline.
+ */
+package org.onosproject.net.pi.runtime;
\ No newline at end of file
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
index 4e8f8e3..df98b8d 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
@@ -139,6 +139,7 @@
         formatMap.put(Criterion.Type.UDP_DST_MASKED, new FormatUnknown());
         formatMap.put(Criterion.Type.SCTP_SRC_MASKED, new FormatUnknown());
         formatMap.put(Criterion.Type.SCTP_DST_MASKED, new FormatUnknown());
+        formatMap.put(Criterion.Type.PROTOCOL_INDEPENDENT, new FormatUnknown());
 
     }