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

- Add LispLocatorRecord interface along with
  DefaultLispLocatorRecord class and unit test class
- Add deserialization logic for four LISP control message classes
  and two auxiliary classes
- Add ByteOperator utility to ease the bit access and manipulation
  for byte data type

Change-Id: I68edf6877a0ebb52260296fc556e0690b795a845
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java
new file mode 100644
index 0000000..29ad1bd
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecord.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.msg.protocols;
+
+import com.google.common.base.Objects;
+import io.netty.buffer.ByteBuf;
+import org.onlab.util.ByteOperator;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default implementation of LispLocatorRecord.
+ */
+public final class DefaultLispLocatorRecord implements LispLocatorRecord {
+
+    private final byte priority;
+    private final byte weight;
+    private final byte multicastPriority;
+    private final byte multicastWeight;
+    private final boolean localLocator;
+    private final boolean rlocProbed;
+    private final boolean routed;
+    private final LispAfiAddress locatorAfi;
+
+    /**
+     * A private constructor that protects object instantiation from external.
+     *
+     * @param priority          uni-cast priority
+     * @param weight            uni-cast weight
+     * @param multicastPriority multi-cast priority
+     * @param multicastWeight   multi-cast weight
+     * @param localLocator      local locator flag
+     * @param rlocProbed        RLOC probed flag
+     * @param routed            routed flag
+     * @param locatorAfi        locator AFI
+     */
+    private DefaultLispLocatorRecord(byte priority, byte weight, byte multicastPriority,
+                                     byte multicastWeight, boolean localLocator, boolean rlocProbed,
+                                     boolean routed, LispAfiAddress locatorAfi) {
+        this.priority = priority;
+        this.weight = weight;
+        this.multicastPriority = multicastPriority;
+        this.multicastWeight = multicastWeight;
+        this.localLocator = localLocator;
+        this.rlocProbed = rlocProbed;
+        this.routed = routed;
+        this.locatorAfi = locatorAfi;
+    }
+
+    @Override
+    public byte getPriority() {
+        return priority;
+    }
+
+    @Override
+    public byte getWeight() {
+        return weight;
+    }
+
+    @Override
+    public byte getMulticastPriority() {
+        return multicastPriority;
+    }
+
+    @Override
+    public byte getMulticastWeight() {
+        return multicastWeight;
+    }
+
+    @Override
+    public boolean isLocalLocator() {
+        return localLocator;
+    }
+
+    @Override
+    public boolean isRlocProbed() {
+        return rlocProbed;
+    }
+
+    @Override
+    public boolean isRouted() {
+        return routed;
+    }
+
+    @Override
+    public LispAfiAddress getLocatorAfi() {
+        return locatorAfi;
+    }
+
+    @Override
+    public void writeTo(ByteBuf byteBuf) {
+
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("priority", priority)
+                .add("weight", weight)
+                .add("multi-cast priority", multicastPriority)
+                .add("multi-cast weight", multicastWeight)
+                .add("local locator", localLocator)
+                .add("RLOC probed", rlocProbed)
+                .add("routed", routed)
+                .add("locator AFI", locatorAfi).toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        DefaultLispLocatorRecord that = (DefaultLispLocatorRecord) o;
+        return Objects.equal(priority, that.priority) &&
+                Objects.equal(weight, that.weight) &&
+                Objects.equal(multicastPriority, that.multicastPriority) &&
+                Objects.equal(multicastWeight, that.multicastWeight) &&
+                Objects.equal(localLocator, that.localLocator) &&
+                Objects.equal(rlocProbed, that.rlocProbed) &&
+                Objects.equal(routed, that.routed) &&
+                Objects.equal(locatorAfi, that.locatorAfi);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(priority, weight, multicastPriority,
+                multicastWeight, localLocator, rlocProbed, routed, locatorAfi);
+    }
+
+    public static final class DefaultLocatorRecordBuilder implements LocatorRecordBuilder {
+
+        private byte priority;
+        private byte weight;
+        private byte multicastPriority;
+        private byte multicastWeight;
+        private boolean localLocator;
+        private boolean rlocProbed;
+        private boolean routed;
+        private LispAfiAddress locatorAfi;
+
+        @Override
+        public LocatorRecordBuilder withPriority(byte priority) {
+            this.priority = priority;
+            return this;
+        }
+
+        @Override
+        public LocatorRecordBuilder withWeight(byte weight) {
+            this.weight = weight;
+            return this;
+        }
+
+        @Override
+        public LocatorRecordBuilder withMulticastPriority(byte priority) {
+            this.multicastPriority = priority;
+            return this;
+        }
+
+        @Override
+        public LocatorRecordBuilder withMulticastWeight(byte weight) {
+            this.multicastWeight = weight;
+            return this;
+        }
+
+        @Override
+        public LocatorRecordBuilder withLocalLocator(boolean localLocator) {
+            this.localLocator = localLocator;
+            return this;
+        }
+
+        @Override
+        public LocatorRecordBuilder withRlocProbed(boolean rlocProbed) {
+            this.rlocProbed = rlocProbed;
+            return this;
+        }
+
+        @Override
+        public LocatorRecordBuilder withRouted(boolean routed) {
+            this.routed = routed;
+            return this;
+        }
+
+        @Override
+        public LocatorRecordBuilder withLocatorAfi(LispAfiAddress locatorAfi) {
+            this.locatorAfi = locatorAfi;
+            return this;
+        }
+
+        @Override
+        public LispLocatorRecord build() {
+            return new DefaultLispLocatorRecord(priority, weight, multicastPriority,
+                    multicastWeight, localLocator, rlocProbed, routed, locatorAfi);
+        }
+    }
+
+    /**
+     * A LISP message reader for LocatorRecord portion.
+     */
+    public static final class LocatorRecordReader implements LispMessageReader<LispLocatorRecord> {
+
+        private static final int SKIP_UNUSED_FLAG_LENGTH = 1;
+        private static final int LOCAL_LOCATOR_INDEX = 2;
+        private static final int RLOC_PROBED_INDEX = 1;
+        private static final int ROUTED_INDEX = 0;
+
+        @Override
+        public LispLocatorRecord readFrom(ByteBuf byteBuf) throws LispParseError {
+
+            // priority -> 8 bits
+            byte priority = (byte) byteBuf.readUnsignedByte();
+
+            // weight -> 8 bits
+            byte weight = (byte) byteBuf.readUnsignedByte();
+
+            // multi-cast priority -> 8 bits
+            byte multicastPriority = (byte) byteBuf.readUnsignedByte();
+
+            // multi-cast weight -> 8 bits
+            byte multicastWeight = (byte) byteBuf.readUnsignedByte();
+
+            // let's skip unused flags
+            byteBuf.skipBytes(SKIP_UNUSED_FLAG_LENGTH);
+
+            byte flags = byteBuf.readByte();
+
+            // local locator flag -> 1 bit
+            boolean localLocator = ByteOperator.getBit(flags, LOCAL_LOCATOR_INDEX);
+
+            // rloc probe flag -> 1 bit
+            boolean rlocProbed = ByteOperator.getBit(flags, RLOC_PROBED_INDEX);
+
+            // routed flag -> 1 bit
+            boolean routed = ByteOperator.getBit(flags, ROUTED_INDEX);
+
+            // TODO: de-serialize ITR-RLOC AFI and address
+
+            return new DefaultLocatorRecordBuilder()
+                        .withPriority(priority)
+                        .withWeight(weight)
+                        .withMulticastPriority(multicastPriority)
+                        .withMulticastWeight(multicastWeight)
+                        .withLocalLocator(localLocator)
+                        .withRlocProbed(rlocProbed)
+                        .withRouted(routed)
+                        .build();
+        }
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
index 831065a..c80b4d1 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
@@ -131,7 +131,7 @@
         private short keyId;
         private byte[] authenticationData;
         private byte recordCount;
-        private List<LispMapRecord> mapRecords = Lists.newArrayList();
+        private List<LispMapRecord> mapRecords;
 
         @Override
         public LispType getType() {
@@ -163,8 +163,8 @@
         }
 
         @Override
-        public NotifyBuilder addRecord(LispMapRecord record) {
-            this.mapRecords.add(record);
+        public NotifyBuilder withMapRecords(List<LispMapRecord> mapRecords) {
+            this.mapRecords = ImmutableList.copyOf(mapRecords);
             return this;
         }
 
@@ -180,9 +180,46 @@
      */
     private static class NotifyReader implements LispMessageReader<LispMapNotify> {
 
+        private static final int RESERVED_SKIP_LENGTH = 3;
+
         @Override
         public LispMapNotify readFrom(ByteBuf byteBuf) throws LispParseError {
-            return null;
+
+            if (byteBuf.readerIndex() != 0) {
+                return null;
+            }
+
+            // skip first three bytes as they represent type and reserved fields
+            byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
+
+            // record count -> 8 bits
+            byte recordCount = (byte) byteBuf.readUnsignedByte();
+
+            // nonce -> 64 bits
+            long nonce = byteBuf.readLong();
+
+            // keyId -> 16 bits
+            short keyId = byteBuf.readShort();
+
+            // authenticationDataLength -> 16 bits
+            short authLength = byteBuf.readShort();
+
+            // authenticationData -> depends on the authenticationDataLength
+            byte[] authData = new byte[authLength];
+            byteBuf.readBytes(authData);
+
+            List<LispMapRecord> mapRecords = Lists.newArrayList();
+            for (int i = 0; i < recordCount; i++) {
+                mapRecords.add(new DefaultLispMapRecord.MapRecordReader().readFrom(byteBuf));
+            }
+
+            return new DefaultNotifyBuilder()
+                        .withRecordCount(recordCount)
+                        .withNonce(nonce)
+                        .withKeyId(keyId)
+                        .withAuthenticationData(authData)
+                        .withMapRecords(mapRecords)
+                        .build();
         }
     }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java
index 7b0c86c..c681e06 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecord.java
@@ -16,10 +16,15 @@
 package org.onosproject.lisp.msg.protocols;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
+import org.onlab.util.ByteOperator;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
 
+import java.util.List;
+
 import static com.google.common.base.MoreObjects.toStringHelper;
 
 /**
@@ -34,6 +39,7 @@
     private final boolean authoritative;
     private final short mapVersionNumber;
     private final LispAfiAddress eidPrefixAfi;
+    private final List<LispLocatorRecord> locatorRecords;
 
     /**
      * A private constructor that protects object instantiation from external.
@@ -48,7 +54,8 @@
      */
     private DefaultLispMapRecord(int recordTtl, int locatorCount, byte maskLength,
                                  LispMapReplyAction action, boolean authoritative,
-                                 short mapVersionNumber, LispAfiAddress eidPrefixAfi) {
+                                 short mapVersionNumber, LispAfiAddress eidPrefixAfi,
+                                 List<LispLocatorRecord> locatorRecords) {
         this.recordTtl = recordTtl;
         this.locatorCount = locatorCount;
         this.maskLength = maskLength;
@@ -56,6 +63,7 @@
         this.authoritative = authoritative;
         this.mapVersionNumber = mapVersionNumber;
         this.eidPrefixAfi = eidPrefixAfi;
+        this.locatorRecords = locatorRecords;
     }
 
     @Override
@@ -94,6 +102,16 @@
     }
 
     @Override
+    public List<LispLocatorRecord> getLocators() {
+        return ImmutableList.copyOf(locatorRecords);
+    }
+
+    @Override
+    public void writeTo(ByteBuf byteBuf) {
+
+    }
+
+    @Override
     public String toString() {
         return toStringHelper(this)
                 .add("record TTL", recordTtl)
@@ -102,7 +120,9 @@
                 .add("action", action)
                 .add("authoritative", authoritative)
                 .add("mapVersionNumber", mapVersionNumber)
-                .add("EID prefix AFI address", eidPrefixAfi).toString();
+                .add("EID prefix AFI address", eidPrefixAfi)
+                .add("locator records", locatorRecords).toString();
+
     }
 
     @Override
@@ -120,13 +140,14 @@
                 Objects.equal(action, that.action) &&
                 Objects.equal(authoritative, that.authoritative) &&
                 Objects.equal(mapVersionNumber, that.mapVersionNumber) &&
-                Objects.equal(eidPrefixAfi, that.eidPrefixAfi);
+                Objects.equal(eidPrefixAfi, that.eidPrefixAfi) &&
+                Objects.equal(locatorRecords, that.locatorRecords);
     }
 
     @Override
     public int hashCode() {
         return Objects.hashCode(recordTtl, locatorCount, maskLength, action,
-                                authoritative, mapVersionNumber, eidPrefixAfi);
+                                authoritative, mapVersionNumber, eidPrefixAfi, locatorRecords);
     }
 
     public static final class DefaultMapRecordBuilder implements MapRecordBuilder {
@@ -138,6 +159,7 @@
         private boolean authoritative;
         private short mapVersionNumber;
         private LispAfiAddress eidPrefixAfi;
+        private List<LispLocatorRecord> locatorRecords;
 
         @Override
         public MapRecordBuilder withRecordTtl(int recordTtl) {
@@ -182,20 +204,66 @@
         }
 
         @Override
+        public MapRecordBuilder withLocators(List<LispLocatorRecord> records) {
+            this.locatorRecords = ImmutableList.copyOf(records);
+            return this;
+        }
+
+        @Override
         public LispMapRecord build() {
             return new DefaultLispMapRecord(recordTtl, locatorCount, maskLength,
-                    action, authoritative, mapVersionNumber, eidPrefixAfi);
+                    action, authoritative, mapVersionNumber, eidPrefixAfi, locatorRecords);
         }
     }
 
     /**
-     * A private LISP message reader for MapRecord portion.
+     * A LISP message reader for MapRecord portion.
      */
-    private static class RecordReader implements LispMessageReader<LispMapRecord> {
+    public static final class MapRecordReader implements LispMessageReader<LispMapRecord> {
+
+        private static final int AUTHORITATIVE_INDEX = 4;
+        private static final int RESERVED_SKIP_LENGTH = 1;
 
         @Override
         public LispMapRecord readFrom(ByteBuf byteBuf) throws LispParseError {
-            return null;
+
+            // Record TTL -> 32 bits
+            int recordTtl = byteBuf.readInt();
+
+            // Locator count -> 8 bits
+            int locatorCount = byteBuf.readUnsignedShort();
+
+            // EID mask length -> 8 bits
+            byte maskLength = (byte) byteBuf.readUnsignedByte();
+
+            // TODO: need to de-serialize LispMapReplyAction
+
+            byte actionWithFlag = byteBuf.readByte();
+
+            // authoritative flag -> 1 bit
+            boolean authoritative = ByteOperator.getBit(actionWithFlag, AUTHORITATIVE_INDEX);
+
+            // let's skip the reserved field
+            byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
+
+            // Map version number -> 12 bits, we treat Rsvd field is all zero
+            short mapVersionNumber = (short) byteBuf.readUnsignedShort();
+
+            // TODO: need to de-serialize EID AFI address
+
+            List<LispLocatorRecord> locators = Lists.newArrayList();
+            for (int i = 0; i < locatorCount; i++) {
+                locators.add(new DefaultLispLocatorRecord.LocatorRecordReader().readFrom(byteBuf));
+            }
+
+            return new DefaultMapRecordBuilder()
+                        .withRecordTtl(recordTtl)
+                        .withLocatorCount(locatorCount)
+                        .withMaskLength(maskLength)
+                        .withAuthoritative(authoritative)
+                        .withMapVersionNumber(mapVersionNumber)
+                        .withLocators(locators)
+                        .build();
         }
     }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
index b77e580..058db10 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
+import org.onlab.util.ByteOperator;
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 
@@ -155,7 +156,7 @@
         private short keyId;
         private byte[] authenticationData;
         private byte recordCount;
-        private final List<LispMapRecord> mapRecords = Lists.newArrayList();
+        private List<LispMapRecord> mapRecords;
         private boolean proxyMapReply;
         private boolean wantMapNotify;
 
@@ -201,8 +202,8 @@
         }
 
         @Override
-        public RegisterBuilder addRecord(LispMapRecord record) {
-            this.mapRecords.add(record);
+        public RegisterBuilder withMapRecords(List<LispMapRecord> mapRecords) {
+            this.mapRecords = ImmutableList.copyOf(mapRecords);
             return this;
         }
 
@@ -218,9 +219,58 @@
      */
     private static class RegisterReader implements LispMessageReader<LispMapRegister> {
 
+        private static final int PROXY_MAP_REPLY_INDEX = 3;
+        private static final int WANT_MAP_NOTIFY_INDEX = 0;
+        private static final int RESERVED_SKIP_LENGTH = 1;
+
         @Override
         public LispMapRegister readFrom(ByteBuf byteBuf) throws LispParseError {
-            return null;
+
+            if (byteBuf.readerIndex() != 0) {
+                return null;
+            }
+
+            // proxyMapReply -> 1 bit
+            boolean proxyMapReplyFlag = ByteOperator.getBit(byteBuf.readByte(), PROXY_MAP_REPLY_INDEX);
+
+            // let's skip the reserved field
+            byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
+
+            byte reservedWithFlag = byteBuf.readByte();
+
+            // wantMapReply -> 1 bit
+            boolean wantMapNotifyFlag = ByteOperator.getBit(reservedWithFlag, WANT_MAP_NOTIFY_INDEX);
+
+            // record count -> 8 bits
+            byte recordCount = (byte) byteBuf.readUnsignedByte();
+
+            // nonce -> 64 bits
+            long nonce = byteBuf.readLong();
+
+            // keyId -> 16 bits
+            short keyId = byteBuf.readShort();
+
+            // authenticationDataLength -> 16 bits
+            short authLength = byteBuf.readShort();
+
+            // authenticationData -> depends on the authenticationDataLength
+            byte[] authData = new byte[authLength];
+            byteBuf.readBytes(authData);
+
+            List<LispMapRecord> mapRecords = Lists.newArrayList();
+            for (int i = 0; i < recordCount; i++) {
+                mapRecords.add(new DefaultLispMapRecord.MapRecordReader().readFrom(byteBuf));
+            }
+
+            return new DefaultRegisterBuilder()
+                    .withIsProxyMapReply(proxyMapReplyFlag)
+                    .withIsWantMapNotify(wantMapNotifyFlag)
+                    .withRecordCount(recordCount)
+                    .withNonce(nonce)
+                    .withKeyId(keyId)
+                    .withAuthenticationData(authData)
+                    .withMapRecords(mapRecords)
+                    .build();
         }
     }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java
index ee42dd1..6e5e218 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReply.java
@@ -17,6 +17,7 @@
 
 import com.google.common.base.Objects;
 import io.netty.buffer.ByteBuf;
+import org.onlab.util.ByteOperator;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -176,9 +177,47 @@
      */
     private static class ReplyReader implements LispMessageReader<LispMapReply> {
 
+        private static final int PROBE_INDEX = 3;
+        private static final int ETR_INDEX = 2;
+        private static final int SECURITY_INDEX = 1;
+        private static final int RESERVED_SKIP_LENGTH = 2;
+
         @Override
         public LispMapReply readFrom(ByteBuf byteBuf) throws LispParseError {
-            return null;
+
+            if (byteBuf.readerIndex() != 0) {
+                return null;
+            }
+
+            byte typeWithFlags = byteBuf.readByte();
+
+            // probe -> 1 bit
+            boolean probe = ByteOperator.getBit(typeWithFlags, PROBE_INDEX);
+
+            // etr -> 1bit
+            boolean etr = ByteOperator.getBit(typeWithFlags, ETR_INDEX);
+
+            // security -> 1 bit
+            boolean security = ByteOperator.getBit(typeWithFlags, SECURITY_INDEX);
+
+            // skip two bytes as they represent reserved fields
+            byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
+
+            // record count -> 8 bits
+            byte recordCount = (byte) byteBuf.readUnsignedByte();
+
+            // nonce -> 64 bits
+            long nonce = byteBuf.readLong();
+
+            // TODO: need to de-serialize EID-RLOC records
+
+            return new DefaultReplyBuilder()
+                        .withIsProbe(probe)
+                        .withIsEtr(etr)
+                        .withIsSecurity(security)
+                        .withRecordCount(recordCount)
+                        .withNonce(nonce)
+                        .build();
         }
     }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java
index f988fa1..d2d7bdb 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequest.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
+import org.onlab.util.ByteOperator;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
 
@@ -227,7 +228,6 @@
             return this;
         }
 
-
         @Override
         public RequestBuilder withIsSmr(boolean smr) {
             this.smr = smr;
@@ -265,14 +265,14 @@
         }
 
         @Override
-        public RequestBuilder addItrRloc(LispAfiAddress itrRloc) {
-            this.itrRlocs.add(itrRloc);
+        public RequestBuilder withItrRlocs(List<LispAfiAddress> itrRlocs) {
+            this.itrRlocs = ImmutableList.copyOf(itrRlocs);
             return this;
         }
 
         @Override
-        public RequestBuilder addEidRecord(LispEidRecord record) {
-            this.eidRecords.add(record);
+        public RequestBuilder withEidRecords(List<LispEidRecord> records) {
+            this.eidRecords = ImmutableList.copyOf(records);
             return this;
         }
 
@@ -288,9 +288,69 @@
      */
     private static class RequestReader implements LispMessageReader<LispMapRequest> {
 
+        private static final int AUTHORITATIVE_INDEX = 3;
+        private static final int MAP_DATA_PRESENT_INDEX = 2;
+        private static final int PROBE_INDEX = 1;
+        private static final int SMR_INDEX = 0;
+        private static final int PITR_INDEX = 7;
+        private static final int SMR_INVOKED_INDEX = 6;
+
         @Override
         public LispMapRequest readFrom(ByteBuf byteBuf) throws LispParseError {
-            return null;
+
+            if (byteBuf.readerIndex() != 0) {
+                return null;
+            }
+
+            byte typeWithFlags = byteBuf.readByte();
+
+            // authoritative -> 1 bit
+            boolean authoritative = ByteOperator.getBit(typeWithFlags, AUTHORITATIVE_INDEX);
+
+            // mapDataPresent -> 1 bit
+            boolean mapDataPresent = ByteOperator.getBit(typeWithFlags, MAP_DATA_PRESENT_INDEX);
+
+            // probe -> 1 bit
+            boolean probe = ByteOperator.getBit(typeWithFlags, PROBE_INDEX);
+
+            // smr -> 1 bit
+            boolean smr = ByteOperator.getBit(typeWithFlags, SMR_INDEX);
+
+            byte reservedWithFlags = byteBuf.readByte();
+
+            // pitr -> 1 bit
+            boolean pitr = ByteOperator.getBit(reservedWithFlags, PITR_INDEX);
+
+            // smrInvoked -> 1 bit
+            boolean smrInvoked = ByteOperator.getBit(reservedWithFlags, SMR_INVOKED_INDEX);
+
+            // let's skip reserved field, only obtains ITR counter value
+            // assume that first 3 bits are all set as 0,
+            // remain 5 bits represent Itr Rloc Counter (IRC)
+            int irc = byteBuf.readUnsignedShort();
+
+            // record count -> 8 bits
+            int recordCount = byteBuf.readUnsignedShort();
+
+            // nonce -> 64 bits
+            long nonce = byteBuf.readLong();
+
+            // TODO: de-serialize source EID AFI and address
+
+            // TODO: de-serialize ITR-RLOC AFI and address
+
+            // TODO: de-serialize EID-RECORD
+
+            return new DefaultRequestBuilder()
+                        .withIsAuthoritative(authoritative)
+                        .withIsMapDataPresent(mapDataPresent)
+                        .withIsProbe(probe)
+                        .withIsSmr(smr)
+                        .withIsPitr(pitr)
+                        .withIsSmrInvoked(smrInvoked)
+                        .withNonce(nonce)
+                        .withRecordCount((byte) recordCount)
+                        .build();
         }
     }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java
index 0984324..498ce13 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispEidRecord.java
@@ -61,9 +61,20 @@
      */
     private static class EidRecordReader implements LispMessageReader<LispEidRecord> {
 
+        private static final int RESERVED_SKIP_LENGTH = 1;
+
         @Override
         public LispEidRecord readFrom(ByteBuf byteBuf) throws LispParseError {
-            return null;
+
+            // let's skip the reserved field
+            byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
+
+            short maskLength = (short) byteBuf.readUnsignedShort();
+
+            // TODO: need to de-serialize AFI address
+            LispAfiAddress prefix = null;
+
+            return new LispEidRecord((byte) maskLength, prefix);
         }
     }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java
new file mode 100644
index 0000000..ca18e0b
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispLocatorRecord.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.msg.protocols;
+
+import io.netty.buffer.ByteBuf;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+/**
+ * LISP locator record section which is part of LISP map record.
+ */
+public interface LispLocatorRecord {
+
+    /**
+     * Obtains priority value.
+     *
+     * @return priority value
+     */
+    byte getPriority();
+
+    /**
+     * Obtains weight value.
+     *
+     * @return weight value
+     */
+    byte getWeight();
+
+    /**
+     * Obtains multi-cast priority value.
+     *
+     * @return multi-cast priority value
+     */
+    byte getMulticastPriority();
+
+    /**
+     * Obtains multi-cast weight value.
+     *
+     * @return multi-cast weight value
+     */
+    byte getMulticastWeight();
+
+    /**
+     * Obtains local locator flag.
+     *
+     * @return local locator flag
+     */
+    boolean isLocalLocator();
+
+    /**
+     * Obtains RLOC probed flag.
+     *
+     * @return RLOC probed flag
+     */
+    boolean isRlocProbed();
+
+    /**
+     * Obtains routed flag.
+     *
+     * @return routed flag
+     */
+    boolean isRouted();
+
+    /**
+     * Obtains locator AFI.
+     *
+     * @return locator AFI
+     */
+    LispAfiAddress getLocatorAfi();
+
+    /**
+     * Writes LISP message object into communication channel.
+     *
+     * @param byteBuf byte buffer
+     */
+    void writeTo(ByteBuf byteBuf);
+
+    /**
+     * A builder of LISP locator record.
+     */
+    interface LocatorRecordBuilder {
+
+        /**
+         * Sets priority value.
+         *
+         * @param priority priority
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withPriority(byte priority);
+
+        /**
+         * Sets weight value.
+         *
+         * @param weight weight
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withWeight(byte weight);
+
+        /**
+         * Sets multi-cast priority value.
+         *
+         * @param priority priority
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withMulticastPriority(byte priority);
+
+        /**
+         * Sets multi-cast weight value.
+         *
+         * @param weight weight
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withMulticastWeight(byte weight);
+
+        /**
+         * Sets local locator flag.
+         *
+         * @param localLocator local locator flag
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withLocalLocator(boolean localLocator);
+
+        /**
+         * Sets RLOC probed flag.
+         *
+         * @param rlocProbed RLOC probed flag
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withRlocProbed(boolean rlocProbed);
+
+        /**
+         * Sets routed flag.
+         *
+         * @param routed routed flag
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withRouted(boolean routed);
+
+        /**
+         * Sets locator AFI.
+         *
+         * @param locatorAfi locator AFI
+         * @return LocatorRecordBuilder object
+         */
+        LocatorRecordBuilder withLocatorAfi(LispAfiAddress locatorAfi);
+
+        /**
+         * Builds locator record.
+         *
+         * @return locator record instance
+         */
+        LispLocatorRecord build();
+    }
+}
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java
index 8e33dba..84830e9 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapNotify.java
@@ -129,12 +129,12 @@
         NotifyBuilder withAuthenticationData(byte[] authenticationData);
 
         /**
-         * Adds a new record to record list.
+         * Sets a collection of map records.
          *
-         * @param record record
-         * @return NotifyBuilder object
+         * @param mapRecords a collection of map records
+         * @return RegisterBuilder object
          */
-        NotifyBuilder addRecord(LispMapRecord record);
+        NotifyBuilder withMapRecords(List<LispMapRecord> mapRecords);
 
         /**
          * Builds LISP map notify message.
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java
index 6374292..49ff541 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRecord.java
@@ -15,8 +15,11 @@
  */
 package org.onosproject.lisp.msg.protocols;
 
+import io.netty.buffer.ByteBuf;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
 
+import java.util.List;
+
 /**
  * LISP record section which is part of LISP map register message.
  */
@@ -72,6 +75,20 @@
     LispAfiAddress getEidPrefixAfi();
 
     /**
+     * Obtains a collection of locator records.
+     *
+     * @return a collection of locator records
+     */
+    List<LispLocatorRecord> getLocators();
+
+    /**
+     * Writes LISP message object into communication channel.
+     *
+     * @param byteBuf byte buffer
+     */
+    void writeTo(ByteBuf byteBuf);
+
+    /**
      * A builder of LISP map record.
      */
     interface MapRecordBuilder {
@@ -133,6 +150,14 @@
         MapRecordBuilder withEidPrefixAfi(LispAfiAddress prefix);
 
         /**
+         * Sets a collection of locator records.
+         *
+         * @param records a collection of locator records
+         * @return MapRecordBuilder object
+         */
+        MapRecordBuilder withLocators(List<LispLocatorRecord> records);
+
+        /**
          * Builds map record.
          *
          * @return map record instance
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java
index a899b43..d3b1e6f 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRegister.java
@@ -159,12 +159,12 @@
         RegisterBuilder withAuthenticationData(byte[] authenticationData);
 
         /**
-         * Adds a new record to record list.
+         * Sets a collection of map records.
          *
-         * @param record record
+         * @param mapRecords a collection of map records
          * @return RegisterBuilder object
          */
-        RegisterBuilder addRecord(LispMapRecord record);
+        RegisterBuilder withMapRecords(List<LispMapRecord> mapRecords);
 
         /**
          * Builds LISP map register message.
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRequest.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRequest.java
index 57f87b2..f548f65 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRequest.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispMapRequest.java
@@ -210,20 +210,20 @@
         RequestBuilder withSourceEid(LispAfiAddress sourceEid);
 
         /**
-         * Adds ITR RLOC into RLOC collection.
+         * Sets a collection of ITR RLOCs.
          *
-         * @param itrRloc ITR RLOC
+         * @param itrRlocs a collection of ITR RLOCs
          * @return RequestBuilder object
          */
-        RequestBuilder addItrRloc(LispAfiAddress itrRloc);
+        RequestBuilder withItrRlocs(List<LispAfiAddress> itrRlocs);
 
         /**
-         * Adds EID record into record collection.
+         * Sets a collection of EID records.
          *
-         * @param record EID record
+         * @param records a collection of EID records
          * @return RequestBuilder object
          */
-        RequestBuilder addEidRecord(LispEidRecord record);
+        RequestBuilder withEidRecords(List<LispEidRecord> records);
 
         /**
          * Builds LISP map request message.
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecordTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecordTest.java
new file mode 100644
index 0000000..7b99612
--- /dev/null
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispLocatorRecordTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.msg.protocols;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Unit tests for DefaultLispLocatorRecord class.
+ */
+public final class DefaultLispLocatorRecordTest {
+
+    private LispLocatorRecord record1;
+    private LispLocatorRecord sameAsRecord1;
+    private LispLocatorRecord record2;
+
+    @Before
+    public void setup() {
+
+        LispLocatorRecord.LocatorRecordBuilder builder1 =
+                    new DefaultLispLocatorRecord.DefaultLocatorRecordBuilder();
+
+        record1 = builder1
+                        .withPriority((byte) 0x01)
+                        .withWeight((byte) 0x01)
+                        .withMulticastPriority((byte) 0x01)
+                        .withMulticastWeight((byte) 0x01)
+                        .withLocalLocator(true)
+                        .withRlocProbed(false)
+                        .withRouted(true)
+                        .build();
+
+        LispLocatorRecord.LocatorRecordBuilder builder2 =
+                    new DefaultLispLocatorRecord.DefaultLocatorRecordBuilder();
+
+        sameAsRecord1 = builder2
+                        .withPriority((byte) 0x01)
+                        .withWeight((byte) 0x01)
+                        .withMulticastPriority((byte) 0x01)
+                        .withMulticastWeight((byte) 0x01)
+                        .withLocalLocator(true)
+                        .withRlocProbed(false)
+                        .withRouted(true)
+                        .build();
+
+        LispLocatorRecord.LocatorRecordBuilder builder3 =
+                    new DefaultLispLocatorRecord.DefaultLocatorRecordBuilder();
+
+        record2 = builder3
+                        .withPriority((byte) 0x02)
+                        .withWeight((byte) 0x02)
+                        .withMulticastPriority((byte) 0x02)
+                        .withMulticastWeight((byte) 0x02)
+                        .withLocalLocator(false)
+                        .withRlocProbed(true)
+                        .withRouted(false)
+                        .build();
+    }
+
+    @Test
+    public void testEquality() {
+        new EqualsTester()
+                .addEqualityGroup(record1, sameAsRecord1)
+                .addEqualityGroup(record2).testEquals();
+    }
+
+    @Test
+    public void testConstruction() {
+        DefaultLispLocatorRecord record = (DefaultLispLocatorRecord) record1;
+
+        assertThat(record.getPriority(), is((byte) 0x01));
+        assertThat(record.getWeight(), is((byte) 0x01));
+        assertThat(record.getMulticastPriority(), is((byte) 0x01));
+        assertThat(record.getMulticastWeight(), is((byte) 0x01));
+        assertThat(record.isLocalLocator(), is(true));
+        assertThat(record.isRlocProbed(), is(false));
+        assertThat(record.isRouted(), is(true));
+    }
+}
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotifyTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotifyTest.java
index 219d6ab..26d8ff0 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotifyTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotifyTest.java
@@ -25,7 +25,7 @@
 /**
  * Unit tests for DefaultLispMapNotify class.
  */
-public class DefaultLispMapNotifyTest {
+public final class DefaultLispMapNotifyTest {
 
     private LispMapNotify notify1;
     private LispMapNotify sameAsNotify1;
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecordTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecordTest.java
index 78af45d..1c85b11 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecordTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRecordTest.java
@@ -25,7 +25,7 @@
 /**
  * Unit tests for DefaultLispMapRecord class.
  */
-public class DefaultLispMapRecordTest {
+public final class DefaultLispMapRecordTest {
 
     private LispMapRecord record1;
     private LispMapRecord sameAsRecord1;
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegisterTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegisterTest.java
index 940345c..1b0a5a4 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegisterTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegisterTest.java
@@ -25,7 +25,7 @@
 /**
  * Unit tests for DefaultLispMapRegister class.
  */
-public class DefaultLispMapRegisterTest {
+public final class DefaultLispMapRegisterTest {
 
     private LispMapRegister register1;
     private LispMapRegister sameAsRegister1;
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReplyTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReplyTest.java
index e078cd9..7b530d2 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReplyTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapReplyTest.java
@@ -25,7 +25,7 @@
 /**
  * Unit tests for DefaultLispMapReply class.
  */
-public class DefaultLispMapReplyTest {
+public final class DefaultLispMapReplyTest {
 
     private LispMapReply reply1;
     private LispMapReply sameAsReply1;
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequestTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequestTest.java
index 13fafc8..155c6a6 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequestTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRequestTest.java
@@ -25,7 +25,7 @@
 /**
  * Unit tests for DefaultLispMapRequest class.
  */
-public class DefaultLispMapRequestTest {
+public final class DefaultLispMapRequestTest {
 
     private LispMapRequest request1;
     private LispMapRequest sameAsRequest1;
diff --git a/utils/misc/src/main/java/org/onlab/util/ByteOperator.java b/utils/misc/src/main/java/org/onlab/util/ByteOperator.java
new file mode 100644
index 0000000..4d30ce7
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/util/ByteOperator.java
@@ -0,0 +1,67 @@
+/*
+ * 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.onlab.util;
+
+/**
+ * Provide a set of byte operations.
+ */
+public final class ByteOperator {
+
+    /**
+     * Private constructor which prevents from external instantiation.
+     */
+    private ByteOperator() {
+
+    }
+
+    /**
+     * Obtains a specific bit value from a byte with given index number.
+     *
+     * @param value byte value
+     * @param index index number
+     * @return a specific bit value from a byte
+     */
+    public static boolean getBit(byte value, int index) {
+        // the length of byte should always be positive whiles less than 8
+        if (index > 7 || index < 0) {
+            return false;
+        }
+
+        int bitMask = getHex((int) Math.pow(2, index));
+        return (value & bitMask) == bitMask;
+    }
+
+    /**
+     * Converts boolean value into bit.
+     *
+     * @param value boolean value
+     * @param bit   bit value
+     * @return converted bit value
+     */
+    public static byte toBit(boolean value, int bit) {
+        return (byte) (value ? bit : 0x00);
+    }
+
+    /**
+     * Convert decimal integer into hex integer.
+     *
+     * @param decimal decimal formatted integer
+     * @return hex formatted integer
+     */
+    private static int getHex(int decimal) {
+        return Integer.valueOf(String.valueOf(decimal), 16);
+    }
+}
diff --git a/utils/misc/src/test/java/org/onlab/util/ByteOperatorTest.java b/utils/misc/src/test/java/org/onlab/util/ByteOperatorTest.java
new file mode 100644
index 0000000..21dffbe
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/util/ByteOperatorTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.onlab.util;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests for ByteOperator.
+ */
+public class ByteOperatorTest {
+
+    @Test
+    public void testGetBit() {
+        byte eight = 0x08;
+        assertThat(ByteOperator.getBit(eight, 0), is(false));
+        assertThat(ByteOperator.getBit(eight, 1), is(false));
+        assertThat(ByteOperator.getBit(eight, 2), is(false));
+        assertThat(ByteOperator.getBit(eight, 3), is(true));
+        assertThat(ByteOperator.getBit(eight, 4), is(false));
+        assertThat(ByteOperator.getBit(eight, 5), is(false));
+        assertThat(ByteOperator.getBit(eight, 6), is(false));
+        assertThat(ByteOperator.getBit(eight, 7), is(false));
+
+        byte one = 0x01;
+        assertThat(ByteOperator.getBit(one, 0), is(true));
+        assertThat(ByteOperator.getBit(one, 1), is(false));
+        assertThat(ByteOperator.getBit(one, 2), is(false));
+        assertThat(ByteOperator.getBit(one, 3), is(false));
+        assertThat(ByteOperator.getBit(one, 4), is(false));
+        assertThat(ByteOperator.getBit(one, 5), is(false));
+        assertThat(ByteOperator.getBit(one, 6), is(false));
+        assertThat(ByteOperator.getBit(one, 7), is(false));
+    }
+}