[ONOS-7905] Add default implementation for kubernetes data model

Change-Id: I08e9266dec2050e8299e4189745608a6e03fd06e
diff --git a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sIpam.java b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sIpam.java
new file mode 100644
index 0000000..cb488b3
--- /dev/null
+++ b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sIpam.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.api;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onlab.packet.IpAddress;
+
+/**
+ * Default implementation of kubernetes IPAM instance.
+ */
+public final class DefaultK8sIpam implements K8sIpam {
+
+    private final IpAddress ipAddress;
+    private final String networkId;
+
+    // private constructor not intended for external invocation
+    public DefaultK8sIpam(IpAddress ipAddress, String networkId) {
+        this.ipAddress = ipAddress;
+        this.networkId = networkId;
+    }
+
+    @Override
+    public IpAddress ipAddress() {
+        return ipAddress;
+    }
+
+    @Override
+    public String networkId() {
+        return networkId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        DefaultK8sIpam that = (DefaultK8sIpam) o;
+        return Objects.equal(ipAddress, that.ipAddress) &&
+                Objects.equal(networkId, that.networkId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(ipAddress, networkId);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("ipAddress", ipAddress)
+                .add("networkId", networkId)
+                .toString();
+    }
+}
diff --git a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sNetwork.java b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sNetwork.java
new file mode 100644
index 0000000..3ac1230
--- /dev/null
+++ b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sNetwork.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.api;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onlab.packet.IpAddress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Default implementation of kubernetes network.
+ */
+public final class DefaultK8sNetwork implements K8sNetwork {
+
+    private static final int DEFAULT_MTU = 1500;
+
+    private final String networkId;
+    private final Type type;
+    private final Integer mtu;
+    private final String segmentId;
+    private final IpAddress gatewayIp;
+    private final String cidr;
+
+    private static final String NOT_NULL_MSG = "Network % cannot be null";
+
+    // private constructor not intended for external invocation
+    private DefaultK8sNetwork(String networkId, Type type, Integer mtu,
+                              String segmentId, IpAddress gatewayIp, String cidr) {
+        this.networkId = networkId;
+        this.type = type;
+        this.mtu = mtu;
+        this.segmentId = segmentId;
+        this.gatewayIp = gatewayIp;
+        this.cidr = cidr;
+    }
+
+    @Override
+    public String networkId() {
+        return networkId;
+    }
+
+    @Override
+    public Type type() {
+        return type;
+    }
+
+    @Override
+    public Integer mtu() {
+        return mtu;
+    }
+
+    @Override
+    public String segmentId() {
+        return segmentId;
+    }
+
+    @Override
+    public IpAddress gatewayIp() {
+        return gatewayIp;
+    }
+
+    @Override
+    public String cidr() {
+        return cidr;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        DefaultK8sNetwork that = (DefaultK8sNetwork) o;
+        return Objects.equal(networkId, that.networkId) &&
+                type == that.type &&
+                Objects.equal(mtu, that.mtu) &&
+                Objects.equal(segmentId, that.segmentId) &&
+                Objects.equal(gatewayIp, that.gatewayIp) &&
+                Objects.equal(cidr, that.cidr);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(networkId, type, mtu, segmentId, gatewayIp, cidr);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("networkId", networkId)
+                .add("type", type)
+                .add("mtu", mtu)
+                .add("segmentId", segmentId)
+                .add("gatewayIp", gatewayIp)
+                .add("cidr", cidr)
+                .toString();
+    }
+
+    /**
+     * Returns new builder instance.
+     *
+     * @return kubernetes network builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Default implementation of kubernetes network builder.
+     */
+    public static final class Builder implements K8sNetwork.Builder {
+
+        private String networkId;
+        private Type type;
+        private Integer mtu;
+        private String segmentId;
+        private IpAddress gatewayIp;
+        private String cidr;
+
+        @Override
+        public K8sNetwork build() {
+            checkArgument(networkId != null, NOT_NULL_MSG, "networkId");
+            checkArgument(type != null, NOT_NULL_MSG, "type");
+            checkArgument(segmentId != null, NOT_NULL_MSG, "segmentId");
+            checkArgument(gatewayIp != null, NOT_NULL_MSG, "gatewayIp");
+            checkArgument(cidr != null, NOT_NULL_MSG, "cidr");
+
+            if (mtu == null) {
+                mtu = DEFAULT_MTU;
+            }
+
+            return new DefaultK8sNetwork(networkId, type, mtu, segmentId, gatewayIp, cidr);
+        }
+
+        @Override
+        public Builder networkId(String networkId) {
+            this.networkId = networkId;
+            return this;
+        }
+
+        @Override
+        public Builder type(Type type) {
+            this.type = type;
+            return this;
+        }
+
+        @Override
+        public Builder mtu(Integer mtu) {
+            this.mtu = mtu;
+            return this;
+        }
+
+        @Override
+        public Builder segmentId(String segmentId) {
+            this.segmentId = segmentId;
+            return this;
+        }
+
+        @Override
+        public Builder gatewayIp(IpAddress ipAddress) {
+            this.gatewayIp = ipAddress;
+            return this;
+        }
+
+        @Override
+        public Builder cidr(String cidr) {
+            this.cidr = cidr;
+            return this;
+        }
+    }
+}
diff --git a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sPort.java b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sPort.java
new file mode 100644
index 0000000..e545f69
--- /dev/null
+++ b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/DefaultK8sPort.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.api;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Default implementation of kubernetes port.
+ */
+public final class DefaultK8sPort implements K8sPort {
+
+    private static final String NOT_NULL_MSG = "Port % cannot be null";
+
+    private final String networkId;
+    private final String portId;
+    private final MacAddress macAddress;
+    private final IpAddress ipAddress;
+    private final DeviceId deviceId;
+    private final PortNumber portNumber;
+    private final State state;
+
+    // private constructor not intended for external invocation
+    private DefaultK8sPort(String networkId, String portId, MacAddress macAddress,
+                           IpAddress ipAddress, DeviceId deviceId,
+                           PortNumber portNumber, State state) {
+        this.networkId = networkId;
+        this.portId = portId;
+        this.macAddress = macAddress;
+        this.ipAddress = ipAddress;
+        this.deviceId = deviceId;
+        this.portNumber = portNumber;
+        this.state = state;
+    }
+
+    @Override
+    public String networkId() {
+        return networkId;
+    }
+
+    @Override
+    public String portId() {
+        return portId;
+    }
+
+    @Override
+    public MacAddress macAddress() {
+        return macAddress;
+    }
+
+    @Override
+    public IpAddress ipAddress() {
+        return ipAddress;
+    }
+
+    @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    @Override
+    public PortNumber portNumber() {
+        return portNumber;
+    }
+
+    @Override
+    public State state() {
+        return state;
+    }
+
+    @Override
+    public K8sPort updateState(State newState) {
+        return new Builder()
+                .networkId(networkId)
+                .portId(portId)
+                .macAddress(macAddress)
+                .ipAddress(ipAddress)
+                .deviceId(deviceId)
+                .portNumber(portNumber)
+                .state(newState)
+                .build();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        DefaultK8sPort that = (DefaultK8sPort) o;
+        return Objects.equal(networkId, that.networkId) &&
+                Objects.equal(portId, that.portId) &&
+                Objects.equal(macAddress, that.macAddress) &&
+                Objects.equal(ipAddress, that.ipAddress) &&
+                Objects.equal(deviceId, that.deviceId) &&
+                Objects.equal(portNumber, that.portNumber) &&
+                state == that.state;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(networkId, portId, macAddress, ipAddress,
+                deviceId, portNumber, state);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("networkId", networkId)
+                .add("portId", portId)
+                .add("macAddress", macAddress)
+                .add("ipAddress", ipAddress)
+                .add("deviceId", deviceId)
+                .add("portNumber", portNumber)
+                .add("state", state)
+                .toString();
+    }
+
+    /**
+     * Returns new builder instance.
+     *
+     * @return kubernetes port builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Default builder implementation.
+     */
+    public static final class Builder implements K8sPort.Builder {
+
+        private String networkId;
+        private String portId;
+        private MacAddress macAddress;
+        private IpAddress ipAddress;
+        private DeviceId deviceId;
+        private PortNumber portNumber;
+        private State state;
+
+        // private constructor not intended to use from external
+        private Builder() {
+        }
+
+        @Override
+        public K8sPort build() {
+            checkArgument(networkId != null, NOT_NULL_MSG, "networkId");
+            checkArgument(portId != null, NOT_NULL_MSG, "portId");
+            checkArgument(macAddress != null, NOT_NULL_MSG, "macAddress");
+            checkArgument(ipAddress != null, NOT_NULL_MSG, "ipAddress");
+            checkArgument(deviceId != null, NOT_NULL_MSG, "deviceId");
+            checkArgument(portNumber != null, NOT_NULL_MSG, "portNumber");
+            checkArgument(state != null, NOT_NULL_MSG, "state");
+
+            return new DefaultK8sPort(networkId, portId, macAddress, ipAddress,
+                    deviceId, portNumber, state);
+        }
+
+        @Override
+        public Builder networkId(String networkId) {
+            this.networkId = networkId;
+            return this;
+        }
+
+        @Override
+        public Builder portId(String portId) {
+            this.portId = portId;
+            return this;
+        }
+
+        @Override
+        public Builder macAddress(MacAddress macAddress) {
+            this.macAddress = macAddress;
+            return this;
+        }
+
+        @Override
+        public Builder ipAddress(IpAddress ipAddress) {
+            this.ipAddress = ipAddress;
+            return this;
+        }
+
+        @Override
+        public Builder deviceId(DeviceId deviceId) {
+            this.deviceId = deviceId;
+            return this;
+        }
+
+        @Override
+        public Builder portNumber(PortNumber portNumber) {
+            this.portNumber = portNumber;
+            return this;
+        }
+
+        @Override
+        public Builder state(State state) {
+            this.state = state;
+            return this;
+        }
+    }
+}
diff --git a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpam.java b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpam.java
index 57f2130..9969f30 100644
--- a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpam.java
+++ b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpam.java
@@ -27,7 +27,7 @@
      *
      * @return IP address
      */
-    IpAddress ipaddress();
+    IpAddress ipAddress();
 
     /**
      * Returns the kubernetes network ID.
diff --git a/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sIpamTest.java b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sIpamTest.java
new file mode 100644
index 0000000..bfb5670
--- /dev/null
+++ b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sIpamTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.api;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Unit tests for the default kubernetes IPAM.
+ */
+public class DefaultK8sIpamTest {
+
+    private static final IpAddress IP_ADDRESS_1 = IpAddress.valueOf("10.10.10.10");
+    private static final IpAddress IP_ADDRESS_2 = IpAddress.valueOf("20.20.20.20");
+    private static final String NETWORK_ID_1 = "network-1";
+    private static final String NETWORK_ID_2 = "network-2";
+
+    private K8sIpam ipam1;
+    private K8sIpam sameAsIpam1;
+    private K8sIpam ipam2;
+
+    /**
+     * Tests class immutability.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultK8sIpam.class);
+    }
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+        ipam1 = new DefaultK8sIpam(IP_ADDRESS_1, NETWORK_ID_1);
+        sameAsIpam1 = new DefaultK8sIpam(IP_ADDRESS_1, NETWORK_ID_1);
+        ipam2 = new DefaultK8sIpam(IP_ADDRESS_2, NETWORK_ID_2);
+    }
+
+    /**
+     * Tests object equality.
+     */
+    @Test
+    public void testEquality() {
+        new EqualsTester().addEqualityGroup(ipam1, sameAsIpam1)
+                .addEqualityGroup(ipam2)
+                .testEquals();
+    }
+
+    /**
+     * Test object construction.
+     */
+    @Test
+    public void testConstruction() {
+        K8sIpam ipam = ipam1;
+
+        assertEquals(IP_ADDRESS_1, ipam.ipAddress());
+        assertEquals(NETWORK_ID_1, ipam.networkId());
+    }
+}
diff --git a/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sNetworkTest.java b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sNetworkTest.java
new file mode 100644
index 0000000..727b0ad
--- /dev/null
+++ b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sNetworkTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.api;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Unit tests for the default kubernetes network class.
+ */
+public class DefaultK8sNetworkTest {
+
+    private static final String NETWORK_ID_1 = "network-1";
+    private static final String NETWORK_ID_2 = "network-2";
+    private static final K8sNetwork.Type TYPE_1 = K8sNetwork.Type.VXLAN;
+    private static final K8sNetwork.Type TYPE_2 = K8sNetwork.Type.GENEVE;
+    private static final Integer MTU_1 = 1500;
+    private static final Integer MTU_2 = 1600;
+    private static final String SEGMENT_ID_1 = "1";
+    private static final String SEGMENT_ID_2 = "2";
+    private static final IpAddress GATEWAY_IP_1 = IpAddress.valueOf("10.10.10.1");
+    private static final IpAddress GATEWAY_IP_2 = IpAddress.valueOf("20.20.20.1");
+    private static final String CIDR_1 = "32";
+    private static final String CIDR_2 = "32";
+
+    private K8sNetwork k8sNetwork1;
+    private K8sNetwork sameAsK8sNetwork1;
+    private K8sNetwork k8sNetwork2;
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+        k8sNetwork1 = DefaultK8sNetwork.builder()
+                .networkId(NETWORK_ID_1)
+                .type(TYPE_1)
+                .mtu(MTU_1)
+                .segmentId(SEGMENT_ID_1)
+                .gatewayIp(GATEWAY_IP_1)
+                .cidr(CIDR_1)
+                .build();
+
+        sameAsK8sNetwork1 = DefaultK8sNetwork.builder()
+                .networkId(NETWORK_ID_1)
+                .type(TYPE_1)
+                .mtu(MTU_1)
+                .segmentId(SEGMENT_ID_1)
+                .gatewayIp(GATEWAY_IP_1)
+                .cidr(CIDR_1)
+                .build();
+
+        k8sNetwork2 = DefaultK8sNetwork.builder()
+                .networkId(NETWORK_ID_2)
+                .type(TYPE_2)
+                .mtu(MTU_2)
+                .segmentId(SEGMENT_ID_2)
+                .gatewayIp(GATEWAY_IP_2)
+                .cidr(CIDR_2)
+                .build();
+    }
+
+    /**
+     * Tests class immutability.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultK8sNetwork.class);
+    }
+
+    /**
+     * Tests object equality.
+     */
+    @Test
+    public void testEquality() {
+        new EqualsTester().addEqualityGroup(k8sNetwork1, sameAsK8sNetwork1)
+                .addEqualityGroup(k8sNetwork2)
+                .testEquals();
+    }
+
+    /**
+     * Test object construction.
+     */
+    @Test
+    public void testConstruction() {
+        K8sNetwork k8sNetwork = k8sNetwork1;
+
+        assertEquals(NETWORK_ID_1, k8sNetwork.networkId());
+        assertEquals(TYPE_1, k8sNetwork.type());
+        assertEquals(MTU_1, k8sNetwork.mtu());
+        assertEquals(SEGMENT_ID_1, k8sNetwork.segmentId());
+        assertEquals(GATEWAY_IP_1, k8sNetwork.gatewayIp());
+        assertEquals(CIDR_1, k8sNetwork.cidr());
+    }
+}
diff --git a/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sPortTest.java b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sPortTest.java
new file mode 100644
index 0000000..0315a7f
--- /dev/null
+++ b/apps/k8s-networking/api/src/test/java/org/onosproject/k8snetworking/api/DefaultK8sPortTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.api;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.k8snetworking.api.K8sPort.State;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertSame;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+import static org.onosproject.k8snetworking.api.K8sPort.State.ACTIVE;
+import static org.onosproject.k8snetworking.api.K8sPort.State.INACTIVE;
+
+/**
+ * Unit tests for the default kubernetes port class.
+ */
+public class DefaultK8sPortTest {
+
+    private static final String NETWORK_ID_1 = "network-1";
+    private static final String NETWORK_ID_2 = "network-2";
+    private static final String PORT_ID_1 = "port-1";
+    private static final String PORT_ID_2 = "port-2";
+    private static final MacAddress MAC_ADDRESS_1 = MacAddress.valueOf("00:11:22:33:44:55");
+    private static final MacAddress MAC_ADDRESS_2 = MacAddress.valueOf("11:22:33:44:55:66");
+    private static final IpAddress IP_ADDRESS_1 = IpAddress.valueOf("10.10.10.10");
+    private static final IpAddress IP_ADDRESS_2 = IpAddress.valueOf("20.20.20.20");
+    private static final DeviceId DEVICE_ID_1 = DeviceId.deviceId("of:000000000000001");
+    private static final DeviceId DEVICE_ID_2 = DeviceId.deviceId("of:000000000000002");
+    private static final PortNumber PORT_NUMBER_1 = PortNumber.portNumber(1);
+    private static final PortNumber PORT_NUMBER_2 = PortNumber.portNumber(2);
+    private static final State STATE_1 = ACTIVE;
+    private static final State STATE_2 = INACTIVE;
+
+    private K8sPort port1;
+    private K8sPort sameAsPort1;
+    private K8sPort port2;
+
+    /**
+     * Tests class immutability.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(DefaultK8sPort.class);
+    }
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+        port1 = DefaultK8sPort.builder()
+                .networkId(NETWORK_ID_1)
+                .portId(PORT_ID_1)
+                .macAddress(MAC_ADDRESS_1)
+                .ipAddress(IP_ADDRESS_1)
+                .deviceId(DEVICE_ID_1)
+                .portNumber(PORT_NUMBER_1)
+                .state(STATE_1)
+                .build();
+
+        sameAsPort1 = DefaultK8sPort.builder()
+                .networkId(NETWORK_ID_1)
+                .portId(PORT_ID_1)
+                .macAddress(MAC_ADDRESS_1)
+                .ipAddress(IP_ADDRESS_1)
+                .deviceId(DEVICE_ID_1)
+                .portNumber(PORT_NUMBER_1)
+                .state(STATE_1)
+                .build();
+
+        port2 = DefaultK8sPort.builder()
+                .networkId(NETWORK_ID_2)
+                .portId(PORT_ID_2)
+                .macAddress(MAC_ADDRESS_2)
+                .ipAddress(IP_ADDRESS_2)
+                .deviceId(DEVICE_ID_2)
+                .portNumber(PORT_NUMBER_2)
+                .state(STATE_2)
+                .build();
+    }
+
+    /**
+     * Tests object equality.
+     */
+    @Test
+    public void testEquality() {
+        new EqualsTester().addEqualityGroup(port1, sameAsPort1)
+                .addEqualityGroup(port2)
+                .testEquals();
+    }
+
+    /**
+     * Test object construction.
+     */
+    @Test
+    public void testConstruction() {
+        K8sPort port = port1;
+
+        assertEquals(NETWORK_ID_1, port.networkId());
+        assertEquals(PORT_ID_1, port.portId());
+        assertEquals(MAC_ADDRESS_1, port.macAddress());
+        assertEquals(IP_ADDRESS_1, port.ipAddress());
+        assertEquals(DEVICE_ID_1, port.deviceId());
+        assertEquals(PORT_NUMBER_1, port.portNumber());
+        assertSame(STATE_1, port.state());
+    }
+}
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sIpamCodec.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sIpamCodec.java
new file mode 100644
index 0000000..695156c
--- /dev/null
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sIpamCodec.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.k8snetworking.api.DefaultK8sIpam;
+import org.onosproject.k8snetworking.api.K8sIpam;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubernetes IPAM codec used for serializing and de-serializing JSON string.
+ */
+public final class K8sIpamCodec extends JsonCodec<K8sIpam> {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String IP_ADDRESS = "ipAddress";
+    private static final String NETWORK_ID = "networkId";
+
+    private static final String MISSING_MESSAGE = " is required in K8sIPAM";
+
+    @Override
+    public ObjectNode encode(K8sIpam ipam, CodecContext context) {
+        checkNotNull(ipam, "Kubernetes IPAM cannot be null");
+
+        return context.mapper().createObjectNode()
+                .put(IP_ADDRESS, ipam.ipAddress().toString())
+                .put(NETWORK_ID, ipam.networkId());
+    }
+
+    @Override
+    public K8sIpam decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        String ipAddress = nullIsIllegal(json.get(IP_ADDRESS).asText(),
+                IP_ADDRESS + MISSING_MESSAGE);
+        String networkId = nullIsIllegal(json.get(NETWORK_ID).asText(),
+                NETWORK_ID + MISSING_MESSAGE);
+
+        return new DefaultK8sIpam(IpAddress.valueOf(ipAddress), networkId);
+    }
+}
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java
new file mode 100644
index 0000000..e6e646b
--- /dev/null
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.k8snetworking.api.DefaultK8sNetwork;
+import org.onosproject.k8snetworking.api.K8sNetwork;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubernetes network codec used for serializing and de-serializing JSON string.
+ */
+public final class K8sNetworkCodec extends JsonCodec<K8sNetwork> {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String NETWORK_ID = "networkId";
+    private static final String TYPE = "type";
+    private static final String MTU = "mtu";
+    private static final String SEGMENT_ID = "segmentId";
+    private static final String GATEWAY_IP = "gatewayIp";
+    private static final String CIDR = "cidr";
+
+    private static final String MISSING_MESSAGE = " is required in K8sNetwork";
+
+    @Override
+    public ObjectNode encode(K8sNetwork network, CodecContext context) {
+        checkNotNull(network, "Kubernetes network cannot be null");
+
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(NETWORK_ID, network.networkId())
+                .put(TYPE, network.type().name())
+                .put(SEGMENT_ID, network.segmentId())
+                .put(GATEWAY_IP, network.gatewayIp().toString())
+                .put(CIDR, network.cidr());
+
+        if (network.mtu() != null) {
+            result.put(MTU, network.mtu());
+        }
+
+        return result;
+    }
+
+    @Override
+    public K8sNetwork decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        String networkId = nullIsIllegal(json.get(NETWORK_ID).asText(),
+                NETWORK_ID + MISSING_MESSAGE);
+        String type = nullIsIllegal(json.get(TYPE).asText(),
+                TYPE + MISSING_MESSAGE);
+        String segmentId = nullIsIllegal(json.get(SEGMENT_ID).asText(),
+                SEGMENT_ID + MISSING_MESSAGE);
+        String gatewayIp = nullIsIllegal(json.get(GATEWAY_IP).asText(),
+                GATEWAY_IP + MISSING_MESSAGE);
+        String cidr = nullIsIllegal(json.get(CIDR).asText(),
+                CIDR + MISSING_MESSAGE);
+
+        DefaultK8sNetwork.Builder networkBuilder = DefaultK8sNetwork.builder()
+                .networkId(networkId)
+                .type(K8sNetwork.Type.valueOf(type))
+                .segmentId(segmentId)
+                .gatewayIp(IpAddress.valueOf(gatewayIp))
+                .cidr(cidr);
+
+        if (json.get(MTU) != null) {
+            networkBuilder.mtu(json.get(MTU).asInt());
+        }
+
+        return networkBuilder.build();
+    }
+}
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sPortCodec.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sPortCodec.java
new file mode 100644
index 0000000..9ca74cb
--- /dev/null
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sPortCodec.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.k8snetworking.api.DefaultK8sPort;
+import org.onosproject.k8snetworking.api.K8sPort;
+import org.onosproject.k8snetworking.api.K8sPort.State;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubernetes port codec used for serializing and de-serializing JSON string.
+ */
+public final class K8sPortCodec extends JsonCodec<K8sPort> {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String NETWORK_ID = "networkId";
+    private static final String PORT_ID = "portId";
+    private static final String MAC_ADDRESS = "macAddress";
+    private static final String IP_ADDRESS = "ipAddress";
+    private static final String DEVICE_ID = "deviceId";
+    private static final String PORT_NUMBER = "portNumber";
+    private static final String STATE = "state";
+
+    private static final String MISSING_MESSAGE = " is required in K8sPort";
+
+    @Override
+    public ObjectNode encode(K8sPort port, CodecContext context) {
+        checkNotNull(port, "Kubernetes port cannot be null");
+
+        return context.mapper().createObjectNode()
+                .put(NETWORK_ID, port.networkId())
+                .put(PORT_ID, port.portId())
+                .put(MAC_ADDRESS, port.macAddress().toString())
+                .put(IP_ADDRESS, port.ipAddress().toString())
+                .put(DEVICE_ID, port.deviceId().toString())
+                .put(PORT_NUMBER, port.portNumber().toString())
+                .put(STATE, port.state().name());
+    }
+
+    @Override
+    public K8sPort decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        String networkId = nullIsIllegal(json.get(NETWORK_ID).asText(),
+                NETWORK_ID + MISSING_MESSAGE);
+        String portId = nullIsIllegal(json.get(PORT_ID).asText(),
+                PORT_ID + MISSING_MESSAGE);
+        String macAddress = nullIsIllegal(json.get(MAC_ADDRESS).asText(),
+                MAC_ADDRESS + MISSING_MESSAGE);
+        String ipAddress = nullIsIllegal(json.get(IP_ADDRESS).asText(),
+                IP_ADDRESS + MISSING_MESSAGE);
+        String deviceId = nullIsIllegal(json.get(DEVICE_ID).asText(),
+                DEVICE_ID + MISSING_MESSAGE);
+        String portNumber = nullIsIllegal(json.get(PORT_NUMBER).asText(),
+                PORT_NUMBER + MISSING_MESSAGE);
+        String state = nullIsIllegal(json.get(STATE).asText(),
+                STATE + MISSING_MESSAGE);
+
+        return DefaultK8sPort.builder()
+                .networkId(networkId)
+                .portId(portId)
+                .macAddress(MacAddress.valueOf(macAddress))
+                .ipAddress(IpAddress.valueOf(ipAddress))
+                .deviceId(DeviceId.deviceId(deviceId))
+                .portNumber(PortNumber.portNumber(portNumber))
+                .state(State.valueOf(state))
+                .build();
+    }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamCodecTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamCodecTest.java
new file mode 100644
index 0000000..8335867
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamCodecTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.k8snetworking.api.DefaultK8sIpam;
+import org.onosproject.k8snetworking.api.K8sIpam;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.k8snetworking.codec.K8sIpamJsonMatcher.matchesK8sIpam;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for kubernetes IPAM codec.
+ */
+public class K8sIpamCodecTest {
+
+    MockCodecContext context;
+
+    JsonCodec<K8sIpam> k8sIpamCodec;
+
+    final CoreService mockCoreService = createMock(CoreService.class);
+    private static final String REST_APP_ID = "org.onosproject.rest";
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+        context = new MockCodecContext();
+        k8sIpamCodec = new K8sIpamCodec();
+
+        assertThat(k8sIpamCodec, notNullValue());
+
+        expect(mockCoreService.registerApplication(REST_APP_ID))
+                .andReturn(APP_ID).anyTimes();
+        replay(mockCoreService);
+        context.registerService(CoreService.class, mockCoreService);
+    }
+
+    /**
+     * Tests the kubernetes IPAM encoding.
+     */
+    @Test
+    public void testK8sIpamEncode() {
+        K8sIpam ipam = new DefaultK8sIpam(
+                IpAddress.valueOf("10.10.10.10"), "network-1");
+
+        ObjectNode nodeJson = k8sIpamCodec.encode(ipam, context);
+        assertThat(nodeJson, matchesK8sIpam(ipam));
+    }
+
+    /**
+     * Tests the kubernetes IPAM decoding.
+     */
+    @Test
+    public void testK8sIpamDecode() throws IOException {
+        K8sIpam ipam = getK8sIpam("K8sIpam.json");
+
+        assertEquals("10.10.10.2", ipam.ipAddress().toString());
+        assertEquals("network-1", ipam.networkId());
+    }
+
+    /**
+     * Reads in an kubernetes IPAM from the given resource and decodes it.
+     *
+     * @param resourceName resource to use to read the JSON for the rule
+     * @return decoded kubernetes node
+     * @throws IOException if processing the resource fails
+     */
+    private K8sIpam getK8sIpam(String resourceName) throws IOException {
+        InputStream jsonStream = K8sIpamCodecTest.class.getResourceAsStream(resourceName);
+        JsonNode json = context.mapper().readTree(jsonStream);
+        MatcherAssert.assertThat(json, notNullValue());
+        K8sIpam node = k8sIpamCodec.decode((ObjectNode) json, context);
+        assertThat(node, notNullValue());
+        return node;
+    }
+
+    /**
+     * Mock codec context for use in codec unit tests.
+     */
+    private class MockCodecContext implements CodecContext {
+        private final ObjectMapper mapper = new ObjectMapper();
+        private final CodecManager manager = new CodecManager();
+        private final Map<Class<?>, Object> services = new HashMap<>();
+
+        /**
+         * Constructs a new mock codec context.
+         */
+        public MockCodecContext() {
+            manager.activate();
+        }
+
+        @Override
+        public ObjectMapper mapper() {
+            return mapper;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> JsonCodec<T> codec(Class<T> entityClass) {
+            if (entityClass == K8sIpam.class) {
+                return (JsonCodec<T>) k8sIpamCodec;
+            }
+            return manager.getCodec(entityClass);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T getService(Class<T> serviceClass) {
+            return (T) services.get(serviceClass);
+        }
+
+        // for registering mock services
+        public <T> void registerService(Class<T> serviceClass, T impl) {
+            services.put(serviceClass, impl);
+        }
+    }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamJsonMatcher.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamJsonMatcher.java
new file mode 100644
index 0000000..81bbf10
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamJsonMatcher.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.k8snetworking.api.K8sIpam;
+
+/**
+ * Hamcrest matcher for kubernetes IPAM.
+ */
+public final class K8sIpamJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+    private final K8sIpam ipam;
+
+    private static final String IP_ADDRESS = "ipAddress";
+    private static final String NETWORK_ID = "networkId";
+
+    private K8sIpamJsonMatcher(K8sIpam ipam) {
+        this.ipam = ipam;
+    }
+
+    @Override
+    protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+        // check IP address
+        String jsonIpAddress = jsonNode.get(IP_ADDRESS).asText();
+        String ipAddress = ipam.ipAddress().toString();
+        if (!jsonIpAddress.equals(ipAddress)) {
+            description.appendText("IP address was " + jsonIpAddress);
+            return false;
+        }
+
+        // check network ID
+        String jsonNetworkId = jsonNode.get(NETWORK_ID).asText();
+        String networkId = ipam.networkId();
+        if (!jsonNetworkId.equals(networkId)) {
+            description.appendText("Network ID was " + jsonNetworkId);
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText(ipam.toString());
+    }
+
+    /**
+     * Factory to allocate kubernetes IPAM matcher.
+     *
+     * @param ipam kubernetes IPAM object we are looking for
+     * @return matcher
+     */
+    public static K8sIpamJsonMatcher matchesK8sIpam(K8sIpam ipam) {
+        return new K8sIpamJsonMatcher(ipam);
+    }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java
new file mode 100644
index 0000000..9d7fd99
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.k8snetworking.api.DefaultK8sNetwork;
+import org.onosproject.k8snetworking.api.K8sNetwork;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.k8snetworking.codec.K8sNetworkJsonMatcher.matchesK8sNetwork;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for kubernetes network codec.
+ */
+public class K8sNetworkCodecTest {
+
+    MockCodecContext context;
+
+    JsonCodec<K8sNetwork> k8sNetworkCodec;
+
+    final CoreService mockCoreService = createMock(CoreService.class);
+    private static final String REST_APP_ID = "org.onosproject.rest";
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+        context = new MockCodecContext();
+        k8sNetworkCodec = new K8sNetworkCodec();
+
+        assertThat(k8sNetworkCodec, notNullValue());
+
+        expect(mockCoreService.registerApplication(REST_APP_ID))
+                .andReturn(APP_ID).anyTimes();
+        replay(mockCoreService);
+        context.registerService(CoreService.class, mockCoreService);
+    }
+
+    /**
+     * Tests the kubernetes network encoding.
+     */
+    @Test
+    public void testK8sNetworkEncode() {
+        K8sNetwork network = DefaultK8sNetwork.builder()
+                .networkId("network-1")
+                .segmentId("1")
+                .type(K8sNetwork.Type.VXLAN)
+                .gatewayIp(IpAddress.valueOf("10.10.10.1"))
+                .cidr("32")
+                .mtu(1500)
+                .build();
+
+        ObjectNode nodeJson = k8sNetworkCodec.encode(network, context);
+        assertThat(nodeJson, matchesK8sNetwork(network));
+    }
+
+    /**
+     * Tests the kubernetes network decoding.
+     */
+    @Test
+    public void testK8sNetworkDecode() throws IOException {
+        K8sNetwork network = getK8sNetwork("K8sNetwork.json");
+
+        assertEquals("network-1", network.networkId());
+        assertEquals("1", network.segmentId());
+        assertEquals("VXLAN", network.type().name());
+        assertEquals("10.10.10.1", network.gatewayIp().toString());
+        assertEquals("32", network.cidr());
+        assertThat(network.mtu(), is(1500));
+    }
+
+    /**
+     * Reads in an kubernetes network from the given resource and decodes it.
+     *
+     * @param resourceName resource to use to read the JSON for the rule
+     * @return decoded kubernetes network
+     * @throws IOException if processing the resource fails
+     */
+    private K8sNetwork getK8sNetwork(String resourceName) throws IOException {
+        InputStream jsonStream = K8sNetworkCodecTest.class.getResourceAsStream(resourceName);
+        JsonNode json = context.mapper().readTree(jsonStream);
+        MatcherAssert.assertThat(json, notNullValue());
+        K8sNetwork network = k8sNetworkCodec.decode((ObjectNode) json, context);
+        assertThat(network, notNullValue());
+        return network;
+    }
+
+    private class MockCodecContext implements CodecContext {
+        private final ObjectMapper mapper = new ObjectMapper();
+        private final CodecManager manager = new CodecManager();
+        private final Map<Class<?>, Object> services = new HashMap<>();
+
+        /**
+         * Constructs a new mock codec context.
+         */
+        public MockCodecContext() {
+            manager.activate();
+        }
+
+        @Override
+        public ObjectMapper mapper() {
+            return mapper;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> JsonCodec<T> codec(Class<T> entityClass) {
+            if (entityClass == K8sNetwork.class) {
+                return (JsonCodec<T>) k8sNetworkCodec;
+            }
+            return manager.getCodec(entityClass);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T getService(Class<T> serviceClass) {
+            return (T) services.get(serviceClass);
+        }
+
+        // for registering mock services
+        public <T> void registerService(Class<T> serviceClass, T impl) {
+            services.put(serviceClass, impl);
+        }
+    }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java
new file mode 100644
index 0000000..435de0f
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.k8snetworking.api.K8sNetwork;
+
+/**
+ * Hamcrest matcher for kubernetes network.
+ */
+public final class K8sNetworkJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+    private final K8sNetwork network;
+
+    private static final String NETWORK_ID = "networkId";
+    private static final String TYPE = "type";
+    private static final String MTU = "mtu";
+    private static final String SEGMENT_ID = "segmentId";
+    private static final String GATEWAY_IP = "gatewayIp";
+    private static final String CIDR = "cidr";
+
+    private K8sNetworkJsonMatcher(K8sNetwork network) {
+        this.network = network;
+    }
+
+    @Override
+    protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+        // check network ID
+        String jsonNetworkId = jsonNode.get(NETWORK_ID).asText();
+        String networkId = network.networkId();
+        if (!jsonNetworkId.equals(networkId)) {
+            description.appendText("network ID was " + jsonNetworkId);
+            return false;
+        }
+
+        // check type
+        String jsonType = jsonNode.get(TYPE).asText();
+        String type = network.type().name();
+        if (!jsonType.equals(type)) {
+            description.appendText("network type was " + jsonType);
+            return false;
+        }
+
+        // check MTU
+        int jsonMtu = jsonNode.get(MTU).asInt();
+        int mtu = network.mtu();
+        if (jsonMtu != mtu) {
+            description.appendText("MTU was " + jsonMtu);
+            return false;
+        }
+
+        // check segment ID
+        String jsonSegmentId = jsonNode.get(SEGMENT_ID).asText();
+        String segmentId = network.segmentId();
+        if (!jsonSegmentId.equals(segmentId)) {
+            description.appendText("segment ID was " + jsonSegmentId);
+            return false;
+        }
+
+        // check gateway IP
+        String jsonGatewayIp = jsonNode.get(GATEWAY_IP).asText();
+        String gatewayIp = network.gatewayIp().toString();
+        if (!jsonGatewayIp.equals(gatewayIp)) {
+            description.appendText("gateway IP was " + jsonGatewayIp);
+            return false;
+        }
+
+        // check CIDR
+        String jsonCidr = jsonNode.get(CIDR).asText();
+        String cidr = network.cidr();
+        if (!jsonCidr.equals(cidr)) {
+            description.appendText("CIDR was " + jsonCidr);
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText(network.toString());
+    }
+
+    /**
+     * Factory to allocate a kubernetes network matcher.
+     *
+     * @param network kubernetes network object we are looking for
+     * @return matcher
+     */
+    public static K8sNetworkJsonMatcher matchesK8sNetwork(K8sNetwork network) {
+        return new K8sNetworkJsonMatcher(network);
+    }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortCodecTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortCodecTest.java
new file mode 100644
index 0000000..cea53f2
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortCodecTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.k8snetworking.api.DefaultK8sPort;
+import org.onosproject.k8snetworking.api.K8sPort;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.k8snetworking.api.K8sPort.State.ACTIVE;
+import static org.onosproject.k8snetworking.codec.K8sPortJsonMatcher.matchesK8sPort;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for kubernetes port codec.
+ */
+public class K8sPortCodecTest {
+
+    MockCodecContext context;
+
+    JsonCodec<K8sPort> k8sPortCodec;
+
+    final CoreService mockCoreService = createMock(CoreService.class);
+    private static final String REST_APP_ID = "org.onosproject.rest";
+
+    /**
+     * Initial setup for this unit test.
+     */
+    @Before
+    public void setUp() {
+        context = new MockCodecContext();
+        k8sPortCodec = new K8sPortCodec();
+
+        assertThat(k8sPortCodec, notNullValue());
+
+        expect(mockCoreService.registerApplication(REST_APP_ID))
+                .andReturn(APP_ID).anyTimes();
+        replay(mockCoreService);
+        context.registerService(CoreService.class, mockCoreService);
+    }
+
+    /**
+     * Tests the kubernetes port encoding.
+     */
+    @Test
+    public void testK8sPortEncode() {
+        K8sPort port = DefaultK8sPort.builder()
+                .networkId("network-1")
+                .portId("port-1")
+                .deviceId(DeviceId.deviceId("of:0000000000000001"))
+                .ipAddress(IpAddress.valueOf("10.10.10.2"))
+                .macAddress(MacAddress.valueOf("00:11:22:33:44:55"))
+                .portNumber(PortNumber.portNumber(1))
+                .state(ACTIVE)
+                .build();
+
+        ObjectNode nodeJson = k8sPortCodec.encode(port, context);
+        assertThat(nodeJson, matchesK8sPort(port));
+    }
+
+    /**
+     * Tests the kubernetes port decoding.
+     */
+    @Test
+    public void testK8sPortDecode() throws IOException {
+        K8sPort port = getK8sPort("K8sPort.json");
+
+        assertEquals("network-1", port.networkId());
+        assertEquals("port-1", port.portId());
+        assertEquals("00:11:22:33:44:55", port.macAddress().toString());
+        assertEquals("10.10.10.10", port.ipAddress().toString());
+        assertEquals("of:0000000000000001", port.deviceId().toString());
+        assertEquals("1", port.portNumber().toString());
+        assertEquals("ACTIVE", port.state().name());
+    }
+
+    /**
+     * Reads in an kubernetes port from the given resource and decodes it.
+     *
+     * @param resourceName resource to use to read the JSON for the rule
+     * @return decoded kubernetes port
+     * @throws IOException if processing the resource fails
+     */
+    private K8sPort getK8sPort(String resourceName) throws IOException {
+        InputStream jsonStream = K8sPortCodecTest.class.getResourceAsStream(resourceName);
+        JsonNode json = context.mapper().readTree(jsonStream);
+        MatcherAssert.assertThat(json, notNullValue());
+        K8sPort port = k8sPortCodec.decode((ObjectNode) json, context);
+        assertThat(port, notNullValue());
+        return port;
+    }
+
+    private class MockCodecContext implements CodecContext {
+        private final ObjectMapper mapper = new ObjectMapper();
+        private final CodecManager manager = new CodecManager();
+        private final Map<Class<?>, Object> services = new HashMap<>();
+
+        /**
+         * Constructs a new mock codec context.
+         */
+        public MockCodecContext() {
+            manager.activate();
+        }
+
+        @Override
+        public ObjectMapper mapper() {
+            return mapper;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> JsonCodec<T> codec(Class<T> entityClass) {
+            if (entityClass == K8sPort.class) {
+                return (JsonCodec<T>) k8sPortCodec;
+            }
+            return manager.getCodec(entityClass);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T getService(Class<T> serviceClass) {
+            return (T) services.get(serviceClass);
+        }
+
+        // for registering mock services
+        public <T> void registerService(Class<T> serviceClass, T impl) {
+            services.put(serviceClass, impl);
+        }
+    }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortJsonMatcher.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortJsonMatcher.java
new file mode 100644
index 0000000..b0f327e
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortJsonMatcher.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.k8snetworking.api.K8sPort;
+
+/**
+ * Hamcrest matcher for kubernetes port.
+ */
+public final class K8sPortJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+    private final K8sPort port;
+
+    private static final String NETWORK_ID = "networkId";
+    private static final String PORT_ID = "portId";
+    private static final String MAC_ADDRESS = "macAddress";
+    private static final String IP_ADDRESS = "ipAddress";
+    private static final String DEVICE_ID = "deviceId";
+    private static final String PORT_NUMBER = "portNumber";
+    private static final String STATE = "state";
+
+    private K8sPortJsonMatcher(K8sPort port) {
+        this.port = port;
+    }
+
+    @Override
+    protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+        // check network ID
+        String jsonNetworkId = jsonNode.get(NETWORK_ID).asText();
+        String networkId = port.networkId();
+        if (!jsonNetworkId.equals(networkId)) {
+            description.appendText("network ID was " + jsonNetworkId);
+            return false;
+        }
+
+        // check port ID
+        String jsonPortId = jsonNode.get(PORT_ID).asText();
+        String portId = port.portId();
+        if (!jsonPortId.equals(portId)) {
+            description.appendText("port ID was " + jsonPortId);
+            return false;
+        }
+
+        // check MAC address
+        String jsonMacAddress = jsonNode.get(MAC_ADDRESS).asText();
+        String macAddress = port.macAddress().toString();
+        if (!jsonMacAddress.equals(macAddress)) {
+            description.appendText("MAC address was " + jsonMacAddress);
+            return false;
+        }
+
+        // check IP address
+        String jsonIpAddress = jsonNode.get(IP_ADDRESS).asText();
+        String ipAddress = port.ipAddress().toString();
+        if (!jsonIpAddress.equals(ipAddress)) {
+            description.appendText("IP address was " + jsonIpAddress);
+            return false;
+        }
+
+        // check device ID
+        String jsonDeviceId = jsonNode.get(DEVICE_ID).asText();
+        String deviceId = port.deviceId().toString();
+        if (!jsonDeviceId.equals(deviceId)) {
+            description.appendText("device ID was " + jsonDeviceId);
+            return false;
+        }
+
+        // check port number
+        String jsonPortNumber = jsonNode.get(PORT_NUMBER).asText();
+        String portNumber = port.portNumber().toString();
+        if (!jsonPortNumber.equals(portNumber)) {
+            description.appendText("port number was " + jsonPortNumber);
+            return false;
+        }
+
+        // check state
+        String jsonState = jsonNode.get(STATE).asText();
+        String state = port.state().name();
+        if (!jsonState.equals(state)) {
+            description.appendText("state was " + jsonState);
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText(port.toString());
+    }
+
+    /**
+     * Factory to allocate an kubernetes port matcher.
+     *
+     * @param port kubernetes port object we are looking for
+     * @return matcher
+     */
+    public static K8sPortJsonMatcher matchesK8sPort(K8sPort port) {
+        return new K8sPortJsonMatcher(port);
+    }
+}
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sIpam.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sIpam.json
new file mode 100644
index 0000000..22e1c19
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sIpam.json
@@ -0,0 +1,4 @@
+{
+  "ipAddress": "10.10.10.2",
+  "networkId": "network-1"
+}
\ No newline at end of file
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json
new file mode 100644
index 0000000..ce15c92
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json
@@ -0,0 +1,8 @@
+{
+  "networkId": "network-1",
+  "type": "VXLAN",
+  "mtu": 1500,
+  "segmentId": "1",
+  "gatewayIp": "10.10.10.1",
+  "cidr": "32"
+}
\ No newline at end of file
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sPort.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sPort.json
new file mode 100644
index 0000000..9c0214c
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sPort.json
@@ -0,0 +1,9 @@
+{
+  "networkId": "network-1",
+  "portId": "port-1",
+  "macAddress": "00:11:22:33:44:55",
+  "ipAddress": "10.10.10.10",
+  "deviceId": "of:0000000000000001",
+  "portNumber": "1",
+  "state": "ACTIVE"
+}
\ No newline at end of file