[ONOS-4718] Initial implementation of LISP address deserializer

Change-Id: I522e16e7fd197380cf4c99038561fe9aa8f93730
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/exceptions/LispReaderException.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/exceptions/LispReaderException.java
new file mode 100644
index 0000000..6665257
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/exceptions/LispReaderException.java
@@ -0,0 +1,57 @@
+/*
+ * 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.exceptions;
+
+/**
+ * LISP address or message reader exception.
+ */
+public class LispReaderException extends Exception {
+
+    /**
+     * Constructor for LispReaderException.
+     */
+    public LispReaderException() {
+        super();
+    }
+
+    /**
+     * Constructor for LispReaderException with message and cause parameters.
+     *
+     * @param message exception message
+     * @param cause   throwable cause
+     */
+    public LispReaderException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructor for LispReaderException with message parameter.
+     *
+     * @param message exception message
+     */
+    public LispReaderException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor for LispReaderException with cause parameter.
+     *
+     * @param cause throwable cause
+     */
+    public LispReaderException(final Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAddressReader.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAddressReader.java
new file mode 100644
index 0000000..7a1f4fc
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAddressReader.java
@@ -0,0 +1,35 @@
+/*
+ * 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.types;
+
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+
+/**
+ * An interface for de-serializing LISP address.
+ */
+public interface LispAddressReader<T> {
+
+    /**
+     * Reads from byte buffer and de-serialize the LISP address.
+     *
+     * @param byteBuf byte buffer
+     * @return LISP address type instance
+     * @throws LispParseError LISP address parse error
+     */
+    T readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException;
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddress.java
index 93ce78f..9493911 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddress.java
@@ -15,6 +15,11 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+
+import java.nio.ByteBuffer;
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -44,41 +49,35 @@
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * }</pre>
  */
-public class LispAppDataLcafAddress extends LispLcafAddress {
+public final class LispAppDataLcafAddress extends LispLcafAddress {
 
     private final byte protocol;
     private final int ipTos;
-    private final short localPort;
-    private final short remotePort;
+    private final short localPortLow;
+    private final short localPortHigh;
+    private final short remotePortLow;
+    private final short remotePortHigh;
     private LispAfiAddress address;
 
     /**
-     * Initializes application data type LCAF address.
+     * @param protocol       protocol number
+     * @param ipTos          IP type of service
+     * @param localPortLow   low-ranged local port number
+     * @param localPortHigh  high-ranged local port number
+     * @param remotePortLow  low-ranged remote port number
+     * @param remotePortHigh high-ranged remote port number
+     * @param address        address
      */
-    public LispAppDataLcafAddress() {
-        super(LispCanonicalAddressFormatEnum.APPLICATION_DATA);
-        this.protocol = 0;
-        this.ipTos = 0;
-        this.localPort = 0;
-        this.remotePort = 0;
-    }
-
-    /**
-     * Initializes application data type LCAF address.
-     *
-     * @param protocol protocol number
-     * @param ipTos ip type of service
-     * @param localPort local port number
-     * @param remotePort remote port number
-     * @param address address
-     */
-    public LispAppDataLcafAddress(byte protocol, int ipTos, short localPort, short remotePort,
-                                  LispAfiAddress address) {
+    private LispAppDataLcafAddress(byte protocol, int ipTos, short localPortLow,
+                                   short localPortHigh, short remotePortLow,
+                                   short remotePortHigh, LispAfiAddress address) {
         super(LispCanonicalAddressFormatEnum.APPLICATION_DATA);
         this.protocol = protocol;
         this.ipTos = ipTos;
-        this.localPort = localPort;
-        this.remotePort = remotePort;
+        this.localPortLow = localPortLow;
+        this.localPortHigh = localPortHigh;
+        this.remotePortLow = remotePortLow;
+        this.remotePortHigh = remotePortHigh;
         this.address = address;
     }
 
@@ -101,21 +100,39 @@
     }
 
     /**
-     * Obtains local port number.
+     * Obtains low-ranged local port number.
      *
-     * @return local port number
+     * @return low-ranged local port number
      */
-    public short getLocalPort() {
-        return localPort;
+    public short getLocalPortLow() {
+        return localPortLow;
     }
 
     /**
-     * Obtains remote port number.
+     * Obtains high-ranged local port number.
      *
-     * @return remote port number
+     * @return high-ranged local port number
      */
-    public short getRemotePort() {
-        return remotePort;
+    public short getLocalPortHigh() {
+        return localPortHigh;
+    }
+
+    /**
+     * Obtains low-ranged remote port number.
+     *
+     * @return low-ranged remote port number
+     */
+    public short getRemotePortLow() {
+        return remotePortLow;
+    }
+
+    /**
+     * Obtains high-ranged remote port number.
+     *
+     * @return high-ranged remote port number
+     */
+    public short getRemotePortHigh() {
+        return remotePortHigh;
     }
 
     /**
@@ -129,7 +146,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(address, protocol, ipTos, localPort, remotePort);
+        return Objects.hash(address, protocol, ipTos, localPortLow,
+                localPortHigh, remotePortLow, remotePortHigh);
     }
 
     @Override
@@ -143,8 +161,10 @@
             return Objects.equals(this.address, other.address) &&
                     Objects.equals(this.protocol, other.protocol) &&
                     Objects.equals(this.ipTos, other.ipTos) &&
-                    Objects.equals(this.localPort, other.localPort) &&
-                    Objects.equals(this.remotePort, other.remotePort);
+                    Objects.equals(this.localPortLow, other.localPortLow) &&
+                    Objects.equals(this.localPortHigh, other.localPortHigh) &&
+                    Objects.equals(this.remotePortLow, other.remotePortLow) &&
+                    Objects.equals(this.remotePortHigh, other.remotePortHigh);
         }
         return false;
     }
@@ -155,8 +175,154 @@
                 .add("address", address)
                 .add("protocol", protocol)
                 .add("ip type of service", ipTos)
-                .add("local port number", localPort)
-                .add("remote port number", remotePort)
+                .add("low-ranged local port number", localPortLow)
+                .add("high-ranged local port number", localPortHigh)
+                .add("low-ranged remote port number", remotePortLow)
+                .add("high-ranged remote port number", remotePortHigh)
                 .toString();
     }
+
+    public static final class AppDataAddressBuilder {
+        private byte protocol;
+        private int ipTos;
+        private short localPortLow;
+        private short localPortHigh;
+        private short remotePortLow;
+        private short remotePortHigh;
+        private LispAfiAddress address;
+
+        /**
+         * Sets protocol number.
+         *
+         * @param protocol protocol number
+         * @return AppDataAddressBuilder object
+         */
+        AppDataAddressBuilder withProtocol(byte protocol) {
+            this.protocol = protocol;
+            return this;
+        }
+
+        /**
+         * Sets IP type of service.
+         *
+         * @param ipTos IP type of service
+         * @return AppDataAddressBuilder object
+         */
+        AppDataAddressBuilder withIpTos(int ipTos) {
+            this.ipTos = ipTos;
+            return this;
+        }
+
+        /**
+         * Sets low-ranged local port number.
+         *
+         * @param localPortLow low-ranged local port number
+         * @return AppDataAddressBuilder object
+         */
+        AppDataAddressBuilder withLocalPortLow(short localPortLow) {
+            this.localPortLow = localPortLow;
+            return this;
+        }
+
+        /**
+         * Sets high-ranged local port number.
+         *
+         * @param localPortHigh high-ranged local port number
+         * @return AppDataAddressBuilder object
+         */
+        AppDataAddressBuilder withLocalPortHigh(short localPortHigh) {
+            this.localPortHigh = localPortHigh;
+            return this;
+        }
+
+        /**
+         * Sets low-ranged remote port number.
+         *
+         * @param remotePortLow low-ranged remote port number
+         * @return AppDataAddressBuilder object
+         */
+        AppDataAddressBuilder withRemotePortLow(short remotePortLow) {
+            this.remotePortLow = remotePortLow;
+            return this;
+        }
+
+        /**
+         * Sets high-ranged remote port number.
+         *
+         * @param remotePortHigh high-ranged remote port number
+         * @return AppDataAddressBuilder object
+         */
+        AppDataAddressBuilder withRemotePortHigh(short remotePortHigh) {
+            this.remotePortHigh = remotePortHigh;
+            return this;
+        }
+
+        /**
+         * Sets AFI address.
+         *
+         * @param address AFI address
+         * @return AppDataAddressBuilder object
+         */
+        AppDataAddressBuilder withAddress(LispAfiAddress address) {
+            this.address = address;
+            return this;
+        }
+
+        /**
+         * Builds LispAppDataLcafAddress instance.
+         *
+         * @return LispAddDataLcafAddress instance
+         */
+        LispAppDataLcafAddress build() {
+            return new LispAppDataLcafAddress(protocol, ipTos, localPortLow,
+                    localPortHigh, remotePortLow, remotePortHigh, address);
+        }
+    }
+
+    /**
+     * Application data LCAF address reader class.
+     */
+    public static class AppDataLcafAddressReader
+            implements LispAddressReader<LispAppDataLcafAddress> {
+
+        @Override
+        public LispAppDataLcafAddress readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
+
+            byte[] ipTosByte = new byte[3];
+            byteBuf.readBytes(ipTosByte);
+
+            byte protocol = (byte) byteBuf.readUnsignedByte();
+            int ipTos = getPartialInt(ipTosByte);
+            short localPortLow = (short) byteBuf.readUnsignedShort();
+            short localPortHigh = (short) byteBuf.readUnsignedShort();
+            short remotePortLow = (short) byteBuf.readUnsignedShort();
+            short remotePortHigh = (short) byteBuf.readUnsignedShort();
+
+            LispAfiAddress address = new LispIpAddress.IpAddressReader().readFrom(byteBuf);
+
+            return new AppDataAddressBuilder()
+                        .withProtocol(protocol)
+                        .withIpTos(ipTos)
+                        .withLocalPortLow(localPortLow)
+                        .withLocalPortHigh(localPortHigh)
+                        .withRemotePortLow(remotePortLow)
+                        .withRemotePortHigh(remotePortHigh)
+                        .withAddress(address)
+                        .build();
+        }
+
+        /**
+         * A utility function that obtains the partial int value from byte arrays.
+         *
+         * @param bytes an array of bytes
+         * @return converted integer
+         */
+        public static int getPartialInt(byte[] bytes) {
+            ByteBuffer buffer = ByteBuffer.allocate(4);
+            buffer.position(4 - bytes.length);
+            buffer.put(bytes);
+            buffer.position(0);
+            return buffer.getInt();
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAsAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAsAddress.java
index fb5c616..28fa729 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAsAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAsAddress.java
@@ -15,6 +15,10 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+
 import java.util.Objects;
 
 /**
@@ -73,4 +77,15 @@
     public String toString() {
         return String.valueOf(asNum);
     }
+
+    /**
+     * Autonomous system address reader class.
+     */
+    public static class AsAddressReader implements LispAddressReader<LispAsAddress> {
+
+        @Override
+        public LispAsAddress readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
+            throw new LispReaderException("Unimplemented method");
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispDistinguishedNameAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispDistinguishedNameAddress.java
index d5fbc988..e0d631f 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispDistinguishedNameAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispDistinguishedNameAddress.java
@@ -15,6 +15,9 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -69,4 +72,24 @@
                 .add("distinguished name", distinguishedName)
                 .toString();
     }
+
+    /**
+     * Distinguished name address reader class.
+     */
+    public static class DistinguishedNameAddressReader
+                        implements LispAddressReader<LispDistinguishedNameAddress> {
+
+        @Override
+        public LispDistinguishedNameAddress readFrom(ByteBuf byteBuf) throws LispParseError {
+
+            StringBuilder sb = new StringBuilder();
+            byte character = byteBuf.readByte();
+            while (character != 0) {
+                sb.append((char) character);
+                character = byteBuf.readByte();
+            }
+
+            return new LispDistinguishedNameAddress(sb.toString());
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpAddress.java
index 5af82ac..29d0b70 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpAddress.java
@@ -15,7 +15,10 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
 import org.onlab.packet.IpAddress;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
 
 /**
  * IP address that is used by LISP Locator.
@@ -58,4 +61,25 @@
     public String toString() {
         return address.toString();
     }
+
+    /**
+     * IP Address reader class.
+     */
+    public static class IpAddressReader implements LispAddressReader<LispIpAddress> {
+
+        @Override
+        public LispIpAddress readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
+
+            // AFI code -> 16 bits
+            short afiCode = (short) byteBuf.readUnsignedShort();
+
+            if (afiCode == 1) {
+                return new LispIpv4Address.Ipv4AddressReader().readFrom(byteBuf);
+            } else if (afiCode == 2) {
+                return new LispIpv6Address.Ipv6AddressReader().readFrom(byteBuf);
+            }
+
+            return null;
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv4Address.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv4Address.java
index 31d607b..1cc5829 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv4Address.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv4Address.java
@@ -15,7 +15,9 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
 import org.onlab.packet.IpAddress;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
 
 import java.util.Objects;
 
@@ -54,4 +56,22 @@
     public int hashCode() {
         return Objects.hash(address, getAfi());
     }
+
+    /**
+     * IPv4 address reader class.
+     */
+    public static class Ipv4AddressReader implements LispAddressReader<LispIpv4Address> {
+
+        private static final int SIZE_OF_IPV4_ADDRESS = 4;
+
+        @Override
+        public LispIpv4Address readFrom(ByteBuf byteBuf) throws LispParseError {
+
+            byte[] ipByte = new byte[SIZE_OF_IPV4_ADDRESS];
+            byteBuf.readBytes(ipByte);
+            IpAddress ipAddress = IpAddress.valueOf(IpAddress.Version.INET, ipByte);
+
+            return new LispIpv4Address(ipAddress);
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv6Address.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv6Address.java
index f486d28..f2eccaa 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv6Address.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispIpv6Address.java
@@ -15,7 +15,9 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
 import org.onlab.packet.IpAddress;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
 
 import java.util.Objects;
 
@@ -54,4 +56,22 @@
     public int hashCode() {
         return Objects.hash(address, getAfi());
     }
+
+    /**
+     * IPv6 address reader class.
+     */
+    public static class Ipv6AddressReader implements LispAddressReader<LispIpv6Address> {
+
+        private static final int SIZE_OF_IPV6_ADDRESS = 16;
+
+        @Override
+        public LispIpv6Address readFrom(ByteBuf byteBuf) throws LispParseError {
+
+            byte[] ipByte = new byte[SIZE_OF_IPV6_ADDRESS];
+            byteBuf.readBytes(ipByte);
+            IpAddress ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, ipByte);
+
+            return new LispIpv6Address(ipAddress);
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispListLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispListLcafAddress.java
index 85e5a86..2077059 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispListLcafAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispListLcafAddress.java
@@ -16,6 +16,9 @@
 package org.onosproject.lisp.msg.types;
 
 import com.google.common.collect.ImmutableList;
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
 
 import java.util.List;
 import java.util.Objects;
@@ -51,7 +54,7 @@
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * }</pre>
  */
-public class LispListLcafAddress extends LispLcafAddress {
+public final class LispListLcafAddress extends LispLcafAddress {
 
     private static final byte LENGTH = 24;
     List<LispAfiAddress> addresses;
@@ -99,4 +102,20 @@
                 .add("addresses", addresses)
                 .toString();
     }
+
+    /**
+     * List LCAF address reader class.
+     */
+    public static class ListLcafAddressReader implements LispAddressReader<LispListLcafAddress> {
+
+        @Override
+        public LispListLcafAddress readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
+
+
+            LispAfiAddress ipv4 = new LispIpAddress.IpAddressReader().readFrom(byteBuf);
+            LispAfiAddress ipv6 = new LispIpAddress.IpAddressReader().readFrom(byteBuf);
+
+            return new LispListLcafAddress(ImmutableList.of(ipv4, ipv6));
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispMacAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispMacAddress.java
index 3a36255..ba789b6 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispMacAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispMacAddress.java
@@ -15,7 +15,9 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
 import org.onlab.packet.MacAddress;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
 
 import java.util.Objects;
 
@@ -68,4 +70,22 @@
     public String toString() {
         return address.toString();
     }
+
+    /**
+     * MAC address reader class.
+     */
+    public static class MacAddressReader implements LispAddressReader<LispMacAddress> {
+
+        private static final int SIZE_OF_MAC_ADDRESS = 6;
+
+        @Override
+        public LispMacAddress readFrom(ByteBuf byteBuf) throws LispParseError {
+
+            byte[] macByte = new byte[SIZE_OF_MAC_ADDRESS];
+            byteBuf.readBytes(macByte);
+            MacAddress macAddress = MacAddress.valueOf(macByte);
+
+            return new LispMacAddress(macAddress);
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java
index f6e1caf..592250d 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java
@@ -15,6 +15,9 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+
 /**
  * No address.
  */
@@ -26,4 +29,15 @@
     public LispNoAddress() {
         super(AddressFamilyIdentifierEnum.NO_ADDRESS);
     }
+
+    /**
+     * LISP no address reader class.
+     */
+    public static class NoAddressReader implements LispAddressReader<LispNoAddress> {
+
+        @Override
+        public LispNoAddress readFrom(ByteBuf byteBuf) throws LispParseError {
+            return new LispNoAddress();
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddress.java
index 6204983..39ed103 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddress.java
@@ -15,6 +15,10 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -40,7 +44,7 @@
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * }</pre>
  */
-public class LispSegmentLcafAddress extends LispLcafAddress {
+public final class LispSegmentLcafAddress extends LispLcafAddress {
 
     private final LispAfiAddress address;
     private final int instanceId;
@@ -52,7 +56,7 @@
      * @param instanceId instance id
      * @param address address
      */
-    public LispSegmentLcafAddress(byte idMaskLength, int instanceId, LispAfiAddress address) {
+    private LispSegmentLcafAddress(byte idMaskLength, int instanceId, LispAfiAddress address) {
         super(LispCanonicalAddressFormatEnum.SEGMENT, idMaskLength);
         this.address = address;
         this.instanceId = instanceId;
@@ -113,4 +117,75 @@
                 .add("idMaskLength", reserved2)
                 .toString();
     }
+
+    public static final class SegmentAddressBuilder {
+        private byte idMaskLength;
+        private LispAfiAddress address;
+        private int instanceId;
+
+        /**
+         * Sets identifier mask length.
+         *
+         * @param idMaskLength identifier mask length
+         * @return SegmentAddressBuilder object
+         */
+        public SegmentAddressBuilder withIdMaskLength(byte idMaskLength) {
+            this.idMaskLength = idMaskLength;
+            return this;
+        }
+
+        /**
+         * Sets instance identifer.
+         *
+         * @param instanceId instance identifier
+         * @return SegmentAddressBuilder object
+         */
+        public SegmentAddressBuilder withInstanceId(int instanceId) {
+            this.instanceId = instanceId;
+            return this;
+        }
+
+        /**
+         * Sets AFI address.
+         *
+         * @param address AFI address
+         * @return SegmentAddressBuilder object
+         */
+        public SegmentAddressBuilder withAddress(LispAfiAddress address) {
+            this.address = address;
+            return this;
+        }
+
+        /**
+         * Builds LispSegmentLcafAddress instance.
+         *
+         * @return LispSegmentLcafAddress instance
+         */
+        public LispSegmentLcafAddress build() {
+            return new LispSegmentLcafAddress(idMaskLength, instanceId, address);
+        }
+    }
+
+    /**
+     * Segment LCAF address reader class.
+     */
+    public static class SegmentLcafAddressReader
+                        implements LispAddressReader<LispSegmentLcafAddress> {
+
+        @Override
+        public LispSegmentLcafAddress readFrom(ByteBuf byteBuf)
+                                        throws LispParseError, LispReaderException {
+
+            // TODO: need to de-serialize IdMaskLength
+            byte idMaskLength = 0x01;
+            int instanceId = (int) byteBuf.readUnsignedInt();
+            LispAfiAddress address = new LispIpAddress.IpAddressReader().readFrom(byteBuf);
+
+            return new SegmentAddressBuilder()
+                            .withIdMaskLength(idMaskLength)
+                            .withInstanceId(instanceId)
+                            .withAddress(address)
+                            .build();
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddress.java
index 6c026e7..24d159a 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddress.java
@@ -15,6 +15,10 @@
  */
 package org.onosproject.lisp.msg.types;
 
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -42,37 +46,27 @@
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * }</pre>
  */
-public class LispSourceDestLcafAddress extends LispLcafAddress {
+public final class LispSourceDestLcafAddress extends LispLcafAddress {
 
-    private LispAfiAddress srcPrefix;
-    private LispAfiAddress dstPrefix;
+    private final LispAfiAddress srcPrefix;
+    private final LispAfiAddress dstPrefix;
     private final byte srcMaskLength;
     private final byte dstMaskLength;
     private final short reserved;
 
     /**
      * Initializes source/dest key type LCAF address.
-     */
-    public LispSourceDestLcafAddress() {
-        super(LispCanonicalAddressFormatEnum.SOURCE_DEST);
-        srcMaskLength = 0;
-        dstMaskLength = 0;
-        reserved = 0;
-    }
-
-    /**
-     * Initializes source/dest key type LCAF address.
      *
-     * @param reserved reserved
+     * @param reserved      reserved
      * @param srcMaskLength source mask length
      * @param dstMaskLength destination mask length
-     * @param srcPrefix source address prefix
-     * @param dstPrefix destination address prefix
+     * @param srcPrefix     source address prefix
+     * @param dstPrefix     destination address prefix
      */
-    public LispSourceDestLcafAddress(short reserved, byte srcMaskLength,
-                                     byte dstMaskLength,
-                                     LispAfiAddress srcPrefix,
-                                     LispAfiAddress dstPrefix) {
+    private LispSourceDestLcafAddress(short reserved, byte srcMaskLength,
+                                      byte dstMaskLength,
+                                      LispAfiAddress srcPrefix,
+                                      LispAfiAddress dstPrefix) {
         super(LispCanonicalAddressFormatEnum.SOURCE_DEST);
         this.reserved = reserved;
         this.srcMaskLength = srcMaskLength;
@@ -140,10 +134,10 @@
         if (obj instanceof LispSourceDestLcafAddress) {
             final LispSourceDestLcafAddress other = (LispSourceDestLcafAddress) obj;
             return Objects.equals(this.srcPrefix, other.srcPrefix) &&
-                   Objects.equals(this.dstPrefix, other.dstPrefix) &&
-                   Objects.equals(this.srcMaskLength, other.srcMaskLength) &&
-                   Objects.equals(this.dstMaskLength, other.dstMaskLength) &&
-                   Objects.equals(this.reserved, other.reserved);
+                    Objects.equals(this.dstPrefix, other.dstPrefix) &&
+                    Objects.equals(this.srcMaskLength, other.srcMaskLength) &&
+                    Objects.equals(this.dstMaskLength, other.dstMaskLength) &&
+                    Objects.equals(this.reserved, other.reserved);
         }
         return false;
     }
@@ -158,4 +152,103 @@
                 .add("reserved", reserved)
                 .toString();
     }
+
+    public static final class SourceDestAddressBuilder {
+        private LispAfiAddress srcPrefix;
+        private LispAfiAddress dstPrefix;
+        private byte srcMaskLength;
+        private byte dstMaskLength;
+        private short reserved;
+
+        /**
+         * Sets source address prefix.
+         *
+         * @param srcPrefix source prefix
+         * @return SourceDestAddressBuilder object
+         */
+        public SourceDestAddressBuilder withSrcPrefix(LispAfiAddress srcPrefix) {
+            this.srcPrefix = srcPrefix;
+            return this;
+        }
+
+        /**
+         * Sets destination address prefix.
+         *
+         * @param dstPrefix
+         * @return SourceDestAddressBuilder object
+         */
+        public SourceDestAddressBuilder withDstPrefix(LispAfiAddress dstPrefix) {
+            this.dstPrefix = dstPrefix;
+            return this;
+        }
+
+        /**
+         * Sets source mask length.
+         *
+         * @param srcMaskLength source mask length
+         * @return SourceDestAddressBuilder object
+         */
+        public SourceDestAddressBuilder withSrcMaskLength(byte srcMaskLength) {
+            this.srcMaskLength = srcMaskLength;
+            return this;
+        }
+
+        /**
+         * Sets destination mask length.
+         *
+         * @param dstMaskLength destination mask length
+         * @return SourceDestAddressBuilder object
+         */
+        public SourceDestAddressBuilder withDstMaskLength(byte dstMaskLength) {
+            this.dstMaskLength = dstMaskLength;
+            return this;
+        }
+
+        /**
+         * Sets reserved value.
+         *
+         * @param reserved reserved field value
+         * @return SourceDestAddressBuilder object
+         */
+        public SourceDestAddressBuilder withReserved(short reserved) {
+            this.reserved = reserved;
+            return this;
+        }
+
+        /**
+         * Builds LispSourceDestLcafAddress instance.
+         *
+         * @return LispSourceDestLcafAddress instance
+         */
+        public LispSourceDestLcafAddress build() {
+            return new LispSourceDestLcafAddress(reserved, srcMaskLength,
+                    dstMaskLength, srcPrefix, dstPrefix);
+        }
+    }
+
+    /**
+     * SourceDest LCAF address reader class.
+     */
+    public static class SourceDestLcafAddressReader
+            implements LispAddressReader<LispSourceDestLcafAddress> {
+
+        @Override
+        public LispSourceDestLcafAddress readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
+
+            short reserved = byteBuf.readShort();
+            byte srcMaskLength = (byte) byteBuf.readUnsignedByte();
+            byte dstMaskLength = (byte) byteBuf.readUnsignedByte();
+
+            LispAfiAddress srcPrefix = new LispIpAddress.IpAddressReader().readFrom(byteBuf);
+            LispAfiAddress dstPrefix = new LispIpAddress.IpAddressReader().readFrom(byteBuf);
+
+            return new SourceDestAddressBuilder()
+                            .withReserved(reserved)
+                            .withSrcMaskLength(srcMaskLength)
+                            .withDstMaskLength(dstMaskLength)
+                            .withSrcPrefix(srcPrefix)
+                            .withDstPrefix(dstPrefix)
+                            .build();
+        }
+    }
 }
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddressTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddressTest.java
index b8b600c..ea528a0 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddressTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddressTest.java
@@ -35,13 +35,48 @@
     @Before
     public void setup() {
 
-        LispAfiAddress ipv4Address1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
-        address1 = new LispAppDataLcafAddress((byte) 0x01, 1, (short) 10, (short) 20, ipv4Address1);
+        LispAppDataLcafAddress.AppDataAddressBuilder builder1 =
+                new LispAppDataLcafAddress.AppDataAddressBuilder();
 
-        sameAsAddress1 = new LispAppDataLcafAddress((byte) 0x01, 1, (short) 10, (short) 20, ipv4Address1);
+        LispAfiAddress ipv4Address1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
+
+        address1 = builder1
+                    .withProtocol((byte) 0x01)
+                    .withIpTos((short) 10)
+                    .withLocalPortLow((short) 1)
+                    .withLocalPortHigh((short) 255)
+                    .withRemotePortLow((short) 2)
+                    .withRemotePortHigh((short) 254)
+                    .withAddress(ipv4Address1)
+                    .build();
+
+        LispAppDataLcafAddress.AppDataAddressBuilder builder2 =
+                new LispAppDataLcafAddress.AppDataAddressBuilder();
+
+        sameAsAddress1 = builder2
+                            .withProtocol((byte) 0x01)
+                            .withIpTos((short) 10)
+                            .withLocalPortLow((short) 1)
+                            .withLocalPortHigh((short) 255)
+                            .withRemotePortLow((short) 2)
+                            .withRemotePortHigh((short) 254)
+                            .withAddress(ipv4Address1)
+                            .build();
+
+        LispAppDataLcafAddress.AppDataAddressBuilder builder3 =
+                new LispAppDataLcafAddress.AppDataAddressBuilder();
 
         LispAfiAddress ipv4Address2 = new LispIpv4Address(IpAddress.valueOf("192.168.2.1"));
-        address2 = new LispAppDataLcafAddress((byte) 0x02, 2, (short) 20, (short) 40, ipv4Address2);
+
+        address2 = builder3
+                        .withProtocol((byte) 0x02)
+                        .withIpTos((short) 20)
+                        .withLocalPortLow((short) 1)
+                        .withLocalPortHigh((short) 255)
+                        .withRemotePortLow((short) 2)
+                        .withRemotePortHigh((short) 254)
+                        .withAddress(ipv4Address2)
+                        .build();
     }
 
     @Test
@@ -58,9 +93,11 @@
         LispAfiAddress ipv4Address = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
 
         assertThat(appDataLcafAddress.getProtocol(), is((byte) 0x01));
-        assertThat(appDataLcafAddress.getIpTos(), is(1));
-        assertThat(appDataLcafAddress.getLocalPort(), is((short) 10));
-        assertThat(appDataLcafAddress.getRemotePort(), is((short) 20));
+        assertThat(appDataLcafAddress.getIpTos(), is(10));
+        assertThat(appDataLcafAddress.getLocalPortLow(), is((short) 1));
+        assertThat(appDataLcafAddress.getLocalPortHigh(), is((short) 255));
+        assertThat(appDataLcafAddress.getRemotePortLow(), is((short) 2));
+        assertThat(appDataLcafAddress.getRemotePortHigh(), is((short) 254));
         assertThat(appDataLcafAddress.getAddress(), is(ipv4Address));
     }
 }
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddressTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddressTest.java
index 8931de8..b1f811c 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddressTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddressTest.java
@@ -35,13 +35,35 @@
     @Before
     public void setup() {
 
-        LispIpv4Address ipv4Address1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
-        address1 = new LispSegmentLcafAddress((byte) 0x01, 1, ipv4Address1);
+        LispSegmentLcafAddress.SegmentAddressBuilder builder1 =
+                            new LispSegmentLcafAddress.SegmentAddressBuilder();
 
-        sameAsAddress1 = new LispSegmentLcafAddress((byte) 0x01, 1, ipv4Address1);
+        LispIpv4Address ipv4Address1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
+
+        address1 = builder1
+                        .withIdMaskLength((byte) 0x01)
+                        .withInstanceId(1)
+                        .withAddress(ipv4Address1)
+                        .build();
+
+        LispSegmentLcafAddress.SegmentAddressBuilder builder2 =
+                            new LispSegmentLcafAddress.SegmentAddressBuilder();
+
+        sameAsAddress1 = builder2
+                            .withIdMaskLength((byte) 0x01)
+                            .withInstanceId(1)
+                            .withAddress(ipv4Address1)
+                            .build();
+
+        LispSegmentLcafAddress.SegmentAddressBuilder builder3 =
+                            new LispSegmentLcafAddress.SegmentAddressBuilder();
 
         LispIpv4Address ipv4Address2 = new LispIpv4Address(IpAddress.valueOf("192.168.2.1"));
-        address2 = new LispSegmentLcafAddress((byte) 0x02, 2, ipv4Address2);
+        address2 = builder3
+                        .withIdMaskLength((byte) 0x02)
+                        .withInstanceId(2)
+                        .withAddress(ipv4Address2)
+                        .build();
     }
 
     @Test
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddressTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddressTest.java
index 8296b43..e212a1c 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddressTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddressTest.java
@@ -35,20 +35,44 @@
     @Before
     public void setup() {
 
+        LispSourceDestLcafAddress.SourceDestAddressBuilder builder1 =
+                new LispSourceDestLcafAddress.SourceDestAddressBuilder();
+
         LispIpv4Address srcAddress1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1"));
         LispIpv4Address dstAddress1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.2"));
 
-        address1 = new LispSourceDestLcafAddress((short) 1, (byte) 0x01,
-                                        (byte) 0x01, srcAddress1, dstAddress1);
+        address1 = builder1
+                        .withReserved((short) 1)
+                        .withSrcMaskLength((byte) 0x01)
+                        .withDstMaskLength((byte) 0x01)
+                        .withSrcPrefix(srcAddress1)
+                        .withDstPrefix(dstAddress1)
+                        .build();
 
-        sameAsAddress1 = new LispSourceDestLcafAddress((short) 1, (byte) 0x01,
-                                        (byte) 0x01, srcAddress1, dstAddress1);
+        LispSourceDestLcafAddress.SourceDestAddressBuilder builder2 =
+                new LispSourceDestLcafAddress.SourceDestAddressBuilder();
+
+        sameAsAddress1 = builder2
+                            .withReserved((short) 1)
+                            .withSrcMaskLength((byte) 0x01)
+                            .withDstMaskLength((byte) 0x01)
+                            .withSrcPrefix(srcAddress1)
+                            .withDstPrefix(dstAddress1)
+                            .build();
+
+        LispSourceDestLcafAddress.SourceDestAddressBuilder builder3 =
+                new LispSourceDestLcafAddress.SourceDestAddressBuilder();
 
         LispIpv4Address srcAddress2 = new LispIpv4Address(IpAddress.valueOf("192.168.2.1"));
         LispIpv4Address dstAddress2 = new LispIpv4Address(IpAddress.valueOf("192.168.2.2"));
 
-        address2 = new LispSourceDestLcafAddress((short) 2, (byte) 0x02,
-                                        (byte) 0x02, srcAddress2, dstAddress2);
+        address2 = builder3
+                        .withReserved((short) 2)
+                        .withSrcMaskLength((byte) 0x02)
+                        .withDstMaskLength((byte) 0x02)
+                        .withSrcPrefix(srcAddress2)
+                        .withDstPrefix(dstAddress2)
+                        .build();
     }
 
     @Test