Merge branch 'master' into dev/murrelet
diff --git a/Dockerfile b/Dockerfile
index bf7f9bf..51b1a58 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,7 +16,7 @@
 # FIXME - dependence on ONOS_ROOT and git at build time is a hack to work around
 # build problems
 WORKDIR /src/onos
-RUN apt-get update && apt-get install -y zip python git && \
+RUN apt-get update && apt-get install -y zip python git bzip2 && \
         export ONOS_ROOT=/src/onos && \
         tools/build/onos-buck build onos && \
         mkdir -p /src/tar && \
diff --git a/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java b/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
index dc93e58..bb909bd 100644
--- a/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
+++ b/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.config;
 
+import java.util.Arrays;
 import java.util.Iterator;
 
 import java.util.LinkedList;
@@ -25,6 +26,8 @@
 import org.onosproject.yang.model.ListKey;
 import org.onosproject.yang.model.NodeKey;
 import org.onosproject.yang.model.ResourceId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.Beta;
 
@@ -43,6 +46,8 @@
 @Beta
 public final class ResourceIdParser {
 
+    private static final Logger log = LoggerFactory.getLogger(ResourceIdParser.class);
+
     /**
      * root node name.
      */
@@ -117,10 +122,14 @@
         return (path + leaf.substring(leaf.indexOf(KEY_SEP)));
     }
 
+    // 1.12.0 - not used by anyone
+    @Deprecated
     public static String appendKeyLeaf(String path, String key) {
         return (path + EL_SEP + key);
     }
 
+    // 1.12.0 - not used by anyone
+    @Deprecated
     public static String appendKeyLeaf(String path, KeyLeaf key) {
         StringBuilder bldr = new StringBuilder();
         bldr.append(key.leafSchema().name());
@@ -161,6 +170,8 @@
         return (path + bldr.toString());
     }
 
+    // 1.12.0 - not used by anyone
+    @Deprecated
     public static String parseNodeKey(NodeKey key) {
         if (key == null) {
             return null;
@@ -269,6 +280,7 @@
         while (itr.hasNext()) {
             String name = itr.next();
             if (name.contains(VAL_SEP)) {
+                // dead branch? VAL_SEP never used in parseResId
                 resBldr.addLeafListBranchPoint(name.substring(0, name.indexOf(NM_SEP)),
                         name.substring(name.indexOf(NM_SEP) + 1, name.indexOf(VAL_SEP)),
                         name.substring(name.indexOf(VAL_SEP) + 1));
@@ -282,7 +294,15 @@
                     if (el.length != 3) {
                         throw new FailedException("Malformed event subject, cannot parse");
                     }
+                    try {
                     resBldr.addKeyLeaf(el[0], el[1], el[2]);
+                    } catch (Exception e) {
+                        log.error("dpath={}", dpath);
+                        log.error("name={}", name);
+                        log.error("key={}", key);
+                        log.error("el={}", Arrays.asList(el));
+                        throw e;
+                    }
                 }
             } else {
                 resBldr.addBranchPointSchema(name.substring(0, name.indexOf(NM_SEP)),
diff --git a/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java b/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java
index 97731a6..1af7b34 100644
--- a/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java
+++ b/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java
@@ -167,7 +167,6 @@
         if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
             addLeaf(path, (LeafNode) node);
         } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
-            path = ResourceIdParser.appendLeafList(path, (LeafListKey) node.key());
             if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
                 throw new FailedException("Requested node already present in the" +
                                                   " store, please use an update method");
@@ -176,7 +175,6 @@
         } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
             traverseInner(path, (InnerNode) node);
         } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
-            path = ResourceIdParser.appendKeyList(path, (ListKey) node.key());
             if (completeVersioned(keystore.get(DocumentPath.from(path))) != null) {
                 throw new FailedException("Requested node already present in the" +
                                                   " store, please use an update method");
diff --git a/apps/config/src/main/java/org/onosproject/d/config/DeviceResourceIds.java b/apps/config/src/main/java/org/onosproject/d/config/DeviceResourceIds.java
index 605ae63..358b400 100644
--- a/apps/config/src/main/java/org/onosproject/d/config/DeviceResourceIds.java
+++ b/apps/config/src/main/java/org/onosproject/d/config/DeviceResourceIds.java
@@ -23,6 +23,7 @@
 import org.onosproject.yang.model.ListKey;
 import org.onosproject.yang.model.NodeKey;
 import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.model.SchemaId;
 
 import com.google.common.annotations.Beta;
 
@@ -38,7 +39,6 @@
     //         +- device (=device root node:ListKey)
 
 
-    // FIXME randomly defined namespace, replace with something appropriate
     /**
      * SchemaId namespace for DCS defined nodes.
      */
@@ -52,22 +52,27 @@
      * SchemaId name for devices node.
      */
     public static final String DEVICES_NAME = "devices";
+    public static final SchemaId DEVICES_SCHEMA = new SchemaId(DEVICES_NAME, DCS_NAMESPACE);
     /**
      * SchemaId name for device node.
      */
     public static final String DEVICE_NAME = "device";
+    public static final SchemaId DEVICE_SCHEMA = new SchemaId(DEVICE_NAME, DCS_NAMESPACE);
     /**
      * KeyLeaf {@code name}, which holds DeviceId information on device node.
      */
     public static final String DEVICE_ID_KL_NAME = "device-id";
 
     /**
-     * ResourceId pointing at root node.
+     * Absolute ResourceId pointing at root node.
+     * @deprecated Use {@link ResourceIds#ROOT_ID} instead
      */
-    public static final ResourceId ROOT_ID = ResourceId.builder()
-            .addBranchPointSchema(ROOT_NAME, DCS_NAMESPACE)
-            .build();
+    @Deprecated
+    public static final ResourceId ROOT_ID = ResourceIds.ROOT_ID;
 
+    /**
+     * Absolute ResourceId pointing at 'devices' node.
+     */
     public static final ResourceId DEVICES_ID = ResourceId.builder()
             .addBranchPointSchema(ROOT_NAME, DCS_NAMESPACE)
             .addBranchPointSchema(DEVICES_NAME, DCS_NAMESPACE)
@@ -80,42 +85,59 @@
     /**
      * nodeKeys index for root node.
      */
+    @Deprecated
     static final int ROOT_INDEX = 0;
     /**
-     * nodeKeys index for devices node.
+     * nodeKeys index relative from root for devices node.
      */
     static final int DEVICES_INDEX = 1;
     /**
-     * nodeKeys index for device node.
+     * nodeKeys index relative from root for device node.
      */
     static final int DEVICE_INDEX = 2;
 
     /**
+     * Converts root relative ResourceId used by DynamicConfigEvent.
+     *
+     * @param rootRelative resource Id
+     * @return absolute ResourceId.
+     */
+    @Beta
+    public static ResourceId toAbsolute(ResourceId rootRelative) {
+        if (ResourceIds.startsWithRootNode(rootRelative)) {
+            return rootRelative;
+        }
+        return ResourceIds.concat(ResourceIds.ROOT_ID, rootRelative);
+    }
+
+    /**
      * Tests if specified path points to root node of a Device.
      *
      * @param path to test.
      * @return true if path points to root node of a Device.
      */
     public static boolean isDeviceRootNode(ResourceId path) {
-        return path.nodeKeys().size() == 3 &&
-               isUnderDeviceRootNode(path);
+        if (ResourceIds.startsWithRootNode(path)) {
+            return path.nodeKeys().size() == 3 &&
+                    isUnderDeviceRootNode(path);
+        } else {
+            return path.nodeKeys().size() == 2 &&
+                    isUnderDeviceRootNode(path);
+        }
     }
 
     /**
-     * Tests if specified path points to root node of a Device.
+     * Tests if specified path points to root node of a Device or it's subtree.
      *
      * @param path to test.
      * @return true if path points to root node of a Device.
      */
     public static boolean isUnderDeviceRootNode(ResourceId path) {
-        return path.nodeKeys().size() >= 3 &&
-                // TODO Would be better to test whole schemeId
-                DEVICE_NAME.equals(path.nodeKeys().get(DEVICE_INDEX).schemaId().name()) &&
-                (path.nodeKeys().get(DEVICE_INDEX) instanceof ListKey) &&
-                // TODO Would be better to test whole schemeId
-                DEVICES_NAME.equals(path.nodeKeys().get(DEVICES_INDEX).schemaId().name()) &&
-                ROOT_NODE.equals(path.nodeKeys().get(ROOT_INDEX));
-    }
+        int rootIdx = ResourceIds.startsWithRootNode(path) ? 0 : -1;
+        return path.nodeKeys().size() >= rootIdx + 3 &&
+                DEVICE_SCHEMA.equals(path.nodeKeys().get(rootIdx + DEVICE_INDEX).schemaId()) &&
+                (path.nodeKeys().get(rootIdx + DEVICE_INDEX) instanceof ListKey) &&
+                DEVICES_SCHEMA.equals(path.nodeKeys().get(rootIdx + DEVICES_INDEX).schemaId());    }
 
     /**
      * Tests if specified path points to root or devices node.
@@ -129,10 +151,9 @@
     }
 
     public static boolean isDevicesNode(ResourceId path) {
-        return path.nodeKeys().size() == 2 &&
-                // TODO Would be better to test whole schemeId
-                DEVICES_NAME.equals(path.nodeKeys().get(DEVICES_INDEX).schemaId().name()) &&
-                ROOT_NODE.equals(path.nodeKeys().get(ROOT_INDEX));
+        int rootIdx = ResourceIds.startsWithRootNode(path) ? 0 : -1;
+        return path.nodeKeys().size() == rootIdx + 2 &&
+                DEVICES_SCHEMA.equals(path.nodeKeys().get(rootIdx + DEVICES_INDEX).schemaId());
     }
 
     public static boolean isRootNode(ResourceId path) {
@@ -151,7 +172,8 @@
         checkArgument(isUnderDeviceRootNode(path), path);
         // FIXME if we decide to drop any of intermediate nodes
         //        "/" - "devices" - "device"
-        return toDeviceId(path.nodeKeys().get(DEVICE_INDEX));
+        int rootIdx = ResourceIds.startsWithRootNode(path) ? 0 : -1;
+        return toDeviceId(path.nodeKeys().get(rootIdx + DEVICE_INDEX));
     }
 
     /**
@@ -162,8 +184,7 @@
      * @throws IllegalArgumentException if not a device node
      */
     public static DeviceId toDeviceId(NodeKey<?> deviceRoot) {
-        // TODO Would be better to test whole schemeId
-        if (!DEVICE_NAME.equals(deviceRoot.schemaId().name())) {
+        if (!DEVICE_SCHEMA.equals(deviceRoot.schemaId())) {
             throw new IllegalArgumentException(deviceRoot + " is not a device node");
         }
 
@@ -189,7 +210,7 @@
      * Transforms DeviceId into a ResourceId pointing to device root node.
      *
      * @param deviceId to transform
-     * @return ResourceId
+     * @return absolute ResourceId
      */
     public static ResourceId toResourceId(DeviceId deviceId) {
         return ResourceId.builder()
diff --git a/apps/config/src/main/java/org/onosproject/d/config/DynamicDeviceConfigServiceView.java b/apps/config/src/main/java/org/onosproject/d/config/DynamicDeviceConfigServiceView.java
index 1ec6929..c3f3e7b 100644
--- a/apps/config/src/main/java/org/onosproject/d/config/DynamicDeviceConfigServiceView.java
+++ b/apps/config/src/main/java/org/onosproject/d/config/DynamicDeviceConfigServiceView.java
@@ -17,6 +17,7 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.d.config.ResourceIds.ROOT_ID;
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.util.Collections;
@@ -51,6 +52,7 @@
 
     private final DeviceId deviceId;
 
+    // absolute ResourceId
     private ResourceId deviceRoot;
 
     /**
@@ -136,10 +138,16 @@
     }
 
     private ResourceId toDeviceRelativeId(ResourceId path) {
-        checkArgument(path.nodeKeys().contains(DeviceResourceIds.ROOT_NODE),
-                      "%s was not absolute path", path);
-
-        return ResourceIds.relativize(deviceRoot, path);
+        // case: absolute
+        if (ResourceIds.startsWithRootNode(path)) {
+            return ResourceIds.relativize(deviceRoot, path);
+        }
+        // case: root relative
+        if (DeviceResourceIds.isUnderDeviceRootNode(path)) {
+            //                                        TODO not efficient
+            return ResourceIds.relativize(deviceRoot, ResourceIds.concat(ROOT_ID, path));
+        }
+        throw new IllegalArgumentException(path + " was not absolute device path");
     }
 
     class DynamicDeviceConfigListener implements DynamicConfigListener {
diff --git a/apps/config/src/main/java/org/onosproject/d/config/ResourceIds.java b/apps/config/src/main/java/org/onosproject/d/config/ResourceIds.java
index fc875a9..a08c04a 100644
--- a/apps/config/src/main/java/org/onosproject/d/config/ResourceIds.java
+++ b/apps/config/src/main/java/org/onosproject/d/config/ResourceIds.java
@@ -18,10 +18,14 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.slf4j.LoggerFactory.getLogger;
 
+import java.util.Iterator;
+import java.util.Objects;
+
 import org.onosproject.yang.model.DataNode;
 import org.onosproject.yang.model.KeyLeaf;
 import org.onosproject.yang.model.LeafListKey;
 import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
 import org.onosproject.yang.model.ResourceId;
 import org.onosproject.yang.model.SchemaId;
 import org.slf4j.Logger;
@@ -37,6 +41,14 @@
     private static final Logger log = getLogger(ResourceIds.class);
 
     /**
+     * Absolute ResourceId pointing at root node.
+     */
+    public static final ResourceId ROOT_ID = ResourceId.builder()
+            .addBranchPointSchema(DeviceResourceIds.ROOT_NAME,
+                                  DeviceResourceIds.DCS_NAMESPACE)
+            .build();
+
+    /**
      * Builds the ResourceId of specified {@code node}.
      *
      * @param parent ResourceId of {@code node} parent
@@ -113,8 +125,20 @@
     public static ResourceId relativize(ResourceId base, ResourceId child) {
         checkArgument(child.nodeKeys().size() >= base.nodeKeys().size(),
                       "%s path must be deeper than base prefix %s", child, base);
-        checkArgument(base.nodeKeys().equals(child.nodeKeys().subList(0, base.nodeKeys().size())),
-                      "%s is not a prefix of %s", child, base);
+        @SuppressWarnings("rawtypes")
+        Iterator<NodeKey> bIt = base.nodeKeys().iterator();
+        @SuppressWarnings("rawtypes")
+        Iterator<NodeKey> cIt = child.nodeKeys().iterator();
+        while (bIt.hasNext()) {
+            NodeKey<?> b = bIt.next();
+            NodeKey<?> c = cIt.next();
+
+            checkArgument(Objects.equals(b, c),
+                          "%s is not a prefix of %s.\n" +
+                          "b:%s != c:%s",
+                          base, child,
+                          b, c);
+        }
 
         return ResourceId.builder().append(child.nodeKeys().subList(base.nodeKeys().size(),
                                                                     child.nodeKeys().size())).build();
@@ -133,4 +157,9 @@
                prefix.nodeKeys().equals(child.nodeKeys().subList(0, prefix.nodeKeys().size()));
     }
 
+    public static boolean startsWithRootNode(ResourceId path) {
+        return !path.nodeKeys().isEmpty() &&
+                DeviceResourceIds.ROOT_NAME.equals(path.nodeKeys().get(0).schemaId().name());
+    }
+
 }
diff --git a/apps/config/src/test/java/org/onosproject/d/config/DeviceResourceIdsTest.java b/apps/config/src/test/java/org/onosproject/d/config/DeviceResourceIdsTest.java
index 83baf5a..5a497d6 100644
--- a/apps/config/src/test/java/org/onosproject/d/config/DeviceResourceIdsTest.java
+++ b/apps/config/src/test/java/org/onosproject/d/config/DeviceResourceIdsTest.java
@@ -15,19 +15,29 @@
  */
 package org.onosproject.d.config;
 
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.*;
 import static org.onosproject.d.config.DeviceResourceIds.DCS_NAMESPACE;
 import static org.onosproject.d.config.DeviceResourceIds.DEVICES_NAME;
+import static org.onosproject.d.config.DeviceResourceIds.DEVICE_ID_KL_NAME;
+import static org.onosproject.d.config.DeviceResourceIds.DEVICE_NAME;
 import static org.onosproject.d.config.DeviceResourceIds.ROOT_NAME;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.onosproject.net.DeviceId;
+import org.onosproject.yang.model.KeyLeaf;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
 import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.model.SchemaId;
 
 public class DeviceResourceIdsTest {
 
-    static final DeviceId DID_A = DeviceId.deviceId("test:A");
+    static final DeviceId DID_A = DeviceId.deviceId("test:a");
 
     static final ResourceId DEVICES = ResourceId.builder()
             .addBranchPointSchema(ROOT_NAME, DCS_NAMESPACE)
@@ -52,6 +62,12 @@
                     .build();
 
         assertEquals(DID_A, DeviceResourceIds.toDeviceId(ridAchild));
+
+        NodeKey<?> nodeKey = ridA.nodeKeys().get(2);
+        assertThat(nodeKey, is(instanceOf(ListKey.class)));
+        assertThat(nodeKey.schemaId(), is(equalTo(new SchemaId(DEVICE_NAME, DCS_NAMESPACE))));
+        ListKey listKey = (ListKey) nodeKey;
+        assertThat(listKey.keyLeafs(), is(contains(new KeyLeaf(DEVICE_ID_KL_NAME, DCS_NAMESPACE, DID_A.toString()))));
     }
 
     @Test
@@ -61,4 +77,36 @@
         assertFalse(DeviceResourceIds.isRootOrDevicesNode(ridA));
     }
 
+    @Test
+    public void testDeviceSubtreeTest() {
+        ResourceId absDevice = ResourceId.builder()
+                    .addBranchPointSchema(ROOT_NAME, DCS_NAMESPACE)
+                    .addBranchPointSchema(DEVICES_NAME, DCS_NAMESPACE)
+                    .addBranchPointSchema(DEVICE_NAME, DCS_NAMESPACE)
+                    .addKeyLeaf(DEVICE_ID_KL_NAME, DCS_NAMESPACE, DID_A.toString())
+                    .build();
+
+        NodeKey<?> deviceKey = absDevice.nodeKeys().get(2);
+        assertThat(deviceKey, is(instanceOf(ListKey.class)));
+        assertThat(deviceKey.schemaId().namespace(), is(equalTo(DCS_NAMESPACE)));
+        assertThat(deviceKey.schemaId().name(), is(equalTo(DEVICE_NAME)));
+        assertTrue(DeviceResourceIds.isUnderDeviceRootNode(absDevice));
+    }
+
+    @Test
+    public void testDeviceSubtreeEventTest() {
+        // root relative ResourceId used by DynamicConfigEvent
+        ResourceId evtDevice = ResourceId.builder()
+                    .addBranchPointSchema(DEVICES_NAME, DCS_NAMESPACE)
+                    .addBranchPointSchema(DEVICE_NAME, DCS_NAMESPACE)
+                    .addKeyLeaf(DEVICE_ID_KL_NAME, DCS_NAMESPACE, DID_A.toString())
+                    .build();
+
+        NodeKey<?> deviceKey = evtDevice.nodeKeys().get(1);
+        assertThat(deviceKey, is(instanceOf(ListKey.class)));
+        assertThat(deviceKey.schemaId().namespace(), is(equalTo(DCS_NAMESPACE)));
+        assertThat(deviceKey.schemaId().name(), is(equalTo(DEVICE_NAME)));
+        assertTrue(DeviceResourceIds.isUnderDeviceRootNode(evtDevice));
+    }
+
 }
diff --git a/apps/config/src/test/java/org/onosproject/d/config/ResourceIdsTest.java b/apps/config/src/test/java/org/onosproject/d/config/ResourceIdsTest.java
index 73f682c..b1c237b 100644
--- a/apps/config/src/test/java/org/onosproject/d/config/ResourceIdsTest.java
+++ b/apps/config/src/test/java/org/onosproject/d/config/ResourceIdsTest.java
@@ -35,12 +35,12 @@
                                   DCS_NAMESPACE)
             .build();
 
-        assertEquals(DEVICES, ResourceIds.concat(DeviceResourceIds.ROOT_ID, devices));
+        assertEquals(DEVICES, ResourceIds.concat(ResourceIds.ROOT_ID, devices));
     }
 
     @Test
     public void testRelativize() {
-        ResourceId relDevices = ResourceIds.relativize(DeviceResourceIds.ROOT_ID, DEVICES);
+        ResourceId relDevices = ResourceIds.relativize(ResourceIds.ROOT_ID, DEVICES);
         assertEquals(DeviceResourceIds.DEVICES_NAME,
                      relDevices.nodeKeys().get(0).schemaId().name());
         assertEquals(DCS_NAMESPACE,
diff --git a/apps/configsync/src/main/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizer.java b/apps/configsync/src/main/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizer.java
index e0067d6..f9fdfb7 100644
--- a/apps/configsync/src/main/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizer.java
+++ b/apps/configsync/src/main/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizer.java
@@ -169,8 +169,9 @@
             DeviceId deviceId = DeviceResourceIds.toDeviceId(path);
             ResourceId deviceRootPath = DeviceResourceIds.toResourceId(deviceId);
 
-            ResourceId relPath = ResourceIds.relativize(deviceRootPath, path);
-            // FIXME figure out how to express give me everything Filter
+            ResourceId absPath = ResourceIds.concat(ResourceIds.ROOT_ID, path);
+            ResourceId relPath = ResourceIds.relativize(deviceRootPath, absPath);
+            // give me everything Filter
             Filter giveMeEverything = Filter.builder().build();
 
             DataNode node = dynConfigService.readNode(path, giveMeEverything);
diff --git a/apps/configsync/src/test/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizerTest.java b/apps/configsync/src/test/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizerTest.java
index 78812fb..bfdead6 100644
--- a/apps/configsync/src/test/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizerTest.java
+++ b/apps/configsync/src/test/java/org/onosproject/d/config/sync/impl/DynamicDeviceConfigSynchronizerTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.d.config.sync.impl;
 
 import static org.junit.Assert.*;
+import static org.onosproject.d.config.ResourceIds.ROOT_ID;
 
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
@@ -61,6 +62,9 @@
 
     CountDownLatch providerCalled = new CountDownLatch(1);
 
+    /**
+     * DynamicConfigService.readNode(ResourceId, Filter) stub.
+     */
     BiFunction<ResourceId, Filter, DataNode> onDcsRead;
 
     BiFunction<DeviceId, SetRequest, CompletableFuture<SetResponse>> onSetConfiguration;
@@ -89,12 +93,13 @@
         ResourceId devicePath = DeviceResourceIds.toResourceId(DID);
         ResourceId cfgPath = REL_INTERFACES;
         ResourceId absPath = ResourceIds.concat(devicePath, cfgPath);
-        DynamicConfigEvent event = new DynamicConfigEvent(DynamicConfigEvent.Type.NODE_REPLACED, absPath);
+        ResourceId evtPath = ResourceIds.relativize(ROOT_ID, absPath);
+        DynamicConfigEvent event = new DynamicConfigEvent(DynamicConfigEvent.Type.NODE_REPLACED, evtPath);
 
         // assertions
         onDcsRead = (path, filter) -> {
             assertTrue(filter.isEmptyFilter());
-            assertEquals("DCS get access by absolute RID", absPath, path);
+            assertEquals("DCService get access by root relative RID", evtPath, path);
             return deviceConfigNode();
         };
 
diff --git a/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java b/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
index 3ec104a..103c9d3 100644
--- a/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
+++ b/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
@@ -564,7 +564,7 @@
 
             ARP arpPacket = (ARP) packet.getPayload();
 
-            ARP arpReply = (ARP) arpPacket.clone();
+            ARP arpReply = arpPacket.duplicate();
             arpReply.setOpCode(ARP.OP_REPLY);
 
             arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
index b9cbd5b..d903cd4 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
@@ -479,7 +479,7 @@
     private Ethernet processDhcpPacketFromClient(PacketContext context,
                                                  Ethernet ethernetPacket) {
         // get dhcp header.
-        Ethernet etherReply = (Ethernet) ethernetPacket.clone();
+        Ethernet etherReply = ethernetPacket.duplicate();
         IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
         UDP udpPacket = (UDP) ipv4Packet.getPayload();
         DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
@@ -577,6 +577,9 @@
             }
         }
 
+        // Remove broadcast flag
+        dhcpPacket.setFlags((short) 0);
+
         udpPacket.setPayload(dhcpPacket);
         // As a DHCP relay, the source port should be server port( instead
         // of client port.
@@ -663,7 +666,7 @@
      */
     private Ethernet processDhcpPacketFromServer(Ethernet ethernetPacket) {
         // get dhcp header.
-        Ethernet etherReply = (Ethernet) ethernetPacket.clone();
+        Ethernet etherReply = ethernetPacket.duplicate();
         IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
         UDP udpPacket = (UDP) ipv4Packet.getPayload();
         DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
@@ -769,7 +772,7 @@
      * @return Ethernet packet processed
      */
     private Ethernet removeRelayAgentOption(Ethernet ethPacket) {
-        Ethernet ethernet = (Ethernet) ethPacket.clone();
+        Ethernet ethernet = ethPacket.duplicate();
         IPv4 ipv4 = (IPv4) ethernet.getPayload();
         UDP udp = (UDP) ipv4.getPayload();
         DHCP dhcpPayload = (DHCP) udp.getPayload();
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
index d5afdb7..a934ad8 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -785,7 +785,7 @@
 
         boolean directConnFlag = directlyConnected(clientDhcp6);
 
-        Ethernet etherReply = (Ethernet) clientPacket.clone();
+        Ethernet etherReply = clientPacket.duplicate();
         etherReply.setSourceMACAddress(relayAgentMac);
 
         if (directConnFlag && this.dhcpConnectMac == null) {
@@ -924,7 +924,7 @@
             return null;
         }
         // get dhcp6 header.
-        Ethernet etherReply = (Ethernet) receivedPacket.clone();
+        Ethernet etherReply = receivedPacket.duplicate();
         IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
         UDP udpPacket = (UDP) ipv6Packet.getPayload();
         DHCP6 dhcp6Relay = (DHCP6) udpPacket.getPayload();
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
index 30c9c16..2e6ce09 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -583,7 +583,7 @@
          */
         private void processArpPacket(PacketContext context, Ethernet packet, MacAddress replyMac) {
             ARP arpPacket = (ARP) packet.getPayload();
-            ARP arpReply = (ARP) arpPacket.clone();
+            ARP arpReply = arpPacket.duplicate();
             arpReply.setOpCode(ARP.OP_REPLY);
 
             arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DistributedDhcpRelayStore.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DistributedDhcpRelayStore.java
index 1e87ba6..38c0580 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DistributedDhcpRelayStore.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DistributedDhcpRelayStore.java
@@ -66,7 +66,13 @@
     protected void activated() {
         dhcpRecords = storageService.<HostId, DhcpRecord>eventuallyConsistentMapBuilder()
                 .withName("DHCP-Relay-Records")
-                .withTimestampProvider((hostId, record) -> new WallClockTimestamp(record.lastSeen()))
+                .withTimestampProvider((hostId, record) -> {
+                    if (record != null) {
+                        return new WallClockTimestamp(record.lastSeen());
+                    } else {
+                        return new WallClockTimestamp();
+                    }
+                })
                 .withSerializer(APP_KRYO)
                 .build();
         listener = new InternalMapListener();
diff --git a/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java b/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java
index 8ed55c6..09b8533 100644
--- a/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java
+++ b/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java
@@ -22,8 +22,8 @@
 import org.apache.felix.scr.annotations.Modified;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.ICMP;
 import org.onlab.packet.ICMP6;
@@ -73,20 +73,24 @@
 import org.onosproject.net.topology.TopologyEvent;
 import org.onosproject.net.topology.TopologyListener;
 import org.onosproject.net.topology.TopologyService;
-import org.onosproject.store.service.StorageService;
-import org.osgi.service.component.ComponentContext;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.EventuallyConsistentMap;
-import org.onosproject.store.service.WallClockTimestamp;
 import org.onosproject.store.service.MultiValuedTimestamp;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
+import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
+
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
 
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -198,6 +202,8 @@
 
     private final TopologyListener topologyListener = new InternalTopologyListener();
 
+    private ExecutorService blackHoleExecutor;
+
 
     @Activate
     public void activate(ComponentContext context) {
@@ -212,6 +218,10 @@
                         MultiValuedTimestamp<>(new WallClockTimestamp(), System.nanoTime()))
                 .build();
 
+        blackHoleExecutor = newSingleThreadExecutor(groupedThreads("onos/app/fwd",
+                                                                   "black-hole-fixer",
+                                                                   log));
+
         cfgService.registerProperties(getClass());
         appId = coreService.registerApplication("org.onosproject.fwd");
 
@@ -230,6 +240,8 @@
         flowRuleService.removeFlowRulesById(appId);
         packetService.removeProcessor(processor);
         topologyService.removeListener(topologyListener);
+        blackHoleExecutor.shutdown();
+        blackHoleExecutor = null;
         processor = null;
         log.info("Stopped");
     }
@@ -719,8 +731,8 @@
                 reasons.forEach(re -> {
                     if (re instanceof LinkEvent) {
                         LinkEvent le = (LinkEvent) re;
-                        if (le.type() == LinkEvent.Type.LINK_REMOVED) {
-                            fixBlackhole(le.subject().src());
+                        if (le.type() == LinkEvent.Type.LINK_REMOVED && blackHoleExecutor != null) {
+                            blackHoleExecutor.submit(() -> fixBlackhole(le.subject().src()));
                         }
                     }
                 });
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
index bfb0701..217a981 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
@@ -192,7 +192,7 @@
                 TpPort.tpPort(patPort),
                 externalGatewayIp);
 
-        packetOut((Ethernet) eth.clone(),
+        packetOut(eth.duplicate(),
                 packetIn.receivedFrom().deviceId(),
                 patPort,
                 externalGatewayIp);
diff --git a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
index c783236..4c9e5f3 100644
--- a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
+++ b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.BiMap;
 import com.google.common.collect.ImmutableBiMap;
 import com.google.common.collect.ImmutableList;
+import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Ethernet;
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.net.ConnectPoint;
@@ -179,9 +180,12 @@
     public InboundPacket mapInboundPacket(DeviceId deviceId, PiPacketOperation packetIn)
             throws PiInterpreterException {
         // We assume that the packet is ethernet, which is fine since default.p4 can deparse only ethernet packets.
-        Ethernet ethPkt = new Ethernet();
-
-        ethPkt.deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
+        Ethernet ethPkt;
+        try {
+            ethPkt = Ethernet.deserializer().deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
+        } catch (DeserializationException dex) {
+            throw new PiInterpreterException(dex.getMessage());
+        }
 
         // Returns the ingress port packet metadata.
         Optional<PiPacketMetadata> packetMetadata = packetIn.metadatas().stream()
diff --git a/bucklets/node.bucklet b/bucklets/node.bucklet
index 3239e46..c5cc14a 100644
--- a/bucklets/node.bucklet
+++ b/bucklets/node.bucklet
@@ -25,7 +25,7 @@
 
     genrule(
         name = 'node-bin-' + version,
-        bash = 'tar -xf $(location :node-release-' + version + ') && ' +
+        bash = 'tar --no-same-owner -xf $(location :node-release-' + version + ') && ' +
                'mv ' + file_name + ' $OUT && ' +
                'chmod +x $OUT',
         out = 'node-binaries',
diff --git a/cli/src/main/java/org/onosproject/cli/net/GroupTypeCompleter.java b/cli/src/main/java/org/onosproject/cli/net/GroupTypeCompleter.java
new file mode 100644
index 0000000..5eb567a
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/GroupTypeCompleter.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cli.net;
+
+import com.google.common.collect.Lists;
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.net.group.Group;
+
+import java.util.List;
+
+/**
+ * Group status completer.
+ */
+public class GroupTypeCompleter extends AbstractChoicesCompleter {
+    @Override
+    protected List<String> choices() {
+        List<String> strings = Lists.newArrayList();
+        for (Group.Type groupType : Group.Type.values()) {
+            strings.add(groupType.toString().toLowerCase());
+        }
+        strings.add(GroupsListCommand.ANY);
+        return strings;
+    }
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java
index 2fc5461..4a58061 100644
--- a/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java
@@ -52,7 +52,7 @@
     private static final String FORMAT =
             "   id=0x%s, state=%s, type=%s, bytes=%s, packets=%s, appId=%s, referenceCount=%s";
     private static final String BUCKET_FORMAT =
-            "   id=0x%s, bucket=%s, bytes=%s, packets=%s, actions=%s";
+            "       id=0x%s, bucket=%s, bytes=%s, packets=%s, actions=%s";
 
     @Argument(index = 1, name = "uri", description = "Device ID",
             required = false, multiValued = false)
@@ -133,7 +133,7 @@
             groups.sort(Comparators.GROUP_COMPARATOR);
             sortedGroups.put(d, groups);
         }
-        if (type != null) {
+        if (type != null && !"any".equals(type))  {
             for (Device device : sortedGroups.keySet()) {
                 sortedGroups.put(device, sortedGroups.get(device).stream()
                         .filter(group -> GroupDescription.Type.valueOf(type.toUpperCase()).equals(group.type()))
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 27e2b4f..1ffeed4 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -513,8 +513,10 @@
             <completers>
                 <ref component-id="groupStatusCompleter"/>
                 <ref component-id="deviceIdCompleter"/>
-                <null/>
             </completers>
+            <optional-completers>
+                <entry key="-t" value-ref="groupTypeCompleter"/>
+            </optional-completers>
         </command>
 
         <command>
@@ -929,6 +931,7 @@
     <bean id="intentIdCompleter" class="org.onosproject.cli.net.completer.IntentIdCompleter"/>
     <bean id="flowRuleStatusCompleter" class="org.onosproject.cli.net.FlowRuleStatusCompleter"/>
     <bean id="groupStatusCompleter" class="org.onosproject.cli.net.GroupStatusCompleter" />
+    <bean id="groupTypeCompleter" class="org.onosproject.cli.net.GroupTypeCompleter" />
     <bean id="connectPointCompleter" class="org.onosproject.cli.net.ConnectPointCompleter"/>
     <bean id="nullCompleter" class="org.apache.karaf.shell.console.completer.NullCompleter"/>
     <bean id="ethTypeCompleter" class="org.onosproject.cli.net.EthTypeCompleter"/>
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/PiInstruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/PiInstruction.java
index 5109a92..5db8a84 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/PiInstruction.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/PiInstruction.java
@@ -21,6 +21,8 @@
 import com.google.common.base.Objects;
 import org.onosproject.net.pi.runtime.PiTableAction;
 
+import static java.lang.String.format;
+
 /**
  * Representation of a protocol-independent instruction.
  */
@@ -71,6 +73,13 @@
 
     @Override
     public String toString() {
-        return tableAction.toString();
+        switch (tableAction.type()) {
+            case ACTION_GROUP_ID:
+            case GROUP_MEMBER_ID:
+                // e.g. PiActionGroupId(1)
+                return format("%s{%s}", tableAction.getClass().getSimpleName(), tableAction.toString());
+            default:
+                return tableAction.toString();
+        }
     }
 }
diff --git a/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java b/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java
index cbcf1b4..58c26c4 100644
--- a/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java
+++ b/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java
@@ -176,22 +176,21 @@
         @Override
         public void run() {
             stopped = false;
-            log.info("Dispatch loop initiated");
+            log.info("Dispatch loop({}) initiated", name);
             while (!stopped) {
                 try {
                     // Fetch the next event and if it is the kill-pill, bail
                     Event event = eventsQueue.take();
-                    if (event == KILL_PILL) {
-                        break;
+                    if (event != KILL_PILL) {
+                        process(event);
                     }
-                    process(event);
                 } catch (InterruptedException e) {
                     log.warn("Dispatch loop interrupted");
                 } catch (Exception | Error e) {
                     log.warn("Error encountered while dispatching event:", e);
                 }
             }
-            log.info("Dispatch loop terminated");
+            log.info("Dispatch loop({}) terminated", name);
         }
 
         // Locate the sink for the event class and use it to process the event
@@ -211,7 +210,6 @@
 
         void stop() {
             stopped = true;
-            stopWatchdog();
             add(KILL_PILL);
         }
 
diff --git a/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java b/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java
index ed78212..cdbd35c 100644
--- a/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java
+++ b/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java
@@ -65,7 +65,7 @@
 
     @Override
     public void forward(NeighbourMessageContext context, Interface outIntf) {
-        Ethernet packetOut = (Ethernet) context.packet().clone();
+        Ethernet packetOut = context.packet().duplicate();
         if (outIntf.vlan().equals(VlanId.NONE)) {
             // The egress interface has no VLAN Id. Send out an untagged
             // packet
diff --git a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
index ec783f0..bace763 100644
--- a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
+++ b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
@@ -117,7 +117,7 @@
 
     private final List<ProcessorEntry> processors = Lists.newCopyOnWriteArrayList();
 
-    private final  PacketDriverProvider defaultProvider = new PacketDriverProvider();
+    private final PacketDriverProvider defaultProvider = new PacketDriverProvider();
 
     private ApplicationId appId;
     private NodeId localNodeId;
@@ -441,6 +441,13 @@
      * Internal listener for device service events.
      */
     private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public boolean isRelevant(DeviceEvent event) {
+            return event.type() == DeviceEvent.Type.DEVICE_ADDED ||
+                    event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
+        }
+
         @Override
         public void event(DeviceEvent event) {
             eventHandlingExecutor.execute(() -> {
@@ -456,14 +463,7 @@
                     if (!deviceService.isAvailable(event.subject().id())) {
                         return;
                     }
-                    switch (event.type()) {
-                        case DEVICE_ADDED:
-                        case DEVICE_AVAILABILITY_CHANGED:
-                            pushRulesToDevice(device);
-                            break;
-                        default:
-                            break;
-                    }
+                    pushRulesToDevice(device);
                 } catch (Exception e) {
                     log.warn("Failed to process {}", event, e);
                 }
diff --git a/core/net/src/test/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActionsTest.java b/core/net/src/test/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActionsTest.java
index 52b5227..40e49af 100644
--- a/core/net/src/test/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActionsTest.java
+++ b/core/net/src/test/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActionsTest.java
@@ -113,7 +113,7 @@
     public void forwardToInterface() {
         Ethernet request = NeighbourTestUtils.createArpRequest(IP1);
 
-        Ethernet forwardedRequest = (Ethernet) request.clone();
+        Ethernet forwardedRequest = request.duplicate();
         forwardedRequest.setSourceMACAddress(INTF2.mac());
         forwardedRequest.setVlanID(INTF2.vlan().toShort());
 
diff --git a/core/store/dist/src/main/java/org/onosproject/store/app/DistributedApplicationStore.java b/core/store/dist/src/main/java/org/onosproject/store/app/DistributedApplicationStore.java
index c65d1aa..c0b124c 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/app/DistributedApplicationStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/app/DistributedApplicationStore.java
@@ -67,7 +67,6 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -78,6 +77,7 @@
 import static com.google.common.collect.Multimaps.newSetMultimap;
 import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
 import static com.google.common.io.ByteStreams.toByteArray;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static org.onlab.util.Tools.groupedThreads;
@@ -95,9 +95,6 @@
 public class DistributedApplicationStore extends ApplicationArchive
         implements ApplicationStore {
 
-    // FIXME: eliminate the need for this
-    private static final int FIXME_ACTIVATION_DELAY = 500;
-
     private final Logger log = getLogger(getClass());
 
     private static final MessageSubject APP_BITS_REQUEST = new MessageSubject("app-bits-request");
@@ -116,7 +113,7 @@
     }
 
     private ScheduledExecutorService executor;
-    private ExecutorService messageHandlingExecutor;
+    private ExecutorService messageHandlingExecutor, activationExecutor;
 
     private ConsistentMap<ApplicationId, InternalApplicationHolder> apps;
     private Topic<Application> appActivationTopic;
@@ -148,12 +145,13 @@
 
     @Activate
     public void activate() {
-        messageHandlingExecutor = Executors.newSingleThreadExecutor(
-                groupedThreads("onos/store/app", "message-handler", log));
+        messageHandlingExecutor = newSingleThreadExecutor(groupedThreads("onos/store/app",
+                                                                         "message-handler", log));
         clusterCommunicator.addSubscriber(APP_BITS_REQUEST,
                                           bytes -> new String(bytes, Charsets.UTF_8),
                                           name -> {
                                               try {
+                                                  log.info("Sending bits for application {}", name);
                                                   return toByteArray(getApplicationInputStream(name));
                                               } catch (IOException e) {
                                                   throw new StorageException(e);
@@ -173,7 +171,9 @@
         appActivationTopic = storageService.getTopic("onos-apps-activation-topic",
                                                      Serializer.using(KryoNamespaces.API));
 
-        appActivationTopic.subscribe(appActivator, messageHandlingExecutor);
+        activationExecutor = newSingleThreadExecutor(groupedThreads("onos/store/app",
+                                                                    "app-activation", log));
+        appActivationTopic.subscribe(appActivator, activationExecutor);
 
         executor = newSingleThreadScheduledExecutor(groupedThreads("onos/app", "store", log));
         statusChangeListener = status -> {
@@ -181,7 +181,7 @@
                 executor.execute(this::bootstrapExistingApplications);
             }
         };
-        apps.addListener(appsListener, messageHandlingExecutor);
+        apps.addListener(appsListener, activationExecutor);
         apps.addStatusChangeListener(statusChangeListener);
         coreAppId = getId(CoreService.CORE_APP_NAME);
         log.info("Started");
@@ -257,6 +257,7 @@
         apps.removeListener(appsListener);
         appActivationTopic.unsubscribe(appActivator);
         messageHandlingExecutor.shutdown();
+        activationExecutor.shutdown();
         executor.shutdown();
         log.info("Stopped");
     }
@@ -508,7 +509,7 @@
      */
     private void fetchBitsIfNeeded(Application app) {
         if (!appBitsAvailable(app)) {
-            fetchBits(app);
+            fetchBits(app, false);
         }
     }
 
@@ -517,15 +518,14 @@
      */
     private void installAppIfNeeded(Application app) {
         if (!appBitsAvailable(app)) {
-            fetchBits(app);
-            notifyDelegate(new ApplicationEvent(APP_INSTALLED, app));
+            fetchBits(app, true);
         }
     }
 
     /**
      * Fetches the bits from the cluster peers.
      */
-    private void fetchBits(Application app) {
+    private void fetchBits(Application app, boolean delegateInstallation) {
         ControllerNode localNode = clusterService.getLocalNode();
         CountDownLatch latch = new CountDownLatch(1);
 
@@ -550,6 +550,9 @@
                             log.info("Downloaded bits for application {} from node {}",
                                      app.id().name(), node.id());
                             latch.countDown();
+                            if (delegateInstallation) {
+                                notifyDelegate(new ApplicationEvent(APP_INSTALLED, app));
+                            }
                         } else if (error != null) {
                             log.warn("Unable to fetch bits for application {} from node {}",
                                      app.id().name(), node.id());
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
index c0c6639..b18081c 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
@@ -1098,7 +1098,14 @@
             if (buildIpv6Selector(filteredSelector, fwd) < 0) {
                 return Collections.emptyList();
             }
-            forTableId = UNICAST_ROUTING_TABLE;
+            //We need to set the proper next table
+            IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
+            if (ipv6Dst.isMulticast()) {
+                forTableId = MULTICAST_ROUTING_TABLE;
+            } else {
+                forTableId = UNICAST_ROUTING_TABLE;
+            }
+
             if (fwd.treatment() != null) {
                 for (Instruction instr : fwd.treatment().allInstructions()) {
                     if (instr instanceof L3ModificationInstruction &&
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
index 75cf081..2f45bae 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableBiMap;
 import com.google.common.collect.ImmutableList;
+import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Ethernet;
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.net.ConnectPoint;
@@ -267,9 +268,12 @@
         }
 
         // Assuming that the packet is ethernet, which is fine since default.p4 can deparse only ethernet packets.
-        Ethernet ethPkt = new Ethernet();
-
-        ethPkt.deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
+        Ethernet ethPkt;
+        try {
+            ethPkt = Ethernet.deserializer().deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
+        } catch (DeserializationException dex) {
+            throw new PiInterpreterException(dex.getMessage());
+        }
 
         // Returns the ingress port packet metadata.
         Optional<PiPacketMetadata> packetMetadata = packetIn.metadatas()
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
index 081e0f1..b2b3760 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4PortStatisticsDiscovery.java
@@ -46,16 +46,29 @@
     // With P4_14, counter names in the generated P4Info won't have any scope.
     // A solution could be that of dynamically building counter IDs based on the P4Info (as in DefaultP4Interpreter).
     private static final String DEFAULT_SCOPE = "port_counters_control";
-    private static final String INGRESS_COUNTER = "ingress_port_counter";
-    private static final String EGRESS_COUNTER = "egress_port_counter";
+    private static final PiCounterId DEFAULT_INGRESS_COUNTER_ID = PiCounterId.of(DEFAULT_SCOPE,
+                                                                                 "ingress_port_counter",
+                                                                                 INDIRECT);
+    private static final PiCounterId DEFAULT_EGRESS_COUNTER_ID = PiCounterId.of(DEFAULT_SCOPE,
+                                                                                "egress_port_counter",
+                                                                                INDIRECT);
 
     /**
-     * Returns the scope string to be used for the counter IDs.
+     * Returns the ID of the ingress port counter.
      *
-     * @return scope string
+     * @return counter ID
      */
-    public String scope() {
-        return DEFAULT_SCOPE;
+    public PiCounterId ingressCounterId() {
+        return DEFAULT_INGRESS_COUNTER_ID;
+    }
+
+    /**
+     * Returns the ID of the egress port counter.
+     *
+     * @return counter ID
+     */
+    public PiCounterId egressCounterId() {
+        return DEFAULT_EGRESS_COUNTER_ID;
     }
 
     @Override
@@ -65,9 +78,6 @@
             return Collections.emptyList();
         }
 
-        final PiCounterId ingressCounterId = PiCounterId.of(scope(), INGRESS_COUNTER, INDIRECT);
-        final PiCounterId egressCounterId = PiCounterId.of(scope(), EGRESS_COUNTER, INDIRECT);
-
         Map<Long, DefaultPortStatistics.Builder> portStatBuilders = Maps.newHashMap();
 
         deviceService.getPorts(deviceId)
@@ -79,8 +89,8 @@
         Set<PiCounterCellId> counterCellIds = Sets.newHashSet();
         portStatBuilders.keySet().forEach(p -> {
             // Counter cell/index = port number.
-            counterCellIds.add(PiIndirectCounterCellId.of(ingressCounterId, p));
-            counterCellIds.add(PiIndirectCounterCellId.of(egressCounterId, p));
+            counterCellIds.add(PiIndirectCounterCellId.of(ingressCounterId(), p));
+            counterCellIds.add(PiIndirectCounterCellId.of(egressCounterId(), p));
         });
 
         Collection<PiCounterCellData> counterEntryResponse;
@@ -103,10 +113,10 @@
                 return;
             }
             DefaultPortStatistics.Builder statsBuilder = portStatBuilders.get(indCellId.index());
-            if (counterData.cellId().counterId().equals(ingressCounterId)) {
+            if (counterData.cellId().counterId().equals(ingressCounterId())) {
                 statsBuilder.setPacketsReceived(counterData.packets());
                 statsBuilder.setBytesReceived(counterData.bytes());
-            } else if (counterData.cellId().counterId().equals(egressCounterId)) {
+            } else if (counterData.cellId().counterId().equals(egressCounterId())) {
                 statsBuilder.setPacketsSent(counterData.packets());
                 statsBuilder.setBytesSent(counterData.bytes());
             } else {
diff --git a/lib/BUCK b/lib/BUCK
index 8b6dc1d..5436710 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -1519,3 +1519,11 @@
   visibility = [ 'PUBLIC' ],
 )
 
+remote_jar (
+  name = 'swagger-annotations',
+  out = 'swagger-annotations-1.5.16.jar',
+  url = 'mvn:io.swagger:swagger-annotations:jar:1.5.16',
+  sha1 = '935f1f2fed2cbdd7a0513981d6c53201e21155f4',
+  maven_coords = 'io.swagger:swagger-annotations:1.5.16',
+  visibility = [ 'PUBLIC' ],
+)
\ No newline at end of file
diff --git a/lib/deps.json b/lib/deps.json
index 071d95f..f0f796c 100644
--- a/lib/deps.json
+++ b/lib/deps.json
@@ -270,6 +270,7 @@
     "google-instrumentation-0.3.0": "mvn:com.google.instrumentation:instrumentation-api:0.3.0",
     "bcpkix-jdk15on": "mvn:org.bouncycastle:bcpkix-jdk15on:1.58",
     "bcprov-jdk15on": "mvn:org.bouncycastle:bcprov-jdk15on:1.58",
-    "hamcrest-optional": "mvn:com.spotify:hamcrest-optional:1.1.0"
+    "hamcrest-optional": "mvn:com.spotify:hamcrest-optional:1.1.0",
+    "swagger-annotations": "mvn:io.swagger:swagger-annotations:1.5.16"
   }
 }
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
index 4d8cfa1..9481b8d 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
@@ -45,6 +45,20 @@
     @Deprecated
     CompletableFuture<String> request(String request) throws NetconfException;
 
+    /**
+     * Executes an asynchronous RPC request to the server and obtains a future
+     * for it's response.
+     *
+     * @param request the XML containing the RPC request for the server.
+     * @return Server response or ERROR
+     * @throws NetconfException when there is a problem in the communication process on
+     * the underlying connection
+     * @throws NetconfTransportException on secure transport-layer error
+     */
+    default CompletableFuture<String> rpc(String request) throws NetconfException {
+        return request(request);
+    }
+
 
     /**
      * Retrieves the requested configuration, different from get-config.
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfTransportException.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfTransportException.java
new file mode 100644
index 0000000..4c610fd
--- /dev/null
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfTransportException.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.netconf;
+
+/**
+ * Exception triggered from NETCONF secure transport layer or below.
+ */
+public class NetconfTransportException extends RuntimeException {
+
+    private static final long serialVersionUID = 5788096975954688094L;
+
+    public NetconfTransportException() {
+    }
+
+    /**
+     * @param message describing the error
+     */
+    public NetconfTransportException(String message) {
+        super(message);
+    }
+
+    /**
+     * @param cause of this exception
+     */
+    public NetconfTransportException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * @param message describing the error
+     * @param cause of this exception
+     */
+    public NetconfTransportException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
index 99f79cd..06fd53a 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
@@ -32,6 +32,7 @@
 import org.bouncycastle.openssl.PEMParser;
 import org.bouncycastle.openssl.PEMKeyPair;
 import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.onlab.util.SharedExecutors;
 import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.NetconfDeviceInfo;
 import org.onosproject.netconf.NetconfDeviceOutputEvent;
@@ -40,11 +41,10 @@
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
 import org.onosproject.netconf.NetconfSessionFactory;
+import org.onosproject.netconf.NetconfTransportException;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.slf4j.LoggerFactory.getLogger;
 
 import java.io.CharArrayReader;
 import java.io.IOException;
@@ -77,8 +77,7 @@
  */
 public class NetconfSessionMinaImpl implements NetconfSession {
 
-    private static final Logger log = LoggerFactory
-            .getLogger(NetconfSessionMinaImpl.class);
+    private static final Logger log = getLogger(NetconfSessionMinaImpl.class);
 
     /**
      * NC 1.0, RFC4742 EOM sequence.
@@ -167,6 +166,8 @@
         replies = new ConcurrentHashMap<>();
         errorReplies = new ArrayList<>();
 
+        // FIXME should not immediately start session on construction
+        // setOnosCapabilities() is useless due to this behavior
         startConnection();
     }
 
@@ -175,6 +176,8 @@
         replies = new ConcurrentHashMap<>();
         errorReplies = new ArrayList<>();
         setOnosCapabilities(capabilities);
+        // FIXME should not immediately start session on construction
+        // setOnosCapabilities() is useless due to this behavior
         startConnection();
     }
 
@@ -206,6 +209,8 @@
         startSession();
     }
 
+    // FIXME blocking
+    @Deprecated
     private void startSession() throws IOException {
         final ConnectFuture connectFuture;
         connectFuture = client.connect(deviceInfo.name(),
@@ -251,6 +256,8 @@
         return kf.generatePublic(spec);
     }
 
+    // FIXME blocking
+    @Deprecated
     private void openChannel() throws IOException {
         channel = session.createSubsystemChannel("netconf");
         OpenFuture channelFuture = channel.open();
@@ -465,13 +472,53 @@
         return message;
     }
 
-
     @Override
     @Deprecated
     public CompletableFuture<String> request(String request) {
         return streamHandler.sendMessage(request);
     }
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * FIXME Note: as of 1.12.0
+     * {@code request} must not include message-id, this method will assign
+     * and insert message-id on it's own.
+     * Will require ONOS-7019 to remove this limitation.
+     */
+    @Override
+    public CompletableFuture<String> rpc(String request) {
+
+        String rpc = request;
+        //  - assign message-id
+        int msgId = messageIdInteger.incrementAndGet();
+        //  - re-write request to insert message-id
+        // FIXME avoid using formatRequestMessageId
+        rpc = formatRequestMessageId(rpc, msgId);
+        //  - ensure it contains XML header
+        rpc = formatXmlHeader(rpc);
+        //  - use chunked framing if talking to NC 1.1 device
+        // FIXME avoid using formatNetconfMessage
+        rpc = formatNetconfMessage(rpc);
+
+        // TODO session liveness check & recovery
+
+        log.debug("Sending {} to {}", rpc, this.deviceInfo.getDeviceId());
+        return streamHandler.sendMessage(rpc, msgId)
+                    .handleAsync((reply, t) -> {
+                        if (t != null) {
+                            // secure transport-layer error
+                            // cannot use NetconfException, which is
+                            // checked Exception.
+                            throw new NetconfTransportException(t);
+                        } else {
+                            // FIXME avoid using checkReply, error handling is weird
+                            checkReply(reply);
+                            return reply;
+                        }
+                    }, SharedExecutors.getPoolThreadExecutor());
+    }
+
     @Override
     public int timeoutConnectSec() {
         return connectTimeout;
@@ -885,6 +932,7 @@
             } else if (reply.contains("<ok/>")
                     || (reply.contains("<rpc-error>")
                     && reply.contains("warning"))) {
+                // FIXME rpc-error with a warning is considered same as Ok??
                 log.debug("Device {} sent reply {}", deviceInfo, reply);
                 return true;
             }
diff --git a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java
index 2f54899..40ba70d 100644
--- a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java
+++ b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java
@@ -62,6 +62,7 @@
     private static final String CONSUMES = "javax.ws.rs.Consumes";
     private static final String JSON = "MediaType.APPLICATION_JSON";
     private static final String OCTET_STREAM = "MediaType.APPLICATION_OCTET_STREAM";
+    private static final String RESPONSES = "io.swagger.annotations.ApiResponses";
 
     private final List<File> srcs;
     private final List<File> resources;
@@ -258,11 +259,10 @@
 
         processConsumesProduces(methodNode, "consumes", consumes);
         processConsumesProduces(methodNode, "produces", produces);
-        if (tag == null || ((method.toLowerCase().equals("post") || method.toLowerCase().equals("put"))
-                && !(tag.getParameters().size() > 1))) {
-            addResponses(methodNode, tag, false);
+        if (tag == null || !(tag.getParameters().size() > 1)) {
+            addResponses(javaMethod, methodNode, tag, false);
         } else {
-            addResponses(methodNode, tag, true);
+            addResponses(javaMethod, methodNode, tag, true);
         }
 
         ObjectNode operations = pathMap.get(fullPath);
@@ -327,24 +327,49 @@
         }
     }
 
-    // Temporary solution to add responses to a method
-    private void addResponses(ObjectNode methodNode, DocletTag tag, boolean responseJson) {
+    private Optional<JavaAnnotation> getResponsesAnnotation(JavaMethod javaMethod) {
+        return javaMethod.getAnnotations().stream().filter(
+                a -> a.getType().getName().equals(RESPONSES)
+        ).findAny();
+    }
+
+    // TODO: add json schema for responses
+    private void addResponses(JavaMethod javaMethod, ObjectNode methodNode, DocletTag tag, boolean responseJson) {
         ObjectNode responses = mapper.createObjectNode();
         methodNode.set("responses", responses);
 
-        ObjectNode success = mapper.createObjectNode();
-        success.put("description", "successful operation");
-        responses.set("200", success);
-        if (tag != null && responseJson) {
-            ObjectNode schema = mapper.createObjectNode();
-            tag.getParameters().stream().forEach(
-                    param -> schema.put("$ref", "#/definitions/" + param));
-            success.set("schema", schema);
-        }
+        Optional<JavaAnnotation> responsesAnnotation = getResponsesAnnotation(javaMethod);
 
-        ObjectNode defaultObj = mapper.createObjectNode();
-        defaultObj.put("description", "Unexpected error");
-        responses.set("default", defaultObj);
+        if (responsesAnnotation.isPresent()) {
+            Object annotationsObj = responsesAnnotation.get().getNamedParameter("value");
+            if (annotationsObj != null && annotationsObj instanceof List) {
+                List<JavaAnnotation> responseAnnotation = (List<JavaAnnotation>) annotationsObj;
+                responseAnnotation.forEach(
+                        javaAnnotation -> {
+                            ObjectNode response = mapper.createObjectNode();
+                            response.put("description",
+                                    String.valueOf(javaAnnotation.getNamedParameter("message"))
+                                            .replaceAll("^\"|\"$", ""));
+                            responses.set(String.valueOf(javaAnnotation.getNamedParameter("code")), response);
+                        }
+                );
+            }
+        } else {
+            ObjectNode success = mapper.createObjectNode();
+            success.put("description", "successful operation");
+            responses.set("200", success);
+
+            ObjectNode defaultObj = mapper.createObjectNode();
+            defaultObj.put("description", "Unexpected error");
+            responses.set("default", defaultObj);
+
+            if (tag != null && responseJson) {
+                ObjectNode schema = mapper.createObjectNode();
+                tag.getParameters().stream().forEach(
+                        param -> schema.put("$ref", "#/definitions/" + param));
+                success.set("schema", schema);
+            }
+        }
     }
 
     // Checks if the annotations has a value of JSON and returns the string
diff --git a/tools/build/onos-buck b/tools/build/onos-buck
index 7d4b174..6830b1d 100755
--- a/tools/build/onos-buck
+++ b/tools/build/onos-buck
@@ -5,8 +5,8 @@
 
 set -e
 
-BUCK_URL="http://onlab.vicci.org/onos/third-party/buck-v2017.09.01.01.zip"
-BUCK_SHA="9addcfd68518ee51b8f08135a7828b38dffb8fe5"
+BUCK_URL="http://onlab.vicci.org/onos/third-party/buck-v2017.10.03.02.zip"
+BUCK_SHA="c82bfa67b18e3acd3a3ec278be1549856cb74d3b"
 
 [  "-U" = "$1" ] && shift && FORCE_UPDATE=True
 
diff --git a/utils/misc/src/main/java/org/onlab/packet/ARP.java b/utils/misc/src/main/java/org/onlab/packet/ARP.java
index 773169b..b76ff61 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ARP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ARP.java
@@ -248,25 +248,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.hardwareType = bb.getShort();
-        this.protocolType = bb.getShort();
-        this.hardwareAddressLength = bb.get();
-        this.protocolAddressLength = bb.get();
-        this.opCode = bb.getShort();
-        this.senderHardwareAddress = new byte[0xff & this.hardwareAddressLength];
-        bb.get(this.senderHardwareAddress, 0, this.senderHardwareAddress.length);
-        this.senderProtocolAddress = new byte[0xff & this.protocolAddressLength];
-        bb.get(this.senderProtocolAddress, 0, this.senderProtocolAddress.length);
-        this.targetHardwareAddress = new byte[0xff & this.hardwareAddressLength];
-        bb.get(this.targetHardwareAddress, 0, this.targetHardwareAddress.length);
-        this.targetProtocolAddress = new byte[0xff & this.protocolAddressLength];
-        bb.get(this.targetProtocolAddress, 0, this.targetProtocolAddress.length);
-        return this;
-    }
 
     /*
      * (non-Javadoc)
@@ -477,6 +458,21 @@
         };
     }
 
+    /**
+     * Make an exact copy of the ARP packet.
+     *
+     * @return copy of the packet
+     */
+    public ARP duplicate() {
+        try {
+            byte[] data = serialize();
+            return deserializer().deserialize(data, 0, data.length);
+        } catch (DeserializationException dex) {
+            // If we can't make an object out of the serialized data, its a defect
+            throw new IllegalStateException(dex);
+        }
+    }
+
     @Override
     public String toString() {
         return toStringHelper(getClass())
diff --git a/utils/misc/src/main/java/org/onlab/packet/BasePacket.java b/utils/misc/src/main/java/org/onlab/packet/BasePacket.java
index c68b0aa..578086b 100644
--- a/utils/misc/src/main/java/org/onlab/packet/BasePacket.java
+++ b/utils/misc/src/main/java/org/onlab/packet/BasePacket.java
@@ -16,6 +16,9 @@
 
 package org.onlab.packet;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
 /**
  * Base packet class.
  */
@@ -84,18 +87,38 @@
         return true;
     }
 
+    /**
+     * This implementation of clone() is here to preserve backwards compatibility. Applications should not
+     * use clone() and instead use the duplicate() methods on the packet classes.
+     *
+     * @return copy of packet
+     */
     @Override
     public Object clone() {
-        IPacket pkt;
-        try {
-            pkt = this.getClass().newInstance();
-        } catch (final Exception e) {
-            throw new RuntimeException("Could not clone packet");
+
+        Class<? extends BasePacket> packetClass = this.getClass();
+        Method[] allMethods = packetClass.getDeclaredMethods();
+
+        Method deserializerFactory = null;
+        for (Method m : allMethods) {
+            String mname = m.getName();
+            if (mname.equals("deserializer")) {
+                deserializerFactory = m;
+                break;
+            }
         }
 
-        final byte[] data = this.serialize();
-        pkt.deserialize(data, 0, data.length);
-        pkt.setParent(this.parent);
-        return pkt;
+        if (deserializerFactory == null) {
+            throw new IllegalStateException("No Deserializer found for " + packetClass.getName());
+        }
+
+        byte[] data = serialize();
+        try {
+            Deserializer deserializer = (Deserializer) deserializerFactory.invoke(this);
+            return deserializer.deserialize(data, 0, data.length);
+        } catch (IllegalAccessException | InvocationTargetException | DeserializationException ex) {
+            throw new IllegalStateException(ex);
+        }
+
     }
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCP.java b/utils/misc/src/main/java/org/onlab/packet/DHCP.java
index 791e970..9e6f38f 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCP.java
@@ -505,16 +505,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        try {
-            return deserializer().deserialize(data, offset, length);
-        } catch (DeserializationException e) {
-            return null;
-        }
-    }
-
     protected void writeString(final String string, final ByteBuffer bb,
             final int maxLength) {
         if (string == null) {
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCP6.java b/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
index f807000..054552c 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
@@ -233,14 +233,6 @@
         };
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        try {
-            return deserializer().deserialize(data, offset, length);
-        } catch (DeserializationException e) {
-            return null;
-        }
-    }
 
     /**
      * Gets the message type of this DHCPv6 packet.
diff --git a/utils/misc/src/main/java/org/onlab/packet/Data.java b/utils/misc/src/main/java/org/onlab/packet/Data.java
index 66a8f50..2d405ca 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Data.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Data.java
@@ -65,13 +65,6 @@
         return this.data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        this.data = Arrays.copyOfRange(data, offset, data.length);
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/EAP.java b/utils/misc/src/main/java/org/onlab/packet/EAP.java
index bf53671..9d9dcf6 100644
--- a/utils/misc/src/main/java/org/onlab/packet/EAP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/EAP.java
@@ -232,25 +232,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.code = bb.get();
-        this.identifier = bb.get();
-        this.length = bb.getShort();
-
-        int dataLength;
-        if (this.code == REQUEST || this.code == RESPONSE) {
-            this.type = bb.get();
-            dataLength = this.length - 5;
-        } else {
-            dataLength = this.length - 4;
-        }
-        this.data = new byte[dataLength];
-        bb.get(this.data);
-        return this;
-    }
 
     @Override
     public int hashCode() {
diff --git a/utils/misc/src/main/java/org/onlab/packet/EAPOL.java b/utils/misc/src/main/java/org/onlab/packet/EAPOL.java
index 3a2aa52..741d302 100644
--- a/utils/misc/src/main/java/org/onlab/packet/EAPOL.java
+++ b/utils/misc/src/main/java/org/onlab/packet/EAPOL.java
@@ -198,26 +198,6 @@
         };
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-
-        // deserialize the EAPOL header
-        this.version = bb.get();
-        this.eapolType = bb.get();
-        this.packetLength = bb.getShort();
-
-        if (this.packetLength > 0) {
-            // deserialize the EAP Payload
-            this.payload = new EAP();
-
-            this.payload = this.payload.deserialize(data, bb.position(), length - 4);
-            this.payload.setParent(this);
-        }
-
-        return this;
-    }
 
     @Override
     public String toString() {
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ethernet.java b/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
index 075066d..006c32e 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
@@ -389,80 +389,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        if (length <= 0) {
-            return null;
-        }
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        if (this.destinationMACAddress == null) {
-            this.destinationMACAddress = MacAddress.valueOf(new byte[6]);
-        }
-        final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
-        bb.get(dstAddr);
-        this.destinationMACAddress = MacAddress.valueOf(dstAddr);
-
-        if (this.sourceMACAddress == null) {
-            this.sourceMACAddress = MacAddress.valueOf(new byte[6]);
-        }
-        final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
-        bb.get(srcAddr);
-        this.sourceMACAddress = MacAddress.valueOf(srcAddr);
-
-        short ethType = bb.getShort();
-        if (ethType == TYPE_QINQ) {
-            final short tci = bb.getShort();
-            this.qInQPriorityCode = (byte) (tci >> 13 & 0x07);
-            this.qinqVID = (short) (tci & 0x0fff);
-            this.qinqTPID = TYPE_QINQ;
-            ethType = bb.getShort();
-        }
-
-        if (ethType == TYPE_VLAN) {
-            final short tci = bb.getShort();
-            this.priorityCode = (byte) (tci >> 13 & 0x07);
-            this.vlanID = (short) (tci & 0x0fff);
-            ethType = bb.getShort();
-
-            // there might be one more tag with 1q TPID
-            if (ethType == TYPE_VLAN) {
-                // packet is double tagged with 1q TPIDs
-                // We handle only double tagged packets here and assume that in this case
-                // TYPE_QINQ above was not hit
-                // We put the values retrieved above with TYPE_VLAN in
-                // qInQ fields
-                this.qInQPriorityCode = this.priorityCode;
-                this.qinqVID = this.vlanID;
-                this.qinqTPID = TYPE_VLAN;
-
-                final short innerTci = bb.getShort();
-                this.priorityCode = (byte) (innerTci >> 13 & 0x07);
-                this.vlanID = (short) (innerTci & 0x0fff);
-                ethType = bb.getShort();
-            }
-        } else {
-            this.vlanID = Ethernet.VLAN_UNTAGGED;
-        }
-        this.etherType = ethType;
-
-        IPacket payload;
-        Deserializer<? extends IPacket> deserializer;
-        if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
-            deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
-        } else {
-            deserializer = Data.deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                    bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-        return this;
-    }
-
     /**
      * Checks to see if a string is a valid MAC address.
      *
@@ -862,4 +788,19 @@
             return eth;
         };
     }
+
+    /**
+     * Make an exact copy of the ethernet packet.
+     *
+     * @return copy of the packet
+     */
+    public Ethernet duplicate() {
+        try {
+            byte[] data = serialize();
+            return deserializer().deserialize(data, 0, data.length);
+        } catch (DeserializationException dex) {
+            // If we can't make an object out of the serialized data, its a defect
+            throw new IllegalStateException(dex);
+        }
+    }
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/ICMP.java b/utils/misc/src/main/java/org/onlab/packet/ICMP.java
index 9513061..d1afcb6 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ICMP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ICMP.java
@@ -134,21 +134,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.icmpType = bb.get();
-        this.icmpCode = bb.get();
-        this.checksum = bb.getShort();
-
-        this.payload = new Data();
-        this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
-                - bb.position());
-        this.payload.setParent(this);
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/ICMP6.java b/utils/misc/src/main/java/org/onlab/packet/ICMP6.java
index e50df26..dcde6b2 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ICMP6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ICMP6.java
@@ -264,31 +264,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.icmpType = bb.get();
-        this.icmpCode = bb.get();
-        this.checksum = bb.getShort();
-
-        Deserializer<? extends IPacket> deserializer;
-        if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmpType)) {
-            deserializer = TYPE_DESERIALIZER_MAP.get(icmpType);
-        } else {
-            deserializer = Data.deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                     bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/IGMP.java b/utils/misc/src/main/java/org/onlab/packet/IGMP.java
index 04308db..3395f66 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IGMP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IGMP.java
@@ -189,32 +189,6 @@
     }
 
     /**
-     * Deserialize an IGMP message.
-     *
-     * @param data bytes to deserialize
-     * @param offset offset to start deserializing from
-     * @param length length of the data to deserialize
-     * @return populated IGMP object
-     */
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-
-        final IGMP igmp;
-        try {
-            igmp = IGMP.deserializer().deserialize(data, offset, length);
-        } catch (DeserializationException e) {
-            log.error("Deserialization exception", e);
-            return this;
-        }
-        this.igmpType = igmp.igmpType;
-        this.resField = igmp.resField;
-        this.checksum = igmp.checksum;
-        this.groups = igmp.groups;
-        return this;
-    }
-
-    /**
      * Deserializer function for IPv4 packets.
      *
      * @return deserializer function
diff --git a/utils/misc/src/main/java/org/onlab/packet/IPacket.java b/utils/misc/src/main/java/org/onlab/packet/IPacket.java
index 11079f7..ed7f287 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IPacket.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IPacket.java
@@ -64,29 +64,5 @@
      */
     byte[] serialize();
 
-    /**
-     * Deserialize this packet layer and all possible payloads.
-     *
-     * NOTE: This method has been deprecated and will be removed in a future
-     * release. It is now recommended to use the Deserializer function provided
-     * by the deserialize() method on each packet to deserialize them. The
-     * Deserializer functions are robust to malformed input.
-     *
-     * @param data bytes to deserialize
-     * @param offset
-     *            offset to start deserializing from
-     * @param length
-     *            length of the data to deserialize
-     * @return the deserialized data
-     * @deprecated in Cardinal Release
-     */
-    @Deprecated
-    IPacket deserialize(byte[] data, int offset, int length);
 
-    /**
-     * Clone this packet and its payload packet but not its parent.
-     *
-     * @return the clone
-     */
-    Object clone();
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/IPv4.java b/utils/misc/src/main/java/org/onlab/packet/IPv4.java
index 7b0ad17..bdfc5c7 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IPv4.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IPv4.java
@@ -412,55 +412,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        short sscratch;
-
-        this.version = bb.get();
-        this.headerLength = (byte) (this.version & 0xf);
-        this.version = (byte) (this.version >> 4 & 0xf);
-        this.diffServ = bb.get();
-        this.totalLength = bb.getShort();
-        this.identification = bb.getShort();
-        sscratch = bb.getShort();
-        this.flags = (byte) (sscratch >> 13 & 0x7);
-        this.fragmentOffset = (short) (sscratch & 0x1fff);
-        this.ttl = bb.get();
-        this.protocol = bb.get();
-        this.checksum = bb.getShort();
-        this.sourceAddress = bb.getInt();
-        this.destinationAddress = bb.getInt();
-
-        if (this.headerLength > 5) {
-            final int optionsLength = (this.headerLength - 5) * 4;
-            this.options = new byte[optionsLength];
-            bb.get(this.options);
-        }
-
-        if (this.totalLength != length) {
-            this.isTruncated = true;
-        } else {
-            this.isTruncated = false;
-        }
-
-        Deserializer<? extends IPacket> deserializer;
-        if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(this.protocol)) {
-            deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(this.protocol);
-        } else {
-            deserializer = Data.deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                    bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
 
     /**
      * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
diff --git a/utils/misc/src/main/java/org/onlab/packet/IPv6.java b/utils/misc/src/main/java/org/onlab/packet/IPv6.java
index c455d59..9483a2b 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IPv6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IPv6.java
@@ -235,39 +235,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        int iscratch;
-
-        iscratch = bb.getInt();
-        this.version = (byte) (iscratch >> 28 & 0xf);
-        this.trafficClass = (byte) (iscratch >> 20 & 0xff);
-        this.flowLabel = iscratch & 0xfffff;
-        this.payloadLength = bb.getShort();
-        this.nextHeader = bb.get();
-        this.hopLimit = bb.get();
-        bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
-        bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
-
-        Deserializer<? extends IPacket> deserializer;
-        if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
-            deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
-        } else {
-            deserializer = Data.deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                    bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/LLC.java b/utils/misc/src/main/java/org/onlab/packet/LLC.java
index 90e09a0..cb54119 100644
--- a/utils/misc/src/main/java/org/onlab/packet/LLC.java
+++ b/utils/misc/src/main/java/org/onlab/packet/LLC.java
@@ -69,15 +69,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.dsap = bb.get();
-        this.ssap = bb.get();
-        this.ctrl = bb.get();
-        return this;
-    }
 
     /**
      * Deserializer function for LLC packets.
diff --git a/utils/misc/src/main/java/org/onlab/packet/LLDP.java b/utils/misc/src/main/java/org/onlab/packet/LLDP.java
index f2d621b..cd46eee 100644
--- a/utils/misc/src/main/java/org/onlab/packet/LLDP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/LLDP.java
@@ -143,43 +143,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        LLDPTLV tlv;
-        do {
-            try {
-                tlv = new LLDPOrganizationalTLV().deserialize(bb);
-            } catch (DeserializationException e) {
-                break;
-            }
-
-            // if there was a failure to deserialize stop processing TLVs
-            if (tlv == null) {
-                break;
-            }
-            switch (tlv.getType()) {
-                case 0x0:
-                    // can throw this one away, its just an end delimiter
-                    break;
-                case 0x1:
-                    this.chassisId = tlv;
-                    break;
-                case 0x2:
-                    this.portId = tlv;
-                    break;
-                case 0x3:
-                    this.ttl = tlv;
-                    break;
-
-                default:
-                    this.optionalTLVList.add(tlv);
-                    break;
-            }
-        } while (tlv.getType() != 0 && bb.hasRemaining());
-        return this;
-    }
 
     /*
      * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/MPLS.java b/utils/misc/src/main/java/org/onlab/packet/MPLS.java
index ba592c5..948075b 100644
--- a/utils/misc/src/main/java/org/onlab/packet/MPLS.java
+++ b/utils/misc/src/main/java/org/onlab/packet/MPLS.java
@@ -71,31 +71,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-
-        int mplsheader = bb.getInt();
-        this.label = ((mplsheader & 0xfffff000) >> 12);
-        this.bos = (byte) ((mplsheader & 0x00000100) >> 8);
-        this.bos = (byte) (mplsheader & 0x000000ff);
-        this.protocol = (this.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;
-
-        Deserializer<? extends IPacket> deserializer;
-        if (protocolDeserializerMap.containsKey(this.protocol)) {
-            deserializer = protocolDeserializerMap.get(this.protocol);
-        } else {
-            deserializer = Data.deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
 
     /**
      * Returns the MPLS label.
diff --git a/utils/misc/src/main/java/org/onlab/packet/PIM.java b/utils/misc/src/main/java/org/onlab/packet/PIM.java
index 68cfe34..f930e3a 100644
--- a/utils/misc/src/main/java/org/onlab/packet/PIM.java
+++ b/utils/misc/src/main/java/org/onlab/packet/PIM.java
@@ -242,28 +242,7 @@
         return data;
     }
 
-    /**
-     * Deserialize the PIM packet.
-     *
-     * @param data bytes to deserialize.
-     * @param offset offset to start deserializing from
-     * @param length length of the data to deserialize
-     *
-     * @return the deserialized PIM packet.
-     */
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-            final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.type = bb.get();
-        this.version = bb.get();
-        this.checksum = bb.getShort();
 
-        //this.payload = new Data();
-        this.payload = this.payload.deserialize(data, bb.position(), bb.limit() - bb.position());
-        this.payload.setParent(this);
-        return this;
-    }
     /**
      * Deserializer function for IPv4 packets.
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/RADIUS.java b/utils/misc/src/main/java/org/onlab/packet/RADIUS.java
index 0a2b220..fff2276 100644
--- a/utils/misc/src/main/java/org/onlab/packet/RADIUS.java
+++ b/utils/misc/src/main/java/org/onlab/packet/RADIUS.java
@@ -275,7 +275,7 @@
             }
         }
         // Assembling EAP object from the concatenated stream
-        message.deserialize(messageStream.toByteArray(), 0, messageStream.size());
+        //message.deserialize(messageStream.toByteArray(), 0, messageStream.size());
         return message;
     }
 
@@ -398,28 +398,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.code = bb.get();
-        this.identifier = bb.get();
-        this.length = bb.getShort();
-        bb.get(this.authenticator, 0, 16);
-
-        int remainingLength = this.length - RADIUS_MIN_LENGTH;
-        while (remainingLength > 0 && bb.hasRemaining()) {
-            RADIUSAttribute attr = new RADIUSAttribute();
-            attr.setType(bb.get());
-            attr.setLength(bb.get());
-            short attrLength = (short) (attr.length & 0xff);
-            attr.value = new byte[attrLength - 2];
-            bb.get(attr.value, 0, attrLength - 2);
-            this.attributes.add(attr);
-            remainingLength -= attr.length;
-        }
-        return this;
-    }
 
     @Override
     public String toString() {
diff --git a/utils/misc/src/main/java/org/onlab/packet/TCP.java b/utils/misc/src/main/java/org/onlab/packet/TCP.java
index 1c84324..735a415 100644
--- a/utils/misc/src/main/java/org/onlab/packet/TCP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/TCP.java
@@ -346,39 +346,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.sourcePort = (bb.getShort() & 0xffff);
-        this.destinationPort = (bb.getShort() & 0xffff);
-        this.sequence = bb.getInt();
-        this.acknowledge = bb.getInt();
-        this.flags = bb.getShort();
-        this.dataOffset = (byte) (this.flags >> 12 & 0xf);
-        this.flags = (short) (this.flags & 0x1ff);
-        this.windowSize = bb.getShort();
-        this.checksum = bb.getShort();
-        this.urgentPointer = bb.getShort();
-        if (this.dataOffset > 5) {
-            int optLength = (this.dataOffset << 2) - 20;
-            if (bb.limit() < bb.position() + optLength) {
-                optLength = bb.limit() - bb.position();
-            }
-            try {
-                this.options = new byte[optLength];
-                bb.get(this.options, 0, optLength);
-            } catch (final IndexOutOfBoundsException e) {
-                this.options = null;
-            }
-        }
-
-        this.payload = new Data();
-        this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
-                - bb.position());
-        this.payload.setParent(this);
-        return this;
-    }
 
     /*
      * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/UDP.java b/utils/misc/src/main/java/org/onlab/packet/UDP.java
index 89638be..9f51713 100644
--- a/utils/misc/src/main/java/org/onlab/packet/UDP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/UDP.java
@@ -195,34 +195,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.sourcePort = (bb.getShort() & 0xffff);
-        this.destinationPort = (bb.getShort() & 0xffff);
-        this.length = bb.getShort();
-        this.checksum = bb.getShort();
-
-        Deserializer<? extends IPacket> deserializer;
-        if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.destinationPort)) {
-            deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.destinationPort);
-        } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.sourcePort)) {
-            deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.sourcePort);
-        } else {
-            deserializer = Data.deserializer();
-        }
-
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                   bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/VXLAN.java b/utils/misc/src/main/java/org/onlab/packet/VXLAN.java
index e4325cd..9e451c6 100644
--- a/utils/misc/src/main/java/org/onlab/packet/VXLAN.java
+++ b/utils/misc/src/main/java/org/onlab/packet/VXLAN.java
@@ -62,32 +62,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-
-        if (bb.remaining() < VXLAN_HEADER_LENGTH) {
-            return this;
-        }
-
-        this.flags = bb.get();
-        bb.get(this.rsvd1);
-        bb.get(this.vni);
-        this.rsvd2 = bb.get();
-
-        Deserializer<? extends IPacket> deserializer = Data.deserializer();
-
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                    bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-        return this;
-    }
-
     /**
      * Returns VNI(VXLAN Network Identifier).
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java
index df5e4d4..c8ca3bd 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java
@@ -19,9 +19,7 @@
 
 import com.google.common.base.MoreObjects;
 import org.onlab.packet.BasePacket;
-import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -146,14 +144,7 @@
         return byteBuffer.array();
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        try {
-            return deserializer().deserialize(data, offset, length);
-        } catch (DeserializationException e) {
-            throw new RuntimeException("Can't deserialize duid due to {}", e);
-        }
-    }
+
 
     public static Deserializer<Dhcp6Duid> deserializer() {
         return (data, offset, length) -> {
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
index 597732d..f19f735 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
@@ -21,7 +21,6 @@
 import org.onlab.packet.Data;
 import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 
 import java.nio.ByteBuffer;
 import java.util.Objects;
@@ -147,14 +146,6 @@
         return bb.array();
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        try {
-            return deserializer().deserialize(data, offset, length);
-        } catch (DeserializationException e) {
-            throw new RuntimeException("Can't deserialize data for DHCPv6 option.", e);
-        }
-    }
 
     protected ToStringHelper getToStringHelper() {
         return toStringHelper(Dhcp6Option.class)
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
index 76f768f..93e9aac 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
@@ -17,9 +17,7 @@
 package org.onlab.packet.dhcp;
 
 import org.onlab.packet.BasePacket;
-import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
@@ -55,15 +53,6 @@
         return byteBuffer.array();
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        try {
-            return deserializer().deserialize(data, offset, length);
-        } catch (DeserializationException e) {
-            log.warn("Can't deserialize DhcpOption {}", e);
-            return null;
-        }
-    }
 
     /**
      * Deserializer function for DHCP option.
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
index adda088..08f488d 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
@@ -17,9 +17,7 @@
 package org.onlab.packet.dhcp;
 
 import com.google.common.collect.Maps;
-import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
@@ -77,15 +75,7 @@
         return byteBuffer.array();
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        try {
-            return deserializer().deserialize(data, offset, length);
-        } catch (DeserializationException e) {
-            log.warn("can't deserialize DHCP relay agent information option {}", e);
-            return null;
-        }
-    }
+
 
     /**
      * Deserializer function for DHCP relay agent option.
diff --git a/utils/misc/src/main/java/org/onlab/packet/ipv6/Authentication.java b/utils/misc/src/main/java/org/onlab/packet/ipv6/Authentication.java
index a6e277a..1cee5be 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ipv6/Authentication.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ipv6/Authentication.java
@@ -18,7 +18,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Data;
-import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.IPacket;
 import org.onlab.packet.IPv6;
@@ -180,36 +179,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.nextHeader = bb.get();
-        this.payloadLength = bb.get();
-        bb.getShort();
-        this.securityParamIndex = bb.getInt();
-        this.sequence = bb.getInt();
-        int icvLength = getTotalLength() - FIXED_HEADER_LENGTH;
-        this.integrityCheck = new byte[icvLength];
-        bb.get(this.integrityCheck, 0, icvLength);
-
-        Deserializer<? extends IPacket> deserializer;
-        if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
-            deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
-        } else {
-            deserializer = Data.deserializer();
-        }
-
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                              bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/ipv6/BaseOptions.java b/utils/misc/src/main/java/org/onlab/packet/ipv6/BaseOptions.java
index 6a9f188..d6c49e1 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ipv6/BaseOptions.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ipv6/BaseOptions.java
@@ -18,7 +18,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Data;
-import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.IPacket;
 import org.onlab.packet.IPv6;
@@ -147,33 +146,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.nextHeader = bb.get();
-        this.headerExtLength = bb.get();
-        int optionLength =
-                FIXED_OPTIONS_LENGTH + LENGTH_UNIT * this.headerExtLength;
-        this.options = new byte[optionLength];
-        bb.get(this.options, 0, optionLength);
-
-        Deserializer<? extends IPacket> deserializer;
-        if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
-            deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
-        } else {
-            deserializer = Data.deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                    bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/ipv6/EncapSecurityPayload.java b/utils/misc/src/main/java/org/onlab/packet/ipv6/EncapSecurityPayload.java
index d8b50ba..a1e1195 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ipv6/EncapSecurityPayload.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ipv6/EncapSecurityPayload.java
@@ -19,7 +19,6 @@
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Data;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 import org.onlab.packet.IPv6;
 
 import java.nio.ByteBuffer;
@@ -110,20 +109,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.securityParamIndex = bb.getInt();
-        this.sequence = bb.getInt();
-
-        this.payload = new Data();
-        this.payload.deserialize(data, bb.position(),
-                                 bb.limit() - bb.position());
-        this.payload.setParent(this);
-
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/ipv6/Fragment.java b/utils/misc/src/main/java/org/onlab/packet/ipv6/Fragment.java
index a03b4e7..112e43e 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ipv6/Fragment.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ipv6/Fragment.java
@@ -18,7 +18,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Data;
-import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.IPacket;
 import org.onlab.packet.IPv6;
@@ -144,32 +143,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.nextHeader = bb.get();
-        bb.get();
-        short sscratch = bb.getShort();
-        this.fragmentOffset = (short) (sscratch >> 3 & 0x1fff);
-        this.moreFragment = (byte) (sscratch & 0x1);
-        this.identification = bb.getInt();
-
-        Deserializer<? extends IPacket> deserializer;
-        if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
-            deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
-        } else {
-            deserializer = Data.deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                    bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
 
     /*
     * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/ipv6/Routing.java b/utils/misc/src/main/java/org/onlab/packet/ipv6/Routing.java
index cc658b7..7f8a0d6 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ipv6/Routing.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ipv6/Routing.java
@@ -18,7 +18,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Data;
-import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.IPacket;
 import org.onlab.packet.IPv6;
@@ -169,35 +168,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.nextHeader = bb.get();
-        this.headerExtLength = bb.get();
-        this.routingType = bb.get();
-        this.segmentsLeft = bb.get();
-        int dataLength =
-                FIXED_ROUTING_DATA_LENGTH + LENGTH_UNIT * this.headerExtLength;
-        this.routingData = new byte[dataLength];
-        bb.get(this.routingData, 0, dataLength);
-
-        Deserializer<? extends IPacket> deserializer;
-        if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
-            deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
-        } else {
-            deserializer = new Data().deserializer();
-        }
-        try {
-            this.payload = deserializer.deserialize(data, bb.position(),
-                                                    bb.limit() - bb.position());
-            this.payload.setParent(this);
-        } catch (DeserializationException e) {
-            return this;
-        }
-
-        return this;
-    }
-
     /*
      * (non-Javadoc)
      *
diff --git a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborAdvertisement.java b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborAdvertisement.java
index 77dd409..77c360a 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborAdvertisement.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborAdvertisement.java
@@ -19,7 +19,6 @@
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.ICMP6;
-import org.onlab.packet.IPacket;
 import org.onlab.packet.IPv6;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
@@ -181,22 +180,7 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        int iscratch;
 
-        iscratch = bb.getInt();
-        this.routerFlag = (byte) (iscratch >> 31 & 0x1);
-        this.solicitedFlag = (byte) (iscratch >> 30 & 0x1);
-        this.overrideFlag = (byte) (iscratch >> 29 & 0x1);
-        bb.get(this.targetAddress, 0, Ip6Address.BYTE_LENGTH);
-
-        this.options.deserialize(data, bb.position(),
-                                 bb.limit() - bb.position());
-
-        return this;
-    }
 
     /*
      * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborDiscoveryOptions.java b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborDiscoveryOptions.java
index ebc378e..d6b1df0 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborDiscoveryOptions.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborDiscoveryOptions.java
@@ -15,12 +15,11 @@
  */
 package org.onlab.packet.ndp;
 
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Objects;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -189,40 +188,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-
-        options.clear();
-
-        //
-        // Deserialize all options
-        //
-        while (bb.hasRemaining()) {
-            byte type = bb.get();
-            if (!bb.hasRemaining()) {
-                break;
-            }
-            byte lengthField = bb.get();
-            int dataLength = lengthField * 8;   // The data length field is in
-            // unit of 8 octets
-
-            // Exclude the type and length fields
-            if (dataLength < 2) {
-                break;
-            }
-            dataLength -= 2;
-
-            if (bb.remaining() < dataLength) {
-                break;
-            }
-            byte[] optionData = new byte[dataLength];
-            bb.get(optionData, 0, optionData.length);
-            addOption(type, optionData);
-        }
-
-        return this;
-    }
 
     @Override
     public int hashCode() {
diff --git a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java
index 06a5339..51018e4 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java
@@ -19,7 +19,6 @@
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.ICMP6;
-import org.onlab.packet.IPacket;
 import org.onlab.packet.IPv6;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
@@ -114,18 +113,7 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
 
-        bb.getInt();
-        bb.get(this.targetAddress, 0, Ip6Address.BYTE_LENGTH);
-
-        this.options.deserialize(data, bb.position(),
-                                 bb.limit() - bb.position());
-
-        return this;
-    }
 
     /*
      * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/ndp/Redirect.java b/utils/misc/src/main/java/org/onlab/packet/ndp/Redirect.java
index 15f68a0..ad5e9dc 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ndp/Redirect.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ndp/Redirect.java
@@ -17,7 +17,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 import org.onlab.packet.Ip6Address;
 
 import java.nio.ByteBuffer;
@@ -127,19 +126,7 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
 
-        bb.getInt();
-        bb.get(this.targetAddress, 0, Ip6Address.BYTE_LENGTH);
-        bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
-
-        this.options.deserialize(data, bb.position(),
-                                 bb.limit() - bb.position());
-
-        return this;
-    }
 
     /*
      * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/ndp/RouterAdvertisement.java b/utils/misc/src/main/java/org/onlab/packet/ndp/RouterAdvertisement.java
index 8582dae..bd0f8a0 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ndp/RouterAdvertisement.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ndp/RouterAdvertisement.java
@@ -17,7 +17,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 
 import java.nio.ByteBuffer;
 import java.util.List;
@@ -210,24 +209,7 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        int bscratch;
 
-        this.currentHopLimit = bb.get();
-        bscratch = bb.get();
-        this.mFlag = (byte) ((bscratch >> 7) & 0x1);
-        this.oFlag = (byte) ((bscratch >> 6) & 0x1);
-        this.routerLifetime = bb.getShort();
-        this.reachableTime = bb.getInt();
-        this.retransmitTimer = bb.getInt();
-
-        this.options.deserialize(data, bb.position(),
-                                 bb.limit() - bb.position());
-
-        return this;
-    }
 
     /*
      * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/ndp/RouterSolicitation.java b/utils/misc/src/main/java/org/onlab/packet/ndp/RouterSolicitation.java
index 116b8cb..902529c 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ndp/RouterSolicitation.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ndp/RouterSolicitation.java
@@ -17,7 +17,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 
 import java.nio.ByteBuffer;
 import java.util.List;
@@ -78,17 +77,6 @@
         return data;
     }
 
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-
-        bb.getInt();
-
-        this.options.deserialize(data, bb.position(),
-                                 bb.limit() - bb.position());
-
-        return this;
-    }
 
     /*
      * (non-Javadoc)
diff --git a/utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java b/utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java
index dadddcc..805748d 100644
--- a/utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java
+++ b/utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java
@@ -17,7 +17,6 @@
 
 import org.onlab.packet.BasePacket;
 import org.onlab.packet.Deserializer;
-import org.onlab.packet.IPacket;
 import org.onlab.packet.IpPrefix;
 
 import java.nio.ByteBuffer;
@@ -180,13 +179,7 @@
         return data2;
     }
 
-    // TODO: I suppose I really need to implement this?
-    @Override
-    public IPacket deserialize(final byte[] data, final int offset,
-                               final int length) {
-        final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        return this;
-    }
+
 
     /**
      * Return the J/P deserializer function.
diff --git a/utils/misc/src/test/java/org/onlab/packet/BasePacketTest.java b/utils/misc/src/test/java/org/onlab/packet/BasePacketTest.java
new file mode 100644
index 0000000..61c9fcc
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/packet/BasePacketTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.packet;
+
+import org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+public class BasePacketTest {
+
+    @Test
+    public void testClone() {
+        Ethernet p1 = new Ethernet();
+        p1.sourceMACAddress = MacAddress.ONOS;
+        p1.destinationMACAddress = MacAddress.ZERO;
+        p1.payload = new Data("xyzzy".getBytes());
+        BasePacket copy1 = (BasePacket) p1.clone();
+        assertThat(p1, equalTo(copy1));
+    }
+
+}
\ No newline at end of file