[ONOS-6554] Implement BMv2-JSON-to-PiPipelineModel parser

1. Create new module incubator/bmv2/model
2. Move all bmv2 model files to incubator/bmv2/model
3. Using PI core interfaces for all bmv2 models
4. Refactor original bmv2 config parser (Bmv2PipelineModelParser)
5. Refactor original bmv2 config parser test

Change-Id: I0db07762d76ab6e2f846e9c3c9d5896f0cbea7f2
diff --git a/incubator/bmv2/model/BUCK b/incubator/bmv2/model/BUCK
new file mode 100644
index 0000000..9f313b6
--- /dev/null
+++ b/incubator/bmv2/model/BUCK
@@ -0,0 +1,7 @@
+COMPILE_DEPS = [
+  '//lib:CORE_DEPS'
+]
+
+osgi_jar_with_tests (
+  deps = COMPILE_DEPS,
+)
diff --git a/incubator/bmv2/model/pom.xml b/incubator/bmv2/model/pom.xml
new file mode 100644
index 0000000..0186416
--- /dev/null
+++ b/incubator/bmv2/model/pom.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016-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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>onos-bmv2-model</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.11.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>bundle</packaging>
+    <artifactId>onos-bmv2-model</artifactId>
+</project>
\ No newline at end of file
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2ActionModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2ActionModel.java
new file mode 100644
index 0000000..0b716e6
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2ActionModel.java
@@ -0,0 +1,109 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.pi.model.PiActionModel;
+import org.onosproject.net.pi.model.PiActionParamModel;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * BMv2 action model.
+ */
+@Beta
+public final class Bmv2ActionModel implements PiActionModel {
+    private final String name;
+    private final int id;
+    private final ImmutableMap<String, PiActionParamModel> params;
+
+    /**
+     * Builds BMv2 action model with given information.
+     *
+     * @param name the model name
+     * @param id the model id
+     * @param params the action parameters
+     */
+    public Bmv2ActionModel(String name, int id, List<Bmv2ActionParamModel> params) {
+        checkNotNull(name, "Model name can't be null");
+        checkNotNull(params, "Action parameters can't be null");
+
+        this.name = name;
+        this.id = id;
+        ImmutableMap.Builder<String, PiActionParamModel> mapBuilder = ImmutableMap.builder();
+        params.forEach(param -> mapBuilder.put(param.name(), param));
+        this.params = mapBuilder.build();
+    }
+
+    /**
+     * Gets id from this action model.
+     *
+     * @return the model id
+     */
+    public int id() {
+        return id;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public Optional<PiActionParamModel> param(String name) {
+        checkNotNull(name, "Parameter name can't be null");
+        return Optional.ofNullable(params.get(name));
+    }
+
+    @Override
+    public List<PiActionParamModel> params() {
+        return (ImmutableList<PiActionParamModel>) params.values();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, params);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof Bmv2ActionModel)) {
+            return false;
+        }
+        Bmv2ActionModel that = (Bmv2ActionModel) obj;
+        return Objects.equals(this.name, that.name) &&
+                Objects.equals(this.params, that.params);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("name", name)
+                .add("params", params)
+                .toString();
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2ActionParamModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2ActionParamModel.java
new file mode 100644
index 0000000..69272cb
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2ActionParamModel.java
@@ -0,0 +1,82 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import org.onosproject.net.pi.model.PiActionParamModel;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * BMv2 action parameter model.
+ */
+@Beta
+public final class Bmv2ActionParamModel implements PiActionParamModel {
+    private final String name;
+    private final int bitWidth;
+
+    /**
+     * Builds a BMv2 action parameter model with given name and bit width.
+     *
+     * @param name the name
+     * @param bitWidth the bit width
+     */
+    public Bmv2ActionParamModel(String name, int bitWidth) {
+        checkNotNull(name, "Parameter name can't be null");
+        checkArgument(bitWidth > 0, "Bit width should be a non-zero positive integer");
+        this.name = name;
+        this.bitWidth = bitWidth;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public int bitWidth() {
+        return bitWidth;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, bitWidth);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof Bmv2ActionParamModel)) {
+            return false;
+        }
+        Bmv2ActionParamModel that = (Bmv2ActionParamModel) obj;
+        return Objects.equals(this.name, that.name) &&
+                this.bitWidth == that.bitWidth;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("name", name)
+                .add("bitWidth", bitWidth)
+                .toString();
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderFieldModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderFieldModel.java
new file mode 100644
index 0000000..3a43238
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderFieldModel.java
@@ -0,0 +1,84 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onosproject.net.pi.model.PiHeaderFieldModel;
+import org.onosproject.net.pi.model.PiHeaderFieldTypeModel;
+import org.onosproject.net.pi.model.PiHeaderModel;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * BMv2 header field model.
+ */
+@Beta
+public final class Bmv2HeaderFieldModel implements PiHeaderFieldModel {
+    private final Bmv2HeaderModel header;
+    private final Bmv2HeaderFieldTypeModel type;
+
+    /**
+     * Builds a BMv2 header field model with given BMv2 header model and header field type model.
+     *
+     * @param header the header model
+     * @param type the header field type model
+     */
+    public Bmv2HeaderFieldModel(Bmv2HeaderModel header, Bmv2HeaderFieldTypeModel type) {
+        checkNotNull(header, "Header can't be null");
+        checkNotNull(type, "Type can't be null");
+        this.header = header;
+        this.type = type;
+    }
+
+    @Override
+    public PiHeaderModel header() {
+        return header;
+    }
+
+    @Override
+    public PiHeaderFieldTypeModel type() {
+        return type;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(header, type);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof Bmv2HeaderFieldModel)) {
+            return false;
+        }
+        Bmv2HeaderFieldModel that = (Bmv2HeaderFieldModel) obj;
+        return Objects.equal(this.header, that.header) &&
+                Objects.equal(this.type, that.type);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("header", header)
+                .add("type", type)
+                .toString();
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderFieldTypeModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderFieldTypeModel.java
new file mode 100644
index 0000000..5f14537
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderFieldTypeModel.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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onosproject.net.pi.model.PiHeaderFieldTypeModel;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * BMv2 header field type model.
+ */
+@Beta
+public final class Bmv2HeaderFieldTypeModel implements PiHeaderFieldTypeModel {
+    private final String name;
+    private final int bitWidth;
+    private final boolean signed;
+
+    /**
+     * Builds a BMv2 header field type model with given information.
+     *
+     * @param name the name of field type
+     * @param bitWidth the bit width of field type
+     * @param signed header type field is signed or not
+     */
+    public Bmv2HeaderFieldTypeModel(String name, int bitWidth, boolean signed) {
+        checkNotNull(name, "Header field type name can't be null");
+        checkArgument(bitWidth > 0, "Bit width should be non-zero positive integer");
+        this.name = name;
+        this.bitWidth = bitWidth;
+        this.signed = signed;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public int bitWidth() {
+        return bitWidth;
+    }
+
+    /**
+     * Determine whether the header type field is signed or not.
+     *
+     * @return true if it is signed; otherwise false
+     */
+    public boolean signed() {
+        return signed;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(name, bitWidth);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final Bmv2HeaderFieldTypeModel other = (Bmv2HeaderFieldTypeModel) obj;
+        return Objects.equal(this.name, other.name) &&
+                Objects.equal(this.bitWidth, other.bitWidth) &&
+                Objects.equal(this.signed, other.signed);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("name", name)
+                .add("bitWidth", bitWidth)
+                .toString();
+    }
+
+
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderModel.java
new file mode 100644
index 0000000..6c838c4
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderModel.java
@@ -0,0 +1,118 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onosproject.net.pi.model.PiHeaderModel;
+import org.onosproject.net.pi.model.PiHeaderTypeModel;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * BMv2 header model.
+ */
+@Beta
+public final class Bmv2HeaderModel implements PiHeaderModel {
+    private final String name;
+    private final int id;
+    private final int index;
+    private final Bmv2HeaderTypeModel type;
+    private final boolean isMetadata;
+
+    /**
+     * Builds a new BMv2 header model with given information.
+     *
+     * @param name the name of this header mdoel
+     * @param id the id of this header model
+     * @param index the header index
+     * @param type the type of this header model
+     * @param metadata if the header is metadata
+     */
+    public Bmv2HeaderModel(String name, int id, int index, Bmv2HeaderTypeModel type, boolean metadata) {
+        checkNotNull(name, "Model name can't be null.");
+        checkArgument(index >= 0, "Index should be a positive integer");
+        checkNotNull(type, "Header type can't be null.");
+        this.name = name;
+        this.id = id;
+        this.index = index;
+        this.type = type;
+        this.isMetadata = metadata;
+    }
+
+    /**
+     * Gets the name of this header model.
+     *
+     * @return name of this model
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Gets the id of this header model.
+     *
+     * @return if of this header model
+     */
+    public int id() {
+        return id;
+    }
+
+    @Override
+    public int index() {
+        return index;
+    }
+
+    @Override
+    public PiHeaderTypeModel type() {
+        return type;
+    }
+
+    @Override
+    public boolean isMetadata() {
+        return isMetadata;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(id, type, isMetadata);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final Bmv2HeaderModel other = (Bmv2HeaderModel) obj;
+        return Objects.equal(this.id, other.id)
+                && Objects.equal(this.type, other.type)
+                && Objects.equal(this.isMetadata, other.isMetadata);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("index", id)
+                .add("type", type)
+                .add("isMetadata", isMetadata)
+                .toString();
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderTypeModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderTypeModel.java
new file mode 100644
index 0000000..735a37e
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2HeaderTypeModel.java
@@ -0,0 +1,109 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.pi.model.PiHeaderFieldTypeModel;
+import org.onosproject.net.pi.model.PiHeaderTypeModel;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * BMv2 header type model.
+ */
+@Beta
+public final class Bmv2HeaderTypeModel implements PiHeaderTypeModel {
+    private final String name;
+    private final int id;
+    private final ImmutableMap<String, PiHeaderFieldTypeModel> fields;
+
+    /**
+     * Builds a BMv2 header type model by given information.
+     *
+     * @param name the name
+     * @param id the id
+     * @param fields the fields
+     */
+    public Bmv2HeaderTypeModel(String name,
+                               int id,
+                               List<Bmv2HeaderFieldTypeModel> fields) {
+        checkNotNull(name, "Type name can't be null");
+        checkNotNull(fields, "Fields can't be null");
+        this.name = name;
+        this.id = id;
+        ImmutableMap.Builder<String, PiHeaderFieldTypeModel> mapBuilder = ImmutableMap.builder();
+        fields.forEach(field -> mapBuilder.put(field.name(), field));
+        this.fields = mapBuilder.build();
+    }
+
+    /**
+     * Gets id of this header type model.
+     *
+     * @return the id
+     */
+    public int id() {
+        return id;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public Optional<PiHeaderFieldTypeModel> field(String fieldName) {
+        return Optional.ofNullable(fields.get(fieldName));
+    }
+
+    @Override
+    public List<PiHeaderFieldTypeModel> fields() {
+        return (ImmutableList<PiHeaderFieldTypeModel>) fields.values();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, fields);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final Bmv2HeaderTypeModel other = (Bmv2HeaderTypeModel) obj;
+        return Objects.equals(this.name, other.name)
+                && Objects.equals(this.fields, other.fields);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("name", name)
+                .add("fields", fields)
+                .toString();
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2Pipeconf.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2Pipeconf.java
new file mode 100644
index 0000000..6c86d61
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2Pipeconf.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.bmv2.model;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.model.PiPipelineModel;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * BMv2 pipeline configuration (pipeconf).
+ */
+public final class Bmv2Pipeconf implements PiPipeconf {
+    private final PiPipeconfId id;
+    private final Bmv2PipelineModel pipelineModel;
+    private final Set<Class<? extends Behaviour>> behaviours;
+    private final Map<ExtensionType, ByteBuffer> extensions;
+
+    /**
+     * Builds a new BMv2 pipeline configuration (pipeconf) by given information.
+     *
+     * @param id the pipeconf id
+     * @param pipelineModel the pipeline model
+     * @param behaviours the behaviors of the pipeline
+     * @param extensions the extensions of the pipeline
+     */
+    public Bmv2Pipeconf(PiPipeconfId id,
+                        Bmv2PipelineModel pipelineModel,
+                        Set<Class<? extends Behaviour>> behaviours,
+                        Map<ExtensionType, ByteBuffer> extensions) {
+        checkNotNull(id, "Pipeconf Id can't be null");
+        checkNotNull(pipelineModel, "Pipeline model can't be null");
+
+        this.id = id;
+        this.pipelineModel = pipelineModel;
+        this.behaviours = behaviours == null ? ImmutableSet.of() : behaviours;
+        this.extensions = extensions == null ? Maps.newHashMap() : extensions;
+    }
+
+    @Override
+    public PiPipeconfId id() {
+        return id;
+    }
+
+    @Override
+    public PiPipelineModel pipelineModel() {
+        return pipelineModel;
+    }
+
+    @Override
+    public Collection<Class<? extends Behaviour>> behaviours() {
+        return behaviours;
+    }
+
+    @Override
+    public Optional<Class<? extends Behaviour>> implementation(Class<? extends Behaviour> behaviour) {
+        return behaviours.stream()
+                .filter(behaviour::isAssignableFrom)
+                .findAny();
+    }
+
+    @Override
+    public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
+        return behaviours.stream()
+                .anyMatch(behaviourClass::isAssignableFrom);
+    }
+
+    @Override
+    public Optional<ByteBuffer> extension(ExtensionType type) {
+        return Optional.ofNullable(extensions.get(type));
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModel.java
new file mode 100644
index 0000000..3da1bc6
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModel.java
@@ -0,0 +1,146 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.onosproject.net.pi.model.PiActionModel;
+import org.onosproject.net.pi.model.PiHeaderModel;
+import org.onosproject.net.pi.model.PiHeaderTypeModel;
+import org.onosproject.net.pi.model.PiPipelineModel;
+import org.onosproject.net.pi.model.PiTableModel;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * BMv2 pipeline model.
+ */
+@Beta
+public class Bmv2PipelineModel implements PiPipelineModel {
+    private final Map<String, PiHeaderTypeModel> headerTypeModels;
+    private final Map<String, PiHeaderModel> headerModels;
+    private final Map<String, PiActionModel> actionModels;
+    private final Map<String, PiTableModel> tableModels;
+
+    /**
+     * Constructs a BMv2 pipeline model by given information.
+     *
+     * @param headerTypeModels the header type models for this pipeline model
+     * @param headerModels the header models for this pipeline model
+     * @param actionModels the action models for this pipeline model
+     * @param tableModels the table models for this pipeline model
+     */
+    Bmv2PipelineModel(List<Bmv2HeaderTypeModel> headerTypeModels,
+                      List<Bmv2HeaderModel> headerModels,
+                      List<Bmv2ActionModel> actionModels,
+                      List<Bmv2TableModel> tableModels) {
+        checkNotNull(headerTypeModels, "Header type models can't be null");
+        checkNotNull(headerModels, "Header models can't be null");
+        checkNotNull(actionModels, "Action models can't be null");
+        checkNotNull(tableModels, "Table models can't be null");
+
+        Map<String, PiHeaderTypeModel> headerTypeModelMap = Maps.newHashMap();
+        headerTypeModels.stream()
+                .filter(Objects::nonNull)
+                .forEach(htm -> headerTypeModelMap.put(htm.name(), htm));
+        this.headerTypeModels = ImmutableMap.copyOf(headerTypeModelMap);
+
+        Map<String, PiHeaderModel> headerModelMap = Maps.newHashMap();
+        headerModels.stream()
+                .filter(Objects::nonNull)
+                .forEach(hm -> headerModelMap.put(hm.type().name(), hm));
+        this.headerModels = ImmutableMap.copyOf(headerModelMap);
+
+        Map<String, PiActionModel> actionModelMap = Maps.newHashMap();
+        actionModels.stream()
+                .filter(Objects::nonNull)
+                .forEach(am -> actionModelMap.put(am.name(), am));
+        this.actionModels = ImmutableMap.copyOf(actionModelMap);
+
+        Map<String, PiTableModel> tableModelMap = Maps.newHashMap();
+        tableModels.stream()
+                .filter(Objects::nonNull)
+                .forEach(tm -> tableModelMap.put(tm.name(), tm));
+        this.tableModels = ImmutableMap.copyOf(tableModelMap);
+    }
+
+    @Override
+    public Optional<PiHeaderTypeModel> headerType(String name) {
+        return Optional.ofNullable(headerTypeModels.get(name));
+    }
+
+    @Override
+    public Collection<PiHeaderTypeModel> headerTypes() {
+        return headerTypeModels.values();
+    }
+
+    @Override
+    public Optional<PiHeaderModel> header(String name) {
+        return Optional.ofNullable(headerModels.get(name));
+    }
+
+    @Override
+    public Collection<PiHeaderModel> headers() {
+        return headerModels.values();
+    }
+
+    @Override
+    public Optional<PiActionModel> action(String name) {
+        return Optional.ofNullable(actionModels.get(name));
+    }
+
+    @Override
+    public Collection<PiActionModel> actions() {
+        return actionModels.values();
+    }
+
+    @Override
+    public Optional<PiTableModel> table(String name) {
+        return Optional.ofNullable(tableModels.get(name));
+    }
+
+    @Override
+    public Collection<PiTableModel> tables() {
+        return tableModels.values();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(headerTypeModels, headerModels, actionModels, tableModels);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof Bmv2PipelineModel)) {
+            return false;
+        }
+        Bmv2PipelineModel that = (Bmv2PipelineModel) obj;
+        return Objects.equals(this.headerTypeModels, that.headerTypeModels) &&
+                Objects.equals(this.headerModels, that.headerModels) &&
+                Objects.equals(this.actionModels, that.actionModels) &&
+                Objects.equals(this.tableModels, that.tableModels);
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModelParser.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModelParser.java
new file mode 100644
index 0000000..c674753
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModelParser.java
@@ -0,0 +1,324 @@
+/*
+ * 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.bmv2.model;
+
+import com.eclipsesource.json.JsonArray;
+import com.eclipsesource.json.JsonObject;
+import com.eclipsesource.json.JsonValue;
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.onosproject.net.pi.model.PiMatchType;
+import org.slf4j.Logger;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * BMv2 pipeline model parser.
+ *
+ * @see <a href="https://github.com/p4lang/behavioral-model/blob/master/docs/JSON_format.md">
+ * BMv2 JSON specification</a>
+ */
+@Beta
+public final class Bmv2PipelineModelParser {
+    private static final Logger log = getLogger(Bmv2PipelineModelParser.class);
+
+    // General fields and values
+    private static final String NAME = "name";
+    private static final String ID = "id";
+    private static final int NO_ID = Integer.MIN_VALUE;
+
+    // Hide default parser
+    private Bmv2PipelineModelParser() {
+    }
+
+    /**
+     * Translate BMv2 json config to Bmv2PipelineModel object.
+     *
+     * @param jsonObject the BMv2 json config
+     * @return Bmv2PipelineModel object for the json config
+     */
+    public static Bmv2PipelineModel parse(JsonObject jsonObject) {
+        List<Bmv2HeaderTypeModel> headerTypeModels = HeaderTypesParser.parse(jsonObject);
+        Map<Integer, Integer> headerIdToIndex = HeaderStackParser.parse(jsonObject);
+        List<Bmv2HeaderModel> headerModels = HeadersParser.parse(jsonObject, headerTypeModels, headerIdToIndex);
+        List<Bmv2ActionModel> actionModels = ActionsParser.parse(jsonObject);
+        List<Bmv2TableModel> tableModels = TablesParser.parse(jsonObject, headerModels, actionModels);
+
+        return new Bmv2PipelineModel(headerTypeModels, headerModels,
+                                     actionModels, tableModels);
+    }
+
+    /**
+     * Parser for BMv2 header types.
+     */
+    private static class HeaderTypesParser {
+        private static final String HEADER_TYPES = "header_types";
+        private static final String FIELDS = "fields";
+        private static final int FIELD_NAME_INDEX = 0;
+        private static final int FIELD_BIT_WIDTH_INDEX = 1;
+        private static final int FIELD_SIGNED_INDEX = 2;
+        private static final int SIZE_WITH_SIGNED_FLAG = 3;
+
+        private static List<Bmv2HeaderTypeModel> parse(JsonObject jsonObject) {
+            List<Bmv2HeaderTypeModel> headerTypeModels = Lists.newArrayList();
+            jsonObject.get(HEADER_TYPES).asArray().forEach(jsonValue ->  {
+                JsonObject headerFieldType = jsonValue.asObject();
+                String name = headerFieldType.getString(NAME, null);
+                int id = headerFieldType.getInt(ID, NO_ID);
+                if (id == NO_ID) {
+                    log.warn("Can't get id from header type field {}", jsonValue);
+                    return;
+                }
+                if (name == null) {
+                    log.warn("Can't get name from header type field {}", jsonValue);
+                    return;
+                }
+                List<Bmv2HeaderFieldTypeModel> fields = Lists.newArrayList();
+                headerFieldType.get(FIELDS).asArray().forEach(fieldValue -> {
+                    JsonArray fieldInfo = fieldValue.asArray();
+                    boolean signed = false;
+                    if (fieldInfo.size() == SIZE_WITH_SIGNED_FLAG) {
+                        // 3-tuple value, third value is a boolean value
+                        // true if the field is signed; otherwise false
+                        signed = fieldInfo.get(FIELD_SIGNED_INDEX).asBoolean();
+                    }
+                    fields.add(new Bmv2HeaderFieldTypeModel(fieldInfo.get(FIELD_NAME_INDEX).asString(),
+                                                            fieldInfo.get(FIELD_BIT_WIDTH_INDEX).asInt(),
+                                                            signed));
+                });
+                headerTypeModels.add(new Bmv2HeaderTypeModel(name, id, fields));
+            });
+            return headerTypeModels;
+        }
+    }
+
+    /**
+     * Parser for BMv2 header stacks.
+     */
+    private static class HeaderStackParser {
+        private static final String HEADER_STACK = "header_stacks";
+        private static final String HEADER_IDS = "header_ids";
+
+        /**
+         * Parser header stacks, return header-id to stack index mapping.
+         *
+         * @param jsonObject BMv2 json config
+         * @return header-id to stack index mapping
+         */
+        private static Map<Integer, Integer> parse(JsonObject jsonObject) {
+            Map<Integer, Integer> headerIdToIndex = Maps.newHashMap();
+            jsonObject.get(HEADER_STACK).asArray().forEach(jsonValue -> {
+                JsonArray headerIds = jsonValue.asObject().get(HEADER_IDS).asArray();
+                int index = 0;
+                for (JsonValue id : headerIds.values()) {
+                    headerIdToIndex.put(id.asInt(), index);
+                    index++;
+                }
+            });
+            return headerIdToIndex;
+        }
+    }
+
+    /**
+     * Parser for BMv2 headers.
+     */
+    private static class HeadersParser {
+        private static final String HEADERS = "headers";
+        private static final String HEADER_TYPE = "header_type";
+        private static final String METADATA = "metadata";
+        private static final String DEFAULT_HEADER_TYPE = "";
+        private static final Integer DEFAULT_HEADER_INDEX = 0;
+
+        private static List<Bmv2HeaderModel> parse(JsonObject jsonObject,
+                                                   List<Bmv2HeaderTypeModel> headerTypeModels,
+                                                   Map<Integer, Integer> headerIdToIndex) {
+            List<Bmv2HeaderModel> headerModels = Lists.newArrayList();
+
+            jsonObject.get(HEADERS).asArray().forEach(jsonValue -> {
+                JsonObject header = jsonValue.asObject();
+                String name = header.getString(NAME, null);
+                int id = header.getInt(ID, NO_ID);
+                String headerTypeName = header.getString(HEADER_TYPE, DEFAULT_HEADER_TYPE);
+                boolean isMetadata = header.getBoolean(METADATA, false);
+
+                if (name == null || id == -1) {
+                    log.warn("Can't get name or id from header {}", header);
+                    return;
+                }
+                Bmv2HeaderTypeModel headerTypeModel = headerTypeModels.stream()
+                        .filter(model -> model.name().equals(headerTypeName))
+                        .findFirst()
+                        .orElse(null);
+
+                if (headerTypeModel == null) {
+                    log.warn("Can't get header type model {} from header {}", headerTypeName, header);
+                    return;
+                }
+
+                Integer index = headerIdToIndex.get(id);
+
+                // No index for this header, set to default
+                if (index == null) {
+                    index = DEFAULT_HEADER_INDEX;
+                }
+                headerModels.add(new Bmv2HeaderModel(name, id, index, headerTypeModel, isMetadata));
+            });
+
+            return headerModels;
+        }
+    }
+
+    /**
+     * Parser for BMv2 actions.
+     */
+    private static class ActionsParser {
+        private static final String ACTIONS = "actions";
+        private static final String RUNTIME_DATA = "runtime_data";
+        private static final String BITWIDTH = "bitwidth";
+
+        private static List<Bmv2ActionModel> parse(JsonObject jsonObject) {
+            List<Bmv2ActionModel> actionModels = Lists.newArrayList();
+
+            jsonObject.get(ACTIONS).asArray().forEach(jsonValue -> {
+                JsonObject action = jsonValue.asObject();
+                String name = action.getString(NAME, null);
+                int id = action.getInt(ID, NO_ID);
+                List<Bmv2ActionParamModel> paramModels = Lists.newArrayList();
+                action.get(RUNTIME_DATA).asArray().forEach(paramValue -> {
+                    JsonObject paramInfo = paramValue.asObject();
+                    String paramName = paramInfo.getString(NAME, null);
+                    int bitWidth = paramInfo.getInt(BITWIDTH, -1);
+
+                    if (paramName == null || bitWidth == -1) {
+                        log.warn("Can't get name or bit width from runtime data {}", paramInfo);
+                        return;
+                    }
+                    paramModels.add(new Bmv2ActionParamModel(paramName, bitWidth));
+                });
+
+                actionModels.add(new Bmv2ActionModel(name, id, paramModels));
+            });
+
+            return actionModels;
+        }
+    }
+
+    /**
+     * Parser for BMv2 tables.
+     */
+    private static class TablesParser {
+        private static final String PIPELINES = "pipelines";
+        private static final String TABLES = "tables";
+        private static final String KEY = "key";
+        private static final String MATCH_TYPE = "match_type";
+        private static final String TARGET = "target";
+        private static final int TARGET_HEADER_INDEX = 0;
+        private static final int TARGET_FIELD_INDEX = 1;
+        private static final String ACTIONS = "actions";
+        private static final String MAX_SIZE = "max_size";
+        private static final int DEFAULT_MAX_SIZE = 0;
+        private static final String WITH_COUNTERS = "with_counters";
+        private static final String SUPPORT_TIMEOUT = "support_timeout";
+
+        private static List<Bmv2TableModel> parse(JsonObject jsonObject,
+                                                  List<Bmv2HeaderModel> headerModels,
+                                                  List<Bmv2ActionModel> actionModels) {
+            List<Bmv2TableModel> tableModels = Lists.newArrayList();
+            jsonObject.get(PIPELINES).asArray().forEach(pipelineVal -> {
+                JsonObject pipeline = pipelineVal.asObject();
+                pipeline.get(TABLES).asArray().forEach(tableVal -> {
+                    JsonObject table = tableVal.asObject();
+                    String tableName = table.getString(NAME, null);
+                    int tableId = table.getInt(ID, NO_ID);
+                    int maxSize = table.getInt(MAX_SIZE, DEFAULT_MAX_SIZE);
+                    boolean hasCounters = table.getBoolean(WITH_COUNTERS, false);
+                    boolean suppportAging = table.getBoolean(SUPPORT_TIMEOUT, false);
+
+                    // Match field
+                    Set<Bmv2TableMatchFieldModel> matchFieldModels =
+                            Sets.newHashSet();
+                    table.get(KEY).asArray().forEach(keyVal -> {
+                        JsonObject key = keyVal.asObject();
+                        String matchTypeName = key.getString(MATCH_TYPE, null);
+
+                        if (matchTypeName == null) {
+                            log.warn("Can't find match type from key {}", key);
+                            return;
+                        }
+                        PiMatchType matchType = PiMatchType.valueOf(matchTypeName.toUpperCase());
+
+                        // convert target array to Bmv2HeaderFieldTypeModel
+                        // e.g. ["ethernet", "dst"]
+                        JsonArray targetArray = key.get(TARGET).asArray();
+                        Bmv2HeaderFieldModel matchField;
+
+                        String headerName = targetArray.get(TARGET_HEADER_INDEX).asString();
+                        String fieldName = targetArray.get(TARGET_FIELD_INDEX).asString();
+
+                        Bmv2HeaderModel headerModel = headerModels.stream()
+                                .filter(hm -> hm.name().equals(headerName))
+                                .findAny()
+                                .orElse(null);
+
+                        if (headerModel == null) {
+                            log.warn("Can't find header {} for table {}", headerName, tableName);
+                            return;
+                        }
+                        Bmv2HeaderFieldTypeModel fieldModel =
+                                (Bmv2HeaderFieldTypeModel) headerModel.type()
+                                        .field(fieldName)
+                                        .orElse(null);
+
+                        if (fieldModel == null) {
+                            log.warn("Can't find field {} from header {}", fieldName, headerName);
+                            return;
+                        }
+                        matchField = new Bmv2HeaderFieldModel(headerModel, fieldModel);
+                        matchFieldModels.add(new Bmv2TableMatchFieldModel(matchType, matchField));
+                    });
+
+                    // Actions
+                    Set<Bmv2ActionModel> actions = Sets.newHashSet();
+                    table.get(ACTIONS).asArray().forEach(actionVal -> {
+                        String actionName = actionVal.asString();
+                        Bmv2ActionModel action = actionModels.stream()
+                                .filter(am -> am.name().equals(actionName))
+                                .findAny()
+                                .orElse(null);
+                        if (action == null) {
+                            log.warn("Can't find action {}", actionName);
+                            return;
+                        }
+                        actions.add(action);
+                    });
+
+                    tableModels.add(new Bmv2TableModel(tableName, tableId,
+                                                       maxSize, hasCounters,
+                                                       suppportAging,
+                                                       matchFieldModels, actions));
+                });
+            });
+
+            return tableModels;
+        }
+    }
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2TableMatchFieldModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2TableMatchFieldModel.java
new file mode 100644
index 0000000..db66613
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2TableMatchFieldModel.java
@@ -0,0 +1,87 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import org.onosproject.net.pi.model.PiMatchType;
+import org.onosproject.net.pi.model.PiTableMatchFieldModel;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.*;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * BMv2 table match field model.
+ */
+@Beta
+public final class Bmv2TableMatchFieldModel implements PiTableMatchFieldModel {
+    private final PiMatchType matchType;
+    private final Bmv2HeaderFieldModel field;
+
+    /**
+     * Creates new BMv2 table match field model using the given type and header field.
+     *
+     * @param matchType the match type
+     * @param field the header field
+     */
+    public Bmv2TableMatchFieldModel(PiMatchType matchType, Bmv2HeaderFieldModel field) {
+        checkNotNull(matchType, "Match type can't be null");
+        checkNotNull(field, "Header field can't be null");
+
+        this.matchType = matchType;
+        this.field = field;
+    }
+
+    @Override
+    public PiMatchType matchType() {
+        return matchType;
+    }
+
+    @Override
+    public Bmv2HeaderFieldModel field() {
+        return field;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(matchType, field);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final Bmv2TableMatchFieldModel other = (Bmv2TableMatchFieldModel) obj;
+        return Objects.equal(this.matchType, other.matchType)
+                && Objects.equal(this.field, other.field);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("matchType", matchType)
+                .add("field", field)
+                .toString();
+    }
+
+
+}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2TableModel.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2TableModel.java
new file mode 100644
index 0000000..8226542
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2TableModel.java
@@ -0,0 +1,149 @@
+/*
+ * 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.bmv2.model;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.pi.model.PiActionModel;
+import org.onosproject.net.pi.model.PiTableMatchFieldModel;
+import org.onosproject.net.pi.model.PiTableModel;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * BMv2 table model.
+ */
+@Beta
+public final class Bmv2TableModel implements PiTableModel {
+    private final String name;
+    private final int id;
+    private final int maxSize;
+    private final boolean hasCounters;
+    private final boolean supportAging;
+    private final Set<PiTableMatchFieldModel> matchFields;
+    private final Set<PiActionModel> actions;
+
+    /**
+     * Creates new BMv2 table model.
+     *
+     * @param name the name of table model
+     * @param id the table id
+     * @param maxSize the max size of table model
+     * @param hasCounters true if the table model has counter; null otherwise
+     * @param supportAging true if the table model supports aging; null otherwise
+     * @param matchFields the match fields of table model
+     * @param actions the actions of table model
+     */
+    public Bmv2TableModel(String name, int id,
+                          int maxSize, boolean hasCounters,
+                          boolean supportAging,
+                          Set<Bmv2TableMatchFieldModel> matchFields,
+                          Set<Bmv2ActionModel> actions) {
+        checkNotNull(name, "Model name can't be null");
+        checkArgument(maxSize >= 0, "Max size should more than 0");
+        checkNotNull(matchFields, "Match fields can't be null");
+        checkNotNull(actions, "Actions can't be null");
+        this.name = name;
+        this.id = id;
+        this.maxSize = maxSize;
+        this.hasCounters = hasCounters;
+        this.supportAging = supportAging;
+        this.matchFields = ImmutableSet.copyOf(matchFields);
+        this.actions = ImmutableSet.copyOf(actions);
+    }
+
+    /**
+     * Gets table model id.
+     *
+     * @return table model id
+     */
+    public int id() {
+        return id;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public int maxSize() {
+        return maxSize;
+    }
+
+    @Override
+    public boolean hasCounters() {
+        return hasCounters;
+    }
+
+    @Override
+    public boolean supportsAging() {
+        return supportAging;
+    }
+
+    @Override
+    public Collection<PiTableMatchFieldModel> matchFields() {
+        return matchFields;
+    }
+
+    @Override
+    public Collection<PiActionModel> actions() {
+        return actions;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, id, maxSize, hasCounters, supportAging,
+                            matchFields, actions);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof Bmv2TableModel)) {
+            return false;
+        }
+        Bmv2TableModel that = (Bmv2TableModel) obj;
+        return Objects.equals(name, that.name) &&
+                Objects.equals(id, that.id) &&
+                Objects.equals(maxSize, that.maxSize) &&
+                Objects.equals(hasCounters, that.hasCounters) &&
+                Objects.equals(supportAging, that.supportAging) &&
+                Objects.equals(matchFields, that.matchFields) &&
+                Objects.equals(actions, that.actions);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("name", name)
+                .add("id", id)
+                .add("maxSize", maxSize)
+                .add("hasCounters", hasCounters)
+                .add("supportAging", supportAging)
+                .add("matchFields", matchFields)
+                .add("actions", actions)
+                .toString();
+    }
+}
\ No newline at end of file
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/package-info.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/package-info.java
new file mode 100644
index 0000000..8ac0656
--- /dev/null
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/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.
+ */
+
+/**
+ * BMv2 target models.
+ */
+package org.onosproject.bmv2.model;
\ No newline at end of file
diff --git a/incubator/bmv2/model/src/test/java/org/onosproject/bmv2/model/Bmv2PipelineModelParserTest.java b/incubator/bmv2/model/src/test/java/org/onosproject/bmv2/model/Bmv2PipelineModelParserTest.java
new file mode 100644
index 0000000..f1bd683
--- /dev/null
+++ b/incubator/bmv2/model/src/test/java/org/onosproject/bmv2/model/Bmv2PipelineModelParserTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2016-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.bmv2.model;
+
+import com.eclipsesource.json.Json;
+import com.eclipsesource.json.JsonObject;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.testing.EqualsTester;
+import org.hamcrest.collection.IsIterableContainingInOrder;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.pi.model.PiHeaderFieldModel;
+import org.onosproject.net.pi.model.PiHeaderModel;
+import org.onosproject.net.pi.model.PiHeaderTypeModel;
+import org.onosproject.net.pi.model.PiMatchType;
+import org.onosproject.net.pi.model.PiTableMatchFieldModel;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.hamcrest.core.IsEqual.equalTo;
+
+/**
+ * BMv2 JSON configuration parser test.
+ */
+public class Bmv2PipelineModelParserTest {
+
+    private JsonObject json;
+    private JsonObject json2;
+
+    @Before
+    public void setUp() throws Exception {
+        json = Json.parse(new BufferedReader(new InputStreamReader(
+                this.getClass().getResourceAsStream("/default.json")))).asObject();
+        json2 = Json.parse(new BufferedReader(new InputStreamReader(
+                this.getClass().getResourceAsStream("/default.json")))).asObject();
+    }
+
+    @Test
+    public void testParse() throws Exception {
+        Bmv2PipelineModel config = Bmv2PipelineModelParser.parse(json);
+        Bmv2PipelineModel config2 = Bmv2PipelineModelParser.parse(json2);
+
+        new EqualsTester()
+                .addEqualityGroup(config, config2)
+                .testEquals();
+
+        /* Check header types */
+        Bmv2HeaderTypeModel stdMetaT =
+                (Bmv2HeaderTypeModel) config.headerType("standard_metadata").orElse(null);
+        Bmv2HeaderTypeModel ethernetT =
+                (Bmv2HeaderTypeModel) config.headerType("ethernet_t").orElse(null);
+        Bmv2HeaderTypeModel intrinsicMetaT =
+                (Bmv2HeaderTypeModel) config.headerType("intrinsic_metadata_t").orElse(null);
+
+        Bmv2HeaderTypeModel stdMetaT2 =
+                (Bmv2HeaderTypeModel) config2.headerType("standard_metadata").orElse(null);
+        Bmv2HeaderTypeModel ethernetT2 =
+                (Bmv2HeaderTypeModel) config2.headerType("ethernet_t").orElse(null);
+        Bmv2HeaderTypeModel intrinsicMetaT2 =
+                (Bmv2HeaderTypeModel) config2.headerType("intrinsic_metadata_t").orElse(null);
+
+        new EqualsTester()
+                .addEqualityGroup(stdMetaT, stdMetaT2)
+                .addEqualityGroup(ethernetT, ethernetT2)
+                .addEqualityGroup(intrinsicMetaT, intrinsicMetaT2)
+                .testEquals();
+
+        // existence
+        assertThat("Json parsed value is null", stdMetaT, notNullValue());
+        assertThat("Json parsed value is null", ethernetT, notNullValue());
+        assertThat("Json parsed value is null", intrinsicMetaT, notNullValue());
+
+        // fields size
+        assertThat("Incorrect size for header type fields",
+                   stdMetaT.fields(), hasSize(18));
+        assertThat("Incorrect size for header type fields",
+                   ethernetT.fields(), hasSize(3));
+        assertThat("Incorrect size for header type fields",
+                   intrinsicMetaT.fields(), hasSize(4));
+
+        // check that fields are in order
+        assertThat("Incorrect order for header type fields",
+                   stdMetaT.fields(), IsIterableContainingInOrder.contains(
+                        stdMetaT.field("ingress_port").get(),
+                        stdMetaT.field("egress_spec").get(),
+                        stdMetaT.field("egress_port").get(),
+                        stdMetaT.field("clone_spec").get(),
+                        stdMetaT.field("instance_type").get(),
+                        stdMetaT.field("drop").get(),
+                        stdMetaT.field("recirculate_port").get(),
+                        stdMetaT.field("packet_length").get(),
+                        stdMetaT.field("enq_timestamp").get(),
+                        stdMetaT.field("enq_qdepth").get(),
+                        stdMetaT.field("deq_timedelta").get(),
+                        stdMetaT.field("deq_qdepth").get(),
+                        stdMetaT.field("ingress_global_timestamp").get(),
+                        stdMetaT.field("lf_field_list").get(),
+                        stdMetaT.field("mcast_grp").get(),
+                        stdMetaT.field("resubmit_flag").get(),
+                        stdMetaT.field("egress_rid").get(),
+                        stdMetaT.field("_padding").get()
+                ));
+
+        /* Check actions */
+        Bmv2ActionModel noAction =
+                (Bmv2ActionModel) config.action("NoAction").orElse(null);
+        Bmv2ActionModel setEgressPortAction =
+                (Bmv2ActionModel) config.action("set_egress_port_0").orElse(null);
+        Bmv2ActionModel sendToCpuAction =
+                (Bmv2ActionModel) config.action("send_to_cpu_0").orElse(null);
+        Bmv2ActionModel dropAction =
+                (Bmv2ActionModel) config.action("_drop_0").orElse(null);
+        Bmv2ActionModel processPortCountersCountPacketAction =
+                (Bmv2ActionModel) config.action("process_port_counters_0.count_packet").orElse(null);
+
+
+        Bmv2ActionModel noAction2 =
+                (Bmv2ActionModel) config.action("NoAction").orElse(null);
+        Bmv2ActionModel setEgressPortAction2 =
+                (Bmv2ActionModel) config.action("set_egress_port_0").orElse(null);
+        Bmv2ActionModel sendToCpuAction2 =
+                (Bmv2ActionModel) config.action("send_to_cpu_0").orElse(null);
+        Bmv2ActionModel dropAction2 =
+                (Bmv2ActionModel) config.action("_drop_0").orElse(null);
+        Bmv2ActionModel processPortCountersCountPacketAction2 =
+                (Bmv2ActionModel) config.action("process_port_counters_0.count_packet").orElse(null);
+
+        new EqualsTester()
+                .addEqualityGroup(noAction, noAction2)
+                .addEqualityGroup(setEgressPortAction, setEgressPortAction2)
+                .addEqualityGroup(sendToCpuAction, sendToCpuAction2)
+                .addEqualityGroup(dropAction, dropAction2)
+                .addEqualityGroup(processPortCountersCountPacketAction, processPortCountersCountPacketAction2)
+                .testEquals();
+
+        // existence
+        assertThat("Json parsed value is null", noAction, notNullValue());
+        assertThat("Json parsed value is null", setEgressPortAction, notNullValue());
+        assertThat("Json parsed value is null", sendToCpuAction, notNullValue());
+        assertThat("Json parsed value is null", dropAction, notNullValue());
+        assertThat("Json parsed value is null", processPortCountersCountPacketAction, notNullValue());
+
+        // runtime data size
+        assertThat("Incorrect size for action runtime data",
+                   noAction.params().size(), is(equalTo(0)));
+        assertThat("Incorrect size for action runtime data",
+                   setEgressPortAction.params().size(), is(equalTo(1)));
+        assertThat("Incorrect size for action runtime data",
+                   sendToCpuAction.params().size(), is(equalTo(0)));
+        assertThat("Incorrect size for action runtime data",
+                   dropAction.params().size(), is(equalTo(0)));
+        assertThat("Incorrect size for action runtime data",
+                   processPortCountersCountPacketAction.params().size(), is(equalTo(0)));
+
+        // runtime data existence and parsing
+        assertThat("Parsed Json value is null",
+                   setEgressPortAction.param("port").orElse(null), notNullValue());
+        assertThat("Incorrect value for action runtime data bitwidth",
+                   setEgressPortAction.param("port").get().bitWidth(), is(equalTo(9)));
+
+
+        /* Check tables */
+        Bmv2TableModel table0 =
+                (Bmv2TableModel) config.table("table0").orElse(null);
+        Bmv2TableModel table02 =
+                (Bmv2TableModel) config2.table("table0").orElse(null);
+
+        new EqualsTester()
+                .addEqualityGroup(table0, table02)
+                .testEquals();
+
+        // existence
+        assertThat("Parsed Json value is null", table0, notNullValue());
+
+        // id and name correspondence
+        assertThat("Incorrect value for table name",
+                   table0.name(), is(equalTo("table0")));
+
+        Set<PiTableMatchFieldModel> matchFields = Sets.newHashSet(table0.matchFields());
+
+        // keys size
+        assertThat("Incorrect size for table keys",
+                   matchFields.size(), is(equalTo(4)));
+
+        Set<PiMatchType> matchTypes = matchFields.stream()
+                .map(PiTableMatchFieldModel::matchType)
+                .collect(Collectors.toSet());
+
+        // key match type
+        assertThat("Incorrect value for table key match type",
+                   matchTypes, containsInAnyOrder(PiMatchType.TERNARY));
+
+        Set<PiHeaderTypeModel> headerTypeModels = matchFields.stream()
+                .map(PiTableMatchFieldModel::field)
+                .map(PiHeaderFieldModel::header)
+                .map(PiHeaderModel::type)
+                .collect(Collectors.toSet());
+
+        // header type
+        assertThat("Incorrect value for table key header type",
+                   headerTypeModels, containsInAnyOrder(ethernetT, stdMetaT));
+
+    }
+}
\ No newline at end of file
diff --git a/incubator/bmv2/model/src/test/resources/default.json b/incubator/bmv2/model/src/test/resources/default.json
new file mode 100644
index 0000000..f0bcc71
--- /dev/null
+++ b/incubator/bmv2/model/src/test/resources/default.json
@@ -0,0 +1,777 @@
+{
+  "program" : "default.p4",
+  "__meta__" : null,
+  "header_types" : [
+    {
+      "name" : "scalars",
+      "id" : 0,
+      "fields" : [
+        ["tmp", 32, false],
+        ["tmp_0", 32, false]
+      ]
+    },
+    {
+      "name" : "ethernet_t",
+      "id" : 1,
+      "fields" : [
+        ["dstAddr", 48, false],
+        ["srcAddr", 48, false],
+        ["etherType", 16, false]
+      ]
+    },
+    {
+      "name" : "ipv4_t",
+      "id" : 2,
+      "fields" : [
+        ["version", 4, false],
+        ["ihl", 4, false],
+        ["diffserv", 8, false],
+        ["totalLen", 16, false],
+        ["identification", 16, false],
+        ["flags", 3, false],
+        ["fragOffset", 13, false],
+        ["ttl", 8, false],
+        ["protocol", 8, false],
+        ["hdrChecksum", 16, false],
+        ["srcAddr", 32, false],
+        ["dstAddr", 32, false]
+      ]
+    },
+    {
+      "name" : "tcp_t",
+      "id" : 3,
+      "fields" : [
+        ["srcPort", 16, false],
+        ["dstPort", 16, false],
+        ["seqNo", 32, false],
+        ["ackNo", 32, false],
+        ["dataOffset", 4, false],
+        ["res", 3, false],
+        ["ecn", 3, false],
+        ["ctrl", 6, false],
+        ["window", 16, false],
+        ["checksum", 16, false],
+        ["urgentPtr", 16, false]
+      ]
+    },
+    {
+      "name" : "udp_t",
+      "id" : 4,
+      "fields" : [
+        ["srcPort", 16, false],
+        ["dstPort", 16, false],
+        ["length_", 16, false],
+        ["checksum", 16, false]
+      ]
+    },
+    {
+      "name" : "ecmp_metadata_t",
+      "id" : 5,
+      "fields" : [
+        ["groupId", 16, false],
+        ["selector", 16, false]
+      ]
+    },
+    {
+      "name" : "wcmp_meta_t",
+      "id" : 6,
+      "fields" : [
+        ["groupId", 16, false],
+        ["numBits", 8, false],
+        ["selector", 64, false]
+      ]
+    },
+    {
+      "name" : "intrinsic_metadata_t",
+      "id" : 7,
+      "fields" : [
+        ["ingress_global_timestamp", 32, false],
+        ["lf_field_list", 32, false],
+        ["mcast_grp", 16, false],
+        ["egress_rid", 16, false]
+      ]
+    },
+    {
+      "name" : "standard_metadata",
+      "id" : 8,
+      "fields" : [
+        ["ingress_port", 9, false],
+        ["egress_spec", 9, false],
+        ["egress_port", 9, false],
+        ["clone_spec", 32, false],
+        ["instance_type", 32, false],
+        ["drop", 1, false],
+        ["recirculate_port", 16, false],
+        ["packet_length", 32, false],
+        ["enq_timestamp", 32, false],
+        ["enq_qdepth", 19, false],
+        ["deq_timedelta", 32, false],
+        ["deq_qdepth", 19, false],
+        ["ingress_global_timestamp", 48, false],
+        ["lf_field_list", 32, false],
+        ["mcast_grp", 16, false],
+        ["resubmit_flag", 1, false],
+        ["egress_rid", 16, false],
+        ["_padding", 5, false]
+      ]
+    }
+  ],
+  "headers" : [
+    {
+      "name" : "scalars",
+      "id" : 0,
+      "header_type" : "scalars",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "standard_metadata",
+      "id" : 1,
+      "header_type" : "standard_metadata",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "ethernet",
+      "id" : 2,
+      "header_type" : "ethernet_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "ipv4",
+      "id" : 3,
+      "header_type" : "ipv4_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "tcp",
+      "id" : 4,
+      "header_type" : "tcp_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "udp",
+      "id" : 5,
+      "header_type" : "udp_t",
+      "metadata" : false,
+      "pi_omit" : true
+    },
+    {
+      "name" : "ecmp_metadata",
+      "id" : 6,
+      "header_type" : "ecmp_metadata_t",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "wcmp_meta",
+      "id" : 7,
+      "header_type" : "wcmp_meta_t",
+      "metadata" : true,
+      "pi_omit" : true
+    },
+    {
+      "name" : "intrinsic_metadata",
+      "id" : 8,
+      "header_type" : "intrinsic_metadata_t",
+      "metadata" : true,
+      "pi_omit" : true
+    }
+  ],
+  "header_stacks" : [],
+  "field_lists" : [],
+  "errors" : [
+    ["NoError", 0],
+    ["PacketTooShort", 1],
+    ["NoMatch", 2],
+    ["StackOutOfBounds", 3],
+    ["HeaderTooShort", 4],
+    ["ParserTimeout", 5]
+  ],
+  "enums" : [],
+  "parsers" : [
+    {
+      "name" : "parser",
+      "id" : 0,
+      "init_state" : "start",
+      "parse_states" : [
+        {
+          "name" : "parse_ethernet",
+          "id" : 0,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "ethernet"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "0x0800",
+              "mask" : null,
+              "next_state" : "parse_ipv4"
+            },
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "etherType"]
+            }
+          ]
+        },
+        {
+          "name" : "parse_ipv4",
+          "id" : 1,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "ipv4"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "0x000006",
+              "mask" : null,
+              "next_state" : "parse_tcp"
+            },
+            {
+              "value" : "0x000011",
+              "mask" : null,
+              "next_state" : "parse_udp"
+            },
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : [
+            {
+              "type" : "field",
+              "value" : ["ipv4", "fragOffset"]
+            },
+            {
+              "type" : "field",
+              "value" : ["ipv4", "protocol"]
+            }
+          ]
+        },
+        {
+          "name" : "parse_tcp",
+          "id" : 2,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "tcp"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : []
+        },
+        {
+          "name" : "parse_udp",
+          "id" : 3,
+          "parser_ops" : [
+            {
+              "parameters" : [
+                {
+                  "type" : "regular",
+                  "value" : "udp"
+                }
+              ],
+              "op" : "extract"
+            }
+          ],
+          "transitions" : [
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : null
+            }
+          ],
+          "transition_key" : []
+        },
+        {
+          "name" : "start",
+          "id" : 4,
+          "parser_ops" : [],
+          "transitions" : [
+            {
+              "value" : "default",
+              "mask" : null,
+              "next_state" : "parse_ethernet"
+            }
+          ],
+          "transition_key" : []
+        }
+      ]
+    }
+  ],
+  "deparsers" : [
+    {
+      "name" : "deparser",
+      "id" : 0,
+      "source_info" : {
+        "filename" : "./include/parsers.p4",
+        "line" : 34,
+        "column" : 8,
+        "source_fragment" : "DeparserImpl"
+      },
+      "order" : ["ethernet", "ipv4", "udp", "tcp"]
+    }
+  ],
+  "meter_arrays" : [],
+  "counter_arrays" : [
+    {
+      "name" : "process_port_counters_0.egress_port_counter",
+      "id" : 0,
+      "source_info" : {
+        "filename" : "./include/port_counters.p4",
+        "line" : 5,
+        "column" : 41,
+        "source_fragment" : "egress_port_counter"
+      },
+      "size" : 254,
+      "is_direct" : false
+    },
+    {
+      "name" : "process_port_counters_0.ingress_port_counter",
+      "id" : 1,
+      "source_info" : {
+        "filename" : "./include/port_counters.p4",
+        "line" : 6,
+        "column" : 41,
+        "source_fragment" : "ingress_port_counter"
+      },
+      "size" : 254,
+      "is_direct" : false
+    }
+  ],
+  "register_arrays" : [],
+  "calculations" : [],
+  "learn_lists" : [],
+  "actions" : [
+    {
+      "name" : "NoAction",
+      "id" : 0,
+      "runtime_data" : [],
+      "primitives" : []
+    },
+    {
+      "name" : "NoAction",
+      "id" : 1,
+      "runtime_data" : [],
+      "primitives" : []
+    },
+    {
+      "name" : "set_egress_port_0",
+      "id" : 2,
+      "runtime_data" : [
+        {
+          "name" : "port",
+          "bitwidth" : 9
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "default.p4",
+            "line" : 22,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port"
+          }
+        }
+      ]
+    },
+    {
+      "name" : "send_to_cpu_0",
+      "id" : 3,
+      "runtime_data" : [],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x00ff"
+            }
+          ],
+          "source_info" : {
+            "filename" : "default.p4",
+            "line" : 26,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = 9w255"
+          }
+        }
+      ]
+    },
+    {
+      "name" : "_drop_0",
+      "id" : 4,
+      "runtime_data" : [],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01ff"
+            }
+          ],
+          "source_info" : {
+            "filename" : "default.p4",
+            "line" : 30,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = 9w511"
+          }
+        }
+      ]
+    },
+    {
+      "name" : "process_port_counters_0.count_packet",
+      "id" : 5,
+      "runtime_data" : [],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "&",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "field",
+                        "value" : ["standard_metadata", "ingress_port"]
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "hexstr",
+                    "value" : "0xffffffff"
+                  }
+                }
+              }
+            }
+          ]
+        },
+        {
+          "op" : "count",
+          "parameters" : [
+            {
+              "type" : "counter_array",
+              "value" : "process_port_counters_0.ingress_port_counter"
+            },
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/port_counters.p4",
+            "line" : 8,
+            "column" : 8,
+            "source_fragment" : "ingress_port_counter.count((bit<32>)(bit<8>)standard_metadata.ingress_port)"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp_0"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "&",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "field",
+                        "value" : ["standard_metadata", "egress_spec"]
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "hexstr",
+                    "value" : "0xffffffff"
+                  }
+                }
+              }
+            }
+          ]
+        },
+        {
+          "op" : "count",
+          "parameters" : [
+            {
+              "type" : "counter_array",
+              "value" : "process_port_counters_0.egress_port_counter"
+            },
+            {
+              "type" : "field",
+              "value" : ["scalars", "tmp_0"]
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/port_counters.p4",
+            "line" : 9,
+            "column" : 8,
+            "source_fragment" : "egress_port_counter.count((bit<32>)(bit<8>)standard_metadata.egress_spec)"
+          }
+        }
+      ]
+    }
+  ],
+  "pipelines" : [
+    {
+      "name" : "ingress",
+      "id" : 0,
+      "source_info" : {
+        "filename" : "default.p4",
+        "line" : 9,
+        "column" : 8,
+        "source_fragment" : "ingress"
+      },
+      "init_table" : "table0",
+      "tables" : [
+        {
+          "name" : "table0",
+          "id" : 0,
+          "source_info" : {
+            "filename" : "default.p4",
+            "line" : 32,
+            "column" : 10,
+            "source_fragment" : "table0"
+          },
+          "key" : [
+            {
+              "match_type" : "ternary",
+              "target" : ["standard_metadata", "ingress_port"],
+              "mask" : null
+            },
+            {
+              "match_type" : "ternary",
+              "target" : ["ethernet", "dstAddr"],
+              "mask" : null
+            },
+            {
+              "match_type" : "ternary",
+              "target" : ["ethernet", "srcAddr"],
+              "mask" : null
+            },
+            {
+              "match_type" : "ternary",
+              "target" : ["ethernet", "etherType"],
+              "mask" : null
+            }
+          ],
+          "match_type" : "ternary",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [2, 3, 4, 0],
+          "actions" : ["set_egress_port_0", "send_to_cpu_0", "_drop_0", "NoAction"],
+          "base_default_next" : "node_3",
+          "next_tables" : {
+            "set_egress_port_0" : "node_3",
+            "send_to_cpu_0" : "node_3",
+            "_drop_0" : "node_3",
+            "NoAction" : "node_3"
+          },
+          "default_entry" : {
+            "action_id" : 0,
+            "action_const" : false,
+            "action_data" : [],
+            "action_entry_const" : false
+          }
+        },
+        {
+          "name" : "process_port_counters_0.port_count_table",
+          "id" : 1,
+          "source_info" : {
+            "filename" : "./include/port_counters.p4",
+            "line" : 11,
+            "column" : 10,
+            "source_fragment" : "port_count_table"
+          },
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [5, 1],
+          "actions" : ["process_port_counters_0.count_packet", "NoAction"],
+          "base_default_next" : null,
+          "next_tables" : {
+            "process_port_counters_0.count_packet" : null,
+            "NoAction" : null
+          },
+          "default_entry" : {
+            "action_id" : 1,
+            "action_const" : false,
+            "action_data" : [],
+            "action_entry_const" : false
+          }
+        }
+      ],
+      "action_profiles" : [],
+      "conditionals" : [
+        {
+          "name" : "node_3",
+          "id" : 0,
+          "source_info" : {
+            "filename" : "./include/port_counters.p4",
+            "line" : 17,
+            "column" : 12,
+            "source_fragment" : "standard_metadata.egress_spec < 9w254"
+          },
+          "expression" : {
+            "type" : "expression",
+            "value" : {
+              "op" : "<",
+              "left" : {
+                "type" : "field",
+                "value" : ["standard_metadata", "egress_spec"]
+              },
+              "right" : {
+                "type" : "hexstr",
+                "value" : "0x00fe"
+              }
+            }
+          },
+          "false_next" : null,
+          "true_next" : "process_port_counters_0.port_count_table"
+        }
+      ]
+    },
+    {
+      "name" : "egress",
+      "id" : 1,
+      "source_info" : {
+        "filename" : "default.p4",
+        "line" : 54,
+        "column" : 8,
+        "source_fragment" : "egress"
+      },
+      "init_table" : null,
+      "tables" : [],
+      "action_profiles" : [],
+      "conditionals" : []
+    }
+  ],
+  "checksums" : [],
+  "force_arith" : [],
+  "extern_instances" : [],
+  "field_aliases" : [
+    [
+      "queueing_metadata.enq_timestamp",
+      ["standard_metadata", "enq_timestamp"]
+    ],
+    [
+      "queueing_metadata.enq_qdepth",
+      ["standard_metadata", "enq_qdepth"]
+    ],
+    [
+      "queueing_metadata.deq_timedelta",
+      ["standard_metadata", "deq_timedelta"]
+    ],
+    [
+      "queueing_metadata.deq_qdepth",
+      ["standard_metadata", "deq_qdepth"]
+    ],
+    [
+      "intrinsic_metadata.ingress_global_timestamp",
+      ["standard_metadata", "ingress_global_timestamp"]
+    ],
+    [
+      "intrinsic_metadata.lf_field_list",
+      ["standard_metadata", "lf_field_list"]
+    ],
+    [
+      "intrinsic_metadata.mcast_grp",
+      ["standard_metadata", "mcast_grp"]
+    ],
+    [
+      "intrinsic_metadata.resubmit_flag",
+      ["standard_metadata", "resubmit_flag"]
+    ],
+    [
+      "intrinsic_metadata.egress_rid",
+      ["standard_metadata", "egress_rid"]
+    ]
+  ]
+}
\ No newline at end of file