[ONOS-5480] The implementation of LISP Encapsulated Control Message (ECM).

Changes
1. ECM message is added.
2. Default ECM message is added with builder, reader, and writer.
3. Implented other messages writeTo() methods.

Change-Id: I3ed6f66a7ec7a318f30596d64c35ac15365c8c4c
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControl.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControl.java
new file mode 100644
index 0000000..36782c2
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControl.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.lisp.msg.protocols;
+
+import com.google.common.base.Objects;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.onlab.packet.Data;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.IP;
+import org.onlab.packet.UDP;
+import org.onlab.util.ByteOperator;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onosproject.lisp.msg.protocols.LispType.LISP_ENCAPSULATED_CONTROL;
+
+/**
+ * Default LISP Encapsulated Control message class.
+ */
+public final class DefaultLispEncapsulatedControl
+        implements LispEncapsulatedControl {
+
+    private final boolean isSecurity;
+    private final IP innerIpHeader;
+    private final UDP innerUdp;
+    private final LispMessage innerMessage;
+
+    static final EcmWriter WRITER;
+    static {
+        WRITER = new EcmWriter();
+    }
+
+    /**
+     * A private constructor that protects object instantiation from external.
+     *
+     * @param isSecurity a security flag
+     * @param innerIpHeader a inner IP Header
+     * @param innerUdp a inner UDP Header
+     * @param innerMessage a inner LISP control message
+     */
+    private  DefaultLispEncapsulatedControl(boolean isSecurity, IP innerIpHeader,
+                                            UDP innerUdp, LispMessage innerMessage) {
+        this.isSecurity = isSecurity;
+        this.innerIpHeader = innerIpHeader;
+        this.innerUdp = innerUdp;
+        this.innerMessage = innerMessage;
+    }
+
+    @Override
+    public LispType getType() {
+        return LISP_ENCAPSULATED_CONTROL;
+    }
+
+    @Override
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        WRITER.writeTo(byteBuf, this);
+    }
+
+    @Override
+    public Builder createBuilder() {
+        return new DefaultEcmBuilder();
+    }
+
+    @Override
+    public boolean isSecurity() {
+        return isSecurity;
+    }
+
+    @Override
+    public IP innerIpHeader() {
+        return innerIpHeader;
+    }
+
+    public UDP innerUdp() {
+        return innerUdp;
+    }
+
+    @Override
+    public LispMessage getControlMessage() {
+        return innerMessage;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("type", getType())
+                .add("isSecurity", isSecurity)
+                .add("inner IP header", innerIpHeader)
+                .add("inner UDP header", innerUdp)
+                .add("inner lisp Message", innerMessage)
+                .toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        DefaultLispEncapsulatedControl that = (DefaultLispEncapsulatedControl) o;
+        return Objects.equal(isSecurity, that.isSecurity) &&
+                Objects.equal(innerIpHeader, that.innerIpHeader) &&
+                Objects.equal(innerUdp, that.innerUdp) &&
+                Objects.equal(innerMessage, that.innerMessage);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(isSecurity, innerIpHeader, innerUdp, innerMessage);
+    }
+
+    /**
+     * LISP ECM Builder implementation.
+     */
+    public static final class DefaultEcmBuilder implements EcmBuilder {
+
+        private boolean isSecurity;
+        private IP innerIpHeader;
+        private UDP innerUdpHeader;
+        private LispMessage innerMessage;
+
+        @Override
+        public LispType getType() {
+            return LispType.LISP_ENCAPSULATED_CONTROL;
+        }
+
+        @Override
+        public EcmBuilder isSecurity(boolean security) {
+            this.isSecurity = security;
+            return this;
+        }
+
+        @Override
+        public EcmBuilder innerIpHeader(IP innerIpHeader) {
+            this.innerIpHeader = innerIpHeader;
+            return this;
+        }
+
+        @Override
+        public EcmBuilder innerUdpHeader(UDP innerUdpHeader) {
+            this.innerUdpHeader = innerUdpHeader;
+            return this;
+        }
+
+        @Override
+        public EcmBuilder innerLispMessage(LispMessage msg) {
+            this.innerMessage = msg;
+            return this;
+        }
+
+        @Override
+        public LispEncapsulatedControl build() {
+            return new DefaultLispEncapsulatedControl(isSecurity, innerIpHeader,
+                                                      innerUdpHeader, innerMessage);
+        }
+    }
+
+    /**
+     * A LISP message reader for ECM.
+     */
+    public static final class EcmReader
+            implements LispMessageReader<LispEncapsulatedControl> {
+
+        private static final int SECURITY_INDEX = 3;
+        private static final int RESERVED_SKIP_LENGTH = 3;
+        private static final int UDP_HEADER_LENGTH = 8;
+        private static final short HEADER_LENGTH_MASK = 0xf;
+
+        @Override
+        public LispEncapsulatedControl readFrom(ByteBuf byteBuf) throws
+                LispParseError, LispReaderException, DeserializationException {
+
+            if (byteBuf.readerIndex() != 0) {
+                return null;
+            }
+
+            boolean securityFlag = ByteOperator.getBit(byteBuf.readByte(),
+                                                            SECURITY_INDEX);
+            // let's skip the reserved field
+            byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
+
+            short totalLength = byteBuf.getShort(byteBuf.readerIndex() + 2);
+
+            byte[] ipHeaderByte = new byte[totalLength];
+            byteBuf.getBytes(byteBuf.readerIndex(), ipHeaderByte, 0, totalLength);
+
+            IP innerIpHeader = IP.deserializer().deserialize(ipHeaderByte, 0,
+                                                             totalLength);
+
+            UDP innerUdp = (UDP) innerIpHeader.getPayload();
+            Data data = (Data) innerUdp.getPayload();
+            ByteBuf msgBuffer = Unpooled.buffer();
+            msgBuffer.writeBytes(data.getData());
+
+            LispMessageReader reader = LispMessageReaderFactory.getReader(msgBuffer);
+            LispMessage innerMessage = (LispMessage) reader.readFrom(msgBuffer);
+
+            return new DefaultLispEncapsulatedControl(securityFlag, innerIpHeader,
+                                                      innerUdp, innerMessage);
+        }
+    }
+
+    /**
+     * LISP ECM writer class.
+     */
+    public static class EcmWriter
+            implements LispMessageWriter<LispEncapsulatedControl> {
+
+        private static final short ECM_MSG_CODE =
+                LispType.LISP_ENCAPSULATED_CONTROL.getTypeCode();
+        private static final int TYPE_SHIFT_BIT = 4;
+
+        private static final int SECURITY_SHIFT_BIT = 3;
+
+        private static final int ENABLE_BIT = 1;
+        private static final int DISABLE_BIT = 0;
+
+        private static final int UNUSED_ZERO = 0;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispEncapsulatedControl message)
+                throws LispWriterException {
+
+            // specify LISP message type
+            byte msgType = (byte) (ECM_MSG_CODE << TYPE_SHIFT_BIT);
+
+            byte security = DISABLE_BIT;
+            if (message.isSecurity()) {
+                security = (byte) (ENABLE_BIT << SECURITY_SHIFT_BIT);
+            }
+
+            byteBuf.writeByte(msgType + security);
+
+            // fill zero into reserved field
+            byteBuf.writeByte((byte) UNUSED_ZERO);
+            byteBuf.writeByte((byte) UNUSED_ZERO);
+            byteBuf.writeByte((byte) UNUSED_ZERO);
+
+            ByteBuf buffer = Unpooled.buffer();
+            message.getControlMessage().writeTo(buffer);
+            byte[] dataBytes = new byte[buffer.writerIndex()];
+            buffer.getBytes(0, dataBytes, 0, buffer.writerIndex());
+
+            message.innerUdp().setPayload(new Data(dataBytes));
+            message.innerIpHeader().setPayload(message.innerUdp());
+
+            byteBuf.writeBytes(message.innerIpHeader().serialize());
+        }
+    }
+
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java
index 14cd884..7413245 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java
@@ -82,8 +82,8 @@
     }
 
     @Override
-    public void writeTo(ByteBuf byteBuf) {
-        // TODO: serialize LispMapRegister message
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        serialize(byteBuf, this);
     }
 
     @Override
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java
index 0b5407e..e242a5d 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java
@@ -41,6 +41,11 @@
     private final boolean routed;
     private final LispAfiAddress locatorAfi;
 
+    static final LocatorRecordWriter WRITER;
+    static {
+        WRITER = new LocatorRecordWriter();
+    }
+
     /**
      * A private constructor that protects object instantiation from external.
      *
@@ -107,8 +112,8 @@
     }
 
     @Override
-    public void writeTo(ByteBuf byteBuf) {
-
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        WRITER.writeTo(byteBuf, this);
     }
 
     @Override
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
index 79317f8..cb18b8f 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
@@ -41,6 +41,11 @@
     private final byte[] authenticationData;
     private final List<LispMapRecord> mapRecords;
 
+    static final NotifyWriter WRITER;
+    static {
+        WRITER = new NotifyWriter();
+    }
+
     /**
      * A private constructor that protects object instantiation from external.
      *
@@ -64,8 +69,8 @@
     }
 
     @Override
-    public void writeTo(ByteBuf byteBuf) {
-        // TODO: serialize LispMapRegister message
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        WRITER.writeTo(byteBuf, this);
     }
 
     @Override
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java
index 9c4bece..d18e238 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java
@@ -45,6 +45,11 @@
     private final LispAfiAddress eidPrefixAfi;
     private final List<LispLocatorRecord> locatorRecords;
 
+    static final MapRecordWriter WRITER;
+    static {
+        WRITER = new MapRecordWriter();
+    }
+
     /**
      * A private constructor that protects object instantiation from external.
      *
@@ -109,8 +114,8 @@
     }
 
     @Override
-    public void writeTo(ByteBuf byteBuf) {
-
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        WRITER.writeTo(byteBuf, this);
     }
 
     @Override
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
index b45d1e6..58244d7 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
@@ -46,6 +46,11 @@
     private final boolean proxyMapReply;
     private final boolean wantMapNotify;
 
+    static final RegisterWriter WRITER;
+    static {
+        WRITER = new RegisterWriter();
+    }
+
     /**
      * A private constructor that protects object instantiation from external.
      *
@@ -75,8 +80,8 @@
     }
 
     @Override
-    public void writeTo(ByteBuf byteBuf) {
-        // TODO: serialize LispMapRegister message
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        WRITER.writeTo(byteBuf, this);
     }
 
     @Override
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java
index 59775f4..5773be8 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java
@@ -40,6 +40,11 @@
     private final boolean security;
     private final List<LispMapRecord> mapRecords;
 
+    static final ReplyWriter WRITER;
+    static {
+        WRITER = new ReplyWriter();
+    }
+
     /**
      * A private constructor that protects object instantiation from external.
      *
@@ -63,8 +68,8 @@
     }
 
     @Override
-    public void writeTo(ByteBuf byteBuf) {
-        // TODO: serialize LispMapReply message
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        WRITER.writeTo(byteBuf, this);
     }
 
     @Override
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java
index 75f73b5..34ec469 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java
@@ -49,6 +49,11 @@
     private final boolean pitr;
     private final boolean smrInvoked;
 
+    static final RequestWriter WRITER;
+    static {
+        WRITER = new RequestWriter();
+    }
+
     /**
      * A private constructor that protects object instantiation from external.
      *
@@ -85,8 +90,8 @@
     }
 
     @Override
-    public void writeTo(ByteBuf byteBuf) {
-        // TODO: serialize LispMapRequest message
+    public void writeTo(ByteBuf byteBuf) throws LispWriterException {
+        WRITER.writeTo(byteBuf, this);
     }
 
     @Override
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEncapsulatedControl.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEncapsulatedControl.java
new file mode 100644
index 0000000..f8113ab
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEncapsulatedControl.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.lisp.msg.protocols;
+
+import org.onlab.packet.IP;
+import org.onlab.packet.UDP;
+
+/**
+ * LISP Encapsulated Control Message (ECM) interface.
+ * <p>
+ * LISP ECM format is defined in RFC6830.
+ * https://tools.ietf.org/html/rfc6830#section-6.1.8
+ *
+ * <pre>
+ * {@literal
+ *      0                   1                   2                   3
+ *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |                       IPv4 or IPv6 Header                     |
+ * OH  |                      (uses RLOC addresses)                    |
+ * \   |                                                               |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |       Source Port = xxxx      |       Dest Port = 4342        |
+ * UDP +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * \   |           UDP Length          |        UDP Checksum           |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * LH  |Type=8 |S|                  Reserved                           |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |                       IPv4 or IPv6 Header                     |
+ * IH  |                  (uses RLOC or EID addresses)                 |
+ * \   |                                                               |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * /   |       Source Port = xxxx      |       Dest Port = yyyy        |
+ * UDP +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * \   |           UDP Length          |        UDP Checksum           |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * LCM |                      LISP Control Message                     |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public interface LispEncapsulatedControl extends LispMessage {
+
+    /**
+     * Obtains security flag.
+     * If this bit is set, the 'Reserved' field will have the authentication data.
+     *
+     * @return security flag
+     */
+    boolean isSecurity();
+
+    /**
+     * Obtains inner IP header.
+     *
+     * @return inner IP header
+     */
+    IP innerIpHeader();
+
+    /**
+     * Obtains inner LISP UDP header.
+     *
+     * @return inner LISP UDP header
+     */
+    UDP innerUdp();
+
+    /**
+     * Obtains inner LISP control message.
+     * The format can be one of other LISP messages.
+     *
+     * @return Inner lisp control messages
+     */
+
+    LispMessage getControlMessage();
+
+    /**
+     * A builder of LISP map request message.
+     */
+    interface EcmBuilder extends Builder {
+
+        /**
+         * Sets security flag.
+         *
+         * @param security security flag
+         * @return ECMBuilder object
+         */
+        EcmBuilder isSecurity(boolean security);
+
+        /**
+         * Sets inner IP header.
+         *
+         * @param innerIpHeader inner IP header in IPv4 or IPv6
+         * @return ECMBuilder object
+         */
+        EcmBuilder innerIpHeader(IP innerIpHeader);
+
+        /**
+         * Sets inner UDP header.
+         *
+         * @param innerUdpHeader inner UDP packet
+         * @return ECMBuilder object
+         */
+        EcmBuilder innerUdpHeader(UDP innerUdpHeader);
+
+        /**
+         * Sets inner LISP control message.
+         *
+         * @param msg the inner lisp message
+         * @return ECMBuilder object
+         */
+        EcmBuilder innerLispMessage(LispMessage msg);
+
+        /**
+         * Builds LISP ECM message.
+         *
+         * @return LISP ECM message
+         */
+        LispEncapsulatedControl build();
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java
index ca18e0b..35aa1da 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java
@@ -16,6 +16,7 @@
 package org.onosproject.lisp.msg.protocols;
 
 import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
 
 /**
@@ -84,7 +85,7 @@
      *
      * @param byteBuf byte buffer
      */
-    void writeTo(ByteBuf byteBuf);
+    void writeTo(ByteBuf byteBuf) throws LispWriterException;
 
     /**
      * A builder of LISP locator record.
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java
index 4e8536c..d710ebc 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java
@@ -16,6 +16,7 @@
 package org.onosproject.lisp.msg.protocols;
 
 import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
 
 import java.util.List;
@@ -86,7 +87,7 @@
      *
      * @param byteBuf byte buffer
      */
-    void writeTo(ByteBuf byteBuf);
+    void writeTo(ByteBuf byteBuf) throws LispWriterException;
 
     /**
      * A builder of LISP map record.
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java
index 6962b3b..4e3cdfa 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessage.java
@@ -16,6 +16,7 @@
 package org.onosproject.lisp.msg.protocols;
 
 import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
 
 /**
  * LISP message interface.
@@ -33,8 +34,10 @@
      * Writes LISP message object into communication channel.
      *
      * @param byteBuf byte buffer
+     * @throws LispWriterException if the writing request is failed due to
+     * the lisp object cannot be written to the buffer.
      */
-    void writeTo(ByteBuf byteBuf);
+    void writeTo(ByteBuf byteBuf) throws LispWriterException;
 
     /**
      * Generates LISP message builder.
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java
index d2b5594..2b53983 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReader.java
@@ -16,6 +16,7 @@
 package org.onosproject.lisp.msg.protocols;
 
 import io.netty.buffer.ByteBuf;
+import org.onlab.packet.DeserializationException;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 import org.onosproject.lisp.msg.exceptions.LispReaderException;
 
@@ -29,7 +30,14 @@
      *
      * @param byteBuf byte buffer
      * @return LISP message instance
-     * @throws LispParseError LISP control message parse error
+     * @throws LispParseError if the requested message cannot be parsed
+     *         as a LISP object
+     * @throws LispReaderException if LISP message reader cannot process
+     *         the received message
+     * @throws DeserializationException if an inner IP header (IPv4 or IPv6)
+     *         cannot be deserialized due to the message not match
+     *         with IP header format
      */
-    T readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException;
+    T readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException,
+            DeserializationException;
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java
index e6a90d8..2798cc9 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageReaderFactory.java
@@ -21,6 +21,7 @@
 import static org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.NotifyReader;
 import static org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.RegisterReader;
 import static org.onosproject.lisp.msg.protocols.DefaultLispMapRequest.RequestReader;
+import static org.onosproject.lisp.msg.protocols.DefaultLispEncapsulatedControl.EcmReader;
 
 /**
  * A factory class which helps to instantiate LISP reader class.
@@ -39,22 +40,31 @@
     public static LispMessageReader getReader(ByteBuf buffer) {
         LispMessageReader reader;
 
-        int type = buffer.getByte(0) >> TYPE_SHIFT_BIT;
+        LispType type = LispType.valueOf(
+                (short) (buffer.getByte(0) >> TYPE_SHIFT_BIT));
+
         switch (type) {
-            case 1:
+            case LISP_MAP_REQUEST:
                 reader = new RequestReader();
                 break;
-            case 2:
+            case LISP_MAP_REPLY:
                 reader = new ReplyReader();
                 break;
-            case 3:
+            case LISP_MAP_REGISTER:
                 reader = new RegisterReader();
                 break;
-            case 4:
+            case LISP_MAP_NOTIFY:
                 reader = new NotifyReader();
                 break;
+            case LISP_ENCAPSULATED_CONTROL:
+                reader = new EcmReader();
+                break;
+            case UNKNOWN:
+                throw new IllegalArgumentException("Unknown message type: "
+                                                           + type);
             default:
-                throw new IllegalArgumentException("Unknown LISP message type: " + type);
+                throw new IllegalArgumentException("Undefined message type: "
+                                                           + type);
         }
         return reader;
     }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java
index aeacc00..b039ac7 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispType.java
@@ -23,12 +23,26 @@
  */
 public enum LispType {
 
-    LISP_MAP_REQUEST(1),            // LISP Map-Request Message
-    LISP_MAP_REPLY(2),              // LISP Map-Reply Message
-    LISP_MAP_REGISTER(3),           // LISP Map-Register Message
-    LISP_MAP_NOTIFY(4),             // LISP Map-Notify Message
-    LISP_INFO(7),                   // LISP Info-Request or Info-Reply Message
-    UNKNOWN(-1);                    // Other Enums for internal use
+    /** LISP Map-Request Message. */
+    LISP_MAP_REQUEST(1),
+
+    /** LISP Map-Reply Message. */
+    LISP_MAP_REPLY(2),
+
+    /** LISP Map-Register Message. */
+    LISP_MAP_REGISTER(3),
+
+    /** LISP Map-Notify Message. */
+    LISP_MAP_NOTIFY(4),
+
+    /** LISP Info-Request or Info-Reply Message. */
+    LISP_INFO(7),
+
+    /** LISP Encapsulated Control Message. */
+    LISP_ENCAPSULATED_CONTROL(8),
+
+    /** Unknown types for internal use. */
+    UNKNOWN(-1);
 
     private final short type;
 
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControlTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControlTest.java
new file mode 100644
index 0000000..fa64950
--- /dev/null
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispEncapsulatedControlTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.lisp.msg.protocols;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.testing.EqualsTester;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.IP;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.UDP;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
+import org.onosproject.lisp.msg.types.LispIpv4Address;
+
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Unit tests for DefaultLispEncapsulatedControl class.
+ */
+public final class DefaultLispEncapsulatedControlTest {
+
+    private static final String ECM1_SRC_IP = "192.168.1.1";
+    private static final String ECM1_DST_IP = "192.168.1.2";
+    private static final String ECM2_SRC_IP = "192.168.2.1";
+    private static final String ECM2_DST_IP = "192.168.2.2";
+    private static final String RECORD_EID = "1.1.1.1";
+
+    private LispEncapsulatedControl ecm1;
+    private LispEncapsulatedControl sameAsEcm1;
+    private LispEncapsulatedControl ecm2;
+
+    @Before
+    public void setup() {
+
+        //Creates ecm1
+        LispEncapsulatedControl.EcmBuilder builder1 =
+                new DefaultLispEncapsulatedControl.DefaultEcmBuilder();
+
+        IP innerIp1 = new IPv4().setSourceAddress(ECM1_SRC_IP)
+                .setDestinationAddress(ECM1_DST_IP)
+                .setProtocol(IPv4.PROTOCOL_UDP).setVersion((byte) (4 & 0xf));
+        UDP innerUdp1 = new UDP().setSourcePort(1)
+                .setDestinationPort(2);
+
+        LispMapRegister.RegisterBuilder msgBuilder = new
+                DefaultLispMapRegister.DefaultRegisterBuilder();
+
+        List<LispMapRecord> records1 = ImmutableList.of(getMapRecord(),
+                                                        getMapRecord());
+
+        LispMapRegister innerMsg1 = msgBuilder.withIsProxyMapReply(true)
+                                    .withIsWantMapNotify(false)
+                                    .withKeyId((short) 1)
+                                    .withNonce(1L)
+                                    .withMapRecords(records1)
+                                    .build();
+
+        ecm1 = builder1.isSecurity(false)
+                .innerIpHeader(innerIp1)
+                .innerUdpHeader(innerUdp1)
+                .innerLispMessage(innerMsg1)
+                .build();
+
+        //Creates sameAsEcm1
+        LispEncapsulatedControl.EcmBuilder builder2 =
+                new DefaultLispEncapsulatedControl.DefaultEcmBuilder();
+
+        IP innerIp2 = new IPv4().setSourceAddress(ECM1_SRC_IP)
+                .setDestinationAddress(ECM1_DST_IP)
+                .setProtocol(IPv4.PROTOCOL_UDP);
+        UDP innerUdp2 = new UDP().setSourcePort(1)
+                .setDestinationPort(2);
+
+        LispMapRegister.RegisterBuilder msgBuilder2 =
+                new DefaultLispMapRegister.DefaultRegisterBuilder();
+
+        List<LispMapRecord> records2 = ImmutableList.of(getMapRecord(),
+                                                        getMapRecord());
+
+        LispMapRegister innerMsg2 = msgBuilder2.withIsProxyMapReply(true)
+                .withIsWantMapNotify(false)
+                .withKeyId((short) 1)
+                .withNonce(1L)
+                .withMapRecords(records2)
+                .build();
+
+        sameAsEcm1 = builder2.isSecurity(false)
+                .innerIpHeader(innerIp2)
+                .innerUdpHeader(innerUdp2)
+                .innerLispMessage(innerMsg2)
+                .build();
+
+        //Creates ecm2
+        LispEncapsulatedControl.EcmBuilder builder3 =
+                new DefaultLispEncapsulatedControl.DefaultEcmBuilder();
+
+        IP innerIp3 = new IPv4().setSourceAddress(ECM2_SRC_IP)
+                .setDestinationAddress(ECM2_DST_IP)
+                .setProtocol(IPv4.PROTOCOL_UDP);
+        UDP innerUdp3 = new UDP().setSourcePort(10)
+                .setDestinationPort(20);
+
+        LispMapRegister.RegisterBuilder msgBuilder3 =
+                new DefaultLispMapRegister.DefaultRegisterBuilder();
+
+        List<LispMapRecord> records3 = ImmutableList.of(getMapRecord(),
+                                                        getMapRecord());
+
+        LispMapRegister innerMsg3 = msgBuilder3.withIsProxyMapReply(true)
+                .withIsWantMapNotify(false)
+                .withKeyId((short) 2)
+                .withNonce(1L)
+                .withMapRecords(records3)
+                .build();
+
+        ecm2 = builder3.isSecurity(false)
+                .innerIpHeader(innerIp3)
+                .innerUdpHeader(innerUdp3)
+                .innerLispMessage(innerMsg3)
+                .build();
+    }
+
+    @Test
+    public void testEquality() {
+        new EqualsTester()
+                .addEqualityGroup(ecm1, sameAsEcm1)
+                .addEqualityGroup(ecm2).testEquals();
+    }
+
+    @Test
+    public void testConstruction() {
+        DefaultLispEncapsulatedControl ecm =
+                (DefaultLispEncapsulatedControl) ecm1;
+
+        assertThat("Inner Ip versions are not match",
+                   ecm.innerIpHeader().getVersion(), is((byte) 4));
+        assertThat("Inner Ip protocols are not match",
+                   ((IPv4) ecm.innerIpHeader()).getProtocol(),
+                   is(IPv4.PROTOCOL_UDP));
+        assertThat("Inner IP source addresses are not match",
+                   ((IPv4) ecm.innerIpHeader()).getSourceAddress(),
+                   is(IPv4.toIPv4Address(ECM1_SRC_IP)));
+        assertThat("Inner IP destination addresses are not match",
+                   ((IPv4) ecm.innerIpHeader()).getDestinationAddress(),
+                   is(IPv4.toIPv4Address(ECM1_DST_IP)));
+        assertThat("Inner UDP source ports are not match",
+                   ecm.innerUdp().getSourcePort(), is(1));
+        assertThat("Inner UDP destination ports are not match",
+                   ecm.innerUdp().getDestinationPort(), is(2));
+        assertThat("Inner LISP control messages are not match",
+                   ecm.getControlMessage().getType(),
+                   is(LispType.LISP_MAP_REGISTER));
+    }
+
+    @Test
+    public void testSerialization() throws LispReaderException,
+            LispWriterException, LispParseError, DeserializationException {
+
+        ByteBuf byteBuf = Unpooled.buffer();
+        DefaultLispEncapsulatedControl.EcmWriter writer =
+                new DefaultLispEncapsulatedControl.EcmWriter();
+        writer.writeTo(byteBuf, ecm1);
+
+        DefaultLispEncapsulatedControl.EcmReader reader =
+                new DefaultLispEncapsulatedControl.EcmReader();
+
+        LispEncapsulatedControl deserialized = reader.readFrom(byteBuf);
+
+        new EqualsTester()
+                .addEqualityGroup(ecm1, deserialized).testEquals();
+    }
+
+    private LispMapRecord getMapRecord() {
+        LispMapRecord.MapRecordBuilder builder1 =
+                new DefaultLispMapRecord.DefaultMapRecordBuilder();
+
+        LispIpv4Address ipv4Locator1 =
+                new LispIpv4Address(IpAddress.valueOf(RECORD_EID));
+
+        return builder1
+                .withRecordTtl(100)
+                .withAuthoritative(true)
+                .withMapVersionNumber((short) 1)
+                .withMaskLength((byte) 0x01)
+                .withAction(LispMapReplyAction.NativelyForward)
+                .withEidPrefixAfi(ipv4Locator1)
+                .build();
+    }
+}