[ONOS-4718] Initial implementation of LISP control msg serializer

Change-Id: Ia068e1b158f05dd70839cb1020f15dc66b0142a0
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 66ef81d..37eeb71 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
@@ -20,9 +20,11 @@
 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 org.onosproject.lisp.msg.types.LispAfiAddress;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
 
 /**
  * Default implementation of LispLocatorRecord.
@@ -265,4 +267,59 @@
                         .build();
         }
     }
+
+    /**
+     * A LISP message writer for LocatorRecord portion.
+     */
+    public static final class LocatorRecordWriter implements LispMessageWriter<LispLocatorRecord> {
+
+        private static final int LOCAL_LOCATOR_SHIFT_BIT = 2;
+        private static final int PROBED_SHIFT_BIT = 1;
+
+        private static final int ENABLE_BIT = 1;
+        private static final int DISABLE_BIT = 0;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispLocatorRecord message) throws LispWriterException {
+
+            // priority
+            byteBuf.writeByte(message.getPriority());
+
+            // weight
+            byteBuf.writeByte(message.getWeight());
+
+            // multicast priority
+            byteBuf.writeByte(message.getMulticastPriority());
+
+            // multicast weight
+            byteBuf.writeByte(message.getMulticastWeight());
+
+            // unused flags
+            byteBuf.writeByte((short) 0);
+
+            // localLocator flag
+            short localLocator = DISABLE_BIT;
+            if (message.isLocalLocator()) {
+                localLocator = (byte) (ENABLE_BIT << LOCAL_LOCATOR_SHIFT_BIT);
+            }
+
+            // rlocProbed flag
+            short probed = DISABLE_BIT;
+            if (message.isRlocProbed()) {
+                probed = (byte) (ENABLE_BIT << PROBED_SHIFT_BIT);
+            }
+
+            // routed flag
+            short routed = DISABLE_BIT;
+            if (message.isRouted()) {
+                routed = (byte) ENABLE_BIT;
+            }
+
+            byteBuf.writeByte((byte) (localLocator + probed + routed));
+
+            // EID prefix AFI with EID prefix
+            AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
+            afiAddressWriter.writeTo(byteBuf, message.getLocatorAfi());
+        }
+    }
 }
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 05cc7f5..30eba1f 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
@@ -22,10 +22,13 @@
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 import org.onosproject.lisp.msg.exceptions.LispReaderException;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
 
+import java.util.Arrays;
 import java.util.List;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordWriter;
 
 /**
  * Default LISP map notify message class.
@@ -34,6 +37,7 @@
 
     private final long nonce;
     private final short keyId;
+    private final short authDataLength;
     private final byte[] authenticationData;
     private final byte recordCount;
     private final List<LispMapRecord> mapRecords;
@@ -47,10 +51,12 @@
      * @param recordCount        record count number
      * @param mapRecords         a collection of map records
      */
-    private DefaultLispMapNotify(long nonce, short keyId, byte[] authenticationData,
-                                 byte recordCount, List<LispMapRecord> mapRecords) {
+    private DefaultLispMapNotify(long nonce, short keyId, short authDataLength,
+                                 byte[] authenticationData, byte recordCount,
+                                 List<LispMapRecord> mapRecords) {
         this.nonce = nonce;
         this.keyId = keyId;
+        this.authDataLength = authDataLength;
         this.authenticationData = authenticationData;
         this.recordCount = recordCount;
         this.mapRecords = mapRecords;
@@ -73,26 +79,31 @@
 
     @Override
     public long getNonce() {
-        return this.nonce;
+        return nonce;
     }
 
     @Override
     public byte getRecordCount() {
-        return this.recordCount;
+        return recordCount;
     }
 
     @Override
     public short getKeyId() {
-        return this.keyId;
+        return keyId;
+    }
+
+    @Override
+    public short getAuthDataLength() {
+        return authDataLength;
     }
 
     @Override
     public byte[] getAuthenticationData() {
-        return ImmutableByteSequence.copyFrom(this.authenticationData).asArray();
+        return ImmutableByteSequence.copyFrom(authenticationData).asArray();
     }
 
     @Override
-    public List<LispMapRecord> getLispRecords() {
+    public List<LispMapRecord> getMapRecords() {
         return ImmutableList.copyOf(mapRecords);
     }
 
@@ -103,6 +114,8 @@
                 .add("nonce", nonce)
                 .add("recordCount", recordCount)
                 .add("keyId", keyId)
+                .add("authentication data length", authDataLength)
+                .add("authentication data", authenticationData)
                 .add("mapRecords", mapRecords).toString();
     }
 
@@ -118,18 +131,20 @@
         return Objects.equal(nonce, that.nonce) &&
                 Objects.equal(recordCount, that.recordCount) &&
                 Objects.equal(keyId, that.keyId) &&
+                Objects.equal(authDataLength, that.authDataLength) &&
                 Objects.equal(authenticationData, that.authenticationData);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(nonce, recordCount, keyId, authenticationData);
+        return Objects.hashCode(nonce, recordCount, keyId, authDataLength, authenticationData);
     }
 
     public static final class DefaultNotifyBuilder implements NotifyBuilder {
 
         private long nonce;
         private short keyId;
+        private short authDataLength;
         private byte[] authenticationData;
         private byte recordCount;
         private List<LispMapRecord> mapRecords;
@@ -158,6 +173,12 @@
         }
 
         @Override
+        public NotifyBuilder withAuthDataLength(short authDataLength) {
+            this.authDataLength = authDataLength;
+            return this;
+        }
+
+        @Override
         public NotifyBuilder withAuthenticationData(byte[] authenticationData) {
             this.authenticationData = authenticationData;
             return this;
@@ -171,15 +192,15 @@
 
         @Override
         public LispMapNotify build() {
-            return new DefaultLispMapNotify(nonce, keyId, authenticationData,
-                    recordCount, mapRecords);
+            return new DefaultLispMapNotify(nonce, keyId, authDataLength,
+                    authenticationData, recordCount, mapRecords);
         }
     }
 
     /**
-     * A private LISP message reader for MapNotify message.
+     * A LISP message reader for MapNotify message.
      */
-    private static class NotifyReader implements LispMessageReader<LispMapNotify> {
+    public static final class NotifyReader implements LispMessageReader<LispMapNotify> {
 
         private static final int RESERVED_SKIP_LENGTH = 3;
 
@@ -218,9 +239,64 @@
                         .withRecordCount(recordCount)
                         .withNonce(nonce)
                         .withKeyId(keyId)
+                        .withAuthDataLength(authLength)
                         .withAuthenticationData(authData)
                         .withMapRecords(mapRecords)
                         .build();
         }
     }
+
+    /**
+     * A LISP message reader for MapNotify message.
+     */
+    public static final class NotifyWriter implements LispMessageWriter<LispMapNotify> {
+
+        private static final int NOTIFY_MSG_TYPE = 4;
+        private static final int NOTIFY_SHIFT_BIT = 4;
+
+        private static final int UNUSED_ZERO = 0;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispMapNotify message) throws LispWriterException {
+
+            // specify LISP message type
+            byte msgType = (byte) (NOTIFY_MSG_TYPE << NOTIFY_SHIFT_BIT);
+            byteBuf.writeByte(msgType);
+
+            // reserved field
+            byteBuf.writeShort((short) UNUSED_ZERO);
+
+            // record count
+            byteBuf.writeByte(message.getRecordCount());
+
+            // nonce
+            byteBuf.writeLong(message.getNonce());
+
+            // keyId
+            byteBuf.writeShort(message.getKeyId());
+
+            // authentication data length in octet
+            byteBuf.writeShort(message.getAuthDataLength());
+
+            // authentication data
+            byte[] data = message.getAuthenticationData();
+            byte[] clone;
+            if (data != null) {
+                clone = data.clone();
+                Arrays.fill(clone, (byte) UNUSED_ZERO);
+            }
+
+            byteBuf.writeBytes(data);
+
+            // TODO: need to implement MAC authentication mechanism
+
+            // serialize map records
+            MapRecordWriter writer = new MapRecordWriter();
+            List<LispMapRecord> records = message.getMapRecords();
+
+            for (int i = 0; i < records.size(); i++) {
+                writer.writeTo(byteBuf, records.get(i));
+            }
+        }
+    }
 }
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 b6605d6..a924c7f 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
@@ -22,11 +22,14 @@
 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 org.onosproject.lisp.msg.types.LispAfiAddress;
 
 import java.util.List;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
+import static org.onosproject.lisp.msg.protocols.DefaultLispLocatorRecord.LocatorRecordWriter;
 
 /**
  * Default implementation of LispMapRecord.
@@ -268,4 +271,58 @@
                         .build();
         }
     }
+
+    /**
+     * A LISP message writer for MapRecord portion.
+     */
+    public static final class MapRecordWriter implements LispMessageWriter<LispMapRecord> {
+
+        private static final int REPLY_ACTION_SHIFT_BIT = 5;
+        private static final int AUTHORITATIVE_FLAG_SHIFT_BIT = 4;
+
+        private static final int ENABLE_BIT = 1;
+        private static final int DISABLE_BIT = 0;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispMapRecord message) throws LispWriterException {
+
+            // record TTL
+            byteBuf.writeInt(message.getRecordTtl());
+
+            // locator count
+            byteBuf.writeByte((byte) message.getLocatorCount());
+
+            // EID mask length
+            byteBuf.writeByte(message.getMaskLength());
+
+            // reply action
+            byte action = (byte) (message.getAction().getAction() << REPLY_ACTION_SHIFT_BIT);
+
+            // authoritative bit
+            byte authoritative = DISABLE_BIT;
+            if (message.isAuthoritative()) {
+                authoritative = ENABLE_BIT;
+            }
+            authoritative = (byte) (authoritative << AUTHORITATIVE_FLAG_SHIFT_BIT);
+
+            byteBuf.writeByte((byte) (action + authoritative));
+
+            // fill zero into reserved field
+            byteBuf.writeByte((short) 0);
+
+            // map version number
+            byteBuf.writeShort(message.getMapVersionNumber());
+
+            // EID prefix AFI with EID prefix
+            AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
+            afiAddressWriter.writeTo(byteBuf, message.getEidPrefixAfi());
+
+            // serialize locator
+            LocatorRecordWriter recordWriter = new LocatorRecordWriter();
+            List<LispLocatorRecord> locators = message.getLocators();
+            for (int i = 0; i < locators.size(); i++) {
+                recordWriter.writeTo(byteBuf, locators.get(i));
+            }
+        }
+    }
 }
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 7f75181..abaf3c8 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
@@ -23,11 +23,14 @@
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 import org.onosproject.lisp.msg.exceptions.LispReaderException;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
 
+import java.util.Arrays;
 import java.util.List;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 
+
 /**
  * Default LISP map register message class.
  */
@@ -35,6 +38,7 @@
 
     private final long nonce;
     private final short keyId;
+    private final short authDataLength;
     private final byte[] authenticationData;
     private final byte recordCount;
     private final List<LispMapRecord> mapRecords;
@@ -52,12 +56,13 @@
      * @param proxyMapReply      proxy map reply flag
      * @param wantMapNotify      want map notify flag
      */
-    private DefaultLispMapRegister(long nonce, short keyId,
+    private DefaultLispMapRegister(long nonce, short keyId, short authDataLength,
                                    byte[] authenticationData, byte recordCount,
                                    List<LispMapRecord> mapRecords,
                                    boolean proxyMapReply, boolean wantMapNotify) {
         this.nonce = nonce;
         this.keyId = keyId;
+        this.authDataLength = authDataLength;
         this.authenticationData = authenticationData;
         this.recordCount = recordCount;
         this.mapRecords = mapRecords;
@@ -106,6 +111,11 @@
     }
 
     @Override
+    public short getAuthDataLength() {
+        return authDataLength;
+    }
+
+    @Override
     public byte[] getAuthenticationData() {
         return ImmutableByteSequence.copyFrom(this.authenticationData).asArray();
     }
@@ -122,6 +132,8 @@
                 .add("nonce", nonce)
                 .add("recordCount", recordCount)
                 .add("keyId", keyId)
+                .add("authentication data length", authDataLength)
+                .add("authentication data", authenticationData)
                 .add("mapRecords", mapRecords)
                 .add("proxyMapReply", proxyMapReply)
                 .add("wantMapNotify", wantMapNotify).toString();
@@ -140,6 +152,7 @@
         return Objects.equal(nonce, that.nonce) &&
                 Objects.equal(recordCount, that.recordCount) &&
                 Objects.equal(keyId, that.keyId) &&
+                Objects.equal(authDataLength, that.authDataLength) &&
                 Objects.equal(authenticationData, that.authenticationData) &&
                 Objects.equal(proxyMapReply, that.proxyMapReply) &&
                 Objects.equal(wantMapNotify, that.wantMapNotify);
@@ -147,14 +160,15 @@
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(nonce, recordCount, keyId, authenticationData,
-                                proxyMapReply, wantMapNotify);
+        return Objects.hashCode(nonce, recordCount, keyId, authDataLength,
+                authenticationData, proxyMapReply, wantMapNotify);
     }
 
     public static final class DefaultRegisterBuilder implements RegisterBuilder {
 
         private long nonce;
         private short keyId;
+        private short authDataLength;
         private byte[] authenticationData;
         private byte recordCount;
         private List<LispMapRecord> mapRecords;
@@ -191,6 +205,12 @@
         }
 
         @Override
+        public RegisterBuilder withAuthDataLength(short authDataLength) {
+            this.authDataLength = authDataLength;
+            return this;
+        }
+
+        @Override
         public RegisterBuilder withKeyId(short keyId) {
             this.keyId = keyId;
             return this;
@@ -210,15 +230,15 @@
 
         @Override
         public LispMapRegister build() {
-            return new DefaultLispMapRegister(nonce, keyId, authenticationData,
-                    recordCount, mapRecords, proxyMapReply, wantMapNotify);
+            return new DefaultLispMapRegister(nonce, keyId, authDataLength,
+                    authenticationData, recordCount, mapRecords, proxyMapReply, wantMapNotify);
         }
     }
 
     /**
-     * A private LISP message reader for MapRegister message.
+     * A LISP message reader for MapRegister message.
      */
-    private static class RegisterReader implements LispMessageReader<LispMapRegister> {
+    public static final class RegisterReader implements LispMessageReader<LispMapRegister> {
 
         private static final int PROXY_MAP_REPLY_INDEX = 3;
         private static final int WANT_MAP_NOTIFY_INDEX = 0;
@@ -274,4 +294,78 @@
                     .build();
         }
     }
+
+    /**
+     * LISP map register message writer class.
+     */
+    public static class RegisterWriter implements LispMessageWriter<LispMapRegister> {
+
+        private static final int REGISTER_MSG_TYPE = 3;
+        private static final int REGISTER_SHIFT_BIT = 4;
+
+        private static final int PROXY_MAP_REPLY_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, LispMapRegister message) throws LispWriterException {
+
+            // specify LISP message type
+            byte msgType = (byte) (REGISTER_MSG_TYPE << REGISTER_SHIFT_BIT);
+
+            // proxy map reply flag
+            byte proxyMapReply = DISABLE_BIT;
+            if (message.isProxyMapReply())  {
+                proxyMapReply = (byte) (ENABLE_BIT << PROXY_MAP_REPLY_SHIFT_BIT);
+            }
+
+            byteBuf.writeByte(msgType + proxyMapReply);
+
+            // fill zero into reserved field
+            byteBuf.writeByte((short) UNUSED_ZERO);
+
+            // want map notify flag
+            byte wantMapNotify = DISABLE_BIT;
+            if (message.isWantMapNotify()) {
+                wantMapNotify = (byte) ENABLE_BIT;
+            }
+
+            byteBuf.writeByte(wantMapNotify);
+
+            // record count
+            byteBuf.writeByte(message.getRecordCount());
+
+            // nonce
+            byteBuf.writeLong(message.getNonce());
+
+            // keyId
+            byteBuf.writeShort(message.getKeyId());
+
+            // authentication data length in octet
+            byteBuf.writeShort(message.getAuthDataLength());
+
+            // authentication data
+            byte[] data = message.getAuthenticationData();
+            byte[] clone;
+            if (data != null) {
+                clone = data.clone();
+                Arrays.fill(clone, (byte) UNUSED_ZERO);
+            }
+
+            byteBuf.writeBytes(data);
+
+            // TODO: need to implement MAC authentication mechanism
+
+            // serialize map records
+            DefaultLispMapRecord.MapRecordWriter writer = new DefaultLispMapRecord.MapRecordWriter();
+            List<LispMapRecord> records = message.getMapRecords();
+
+            for (int i = 0; i < records.size(); i++) {
+                writer.writeTo(byteBuf, records.get(i));
+            }
+        }
+    }
 }
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 a180a2d..220bf7e 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
@@ -22,10 +22,12 @@
 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 java.util.List;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordWriter;
 
 /**
  * Default LISP map reply message class.
@@ -75,27 +77,27 @@
 
     @Override
     public boolean isProbe() {
-        return this.probe;
+        return probe;
     }
 
     @Override
     public boolean isEtr() {
-        return this.etr;
+        return etr;
     }
 
     @Override
     public boolean isSecurity() {
-        return this.security;
+        return security;
     }
 
     @Override
     public byte getRecordCount() {
-        return this.recordCount;
+        return recordCount;
     }
 
     @Override
     public long getNonce() {
-        return this.nonce;
+        return nonce;
     }
 
     @Override
@@ -194,9 +196,9 @@
     }
 
     /**
-     * A private LISP message reader for MapReply message.
+     * A LISP message reader for MapReply message.
      */
-    private static class ReplyReader implements LispMessageReader<LispMapReply> {
+    public static final class ReplyReader implements LispMessageReader<LispMapReply> {
 
         private static final int PROBE_INDEX = 3;
         private static final int ETR_INDEX = 2;
@@ -244,4 +246,66 @@
                         .build();
         }
     }
+
+    /**
+     * A LISP message writer for MapReply message.
+     */
+    public static final class ReplyWriter implements LispMessageWriter<LispMapReply> {
+
+        private static final int REPLY_MSG_TYPE = 2;
+        private static final int REPLY_SHIFT_BIT = 4;
+
+        private static final int PROBE_FLAG_SHIFT_BIT = 3;
+        private static final int ETR_FLAG_SHIFT_BIT = 2;
+        private static final int SECURITY_FLAG_SHIFT_BIT = 1;
+
+        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, LispMapReply message) throws LispWriterException {
+
+            // specify LISP message type
+            byte msgType = (byte) (REPLY_MSG_TYPE << REPLY_SHIFT_BIT);
+
+            // probe flag
+            byte probe = DISABLE_BIT;
+            if (message.isProbe()) {
+                probe = (byte) (ENABLE_BIT << PROBE_FLAG_SHIFT_BIT);
+            }
+
+            // etr flag
+            byte etr = DISABLE_BIT;
+            if (message.isEtr()) {
+                etr = (byte) (ENABLE_BIT << ETR_FLAG_SHIFT_BIT);
+            }
+
+            // security flag
+            byte security = DISABLE_BIT;
+            if (message.isSecurity()) {
+                security = (byte) (ENABLE_BIT << SECURITY_FLAG_SHIFT_BIT);
+            }
+
+            byteBuf.writeByte((byte) (msgType + probe + etr + security));
+
+            // reserved field
+            byteBuf.writeShort((short) UNUSED_ZERO);
+
+            // record count
+            byteBuf.writeByte(message.getRecordCount());
+
+            // nonce
+            byteBuf.writeLong(message.getNonce());
+
+            // serialize map records
+            MapRecordWriter writer = new MapRecordWriter();
+            List<LispMapRecord> records = message.getMapRecords();
+
+            for (int i = 0; i < records.size(); i++) {
+                writer.writeTo(byteBuf, records.get(i));
+            }
+        }
+    }
 }
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 9c6ff92..45e85bf 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
@@ -22,11 +22,14 @@
 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 org.onosproject.lisp.msg.types.LispAfiAddress;
 
 import java.util.List;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
+import static org.onosproject.lisp.msg.protocols.LispEidRecord.EidRecordWriter;
 
 /**
  * Default LISP map request message class.
@@ -94,47 +97,47 @@
 
     @Override
     public boolean isAuthoritative() {
-        return this.authoritative;
+        return authoritative;
     }
 
     @Override
     public boolean isMapDataPresent() {
-        return this.mapDataPresent;
+        return mapDataPresent;
     }
 
     @Override
     public boolean isProbe() {
-        return this.probe;
+        return probe;
     }
 
     @Override
     public boolean isSmr() {
-        return this.smr;
+        return smr;
     }
 
     @Override
     public boolean isPitr() {
-        return this.pitr;
+        return pitr;
     }
 
     @Override
     public boolean isSmrInvoked() {
-        return this.smrInvoked;
+        return smrInvoked;
     }
 
     @Override
     public byte getRecordCount() {
-        return this.recordCount;
+        return recordCount;
     }
 
     @Override
     public long getNonce() {
-        return this.nonce;
+        return nonce;
     }
 
     @Override
     public LispAfiAddress getSourceEid() {
-        return this.sourceEid;
+        return sourceEid;
     }
 
     @Override
@@ -285,9 +288,9 @@
     }
 
     /**
-     * A private LISP message reader for MapRequest message.
+     * A LISP message reader for MapRequest message.
      */
-    private static class RequestReader implements LispMessageReader<LispMapRequest> {
+    public static final class RequestReader implements LispMessageReader<LispMapRequest> {
 
         private static final int AUTHORITATIVE_INDEX = 3;
         private static final int MAP_DATA_PRESENT_INDEX = 2;
@@ -365,4 +368,101 @@
                         .build();
         }
     }
+
+    /**
+     * A LISP message writer for MapRequest message.
+     */
+    public static final class RequestWriter implements LispMessageWriter<LispMapRequest> {
+
+        private static final int REQUEST_MSG_TYPE = 1;
+        private static final int REQUEST_SHIFT_BIT = 4;
+
+        private static final int AUTHORITATIVE_SHIFT_BIT = 3;
+        private static final int MAP_DATA_PRESENT_SHIFT_BIT = 2;
+        private static final int PROBE_SHIFT_BIT = 1;
+
+        private static final int PITR_SHIFT_BIT = 7;
+        private static final int SMR_INVOKED_SHIFT_BIT = 6;
+
+        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, LispMapRequest message) throws LispWriterException {
+
+            // specify LISP message type
+            byte msgType = (byte) (REQUEST_MSG_TYPE << REQUEST_SHIFT_BIT);
+
+            // authoritative flag
+            byte authoritative = DISABLE_BIT;
+            if (message.isAuthoritative()) {
+                authoritative = (byte) (ENABLE_BIT << AUTHORITATIVE_SHIFT_BIT);
+            }
+
+            // map data present flag
+            byte mapDataPresent = DISABLE_BIT;
+            if (message.isMapDataPresent()) {
+                mapDataPresent = (byte) (ENABLE_BIT << MAP_DATA_PRESENT_SHIFT_BIT);
+            }
+
+            // probe flag
+            byte probe = DISABLE_BIT;
+            if (message.isProbe()) {
+                probe = (byte) (ENABLE_BIT << PROBE_SHIFT_BIT);
+            }
+
+            // SMR flag
+            byte smr = DISABLE_BIT;
+            if (message.isSmr()) {
+                smr = (byte) ENABLE_BIT;
+            }
+
+            byteBuf.writeByte((byte) (msgType + authoritative + mapDataPresent + probe + smr));
+
+            // PITR flag bit
+            byte pitr = DISABLE_BIT;
+            if (message.isPitr()) {
+                pitr = (byte) (ENABLE_BIT << PITR_SHIFT_BIT);
+            }
+
+            // SMR invoked flag bit
+            byte smrInvoked = DISABLE_BIT;
+            if (message.isSmrInvoked()) {
+                smrInvoked = (byte) (ENABLE_BIT << SMR_INVOKED_SHIFT_BIT);
+            }
+
+            byteBuf.writeByte((byte) (pitr + smrInvoked));
+
+            // TODO: ITR RLOC count
+            byteBuf.writeByte((byte) UNUSED_ZERO);
+
+            // record count
+            byteBuf.writeByte(message.getRecordCount());
+
+            // nonce
+            byteBuf.writeLong(message.getNonce());
+
+            // Source EID AFI with Source EID address
+            AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
+            afiAddressWriter.writeTo(byteBuf, message.getSourceEid());
+
+            // ITR RLOCs
+            List<LispAfiAddress> rlocs = message.getItrRlocs();
+            for (int i = 0; i < rlocs.size(); i++) {
+                afiAddressWriter.writeTo(byteBuf, rlocs.get(i));
+            }
+
+            // EID records
+            EidRecordWriter recordWriter = new EidRecordWriter();
+            List<LispEidRecord> records = message.getEids();
+
+            for (int i = 0; i < records.size(); i++) {
+                recordWriter.writeTo(byteBuf, records.get(i));
+            }
+
+            // TODO: handle Map-Reply record
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java
index 1e79d19..35fe975 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java
@@ -18,8 +18,11 @@
 import io.netty.buffer.ByteBuf;
 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.LispAfiAddress;
 
+import static org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
+
 /**
  * LISP EID record section which is part of LISP map request message.
  */
@@ -58,9 +61,9 @@
     }
 
     /**
-     * A private LISP message reader for EidRecord portion.
+     * A LISP message reader for EidRecord portion.
      */
-    public static class EidRecordReader implements LispMessageReader<LispEidRecord> {
+    public static final class EidRecordReader implements LispMessageReader<LispEidRecord> {
 
         private static final int RESERVED_SKIP_LENGTH = 1;
 
@@ -77,4 +80,26 @@
             return new LispEidRecord((byte) maskLength, prefix);
         }
     }
+
+    /**
+     * A LISP message writer for EidRecord portion.
+     */
+    public static final class EidRecordWriter implements LispMessageWriter<LispEidRecord> {
+
+        private static final int UNUSED_ZERO = 0;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispEidRecord message) throws LispWriterException {
+
+            // fill zero into reserved field
+            byteBuf.writeByte((short) UNUSED_ZERO);
+
+            // mask length
+            byteBuf.writeByte(message.getMaskLength());
+
+            // EID prefix AFI with EID prefix
+            AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
+            afiAddressWriter.writeTo(byteBuf, message.getPrefix());
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java
index fd6e025..052df6a 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java
@@ -78,6 +78,13 @@
     short getKeyId();
 
     /**
+     * Obtains authentication data length.
+     *
+     * @return authentication data length
+     */
+    short getAuthDataLength();
+
+    /**
      * Obtains authentication data.
      *
      * @return authentication data
@@ -89,7 +96,7 @@
      *
      * @return a collection of records
      */
-    List<LispMapRecord> getLispRecords();
+    List<LispMapRecord> getMapRecords();
 
     /**
      * A builder of LISP map notify message.
@@ -121,6 +128,14 @@
         NotifyBuilder withKeyId(short keyId);
 
         /**
+         * Sets authentication data length.
+         *
+         * @param authDataLength authentication data length
+         * @return NotifyBuilder object
+         */
+        NotifyBuilder withAuthDataLength(short authDataLength);
+
+        /**
          * Sets authentication data.
          *
          * @param authenticationData authentication data
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java
index 16f6956..beb79dd 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java
@@ -92,6 +92,13 @@
     short getKeyId();
 
     /**
+     * Obtains authentication data length.
+     *
+     * @return authentication data length
+     */
+    short getAuthDataLength();
+
+    /**
      * Obtains authentication data.
      *
      * @return authentication data
@@ -143,6 +150,14 @@
         RegisterBuilder withNonce(long nonce);
 
         /**
+         * Sets authentication data length.
+         *
+         * @param authDataLength authentication data length
+         * @return RegisterBuilder object
+         */
+        RegisterBuilder withAuthDataLength(short authDataLength);
+
+        /**
          * Sets key identifier.
          *
          * @param keyId key identifier
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageWriter.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageWriter.java
new file mode 100644
index 0000000..b350ab0
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMessageWriter.java
@@ -0,0 +1,34 @@
+/*
+ * 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 io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
+
+/**
+ * An interface for serializing LISP control message.
+ */
+public interface LispMessageWriter<T> {
+
+    /**
+     * Serializes LISP control message object and writes to byte buffer.
+     *
+     * @param byteBuf byte buffer
+     * @param message LISP address type instance
+     * @throws LispWriterException LISP writer exception
+     */
+    void writeTo(ByteBuf byteBuf, T message) throws LispWriterException;
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAddressWriter.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAddressWriter.java
index 299f57a..2dcea9a 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAddressWriter.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAddressWriter.java
@@ -24,11 +24,11 @@
 public interface LispAddressWriter<T> {
 
     /**
-     * Writes from LISP address object and serialize to byte buffer.
+     * Serializes LISP address object and writes to byte buffer.
      *
      * @param byteBuf byte buffer
      * @param address LISP address type instance
-     * @throws LispWriterException Lisp writer exception
+     * @throws LispWriterException LISP writer exception
      */
     void writeTo(ByteBuf byteBuf, T address) throws LispWriterException;