[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/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