Refactor: move LCAF related address classes under lcaf package

Change-Id: I828fe5596c84b121b9382a69107ddfce20840f99
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispAppDataLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispAppDataLcafAddress.java
new file mode 100644
index 0000000..911e0ad
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispAppDataLcafAddress.java
@@ -0,0 +1,412 @@
+/*
+ * 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.lcaf;
+
+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.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Application data type LCAF address class.
+ * <p>
+ * Application data type is defined in draft-ietf-lisp-lcaf-22
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-27
+ *
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Type = 4    |     Rsvd2     |            Length             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |       IP TOS, IPv6 TC, or Flow Label          |    Protocol   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |    Local Port (lower-range)   |    Local Port (upper-range)   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Remote Port (lower-range)   |   Remote Port (upper-range)   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |         Address  ...          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public final class LispAppDataLcafAddress extends LispLcafAddress {
+
+    private final byte protocol;
+    private final int ipTos;
+    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
+     */
+    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.localPortLow = localPortLow;
+        this.localPortHigh = localPortHigh;
+        this.remotePortLow = remotePortLow;
+        this.remotePortHigh = remotePortHigh;
+        this.address = address;
+    }
+
+    /**
+     * Initializes application data type LCAF address.
+     *
+     * @param reserved1      reserved1
+     * @param reserved2      reserved2
+     * @param flag           flag
+     * @param length         length
+     * @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
+     */
+    private LispAppDataLcafAddress(byte reserved1, byte reserved2, byte flag, short length,
+                                   byte protocol, int ipTos, short localPortLow,
+                                   short localPortHigh, short remotePortLow,
+                                   short remotePortHigh, LispAfiAddress address) {
+        super(LispCanonicalAddressFormatEnum.APPLICATION_DATA, reserved1, reserved2, flag, length);
+        this.protocol = protocol;
+        this.ipTos = ipTos;
+        this.localPortLow = localPortLow;
+        this.localPortHigh = localPortHigh;
+        this.remotePortLow = remotePortLow;
+        this.remotePortHigh = remotePortHigh;
+        this.address = address;
+    }
+
+    /**
+     * Obtains protocol number.
+     *
+     * @return protocol number
+     */
+    public byte getProtocol() {
+        return protocol;
+    }
+
+    /**
+     * Obtains IP type of service.
+     *
+     * @return IP type of service
+     */
+    public int getIpTos() {
+        return ipTos;
+    }
+
+    /**
+     * Obtains low-ranged local port number.
+     *
+     * @return low-ranged local port number
+     */
+    public short getLocalPortLow() {
+        return localPortLow;
+    }
+
+    /**
+     * Obtains high-ranged local port number.
+     *
+     * @return high-ranged local port number
+     */
+    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;
+    }
+
+    /**
+     * Obtains address.
+     *
+     * @return address
+     */
+    public LispAfiAddress getAddress() {
+        return address;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(address, protocol, ipTos, localPortLow,
+                localPortHigh, remotePortLow, remotePortHigh);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispAppDataLcafAddress) {
+            final LispAppDataLcafAddress other = (LispAppDataLcafAddress) obj;
+            return Objects.equals(this.address, other.address) &&
+                    Objects.equals(this.protocol, other.protocol) &&
+                    Objects.equals(this.ipTos, other.ipTos) &&
+                    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;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("address", address)
+                .add("protocol", protocol)
+                .add("ip type of service", ipTos)
+                .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
+            extends LcafAddressBuilder<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
+         */
+        public AppDataAddressBuilder withProtocol(byte protocol) {
+            this.protocol = protocol;
+            return this;
+        }
+
+        /**
+         * Sets IP type of service.
+         *
+         * @param ipTos IP type of service
+         * @return AppDataAddressBuilder object
+         */
+        public 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
+         */
+        public 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
+         */
+        public 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
+         */
+        public 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
+         */
+        public AppDataAddressBuilder withRemotePortHigh(short remotePortHigh) {
+            this.remotePortHigh = remotePortHigh;
+            return this;
+        }
+
+        /**
+         * Sets AFI address.
+         *
+         * @param address AFI address
+         * @return AppDataAddressBuilder object
+         */
+        public AppDataAddressBuilder withAddress(LispAfiAddress address) {
+            this.address = address;
+            return this;
+        }
+
+        /**
+         * Builds LispAppDataLcafAddress instance.
+         *
+         * @return LispAddDataLcafAddress instance
+         */
+        public LispAppDataLcafAddress build() {
+
+            checkNotNull(address, "Must specify an address");
+
+            return new LispAppDataLcafAddress(reserved1, reserved2, flag, length,
+                    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 {
+
+            LispLcafAddress.deserializeCommon(byteBuf);
+
+            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 LispAfiAddress.AfiAddressReader().readFrom(byteBuf);
+
+            return new AppDataAddressBuilder()
+                    .withProtocol(protocol)
+                    .withIpTos(ipTos)
+                    .withLocalPortLow(localPortLow)
+                    .withLocalPortHigh(localPortHigh)
+                    .withRemotePortLow(remotePortLow)
+                    .withRemotePortHigh(remotePortHigh)
+                    .withAddress(address)
+                    .build();
+        }
+
+        /**
+         * An 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();
+        }
+    }
+
+    /**
+     * Application data LCAF address writer class.
+     */
+    public static class AppDataLcafAddressWriter
+            implements LispAddressWriter<LispAppDataLcafAddress> {
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispAppDataLcafAddress address)
+                throws LispWriterException {
+
+            int lcafIndex = byteBuf.writerIndex();
+            LispLcafAddress.serializeCommon(byteBuf, address);
+
+            byte[] tos = getPartialByteArray(address.getIpTos());
+            byteBuf.writeBytes(tos);
+            byteBuf.writeByte(address.getProtocol());
+            byteBuf.writeShort(address.getLocalPortLow());
+            byteBuf.writeShort(address.getLocalPortHigh());
+            byteBuf.writeShort(address.getRemotePortLow());
+            byteBuf.writeShort(address.getRemotePortHigh());
+
+            LispAfiAddress.AfiAddressWriter writer = new LispAfiAddress.AfiAddressWriter();
+            writer.writeTo(byteBuf, address.getAddress());
+
+            LispLcafAddress.updateLength(lcafIndex, byteBuf);
+        }
+
+        /**
+         * An utility function that obtains byte array from partial int value.
+         *
+         * @param value integer value
+         * @return an array of bytes
+         */
+        public static byte[] getPartialByteArray(int value) {
+            ByteBuffer buffer = ByteBuffer.allocate(4);
+            byte[] array = buffer.putInt(value).array();
+            return Arrays.copyOfRange(array, 1, 4);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispAsLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispAsLcafAddress.java
new file mode 100644
index 0000000..22ddb57
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispAsLcafAddress.java
@@ -0,0 +1,196 @@
+/*
+ * 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.lcaf;
+
+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.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * AS Numbers type LCAF address class.
+ * <p>
+ * AS Number type is defined in draft-ietf-lisp-lcaf-22
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-9
+ *
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Type = 3    |     Rsvd2     |             Length            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                           AS Number                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |         Address  ...          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public final class LispAsLcafAddress extends LispLcafAddress {
+
+    private final LispAfiAddress address;
+    private final int asNumber;
+
+    /**
+     * Initializes AS numbers type LCAF address.
+     *
+     * @param asNumber AS number
+     * @param address  AFI address
+     */
+    private LispAsLcafAddress(int asNumber, LispAfiAddress address) {
+        super(LispCanonicalAddressFormatEnum.AS);
+        this.asNumber = asNumber;
+        this.address = address;
+    }
+
+    /**
+     * Obtains address.
+     *
+     * @return address
+     */
+    public LispAfiAddress getAddress() {
+        return address;
+    }
+
+    /**
+     * Obtains AS number.
+     *
+     * @return AS number
+     */
+    public int getAsNumber() {
+        return asNumber;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(asNumber, address);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispAsLcafAddress) {
+            final LispAsLcafAddress other = (LispAsLcafAddress) obj;
+            return Objects.equals(this.asNumber, other.asNumber) &&
+                    Objects.equals(this.address, other.address);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("asNumber", asNumber)
+                .add("address", address)
+                .toString();
+    }
+
+    public static final class AsAddressBuilder
+                                extends LcafAddressBuilder<AsAddressBuilder> {
+        private int asNumber;
+        private LispAfiAddress address;
+
+        /**
+         * Sets AS number.
+         *
+         * @param asNumber AS number
+         * @return AsAddressBuilder object
+         */
+        public AsAddressBuilder withAsNumber(int asNumber) {
+            this.asNumber = asNumber;
+            return this;
+        }
+
+        /**
+         * Sets AFI address.
+         *
+         * @param address AFI address
+         * @return AsAddressBuilder object
+         */
+        public AsAddressBuilder withAddress(LispAfiAddress address) {
+            this.address = address;
+            return this;
+        }
+
+        /**
+         * Builds LispAsLcafAddress instance.
+         *
+         * @return LispAsLcafAddress instance
+         */
+        public LispAsLcafAddress build() {
+
+            checkNotNull(address, "Must specify an address");
+
+            return new LispAsLcafAddress(asNumber, address);
+        }
+    }
+
+    /**
+     * AS number LCAF address reader class.
+     */
+    public static class AsLcafAddressReader
+                        implements LispAddressReader<LispAsLcafAddress> {
+
+        @Override
+        public LispAsLcafAddress readFrom(ByteBuf byteBuf)
+                                    throws LispParseError, LispReaderException {
+
+            LispLcafAddress.deserializeCommon(byteBuf);
+
+            int asNumber = (int) byteBuf.readUnsignedInt();
+            LispAfiAddress address = new LispAfiAddress.AfiAddressReader().readFrom(byteBuf);
+
+            return new AsAddressBuilder()
+                            .withAsNumber(asNumber)
+                            .withAddress(address)
+                            .build();
+        }
+    }
+
+    /**
+     * AS number LCAF address writer class.
+     */
+    public static class AsLcafAddressWriter
+                        implements LispAddressWriter<LispAsLcafAddress> {
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispAsLcafAddress address)
+                                                    throws LispWriterException {
+
+            int lcafIndex = byteBuf.writerIndex();
+            LispLcafAddress.serializeCommon(byteBuf, address);
+
+            byteBuf.writeInt(address.getAsNumber());
+
+            new LispAfiAddress.AfiAddressWriter().writeTo(byteBuf, address.getAddress());
+
+            LispLcafAddress.updateLength(lcafIndex, byteBuf);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispCanonicalAddressFormatEnum.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispCanonicalAddressFormatEnum.java
new file mode 100644
index 0000000..011a0dc
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispCanonicalAddressFormatEnum.java
@@ -0,0 +1,74 @@
+/*
+ * 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.lcaf;
+
+/**
+ * LISP Canonical Address Format (LCAF) Enumeration class.
+ *
+ * LCAF defines a canonical address format encoding used in LISP control message
+ * and in the encoding of lookup keys for the LISP Mapping Database System.
+ *
+ * LCAF is defined in draft-ietf-lisp-lcaf-20
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-20
+ */
+public enum LispCanonicalAddressFormatEnum {
+    LIST(1),                    // AFI LIST Type
+    SEGMENT(2),                 // Instance ID Type
+    AS(3),                      // AS Number Type
+    APPLICATION_DATA(4),        // Application Data Type
+    NAT(7),                     // NAT Traversal Type
+    MULTICAST(9),               // Multi-cast Info Type
+    SECURITY(11),               // Security Key Type
+    SOURCE_DEST(12),            // Source/Dest Key Type
+    TRAFFIC_ENGINEERING(10),    // Explicit Locator Path Type
+    UNSPECIFIED(0),             // Unspecified Type
+    UNKNOWN(-1);                // Unknown Type
+
+    private byte lispCode;
+
+    /**
+     * Private constructor which avoid instantiating object externally.
+     *
+     * @param lispCode lisp code value
+     */
+    LispCanonicalAddressFormatEnum(int lispCode) {
+        this.lispCode = (byte) lispCode;
+    }
+
+    /**
+     * Obtains lisp code value.
+     *
+     * @return lisp code value
+     */
+    public byte getLispCode() {
+        return lispCode;
+    }
+
+    /**
+     * Obtains the LCAF enum using given lisp code.
+     *
+     * @param lispCode lisp code
+     * @return LCAP enum
+     */
+    public static LispCanonicalAddressFormatEnum valueOf(int lispCode) {
+        for (LispCanonicalAddressFormatEnum val : values()) {
+            if (val.getLispCode() == lispCode) {
+                return val;
+            }
+        }
+        return UNKNOWN;
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispLcafAddress.java
new file mode 100644
index 0000000..a6b5d46
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispLcafAddress.java
@@ -0,0 +1,468 @@
+/*
+ * 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.lcaf;
+
+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.AddressFamilyIdentifierEnum;
+import org.onosproject.lisp.msg.types.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.APPLICATION_DATA;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.LIST;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.NAT;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.SEGMENT;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.SOURCE_DEST;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.TRAFFIC_ENGINEERING;
+
+
+/**
+ * LISP Canonical Address Formatted address class.
+ * <p>
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |    Type       |     Rsvd2     |            Length             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public class LispLcafAddress extends LispAfiAddress {
+
+    private static final Logger log = LoggerFactory.getLogger(LispLcafAddress.class);
+
+    private final LispCanonicalAddressFormatEnum lcafType;
+    private final byte reserved1;
+    private final byte reserved2;
+    private final byte flag;
+    private final short length;
+
+    private static final int LCAF_AFI_CODE_BYTE_LENGTH = 2;
+
+    private static final int LENGTH_FIELD_INDEX = 7;
+    public static final int COMMON_HEADER_SIZE = 8;
+
+    /**
+     * Initializes LCAF address.
+     *
+     * @param lcafType  LCAF type
+     * @param reserved1 reserved1 field
+     * @param reserved2 reserved2 field
+     * @param flag      flag field
+     * @param length    length field
+     */
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType,
+                              byte reserved1, byte reserved2, byte flag, short length) {
+        super(AddressFamilyIdentifierEnum.LCAF);
+        this.lcafType = lcafType;
+        this.reserved1 = reserved1;
+        this.reserved2 = reserved2;
+        this.flag = flag;
+        this.length = length;
+    }
+
+    /**
+     * Initializes LCAF address.
+     *
+     * @param lcafType  LCAF type
+     * @param reserved2 reserved2 field
+     * @param flag      flag field
+     * @param length    length field
+     */
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType,
+                              byte reserved2, byte flag, short length) {
+        super(AddressFamilyIdentifierEnum.LCAF);
+        this.lcafType = lcafType;
+        this.reserved2 = reserved2;
+        this.flag = flag;
+        this.length = length;
+        this.reserved1 = 0;
+    }
+
+    /**
+     * Initializes LCAF address.
+     *
+     * @param lcafType  LCAF type
+     * @param reserved2 reserved2 field
+     * @param length    length field
+     */
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType,
+                              byte reserved2, short length) {
+        super(AddressFamilyIdentifierEnum.LCAF);
+        this.lcafType = lcafType;
+        this.reserved2 = reserved2;
+        this.length = length;
+        this.reserved1 = 0;
+        this.flag = 0;
+    }
+
+    /**
+     * Initializes LCAF address.
+     *
+     * @param lcafType  LCAF type
+     * @param reserved2 reserved2 field
+     */
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType, byte reserved2) {
+        super(AddressFamilyIdentifierEnum.LCAF);
+        this.lcafType = lcafType;
+        this.reserved2 = reserved2;
+        this.reserved1 = 0;
+        this.flag = 0;
+        this.length = 0;
+    }
+
+    /**
+     * Initializes LCAF address.
+     *
+     * @param lcafType LCAF type
+     * @param length   length field
+     */
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType, short length) {
+        super(AddressFamilyIdentifierEnum.LCAF);
+        this.lcafType = lcafType;
+        this.reserved1 = 0;
+        this.reserved2 = 0;
+        this.flag = 0;
+        this.length = length;
+    }
+
+    /**
+     * Initializes LCAF address.
+     *
+     * @param lcafType LCAF type
+     */
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType) {
+        super(AddressFamilyIdentifierEnum.LCAF);
+        this.lcafType = lcafType;
+        this.reserved1 = 0;
+        this.reserved2 = 0;
+        this.flag = 0;
+        this.length = 0;
+    }
+
+    /**
+     * Obtains LCAF type.
+     *
+     * @return LCAF type
+     */
+    public LispCanonicalAddressFormatEnum getType() {
+        return lcafType;
+    }
+
+    /**
+     * Obtains LCAF reserved1 value.
+     *
+     * @return LCAF reserved1 value
+     */
+    public byte getReserved1() {
+        return reserved1;
+    }
+
+    /**
+     * Obtains LCAF reserved2 value.
+     *
+     * @return LCAF reserved2 value
+     */
+    public byte getReserved2() {
+        return reserved2;
+    }
+
+    /**
+     * Obtains LCAF flag value.
+     *
+     * @return LCAF flag value
+     */
+    public byte getFlag() {
+        return flag;
+    }
+
+    /**
+     * Obtains LCAF length value.
+     *
+     * @return LCAF length value
+     */
+    public short getLength() {
+        return length;
+    }
+
+    /**
+     * Deserializes common fields from byte buffer.
+     *
+     * @param byteBuf byte buffer
+     * @return LispLcafAddress with filled common data fields
+     */
+    public static LispLcafAddress deserializeCommon(ByteBuf byteBuf) {
+
+        // let's skip first and second two bytes
,
+        // because it represents LCAF AFI code
+        byteBuf.skipBytes(LCAF_AFI_CODE_BYTE_LENGTH);
+
+        // reserved1 -> 8 bits
+        byte reserved1 = (byte) byteBuf.readUnsignedByte();
+
+        // flags -> 8 bits
+        byte flag = (byte) byteBuf.readUnsignedByte();
+
+        // LCAF type -> 8 bits
+        byte lcafType = (byte) byteBuf.readUnsignedByte();
+
+        // reserved2 -> 8bits
+        byte reserved2 = (byte) byteBuf.readUnsignedByte();
+
+        // length -> 16 bits
+        short length = (short) byteBuf.readUnsignedShort();
+
+        return new LispLcafAddress(LispCanonicalAddressFormatEnum.valueOf(lcafType),
+                reserved1, reserved2, flag, length);
+    }
+
+    /**
+     * Updates the header length field value based on the size of LISP header.
+     *
+     * @param lcafIndex the index of LCAF address, because LCAF address is
+     *                  contained inside LISP control message, so to correctly
+     *                  find the right LCAF length index, we need to know the
+     *                  absolute lcaf index inside LISP control message byte buf
+     * @param byteBuf   netty byte buffer
+     */
+    public static void updateLength(int lcafIndex, ByteBuf byteBuf) {
+        byteBuf.setByte(lcafIndex + LENGTH_FIELD_INDEX,
+                        byteBuf.writerIndex() - COMMON_HEADER_SIZE - lcafIndex);
+    }
+
+    /**
+     * Serializes common fields to byte buffer.
+     *
+     * @param byteBuf byte buffer
+     * @param address LISP LCAF address instance
+     */
+    public static void serializeCommon(ByteBuf byteBuf, LispLcafAddress address) {
+
+        byteBuf.writeShort(AddressFamilyIdentifierEnum.LCAF.getIanaCode());
+        byteBuf.writeByte(address.getReserved1());
+        byteBuf.writeByte(address.getFlag());
+        byteBuf.writeByte(address.getType().getLispCode());
+        byteBuf.writeByte(address.getReserved2());
+        byteBuf.writeShort(address.getLength());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(lcafType, reserved1, reserved2, flag, length);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispLcafAddress) {
+            final LispLcafAddress other = (LispLcafAddress) obj;
+            return Objects.equals(this.lcafType, other.lcafType) &&
+                    Objects.equals(this.reserved1, other.reserved1) &&
+                    Objects.equals(this.reserved2, other.reserved2) &&
+                    Objects.equals(this.flag, other.flag) &&
+                    Objects.equals(this.length, other.length);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("lcafType", lcafType)
+                .add("reserved1", reserved1)
+                .add("reserved2", reserved2)
+                .add("flag", flag)
+                .add("length", length)
+                .toString();
+    }
+
+    protected static class LcafAddressBuilder<T> {
+
+        protected byte reserved1;
+        protected byte flag;
+        protected byte lcafType;
+        protected byte reserved2;
+        protected short length;
+
+        /**
+         * Sets reserved1 value.
+         *
+         * @param reserved1 reserved1 value
+         * @return LcafAddressBuilder object
+         */
+        public T withReserved1(byte reserved1) {
+            this.reserved1 = reserved1;
+            return (T) this;
+        }
+
+        /**
+         * Sets flag.
+         *
+         * @param flag flag boolean
+         * @return LcafAddressBuilder object
+         */
+        public T withFlag(byte flag) {
+            this.flag = flag;
+            return (T) this;
+        }
+
+        /**
+         * Sets LCAF type.
+         *
+         * @param lcafType LCAF type
+         * @return LcafAddressBuilder object
+         */
+        public T withLcafType(byte lcafType) {
+            this.lcafType = lcafType;
+            return (T) this;
+        }
+
+        /**
+         * Sets reserved2 value.
+         *
+         * @param reserved2 reserved2 value
+         * @return LcafAddressBuilder object
+         */
+        public T withReserved2(byte reserved2) {
+            this.reserved2 = reserved2;
+            return (T) this;
+        }
+
+        /**
+         * Sets length value.
+         *
+         * @param length length value
+         * @return LcafAddressBuilder object
+         */
+        public T withLength(short length) {
+            this.length = length;
+            return (T) this;
+        }
+
+        /**
+         * Builds LispLcafAddress object.
+         *
+         * @return LispLcafAddress instance
+         */
+        public LispLcafAddress build() {
+            return new LispLcafAddress(LispCanonicalAddressFormatEnum
+                                               .valueOf(lcafType),
+                                       reserved1, reserved2, flag, length);
+        }
+    }
+
+    /**
+     * LISP LCAF reader class.
+     */
+    public static class LcafAddressReader
+            implements LispAddressReader<LispLcafAddress> {
+
+        private static final int LCAF_TYPE_FIELD_INDEX = 4;
+
+        @Override
+        public LispLcafAddress readFrom(ByteBuf byteBuf)
+                throws LispParseError, LispReaderException {
+
+            int index = byteBuf.readerIndex();
+
+            // LCAF type -> 8 bits
+            byte lcafType = (byte) byteBuf.getUnsignedByte(index + LCAF_TYPE_FIELD_INDEX);
+
+            if (lcafType == APPLICATION_DATA.getLispCode()) {
+                return new LispAppDataLcafAddress.AppDataLcafAddressReader().readFrom(byteBuf);
+            }
+
+            if (lcafType == NAT.getLispCode()) {
+                return new LispNatLcafAddress.NatLcafAddressReader().readFrom(byteBuf);
+            }
+
+            if (lcafType == LIST.getLispCode()) {
+                return new LispListLcafAddress.ListLcafAddressReader().readFrom(byteBuf);
+            }
+
+            if (lcafType == SEGMENT.getLispCode()) {
+                return new LispSegmentLcafAddress.SegmentLcafAddressReader().readFrom(byteBuf);
+            }
+
+            if (lcafType == SOURCE_DEST.getLispCode()) {
+                return new LispSourceDestLcafAddress.SourceDestLcafAddressReader().readFrom(byteBuf);
+            }
+
+            if (lcafType == TRAFFIC_ENGINEERING.getLispCode()) {
+                return new LispTeLcafAddress.TeLcafAddressReader().readFrom(byteBuf);
+            }
+
+            log.warn("Unsupported LCAF type, please specify a correct LCAF type");
+
+            return null;
+        }
+    }
+
+    /**
+     * LISP LCAF address writer class.
+     */
+    public static class LcafAddressWriter
+            implements LispAddressWriter<LispLcafAddress> {
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispLcafAddress address)
+                throws LispWriterException {
+            switch (address.getType()) {
+                case APPLICATION_DATA:
+                    new LispAppDataLcafAddress.AppDataLcafAddressWriter().writeTo(byteBuf,
+                            (LispAppDataLcafAddress) address);
+                    break;
+                case NAT:
+                    new LispNatLcafAddress.NatLcafAddressWriter().writeTo(byteBuf,
+                            (LispNatLcafAddress) address);
+                    break;
+                case LIST:
+                    new LispListLcafAddress.ListLcafAddressWriter().writeTo(byteBuf,
+                            (LispListLcafAddress) address);
+                    break;
+                case SEGMENT:
+                    new LispSegmentLcafAddress.SegmentLcafAddressWriter().writeTo(byteBuf,
+                            (LispSegmentLcafAddress) address);
+                    break;
+                case SOURCE_DEST:
+                    new LispSourceDestLcafAddress.SourceDestLcafAddressWriter().writeTo(byteBuf,
+                            (LispSourceDestLcafAddress) address);
+                    break;
+                case TRAFFIC_ENGINEERING:
+                    new LispTeLcafAddress.TeLcafAddressWriter().writeTo(byteBuf,
+                            (LispTeLcafAddress) address);
+                    break;
+                default:
+                    log.warn("Unsupported LCAF type, please specify a correct LCAF type");
+                    break;
+            }
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispListLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispListLcafAddress.java
new file mode 100644
index 0000000..1b5983e
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispListLcafAddress.java
@@ -0,0 +1,223 @@
+/*
+ * 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.lcaf;
+
+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 org.onosproject.lisp.msg.exceptions.LispWriterException;
+import org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum;
+import org.onosproject.lisp.msg.types.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.onosproject.lisp.msg.types.LispIpv4Address;
+import org.onosproject.lisp.msg.types.LispIpv4Address.Ipv4AddressWriter;
+import org.onosproject.lisp.msg.types.LispIpv6Address;
+import org.onosproject.lisp.msg.types.LispIpv6Address.Ipv6AddressWriter;
+
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * List type LCAF address class.
+ * <p>
+ * List type is defined in draft-ietf-lisp-lcaf-22
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-22
+ *
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Type = 1    |     Rsvd2     |            Length             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            AFI = 1            |       IPv4 Address ...        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |     ...  IPv4 Address         |            AFI = 2            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          IPv6 Address ...                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     ...  IPv6 Address  ...                    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     ...  IPv6 Address  ...                    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     ...  IPv6 Address                         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public final class LispListLcafAddress extends LispLcafAddress {
+
+    private static final short LENGTH = 24;
+    List<LispAfiAddress> addresses;
+
+    /**
+     * Initializes list type LCAF address.
+     *
+     * @param addresses a set of IPv4 and IPv6 addresses
+     */
+    public LispListLcafAddress(List<LispAfiAddress> addresses) {
+        super(LispCanonicalAddressFormatEnum.LIST, LENGTH);
+
+        checkArgument(checkAddressValidity(addresses), "Malformed addresses, please " +
+                "specify IPv4 address first, and then specify IPv6 address");
+
+        this.addresses = addresses;
+    }
+
+    /**
+     * Initializes list type LCAF address.
+     *
+     * @param reserved1 reserved1 field
+     * @param flag      flag
+     * @param reserved2 reserved2 field
+     * @param addresses a set of IPv4 and IPv6 addresses
+     */
+    public LispListLcafAddress(byte reserved1, byte reserved2, byte flag,
+                               List<LispAfiAddress> addresses) {
+        super(LispCanonicalAddressFormatEnum.LIST, reserved1, flag, reserved2, LENGTH);
+
+        checkArgument(checkAddressValidity(addresses), "Malformed addresses, please " +
+                "specify IPv4 address first, and then specify IPv6 address");
+
+        this.addresses = addresses;
+    }
+
+    /**
+     * Checks the validity of a collection of input addresses.
+     *
+     * @param addresses a collection of addresses
+     * @return validity result
+     */
+    private boolean checkAddressValidity(List<LispAfiAddress> addresses) {
+        // we need to make sure that the address collection is comprised of
+        // one IPv4 address and one IPv6 address
+
+        if (addresses == null || addresses.size() != 2) {
+            return false;
+        }
+
+        LispAfiAddress ipv4 = addresses.get(0);
+        LispAfiAddress ipv6 = addresses.get(1);
+
+        if (ipv4.getAfi() != AddressFamilyIdentifierEnum.IP4) {
+            return false;
+        }
+
+        if (ipv6.getAfi() != AddressFamilyIdentifierEnum.IP6) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Obtains a set of AFI addresses including IPv4 and IPv6.
+     *
+     * @return a set of AFI addresses
+     */
+    public List<LispAfiAddress> getAddresses() {
+        return ImmutableList.copyOf(addresses);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(addresses);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispListLcafAddress) {
+            final LispListLcafAddress other = (LispListLcafAddress) obj;
+            return Objects.equals(this.addresses, other.addresses);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .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 {
+
+            LispLcafAddress lcafAddress = LispLcafAddress.deserializeCommon(byteBuf);
+
+            LispAfiAddress.AfiAddressReader reader = new LispAfiAddress.AfiAddressReader();
+
+            LispAfiAddress ipv4 = reader.readFrom(byteBuf);
+            LispAfiAddress ipv6 = reader.readFrom(byteBuf);
+
+            return new LispListLcafAddress(lcafAddress.getReserved1(),
+                                            lcafAddress.getReserved2(),
+                                            lcafAddress.getFlag(),
+                                            ImmutableList.of(ipv4, ipv6));
+        }
+    }
+
+    /**
+     * List LCAF address writer class.
+     */
+    public static class ListLcafAddressWriter
+                        implements LispAddressWriter<LispListLcafAddress> {
+
+        private static final int IPV4_ADDRESS_INDEX = 0;
+        private static final int IPV6_ADDRESS_INDEX = 1;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispListLcafAddress address)
+                                                    throws LispWriterException {
+
+            int lcafIndex = byteBuf.writerIndex();
+            LispLcafAddress.serializeCommon(byteBuf, address);
+
+            Ipv4AddressWriter v4Writer = new Ipv4AddressWriter();
+            Ipv6AddressWriter v6Writer = new Ipv6AddressWriter();
+
+            LispAfiAddress ipv4 = address.getAddresses().get(IPV4_ADDRESS_INDEX);
+            LispAfiAddress ipv6 = address.getAddresses().get(IPV6_ADDRESS_INDEX);
+
+            // IPv4 address
+            byteBuf.writeShort(ipv4.getAfi().getIanaCode());
+            v4Writer.writeTo(byteBuf, (LispIpv4Address) ipv4);
+
+            // IPv6 address
+            byteBuf.writeShort(ipv6.getAfi().getIanaCode());
+            v6Writer.writeTo(byteBuf, (LispIpv6Address) ipv6);
+
+            LispLcafAddress.updateLength(lcafIndex, byteBuf);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispNatLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispNatLcafAddress.java
new file mode 100644
index 0000000..6da6b42
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispNatLcafAddress.java
@@ -0,0 +1,339 @@
+/*
+ * 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.lcaf;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+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.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Network Address Translation (NAT) address class.
+ * <p>
+ * Instance ID type is defined in draft-ietf-lisp-lcaf-22
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-12
+ *
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Type = 7    |     Rsvd2     |             Length            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |       MS UDP Port Number      |      ETR UDP Port Number      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |  Global ETR RLOC Address  ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |       MS RLOC Address  ...    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          | Private ETR RLOC Address  ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |      RTR RLOC Address 1 ...   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |      RTR RLOC Address k ...   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public final class LispNatLcafAddress extends LispLcafAddress {
+
+    private final short msUdpPortNumber;
+    private final short etrUdpPortNumber;
+    private final LispAfiAddress globalEtrRlocAddress;
+    private final LispAfiAddress msRlocAddress;
+    private final LispAfiAddress privateEtrRlocAddress;
+    private final List<LispAfiAddress> rtrRlocAddresses;
+
+    /**
+     * Initializes NAT type LCAF address.
+     *
+     * @param reserved2             reserved2
+     * @param length                length
+     * @param msUdpPortNumber       Map Server (MS) UDP port number
+     * @param etrUdpPortNumber      ETR UDP port number
+     * @param globalEtrRlocAddress  global ETR RLOC address
+     * @param msRlocAddress         Map Server (MS) RLOC address
+     * @param privateEtrRlocAddress private ETR RLOC address
+     * @param rtrRlocAddresses      a collection of RTR RLOC addresses
+     */
+    private LispNatLcafAddress(byte reserved2, short length, short msUdpPortNumber,
+                               short etrUdpPortNumber, LispAfiAddress globalEtrRlocAddress,
+                               LispAfiAddress msRlocAddress, LispAfiAddress privateEtrRlocAddress,
+                               List<LispAfiAddress> rtrRlocAddresses) {
+        super(LispCanonicalAddressFormatEnum.NAT, reserved2, length);
+        this.msUdpPortNumber = msUdpPortNumber;
+        this.etrUdpPortNumber = etrUdpPortNumber;
+        this.globalEtrRlocAddress = globalEtrRlocAddress;
+        this.msRlocAddress = msRlocAddress;
+        this.privateEtrRlocAddress = privateEtrRlocAddress;
+        this.rtrRlocAddresses = ImmutableList.copyOf(rtrRlocAddresses);
+    }
+
+    /**
+     * Obtains Map Server UDP port number.
+     *
+     * @return Map Server UDP port number
+     */
+    public short getMsUdpPortNumber() {
+        return msUdpPortNumber;
+    }
+
+    /**
+     * Obtains ETR UDP port number.
+     *
+     * @return ETR UDP port number
+     */
+    public short getEtrUdpPortNumber() {
+        return etrUdpPortNumber;
+    }
+
+    /**
+     * Obtains global ETR RLOC address.
+     *
+     * @return global ETR
+     */
+    public LispAfiAddress getGlobalEtrRlocAddress() {
+        return globalEtrRlocAddress;
+    }
+
+    /**
+     * Obtains Map Server RLOC address.
+     *
+     * @return Map Server RLOC address
+     */
+    public LispAfiAddress getMsRlocAddress() {
+        return msRlocAddress;
+    }
+
+    /**
+     * Obtains private ETR RLOC address.
+     *
+     * @return private ETR RLOC address
+     */
+    public LispAfiAddress getPrivateEtrRlocAddress() {
+        return privateEtrRlocAddress;
+    }
+
+    /**
+     * Obtains a collection of RTR RLOC addresses.
+     *
+     * @return a collection of RTR RLOC addresses
+     */
+    public List<LispAfiAddress> getRtrRlocAddresses() {
+        return ImmutableList.copyOf(rtrRlocAddresses);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(msUdpPortNumber, etrUdpPortNumber,
+                globalEtrRlocAddress, msRlocAddress, privateEtrRlocAddress);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispNatLcafAddress) {
+            final LispNatLcafAddress other = (LispNatLcafAddress) obj;
+            return Objects.equals(this.msUdpPortNumber, other.msUdpPortNumber) &&
+                    Objects.equals(this.etrUdpPortNumber, other.etrUdpPortNumber) &&
+                    Objects.equals(this.globalEtrRlocAddress, other.globalEtrRlocAddress) &&
+                    Objects.equals(this.msRlocAddress, other.msRlocAddress) &&
+                    Objects.equals(this.privateEtrRlocAddress, other.privateEtrRlocAddress) &&
+                    Objects.equals(this.rtrRlocAddresses, other.rtrRlocAddresses);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("Map Server UDP port number", msUdpPortNumber)
+                .add("ETR UDP port number", etrUdpPortNumber)
+                .add("global ETR RLOC address", globalEtrRlocAddress)
+                .add("Map Server RLOC address", msRlocAddress)
+                .add("private ETR RLOC address", privateEtrRlocAddress)
+                .add("RTR RLOC addresses", rtrRlocAddresses)
+                .toString();
+    }
+
+    public static final class NatAddressBuilder extends LcafAddressBuilder<NatAddressBuilder> {
+
+        private short msUdpPortNumber;
+        private short etrUdpPortNumber;
+        private LispAfiAddress globalEtrRlocAddress;
+        private LispAfiAddress msRlocAddress;
+        private LispAfiAddress privateEtrRlocAddress;
+        private List<LispAfiAddress> rtrRlocAddresses = Lists.newArrayList();
+
+        /**
+         * Sets Map Server UDP port number.
+         *
+         * @param msUdpPortNumber Map Server UDP port number
+         * @return NatAddressBuilder object
+         */
+        public NatAddressBuilder withMsUdpPortNumber(short msUdpPortNumber) {
+            this.msUdpPortNumber = msUdpPortNumber;
+            return this;
+        }
+
+        /**
+         * Sets ETR UDP port number.
+         *
+         * @param etrUdpPortNumber ETR UDP port number
+         * @return NatAddressBuilder object
+         */
+        public NatAddressBuilder withEtrUdpPortNumber(short etrUdpPortNumber) {
+            this.etrUdpPortNumber = etrUdpPortNumber;
+            return this;
+        }
+
+        /**
+         * Sets global ETR RLOC address.
+         *
+         * @param globalEtrRlocAddress global ETR RLOC address
+         * @return NatAddressBuilder object
+         */
+        public NatAddressBuilder withGlobalEtrRlocAddress(LispAfiAddress globalEtrRlocAddress) {
+            this.globalEtrRlocAddress = globalEtrRlocAddress;
+            return this;
+        }
+
+        /**
+         * Sets Map Server RLOC address.
+         *
+         * @param msRlocAddress Map Server RLOC address
+         * @return NatAddressBuilder object
+         */
+        public NatAddressBuilder withMsRlocAddress(LispAfiAddress msRlocAddress) {
+            this.msRlocAddress = msRlocAddress;
+            return this;
+        }
+
+        /**
+         * Sets private ETR RLOC address.
+         *
+         * @param privateEtrRlocAddress private ETR RLOC address
+         * @return NatAddressBuilder object
+         */
+        public NatAddressBuilder withPrivateEtrRlocAddress(LispAfiAddress privateEtrRlocAddress) {
+            this.privateEtrRlocAddress = privateEtrRlocAddress;
+            return this;
+        }
+
+        /**
+         * Sets RTR RLOC addresses.
+         *
+         * @param rtrRlocAddresses a collection of RTR RLOC addresses
+         * @return NatAddressBuilder object
+         */
+        public NatAddressBuilder withRtrRlocAddresses(List<LispAfiAddress> rtrRlocAddresses) {
+            if (rtrRlocAddresses != null) {
+                this.rtrRlocAddresses = ImmutableList.copyOf(rtrRlocAddresses);
+            }
+            return this;
+        }
+
+        public LispNatLcafAddress build() {
+
+            // TODO: need to do null check
+
+            return new LispNatLcafAddress(reserved2, length, msUdpPortNumber,
+                    etrUdpPortNumber, globalEtrRlocAddress, msRlocAddress,
+                    privateEtrRlocAddress, rtrRlocAddresses);
+        }
+    }
+
+    /**
+     * NAT LCAF address reader class.
+     */
+    public static class NatLcafAddressReader
+            implements LispAddressReader<LispNatLcafAddress> {
+
+        @Override
+        public LispNatLcafAddress readFrom(ByteBuf byteBuf)
+                throws LispParseError, LispReaderException {
+
+            LispLcafAddress lcafAddress = deserializeCommon(byteBuf);
+
+            short msUdpPortNumber = (short) byteBuf.readUnsignedShort();
+            short etrUdpPortNumber = (short) byteBuf.readUnsignedShort();
+
+            LispAfiAddress globalEtrRlocAddress = new AfiAddressReader().readFrom(byteBuf);
+            LispAfiAddress msRlocAddress = new AfiAddressReader().readFrom(byteBuf);
+            LispAfiAddress privateEtrRlocAddress = new AfiAddressReader().readFrom(byteBuf);
+
+            List<LispAfiAddress> rtrRlocAddresses = Lists.newArrayList();
+
+            while (byteBuf.readerIndex() - COMMON_HEADER_SIZE < lcafAddress.getLength()) {
+                rtrRlocAddresses.add(new AfiAddressReader().readFrom(byteBuf));
+            }
+
+            return new NatAddressBuilder()
+                            .withMsUdpPortNumber(msUdpPortNumber)
+                            .withEtrUdpPortNumber(etrUdpPortNumber)
+                            .withGlobalEtrRlocAddress(globalEtrRlocAddress)
+                            .withMsRlocAddress(msRlocAddress)
+                            .withPrivateEtrRlocAddress(privateEtrRlocAddress)
+                            .withRtrRlocAddresses(rtrRlocAddresses)
+                            .build();
+        }
+    }
+
+    /**
+     * NAT LCAF address writer class.
+     */
+    public static class NatLcafAddressWriter
+            implements LispAddressWriter<LispNatLcafAddress> {
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispNatLcafAddress address)
+                throws LispWriterException {
+
+            int lcafIndex = byteBuf.writerIndex();
+            serializeCommon(byteBuf, address);
+
+            byteBuf.writeShort(address.getMsUdpPortNumber());
+            byteBuf.writeShort(address.getEtrUdpPortNumber());
+
+            AfiAddressWriter writer = new LispAfiAddress.AfiAddressWriter();
+            writer.writeTo(byteBuf, address.getGlobalEtrRlocAddress());
+            writer.writeTo(byteBuf, address.getMsRlocAddress());
+            writer.writeTo(byteBuf, address.getPrivateEtrRlocAddress());
+
+            List<LispAfiAddress> rtrRlocAddresses = address.getRtrRlocAddresses();
+
+            for (int i = 0; i < rtrRlocAddresses.size(); i++) {
+                writer.writeTo(byteBuf, rtrRlocAddresses.get(i));
+            }
+
+            updateLength(lcafIndex, byteBuf);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispSegmentLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispSegmentLcafAddress.java
new file mode 100644
index 0000000..914664e
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispSegmentLcafAddress.java
@@ -0,0 +1,244 @@
+/*
+ * 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.lcaf;
+
+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.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Instance ID type LCAF address class.
+ * <p>
+ * Instance ID type is defined in draft-ietf-lisp-lcaf-22
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-7
+ *
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Type = 2    | IID mask-len  |            Length             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Instance ID                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |         Address  ...          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public final class LispSegmentLcafAddress extends LispLcafAddress {
+
+    private final LispAfiAddress address;
+    private final int instanceId;
+
+    /**
+     * Initializes segment type LCAF address.
+     *
+     * @param idMaskLength Id mask length
+     * @param instanceId   instance id
+     * @param address      address
+     */
+    private LispSegmentLcafAddress(byte idMaskLength, int instanceId,
+                                   LispAfiAddress address) {
+        super(LispCanonicalAddressFormatEnum.SEGMENT, idMaskLength);
+        this.address = address;
+        this.instanceId = instanceId;
+    }
+
+    /**
+     * Initializes segment type LCAF address.
+     *
+     * @param reserved1    reserved1
+     * @param idMaskLength ID mask length
+     * @param flag         flag
+     * @param length       length
+     * @param instanceId   instance id
+     * @param address      address
+     */
+    private LispSegmentLcafAddress(byte reserved1, byte idMaskLength, byte flag,
+                                   short length, int instanceId,
+                                   LispAfiAddress address) {
+        super(LispCanonicalAddressFormatEnum.SEGMENT, reserved1,
+                                                    idMaskLength, flag, length);
+        this.address = address;
+        this.instanceId = instanceId;
+    }
+
+    /**
+     * Obtains address.
+     *
+     * @return address
+     */
+    public LispAfiAddress getAddress() {
+        return address;
+    }
+
+    /**
+     * Obtains instance id.
+     *
+     * @return instance id
+     */
+    public int getInstanceId() {
+        return instanceId;
+    }
+
+    /**
+     * Obtains id mask length.
+     *
+     * @return id mask length
+     */
+    public byte getIdMaskLength() {
+        return getReserved2();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(address, instanceId, getReserved2());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispSegmentLcafAddress) {
+            final LispSegmentLcafAddress other = (LispSegmentLcafAddress) obj;
+            return Objects.equals(this.address, other.address) &&
+                    Objects.equals(this.instanceId, other.instanceId) &&
+                    Objects.equals(this.getReserved2(), other.getReserved2());
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("address", address)
+                .add("instanceId", instanceId)
+                .add("idMaskLength", getReserved2())
+                .toString();
+    }
+
+    public static final class SegmentAddressBuilder
+                              extends LcafAddressBuilder<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() {
+
+            checkNotNull(address, "Must specify an address");
+
+            return new LispSegmentLcafAddress(reserved1, idMaskLength, flag,
+                                              length, instanceId, address);
+        }
+    }
+
+    /**
+     * Segment LCAF address reader class.
+     */
+    public static class SegmentLcafAddressReader
+            implements LispAddressReader<LispSegmentLcafAddress> {
+
+        @Override
+        public LispSegmentLcafAddress readFrom(ByteBuf byteBuf)
+                throws LispParseError, LispReaderException {
+
+            LispLcafAddress lcafAddress = LispLcafAddress.deserializeCommon(byteBuf);
+
+            byte idMaskLength = lcafAddress.getReserved2();
+
+            int instanceId = (int) byteBuf.readUnsignedInt();
+            LispAfiAddress address = new AfiAddressReader().readFrom(byteBuf);
+
+            return new SegmentAddressBuilder()
+                    .withIdMaskLength(idMaskLength)
+                    .withInstanceId(instanceId)
+                    .withAddress(address)
+                    .build();
+        }
+    }
+
+    /**
+     * Segment LCAF address writer class.
+     */
+    public static class SegmentLcafAddressWriter
+            implements LispAddressWriter<LispSegmentLcafAddress> {
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispSegmentLcafAddress address)
+                throws LispWriterException {
+
+            int lcafIndex = byteBuf.writerIndex();
+            LispLcafAddress.serializeCommon(byteBuf, address);
+
+            byteBuf.writeInt(address.getInstanceId());
+
+            new LispAfiAddress.AfiAddressWriter().writeTo(byteBuf, address.getAddress());
+
+            LispLcafAddress.updateLength(lcafIndex, byteBuf);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispSourceDestLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispSourceDestLcafAddress.java
new file mode 100644
index 0000000..00accd9
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispSourceDestLcafAddress.java
@@ -0,0 +1,318 @@
+/*
+ * 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.lcaf;
+
+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.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Source/Dest key type LCAF address class.
+ * <p>
+ * Source destination key type is defined in draft-ietf-lisp-lcaf-22
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-19
+ *
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Type = 12   |     Rsvd2     |             Length            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            Reserved           |   Source-ML   |    Dest-ML    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |         Source-Prefix ...     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |     Destination-Prefix ...    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public final class LispSourceDestLcafAddress extends LispLcafAddress {
+
+    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.
+     *
+     * @param reserved      reserved
+     * @param srcMaskLength source mask length
+     * @param dstMaskLength destination mask length
+     * @param srcPrefix     source address prefix
+     * @param dstPrefix     destination address prefix
+     */
+    private LispSourceDestLcafAddress(short reserved, byte srcMaskLength,
+                                      byte dstMaskLength,
+                                      LispAfiAddress srcPrefix,
+                                      LispAfiAddress dstPrefix) {
+        super(LispCanonicalAddressFormatEnum.SOURCE_DEST);
+        this.reserved = reserved;
+        this.srcMaskLength = srcMaskLength;
+        this.dstMaskLength = dstMaskLength;
+        this.srcPrefix = srcPrefix;
+        this.dstPrefix = dstPrefix;
+    }
+
+    /**
+     * Initializes source/destination key type LCAF address.
+     *
+     * @param reserved1     reserved1
+     * @param reserved2     reserved2
+     * @param flag          flag
+     * @param length        length
+     * @param reserved      reserved
+     * @param srcMaskLength source mask length
+     * @param dstMaskLength destination mask length
+     * @param srcPrefix     source address prefix
+     * @param dstPrefix     destination address prefix
+     */
+    private LispSourceDestLcafAddress(byte reserved1, byte reserved2, byte flag,
+                                      short length, short reserved,
+                                      byte srcMaskLength, byte dstMaskLength,
+                                      LispAfiAddress srcPrefix,
+                                      LispAfiAddress dstPrefix) {
+        super(LispCanonicalAddressFormatEnum.SOURCE_DEST, reserved1,
+                                                        reserved2, flag, length);
+        this.reserved = reserved;
+        this.srcMaskLength = srcMaskLength;
+        this.dstMaskLength = dstMaskLength;
+        this.srcPrefix = srcPrefix;
+        this.dstPrefix = dstPrefix;
+    }
+
+    /**
+     * Obtains source address prefix.
+     *
+     * @return source address prefix
+     */
+    public LispAfiAddress getSrcPrefix() {
+        return srcPrefix;
+    }
+
+    /**
+     * Obtains destination address prefix.
+     *
+     * @return destination address prefix
+     */
+    public LispAfiAddress getDstPrefix() {
+        return dstPrefix;
+    }
+
+    /**
+     * Obtains source mask length.
+     *
+     * @return source mask length
+     */
+    public byte getSrcMaskLength() {
+        return srcMaskLength;
+    }
+
+    /**
+     * Obtains destination mask length.
+     *
+     * @return destination mask length
+     */
+    public byte getDstMaskLength() {
+        return dstMaskLength;
+    }
+
+    /**
+     * Obtains reserved value.
+     *
+     * @return reserved value
+     */
+    public short getReserved() {
+        return reserved;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(srcPrefix, dstPrefix, srcMaskLength, dstMaskLength, reserved);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        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);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("source prefix", srcPrefix)
+                .add("destination prefix", dstPrefix)
+                .add("source mask length", srcMaskLength)
+                .add("destination mask length", dstMaskLength)
+                .add("reserved", reserved)
+                .toString();
+    }
+
+    public static final class SourceDestAddressBuilder
+            extends LcafAddressBuilder<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 destination prefix
+         * @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() {
+
+            checkNotNull(srcPrefix, "Must specify a source address prefix");
+            checkNotNull(dstPrefix, "Must specify a destination address prefix");
+
+            return new LispSourceDestLcafAddress(reserved1, reserved2, flag, length,
+                    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 {
+
+            deserializeCommon(byteBuf);
+
+            short reserved = byteBuf.readShort();
+            byte srcMaskLength = (byte) byteBuf.readUnsignedByte();
+            byte dstMaskLength = (byte) byteBuf.readUnsignedByte();
+
+            LispAfiAddress srcPrefix = new AfiAddressReader().readFrom(byteBuf);
+            LispAfiAddress dstPrefix = new AfiAddressReader().readFrom(byteBuf);
+
+            return new SourceDestAddressBuilder()
+                    .withReserved(reserved)
+                    .withSrcMaskLength(srcMaskLength)
+                    .withDstMaskLength(dstMaskLength)
+                    .withSrcPrefix(srcPrefix)
+                    .withDstPrefix(dstPrefix)
+                    .build();
+        }
+    }
+
+    /**
+     * SourceDest LCAF address writer class.
+     */
+    public static class SourceDestLcafAddressWriter
+            implements LispAddressWriter<LispSourceDestLcafAddress> {
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispSourceDestLcafAddress address)
+                throws LispWriterException {
+
+            int lcafIndex = byteBuf.writerIndex();
+            serializeCommon(byteBuf, address);
+
+            byteBuf.writeShort(address.getReserved());
+            byteBuf.writeByte(address.getSrcMaskLength());
+            byteBuf.writeByte(address.getDstMaskLength());
+            AfiAddressWriter writer = new AfiAddressWriter();
+            writer.writeTo(byteBuf, address.getSrcPrefix());
+            writer.writeTo(byteBuf, address.getDstPrefix());
+
+            updateLength(lcafIndex, byteBuf);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispTeLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispTeLcafAddress.java
new file mode 100644
index 0000000..6b61305
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispTeLcafAddress.java
@@ -0,0 +1,174 @@
+/*
+ * 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.lcaf;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+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.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Traffic Engineering (TE) type LCAF address class.
+ * <p>
+ * Traffic Engineering type is defined in draft-ietf-lisp-lcaf-22
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-16
+ *
+ * <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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           AFI = 16387         |     Rsvd1     |     Flags     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Type = 10   |     Rsvd2     |            Length             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           Rsvd3         |L|P|S|           AFI = x             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Reencap Hop 1  ...                    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           Rsvd3         |L|P|S|           AFI = x             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Reencap Hop k  ...                    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * }</pre>
+ */
+public final class LispTeLcafAddress extends LispLcafAddress {
+
+    private final List<LispTeRecord> records;
+
+    /**
+     * Initializes Traffic Engineering type LCAF address.
+     *
+     * @param records a collection of Re-encapsulated RLOC addresses
+     */
+    private LispTeLcafAddress(List<LispTeRecord> records) {
+        super(LispCanonicalAddressFormatEnum.TRAFFIC_ENGINEERING);
+        this.records = records;
+    }
+
+    /**
+     * Obtains a collection of TE records.
+     *
+     * @return a collection of TE records
+     */
+    public List<LispTeRecord> getTeRecords() {
+        return ImmutableList.copyOf(records);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(records);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispTeLcafAddress) {
+            final LispTeLcafAddress other = (LispTeLcafAddress) obj;
+            return Objects.equals(records, other.records);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("TE records", records).toString();
+    }
+
+    public static final class TeAddressBuilder
+                                extends LcafAddressBuilder<TeAddressBuilder> {
+        private List<LispTeRecord> records;
+
+        /**
+         * Sets a collection of TE records.
+         *
+         * @param records a collection of TE records
+         * @return TeAddressBuilder object
+         */
+        public TeAddressBuilder withTeRecords(List<LispTeRecord> records) {
+            this.records = records;
+            return this;
+        }
+
+        /**
+         * Builds LispTeLcafAddress instance.
+         *
+         * @return LispTeLcafAddress instance
+         */
+        public LispTeLcafAddress build() {
+            return new LispTeLcafAddress(records);
+        }
+    }
+    /**
+     * TE LCAF address reader class.
+     */
+    public static class TeLcafAddressReader
+                        implements LispAddressReader<LispTeLcafAddress> {
+
+        @Override
+        public LispTeLcafAddress readFrom(ByteBuf byteBuf)
+                                    throws LispParseError, LispReaderException {
+
+            LispLcafAddress lcafAddress = LispLcafAddress.deserializeCommon(byteBuf);
+
+            List<LispTeRecord> teRecords = Lists.newArrayList();
+            while (byteBuf.readerIndex() - COMMON_HEADER_SIZE < lcafAddress.getLength()) {
+                teRecords.add(new LispTeRecord.TeRecordReader().readFrom(byteBuf));
+            }
+
+            return new TeAddressBuilder()
+                        .withTeRecords(teRecords)
+                        .build();
+        }
+    }
+
+    /**
+     * TE LCAF address writer class.
+     */
+    public static class TeLcafAddressWriter
+                            implements LispAddressWriter<LispTeLcafAddress> {
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispTeLcafAddress address)
+                                                    throws LispWriterException {
+
+            int lcafIndex = byteBuf.writerIndex();
+            LispLcafAddress.serializeCommon(byteBuf, address);
+
+            LispTeRecord.TeRecordWriter writer = new LispTeRecord.TeRecordWriter();
+
+            List<LispTeRecord> teRecords = address.getTeRecords();
+            for (int i = 0; i < teRecords.size(); i++) {
+                writer.writeTo(byteBuf, teRecords.get(i));
+            }
+
+            LispLcafAddress.updateLength(lcafIndex, byteBuf);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispTeRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispTeRecord.java
new file mode 100644
index 0000000..6b4b56a
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/LispTeRecord.java
@@ -0,0 +1,269 @@
+/*
+ * 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.lcaf;
+
+import io.netty.buffer.ByteBuf;
+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.LispAddressReader;
+import org.onosproject.lisp.msg.types.LispAddressWriter;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressReader;
+import org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Traffic Engineering record class.
+ */
+public class LispTeRecord {
+
+    private final boolean lookup;
+    private final boolean rlocProbe;
+    private final boolean strict;
+    private final LispAfiAddress rtrRlocAddress;
+
+    /**
+     * Initializes TE record.
+     *
+     * @param lookup     lookup bit
+     * @param rlocProbe  rloc probe bit
+     * @param strict     strict bit
+     * @param rtrAddress RTR address
+     */
+    public LispTeRecord(boolean lookup, boolean rlocProbe,
+                        boolean strict, LispAfiAddress rtrAddress) {
+        this.lookup = lookup;
+        this.rlocProbe = rlocProbe;
+        this.strict = strict;
+        this.rtrRlocAddress = rtrAddress;
+    }
+
+    /**
+     * Obtains lookup bit flag.
+     *
+     * @return lookup bit flag
+     */
+    public boolean isLookup() {
+        return lookup;
+    }
+
+    /**
+     * Obtains RLOC probe bit flag.
+     *
+     * @return RLOC probe bit flag
+     */
+    public boolean isRlocProbe() {
+        return rlocProbe;
+    }
+
+    /**
+     * Obtains strict bit flag.
+     *
+     * @return strict bit flag
+     */
+    public boolean isStrict() {
+        return strict;
+    }
+
+    /**
+     * Obtains Re-encapsulated RLOC address.
+     *
+     * @return Re-encapsulated RLOC address
+     */
+    public LispAfiAddress getRtrRlocAddress() {
+        return rtrRlocAddress;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(lookup, rlocProbe, strict, rtrRlocAddress);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof LispTeRecord) {
+            final LispTeRecord other = (LispTeRecord) obj;
+            return Objects.equals(this.lookup, other.lookup) &&
+                    Objects.equals(this.rlocProbe, other.rlocProbe) &&
+                    Objects.equals(this.strict, other.strict) &&
+                    Objects.equals(this.rtrRlocAddress, other.rtrRlocAddress);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("Lookup bit", lookup)
+                .add("RLOC probe bit", rlocProbe)
+                .add("strict bit", strict)
+                .add("RTR address", rtrRlocAddress)
+                .toString();
+    }
+
+    public static final class TeRecordBuilder {
+        private boolean lookup;
+        private boolean rlocProbe;
+        private boolean strict;
+        private LispAfiAddress rtrRlocAddress;
+
+        /**
+         * Sets lookup flag.
+         *
+         * @param lookup lookup flag
+         * @return TeRecordBuilder object
+         */
+        public TeRecordBuilder withIsLookup(boolean lookup) {
+            this.lookup = lookup;
+            return this;
+        }
+
+        /**
+         * Sets RLOC probe flag.
+         *
+         * @param rlocProbe RLOC probe flag
+         * @return TeRecordBuilder object
+         */
+        public TeRecordBuilder withIsRlocProbe(boolean rlocProbe) {
+            this.rlocProbe = rlocProbe;
+            return this;
+        }
+
+        /**
+         * Sets strict flag.
+         *
+         * @param strict strict flag
+         * @return TeRecordBuilder object
+         */
+        public TeRecordBuilder withIsStrict(boolean strict) {
+            this.strict = strict;
+            return this;
+        }
+
+        /**
+         * Sets RTR RLOC address.
+         *
+         * @param rtrRlocAddress RTR RLOC address
+         * @return TeRecordBuilder object
+         */
+        public TeRecordBuilder withRtrRlocAddress(LispAfiAddress rtrRlocAddress) {
+            this.rtrRlocAddress = rtrRlocAddress;
+            return this;
+        }
+
+        /**
+         * Builds TeRecord instance.
+         *
+         * @return TeRcord instance
+         */
+        public LispTeRecord build() {
+
+            return new LispTeRecord(lookup, rlocProbe, strict, rtrRlocAddress);
+        }
+    }
+
+    /**
+     * Traffic Engineering record reader class.
+     */
+    public static class TeRecordReader implements LispAddressReader<LispTeRecord> {
+
+        private static final int RESERVED_SKIP_LENGTH = 1;
+
+        private static final int STRICT_INDEX = 1;
+        private static final int RLOC_PROBE_INDEX = 2;
+        private static final int LOOKUP_INDEX = 3;
+
+        @Override
+        public LispTeRecord readFrom(ByteBuf byteBuf)
+                                    throws LispParseError, LispReaderException {
+
+            // let's skip reserved 3
+            byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
+
+            byte flags = byteBuf.readByte();
+
+            // lookup -> 1 bit
+            boolean lookup = ByteOperator.getBit(flags, LOOKUP_INDEX);
+
+            // rlocProbe -> 1 bit
+            boolean rlocProbe = ByteOperator.getBit(flags, RLOC_PROBE_INDEX);
+
+            // strict -> 1 bit
+            boolean strict = ByteOperator.getBit(flags, STRICT_INDEX);
+
+            AfiAddressReader reader = new AfiAddressReader();
+
+            LispAfiAddress rtrAddress = reader.readFrom(byteBuf);
+
+            return new LispTeRecord(lookup, rlocProbe, strict, rtrAddress);
+        }
+    }
+
+    /**
+     * Traffic Engineering record writer class.
+     */
+    public static class TeRecordWriter implements LispAddressWriter<LispTeRecord> {
+
+        private static final int LOOKUP_FLAG_SHIFT_BIT = 3;
+        private static final int RLOC_PROBE_FLAG_SHIFT_BIT = 2;
+        private static final int STRICT_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, LispTeRecord record)
+                                                    throws LispWriterException {
+
+            byteBuf.writeByte(UNUSED_ZERO);
+
+            // lookup flag
+            byte lookup = DISABLE_BIT;
+            if (record.isLookup()) {
+                lookup = (byte) (ENABLE_BIT << LOOKUP_FLAG_SHIFT_BIT);
+            }
+
+            // RLOC probe flag
+            byte rlocProbe = DISABLE_BIT;
+            if (record.isRlocProbe()) {
+                rlocProbe = (byte) (ENABLE_BIT << RLOC_PROBE_FLAG_SHIFT_BIT);
+            }
+
+            // strict flag
+            byte strict = DISABLE_BIT;
+            if (record.isStrict()) {
+                strict = (byte) (ENABLE_BIT << STRICT_FLAG_SHIFT_BIT);
+            }
+
+            byteBuf.writeByte((byte) (lookup + rlocProbe + strict));
+
+            // RTR RLOC address
+            AfiAddressWriter writer = new AfiAddressWriter();
+            writer.writeTo(byteBuf, record.rtrRlocAddress);
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/package-info.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/package-info.java
new file mode 100644
index 0000000..21a149d
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/lcaf/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * LISP Canonical Address Formatted address type package.
+ */
+package org.onosproject.lisp.msg.types.lcaf;
\ No newline at end of file