[ONOS-4718] Add more LCAF type address with augmented LCAF class

In this commit, we added List Type, Instance ID Type, Source/Dest
Key Type and Application Data Type LCAF address classes.

Change-Id: I39881714069a32c52474ee82f8a9acdfcdc862b7
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddress.java
new file mode 100644
index 0000000..f3f3808
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAppDataLcafAddress.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.msg.types;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Application data type LCAF address class.
+ *
+ * Application data type is defined in draft-ietf-lisp-lcaf-13
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-13#page-26
+ *
+ *  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     |            12 + n             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |       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  ...          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class LispAppDataLcafAddress extends LispLcafAddress {
+
+    private final byte protocol;
+    private final int ipTos;
+    private final short localPort;
+    private final short remotePort;
+    private LispAfiAddress address;
+
+    /**
+     * Initializes application data type LCAF address.
+     */
+    public LispAppDataLcafAddress() {
+        super(LispCanonicalAddressFormatEnum.APPLICATION_DATA);
+        this.protocol = 0;
+        this.ipTos = 0;
+        this.localPort = 0;
+        this.remotePort = 0;
+    }
+
+    /**
+     * Initializes application data type LCAF address.
+     *
+     * @param protocol protocol number
+     * @param ipTos ip type of service
+     * @param localPort local port number
+     * @param remotePort remote port number
+     * @param address address
+     */
+    public LispAppDataLcafAddress(byte protocol, int ipTos, short localPort, short remotePort,
+                                  LispAfiAddress address) {
+        super(LispCanonicalAddressFormatEnum.APPLICATION_DATA);
+        this.protocol = protocol;
+        this.ipTos = ipTos;
+        this.localPort = localPort;
+        this.remotePort = remotePort;
+        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 local port number.
+     *
+     * @return local port number
+     */
+    public short getLocalPort() {
+        return localPort;
+    }
+
+    /**
+     * Obtains remote port number.
+     *
+     * @return remote port number
+     */
+    public short getRemotePort() {
+        return remotePort;
+    }
+
+    /**
+     * Obtains address.
+     *
+     * @return address
+     */
+    public LispAfiAddress getAddress() {
+        return address;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((address == null) ? 0 : address.hashCode());
+        result = prime * result + protocol;
+        result = prime * result + ipTos;
+        result = prime * result + localPort;
+        result = prime * result + remotePort;
+        return result;
+    }
+
+    @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.localPort, other.localPort) &&
+                    Objects.equals(this.remotePort, other.remotePort);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("address", address)
+                .add("protocol", protocol)
+                .add("ip type of service", ipTos)
+                .add("local port number", localPort)
+                .add("remote port number", remotePort)
+                .toString();
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispLcafAddress.java
index 2490ac57..ce51271 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispLcafAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispLcafAddress.java
@@ -21,22 +21,104 @@
 
 /**
  * LISP Canonical Address Formatted address class.
+ *
+ *  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             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 public class LispLcafAddress extends LispAfiAddress {
 
     protected final LispCanonicalAddressFormatEnum lcafType;
-    protected final byte value;
+    protected final byte reserved1;
+    protected final byte reserved2;
+    protected final byte flag;
+    protected final byte length;
 
     /**
      * Initializes LCAF address.
      *
      * @param lcafType LCAF type
-     * @param value LCAF value
+     * @param reserved1 reserved1 field
+     * @param reserved2 reserved2 field
+     * @param flag flag field
+     * @param length length field
      */
-    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType, byte value) {
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType,
+                              byte reserved1, byte reserved2, byte flag, byte length) {
         super(AddressFamilyIdentifierEnum.LCAF);
         this.lcafType = lcafType;
-        this.value = value;
+        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, byte 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, byte 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
+     */
+    protected LispLcafAddress(LispCanonicalAddressFormatEnum lcafType) {
+        super(AddressFamilyIdentifierEnum.LCAF);
+        this.lcafType = lcafType;
+        this.reserved1 = 0;
+        this.reserved2 = 0;
+        this.flag = 0;
+        this.length = 0;
     }
 
     /**
@@ -49,12 +131,39 @@
     }
 
     /**
-     * Obtains LCAF value.
+     * Obtains LCAF reserved1 value.
      *
-     * @return LCAF value
+     * @return LCAF reserved1 value
      */
-    public byte getValue() {
-        return 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 byte getLength() {
+        return length;
     }
 
     @Override
@@ -62,7 +171,10 @@
         final int prime = 31;
         int result = super.hashCode();
         result = prime * result + ((lcafType == null) ? 0 : lcafType.hashCode());
-        result = prime * result + value;
+        result = prime * result + reserved1;
+        result = prime * result + reserved2;
+        result = prime * result + flag;
+        result = prime * result + length;
         return result;
     }
 
@@ -75,7 +187,10 @@
         if (obj instanceof LispLcafAddress) {
             final LispLcafAddress other = (LispLcafAddress) obj;
             return Objects.equals(this.lcafType, other.lcafType) &&
-                    Objects.equals(this.value, other.value);
+                   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;
     }
@@ -84,7 +199,10 @@
     public String toString() {
         return toStringHelper(this)
                 .add("lcafType", lcafType)
-                .add("lcafValue", value)
+                .add("reserved1", reserved1)
+                .add("reserved2", reserved2)
+                .add("flag", flag)
+                .add("length", length)
                 .toString();
     }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispListLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispListLcafAddress.java
new file mode 100644
index 0000000..e92810a
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispListLcafAddress.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.msg.types;
+
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * List type LCAF address class.
+ *
+ * List type is defined in draft-ietf-lisp-lcaf-13
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-13#page-21
+ *
+ *  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     |         2 + 4 + 2 + 16        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            AFI = 1            |       IPv4 Address ...        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |     ...  IPv4 Address         |            AFI = 2            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          IPv6 Address ...                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     ...  IPv6 Address  ...                    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     ...  IPv6 Address  ...                    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     ...  IPv6 Address                         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class LispListLcafAddress extends LispLcafAddress {
+
+    private static final byte 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);
+    }
+
+    /**
+     * Obtains a set of AFI addresses including IPv4 and IPv6.
+     *
+     * @return a set of AFI addresses
+     */
+    public List<LispAfiAddress> getAddresses() {
+        return addresses;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((addresses == null) ? 0 : addresses.hashCode());
+        return result;
+    }
+
+    @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();
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddress.java
new file mode 100644
index 0000000..b44905e
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSegmentLcafAddress.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.msg.types;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Instance ID type LCAF address class.
+ * Instance ID type is defined in draft-ietf-lisp-lcaf-13
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-13#page-7
+ *
+ *  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  |             4 + n             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Instance ID                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |         Address  ...          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public 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
+     */
+    public LispSegmentLcafAddress(byte idMaskLength, int instanceId, LispAfiAddress address) {
+        super(LispCanonicalAddressFormatEnum.SEGMENT, idMaskLength);
+        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 reserved2;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((address == null) ? 0 : address.hashCode());
+        result = prime * result + instanceId;
+        result = prime * result + reserved2;
+        return result;
+    }
+
+    @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.reserved2, other.reserved2);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("address", address)
+                .add("instanceId", instanceId)
+                .add("idMaskLength", reserved2)
+                .toString();
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddress.java
new file mode 100644
index 0000000..6438fb3
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispSourceDestLcafAddress.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.msg.types;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Source/Dest key type LCAF address class.
+ * Source destination key type is defined in draft-ietf-lisp-lcaf-13
+ * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-13#page-18
+ *
+ *  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     |             4 + n             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            Reserved           |   Source-ML   |    Dest-ML    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |         Source-Prefix ...     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |              AFI = x          |     Destination-Prefix ...    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class LispSourceDestLcafAddress extends LispLcafAddress {
+
+    private LispAfiAddress srcPrefix;
+    private LispAfiAddress dstPrefix;
+    private final byte srcMaskLength;
+    private final byte dstMaskLength;
+    private final short reserved;
+
+    /**
+     * Initializes source/dest key type LCAF address.
+     */
+    public LispSourceDestLcafAddress() {
+        super(LispCanonicalAddressFormatEnum.SOURCE_DEST);
+        srcMaskLength = 0;
+        dstMaskLength = 0;
+        reserved = 0;
+    }
+
+    /**
+     * Initializes source/dest key type LCAF address.
+     *
+     * @param reserved reserved
+     * @param srcMaskLength source mask length
+     * @param dstMaskLength destination mask length
+     * @param srcPrefix source address prefix
+     * @param dstPrefix destination address prefix
+     */
+    public 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;
+    }
+
+    /**
+     * 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() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((srcPrefix == null) ? 0 : srcPrefix.hashCode());
+        result = prime * result + ((dstPrefix == null) ? 0 : dstPrefix.hashCode());
+        result = prime * result + srcMaskLength;
+        result = prime * result + dstMaskLength;
+        result = prime * result + reserved;
+        return result;
+    }
+
+    @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();
+    }
+}