Merge remote-tracking branch 'origin/master' into dev/auklet
diff --git a/apps/acl/src/main/java/org/onosproject/acl/AclRule.java b/apps/acl/src/main/java/org/onosproject/acl/AclRule.java
index ff01aa4..02b7025 100644
--- a/apps/acl/src/main/java/org/onosproject/acl/AclRule.java
+++ b/apps/acl/src/main/java/org/onosproject/acl/AclRule.java
@@ -44,6 +44,7 @@
     private final Action action;
 
     protected static IdGenerator idGenerator;
+    private static final Object ID_GENERATOR_LOCK = new Object();
 
     /**
      * Enum type for ACL rule's action.
@@ -75,8 +76,10 @@
      */
     private AclRule(Ip4Prefix srcIp, Ip4Prefix dstIp, byte ipProto,
                     short dstTpPort, Action action) {
-        checkState(idGenerator != null, "Id generator is not bound.");
-        this.id = RuleId.valueOf(idGenerator.getNewId());
+        synchronized (ID_GENERATOR_LOCK) {
+            checkState(idGenerator != null, "Id generator is not bound.");
+            this.id = RuleId.valueOf(idGenerator.getNewId());
+        }
         this.srcIp = srcIp;
         this.dstIp = dstIp;
         this.ipProto = ipProto;
@@ -225,8 +228,10 @@
      * @param newIdGenerator id generator
      */
     public static void bindIdGenerator(IdGenerator newIdGenerator) {
-        checkState(idGenerator == null, "Id generator is already bound.");
-        idGenerator = checkNotNull(newIdGenerator);
+        synchronized (ID_GENERATOR_LOCK) {
+            checkState(idGenerator == null, "Id generator is already bound.");
+            idGenerator = checkNotNull(newIdGenerator);
+        }
     }
 
     public RuleId id() {
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java
index b21c5f6..9d188dd 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java
@@ -399,7 +399,7 @@
                 try {
                     asnPath.add(path.getInt(i));
                 } catch (JSONException e) {
-                    e.printStackTrace();
+                    log.warn("checkPath", e);
                 }
             }
             // reverse the list to get path starting from origin
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDeaggregatorImpl.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDeaggregatorImpl.java
index 5660644..d9141f4 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDeaggregatorImpl.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDeaggregatorImpl.java
@@ -23,7 +23,6 @@
 import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.util.CharsetUtil;
-import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -395,8 +394,7 @@
                             ByteBuf buffer = Unpooled.copiedBuffer(jsonInString, CharsetUtil.UTF_8);
                             ctx.writeAndFlush(buffer);
                         } catch (JsonProcessingException e) {
-                            e.printStackTrace();
-                            log.warn(ExceptionUtils.getFullStackTrace(e));
+                            log.warn("processMoasPacket()", e);
                         }
 
                         remoteTunnelIp = IpAddress.valueOf(msg.getLocalIp());
@@ -465,6 +463,7 @@
 
                         installRules();
                     }
+                    break;
                 }
                 default:
             }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientHandler.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientHandler.java
index 58954d9..b7cb3c5 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientHandler.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientHandler.java
@@ -24,7 +24,6 @@
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.util.CharsetUtil;
-import org.apache.commons.lang.exception.ExceptionUtils;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onosproject.artemis.ArtemisPacketProcessor;
@@ -69,8 +68,7 @@
             ByteBuf buffer = Unpooled.copiedBuffer(jsonInString, CharsetUtil.UTF_8);
             ctx.writeAndFlush(buffer);
         } catch (JsonProcessingException e) {
-            e.printStackTrace();
-            log.warn(ExceptionUtils.getFullStackTrace(e));
+            log.warn("channelActive()", e);
         }
     }
 
@@ -87,8 +85,7 @@
 
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-        log.error(ExceptionUtils.getFullStackTrace(cause));
-        cause.printStackTrace();
+        log.error("exceptionCaught()", cause);
         ctx.close();
     }
 
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerHandler.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerHandler.java
index d140416..6a6a0ab 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerHandler.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerHandler.java
@@ -22,7 +22,6 @@
 import io.netty.channel.ChannelHandler.Sharable;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
-import org.apache.commons.lang.exception.ExceptionUtils;
 import org.onlab.packet.IpAddress;
 import org.onosproject.artemis.impl.objects.ArtemisMessage;
 import org.slf4j.Logger;
@@ -77,8 +76,7 @@
 
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-        log.error(ExceptionUtils.getFullStackTrace(cause));
-        cause.printStackTrace();
+        log.error("exceptionCaught()", cause);
         ctx.close();
     }
 
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitors.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitors.java
index 5fb9be4..d645360 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitors.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitors.java
@@ -54,7 +54,7 @@
 
             socket.emit("exa_subscribe", parameters);
         } catch (JSONException e) {
-            e.printStackTrace();
+            log.warn("onConenct()", e);
         }
     }
 
@@ -88,7 +88,7 @@
                 packetProcessor.processMonitorPacket(message);
             }
         } catch (JSONException e) {
-            e.printStackTrace();
+            log.warn("onExaMessage()", e);
         }
     }
 
@@ -112,7 +112,7 @@
                 this.socket.on(Socket.EVENT_PING, args -> socket.emit("pong"));
                 this.socket.on("exa_message", this::onExaMessage);
             } catch (URISyntaxException e) {
-                e.printStackTrace();
+                log.warn("startMonitor()", e);
             }
             this.socket.connect();
         }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitors.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitors.java
index e848875..52025c9 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitors.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitors.java
@@ -17,7 +17,6 @@
 
 import io.socket.client.IO;
 import io.socket.client.Socket;
-import org.apache.commons.lang.exception.ExceptionUtils;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.onlab.packet.IpPrefix;
@@ -63,7 +62,7 @@
 
             socket.emit("ris_subscribe", parameters);
         } catch (JSONException e) {
-            e.printStackTrace();
+            log.warn("onConnect()", e);
         }
     }
 
@@ -110,8 +109,7 @@
                 packetProcessor.processMonitorPacket(message);
             }
         } catch (JSONException e) {
-            log.error(ExceptionUtils.getFullStackTrace(e));
-            e.printStackTrace();
+            log.error("onRisMessage()", e);
         }
         socket.emit("ping");
     }
@@ -129,8 +127,7 @@
                 this.socket.on(Socket.EVENT_PONG, args -> socket.emit("ping"));
                 this.socket.on("ris_message", this::onRisMessage);
             } catch (URISyntaxException e) {
-                log.error(ExceptionUtils.getFullStackTrace(e));
-                e.printStackTrace();
+                log.error("startMonitor()", e);
             }
 
             this.socket.connect();
diff --git a/apps/castor/src/main/java/org/onosproject/castor/CastorWebResource.java b/apps/castor/src/main/java/org/onosproject/castor/CastorWebResource.java
index 409216b..37630cf 100644
--- a/apps/castor/src/main/java/org/onosproject/castor/CastorWebResource.java
+++ b/apps/castor/src/main/java/org/onosproject/castor/CastorWebResource.java
@@ -20,6 +20,7 @@
 import org.onlab.packet.IpAddress;
 import org.onosproject.rest.AbstractWebResource;
 
+import java.io.IOException;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -88,8 +89,7 @@
                 get(ArpService.class).createArp(peer);
                 arpResult = ", ARP packet sent, MAC was not known";
             }
-        } catch (Exception e) {
-            e.printStackTrace();
+        } catch (IOException e) {
             String result = "Unable to process due to some reason, Try again";
             ObjectNode node = mapper().createObjectNode().put("response", result);
             return ok(node).build();
@@ -117,8 +117,7 @@
             ObjectMapper mapper = new ObjectMapper();
             Peer peer = mapper.readValue(incomingData, Peer.class);
             get(ConnectivityManagerService.class).deletePeer(peer);
-        } catch (Exception e) {
-            e.printStackTrace();
+        } catch (IOException e) {
             return Response.status(500).entity("Unable to delete the peer").build();
         }
         String result = "Peer Deleted";
@@ -143,8 +142,7 @@
             ObjectMapper mapper = new ObjectMapper();
             Peer peer = mapper.readValue(incomingData, Peer.class);
             get(ConnectivityManagerService.class).start(peer);
-        } catch (Exception e) {
-            e.printStackTrace();
+        } catch (IOException e) {
             return Response.status(500).entity("Unable to add the route server").build();
         }
         String result = "Server Entered";
diff --git a/apps/castor/src/main/java/org/onosproject/castor/ConnectivityManager.java b/apps/castor/src/main/java/org/onosproject/castor/ConnectivityManager.java
index 7a1fcec..2d40f6d 100644
--- a/apps/castor/src/main/java/org/onosproject/castor/ConnectivityManager.java
+++ b/apps/castor/src/main/java/org/onosproject/castor/ConnectivityManager.java
@@ -30,6 +30,7 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
@@ -188,8 +189,8 @@
                 .key(key)
                 .selector(selector)
                 .treatment(treatment)
-                .ingressPoint(portOne)
-                .egressPoint(portTwo)
+                .filteredIngressPoint(new FilteredConnectPoint(portOne))
+                .filteredEgressPoint(new FilteredConnectPoint(portTwo))
                 .priority(PRIORITY_OFFSET)
                 .build());
 
@@ -207,8 +208,8 @@
                 .key(key)
                 .selector(selector)
                 .treatment(treatment)
-                .ingressPoint(portTwo)
-                .egressPoint(portOne)
+                .filteredIngressPoint(new FilteredConnectPoint(portTwo))
+                .filteredEgressPoint(new FilteredConnectPoint(portOne))
                 .priority(PRIORITY_OFFSET)
                 .build());
 
@@ -226,8 +227,8 @@
                 .key(key)
                 .selector(selector)
                 .treatment(treatment)
-                .ingressPoint(portOne)
-                .egressPoint(portTwo)
+                .filteredIngressPoint(new FilteredConnectPoint(portOne))
+                .filteredEgressPoint(new FilteredConnectPoint(portTwo))
                 .priority(PRIORITY_OFFSET)
                 .build());
 
@@ -245,8 +246,8 @@
                 .key(key)
                 .selector(selector)
                 .treatment(treatment)
-                .ingressPoint(portTwo)
-                .egressPoint(portOne)
+                .filteredIngressPoint(new FilteredConnectPoint(portTwo))
+                .filteredEgressPoint(new FilteredConnectPoint(portOne))
                 .priority(PRIORITY_OFFSET)
                 .build());
 
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
index f3c5b6e..6f41005 100644
--- a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
@@ -163,6 +163,7 @@
                 break;
             case TWOOCTET:
                 maId = MaId2Octet.asMaId(nameParts[0]);
+                break;
             case CHARACTERSTRING:
             default:
                 maId = MaIdCharStr.asMaId(nameParts[0]);
diff --git a/apps/cip/src/main/java/org/onosproject/cip/ClusterIpManager.java b/apps/cip/src/main/java/org/onosproject/cip/ClusterIpManager.java
index f48b7f5..5dff893 100644
--- a/apps/cip/src/main/java/org/onosproject/cip/ClusterIpManager.java
+++ b/apps/cip/src/main/java/org/onosproject/cip/ClusterIpManager.java
@@ -182,6 +182,7 @@
             log.error("Unable to execute command {}", command, e);
         } catch (InterruptedException e) {
             log.error("Interrupted executing command {}", command, e);
+            Thread.currentThread().interrupt();
         }
     }
 
diff --git a/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java b/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
index bb562e8..25bceb8 100644
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
@@ -120,5 +120,15 @@
      * @return future that will be completed with RpcOutput
      * @throws FailedException if the RPC could not be invoked
      */
+    @Deprecated
     CompletableFuture<RpcOutput> invokeRpc(ResourceId id, RpcInput input);
+
+    /**
+     * Invokes an RPC.
+     *
+     * @param input RPC input with ResourceId and DataNode
+     * @return future that will be completed with RpcOutput
+     * @throws FailedException if the RPC could not be invoked
+     */
+    CompletableFuture<RpcOutput> invokeRpc(RpcInput input);
 }
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/DynamicConfigServiceAdapter.java b/apps/config/src/main/java/org/onosproject/config/DynamicConfigServiceAdapter.java
index 4dcd671..a74aaae 100644
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigServiceAdapter.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigServiceAdapter.java
@@ -69,6 +69,12 @@
     }
 
     @Override
+    public CompletableFuture<RpcOutput> invokeRpc(RpcInput input) {
+        //TODO: implement me, not sure about purpose of this adapter.
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void addListener(DynamicConfigListener listener) {
         listenerRegistry.addListener(listener);
     }
diff --git a/apps/config/src/main/java/org/onosproject/config/ForwardingDynamicConfigService.java b/apps/config/src/main/java/org/onosproject/config/ForwardingDynamicConfigService.java
index b8e9167..5fcdc04 100644
--- a/apps/config/src/main/java/org/onosproject/config/ForwardingDynamicConfigService.java
+++ b/apps/config/src/main/java/org/onosproject/config/ForwardingDynamicConfigService.java
@@ -85,4 +85,9 @@
                                                   RpcInput input) {
         return delegate.invokeRpc(id, input);
     }
+
+    @Override
+    public CompletableFuture<RpcOutput> invokeRpc(RpcInput input) {
+        return delegate.invokeRpc(input);
+    }
 }
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 50e807a..fe37697 100644
--- a/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
+++ b/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
@@ -80,12 +80,7 @@
 
     public static NodeKey getInstanceKey(ResourceId path) {
         int last = path.nodeKeys().size();
-        NodeKey ret = path.nodeKeys().get(last - 1);
-        if (ret instanceof NodeKey) {
-            return ret;
-        } else {
-            return null;
-        }
+        return path.nodeKeys().get(last - 1);
     }
 
     public static NodeKey getMultiInstanceKey(ResourceId path) {
@@ -281,7 +276,8 @@
                     String key = keys[i];
                     String[] el = keys[i].split(NM_CHK);
                     if (el.length != 3) {
-                        throw new FailedException("Malformed event subject, cannot parse");
+                        throw new FailedException("Malformed event subject, cannot parse " +
+                                                  key + " in " + dpath);
                     }
                     try {
                     resBldr.addKeyLeaf(el[0], el[1], el[2]);
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 8f1662c..c960646 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
@@ -50,6 +50,7 @@
 import org.onosproject.yang.model.KeyLeaf;
 import org.onosproject.yang.model.LeafListKey;
 import org.onosproject.yang.model.LeafNode;
+import org.onosproject.yang.model.LeafType;
 import org.onosproject.yang.model.ListKey;
 import org.onosproject.yang.model.NodeKey;
 import org.onosproject.yang.model.ResourceId;
@@ -110,7 +111,8 @@
                 .register(KeyLeaf.class)
                 .register(BigInteger.class)
                 .register(BigDecimal.class)
-                .register(LinkedHashMap.class);
+                .register(LinkedHashMap.class)
+                .register(LeafType.class);
         keystore = storageService.<DataNode.Type>documentTreeBuilder()
                 .withSerializer(Serializer.using(kryoBuilder.build()))
                 .withName("config-key-store")
@@ -309,14 +311,19 @@
                 DataNode.Type type = v.value();
                 String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
                 if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
-                    superBldr.createChildBuilder(name, nmSpc, readLeaf(tempPath).value())
+                    LeafNode lfnode = readLeaf(tempPath);
+                    // FIXME there should be builder for copying
+                    superBldr.createChildBuilder(name, nmSpc, lfnode.value(), lfnode.valueNamespace())
                             .type(type)
+                            .leafType(lfnode.leafType())
                             .exitNode();
                 } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
                     String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
                     LeafNode lfnode = readLeaf(mlpath);
-                    superBldr.createChildBuilder(name, nmSpc, lfnode.value())
+                    // FIXME there should be builder for copying
+                    superBldr.createChildBuilder(name, nmSpc, lfnode.value(), lfnode.valueNamespace())
                             .type(type)
+                            .leafType(lfnode.leafType())
                             .addLeafListValue(lfnode.value())
                             .exitNode();
                     //TODO this alone should be sufficient and take the nm, nmspc too
@@ -495,6 +502,7 @@
                     //log.info("UNKNOWN operation in store");
                     type = UNKNOWN_OPRN;
             }
+            // FIXME don't use ResourceIdParser
             path = ResourceIdParser.getResId(event.path().pathElements());
             notifyDelegate(new DynamicConfigEvent(type, path));
         }
diff --git a/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java b/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java
index d976a40..cdec56a 100644
--- a/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java
+++ b/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java
@@ -51,6 +51,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import org.slf4j.Logger;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.d.config.DeviceResourceIds.DCS_NAMESPACE;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -206,6 +207,21 @@
                                 context.rpcName(), RpcMessageId.generate(), input));
     }
 
+    @Override
+    public CompletableFuture<RpcOutput> invokeRpc(RpcInput input) {
+        checkNotNull(input);
+        checkNotNull(input.id());
+        RpcContext context = contextProvider.getRpcContext(input.id());
+        String srvcIntf = context.serviceIntf().getName();
+        RpcService handler = handlerRegistry.get(srvcIntf);
+        if (handler == null) {
+            throw new FailedException("No registered handler found, cannot invoke");
+        }
+        return CompletableFuture.supplyAsync(
+            new RpcExecutor(handler, getSvcId(handler, srvcIntf),
+                context.rpcName(), RpcMessageId.generate(), input));
+    }
+
     /**
      * Auxiliary store delegate to receive notification about changes in the store.
      */
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 c3f3e7b..2d25fcb 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
@@ -117,6 +117,11 @@
     }
 
     @Override
+    public CompletableFuture<RpcOutput> invokeRpc(RpcInput input) {
+        return super.invokeRpc(new RpcInput(toAbsoluteId(input.id()), input.data()));
+    }
+
+    @Override
     public void addListener(DynamicConfigListener listener) {
         super.addListener(wrapped.computeIfAbsent(listener,
                                                   DynamicDeviceConfigListener::new));
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 0d48e19..f5a8135 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
@@ -22,6 +22,7 @@
 import static org.onosproject.d.config.sync.operation.SetResponse.response;
 import static org.slf4j.LoggerFactory.getLogger;
 
+import java.time.Duration;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -89,6 +90,10 @@
 
     private DynamicConfigListener listener = new InnerDyConListener();
 
+    // FIXME hack for unconsolidated event bug
+    private Duration quietPeriod = Duration.ofSeconds(2);
+    private long quietUntil = 0;
+
     @Activate
     public void activate() {
         // TODO start background task to sync Controller and Device?
@@ -163,6 +168,12 @@
     }
 
     void processEventNonBatch(DynamicConfigEvent event) {
+        if (System.currentTimeMillis() < quietUntil) {
+            log.trace("Ignoring {}. Quiet period until {}",
+                      event, Tools.defaultOffsetDataTime(quietUntil));
+            return;
+        }
+
         ResourceId path = event.subject();
         if (isUnderDeviceRootNode(path)) {
             log.trace("processing event:{}", event);
@@ -209,6 +220,9 @@
                     log.error("Request to {} failed {}", deviceId, response, e);
                 }
             });
+
+            // FIXME hack for unconsolidated event bug
+            quietUntil = System.currentTimeMillis() + quietPeriod.toMillis();
         } else {
             log.warn("Ignored event's ResourceId: {}", event.subject());
         }
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 0cb3468..80d29fc 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -39,8 +39,11 @@
 import org.onlab.packet.TpPort;
 import org.onlab.packet.UDP;
 import org.onlab.packet.VlanId;
+import org.onlab.packet.dhcp.Dhcp6ClientDataOption;
+import org.onlab.packet.dhcp.Dhcp6LeaseQueryOption;
 import org.onlab.packet.dhcp.Dhcp6RelayOption;
 import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
+import org.onlab.packet.dhcp.Dhcp6Option;
 import org.onlab.packet.dhcp.Dhcp6IaNaOption;
 import org.onlab.packet.dhcp.Dhcp6IaTaOption;
 import org.onlab.packet.dhcp.Dhcp6IaPdOption;
@@ -102,8 +105,6 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.dhcprelay.Dhcp6HandlerUtil.InternalPacket;
-
-
 import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.Collection;
@@ -117,6 +118,7 @@
 import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
 import java.util.concurrent.Semaphore;
 
+
 @Component
 @Service
 @Property(name = "version", value = "6")
@@ -139,9 +141,18 @@
             .matchUdpSrc(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
             .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
             .build();
+    // lease query reply is from server to client (no relay in between) - so we need to
+    // catch that scenario also ..
+    private static final TrafficSelector LEASE_QUERY_RESPONSE_SELECTOR = DefaultTrafficSelector.builder()
+            .matchEthType(Ethernet.TYPE_IPV6)
+            .matchIPProtocol(IPv6.PROTOCOL_UDP)
+            .matchUdpSrc(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
+            .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
+            .build();
     static final Set<TrafficSelector> DHCP_SELECTORS = ImmutableSet.of(
             CLIENT_SERVER_SELECTOR,
-            SERVER_RELAY_SELECTOR
+            SERVER_RELAY_SELECTOR,
+            LEASE_QUERY_RESPONSE_SELECTOR
     );
     private static Logger log = LoggerFactory.getLogger(Dhcp6HandlerImpl.class);
 
@@ -182,11 +193,8 @@
     protected ApplicationId appId;
     protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
     private InternalHostListener hostListener = new InternalHostListener();
-
     private Boolean dhcpFpmEnabled = false;
-
     private Dhcp6HandlerUtil dhcp6HandlerUtil = new Dhcp6HandlerUtil();
-
     private List<DhcpServerInfo> defaultServerInfoList = Lists.newArrayList();
     private List<DhcpServerInfo> indirectServerInfoList = Lists.newArrayList();
     private class IpAddressInfo {
@@ -211,10 +219,12 @@
                             DHCP6.MsgType.RELEASE.value(),
                             DHCP6.MsgType.DECLINE.value(),
                             DHCP6.MsgType.CONFIRM.value(),
-                            DHCP6.MsgType.RELAY_FORW.value());
+                            DHCP6.MsgType.RELAY_FORW.value(),
+                            DHCP6.MsgType.LEASEQUERY.value());
     // SERVER message types
     public static final Set<Byte> MSG_TYPE_FROM_SERVER =
-            ImmutableSet.of(DHCP6.MsgType.RELAY_REPL.value());
+            ImmutableSet.of(DHCP6.MsgType.RELAY_REPL.value(),
+                            DHCP6.MsgType.LEASEQUERY_REPLY.value());
 
     @Activate
     protected void activate() {
@@ -267,7 +277,6 @@
             }
             processIgnoreVlanRule(deviceId, vlanId, ADD);
         });
-
         ignoredVlans.forEach((deviceId, vlanId) -> {
             if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
                 // not contains in new config, remove it
@@ -287,6 +296,160 @@
         });
     }
 
+    public DhcpRecord getDhcpRelayRecordFor(Ip6Address clientAddress) {
+
+        Collection<DhcpRecord>  records = dhcpRelayStore.getDhcpRecords();
+        DhcpRecord dr = null;
+        for (DhcpRecord e:records) {
+            if (e.ip6Address().isPresent()) {
+                if (e.ip6Address().get().equals(clientAddress)) {
+                    dr = e;
+                    break;
+                }
+            }
+        }
+        return dr;
+    }
+
+    public MacAddress findNextHopMacForIp6FromRelayStore(Ip6Address clientAddress,
+                                                         MacAddress clientMacAddress, VlanId vlanID) {
+
+        DhcpRecord dr = getDhcpRelayRecordFor(clientAddress);
+
+        if (dr != null) {
+           Optional<MacAddress> nextHopTempMac = dr.nextHopTemp();
+            if (nextHopTempMac.isPresent()) {
+                log.info("findNextHopForIp6FromRelayStore " + clientAddress + " got mac " + nextHopTempMac.toString());
+                return nextHopTempMac.get();
+            }
+        } else {
+            log.warn("findNextHopMacForIp6FromRelayStore could NOT find next hop for " + clientAddress);
+            return null;
+        }
+        return null;
+    }
+
+    public Ip6Address findNextHopIp6FromRelayStore(Ip6Address clientAddress) {
+
+        DhcpRecord dr = getDhcpRelayRecordFor(clientAddress);
+        if (dr != null) {
+            Optional<MacAddress> nextHopMac = dr.nextHop();
+            if (nextHopMac.isPresent()) {
+                // find the local ip6 from the host store
+                HostId gwHostId = HostId.hostId(nextHopMac.get(), dr.vlanId());
+                Host gwHost = hostService.getHost(gwHostId);
+                if (gwHost == null) {
+                    log.warn("Can't find next hop host ID {}", gwHostId);
+                    return null;
+                }
+                Ip6Address nextHopIp = gwHost.ipAddresses()
+                        .stream()
+                        .filter(IpAddress::isIp6)
+                        .filter(IpAddress::isLinkLocal)
+                        .map(IpAddress::getIp6Address)
+                        .findFirst()
+                        .orElse(null);
+
+                log.info("findNextHopIp6FromRelayStore " + clientAddress + " got mac " +
+                                 nextHopMac.toString() + " ip6 " + nextHopIp);
+                return nextHopIp;
+            }
+        } else {
+            log.warn("findNextHopIp6FromRelayStore could NOT find next hop for " + clientAddress);
+            return null;
+        }
+        return null;
+    }
+
+    private void setPotentialNextHopForIp6InRelayStore(Ip6Address clientAddress,
+                                                       VlanId vlanId, MacAddress nh) {
+        DhcpRecord dr = getDhcpRelayRecordFor(clientAddress);
+        if (dr != null) {
+            dr.nextHopTemp(nh);
+            log.debug("LQ6 potential NH mac " + nh.toString() + " UPDATED in RelayRecord client " + clientAddress);
+        } else {
+            log.warn("LQ6 potential NH mac" + nh.toString() +
+                             " NOT FOUND in RelayRecord for client - LQ rejected" + clientAddress);
+        }
+    }
+
+    public void handleLeaseQuery6ReplyMsg(PacketContext context, DHCP6 dhcp6Payload) {
+        ConnectPoint inPort = context.inPacket().receivedFrom();
+        log.info("Got LQV6-REPLY on port {}", inPort);
+        List<Dhcp6Option> lopt = dhcp6Payload.getOptions();
+        log.info("Options list: {}", lopt);
+        // find out if this lease is known is
+        Dhcp6ClientDataOption clientDataOption = dhcp6Payload.getOptions()
+                .stream()
+                .filter(opt -> opt instanceof Dhcp6ClientDataOption)
+                .map(pld -> (Dhcp6ClientDataOption) pld)
+                .findFirst()
+                .orElse(null);
+
+        if (clientDataOption == null) {
+            log.warn("clientDataOption option is not present, " +
+                             "lease is UNKNOWN - not adding any new route...");
+        } else {
+            Dhcp6IaAddressOption aiAddressOption = clientDataOption.getOptions()
+                    .stream()
+                    .filter(opt -> opt instanceof Dhcp6IaAddressOption)
+                    .map(pld -> (Dhcp6IaAddressOption) pld)
+                    .findFirst()
+                    .orElse(null);
+
+            Dhcp6ClientIdOption clientIdOption = clientDataOption.getOptions()
+                    .stream()
+                    .filter(opt -> opt instanceof Dhcp6ClientIdOption)
+                    .map(pld -> (Dhcp6ClientIdOption) pld)
+                    .findFirst()
+                    .orElse(null);
+
+            if (aiAddressOption == null) {
+                log.warn("clientDataOption from DHCP server does not " +
+                                 "contains Dhcp6IaAddressOption for the client - giving up...");
+            } else {
+                Ip6Address clientAddress = aiAddressOption.getIp6Address();
+                MacAddress clientMacAddress = MacAddress.valueOf(clientIdOption.getDuid().getLinkLayerAddress());
+                Ethernet packet = context.inPacket().parsed();
+                VlanId vlanId = VlanId.vlanId(packet.getVlanID());
+                MacAddress potentialNextHopMac =
+                        findNextHopMacForIp6FromRelayStore(clientAddress, clientMacAddress, vlanId);
+
+                if (potentialNextHopMac == null) {
+                    log.warn("Can't find next hop host mac for client {} mac:{}/{}",
+                             clientAddress, clientMacAddress, vlanId);
+                    return;
+                } else {
+                    log.info("Next hop mac for {}/{}/{} is {}", clientAddress,
+                             clientMacAddress, vlanId, potentialNextHopMac.toString());
+                }
+                // search the next hop in the hosts store
+                HostId gwHostId = HostId.hostId(potentialNextHopMac, vlanId);
+                Host gwHost = hostService.getHost(gwHostId);
+                if (gwHost == null) {
+                    log.warn("Can't find next hop host ID {}", gwHostId);
+                    return;
+                }
+                Ip6Address nextHopIp = gwHost.ipAddresses()
+                        .stream()
+                        .filter(IpAddress::isIp6)
+                        .filter(IpAddress::isLinkLocal)
+                        .map(IpAddress::getIp6Address)
+                        .findFirst()
+                        .orElse(null);
+                if (nextHopIp == null) {
+                    log.warn("Can't find IP6 address of next hop {}", gwHost);
+                    return;
+                }
+                log.info("client " + clientAddress + " is known !");
+                Route routeForIP6 = new Route(Route.Source.STATIC, clientAddress.toIpPrefix(), nextHopIp);
+                log.debug("updating route of Client for indirectly connected.");
+                log.debug("client ip: " + clientAddress + ", next hop ip6: " + nextHopIp);
+                routeStore.updateRoute(routeForIP6);
+            }
+        }
+    }
+
     @Override
     public void processDhcpPacket(PacketContext context, BasePacket payload) {
         checkNotNull(payload, "DHCP6 payload can't be null");
@@ -295,7 +458,8 @@
         Ethernet receivedPacket = context.inPacket().parsed();
 
         if (!configured()) {
-            log.warn("Missing DHCP6 relay server config. Abort packet processing dhcp6 payload {}", dhcp6Payload);
+            log.warn("Missing DHCP6 relay server config. " +
+                             "Abort packet processing dhcp6 payload {}", dhcp6Payload);
             return;
         }
         byte msgTypeVal = dhcp6Payload.getMsgType();
@@ -314,22 +478,47 @@
             return;
         }
 
-        if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) {
-
+        if (msgTypeVal == DHCP6.MsgType.LEASEQUERY.value()) {
             List<InternalPacket> ethernetClientPacket =
-                    processDhcp6PacketFromClient(context, receivedPacket, receivingInterfaces);
+                    processLQ6PacketFromClient(context, receivedPacket, receivingInterfaces, dhcp6Payload);
             for (InternalPacket internalPacket : ethernetClientPacket) {
                 forwardPacket(internalPacket);
             }
-        } else if (MSG_TYPE_FROM_SERVER.contains(msgTypeVal)) {
-            log.debug("calling processDhcp6PacketFromServer with RELAY_REPL {}", msgTypeVal);
+        } else if (msgTypeVal == DHCP6.MsgType.LEASEQUERY_REPLY.value()) {
+
+            IPv6 clientIpv6 = (IPv6) receivedPacket.getPayload();
+            UDP clientUdp = (UDP) clientIpv6.getPayload();
+            DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
+            Interface serverInterface = dhcp6HandlerUtil.directlyConnected(clientDhcp6) ?
+                    getServerInterface() : getIndirectServerInterface();
             InternalPacket ethernetPacketReply =
-                    processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces);
+                    dhcp6HandlerUtil.processLQ6PacketFromServer(
+                            defaultServerInfoList, indirectServerInfoList,
+                            serverInterface, interfaceService,
+                            hostService,
+                            context, receivedPacket, receivingInterfaces);
             if (ethernetPacketReply != null) {
                 forwardPacket(ethernetPacketReply);
             }
+            handleLeaseQuery6ReplyMsg(context, dhcp6Payload);
         } else {
-            log.warn("Not so fast, packet type {} not supported yet", msgTypeVal);
+            if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) {
+
+                List<InternalPacket> ethernetClientPacket =
+                        processDhcp6PacketFromClient(context, receivedPacket, receivingInterfaces);
+                for (InternalPacket internalPacket : ethernetClientPacket) {
+                    forwardPacket(internalPacket);
+                }
+            } else if (MSG_TYPE_FROM_SERVER.contains(msgTypeVal)) {
+                log.debug("calling processDhcp6PacketFromServer with RELAY_REPL {}", msgTypeVal);
+                InternalPacket ethernetPacketReply =
+                        processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces);
+                if (ethernetPacketReply != null) {
+                    forwardPacket(ethernetPacketReply);
+                }
+            } else {
+                log.warn("Not so fast, packet type {} not supported yet", msgTypeVal);
+            }
         }
     }
 
@@ -352,8 +541,6 @@
         // Do nothing here
     }
 
-
-
     //forward the packet to ConnectPoint where the DHCP server is attached.
     private void forwardPacket(InternalPacket packet) {
         //send Packetout to dhcp server connectpoint.
@@ -369,9 +556,6 @@
         } // if
     }
 
-
-
-
     /**
      * extract from dhcp6 packet client ipv6 address of given by dhcp server.
      *
@@ -422,6 +606,7 @@
         }
         return ipInfo;
     }
+
     /**
      * extract from dhcp6 packet Prefix prefix provided by dhcp server.
      *
@@ -500,6 +685,7 @@
 
         return clientIdOption;
     }
+
     /**
      * remove host or route and update dhcp relay record attributes.
      *
@@ -648,7 +834,7 @@
                 recordSemaphore.release();
             }
         } catch (InterruptedException e) {
-            e.printStackTrace();
+            Thread.currentThread().interrupt();
         }
     }
 
@@ -661,6 +847,7 @@
      * @param embeddedDhcp6 the dhcp6 payload within relay
      * @param srcMac client gw/host macAddress
      * @param clientInterface client interface
+     * @param dhcpServerIp6Address DHCP server IP
      */
     private void addHostOrRoute(boolean directConnFlag, ConnectPoint location, DHCP6 dhcp6Relay,
                                 DHCP6 embeddedDhcp6, MacAddress srcMac, Interface clientInterface) {
@@ -774,11 +961,11 @@
         if (leafMsgType == DHCP6.MsgType.REPLY.value()) {
             if (ipInfo != null) {
                 log.debug("IP6 address is being stored into dhcp-relay store.");
-                log.debug("IP6 address {}", HexString.toHexString(ipInfo.ip6Address.toOctets(), ":"));
+                log.debug("Client IP6 address {}", HexString.toHexString(ipInfo.ip6Address.toOctets(), ":"));
                 record.ip6Address(ipInfo.ip6Address);
                 record.updateAddrPrefTime(ipInfo.prefTime);
                 record.updateLastIp6Update();
-            } else {
+             } else {
                 log.debug("IP6 address is not returned from server. Maybe only PD is returned.");
             }
             if (pdInfo != null) {
@@ -807,10 +994,107 @@
                 recordSemaphore.release();
             }
         } catch (InterruptedException e) {
-            e.printStackTrace();
+            Thread.currentThread().interrupt();
         }
     }
 
+    private List<InternalPacket> processLQ6PacketFromClient(PacketContext context,
+                                                              Ethernet clientPacket,
+                                                              Set<Interface> clientInterfaces,
+                                                              DHCP6 dhcp6Payload) {
+        ConnectPoint inPort = context.inPacket().receivedFrom();
+        log.info("Got LQ-REQUEST V6 on port {}", inPort);
+        List<Dhcp6Option> lopt = dhcp6Payload.getOptions();
+        log.info("Options list: {}", lopt);
+        Dhcp6LeaseQueryOption lqoption = dhcp6Payload.getOptions()
+                .stream()
+                .filter(opt -> opt instanceof Dhcp6LeaseQueryOption)
+                .map(pld -> (Dhcp6LeaseQueryOption) pld)
+                .findFirst()
+                .orElse(null);
+
+        if (lqoption == null) {
+            // Can't find dhcp payload
+            log.warn("Can't find dhcp6 lease query message - aborting");
+            return null;
+        } else {
+            log.info("dhcp6 lqv6 options found: {}", lqoption);
+        }
+        log.warn("LQv6 for " + lqoption.linkAddress.toString() + " comes from " + inPort.toString());
+        Ethernet packet = context.inPacket().parsed();
+        Ip6Address clientAddress = lqoption.linkAddress;
+        IPv6 ipv6Packet = (IPv6) packet.getPayload();
+        Ip6Address nextHopIp = findNextHopIp6FromRelayStore(clientAddress);
+
+        // 1. only if there is a route to remove - remove it
+        if (nextHopIp != null) {
+            Route routeForIP6 = new Route(Route.Source.STATIC, clientAddress.toIpPrefix(), nextHopIp);
+            log.debug("Removing route of Client " + clientAddress +
+                              " for indirectly connected - next hop ip6 " + nextHopIp);
+            routeStore.removeRoute(routeForIP6);
+        }
+
+        // 2. note the potential NH this packet came from in case it's a known lease
+        //    this NH will then be used to build the route
+        MacAddress potentialNH = packet.getSourceMAC();
+        VlanId vlanId = VlanId.vlanId(packet.getVlanID());
+        setPotentialNextHopForIp6InRelayStore(clientAddress, vlanId, potentialNH);
+
+        // 3. route this LQ6 to all relevant servers
+        IPv6 clientIpv6 = (IPv6) clientPacket.getPayload();
+        UDP clientUdp = (UDP) clientIpv6.getPayload();
+        DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
+
+        boolean directConnFlag = dhcp6HandlerUtil.directlyConnected(clientDhcp6);
+
+        ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom();
+        VlanId vlanIdInUse = VlanId.vlanId(clientPacket.getVlanID());
+        Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
+                .stream().filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse))
+                .findFirst()
+                .orElse(null);
+
+        List<InternalPacket> internalPackets = new ArrayList<>();
+        List<DhcpServerInfo> serverInfoList = findValidServerInfo(directConnFlag);
+        List<DhcpServerInfo> copyServerInfoList = new ArrayList<DhcpServerInfo>(serverInfoList);
+
+        for (DhcpServerInfo serverInfo : copyServerInfoList) {
+            if (!dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) {
+                log.warn("Can't get server connect point, ignore");
+                continue;
+            }
+            DhcpServerInfo newServerInfo = getHostInfoForServerInfo(serverInfo, serverInfoList);
+            if (newServerInfo == null) {
+                log.warn("Can't get server interface with host info resolved, ignore");
+                continue;
+            }
+
+            Interface serverInterface = getServerInterface(newServerInfo);
+            if (serverInterface == null) {
+                log.warn("Can't get server interface, ignore");
+                continue;
+            }
+
+
+            Ethernet etherRouted = (Ethernet) clientPacket.clone();
+            MacAddress macFacingServer = serverInterface.mac();
+            if (macFacingServer == null) {
+                log.warn("No MAC address for server Interface {}", serverInterface);
+                return null;
+            }
+            etherRouted.setSourceMACAddress(macFacingServer);
+            etherRouted.setDestinationMACAddress(newServerInfo.getDhcpConnectMac().get());
+            InternalPacket internalPacket =
+                    new Dhcp6HandlerUtil().new InternalPacket(etherRouted,
+                              serverInfo.getDhcpServerConnectPoint().get());
+            internalPackets.add(internalPacket);
+            log.debug("Sending LQ to DHCP server {}", newServerInfo.getDhcpServerIp6());
+        }
+        log.debug("num of client packets to send is{}", internalPackets.size());
+
+        return internalPackets;
+    }
+
     /**
      * build the DHCP6 solicit/request packet with gatewayip.
      *
@@ -980,7 +1264,9 @@
             udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
         }
         // add host or route
-        addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6, clientMac, clientInterface);
+        addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6,
+                       clientMac, clientInterface);
+
 
         udpPacket.setPayload(embeddedDhcp6);
         udpPacket.resetChecksum();
@@ -989,6 +1275,19 @@
         return new Dhcp6HandlerUtil().new InternalPacket(etherReply, clientConnectionPoint);
     }
 
+    // Returns the first v6 interface ip out of a set of interfaces or null.
+    // Checks all interfaces, and ignores v6 interface ips
+    private Ip6Address getRelayAgentIPv6Address(Set<Interface> intfs) {
+        for (Interface intf : intfs) {
+            for (InterfaceIpAddress ip : intf.ipAddressesList()) {
+                Ip6Address relayAgentIp = ip.ipAddress().getIp6Address();
+                if (relayAgentIp != null) {
+                    return relayAgentIp;
+                }
+            }
+        }
+        return null;
+    }
 
     @Override
     public void setDhcpFpmEnabled(Boolean enabled) {
@@ -1131,7 +1430,6 @@
             }
         }
     }
-
     /**
      * Handle host removed.
      * If the host is DHCP server or gateway, unset connect mac and vlan.
@@ -1181,6 +1479,65 @@
                 .findFirst()
                 .orElse(null);
     }
+
+   /**
+     * Gets Interface facing to the server for default host.
+     *
+     * @return the Interface facing to the server; null if not found
+     */
+    private Interface getServerInterface() {
+        DhcpServerInfo serverInfo;
+        ConnectPoint dhcpServerConnectPoint;
+        VlanId dhcpConnectVlan;
+
+        if (!defaultServerInfoList.isEmpty()) {
+            serverInfo = defaultServerInfoList.get(0);
+            dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
+            dhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
+        } else {
+            return null;
+        }
+        if (dhcpServerConnectPoint == null || dhcpConnectVlan == null) {
+            log.info("Default DHCP server {} not resolve yet", serverInfo.getDhcpGatewayIp6());
+            return null;
+        }
+        return interfaceService.getInterfacesByPort(dhcpServerConnectPoint)
+                .stream()
+                .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan))
+                .findFirst()
+                .orElse(null);
+    }
+
+    /**
+     * Gets Interface facing to the server for indirect hosts.
+     * Use default server Interface if indirect server not configured.
+     *
+     * @return the Interface facing to the server; null if not found
+     */
+    private Interface getIndirectServerInterface() {
+        DhcpServerInfo serverInfo;
+
+        ConnectPoint indirectDhcpServerConnectPoint;
+        VlanId indirectDhcpConnectVlan;
+
+        if (!indirectServerInfoList.isEmpty()) {
+            serverInfo = indirectServerInfoList.get(0);
+            indirectDhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
+            indirectDhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
+        } else {
+            return getServerInterface();
+        }
+        if (indirectDhcpServerConnectPoint == null || indirectDhcpConnectVlan == null) {
+            log.info("Indirect DHCP server {} not resolve yet", serverInfo.getDhcpGatewayIp6());
+            return null;
+        }
+        return interfaceService.getInterfacesByPort(indirectDhcpServerConnectPoint)
+                .stream()
+                .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, indirectDhcpConnectVlan))
+                .findFirst()
+                .orElse(null);
+    }
+
     /**
      * Checks if serverInfo's host info (mac and vlan) is filled in; if not, fills in.
      *
@@ -1256,15 +1613,16 @@
         return serverInterface;
     }
 
-
     private void requestDhcpPacket(Ip6Address serverIp) {
         requestServerDhcpPacket(serverIp);
         requestClientDhcpPacket(serverIp);
+        requestServerLQPacket(serverIp);
     }
 
     private void cancelDhcpPacket(Ip6Address serverIp) {
         cancelServerDhcpPacket(serverIp);
         cancelClientDhcpPacket(serverIp);
+        cancelServerLQPacket(serverIp);
     }
 
     private void cancelServerDhcpPacket(Ip6Address serverIp) {
@@ -1277,6 +1635,16 @@
                                     appId);
     }
 
+    private void cancelServerLQPacket(Ip6Address serverIp) {
+        TrafficSelector serverSelector =
+                DefaultTrafficSelector.builder(LEASE_QUERY_RESPONSE_SELECTOR)
+                        .matchIPv6Src(serverIp.toIpPrefix())
+                        .build();
+        packetService.cancelPackets(serverSelector,
+                                    PacketPriority.CONTROL,
+                                    appId);
+    }
+
     private void requestServerDhcpPacket(Ip6Address serverIp) {
         TrafficSelector serverSelector =
                 DefaultTrafficSelector.builder(SERVER_RELAY_SELECTOR)
@@ -1287,6 +1655,16 @@
                                      appId);
     }
 
+    private void requestServerLQPacket(Ip6Address serverIp) {
+        TrafficSelector serverSelector =
+                DefaultTrafficSelector.builder(LEASE_QUERY_RESPONSE_SELECTOR)
+                        .matchIPv6Src(serverIp.toIpPrefix())
+                        .build();
+        packetService.requestPackets(serverSelector,
+                                     PacketPriority.CONTROL,
+                                     appId);
+    }
+
     private void cancelClientDhcpPacket(Ip6Address serverIp) {
         // Packet comes from relay
         TrafficSelector indirectClientSelector =
@@ -1419,6 +1797,7 @@
             flowObjectiveService.apply(deviceId, fwd);
         });
     }
+
     /**
      * Find first ipaddress for a given Host info i.e.  mac and vlan.
      *
@@ -1481,6 +1860,7 @@
         }
         return foundServerInfo;
     }
+
     /**
      * Set the dhcp6 lease expiry poll interval value.
      *
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java
index 6e47a0d..17456f9 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerUtil.java
@@ -44,8 +44,11 @@
 import java.util.Set;
 import java.util.List;
 import java.util.ArrayList;
+import org.onosproject.net.intf.InterfaceService;
 
-
+import org.onosproject.net.Host;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.HostLocation;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -69,6 +72,127 @@
     }
 
     /**
+     *
+     * process the LQ reply packet from dhcp server.
+     *
+     * @param defaultServerInfoList default server list
+     * @param indirectServerInfoList default indirect server list
+     * @param serverInterface server interface
+     * @param interfaceService interface service
+     * @param hostService host service
+     * @param context packet context
+     * @param receivedPacket server ethernet packet
+     * @param recevingInterfaces set of server side interfaces
+     * @return a packet ready to be sent to relevant output interface
+     */
+    public InternalPacket processLQ6PacketFromServer(
+            List<DhcpServerInfo> defaultServerInfoList,
+            List<DhcpServerInfo> indirectServerInfoList,
+            Interface serverInterface,
+            InterfaceService interfaceService,
+            HostService hostService,
+            PacketContext context,
+            Ethernet receivedPacket, Set<Interface> recevingInterfaces) {
+        // get dhcp6 header.
+        Ethernet etherReply = (Ethernet) receivedPacket.clone();
+        IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
+        UDP udpPacket = (UDP) ipv6Packet.getPayload();
+        DHCP6 lq6Reply = (DHCP6) udpPacket.getPayload();
+
+        // TODO: refactor
+        ConnectPoint receivedFrom = context.inPacket().receivedFrom();
+        DeviceId receivedFromDevice = receivedFrom.deviceId();
+        DhcpServerInfo serverInfo;
+        Ip6Address dhcpServerIp = null;
+        ConnectPoint dhcpServerConnectPoint = null;
+        MacAddress dhcpConnectMac = null;
+        VlanId dhcpConnectVlan = null;
+        Ip6Address dhcpGatewayIp = null;
+
+        // todo: refactor
+        Ip6Address indirectDhcpServerIp = null;
+        ConnectPoint indirectDhcpServerConnectPoint = null;
+        MacAddress indirectDhcpConnectMac = null;
+        VlanId indirectDhcpConnectVlan = null;
+        Ip6Address indirectDhcpGatewayIp = null;
+        Ip6Address indirectRelayAgentIpFromCfg = null;
+
+        if (!defaultServerInfoList.isEmpty()) {
+            serverInfo = defaultServerInfoList.get(0);
+            dhcpConnectMac = serverInfo.getDhcpConnectMac().orElse(null);
+            dhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
+            dhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
+            dhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
+            dhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
+        }
+
+        if (!indirectServerInfoList.isEmpty()) {
+            serverInfo = indirectServerInfoList.get(0);
+            indirectDhcpConnectMac = serverInfo.getDhcpConnectMac().orElse(null);
+            indirectDhcpGatewayIp = serverInfo.getDhcpGatewayIp6().orElse(null);
+            indirectDhcpServerIp = serverInfo.getDhcpServerIp6().orElse(null);
+            indirectDhcpServerConnectPoint = serverInfo.getDhcpServerConnectPoint().orElse(null);
+            indirectDhcpConnectVlan = serverInfo.getDhcpConnectVlan().orElse(null);
+            indirectRelayAgentIpFromCfg = serverInfo.getRelayAgentIp6(receivedFromDevice).orElse(null);
+        }
+
+        Boolean directConnFlag = directlyConnected(lq6Reply);
+        ConnectPoint inPort = context.inPacket().receivedFrom();
+        if ((directConnFlag || (!directConnFlag && indirectDhcpServerIp == null))
+                && !inPort.equals(dhcpServerConnectPoint)) {
+            log.warn("Receiving port {} is not the same as server connect point {} for direct or indirect-null",
+                     inPort, dhcpServerConnectPoint);
+            return null;
+        }
+
+        if (!directConnFlag && indirectDhcpServerIp != null &&
+                !inPort.equals(indirectDhcpServerConnectPoint)) {
+            log.warn("Receiving port {} is not the same as server connect point {} for indirect",
+                     inPort, indirectDhcpServerConnectPoint);
+            return null;
+        }
+
+
+        Ip6Address nextHopIP =  Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
+        // use hosts store to find out the next hop mac and connection point
+        Set<Host> hosts = hostService.getHostsByIp(nextHopIP);
+        Host host;
+        if (!hosts.isEmpty()) {
+            host = hosts.iterator().next();
+        } else {
+            log.warn("Host {} is not in store", nextHopIP);
+            return null;
+        }
+
+        HostLocation hl = host.location();
+        String clientConnectionPointStr = hl.toString(); // iterator().next());
+        ConnectPoint clientConnectionPoint = ConnectPoint.deviceConnectPoint(clientConnectionPointStr);
+
+
+        VlanId originalPacketVlanId = VlanId.vlanId(etherReply.getVlanID());
+        Interface iface;
+        iface = interfaceService.getInterfacesByPort(clientConnectionPoint)
+                .stream()
+                .filter(iface1 -> interfaceContainsVlan(iface1, originalPacketVlanId))
+                .findFirst()
+                .orElse(null);
+
+        etherReply.setSourceMACAddress(iface.mac());
+        etherReply.setDestinationMACAddress(host.mac());
+
+
+        // add host or route
+        //addHostOrRoute(directConnFlag, clientConnectionPoint, lq6Reply, embeddedDhcp6, clientMac, clientInterface);
+        // workaround for a bug where core sends src port as 547 (server)
+        udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
+        udpPacket.setPayload(lq6Reply);
+        udpPacket.resetChecksum();
+        ipv6Packet.setPayload(udpPacket);
+        etherReply.setPayload(ipv6Packet);
+
+        return new Dhcp6HandlerUtil().new InternalPacket(etherReply, clientConnectionPoint);
+    }
+    /**
      * Returns the first interface ip from interface.
      *
      * @param iface interface of one connect point
@@ -258,7 +382,14 @@
      * @return true if the host is directly connected to the network; false otherwise
      */
     public boolean directlyConnected(DHCP6 dhcp6Payload) {
+
         log.debug("directlyConnected enters");
+        if (dhcp6Payload.getMsgType() == DHCP6.MsgType.LEASEQUERY.value() ||
+                dhcp6Payload.getMsgType() == DHCP6.MsgType.LEASEQUERY_REPLY.value()) {
+            log.debug("directlyConnected false. MsgType {}", dhcp6Payload.getMsgType());
+
+            return false;
+        }
 
         if (dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_FORW.value() &&
                 dhcp6Payload.getMsgType() != DHCP6.MsgType.RELAY_REPL.value()) {
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 39123ac..2c4b89d 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -625,6 +625,7 @@
                     break;
                 case DEVICE_AVAILABILITY_CHANGED:
                     deviceAvailabilityChanged(device);
+                    break;
                 default:
                     break;
             }
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpRecord.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpRecord.java
index 44c6c3c..e4c2673 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpRecord.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpRecord.java
@@ -53,7 +53,6 @@
     private IpPrefix pdPrefix;
     private DHCP6.MsgType ip6Status;
 
-
     private long lastSeen;
     private long lastIp6Update;
     private long lastPdUpdate;
@@ -418,7 +417,6 @@
         newRecord.addrPrefTime = addrPrefTime;
         newRecord.pdPrefTime = pdPrefTime;
         newRecord.v6Counters = v6Counters;
-
         return newRecord;
     }
 
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnRouteManager.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnRouteManager.java
index 28abb7d..3c9f223 100644
--- a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnRouteManager.java
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnRouteManager.java
@@ -226,6 +226,7 @@
                     listener.event(queue.take());
                 } catch (InterruptedException e) {
                     log.info("Route listener event thread shutting down: {}", e.getMessage());
+                    Thread.currentThread().interrupt();
                     break;
                 } catch (Exception e) {
                     log.warn("Exception during route event handler", e);
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java
index 562171b..7a87fd5 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java
@@ -807,15 +807,16 @@
 
         @Override
         public void event(EvpnRouteEvent event) {
-            if (!(event.subject() instanceof EvpnRoute)) {
+            if (event.subject() != null) {
+                EvpnRoute route = (EvpnRoute) event.subject();
+                if (EvpnRouteEvent.Type.ROUTE_ADDED == event.type()) {
+                    onBgpEvpnRouteUpdate(route);
+                } else if (EvpnRouteEvent.Type.ROUTE_REMOVED == event.type()) {
+                    onBgpEvpnRouteDelete(route);
+                }
+            } else {
                 return;
             }
-            EvpnRoute route = (EvpnRoute) event.subject();
-            if (EvpnRouteEvent.Type.ROUTE_ADDED == event.type()) {
-                onBgpEvpnRouteUpdate(route);
-            } else if (EvpnRouteEvent.Type.ROUTE_REMOVED == event.type()) {
-                onBgpEvpnRouteDelete(route);
-            }
         }
     }
 
diff --git a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java
index f12bacb..74ed2c2 100644
--- a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java
+++ b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java
@@ -107,21 +107,6 @@
         return true;
     }
 
-    //TODO maybe map for field to update ?
-    @Override
-    public Alarm updateBookkeepingFields(AlarmId id, boolean isAcknowledged, String assignedUser) {
-        Alarm found = store.getAlarm(id);
-        if (found == null) {
-            throw new ItemNotFoundException("Alarm with id " + id + " found");
-        }
-        Alarm updated = new DefaultAlarm.Builder(found)
-                .withId(found.id())
-                .withAcknowledged(isAcknowledged)
-                .withAssignedUser(assignedUser).build();
-        store.createOrUpdateAlarm(updated);
-        return updated;
-    }
-
     @Override
     public Alarm updateBookkeepingFields(AlarmId id, boolean clear, boolean isAcknowledged,
                                          String assignedUser) {
diff --git a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/PollingAlarmProvider.java b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/PollingAlarmProvider.java
index 7222bac..c74934c 100644
--- a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/PollingAlarmProvider.java
+++ b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/PollingAlarmProvider.java
@@ -22,6 +22,7 @@
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderRegistry;
@@ -70,6 +71,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected AlarmProviderRegistry providerRegistry;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
     protected AlarmProviderService providerService;
 
     protected ScheduledExecutorService alarmsExecutor;
@@ -101,6 +105,7 @@
 
     @Activate
     public void activate(ComponentContext context) {
+        cfgService.registerProperties(getClass());
         alarmsExecutor = newScheduledThreadPool(CORE_POOL_SIZE,
                                                 groupedThreads("onos/pollingalarmprovider",
                                                                "alarm-executor-%d", log));
@@ -127,6 +132,7 @@
 
     @Deactivate
     public void deactivate() {
+        cfgService.unregisterProperties(getClass(), false);
         providerRegistry.unregister(this);
         mastershipService.removeListener(mastershipListener);
         deviceService.removeListener(deviceListener);
diff --git a/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/PollingAlarmProviderTest.java b/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/PollingAlarmProviderTest.java
index b2f2469..560203b 100644
--- a/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/PollingAlarmProviderTest.java
+++ b/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/PollingAlarmProviderTest.java
@@ -22,6 +22,8 @@
 import org.junit.Test;
 import org.onlab.osgi.ComponentContextAdapter;
 import org.onlab.packet.ChassisId;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.cluster.RoleInfo;
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
@@ -80,6 +82,8 @@
 
     private final AlarmProviderService alarmProviderService = new MockAlarmProviderService();
 
+    private final ComponentConfigService cfgService = new ComponentConfigAdapter();
+
     private final ComponentContext context = new MockComponentContext();
 
     private static final DeviceId DEVICE_ID = DeviceId.deviceId("foo:1.1.1.1:1");
@@ -114,6 +118,7 @@
         provider.providerRegistry = providerRegistry;
         provider.deviceService = deviceService;
         provider.mastershipService = mastershipService;
+        provider.cfgService = cfgService;
         AbstractProjectableModel.setDriverService(null, new DriverServiceAdapter());
         provider.activate(context);
     }
diff --git a/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java b/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java
index 004f45b..1963b7c 100644
--- a/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java
+++ b/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java
@@ -134,7 +134,7 @@
 
             }
             Alarm updated = service.updateBookkeepingFields(
-                    alarm.id(), alarm.acknowledged(), alarm.assignedUser()
+                    alarm.id(), alarm.cleared(), alarm.acknowledged(), alarm.assignedUser()
             );
             ObjectNode encoded = new AlarmCodec().encode(updated, this);
             return ok(encoded.toString()).build();
diff --git a/apps/intentsync/src/main/java/org/onosproject/intentsync/IntentSynchronizer.java b/apps/intentsync/src/main/java/org/onosproject/intentsync/IntentSynchronizer.java
index 6561bca..c15ea3c 100644
--- a/apps/intentsync/src/main/java/org/onosproject/intentsync/IntentSynchronizer.java
+++ b/apps/intentsync/src/main/java/org/onosproject/intentsync/IntentSynchronizer.java
@@ -305,6 +305,7 @@
                     log.info("IntentSynchronizer leader changed. New leader is {}", event.subject().leaderNodeId());
                     leaderChanged(false);
                 }
+                break;
             default:
                 break;
             }
diff --git a/apps/kafka-integration/app/src/main/java/org/onosproject/kafkaintegration/impl/KafkaStorageManager.java b/apps/kafka-integration/app/src/main/java/org/onosproject/kafkaintegration/impl/KafkaStorageManager.java
index 66bfc18..19e58ca 100644
--- a/apps/kafka-integration/app/src/main/java/org/onosproject/kafkaintegration/impl/KafkaStorageManager.java
+++ b/apps/kafka-integration/app/src/main/java/org/onosproject/kafkaintegration/impl/KafkaStorageManager.java
@@ -77,9 +77,9 @@
         try {
             task = future.get();
         } catch (InterruptedException e) {
-            e.printStackTrace();
+            Thread.currentThread().interrupt();
         } catch (ExecutionException e) {
-            e.printStackTrace();
+            log.warn("consumeEvent()", e);
         }
 
         if (task != null) {
diff --git a/apps/l3vpn/src/main/java/org/onosproject/l3vpn/netl3vpn/impl/NetL3VpnManager.java b/apps/l3vpn/src/main/java/org/onosproject/l3vpn/netl3vpn/impl/NetL3VpnManager.java
index 45e9f9b..b7d4ddd 100644
--- a/apps/l3vpn/src/main/java/org/onosproject/l3vpn/netl3vpn/impl/NetL3VpnManager.java
+++ b/apps/l3vpn/src/main/java/org/onosproject/l3vpn/netl3vpn/impl/NetL3VpnManager.java
@@ -1094,6 +1094,7 @@
                                          .leaderNodeId());
                         leaderChanged(false);
                     }
+                    break;
                 default:
                     break;
             }
diff --git a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java
index 92043d5..33b52a4 100644
--- a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java
+++ b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java
@@ -194,7 +194,7 @@
             return netconfTranslator.editDeviceConfig(
                     deviceId, builder.build(), operationType);
         } catch (IOException e) {
-            e.printStackTrace();
+            log.debug("parseAndEdit()", e);
             return false;
         }
     }
diff --git a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java
index c563204..f663fd0 100644
--- a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java
+++ b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java
@@ -93,8 +93,8 @@
 @Component(immediate = true)
 public class NetconfTranslatorImpl implements NetconfTranslator {
 
-    private final Logger log = LoggerFactory
-            .getLogger(getClass());
+    private static final Logger log = LoggerFactory
+            .getLogger(NetconfTranslator.class);
 
     private NodeId localNodeId;
 
@@ -354,7 +354,7 @@
             try {
                 rIdBldr = rid.copyBuilder();
             } catch (CloneNotSupportedException e) {
-                e.printStackTrace();
+                log.debug("clone not supported", e);
             }
         } else {
             rIdBldr.addBranchPointSchema("/", null);
diff --git a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/Utils.java b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/Utils.java
index cb8e89c..5e06420 100644
--- a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/Utils.java
+++ b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/Utils.java
@@ -108,7 +108,7 @@
         try {
             transformer = transformerFactory.newTransformer();
         } catch (TransformerConfigurationException e) {
-            e.printStackTrace();
+            return "";
         }
 
         // Need to omit the xml header and set indent to 4
@@ -122,7 +122,7 @@
             try {
                 transformer.transform(xmlInput, xmlOutput);
             } catch (TransformerException e) {
-                e.printStackTrace();
+                return "";
             }
         }
         return xmlOutput.getWriter().toString();
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageEncoder.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageEncoder.java
index 256970d..060cb4a 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageEncoder.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageEncoder.java
@@ -26,8 +26,7 @@
 public final class OFMessageEncoder extends MessageToByteEncoder<Iterable<OFMessage>> {
 
     @Override
-    protected void encode(ChannelHandlerContext ctx, Iterable<OFMessage> msgList, ByteBuf out)
-            throws Exception {
+    protected void encode(ChannelHandlerContext ctx, Iterable<OFMessage> msgList, ByteBuf out) {
         if (!ctx.channel().isActive()) {
             return;
         }
diff --git a/apps/openstacknetworking/BUCK b/apps/openstacknetworking/BUCK
index 4a5d19c..f6a3a5d 100644
--- a/apps/openstacknetworking/BUCK
+++ b/apps/openstacknetworking/BUCK
@@ -1,14 +1,20 @@
 COMPILE_DEPS = [
-  '//lib:CORE_DEPS',
-  '//lib:JACKSON',
-  '//lib:KRYO',
-  '//core/store/serializers:onos-core-serializers',
-  '//lib:org.apache.karaf.shell.console',
-  '//lib:javax.ws.rs-api',
-  '//utils/rest:onlab-rest',
-  '//cli:onos-cli',
-  '//apps/openstacknode/api:onos-apps-openstacknode-api',
-  '//lib:openstack4j-core',
+    '//lib:CORE_DEPS',
+    '//lib:JACKSON',
+    '//lib:KRYO',
+    '//core/store/serializers:onos-core-serializers',
+    '//lib:org.apache.karaf.shell.console',
+    '//lib:javax.ws.rs-api',
+    '//utils/rest:onlab-rest',
+    '//cli:onos-cli',
+    '//apps/openstacknode/api:onos-apps-openstacknode-api',
+    '//lib:openstack4j-core',
+    '//lib:openstack4j-http-connector',
+    '//lib:openstack4j-httpclient',
+    '//lib:json-patch',
+    '//lib:jackson-coreutils',
+    '//lib:btf',
+    '//lib:msg-simple',
 ]
 
 TEST_DEPS = [
@@ -17,23 +23,43 @@
     '//core/common:onos-core-common-tests',
 ]
 
+BUNDLES = [
+    '//apps/openstacknetworking:onos-apps-openstacknetworking',
+]
+
+EXCLUDED_BUNDLES = [
+    '//lib:openstack4j-core',
+    '//lib:openstack4j-http-connector',
+    '//lib:openstack4j-httpclient',
+    '//lib:json-patch',
+    '//lib:jackson-coreutils',
+    '//lib:btf',
+    '//lib:msg-simple',
+    '//lib:spifly-bundle',
+    '//lib:spifly-weaver',
+    '//lib:spifly-core',
+    '//lib:aries-util',
+]
+
 osgi_jar_with_tests (
-  deps = COMPILE_DEPS,
-  test_deps = TEST_DEPS,
-  web_context = '/onos/openstacknetworking',
-  api_title = 'OpenStack Networking API',
-  api_version = '1.0',
-  api_description = 'REST API for OpenStack Networking',
-  api_package = 'org.onosproject.openstacknetworking.web',
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+    web_context = '/onos/openstacknetworking',
+    api_title = 'OpenStack Networking API',
+    api_version = '1.0',
+    api_description = 'REST API for OpenStack Networking',
+    api_package = 'org.onosproject.openstacknetworking.web',
 )
 
 onos_app (
-  app_name = 'org.onosproject.openstacknetworking',
-  title = 'OpenStack Networking',
-  category = 'Utility',
-  url = 'http://onosproject.org',
-  description = 'OpenStack Networking application.',
-  required_apps = [
-    'org.onosproject.openstacknode'
-  ]
+    app_name = 'org.onosproject.openstacknetworking',
+    title = 'OpenStack Networking',
+    category = 'Utility',
+    url = 'http://onosproject.org',
+    included_bundles = BUNDLES,
+    excluded_bundles = EXCLUDED_BUNDLES,
+    description = 'OpenStack Networking application.',
+    required_apps = [
+        'org.onosproject.openstacknode'
+    ]
 )
diff --git a/apps/openstacknetworking/app.xml b/apps/openstacknetworking/app.xml
new file mode 100644
index 0000000..2f8c3db
--- /dev/null
+++ b/apps/openstacknetworking/app.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2018-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.
+  -->
+<app name="org.onosproject.openstacknetworking" origin="ON.Lab" version="${project.version}"
+     category="Traffic Steering" url="http://onosproject.org" title="OpenStack Networking App"
+     featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
+     features="${project.artifactId}">
+    <description>${project.description}</description>
+    <artifact>mvn:${project.groupId}/onos-apps-openstacknetworking/${project.version}</artifact>
+</app>
diff --git a/apps/openstacknetworking/features.xml b/apps/openstacknetworking/features.xml
new file mode 100644
index 0000000..4ae8836
--- /dev/null
+++ b/apps/openstacknetworking/features.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ Copyright 2018-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.
+  -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+    <feature name="${project.artifactId}" version="${project.version}"
+             description="${project.description}">
+        <feature>onos-api</feature>
+        <bundle>mvn:${project.groupId}/onos-apps-openstacknetworking/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-apps-openstacknode-api/${project.version}</bundle>
+    </feature>
+</features>
diff --git a/apps/openstacknetworking/pom.xml b/apps/openstacknetworking/pom.xml
index d3f08d6..516ba82 100644
--- a/apps/openstacknetworking/pom.xml
+++ b/apps/openstacknetworking/pom.xml
@@ -150,17 +150,42 @@
         <dependency>
             <groupId>org.pacesys</groupId>
             <artifactId>openstack4j-core</artifactId>
-            <version>2.11</version>
+            <version>3.1.0</version>
         </dependency>
         <dependency>
             <groupId>org.pacesys.openstack4j.connectors</groupId>
             <artifactId>openstack4j-http-connector</artifactId>
-            <version>2.11</version>
+            <version>3.1.0</version>
         </dependency>
         <dependency>
             <groupId>org.pacesys.openstack4j.connectors</groupId>
             <artifactId>openstack4j-httpclient</artifactId>
-            <version>2.11</version>
+            <version>3.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>json-patch</artifactId>
+            <version>1.9</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>jackson-coreutils</artifactId>
+            <version>1.6</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>btf</artifactId>
+            <version>1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>msg-simple</artifactId>
+            <version>1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+            <version>1.15</version>
         </dependency>
     </dependencies>
 
@@ -212,7 +237,12 @@
                         <Embed-Dependency>
                             openstack4j-core,
                             openstack4j-http-connector,
-                            openstack4j-httpclient
+                            openstack4j-httpclient,
+                            json-patch,
+                            jackson-coreutils,
+                            btf,
+                            msg-simple,
+                            snakeyaml
                         </Embed-Dependency>
                     </instructions>
                 </configuration>
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
index 24308ff..e89141b 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
@@ -28,7 +28,7 @@
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
 import org.openstack4j.api.OSClient;
 import org.openstack4j.api.exceptions.AuthenticationException;
-import org.openstack4j.model.identity.Access;
+import org.openstack4j.model.identity.v2.Access;
 import org.openstack4j.model.network.IP;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
@@ -90,7 +90,7 @@
 
         Access osAccess;
         try {
-            osAccess = OSFactory.builder()
+            osAccess = OSFactory.builderV2()
                     .endpoint(this.endpoint)
                     .tenantName(this.tenant)
                     .credentials(this.user, this.password)
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java
index 3b7b38c..8e03ba5 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java
@@ -38,6 +38,8 @@
 import org.onosproject.store.service.StorageService;
 import org.onosproject.store.service.Versioned;
 import org.openstack4j.model.network.IPVersionType;
+import org.openstack4j.model.network.Ipv6AddressMode;
+import org.openstack4j.model.network.Ipv6RaMode;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
@@ -95,6 +97,8 @@
             .register(NeutronPool.class)
             .register(NeutronHostRoute.class)
             .register(IPVersionType.class)
+            .register(Ipv6AddressMode.class)
+            .register(Ipv6RaMode.class)
             .build();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index 0e4f7ab..64141b2 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -248,6 +248,7 @@
                                 event.subject().id());
                         processPortRemoved(event.port());
                     });
+                    break;
                 default:
                     break;
             }
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
index 0341aea..0132d35 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
@@ -66,6 +66,7 @@
      * @param input floating ip JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated floating ip already exists
+     * @onos.rsModel NeutronFloatingIp
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -90,6 +91,7 @@
      * @param input floating ip JSON input stream
      * @return 200 OK with the updated floating ip, 400 BAD_REQUEST if the requested
      * floating ip does not exist
+     * @onos.rsModel NeutronFloatingIp
      */
     @PUT
     @Path("{id}")
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java
index 1691234..6f0b4cf 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java
@@ -65,6 +65,7 @@
      * @param input network JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated network already exists
+     * @onos.rsModel NeutronNetwork
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -89,6 +90,7 @@
      * @param input network JSON input stream
      * @return 200 OK with the updated network, 400 BAD_REQUEST if the requested
      * network does not exist
+     * @onos.rsModel NeutronNetwork
      */
     @PUT
     @Path("{id}")
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
index a1c5e7c..e657d4b 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
@@ -65,6 +65,7 @@
      * @param input port JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated port already exists
+     * @onos.rsModel NeutronPort
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -88,6 +89,7 @@
      * @param input port JSON input stream
      * @return 200 OK with the updated port, 400 BAD_REQUEST if the requested
      * port does not exist
+     * @onos.rsModel NeutronPort
      */
     @PUT
     @Path("{id}")
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java
index eff151d..5959101 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java
@@ -68,6 +68,7 @@
      * @param input router JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated router already exists
+     * @onos.rsModel NeutronRouter
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -92,6 +93,7 @@
      * @param input router JSON input stream
      * @return 200 OK with the updated router, 400 BAD_REQUEST if the requested
      * router does not exist
+     * @onos.rsModel NeutronRouter
      */
     @PUT
     @Path("{id}")
@@ -114,6 +116,7 @@
      * @param input router interface JSON input stream
      * @return 200 OK with the updated router interface, 400 BAD_REQUEST if the
      * requested router does not exist
+     * @onos.rsModel NeutronRouterInterface
      */
     @PUT
     @Path("{id}/add_router_interface")
@@ -135,6 +138,7 @@
      * @param input router interface JSON input stream
      * @return 200 OK with the updated router interface, 400 BAD_REQUEST if the
      * requested router does not exist
+     * @onos.rsModel NeutronRouterInterface
      */
     @PUT
     @Path("{id}/remove_router_interface")
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java
index e778a4f..669a3ad 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java
@@ -63,6 +63,7 @@
      * @param input security group JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated port already exists
+     * @onos.rsModel NeutronSecurityGroupRule
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java
index 244b984..7ba4538 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java
@@ -64,6 +64,7 @@
      * @param input security group JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated port already exists
+     * @onos.rsModel NeutronSecurityGroup
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -86,6 +87,7 @@
      * @param input security group JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated port already exists
+     * @onos.rsModel NeutronSecurityGroup
      */
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java
index a3e2368..fb6192c 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java
@@ -66,6 +66,7 @@
      * @param input subnet JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated subnet already exists
+     * @onos.rsModel NeutronSubnet
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -90,6 +91,7 @@
      * @param input subnet JSON input stream
      * @return 200 OK with the updated subnet, 400 BAD_REQUEST if the requested
      * subnet does not exist
+     * @onos.rsModel NeutronSubnet
      */
     @PUT
     @Path("{id}")
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronFloatingIp.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronFloatingIp.json
new file mode 100644
index 0000000..7976ffe
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronFloatingIp.json
@@ -0,0 +1,58 @@
+{
+  "type": "object",
+  "required": [
+    "floatingip"
+  ],
+  "properties": {
+    "floatingip": {
+      "type": "object",
+      "description": "A floatingip object.",
+      "required": [
+        "id",
+        "router_id",
+        "tenant_id",
+        "floating_network_id",
+        "floating_ip_address",
+        "fixed_ip_address",
+        "port_id"
+      ],
+      "properties": {
+        "id": {
+          "type": "string",
+          "example": "2f245a7b-796b-4f26-9cf9-9e82d248fda7",
+          "description": "The ID of the floating IP address."
+        },
+        "router_id": {
+          "type": "string",
+          "example": "d23abc8d-2991-4a55-ba98-2aaea84cc72",
+          "description": "The ID of the router for the floating IP."
+        },
+        "tenant_id": {
+          "type": "string",
+          "example": "4969c491a3c74ee4af974e6d800c62de",
+          "description": "The ID of the project."
+        },
+        "floating_network_id": {
+          "type": "string",
+          "example": "376da547-b977-4cfe-9cba-275c80debf57",
+          "description": "The ID of the network associated with the floating IP."
+        },
+        "floating_ip_address": {
+          "type": "string",
+          "example": "172.24.4.228",
+          "description": "The floating IP address."
+        },
+        "fixed_ip_address": {
+          "type": "string",
+          "example": "10.0.0.3",
+          "description": "The fixed IP address that is associated with the floating IP address."
+        },
+        "port_id": {
+          "type": "string",
+          "example": "ce705c24-c1ef-408a-bda3-7bbd946164ab",
+          "description": "The ID of a port associated with the floating IP."
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronNetwork.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronNetwork.json
new file mode 100644
index 0000000..ecc86d8
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronNetwork.json
@@ -0,0 +1,86 @@
+
+{
+  "type": "object",
+  "required": [
+    "network"
+  ],
+  "properties": {
+    "network": {
+      "type": "object",
+      "description": "A network object.",
+      "required": [
+        "id",
+        "subnets",
+        "provider:physical_network",
+        "admin_state_up",
+        "tenant_id",
+        "provider:network_type",
+        "router:external",
+        "provider:segmentation_id",
+        "availability_zone_hints",
+        "availability_zones"
+      ],
+      "properties": {
+        "id": {
+          "type": "string",
+          "example": "396f12f8-521e-4b91-8e21-2e003500433a",
+          "description": "The ID of the network."
+        },
+        "subnets": {
+          "type": "array",
+          "items": {
+            "type": "string",
+            "example": "10.10.0.0/24",
+            "description": "The associated subnets."
+          }
+        },
+        "provider:physical_network": {
+          "type": "string",
+          "example": "physnet1",
+          "description": "The physical network where this network is implemented."
+        },
+        "admin_state_up": {
+          "type": "boolean",
+          "example": true,
+          "description": "The administrative state of the network, which is up (true) or down (false)."
+        },
+        "tenant_id": {
+          "type": "string",
+          "example": "20bd52ff3e1b40039c312395b04683cf",
+          "description": "The ID of the project."
+        },
+        "provider:network_type": {
+          "type": "string",
+          "example": "vlan",
+          "description": "The type of physical network that this network is mapped to."
+        },
+        "router:external": {
+          "type": "boolean",
+          "example": true,
+          "description": "Indicates whether the network has an external routing facility that’s not managed by the networking service."
+        },
+        "provider:segmentation_id": {
+          "type": "string",
+          "example": "1002",
+          "description": "The ID of the isolated segment on the physical network."
+        },
+        "availability_zone_hints": {
+          "type": "array",
+          "items": {
+            "type": "string",
+            "example": "1",
+            "description": "The availability zone candidate for the network."
+          }
+        },
+        "availability_zones": {
+          "type": "array",
+          "items": {
+            "type": "string",
+            "example": "nova",
+            "description": "The availability zone for the network."
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronPort.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronPort.json
new file mode 100644
index 0000000..5a833bf
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronPort.json
@@ -0,0 +1,190 @@
+{
+  "type": "object",
+  "required": [
+    "port"
+  ],
+  "properties": {
+    "port": {
+      "type": "object",
+      "description": "A port object.",
+      "required": [
+        "id",
+        "admin_state_up",
+        "device_id",
+        "device_owner",
+        "fixed_ips",
+        "allowed_address_pairs",
+        "mac_address",
+        "network_id",
+        "state",
+        "tenant_id",
+        "security_groups",
+        "extra_dhcp_opts",
+        "port_security_enabled",
+        "binding:host_id",
+        "binding:vif_type",
+        "binding:vif_details",
+        "binding:vnic_type",
+        "binding:profile"
+
+      ],
+      "properties": {
+        "id": {
+          "type": "string",
+          "example": "65c0ee9f-d634-4522-8954-51021b570b0d",
+          "description": "The ID of the resource."
+        },
+        "admin_state_up": {
+          "type": "boolean",
+          "example": true,
+          "description": "The administrative state of the resource, which is up (true) or down (false)."
+        },
+        "device_id": {
+          "type": "string",
+          "example": "1",
+          "description": "The ID of the device that uses this port. For example, a server instance or a logical router."
+        },
+        "device_owner": {
+          "type": "string",
+          "example": "compute:nova",
+          "description": "The entity type that uses this port. For example, compute:nova (server instance)."
+        },
+        "fixed_ips": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "title": "fixed_ips",
+            "description": "The IP addresses for the port. If the port has multiple IP addresses, this field has multiple entries.",
+            "required": [
+              "ip_address",
+              "subnet_id"
+            ],
+            "properties": {
+              "ip_address": {
+                "type": "string",
+                "example": "10.0.0.2",
+                "description": "The IP address of the port."
+              },
+              "subnet_id": {
+                "type": "string",
+                "example": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+                "description": "The ID of the subnet."
+              }
+            }
+          }
+        },
+        "allowed_address_pairs": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "title": "allowed_address_pairs",
+            "description": "A set of zero or more allowed address pair objects each where address pair object contains an ip_address and mac_address.",
+            "required": [
+              "ip_address",
+              "mac_address"
+            ],
+            "properties": {
+              "ip_address": {
+                "type": "string",
+                "example": "12.12.11.12",
+                "description": "The IP address of the port."
+              },
+              "mac_address": {
+                "type": "string",
+                "example": "fa:14:2a:b3:cb:f0",
+                "description": "The MAC address of the port."
+              }
+            }
+          }
+        },
+        "mac_address": {
+          "type": "string",
+          "example": "fa:16:3e:c9:cb:f0",
+          "description": "The MAC address of the port."
+        },
+        "network_id": {
+          "type": "string",
+          "example": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+          "description": "The ID of the attached network."
+        },
+        "status": {
+          "type": "string",
+          "example": "ACTIVE",
+          "description": "The port status. Values are ACTIVE, DOWN, BUILD and ERROR."
+        },
+        "tenant_id": {
+          "type": "string",
+          "example": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
+          "description": "The ID of the project."
+        },
+        "security_groups": {
+          "type": "array",
+          "items": {
+            "type": "string",
+            "example": "f0ac4394-7e4a-4409-9701-ba8be283dbc3",
+            "description": "The IDs of security groups applied to the port."
+          }
+        },
+        "extra_dhcp_opts": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "title": "extra_dhcp_opts",
+            "description": "A set of zero or more extra DHCP option pairs. An option pair consists of an option value and name.",
+            "required": [
+              "opt_value",
+              "opt_name"
+            ],
+            "properties": {
+              "opt_value": {
+                "type": "string",
+                "example": "pxelinux.0",
+                "description": "A value of option pair."
+              },
+              "opt_name": {
+                "type": "string",
+                "example": "bootfile-name",
+                "description": "A name of option pair."
+              }
+            }
+          }
+        },
+        "port_security_enabled": {
+          "type": "boolean",
+          "example": true,
+          "description": "The port security status. A valid value is enabled (true) or disabled (false)."
+        },
+        "binding:host_id": {
+          "type": "string",
+          "example": "4df8d9ff-6f6f-438f-90a1-ef660d4586ad",
+          "description": "The ID of the host where the port resides."
+        },
+        "binding:vif_type": {
+          "type": "string",
+          "example": "unbound",
+          "description": "The type of which mechanism is used for the port."
+        },
+        "binding:vif_details": {
+          "type": "object",
+          "additionalProperties": {
+            "type": "string",
+            "example": "",
+            "description": "A dictionary which contains additional information on the port."
+          }
+        },
+        "binding:vnic_type": {
+          "type": "string",
+          "example": "other",
+          "description": "The type of vNIC which this port should be attached to. This is used to determine which mechanism driver(s) to be used to bind the port."
+        },
+        "binding:profile": {
+          "type": "object",
+          "additionalProperties": {
+            "type": "string",
+            "description": "A dictionary that enables the application running on the specific host to pass and receive vif port information specific to the networking back-end."
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronRouter.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronRouter.json
new file mode 100644
index 0000000..47d0f41
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronRouter.json
@@ -0,0 +1,96 @@
+{
+  "type": "object",
+  "required": [
+    "router"
+  ],
+  "properties": {
+    "router": {
+      "type": "object",
+      "description": "A router object.",
+      "required": [
+        "id",
+        "name",
+        "status",
+        "external_gateway_info",
+        "admin_state_up",
+        "tenant_id",
+        "routes",
+        "distributed"
+      ],
+      "properties": {
+        "id": {
+          "type": "string",
+          "example": "f49a1319-423a-4ee6-ba54-1d95a4f6cc68",
+          "description": "The ID of the router."
+        },
+        "name": {
+          "type": "string",
+          "example": "router1",
+          "description": "Human-readable name of the resource."
+        },
+        "status": {
+          "type": "string",
+          "example": "ACTIVE",
+          "description": "The router status."
+        },
+        "external_gateway_info": {
+          "type": "object",
+          "description": "The external gateway information of the router.",
+          "required": [
+            "network_id",
+            "enable_snat"
+          ],
+          "properties": {
+            "network_id": {
+              "type": "string",
+              "example": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+              "description": "Network ID which the router gateway is connected to."
+            },
+            "enable_snat": {
+              "type": "boolean",
+              "example": false,
+              "description": "Enable Source NAT (SNAT) attribute. true means Network Address Translation (NAT) is enabled."
+            }
+          }
+        },
+        "admin_state_up": {
+          "type": "boolean",
+          "example": true,
+          "description": "The administrative state of the resource, which is up (true) or down (false)."
+        },
+        "tenant_id": {
+          "type": "string",
+          "example": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
+          "description": "The ID of the project."
+        },
+        "routes": {
+          "type": "array",
+          "description": "The extra routes configuration for L3 router. A list of dictionaries with destination and nexthop parameters.",
+          "items": {
+            "type": "object",
+            "title": "route",
+            "required": [
+              "destination",
+              "nexthop"
+            ],
+            "properties": {
+              "destination": {
+                "type": "string",
+                "description": "The destination CIDR."
+              },
+              "nexthop": {
+                "type": "string",
+                "description": "The IP address of the next hop for the corresponding destination."
+              }
+            }
+          }
+        },
+        "distributed": {
+          "type": "boolean",
+          "example": false,
+          "description": "true indicates a distributed router. It is available when dvr extension is enabled."
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronRouterInterface.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronRouterInterface.json
new file mode 100644
index 0000000..59ae058
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronRouterInterface.json
@@ -0,0 +1,32 @@
+{
+  "type": "object",
+  "description": "A router interface object.",
+  "required": [
+    "id",
+    "tenant_id",
+    "subnet_id",
+    "port_id"
+  ],
+  "properties": {
+    "id": {
+      "type": "string",
+      "example": "f49a1319-423a-4ee6-ba54-1d95a4f6cc68",
+      "description": "The ID of the router interface."
+    },
+    "tenant_id": {
+      "type": "string",
+      "example": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
+      "description": "The ID of the project."
+    },
+    "subnet_id": {
+      "type": "string",
+      "example": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+      "description": "The subnet ID on which you want to create the floating IP."
+    },
+    "port_id": {
+      "type": "string",
+      "example": "ce705c24-c1ef-408a-bda3-7bbd946164ab",
+      "description": "The ID of a port associated with the floating IP."
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronSecurityGroup.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronSecurityGroup.json
new file mode 100644
index 0000000..6859b59
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronSecurityGroup.json
@@ -0,0 +1,115 @@
+{
+  "type": "object",
+  "description": "A security_group object.",
+  "required": [
+    "security_group"
+  ],
+  "properties": {
+    "security_group": {
+      "type": "object",
+      "required": [
+        "id",
+        "tenant_id",
+        "description",
+        "name",
+        "security_group_rules"
+      ],
+      "properties": {
+        "id": {
+          "type": "string",
+          "example": "2076db17-a522-4506-91de-c6dd8e837028",
+          "description": "The ID of the security group."
+        },
+        "tenant_id": {
+          "type": "string",
+          "example": "e4f50856753b4dc6afee5fa6b9b6c550",
+          "description": "The ID of the project."
+        },
+        "description": {
+          "type": "string",
+          "example": "security group for webservers",
+          "description": "A human-readable description for the resource."
+        },
+        "name": {
+          "type": "string",
+          "example": "new-webservers",
+          "description": "Human-readable name of the resource."
+        },
+        "security_group_rules": {
+          "type": "array",
+          "description": "A list of security_group_rule objects.",
+          "items": {
+            "type": "object",
+            "description": "A security group rule object.",
+            "required": [
+              "id",
+              "tenant_id",
+              "security_group_id",
+              "direction",
+              "ethertype",
+              "port_range_max",
+              "port_range_min",
+              "protocol",
+              "remote_ip_prefix",
+              "remote_group_id"
+            ],
+            "properties": {
+              "id": {
+                "type": "string",
+                "example": "2bc0accf-312e-429a-956e-e4407625eb62",
+                "description": "The ID of this security group rule."
+              },
+              "tenant_id": {
+                "type": "string",
+                "example": "e4f50856753b4dc6afee5fa6b9b6c550",
+                "description": "The ID of the project."
+              },
+              "security_group_id": {
+                "type": "string",
+                "example": "a7734e61-b545-452d-a3cd-0189cbd9747a",
+                "description": "The security group ID to associate with this security group rule."
+              },
+              "direction": {
+                "type": "string",
+                "example": "ingress",
+                "description": "Ingress or egress, which is the direction in which the metering rule is applied."
+              },
+              "ethertype": {
+                "type": "string",
+                "example": "IPv4",
+                "description": "Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules."
+              },
+              "port_range_max": {
+                "type": "integer",
+                "format": "int32",
+                "example": 80,
+                "description": "The maximum port number in the range that is matched by the security group rule."
+              },
+              "port_range_min": {
+                "type": "integer",
+                "format": "int32",
+                "example": 80,
+                "description": "The minimum port number in the range that is matched by the security group rule."
+              },
+              "protocol": {
+                "type": "string",
+                "example": "tcp",
+                "description": "The IP protocol can be represented by a string, an integer, or null."
+              },
+              "remote_ip_prefix": {
+                "type": "string",
+                "example": "",
+                "description": "The remote IP prefix to associate with this metering rule packet."
+              },
+              "remote_group_id": {
+                "type": "string",
+                "example": "85cc3048-abc3-43cc-89b3-377341426ac5",
+                "description": "The remote group UUID to associate with this security group rule."
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronSecurityGroupRule.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronSecurityGroupRule.json
new file mode 100644
index 0000000..d68ea46
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronSecurityGroupRule.json
@@ -0,0 +1,78 @@
+{
+  "type": "object",
+  "description": "",
+  "required": [
+    "security_group_rule"
+  ],
+  "properties": {
+    "security_group_rule": {
+      "type": "object",
+      "required": [
+        "id",
+        "tenant_id",
+        "security_group_id",
+        "direction",
+        "ethertype",
+        "port_range_max",
+        "port_range_min",
+        "protocol",
+        "remote_ip_prefix",
+        "remote_group_id"
+      ],
+      "properties": {
+        "id": {
+          "type": "string",
+          "example": "2bc0accf-312e-429a-956e-e4407625eb62",
+          "description": "The ID of this security group rule."
+        },
+        "tenant_id": {
+          "type": "string",
+          "example": "e4f50856753b4dc6afee5fa6b9b6c550",
+          "description": "The ID of the project."
+        },
+        "security_group_id": {
+          "type": "string",
+          "example": "a7734e61-b545-452d-a3cd-0189cbd9747a",
+          "description": "The security group ID to associate with this security group rule."
+        },
+        "direction": {
+          "type": "string",
+          "example": "ingress",
+          "description": "Ingress or egress, which is the direction in which the metering rule is applied."
+        },
+        "ethertype": {
+          "type": "string",
+          "example": "IPv4",
+          "description": "Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules."
+        },
+        "port_range_max": {
+          "type": "integer",
+          "format": "int32",
+          "example": 80,
+          "description": "The maximum port number in the range that is matched by the security group rule."
+        },
+        "port_range_min": {
+          "type": "integer",
+          "format": "int32",
+          "example": 80,
+          "description": "The minimum port number in the range that is matched by the security group rule."
+        },
+        "protocol": {
+          "type": "string",
+          "example": "tcp",
+          "description": "The IP protocol can be represented by a string, an integer, or null."
+        },
+        "remote_ip_prefix": {
+          "type": "string",
+          "example": "",
+          "description": "The remote IP prefix to associate with this metering rule packet."
+        },
+        "remote_group_id": {
+          "type": "string",
+          "example": "85cc3048-abc3-43cc-89b3-377341426ac5",
+          "description": "The remote group UUID to associate with this security group rule."
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/src/main/resources/definitions/NeutronSubnet.json b/apps/openstacknetworking/src/main/resources/definitions/NeutronSubnet.json
new file mode 100644
index 0000000..3a44ff4
--- /dev/null
+++ b/apps/openstacknetworking/src/main/resources/definitions/NeutronSubnet.json
@@ -0,0 +1,114 @@
+{
+  "type": "object",
+  "description": "A subnet object.",
+  "required": [
+    "subnets"
+  ],
+  "properties": {
+    "subnets": {
+      "type": "object",
+      "required": [
+        "enable_dhcp",
+        "network_id",
+        "tenant_id",
+        "dns_nameservers",
+        "allocation_pools",
+        "host_routes",
+        "ip_version",
+        "gateway_ip",
+        "ipv6_address_mode",
+        "ipv6_ra_mode"
+      ],
+      "properties": {
+        "enable_dhcp": {
+          "type": "boolean",
+          "example": true,
+          "description": "Indicates whether dhcp is enabled or disabled for the subnet."
+        },
+        "network_id": {
+          "type": "string",
+          "example": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+          "description": "The ID of the network to which the subnet belongs."
+        },
+        "tenant_id": {
+          "type": "string",
+          "example": "4fd44f30292945e481c7b8a0c8908869",
+          "description": "The ID of the project."
+        },
+        "dns_nameservers": {
+          "type": "array",
+          "description": "List of dns name servers associated with the subnet.",
+          "items": {
+            "type": "string",
+            "description": "A dns name server instance."
+          }
+        },
+        "allocation_pools": {
+          "type": "array",
+          "description": "Allocation pools with start and end IP addresses for this subnet.",
+          "items": {
+            "type": "object",
+            "description": "An allocation pool.",
+            "required": [
+              "start",
+              "end"
+            ],
+            "properties": {
+              "start": {
+                "type": "string",
+                "example": "192.168.199.2",
+                "description": "A start IP address for this subnet."
+              },
+              "end": {
+                "type": "string",
+                "example": "10.10.10.254",
+                "description": "An end IP address for this subnet."
+              }
+            }
+          }
+        },
+        "host_routes": {
+          "type": "array",
+          "description": "Additional routes for the subnet. A list of dictionaries with destination and nexthop parameters.",
+          "items": {
+            "type": "object",
+            "description": "A route for the subnet.",
+            "required": [
+              "destination",
+              "nexthop"
+            ],
+            "properties": {
+              "destination": {
+                "type": "string",
+                "description": "The destination CIDR."
+              },
+              "nexthop": {
+                "type": "string",
+                "description": "The IP address of the next hop for the corresponding destination."
+              }
+            }
+          }
+        },
+        "ip_version": {
+          "type": "integer",
+          "format": "int32",
+          "example": 4,
+          "description": "The IP protocol version. Value is 4 or 6."
+        },
+        "gateway_ip": {
+          "type": "string",
+          "example": "192.168.199.1",
+          "description": "Gateway IP of this subnet. If the value is null that implies no gateway is associated with the subnet."
+        },
+        "ipv6_address_mode": {
+          "type": "string",
+          "description": "The IPv6 address modes specifies mechanisms for assigning IP addresses."
+        },
+        "ipv6_ra_mode": {
+          "type": "string",
+          "description": "The IPv6 router advertisement specifies whether the networking service should transmit ICMPv6 packets, for a subnet."
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/Constants.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/Constants.java
index 06e592c..8bf4ceb 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/Constants.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/Constants.java
@@ -28,4 +28,11 @@
     public static final String DEFAULT_TUNNEL = "vxlan";
     public static final String PATCH_INTG_BRIDGE = "patch-intg";
     public static final String PATCH_ROUT_BRIDGE = "patch-rout";
+    public static final String GATEWAY = "GATEWAY";
+    public static final String HOST_NAME = "hostname";
+    public static final String TYPE = "type";
+    public static final String MANAGEMENT_IP = "managementIp";
+    public static final String DATA_IP = "dataIp";
+    public static final String VLAN_INTF_NAME = "vlanPort";
+    public static final String UPLINK_PORT = "uplinkPort";
 }
\ No newline at end of file
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NodeState.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NodeState.java
index f65901c..f34bdb7 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NodeState.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/NodeState.java
@@ -45,20 +45,6 @@
 
         @Override
         public NodeState nextState() {
-            return PORT_CREATED;
-        }
-    },
-    /**
-     * Indicates required ports are added.
-     */
-    PORT_CREATED {
-        @Override
-        public void process(OpenstackNodeHandler handler, OpenstackNode osNode) {
-            handler.processPortCreatedState(osNode);
-        }
-
-        @Override
-        public NodeState nextState() {
             return COMPLETE;
         }
     },
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
index ca03b86..f1e2bc5 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
@@ -72,13 +72,6 @@
     DeviceId intgBridge();
 
     /**
-     * Returns the router bridge device ID.
-     *
-     * @return device id; null if the node type is compute
-     */
-    DeviceId routerBridge();
-
-    /**
      * Returns the management network IP address of the node.
      *
      * @return ip address
@@ -151,6 +144,13 @@
     MacAddress vlanPortMac();
 
     /**
+     * Returns the uplink port name.
+     *
+     * @return uplink port name; null if the node type is compute
+     */
+    String uplinkPort();
+
+    /**
      * Returns new openstack node instance with given state.
      *
      * @param newState updated state
@@ -195,14 +195,6 @@
         Builder intgBridge(DeviceId intgBridge);
 
         /**
-         * Returns openstack node builder with supplied router bridge ID.
-         *
-         * @param routerBridge router bridge id
-         * @return openstack node builder
-         */
-        Builder routerBridge(DeviceId routerBridge);
-
-        /**
          * Returns openstack node builder with supplied management IP address.
          *
          * @param managementIp management ip address
@@ -227,6 +219,14 @@
         Builder vlanIntf(String vlanIntf);
 
         /**
+         * Returns openstack node builder with supplied uplink port.
+         *
+         * @param uplinkPort uplink port name
+         * @return openstack node builder
+         */
+        Builder uplinkPort(String uplinkPort);
+
+        /**
          * Returns openstack node builder with supplied node state.
          *
          * @param state node state
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeHandler.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeHandler.java
index 0264d17..a421410 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeHandler.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNodeHandler.java
@@ -37,14 +37,6 @@
     void processDeviceCreatedState(OpenstackNode osNode);
 
     /**
-     * Processes the given node for port created state.
-     * It creates gateway groups on compute node.
-     *
-     * @param osNode openstack node
-     */
-    void processPortCreatedState(OpenstackNode osNode);
-
-    /**
      * Processes the given node for complete state.
      * It performs post-init jobs for the complete node.
      *
diff --git a/apps/openstacknode/app/BUCK b/apps/openstacknode/app/BUCK
index ee11cb5..4612f6a 100644
--- a/apps/openstacknode/app/BUCK
+++ b/apps/openstacknode/app/BUCK
@@ -16,6 +16,8 @@
     '//lib:TEST_ADAPTERS',
     '//core/api:onos-api-tests',
     '//core/common:onos-core-common-tests',
+    '//web/api:onos-rest-tests',
+    '//lib:TEST_REST',
 ]
 
 osgi_jar_with_tests (
diff --git a/apps/openstacknode/app/pom.xml b/apps/openstacknode/app/pom.xml
index 7a2cec2..3555cf8 100644
--- a/apps/openstacknode/app/pom.xml
+++ b/apps/openstacknode/app/pom.xml
@@ -40,6 +40,14 @@
             org.onosproject.ovsdb-base,
             org.onosproject.drivers.ovsdb
         </onos.app.requires>
+
+        <web.context>/onos/openstacknode</web.context>
+        <api.version>1.0</api.version>
+        <api.title>OpenStack Node API</api.title>
+        <api.description>
+            REST API for OpenStack Node
+        </api.description>
+        <api.package>org.onosproject.openstacknode.web</api.package>
     </properties>
 
     <dependencies>
@@ -123,5 +131,68 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-client</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-jetty</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Include-Resource>
+                            WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
+                            {maven-resources}
+                        </Include-Resource>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            *,org.glassfish.jersey.servlet
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java
index 75d09cf..3ad60ef 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeCheckCommand.java
@@ -23,17 +23,11 @@
 import org.onosproject.net.Port;
 import org.onosproject.net.Device;
 import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupBucket;
-import org.onosproject.net.group.GroupService;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.openstacknode.api.Constants.*;
-import static org.onosproject.openstacknode.api.OpenstackNode.NetworkMode.VLAN;
-import static org.onosproject.openstacknode.api.OpenstackNode.NetworkMode.VXLAN;
-import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 
 /**
  * Checks detailed node init state.
@@ -48,14 +42,11 @@
 
     private static final String MSG_OK = "OK";
     private static final String MSG_NO = "NO";
-    private static final String BUCKET_FORMAT =
-            "   bucket=%s, bytes=%s, packets=%s, actions=%s";
 
     @Override
     protected void execute() {
         OpenstackNodeService osNodeService = AbstractShellCommand.get(OpenstackNodeService.class);
         DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);
-        GroupService groupService = AbstractShellCommand.get(GroupService.class);
 
         OpenstackNode osNode = osNodeService.node(hostname);
         if (osNode == null) {
@@ -78,7 +69,9 @@
             if (osNode.vlanIntf() != null) {
                 printPortState(deviceService, osNode.intgBridge(), osNode.vlanIntf());
             }
-            printGatewayGroupState(osNodeService, groupService, osNode);
+            if (osNode.type() == OpenstackNode.NodeType.GATEWAY) {
+                printPortState(deviceService, osNode.intgBridge(), osNode.uplinkPort());
+            }
         } else {
             print("%s %s=%s is not available",
                     MSG_NO,
@@ -104,43 +97,4 @@
             print("%s %s does not exist", MSG_NO, portName);
         }
     }
-
-    private void printGatewayGroupState(OpenstackNodeService osNodeService,
-                                        GroupService groupService, OpenstackNode osNode) {
-        if (osNode.type() == GATEWAY) {
-            return;
-        }
-        if (osNodeService.completeNodes(GATEWAY).isEmpty()) {
-            print("N/A No complete state gateway nodes exist");
-            return;
-        }
-        if (osNode.dataIp() != null) {
-            Group osGroup = groupService.getGroup(osNode.intgBridge(),
-                    osNode.gatewayGroupKey(VXLAN));
-            if (osGroup == null || osGroup.state() != Group.GroupState.ADDED) {
-                print("%s VXLAN gateway group does not exist", MSG_NO);
-            } else {
-                print("%s VXLAN group 0x%s added", MSG_OK, Integer.toHexString(osGroup.id().id()));
-                int i = 0;
-                for (GroupBucket bucket : osGroup.buckets().buckets()) {
-                    print(BUCKET_FORMAT, ++i, bucket.bytes(), bucket.packets(),
-                            bucket.treatment().allInstructions());
-                }
-            }
-        }
-        if (osNode.vlanIntf() != null) {
-            Group osGroup = groupService.getGroup(osNode.intgBridge(),
-                    osNode.gatewayGroupKey(VLAN));
-            if (osGroup == null || osGroup.state() != Group.GroupState.ADDED) {
-                print("\n%s VLAN gateway group does not exist", MSG_NO);
-            } else {
-                print("\n%s VLAN group 0x%s added", MSG_OK, Integer.toHexString(osGroup.id().id()));
-                int i = 0;
-                for (GroupBucket bucket : osGroup.buckets().buckets()) {
-                    print(BUCKET_FORMAT, ++i, bucket.bytes(), bucket.packets(),
-                            bucket.treatment().allInstructions());
-                }
-            }
-        }
-    }
 }
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java
index f7207df..4d5d900 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/cli/OpenstackNodeListCommand.java
@@ -46,17 +46,17 @@
         if (outputJson()) {
             print("%s", json(osNodes));
         } else {
-            print(FORMAT, "Hostname", "Type", "Integration Bridge", "Router Bridge",
-                    "Management IP", "Data IP", "VLAN Intf", "State");
+            print(FORMAT, "Hostname", "Type", "Integration Bridge",
+                    "Management IP", "Data IP", "VLAN Intf", "Uplink Port", "State");
             for (OpenstackNode osNode : osNodes) {
                 print(FORMAT,
                         osNode.hostname(),
                         osNode.type(),
                         osNode.intgBridge(),
-                        osNode.routerBridge() != null ? osNode.routerBridge() : "",
                         osNode.managementIp(),
                         osNode.dataIp() != null ? osNode.dataIp() : "",
                         osNode.vlanIntf() != null ? osNode.vlanIntf() : "",
+                        osNode.uplinkPort() != null ? osNode.uplinkPort() : "",
                         osNode.state());
             }
             print("Total %s nodes", osNodeService.nodes().size());
@@ -71,12 +71,12 @@
                     .put("hostname", osNode.hostname())
                     .put("type", osNode.type().name())
                     .put("integrationBridge", osNode.intgBridge().toString())
-                    .put("routerBridge", osNode.routerBridge().toString())
                     .put("managementIp", osNode.managementIp().toString())
                     .put("dataIp", osNode.dataIp().toString())
                     .put("vlanIntf", osNode.vlanIntf())
                     .put("tunnelPortNum", osNode.tunnelPortNum().toString())
                     .put("vlanPortNum", osNode.vlanPortNum().toString())
+                    .put("uplinkPort", osNode.uplinkPort())
                     .put("state", osNode.state().name()));
         }
         return result;
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
new file mode 100644
index 0000000..9341725
--- /dev/null
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018-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.openstacknode.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.impl.DefaultOpenstackNode;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.onosproject.openstacknode.api.Constants.DATA_IP;
+import static org.onosproject.openstacknode.api.Constants.GATEWAY;
+import static org.onosproject.openstacknode.api.Constants.HOST_NAME;
+import static org.onosproject.openstacknode.api.Constants.MANAGEMENT_IP;
+import static org.onosproject.openstacknode.api.Constants.UPLINK_PORT;
+import static org.onosproject.openstacknode.api.Constants.VLAN_INTF_NAME;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Openstack node codec used for serializing and de-serializing JSON string.
+ */
+public final class OpenstackNodeCodec extends JsonCodec<OpenstackNode> {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String TYPE = "type";
+    private static final String INTEGRATION_BRIDGE = "integrationBridge";
+
+    private static final String MISSING_MESSAGE = " is required in OpenstackNode";
+
+    @Override
+    public ObjectNode encode(OpenstackNode node, CodecContext context) {
+        checkNotNull(node, "Openstack node cannot be null");
+
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(HOST_NAME, node.hostname())
+                .put(TYPE, node.type().name())
+                .put(MANAGEMENT_IP, node.managementIp().toString())
+                .put(INTEGRATION_BRIDGE, node.intgBridge().toString());
+
+        OpenstackNode.NodeType type = node.type();
+
+        if (type == OpenstackNode.NodeType.GATEWAY) {
+            result.put(UPLINK_PORT, node.uplinkPort());
+        }
+
+        if (node.vlanIntf() != null) {
+            result.put(VLAN_INTF_NAME, node.vlanIntf());
+        }
+
+        if (node.dataIp() != null) {
+            result.put(DATA_IP, node.dataIp().toString());
+        }
+
+        return result;
+    }
+
+    @Override
+    public OpenstackNode decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        String hostname = nullIsIllegal(json.get(HOST_NAME).asText(),
+                HOST_NAME + MISSING_MESSAGE);
+        String type = nullIsIllegal(json.get(TYPE).asText(),
+                TYPE + MISSING_MESSAGE);
+        String mIp = nullIsIllegal(json.get(MANAGEMENT_IP).asText(),
+                MANAGEMENT_IP + MISSING_MESSAGE);
+        String iBridge = nullIsIllegal(json.get(INTEGRATION_BRIDGE).asText(),
+                INTEGRATION_BRIDGE + MISSING_MESSAGE);
+
+        DefaultOpenstackNode.Builder nodeBuilder = DefaultOpenstackNode.builder()
+                .hostname(hostname)
+                .type(OpenstackNode.NodeType.valueOf(type))
+                .managementIp(IpAddress.valueOf(mIp))
+                .intgBridge(DeviceId.deviceId(iBridge))
+                .state(NodeState.INIT);
+
+        if (type.equals(GATEWAY)) {
+            nodeBuilder.uplinkPort(nullIsIllegal(json.get(UPLINK_PORT).asText(),
+                    UPLINK_PORT + MISSING_MESSAGE));
+        }
+        if (json.get(VLAN_INTF_NAME) != null) {
+            nodeBuilder.vlanIntf(json.get(VLAN_INTF_NAME).asText());
+        }
+        if (json.get(DATA_IP) != null) {
+            nodeBuilder.dataIp(IpAddress.valueOf(json.get(DATA_IP).asText()));
+        }
+
+        log.trace("node is {}", nodeBuilder.build().toString());
+
+        return nodeBuilder.build();
+    }
+}
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/package-info.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/package-info.java
new file mode 100644
index 0000000..98ecbd5
--- /dev/null
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-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.
+ */
+
+/**
+ * Implementations of the codec broker and openstacknode entity JSON codecs.
+ */
+package org.onosproject.openstacknode.codec;
\ No newline at end of file
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
index f02684a..6650be6 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
@@ -46,27 +46,28 @@
     private final String hostname;
     private final NodeType type;
     private final DeviceId intgBridge;
-    private final DeviceId routerBridge;
     private final IpAddress managementIp;
     private final IpAddress dataIp;
     private final String vlanIntf;
+    private final String uplinkPort;
     private final NodeState state;
 
-    protected DefaultOpenstackNode(String hostname,
-                                 NodeType type,
-                                 DeviceId intgBridge,
-                                 DeviceId routerBridge,
-                                 IpAddress managementIp,
-                                 IpAddress dataIp,
-                                 String vlanIntf,
-                                 NodeState state) {
+    private static final String OVSDB = "ovsdb:";
+
+    protected DefaultOpenstackNode(String hostname, NodeType type,
+                                   DeviceId intgBridge,
+                                   IpAddress managementIp,
+                                   IpAddress dataIp,
+                                   String vlanIntf,
+                                   String uplinkPort,
+                                   NodeState state) {
         this.hostname = hostname;
         this.type = type;
         this.intgBridge = intgBridge;
-        this.routerBridge = routerBridge;
         this.managementIp = managementIp;
         this.dataIp = dataIp;
         this.vlanIntf = vlanIntf;
+        this.uplinkPort = uplinkPort;
         this.state = state;
     }
 
@@ -82,7 +83,7 @@
 
     @Override
     public DeviceId ovsdb() {
-        return DeviceId.deviceId("ovsdb:" + managementIp().toString());
+        return DeviceId.deviceId(OVSDB + managementIp().toString());
     }
 
     @Override
@@ -91,11 +92,6 @@
     }
 
     @Override
-    public DeviceId routerBridge() {
-        return routerBridge;
-    }
-
-    @Override
     public IpAddress managementIp() {
         return managementIp;
     }
@@ -111,6 +107,11 @@
     }
 
     @Override
+    public String uplinkPort() {
+        return uplinkPort;
+    }
+
+    @Override
     public NodeState state() {
         return state;
     }
@@ -187,9 +188,9 @@
             if (Objects.equals(hostname, that.hostname) &&
                     Objects.equals(type, that.type) &&
                     Objects.equals(intgBridge, that.intgBridge) &&
-                    Objects.equals(routerBridge, that.routerBridge) &&
                     Objects.equals(managementIp, that.managementIp) &&
                     Objects.equals(dataIp, that.dataIp) &&
+                    Objects.equals(uplinkPort, that.uplinkPort) &&
                     Objects.equals(vlanIntf, that.vlanIntf)) {
                 return true;
             }
@@ -202,10 +203,10 @@
         return Objects.hash(hostname,
                 type,
                 intgBridge,
-                routerBridge,
                 managementIp,
                 dataIp,
-                vlanIntf);
+                vlanIntf,
+                uplinkPort);
     }
 
     @Override
@@ -214,10 +215,10 @@
                 .add("hostname", hostname)
                 .add("type", type)
                 .add("integrationBridge", intgBridge)
-                .add("routerBridge", routerBridge)
                 .add("managementIp", managementIp)
                 .add("dataIp", dataIp)
                 .add("vlanIntf", vlanIntf)
+                .add("uplinkPort", uplinkPort)
                 .add("state", state)
                 .toString();
     }
@@ -228,10 +229,10 @@
                 .type(type)
                 .hostname(hostname)
                 .intgBridge(intgBridge)
-                .routerBridge(routerBridge)
                 .managementIp(managementIp)
                 .dataIp(dataIp)
                 .vlanIntf(vlanIntf)
+                .uplinkPort(uplinkPort)
                 .state(newState)
                 .build();
     }
@@ -256,10 +257,10 @@
                 .hostname(osNode.hostname())
                 .type(osNode.type())
                 .intgBridge(osNode.intgBridge())
-                .routerBridge(osNode.routerBridge())
                 .managementIp(osNode.managementIp())
                 .dataIp(osNode.dataIp())
                 .vlanIntf(osNode.vlanIntf())
+                .uplinkPort(osNode.uplinkPort())
                 .state(osNode.state());
     }
 
@@ -268,10 +269,10 @@
         private String hostname;
         private NodeType type;
         private DeviceId intgBridge;
-        private DeviceId routerBridge;
         private IpAddress managementIp;
         private IpAddress dataIp;
         private String vlanIntf;
+        private String uplinkPort;
         private NodeState state;
 
         private Builder() {
@@ -285,8 +286,8 @@
             checkArgument(managementIp != null, "Node management IP cannot be null");
             checkArgument(state != null, "Node state cannot be null");
 
-            if (type == NodeType.GATEWAY && routerBridge == null) {
-                throw new IllegalArgumentException("Router bridge is required for gateway node");
+            if (type == NodeType.GATEWAY && uplinkPort == null) {
+                throw new IllegalArgumentException("Uplink port is required for gateway node");
             }
             if (dataIp == null && Strings.isNullOrEmpty(vlanIntf)) {
                 throw new IllegalArgumentException("Either data IP or VLAN interface is required");
@@ -295,10 +296,10 @@
             return new DefaultOpenstackNode(hostname,
                     type,
                     intgBridge,
-                    routerBridge,
                     managementIp,
                     dataIp,
                     vlanIntf,
+                    uplinkPort,
                     state);
         }
 
@@ -323,12 +324,6 @@
         }
 
         @Override
-        public Builder routerBridge(DeviceId routerBridge) {
-            this.routerBridge = routerBridge;
-            return this;
-        }
-
-        @Override
         public Builder managementIp(IpAddress managementIp) {
             this.managementIp = managementIp;
             return this;
@@ -347,6 +342,12 @@
         }
 
         @Override
+        public Builder uplinkPort(String uplinkPort) {
+            this.uplinkPort = uplinkPort;
+            return this;
+        }
+
+        @Override
         public Builder state(NodeState state) {
             this.state = state;
             return this;
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
index 625d41d..7b8cda1 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
@@ -15,9 +15,6 @@
  */
 package org.onosproject.openstacknode.impl;
 
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -42,11 +39,9 @@
 import org.onosproject.net.behaviour.BridgeName;
 import org.onosproject.net.behaviour.ControllerInfo;
 import org.onosproject.net.behaviour.DefaultBridgeDescription;
-import org.onosproject.net.behaviour.DefaultPatchDescription;
 import org.onosproject.net.behaviour.DefaultTunnelDescription;
 import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
 import org.onosproject.net.behaviour.InterfaceConfig;
-import org.onosproject.net.behaviour.PatchDescription;
 import org.onosproject.net.behaviour.TunnelDescription;
 import org.onosproject.net.behaviour.TunnelEndPoints;
 import org.onosproject.net.behaviour.TunnelKeys;
@@ -54,21 +49,11 @@
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.ExtensionPropertyException;
 import org.onosproject.net.flow.instructions.ExtensionTreatment;
-import org.onosproject.net.group.DefaultGroupDescription;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupBucket;
-import org.onosproject.net.group.GroupBuckets;
-import org.onosproject.net.group.GroupDescription;
-import org.onosproject.net.group.GroupEvent;
-import org.onosproject.net.group.GroupListener;
-import org.onosproject.net.group.GroupService;
+
 import org.onosproject.openstacknode.api.NodeState;
 import org.onosproject.openstacknode.api.OpenstackNode;
-import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
 import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeHandler;
@@ -87,19 +72,13 @@
 import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.packet.TpPort.tpPort;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
-import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
 import static org.onosproject.openstacknode.api.Constants.*;
-import static org.onosproject.openstacknode.api.Constants.PATCH_INTG_BRIDGE;
 import static org.onosproject.openstacknode.api.NodeState.*;
-import static org.onosproject.openstacknode.api.OpenstackNode.NetworkMode.VLAN;
-import static org.onosproject.openstacknode.api.OpenstackNode.NetworkMode.VXLAN;
-import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -137,9 +116,6 @@
     protected OvsdbController ovsdbController;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected GroupService groupService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackNodeService osNodeService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -157,7 +133,6 @@
 
     private final DeviceListener ovsdbListener = new InternalOvsdbListener();
     private final DeviceListener bridgeListener = new InternalBridgeListener();
-    private final GroupListener groupListener = new InternalGroupListener();
     private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
 
     private ApplicationId appId;
@@ -170,7 +145,6 @@
 
         componentConfigService.registerProperties(getClass());
         leadershipService.runForLeadership(appId.name());
-        groupService.addListener(groupListener);
         deviceService.addListener(ovsdbListener);
         deviceService.addListener(bridgeListener);
         osNodeService.addListener(osNodeListener);
@@ -183,7 +157,6 @@
         osNodeService.removeListener(osNodeListener);
         deviceService.removeListener(bridgeListener);
         deviceService.removeListener(ovsdbListener);
-        groupService.removeListener(groupListener);
         componentConfigService.unregisterProperties(getClass(), false);
         leadershipService.withdraw(appId.name());
         eventExecutor.shutdown();
@@ -211,64 +184,31 @@
         if (!deviceService.isAvailable(osNode.intgBridge())) {
             createBridge(osNode, INTEGRATION_BRIDGE, osNode.intgBridge());
         }
-        if (osNode.type() == GATEWAY &&
-                !isBridgeCreated(osNode.ovsdb(), ROUTER_BRIDGE)) {
-            createBridge(osNode, ROUTER_BRIDGE, osNode.routerBridge());
-        }
     }
 
     @Override
     public void processDeviceCreatedState(OpenstackNode osNode) {
-        if (!isOvsdbConnected(osNode)) {
-            ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
-            return;
-        }
-        if (osNode.type() == GATEWAY && (
-                !isIntfEnabled(osNode, PATCH_INTG_BRIDGE) ||
-                        !isIntfCreated(osNode, PATCH_ROUT_BRIDGE)
-        )) {
-            createPatchInterface(osNode);
-        }
-        if (osNode.dataIp() != null &&
-                !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
-            createTunnelInterface(osNode);
-        }
-        if (osNode.vlanIntf() != null &&
-                !isIntfEnabled(osNode, osNode.vlanIntf())) {
-            addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.vlanIntf());
-        }
-    }
+        try {
+            if (!isOvsdbConnected(osNode)) {
+                ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
+                return;
+            }
 
-    @Override
-    public void processPortCreatedState(OpenstackNode osNode) {
-        switch (osNode.type()) {
-            case COMPUTE:
-                if (osNode.dataIp() != null) {
-                    addOrUpdateGatewayGroup(osNode,
-                            osNodeService.completeNodes(GATEWAY),
-                            VXLAN);
-                }
-                if (osNode.vlanIntf() != null) {
-                    addOrUpdateGatewayGroup(osNode,
-                            osNodeService.completeNodes(GATEWAY),
-                            VLAN);
-                }
-                break;
-            case GATEWAY:
-                Set<OpenstackNode> gateways =
-                        Sets.newHashSet(osNodeService.completeNodes(GATEWAY));
-                gateways.add(osNode);
-                osNodeService.completeNodes(COMPUTE).forEach(n -> {
-                    if (n.dataIp() != null) {
-                        addOrUpdateGatewayGroup(n, gateways, VXLAN);
-                    }
-                    if (n.vlanIntf() != null) {
-                        addOrUpdateGatewayGroup(n, gateways, VLAN);
-                    }
-                });
-                break;
-            default:
-                break;
+            if (osNode.type() == GATEWAY) {
+                addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.uplinkPort());
+            }
+
+            if (osNode.dataIp() != null &&
+                    !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
+                createTunnelInterface(osNode);
+            }
+
+            if (osNode.vlanIntf() != null &&
+                    !isIntfEnabled(osNode, osNode.vlanIntf())) {
+                addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.vlanIntf());
+            }
+        } catch (Exception e) {
+            log.error("Exception occured because of {}", e.toString());
         }
     }
 
@@ -283,28 +223,7 @@
 
     @Override
     public void processIncompleteState(OpenstackNode osNode) {
-        if (osNode.type() == COMPUTE) {
-            if (osNode.dataIp() != null) {
-                groupService.removeGroup(osNode.intgBridge(), osNode.gatewayGroupKey(VXLAN), appId);
-            }
-            if (osNode.vlanIntf() != null) {
-                groupService.removeGroup(osNode.intgBridge(), osNode.gatewayGroupKey(VLAN), appId);
-            }
-        }
-        if (osNode.type() == GATEWAY) {
-            osNodeService.completeNodes(COMPUTE).forEach(n -> {
-                if (n.dataIp() != null) {
-                    addOrUpdateGatewayGroup(n,
-                            osNodeService.completeNodes(GATEWAY),
-                            VXLAN);
-                }
-                if (n.vlanIntf() != null) {
-                    addOrUpdateGatewayGroup(n,
-                            osNodeService.completeNodes(GATEWAY),
-                            VLAN);
-                }
-            });
-        }
+        //TODO
     }
 
     private boolean isOvsdbConnected(OpenstackNode osNode) {
@@ -322,22 +241,16 @@
             return;
         }
 
-        // TODO fix this when we use single ONOS cluster for both openstackNode and vRouter
-        Set<IpAddress> controllerIps;
-        if (bridgeName.equals(ROUTER_BRIDGE)) {
-            // TODO checks if empty controller does not break anything
-            controllerIps = ImmutableSet.of();
-        } else {
-            controllerIps = clusterService.getNodes().stream()
+        Set<IpAddress> controllerIps = clusterService.getNodes().stream()
                     .map(ControllerNode::ip)
                     .collect(Collectors.toSet());
-        }
 
         List<ControllerInfo> controllers = controllerIps.stream()
                 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
                 .collect(Collectors.toList());
 
         String dpid = deviceId.toString().substring(DPID_BEGIN);
+
         BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
                 .name(bridgeName)
                 .failMode(BridgeDescription.FailMode.SECURE)
@@ -382,91 +295,6 @@
         ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
     }
 
-    private void createPatchInterface(OpenstackNode osNode) {
-        checkArgument(osNode.type().equals(OpenstackNode.NodeType.GATEWAY));
-        if (isIntfEnabled(osNode, PATCH_INTG_BRIDGE) &&
-                isIntfCreated(osNode, PATCH_ROUT_BRIDGE)) {
-            return;
-        }
-
-        Device device = deviceService.getDevice(osNode.ovsdb());
-        if (device == null || !device.is(InterfaceConfig.class)) {
-            log.error("Failed to create patch interfaces on {}", osNode.hostname());
-            return;
-        }
-
-        PatchDescription patchIntg = DefaultPatchDescription.builder()
-                .deviceId(INTEGRATION_BRIDGE)
-                .ifaceName(PATCH_INTG_BRIDGE)
-                .peer(PATCH_ROUT_BRIDGE)
-                .build();
-
-        PatchDescription patchRout = DefaultPatchDescription.builder()
-                .deviceId(ROUTER_BRIDGE)
-                .ifaceName(PATCH_ROUT_BRIDGE)
-                .peer(PATCH_INTG_BRIDGE)
-                .build();
-
-        InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
-        ifaceConfig.addPatchMode(PATCH_INTG_BRIDGE, patchIntg);
-        ifaceConfig.addPatchMode(PATCH_ROUT_BRIDGE, patchRout);
-    }
-
-    private void addOrUpdateGatewayGroup(OpenstackNode osNode,
-                                         Set<OpenstackNode> gatewayNodes,
-                                         NetworkMode mode) {
-        GroupBuckets buckets = gatewayGroupBuckets(osNode, gatewayNodes, mode);
-        if (groupService.getGroup(osNode.intgBridge(), osNode.gatewayGroupKey(mode)) == null) {
-            GroupDescription groupDescription = new DefaultGroupDescription(
-                    osNode.intgBridge(),
-                    GroupDescription.Type.SELECT,
-                    buckets,
-                    osNode.gatewayGroupKey(mode),
-                    osNode.gatewayGroupId(mode).id(),
-                    appId);
-            groupService.addGroup(groupDescription);
-            log.debug("Created gateway group for {}", osNode.hostname());
-        } else {
-            groupService.setBucketsForGroup(
-                    osNode.intgBridge(),
-                    osNode.gatewayGroupKey(mode),
-                    buckets,
-                    osNode.gatewayGroupKey(mode),
-                    appId);
-            log.debug("Updated gateway group for {}", osNode.hostname());
-        }
-    }
-
-    private GroupBuckets gatewayGroupBuckets(OpenstackNode osNode,
-                                             Set<OpenstackNode> gatewayNodes,
-                                             NetworkMode mode) {
-        List<GroupBucket> bucketList = Lists.newArrayList();
-        switch (mode) {
-            case VXLAN:
-                gatewayNodes.stream().filter(n -> n.dataIp() != null).forEach(n -> {
-                    TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                            .extension(tunnelDstTreatment(osNode.intgBridge(),
-                                    n.dataIp()),
-                                    osNode.intgBridge())
-                            .setOutput(osNode.tunnelPortNum())
-                            .build();
-                    bucketList.add(createSelectGroupBucket(treatment));
-                });
-                return new GroupBuckets(bucketList);
-            case VLAN:
-                gatewayNodes.stream().filter(n -> n.vlanIntf() != null).forEach(n -> {
-                    TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                            .setEthDst(n.vlanPortMac())
-                            .setOutput(osNode.vlanPortNum())
-                            .build();
-                    bucketList.add(createSelectGroupBucket(treatment));
-                });
-                return new GroupBuckets(bucketList);
-            default:
-                return null;
-        }
-    }
-
     private ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, IpAddress remoteIp) {
         Device device = deviceService.getDevice(deviceId);
         if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
@@ -489,17 +317,6 @@
         }
     }
 
-    private boolean isBridgeCreated(DeviceId ovsdbId, String bridgeName) {
-        Device device = deviceService.getDevice(ovsdbId);
-        if (device == null || !deviceService.isAvailable(device.id()) ||
-                !device.is(BridgeConfig.class)) {
-            return false;
-        }
-        BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
-        return bridgeConfig.getBridges().stream()
-                .anyMatch(bridge -> bridge.name().equals(bridgeName));
-    }
-
     private boolean isIntfEnabled(OpenstackNode osNode, String intf) {
         if (!deviceService.isAvailable(osNode.intgBridge())) {
             return false;
@@ -510,67 +327,12 @@
                         port.isEnabled());
     }
 
-    private boolean isIntfCreated(OpenstackNode osNode, String intf) {
-        Device device = deviceService.getDevice(osNode.ovsdb());
-        if (device == null || !deviceService.isAvailable(osNode.ovsdb()) ||
-                !device.is(BridgeConfig.class)) {
-            return false;
-        }
-
-        BridgeConfig bridgeConfig =  device.as(BridgeConfig.class);
-        return bridgeConfig.getPorts().stream()
-                .anyMatch(port -> port.annotations().value(PORT_NAME).equals(intf));
-    }
-
-    private boolean isGroupCreated(OpenstackNode osNode) {
-        for (OpenstackNode gNode : osNodeService.completeNodes(GATEWAY)) {
-            if (!isGatewayBucketAdded(osNode, gNode)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean isGatewayBucketAdded(OpenstackNode cNode, OpenstackNode gNode) {
-        if (cNode.dataIp() != null) {
-            Group osGroup = groupService.getGroup(cNode.intgBridge(),
-                    cNode.gatewayGroupKey(VXLAN));
-            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                    .extension(tunnelDstTreatment(gNode.intgBridge(),
-                            gNode.dataIp()),
-                            cNode.intgBridge())
-                    .setOutput(cNode.tunnelPortNum())
-                    .build();
-            GroupBucket bucket = createSelectGroupBucket(treatment);
-            if (osGroup == null || !osGroup.buckets().buckets().contains(bucket)) {
-                return false;
-            }
-        }
-        if (cNode.vlanIntf() != null) {
-            Group osGroup = groupService.getGroup(cNode.intgBridge(),
-                    cNode.gatewayGroupKey(VLAN));
-            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                    .setEthDst(gNode.vlanPortMac())
-                    .setOutput(cNode.vlanPortNum())
-                    .build();
-            GroupBucket bucket = createSelectGroupBucket(treatment);
-            if (osGroup == null || !osGroup.buckets().buckets().contains(bucket)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     private boolean isCurrentStateDone(OpenstackNode osNode) {
         switch (osNode.state()) {
             case INIT:
                 if (!deviceService.isAvailable(osNode.intgBridge())) {
                     return false;
                 }
-                if (osNode.type() == GATEWAY &&
-                        !isBridgeCreated(osNode.ovsdb(), ROUTER_BRIDGE)) {
-                    return false;
-                }
                 return true;
             case DEVICE_CREATED:
                 if (osNode.dataIp() != null &&
@@ -581,23 +343,11 @@
                         !isIntfEnabled(osNode, osNode.vlanIntf())) {
                     return false;
                 }
-                if (osNode.type() == GATEWAY && (
-                        !isIntfEnabled(osNode, PATCH_INTG_BRIDGE) ||
-                        !isIntfCreated(osNode, PATCH_ROUT_BRIDGE))) {
+                if (osNode.type() == GATEWAY &&
+                        !isIntfEnabled(osNode, osNode.uplinkPort())) {
                     return false;
                 }
                 return true;
-            case PORT_CREATED:
-                if (osNode.type() == COMPUTE) {
-                    return isGroupCreated(osNode);
-                } else {
-                    for (OpenstackNode cNode : osNodeService.completeNodes(COMPUTE)) {
-                        if (!isGatewayBucketAdded(cNode, osNode)) {
-                            return false;
-                        }
-                    }
-                    return true;
-                }
             case COMPLETE:
                 return false;
             case INCOMPLETE:
@@ -700,9 +450,7 @@
                         if (osNode.state() == DEVICE_CREATED && (
                                 Objects.equals(portName, DEFAULT_TUNNEL) ||
                                 Objects.equals(portName, osNode.vlanIntf()) ||
-                                Objects.equals(portName, PATCH_INTG_BRIDGE) ||
-                                Objects.equals(portName, PATCH_ROUT_BRIDGE))) {
-                            // FIXME we never gets PATCH_ROUTE_BRIDGE port added events as of now
+                                Objects.equals(portName, osNode.uplinkPort()))) {
                             log.debug("Interface {} added to {}", portName, event.subject().id());
                             bootstrapNode(osNode);
                         }
@@ -715,8 +463,7 @@
                         if (osNode.state() == COMPLETE && (
                                 Objects.equals(portName, DEFAULT_TUNNEL) ||
                                 Objects.equals(portName, osNode.vlanIntf()) ||
-                                Objects.equals(portName, PATCH_INTG_BRIDGE) ||
-                                Objects.equals(portName, PATCH_ROUT_BRIDGE))) {
+                                        Objects.equals(portName, osNode.uplinkPort()))) {
                             log.warn("Interface {} removed from {}", portName, event.subject().id());
                             setState(osNode, INCOMPLETE);
                         }
@@ -731,54 +478,6 @@
         }
     }
 
-    private class InternalGroupListener implements GroupListener {
-
-        @Override
-        public boolean isRelevant(GroupEvent event) {
-            NodeId leader = leadershipService.getLeader(appId.name());
-            return Objects.equals(localNode, leader);
-        }
-
-        @Override
-        public void event(GroupEvent event) {
-            switch (event.type()) {
-                case GROUP_ADDED:
-                    eventExecutor.execute(() -> {
-                        log.trace("Group added, ID:{} state:{}", event.subject().id(),
-                                event.subject().state());
-                        processGroup(event.subject());
-                    });
-                    break;
-                case GROUP_UPDATED:
-                    eventExecutor.execute(() -> {
-                        log.trace("Group updated, ID:{} state:{}", event.subject().id(),
-                                event.subject().state());
-                        processGroup(event.subject());
-                    });
-                    break;
-                case GROUP_REMOVED:
-                    // TODO handle group removed
-                    break;
-                default:
-                    break;
-            }
-        }
-
-        private void processGroup(Group group) {
-            OpenstackNode osNode = osNodeService.nodes(COMPUTE).stream()
-                    .filter(n -> n.state() == PORT_CREATED &&
-                            (n.gatewayGroupId(VXLAN).equals(group.id()) ||
-                            n.gatewayGroupId(VLAN).equals(group.id())))
-                    .findAny().orElse(null);
-            if (osNode != null) {
-                bootstrapNode(osNode);
-            }
-            osNodeService.nodes(GATEWAY).stream()
-                    .filter(gNode -> gNode.state() == PORT_CREATED)
-                    .forEach(DefaultOpenstackNodeHandler.this::bootstrapNode);
-        }
-    }
-
     private class InternalOpenstackNodeListener implements OpenstackNodeListener {
 
         @Override
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
index 4642dd7..f3ece18 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
@@ -171,8 +171,7 @@
     public OpenstackNode node(DeviceId deviceId) {
         OpenstackNode result = osNodeStore.nodes().stream()
                 .filter(osNode -> Objects.equals(osNode.intgBridge(), deviceId) ||
-                        Objects.equals(osNode.ovsdb(), deviceId) ||
-                        Objects.equals(osNode.routerBridge(), deviceId))
+                        Objects.equals(osNode.ovsdb(), deviceId))
                 .findFirst().orElse(null);
         return result;
     }
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeCodecRegister.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeCodecRegister.java
new file mode 100644
index 0000000..86947d8
--- /dev/null
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeCodecRegister.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018-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.openstacknode.web;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.codec.CodecService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.codec.OpenstackNodeCodec;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the JSON codec brokering service for OpenstackNode.
+ */
+@Component(immediate = true)
+public class OpenstackNodeCodecRegister {
+
+    private final org.slf4j.Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CodecService codecService;
+
+    @Activate
+    public void activate() {
+        codecService.registerCodec(OpenstackNode.class, new OpenstackNodeCodec());
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        codecService.unregisterCodec(OpenstackNode.class);
+
+        log.info("Stopped");
+    }
+}
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeWebApplication.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeWebApplication.java
new file mode 100644
index 0000000..88e9b19
--- /dev/null
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeWebApplication.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018-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.openstacknode.web;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * Openstack node REST APIs web application.
+ */
+public class OpenstackNodeWebApplication extends AbstractWebApplication {
+    @Override
+    public Set<Class<?>> getClasses() {
+        return getClasses(OpenstackNodeWebResource.class);
+    }
+}
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeWebResource.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeWebResource.java
index 9d311b2..e0f6e53 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeWebResource.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/web/OpenstackNodeWebResource.java
@@ -17,15 +17,11 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.Sets;
-import org.onlab.osgi.DefaultServiceDirectory;
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.DeviceId;
-import org.onosproject.openstacknode.api.NodeState;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
-import org.onosproject.openstacknode.impl.DefaultOpenstackNode;
 import org.onosproject.rest.AbstractWebResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,6 +43,10 @@
 import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
 import static javax.ws.rs.core.Response.created;
 
+/**
+ * Handles REST API call of openstack node config.
+ */
+
 @Path("configure")
 public class OpenstackNodeWebResource extends AbstractWebResource {
     private final Logger log = LoggerFactory.getLogger(getClass());
@@ -58,25 +58,22 @@
     private static final String NODE_ID = "NODE_ID";
     private static final String DELETE = "DELETE";
 
-    private static final String HOST_NAME = "hostname";
-    private static final String TYPE = "type";
-    private static final String MANAGEMENT_IP = "managementIp";
-    private static final String DATA_IP = "dataIp";
-    private static final String INTEGRATION_BRIDGE = "integrationBridge";
-    private static final String VLAN_INTF_NAME = "vlanPort";
-
-    // GATEWAY node specific fields
-    private static final String ROUTER_BRIDGE = "routerBridge";
-
-
     private final OpenstackNodeAdminService osNodeAdminService =
-            DefaultServiceDirectory.getService(OpenstackNodeAdminService.class);
+                                            get(OpenstackNodeAdminService.class);
     private final OpenstackNodeService osNodeService =
-            DefaultServiceDirectory.getService(OpenstackNodeService.class);
+                                            get(OpenstackNodeService.class);
 
     @Context
     private UriInfo uriInfo;
 
+    /**
+     * Creates a set of openstack nodes' config from the JSON input stream.
+     *
+     * @param input openstack nodes JSON input stream
+     * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+     * is malformed
+     * @onos.rsModel OpenstackNode
+     */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
@@ -97,6 +94,14 @@
         return created(locationBuilder.build()).build();
     }
 
+    /**
+     * Creates a set of openstack nodes' config from the JSON input stream.
+     *
+     * @param input openstack nodes JSON input stream
+     * @return 200 OK with the updated openstack node's config, 400 BAD_REQUEST
+     * if the JSON is malformed
+     * @onos.rsModel OpenstackNode
+     */
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
@@ -117,6 +122,13 @@
         return Response.ok().build();
     }
 
+    /**
+     * Removes a set of openstack nodes' config from the JSON input stream.
+     *
+     * @param input openstack nodes JSON input stream
+     * @return 204 NO_CONTENT, 400 BAD_REQUEST if the JSON is malformed
+     * @onos.rsModel OpenstackNode
+     */
     @DELETE
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
@@ -144,36 +156,14 @@
              ArrayNode nodes = (ArrayNode) jsonTree.path(NODES);
              nodes.forEach(node -> {
                  try {
-                     String hostname = node.get(HOST_NAME).asText();
-                     String type = node.get(TYPE).asText();
-                     String mIp = node.get(MANAGEMENT_IP).asText();
-                     String iBridge = node.get(INTEGRATION_BRIDGE).asText();
-                     String rBridge = null;
-                     if (node.get(ROUTER_BRIDGE) != null) {
-                         rBridge = node.get(ROUTER_BRIDGE).asText();
-                     }
-                     DefaultOpenstackNode.Builder nodeBuilder = DefaultOpenstackNode.builder()
-                             .hostname(hostname)
-                             .type(OpenstackNode.NodeType.valueOf(type))
-                             .managementIp(IpAddress.valueOf(mIp))
-                             .intgBridge(DeviceId.deviceId(iBridge))
-                             .state(NodeState.INIT);
+                     ObjectNode objectNode = node.deepCopy();
+                     OpenstackNode openstackNode =
+                             codec(OpenstackNode.class).decode(objectNode, this);
 
-                     if (node.get(VLAN_INTF_NAME) != null) {
-                         nodeBuilder.vlanIntf(node.get(VLAN_INTF_NAME).asText());
-                     }
-                     if (node.get(DATA_IP) != null) {
-                         nodeBuilder.dataIp(IpAddress.valueOf(node.get(DATA_IP).asText()));
-                     }
-                     if (rBridge != null) {
-                         nodeBuilder.routerBridge(DeviceId.deviceId(rBridge));
-                     }
-
-                     log.trace("node is {}", nodeBuilder.build().toString());
-                     nodeSet.add(nodeBuilder.build());
+                     nodeSet.add(openstackNode);
                  } catch (Exception e) {
                      log.error(e.toString());
-                     throw  new IllegalArgumentException();
+                     throw new IllegalArgumentException();
                  }
              });
         } catch (Exception e) {
diff --git a/apps/openstacknode/app/src/main/resources/definitions/OpenstackNode.json b/apps/openstacknode/app/src/main/resources/definitions/OpenstackNode.json
new file mode 100644
index 0000000..8ac64e3
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/definitions/OpenstackNode.json
@@ -0,0 +1,45 @@
+{
+  "type": "array",
+  "items": {
+    "type": "object",
+    "required": [
+      "hostname",
+      "type",
+      "managementIp",
+      "dataIp",
+      "uplinkPort",
+      "integrationBridge",
+      "vlanPort"
+    ],
+    "properties": {
+      "hostname": {
+        "type": "string",
+        "example": "host1"
+      },
+      "type": {
+        "type": "string",
+        "example": "GATEWAY"
+      },
+      "managementIp": {
+        "type": "string",
+        "example": "10.10.10.1"
+      },
+      "dataIp": {
+        "type": "string",
+        "example": "20.20.20.2"
+      },
+      "uplinkPort": {
+        "type": "string",
+        "example": "2"
+      },
+      "integrationBridge": {
+        "type": "string",
+        "example": "of:0000000000000001"
+      },
+      "vlanPort": {
+        "type": "string",
+        "example": "1"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml b/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml
index 689c8ec..e1f7ceb 100644
--- a/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/openstacknode/app/src/main/webapp/WEB-INF/web.xml
@@ -14,20 +14,38 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          id="ONOS" version="2.5">
     <display-name>Openstack Node REST API v1.0</display-name>
 
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>JAX-RS Service</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
         <init-param>
-            <param-name>jersey.config.server.provider.classnames</param-name>
-            <param-value>
-                org.onosproject.openstacknode.web.OpenstackNodeWebResource
-            </param-value>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.onosproject.openstacknode.web.OpenstackNodeWebApplication</param-value>
         </init-param>
         <load-on-startup>1</load-on-startup>
     </servlet>
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandlerTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandlerTest.java
index b748bb8..a55cb25 100644
--- a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandlerTest.java
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandlerTest.java
@@ -40,7 +40,6 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.core.DefaultApplicationId;
-import org.onosproject.core.GroupId;
 import org.onosproject.net.Annotations;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DefaultDevice;
@@ -70,14 +69,6 @@
 import org.onosproject.net.flow.instructions.ExtensionPropertyException;
 import org.onosproject.net.flow.instructions.ExtensionTreatment;
 import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
-import org.onosproject.net.group.DefaultGroup;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupBuckets;
-import org.onosproject.net.group.GroupDescription;
-import org.onosproject.net.group.GroupEvent;
-import org.onosproject.net.group.GroupKey;
-import org.onosproject.net.group.GroupListener;
-import org.onosproject.net.group.GroupService;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.openstacknode.api.NodeState;
 import org.onosproject.openstacknode.api.OpenstackNode;
@@ -113,7 +104,6 @@
 import static org.onosproject.openstacknode.api.NodeState.DEVICE_CREATED;
 import static org.onosproject.openstacknode.api.NodeState.INCOMPLETE;
 import static org.onosproject.openstacknode.api.NodeState.INIT;
-import static org.onosproject.openstacknode.api.NodeState.PORT_CREATED;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 
@@ -145,38 +135,28 @@
     private static final String COMPUTE_1_HOSTNAME = "compute_1";
     private static final String COMPUTE_2_HOSTNAME = "compute_2";
     private static final String COMPUTE_3_HOSTNAME = "compute_3";
-    private static final String COMPUTE_4_HOSTNAME = "compute_4";
     private static final String GATEWAY_1_HOSTNAME = "gateway_1";
     private static final String GATEWAY_2_HOSTNAME = "gateway_2";
     private static final String GATEWAY_3_HOSTNAME = "gateway_3";
-    private static final String GATEWAY_4_HOSTNAME = "gateway_4";
 
     private static final IpAddress COMPUTE_1_IP = IpAddress.valueOf("10.100.0.1");
     private static final IpAddress COMPUTE_2_IP = IpAddress.valueOf("10.100.0.2");
     private static final IpAddress COMPUTE_3_IP = IpAddress.valueOf("10.100.0.3");
-    private static final IpAddress COMPUTE_4_IP = IpAddress.valueOf("10.100.0.4");
     private static final IpAddress GATEWAY_1_IP = IpAddress.valueOf("10.100.0.5");
     private static final IpAddress GATEWAY_2_IP = IpAddress.valueOf("10.100.0.6");
     private static final IpAddress GATEWAY_3_IP = IpAddress.valueOf("10.100.0.7");
-    private static final IpAddress GATEWAY_4_IP = IpAddress.valueOf("10.100.0.8");
+
+    private static final String GATEWAY_UPLINK_PORT = "eth0";
 
     private static final Device COMPUTE_1_INTG_DEVICE = createOpenFlowDevice(1, INTEGRATION_BRIDGE);
     private static final Device COMPUTE_2_INTG_DEVICE = createOpenFlowDevice(2, INTEGRATION_BRIDGE);
     private static final Device COMPUTE_3_INTG_DEVICE = createOpenFlowDevice(3, INTEGRATION_BRIDGE);
-    private static final Device COMPUTE_4_INTG_DEVICE = createOpenFlowDevice(4, INTEGRATION_BRIDGE);
-    private static final Device GATEWAY_1_INTG_DEVICE = createOpenFlowDevice(5, INTEGRATION_BRIDGE);
-    private static final Device GATEWAY_1_ROUT_DEVICE = createOpenFlowDevice(6, ROUTER_BRIDGE);
-    private static final Device GATEWAY_2_INTG_DEVICE = createOpenFlowDevice(7, INTEGRATION_BRIDGE);
-    private static final Device GATEWAY_2_ROUT_DEVICE = createOpenFlowDevice(8, ROUTER_BRIDGE);
-    private static final Device GATEWAY_3_INTG_DEVICE = createOpenFlowDevice(9, INTEGRATION_BRIDGE);
-    private static final Device GATEWAY_3_ROUT_DEVICE = createOpenFlowDevice(10, ROUTER_BRIDGE);
-    private static final Device GATEWAY_4_INTG_DEVICE = createOpenFlowDevice(11, INTEGRATION_BRIDGE);
-    private static final Device GATEWAY_4_ROUT_DEVICE = createOpenFlowDevice(12, ROUTER_BRIDGE);
+    private static final Device GATEWAY_1_INTG_DEVICE = createOpenFlowDevice(4, INTEGRATION_BRIDGE);
+    private static final Device GATEWAY_2_INTG_DEVICE = createOpenFlowDevice(5, INTEGRATION_BRIDGE);
+    private static final Device GATEWAY_3_INTG_DEVICE = createOpenFlowDevice(6, INTEGRATION_BRIDGE);
 
     private static final Device COMPUTE_1_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_1_IP);
     private static final Device COMPUTE_2_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_2_IP);
-    private static final Device COMPUTE_3_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_3_IP);
-    private static final Device COMPUTE_4_OVSDB_DEVICE = createOvsdbDevice(COMPUTE_4_IP);
     private static final Device GATEWAY_1_OVSDB_DEVICE = createOvsdbDevice(GATEWAY_1_IP);
     private static final Device GATEWAY_2_OVSDB_DEVICE = createOvsdbDevice(GATEWAY_2_IP);
 
@@ -201,14 +181,6 @@
             COMPUTE,
             COMPUTE_3_INTG_DEVICE,
             COMPUTE_3_IP,
-            PORT_CREATED
-    );
-
-    private static final OpenstackNode COMPUTE_4 = createNode(
-            COMPUTE_4_HOSTNAME,
-            COMPUTE,
-            COMPUTE_4_INTG_DEVICE,
-            COMPUTE_4_IP,
             COMPLETE
     );
 
@@ -216,8 +188,8 @@
             GATEWAY_1_HOSTNAME,
             GATEWAY,
             GATEWAY_1_INTG_DEVICE,
-            GATEWAY_1_ROUT_DEVICE,
             GATEWAY_1_IP,
+            GATEWAY_UPLINK_PORT,
             INIT
     );
 
@@ -225,8 +197,8 @@
             GATEWAY_2_HOSTNAME,
             GATEWAY,
             GATEWAY_2_INTG_DEVICE,
-            GATEWAY_2_ROUT_DEVICE,
             GATEWAY_2_IP,
+            GATEWAY_UPLINK_PORT,
             DEVICE_CREATED
     );
 
@@ -234,17 +206,8 @@
             GATEWAY_3_HOSTNAME,
             GATEWAY,
             GATEWAY_3_INTG_DEVICE,
-            GATEWAY_3_ROUT_DEVICE,
             GATEWAY_3_IP,
-            PORT_CREATED
-    );
-
-    private static final OpenstackNode GATEWAY_4 = createNode(
-            GATEWAY_4_HOSTNAME,
-            GATEWAY,
-            GATEWAY_4_INTG_DEVICE,
-            GATEWAY_4_ROUT_DEVICE,
-            GATEWAY_4_IP,
+            GATEWAY_UPLINK_PORT,
             COMPLETE
     );
 
@@ -280,7 +243,6 @@
         target.deviceService = TEST_DEVICE_SERVICE;
         target.deviceAdminService = mockDeviceAdminService;
         target.ovsdbController = mockOvsdbController;
-        target.groupService = new TestGroupService();
         target.osNodeService = testNodeManager;
         target.osNodeAdminService = testNodeManager;
         target.componentConfigService = new TestComponentConfigService();
@@ -341,7 +303,7 @@
         assertEquals(ERR_STATE_NOT_MATCH, DEVICE_CREATED,
                 testNodeManager.node(COMPUTE_2_HOSTNAME).state());
         target.processDeviceCreatedState(COMPUTE_2);
-        assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED,
+        assertEquals(ERR_STATE_NOT_MATCH, COMPLETE,
                 testNodeManager.node(COMPUTE_2_HOSTNAME).state());
     }
 
@@ -354,69 +316,28 @@
         testNodeManager.createNode(GATEWAY_2);
         TEST_DEVICE_SERVICE.devMap.put(GATEWAY_2_OVSDB_DEVICE.id(), GATEWAY_2_OVSDB_DEVICE);
         TEST_DEVICE_SERVICE.devMap.put(GATEWAY_2_INTG_DEVICE.id(), GATEWAY_2_INTG_DEVICE);
+        TEST_DEVICE_SERVICE.portList.add(createPort(GATEWAY_2_INTG_DEVICE, GATEWAY_UPLINK_PORT));
 
         assertEquals(ERR_STATE_NOT_MATCH, DEVICE_CREATED,
                 testNodeManager.node(GATEWAY_2_HOSTNAME).state());
         target.processDeviceCreatedState(GATEWAY_2);
-        assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED,
+        assertEquals(ERR_STATE_NOT_MATCH, COMPLETE,
                 testNodeManager.node(GATEWAY_2_HOSTNAME).state());
     }
 
     /**
-     * Checks if the compute node state changes from PORT_CREATED to
-     * COMPLETE after processing PORT_CREATED state.
-     */
-    @Test
-    public void testComputeNodeProcessPortCreatedState() {
-        testNodeManager.createNode(COMPUTE_3);
-        TEST_DEVICE_SERVICE.devMap.put(COMPUTE_3_OVSDB_DEVICE.id(), COMPUTE_3_OVSDB_DEVICE);
-        TEST_DEVICE_SERVICE.devMap.put(COMPUTE_3_INTG_DEVICE.id(), COMPUTE_3_INTG_DEVICE);
-        TEST_DEVICE_SERVICE.portList.add(createPort(COMPUTE_3_INTG_DEVICE, DEFAULT_TUNNEL));
-
-        testNodeManager.createNode(GATEWAY_4);
-        TEST_DEVICE_SERVICE.devMap.put(GATEWAY_4_INTG_DEVICE.id(), GATEWAY_4_INTG_DEVICE);
-
-        assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED,
-                testNodeManager.node(COMPUTE_3_HOSTNAME).state());
-        target.processPortCreatedState(COMPUTE_3);
-        assertEquals(ERR_STATE_NOT_MATCH, COMPLETE,
-                testNodeManager.node(COMPUTE_3_HOSTNAME).state());
-    }
-
-    /**
-     * Checks if the gateway node state changes from PORT_CREATED to
-     * COMPLETE after processing PORT_CREATED state.
-     */
-    @Test
-    public void testGatewayNodeProcessPortCreatedState() {
-        testNodeManager.createNode(COMPUTE_4);
-        TEST_DEVICE_SERVICE.devMap.put(COMPUTE_4_OVSDB_DEVICE.id(), COMPUTE_4_OVSDB_DEVICE);
-        TEST_DEVICE_SERVICE.devMap.put(COMPUTE_4_INTG_DEVICE.id(), COMPUTE_4_INTG_DEVICE);
-        TEST_DEVICE_SERVICE.portList.add(createPort(COMPUTE_4_INTG_DEVICE, DEFAULT_TUNNEL));
-
-        testNodeManager.createNode(GATEWAY_3);
-        TEST_DEVICE_SERVICE.devMap.put(GATEWAY_3_INTG_DEVICE.id(), GATEWAY_4_INTG_DEVICE);
-
-        assertEquals(ERR_STATE_NOT_MATCH, PORT_CREATED,
-                testNodeManager.node(GATEWAY_3_HOSTNAME).state());
-        target.processPortCreatedState(GATEWAY_3);
-        assertEquals(ERR_STATE_NOT_MATCH, COMPLETE,
-                testNodeManager.node(GATEWAY_3_HOSTNAME).state());
-    }
-
-    /**
      * Checks if the compute node state changes from COMPLETE to INCOMPLETE
      * when integration bridge is disconnected.
      */
     @Test
     public void testBackToIncompleteWhenBrIntDisconnected() {
-        testNodeManager.createNode(COMPUTE_4);
+        testNodeManager.createNode(COMPUTE_3);
 
         assertEquals(ERR_STATE_NOT_MATCH, COMPLETE,
-                testNodeManager.node(COMPUTE_4_HOSTNAME).state());
-        TEST_DEVICE_SERVICE.removeDevice(COMPUTE_4_INTG_DEVICE);
+                testNodeManager.node(COMPUTE_3_HOSTNAME).state());
+        TEST_DEVICE_SERVICE.removeDevice(COMPUTE_3_INTG_DEVICE);
         assertEquals(ERR_STATE_NOT_MATCH, INCOMPLETE,
-                testNodeManager.node(COMPUTE_4_HOSTNAME).state());
+                testNodeManager.node(COMPUTE_3_HOSTNAME).state());
     }
 
     /**
@@ -425,14 +346,14 @@
      */
     @Test
     public void testBackToIncompleteWhenVxlanRemoved() {
-        testNodeManager.createNode(COMPUTE_4);
+        testNodeManager.createNode(COMPUTE_3);
 
         assertEquals(ERR_STATE_NOT_MATCH, COMPLETE,
-                testNodeManager.node(COMPUTE_4_HOSTNAME).state());
-        TEST_DEVICE_SERVICE.removePort(COMPUTE_4_INTG_DEVICE, createPort(
-                COMPUTE_4_INTG_DEVICE, DEFAULT_TUNNEL));
+                testNodeManager.node(COMPUTE_3_HOSTNAME).state());
+        TEST_DEVICE_SERVICE.removePort(COMPUTE_3_INTG_DEVICE, createPort(
+                COMPUTE_3_INTG_DEVICE, DEFAULT_TUNNEL));
         assertEquals(ERR_STATE_NOT_MATCH, INCOMPLETE,
-                testNodeManager.node(COMPUTE_4_HOSTNAME).state());
+                testNodeManager.node(COMPUTE_3_HOSTNAME).state());
 
     }
 
@@ -474,26 +395,24 @@
                 hostname,
                 type,
                 intgBridge.id(),
-                null,
                 ipAddr,
                 ipAddr,
-                null, state);
+                null, null, state);
     }
 
     private static OpenstackNode createNode(String hostname,
                                             OpenstackNode.NodeType type,
                                             Device intgBridge,
-                                            Device routerBridge,
                                             IpAddress ipAddr,
+                                            String uplinkPort,
                                             NodeState state) {
         return new TestOpenstackNode(
                 hostname,
                 type,
                 intgBridge.id(),
-                routerBridge.id(),
                 ipAddr,
                 ipAddr,
-                null, state);
+                null, uplinkPort, state);
     }
 
     private static final class TestDevice extends DefaultDevice {
@@ -546,18 +465,18 @@
         private TestOpenstackNode(String hostname,
                                   NodeType type,
                                   DeviceId intgBridge,
-                                  DeviceId routerBridge,
                                   IpAddress managementIp,
                                   IpAddress dataIp,
                                   String vlanIntf,
+                                  String uplinkPort,
                                   NodeState state) {
             super(hostname,
                     type,
                     intgBridge,
-                    routerBridge,
                     managementIp,
                     dataIp,
                     vlanIntf,
+                    uplinkPort,
                     state);
         }
 
@@ -572,11 +491,6 @@
         }
 
         @Override
-        public PortNumber patchPortNum() {
-            return PortNumber.portNumber(1);
-        }
-
-        @Override
         public MacAddress vlanPortMac() {
             return MacAddress.NONE;
         }
@@ -621,8 +535,7 @@
         public OpenstackNode node(DeviceId deviceId) {
             return osNodeMap.values().stream()
                     .filter(osNode -> Objects.equals(osNode.intgBridge(), deviceId) ||
-                            Objects.equals(osNode.ovsdb(), deviceId) ||
-                            Objects.equals(osNode.routerBridge(), deviceId))
+                            Objects.equals(osNode.ovsdb(), deviceId))
                     .findFirst().orElse(null);
         }
 
@@ -885,81 +798,6 @@
         }
     }
 
-    private static class TestGroupService implements GroupService {
-        Map<GroupKey, Group> groupMap = Maps.newHashMap();
-        Map<GroupKey, GroupBuckets> groupBucketsMap = Maps.newHashMap();
-        List<GroupListener> listeners = Lists.newArrayList();
-
-        @Override
-        public void addListener(GroupListener listener) {
-            listeners.add(listener);
-        }
-
-        @Override
-        public void removeListener(GroupListener listener) {
-            listeners.remove(listener);
-        }
-
-        @Override
-        public void addGroup(GroupDescription groupDesc) {
-            DefaultGroup group = new DefaultGroup(GroupId.valueOf(groupDesc.givenGroupId()), groupDesc);
-            group.setState(Group.GroupState.ADDED);
-            groupMap.put(groupDesc.appCookie(), group);
-            groupBucketsMap.put(groupDesc.appCookie(), groupDesc.buckets());
-
-            GroupEvent event = new GroupEvent(GroupEvent.Type.GROUP_ADDED, group);
-            listeners.stream().filter(listener -> listener.isRelevant(event))
-                    .forEach(listener -> listener.event(event));
-        }
-
-        @Override
-        public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
-            return groupMap.get(appCookie);
-        }
-
-        @Override
-        public void addBucketsToGroup(DeviceId deviceId, GroupKey oldCookie, GroupBuckets buckets,
-                                      GroupKey newCookie, ApplicationId appId) {
-
-        }
-
-        @Override
-        public void removeBucketsFromGroup(DeviceId deviceId, GroupKey oldCookie, GroupBuckets buckets,
-                                           GroupKey newCookie, ApplicationId appId) {
-
-        }
-
-        @Override
-        public void purgeGroupEntries(DeviceId deviceId) {
-
-        }
-
-        @Override
-        public void removeGroup(DeviceId deviceId, GroupKey appCookie, ApplicationId appId) {
-
-        }
-
-        @Override
-        public Iterable<Group> getGroups(DeviceId deviceId, ApplicationId appId) {
-            return null;
-        }
-
-        @Override
-        public Iterable<Group> getGroups(DeviceId deviceId) {
-            return null;
-        }
-
-        @Override
-        public void setBucketsForGroup(DeviceId deviceId, GroupKey oldCookie, GroupBuckets buckets,
-                                       GroupKey newCookie, ApplicationId appId) {
-            groupBucketsMap.put(newCookie, buckets);
-            GroupEvent event = new GroupEvent(GroupEvent.Type.GROUP_UPDATED, groupMap.get(newCookie));
-            listeners.stream().filter(listener -> listener.isRelevant(event))
-                    .forEach(listener -> listener.event(event));
-        }
-
-    }
-
     private static class TestExtensionTreatment implements ExtensionTreatment {
         Ip4Address tunnelDst;
 
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeTest.java
index b881dff..47ce53d 100644
--- a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeTest.java
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeTest.java
@@ -133,20 +133,4 @@
                 .state(NodeState.INIT)
                 .build();
     }
-
-    /**
-     * Checks building a gateway type node without router bridge ID
-     * fails with proper exception.
-     */
-    @Test(expected = IllegalArgumentException.class)
-    public void testGatewayWithoutRouterBridgeId() {
-        DefaultOpenstackNode.builder()
-                .hostname(HOSTNAME_1)
-                .type(OpenstackNode.NodeType.GATEWAY)
-                .intgBridge(DEVICE_1.id())
-                .managementIp(TEST_IP)
-                .dataIp(TEST_IP)
-                .state(NodeState.INIT)
-                .build();
-    }
 }
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java
index 28cdfde..df9ae73 100644
--- a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java
@@ -64,11 +64,12 @@
     private static final String COMPUTE_3_HOSTNAME = "compute_3";
     private static final String GATEWAY_1_HOSTNAME = "gateway_1";
 
+    private static final String GATEWAY_1_UPLINKPORT = "eth0";
+
     private static final Device COMPUTE_1_INTG_DEVICE = createDevice(1);
     private static final Device COMPUTE_2_INTG_DEVICE = createDevice(2);
     private static final Device COMPUTE_3_INTG_DEVICE = createDevice(3);
     private static final Device GATEWAY_1_INTG_DEVICE = createDevice(4);
-    private static final Device GATEWAY_1_ROUT_DEVICE = createDevice(5);
 
     private static final OpenstackNode COMPUTE_1 = createNode(
             COMPUTE_1_HOSTNAME,
@@ -95,8 +96,8 @@
             GATEWAY_1_HOSTNAME,
             OpenstackNode.NodeType.GATEWAY,
             GATEWAY_1_INTG_DEVICE,
-            GATEWAY_1_ROUT_DEVICE,
             IpAddress.valueOf("10.100.0.4"),
+            GATEWAY_1_UPLINKPORT,
             NodeState.COMPLETE
     );
 
@@ -288,8 +289,6 @@
                 target.node(GATEWAY_1_INTG_DEVICE.id()), GATEWAY_1));
         assertTrue(ERR_NOT_FOUND, Objects.equals(
                 target.node(GATEWAY_1.ovsdb()), GATEWAY_1));
-        assertTrue(ERR_NOT_FOUND, Objects.equals(
-                target.node(GATEWAY_1.routerBridge()), GATEWAY_1));
     }
 
     private void validateEvents(Enum... types) {
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeTest.java
index 53bd593..fbec333 100644
--- a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeTest.java
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeTest.java
@@ -57,15 +57,15 @@
     }
 
     protected static OpenstackNode createNode(String hostname, NodeType type,
-                                              Device intgBridge, Device routerBridge,
-                                              IpAddress ipAddr, NodeState state) {
+                                              Device intgBridge, IpAddress ipAddr,
+                                              String uplinkPort, NodeState state) {
         return org.onosproject.openstacknode.impl.DefaultOpenstackNode.builder()
                 .hostname(hostname)
                 .type(type)
                 .intgBridge(intgBridge.id())
-                .routerBridge(routerBridge.id())
                 .managementIp(ipAddr)
                 .dataIp(ipAddr)
+                .uplinkPort(uplinkPort)
                 .state(state)
                 .build();
     }
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/web/OpenstackNodeWebResourceTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/web/OpenstackNodeWebResourceTest.java
new file mode 100644
index 0000000..ed8cd9a
--- /dev/null
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/web/OpenstackNodeWebResourceTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2018-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.openstacknode.web;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecService;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.openstacknode.codec.OpenstackNodeCodec;
+import org.onosproject.openstacknode.impl.DefaultOpenstackNode;
+import org.onosproject.rest.resources.ResourceTest;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.anyString;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit test for Openstack node REST API.
+ */
+public class OpenstackNodeWebResourceTest extends ResourceTest {
+
+    final OpenstackNodeService mockOpenstackNodeService =
+            createMock(OpenstackNodeService.class);
+    final OpenstackNodeAdminService mockOpenstackNodeAdminService =
+            createMock(OpenstackNodeAdminService.class);
+    private static final String PATH = "configure";
+
+    /**
+     * Constructs an openstack node resource test instance.
+     */
+    public OpenstackNodeWebResourceTest() {
+        super(ResourceConfig.forApplicationClass(OpenstackNodeWebApplication.class));
+    }
+
+    private OpenstackNode openstackNode;
+
+    /**
+     * Sets up the global values for all the tests.
+     */
+    @Before
+    public void setUpTest() {
+        final CodecManager codecService = new CodecManager();
+        codecService.activate();
+        codecService.registerCodec(OpenstackNode.class, new OpenstackNodeCodec());
+        ServiceDirectory testDirectory =
+                new TestServiceDirectory()
+                        .add(OpenstackNodeService.class, mockOpenstackNodeService)
+                        .add(OpenstackNodeAdminService.class, mockOpenstackNodeAdminService)
+                        .add(CodecService.class, codecService);
+        setServiceDirectory(testDirectory);
+
+        openstackNode = DefaultOpenstackNode.builder()
+                            .hostname("compute-node")
+                            .type(OpenstackNode.NodeType.COMPUTE)
+                            .dataIp(IpAddress.valueOf("10.134.34.222"))
+                            .managementIp(IpAddress.valueOf("10.134.231.30"))
+                            .intgBridge(DeviceId.deviceId("of:00000000000000a1"))
+                            .uplinkPort("eth2")
+                            .state(NodeState.INIT)
+                            .build();
+    }
+
+    /**
+     * Tests the results of the REST API POST with creating new nodes operation.
+     */
+    @Test
+    public void testCreateNodesWithCreateOperation() {
+        expect(mockOpenstackNodeService.node(anyString())).andReturn(null).once();
+        replay(mockOpenstackNodeService);
+
+        mockOpenstackNodeAdminService.createNode(anyObject());
+        replay(mockOpenstackNodeAdminService);
+
+        final WebTarget wt = target();
+        InputStream jsonStream = OpenstackNodeWebResourceTest.class
+                .getResourceAsStream("openstack-node-gateway-config.json");
+        Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        final int status = response.getStatus();
+
+        assertThat(status, is(201));
+
+        verify(mockOpenstackNodeService);
+        verify(mockOpenstackNodeAdminService);
+    }
+
+    /**
+     * Tests the results of the REST API POST without creating new nodes operation.
+     */
+    @Test
+    public void testCreateNodesWithoutCreateOperation() {
+        expect(mockOpenstackNodeService.node(anyString())).andReturn(openstackNode).once();
+        replay(mockOpenstackNodeService);
+
+        final WebTarget wt = target();
+        InputStream jsonStream = OpenstackNodeWebResourceTest.class
+                .getResourceAsStream("openstack-node-gateway-config.json");
+        Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        final int status = response.getStatus();
+
+        assertThat(status, is(201));
+
+        verify(mockOpenstackNodeService);
+    }
+
+    /**
+     * Tests the results of the REST API PUT with modifying the nodes.
+     */
+    @Test
+    public void testUpdateNodesWithoutModifyOperation() {
+        expect(mockOpenstackNodeService.node(anyString())).andReturn(openstackNode).once();
+        replay(mockOpenstackNodeService);
+
+        mockOpenstackNodeAdminService.updateNode(anyObject());
+        replay(mockOpenstackNodeAdminService);
+
+        final WebTarget wt = target();
+        InputStream jsonStream = OpenstackNodeWebResourceTest.class
+                .getResourceAsStream("openstack-node-gateway-config.json");
+        Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
+                .put(Entity.json(jsonStream));
+        final int status = response.getStatus();
+
+        assertThat(status, is(200));
+
+        verify(mockOpenstackNodeService);
+        verify(mockOpenstackNodeAdminService);
+    }
+
+    /**
+     * Tests the results of the REST API PUT without modifying the nodes.
+     */
+    @Test
+    public void testUpdateNodesWithModifyOperation() {
+        expect(mockOpenstackNodeService.node(anyString())).andReturn(null).once();
+        replay(mockOpenstackNodeService);
+
+        final WebTarget wt = target();
+        InputStream jsonStream = OpenstackNodeWebResourceTest.class
+                .getResourceAsStream("openstack-node-gateway-config.json");
+        Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
+                .put(Entity.json(jsonStream));
+        final int status = response.getStatus();
+
+        assertThat(status, is(304));
+
+        verify(mockOpenstackNodeService);
+    }
+}
diff --git a/apps/openstacknode/app/src/test/resources/org/onosproject/openstacknode/web/openstack-node-gateway-config.json b/apps/openstacknode/app/src/test/resources/org/onosproject/openstacknode/web/openstack-node-gateway-config.json
new file mode 100644
index 0000000..af4537f
--- /dev/null
+++ b/apps/openstacknode/app/src/test/resources/org/onosproject/openstacknode/web/openstack-node-gateway-config.json
@@ -0,0 +1,14 @@
+{
+  "nodes" : [
+    {
+      "hostname" : "gateway-node",
+      "type" : "GATEWAY",
+      "managementIp" : "10.134.231.32",
+      "dataIp" : "10.134.34.224",
+      "integrationBridge" : "of:00000000000000a2",
+      "routerBridge" : "of:00000000000000b1",
+      "uplinkPort" : "eth2",
+      "routerController" : "172.17.0.2"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apps/openstacknode/network-cfg.json b/apps/openstacknode/network-cfg.json
index 6cca7ed..a9918d9 100644
--- a/apps/openstacknode/network-cfg.json
+++ b/apps/openstacknode/network-cfg.json
@@ -26,9 +26,7 @@
                                 "dataIp" : "172.16.130.7",
                                 "vlanPort" : "eth2",
                                 "integrationBridge" : "of:00000000000000a3",
-                                "routerBridge" : "of:00000000000000b1",
-                                "uplinkPort" : "quagga-router",
-                                "routerController" : "172.17.0.2"
+                                "uplinkPort" : "ens6"
 
                         }
                 ]
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index e3794c2..3612273 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -24,10 +24,16 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.Annotations;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultLink;
 import org.onosproject.net.DefaultOchSignalComparator;
+import org.onosproject.net.DefaultPath;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Link;
@@ -42,12 +48,12 @@
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.OpticalPathIntent;
 import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.resource.Resource;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.ResourceService;
 import org.onosproject.net.resource.Resources;
-import org.onosproject.net.topology.AdapterLinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyEdge;
 import org.onosproject.net.topology.TopologyService;
@@ -63,8 +69,8 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import java.util.stream.IntStream;
+import java.util.stream.Stream;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
@@ -78,6 +84,8 @@
     private static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class);
     // By default, allocate 50 GHz lambdas (4 slots of 12.5 GHz) for each intent.
     private static final int SLOT_COUNT = 4;
+    private static final ProviderId PROVIDER_ID = new ProviderId("opticalConnectivityIntent",
+            "org.onosproject.net.optical.intent");
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected IntentExtensionService intentManager;
@@ -137,7 +145,7 @@
                 .map(path -> Maps.immutableEntry(path, findFirstAvailableLambda(intent, path)))
                 .filter(entry -> !entry.getValue().isEmpty())
                 .filter(entry -> convertToResources(entry.getKey(),
-                                                    entry.getValue()).stream().allMatch(resourceService::isAvailable))
+                        entry.getValue()).stream().allMatch(resourceService::isAvailable))
                 .findFirst();
 
         // Allocate resources and create optical path intent
@@ -157,8 +165,8 @@
      * Only supports fixed grid for now.
      *
      * @param parentIntent this intent (used for resource tracking)
-     * @param path the path to use
-     * @param lambda the lambda to use
+     * @param path         the path to use
+     * @param lambda       the lambda to use
      * @return optical path intent
      */
     private Intent createIntent(OpticalConnectivityIntent parentIntent, Path path, OchSignal lambda) {
@@ -180,7 +188,7 @@
     /**
      * Convert given lambda as discrete resource of all path ports.
      *
-     * @param path the path
+     * @param path   the path
      * @param lambda the lambda
      * @return list of discrete resources
      */
@@ -197,7 +205,7 @@
     /**
      * Reserve all required resources for this intent.
      *
-     * @param intent the intent
+     * @param intent    the intent
      * @param resources list of resources to reserve
      */
     private void allocateResources(Intent intent, List<Resource> resources) {
@@ -252,7 +260,7 @@
 
     /**
      * Get the number of 12.5 GHz slots required for the path.
-     *
+     * <p>
      * For now this returns a constant value of 4 (i.e., fixed grid 50 GHz slot),
      * but in the future can depend on optical reach, line rate, transponder port capabilities, etc.
      *
@@ -284,7 +292,7 @@
      * Returns list of consecutive resources in given set of lambdas.
      *
      * @param lambdas list of lambdas
-     * @param count number of consecutive lambdas to return
+     * @param count   number of consecutive lambdas to return
      * @return list of consecutive lambdas
      */
     private List<OchSignal> findFirstLambda(Set<OchSignal> lambdas, int count) {
@@ -330,45 +338,73 @@
         // Route in WDM topology
         Topology topology = topologyService.currentTopology();
         //TODO: refactor with LinkWeigher class Implementation
-        LinkWeight weight = new LinkWeight() {
+        LinkWeigher weight = new LinkWeigher() {
 
             @Override
-            public double weight(TopologyEdge edge) {
+            public Weight getInitialWeight() {
+                return ScalarWeight.toWeight(0.0);
+            }
+
+            @Override
+            public Weight getNonViableWeight() {
+                return ScalarWeight.NON_VIABLE_WEIGHT;
+            }
+
+            @Override
+            public Weight weight(TopologyEdge edge) {
                 // Disregard inactive or non-optical links
                 if (edge.link().state() == Link.State.INACTIVE) {
-                    return -1;
+                    return ScalarWeight.toWeight(-1);
                 }
                 if (edge.link().type() != Link.Type.OPTICAL) {
-                    return -1;
+                    return ScalarWeight.toWeight(-1);
                 }
                 // Adhere to static port mappings
                 DeviceId srcDeviceId = edge.link().src().deviceId();
                 if (srcDeviceId.equals(intent.getSrc().deviceId())) {
                     ConnectPoint srcStaticPort = staticPort(intent.getSrc());
                     if (srcStaticPort != null) {
-                        return srcStaticPort.equals(edge.link().src()) ? 1 : -1;
+                        return ScalarWeight.toWeight(srcStaticPort.equals(edge.link().src()) ? 1 : -1);
                     }
                 }
                 DeviceId dstDeviceId = edge.link().dst().deviceId();
                 if (dstDeviceId.equals(intent.getDst().deviceId())) {
                     ConnectPoint dstStaticPort = staticPort(intent.getDst());
                     if (dstStaticPort != null) {
-                        return dstStaticPort.equals(edge.link().dst()) ? 1 : -1;
+                        return ScalarWeight.toWeight(dstStaticPort.equals(edge.link().dst()) ? 1 : -1);
                     }
                 }
 
-                return 1;
+                return ScalarWeight.toWeight(1);
             }
         };
 
         ConnectPoint start = intent.getSrc();
         ConnectPoint end = intent.getDst();
+
+        // 0 hop case
+        if (start.deviceId().equals(end.deviceId())) {
+            log.debug("install optical intent for 0 hop i.e srcDeviceId=dstDeviceId");
+            DefaultLink defaultLink = DefaultLink.builder()
+                    .providerId(PROVIDER_ID)
+                    .src(start)
+                    .dst(end)
+                    .state(Link.State.ACTIVE)
+                    .type(Link.Type.DIRECT)
+                    .isExpected(true)
+                    .build();
+            List<Link> links = ImmutableList.<Link>builder().add(defaultLink).build();
+            Annotations annotations = DefaultAnnotations.builder().build();
+            DefaultPath defaultPath = new DefaultPath(PROVIDER_ID, links, null, annotations);
+            return ImmutableList.<Path>builder().add(defaultPath).build().stream();
+        }
+
         //head link's src port should be same as intent src port and tail link dst port
         //should be same as intent dst port in the path.
         Stream<Path> paths = topologyService.getKShortestPaths(topology,
                 start.deviceId(),
                 end.deviceId(),
-                AdapterLinkWeigher.adapt(weight))
+                weight)
                 .filter(p -> p.links().get(0).src().port().equals(start.port()) &&
                         p.links().get(p.links().size() - 1).dst().port().equals(end.port()));
         if (log.isDebugEnabled()) {
@@ -376,9 +412,9 @@
                     .map(path -> {
                         // no-op map stage to add debug logging
                         log.debug("Candidate path: {}",
-                                  path.links().stream()
-                                          .map(lk -> lk.src() + "-" + lk.dst())
-                                          .collect(Collectors.toList()));
+                                path.links().stream()
+                                        .map(lk -> lk.src() + "-" + lk.dst())
+                                        .collect(Collectors.toList()));
                         return path;
                     });
         }
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompiler.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompiler.java
index 4b386bd..e45bfb1 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompiler.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompiler.java
@@ -21,6 +21,8 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
@@ -54,8 +56,9 @@
 import org.onosproject.net.resource.ResourceService;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.Resources;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyEdge;
 import org.onosproject.net.topology.TopologyService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -256,25 +259,41 @@
         // Route in OTU topology
         Topology topology = topologyService.currentTopology();
 
-        LinkWeight weight = edge -> {
-            // Disregard inactive or non-optical links
-            if (edge.link().state() == Link.State.INACTIVE) {
-                return -1;
+
+        class Weigher implements LinkWeigher {
+            @Override
+            public Weight weight(TopologyEdge edge) {
+                if (edge.link().state() == Link.State.INACTIVE) {
+                    return ScalarWeight.toWeight(-1);
+                }
+                if (edge.link().type() != Link.Type.OPTICAL) {
+                    return ScalarWeight.toWeight(-1);
+                }
+                // Find path with available TributarySlots resources
+                if (!isAvailableTributarySlots(intent, edge.link())) {
+                    return ScalarWeight.toWeight(-1);
+                }
+                return ScalarWeight.toWeight(1);
             }
-            if (edge.link().type() != Link.Type.OPTICAL) {
-                return -1;
+
+            @Override
+            public Weight getInitialWeight() {
+                return null;
             }
-            // Find path with available TributarySlots resources
-            if (!isAvailableTributarySlots(intent, edge.link())) {
-                return -1;
+
+            @Override
+            public Weight getNonViableWeight() {
+                return null;
             }
-            return 1;
-        };
+        }
+
+
+        LinkWeigher weigher = new Weigher();
 
         ConnectPoint start = intent.getSrc();
         ConnectPoint end = intent.getDst();
 
-        return topologyService.getPaths(topology, start.deviceId(), end.deviceId(), weight);
+        return topologyService.getPaths(topology, start.deviceId(), end.deviceId(), weigher);
     }
 
     private boolean isAvailableTributarySlots(OpticalOduIntent intent, Link link) {
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompiler.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompiler.java
index 0c777bf..9786cd4 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompiler.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompiler.java
@@ -99,11 +99,11 @@
 
         return Collections.singletonList(
                 new FlowRuleIntent(appId,
-                                   intent.key(),
-                                   rules,
-                                   intent.resources(),
-                                   PathIntent.ProtectionType.PRIMARY,
-                                   intent.resourceGroup()
+                        intent.key(),
+                        rules,
+                        intent.resources(),
+                        PathIntent.ProtectionType.PRIMARY,
+                        intent.resourceGroup()
                 )
         );
     }
@@ -119,6 +119,32 @@
         selectorBuilder.matchInPort(intent.src().port());
 
         List<FlowRule> rules = new LinkedList<>();
+
+        /*
+         * especial case for 0 hop when srcDeviceId = dstDeviceId
+         * and path contain only one fake default path.
+         */
+        if (intent.src().deviceId().equals(intent.dst().deviceId()) &&
+                intent.path().links().size() == 1) {
+            log.debug("handling 0 hop case for intent {}", intent);
+            TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+            if (!isTransparent(intent.src().deviceId())) {
+                treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda()));
+            }
+            treatmentBuilder.setOutput(intent.dst().port());
+
+            FlowRule rule = DefaultFlowRule.builder()
+                    .forDevice(intent.src().deviceId())
+                    .withSelector(selectorBuilder.build())
+                    .withTreatment(treatmentBuilder.build())
+                    .withPriority(intent.priority())
+                    .fromApp(appId)
+                    .makePermanent()
+                    .build();
+            rules.add(rule);
+            return rules;
+        }
+
         ConnectPoint current = intent.src();
 
         for (Link link : intent.path().links()) {
@@ -181,6 +207,32 @@
         selectorBuilder.matchInPort(intent.dst().port());
 
         List<FlowRule> rules = new LinkedList<>();
+
+        /*
+         * especial case for 0 hop when srcDeviceId = dstDeviceId
+         * and path contain only one fake default path.
+         */
+        if (intent.src().deviceId().equals(intent.dst().deviceId()) &&
+                intent.path().links().size() == 1) {
+            log.debug("handling 0 hop reverse path case for intent {}", intent);
+            TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+            if (!isTransparent(intent.src().deviceId())) {
+                treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda()));
+            }
+            treatmentBuilder.setOutput(intent.src().port());
+
+            FlowRule rule = DefaultFlowRule.builder()
+                    .forDevice(intent.src().deviceId())
+                    .withSelector(selectorBuilder.build())
+                    .withTreatment(treatmentBuilder.build())
+                    .withPriority(intent.priority())
+                    .fromApp(appId)
+                    .makePermanent()
+                    .build();
+            rules.add(rule);
+            return rules;
+        }
+
         ConnectPoint current = intent.dst();
 
         for (Link link : Lists.reverse(intent.path().links())) {
@@ -254,7 +306,7 @@
     private boolean isTransparent(DeviceId deviceId) {
         return TRANSPARENT_DEVICES.contains(
                 Optional.ofNullable(deviceService.getDevice(deviceId))
-                .map(Device::type)
-                .orElse(Type.OTHER));
+                        .map(Device::type)
+                        .orElse(Type.OTHER));
     }
 }
diff --git a/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompilerTest.java b/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompilerTest.java
index 1ae85a7..2c39274 100644
--- a/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompilerTest.java
+++ b/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalOduIntentCompilerTest.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.ChassisId;
 import org.onosproject.TestApplicationId;
 import org.onosproject.core.ApplicationId;
@@ -65,7 +66,7 @@
 import org.onosproject.net.optical.impl.DefaultOtuPort;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.resource.MockResourceService;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyServiceAdapter;
 
@@ -161,7 +162,7 @@
             DefaultLink.builder().providerId(PID).src(d1p2).dst(d2p1).type(OPTICAL).build(),
             DefaultLink.builder().providerId(PID).src(d2p2).dst(d3p1).type(OPTICAL).build()
     );
-    private final Path path = new DefaultPath(PID, links, 3);
+    private final Path path = new DefaultPath(PID, links, ScalarWeight.toWeight(3));
 
     private OpticalOduIntent intent;
 
@@ -172,13 +173,13 @@
         Set<Path> paths = Sets.newHashSet(path);
 
         @Override
-        public Topology currentTopology() {
-            return null;
+        public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeigher weight) {
+            return paths;
         }
 
         @Override
-        public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight) {
-            return paths;
+        public Topology currentTopology() {
+            return null;
         }
     }
 
diff --git a/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompilerTest.java
index d8ae141..43c279d 100644
--- a/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompilerTest.java
+++ b/apps/optical-model/src/test/java/org/onosproject/net/optical/intent/impl/compiler/OpticalPathIntentCompilerTest.java
@@ -17,6 +17,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onosproject.TestApplicationId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
@@ -78,7 +79,7 @@
                 .appId(appId)
                 .src(d1p1)
                 .dst(d3p1)
-                .path(new DefaultPath(PID, links, hops))
+                .path(new DefaultPath(PID, links, ScalarWeight.toWeight(hops)))
                 .lambda(createLambda())
                 .signalType(OchSignalType.FIXED_GRID)
                 .build();
diff --git a/apps/pathpainter/src/main/java/org/onosproject/pathpainter/PathPainterTopovMessageHandler.java b/apps/pathpainter/src/main/java/org/onosproject/pathpainter/PathPainterTopovMessageHandler.java
index 7da14a9..b1f9d44 100644
--- a/apps/pathpainter/src/main/java/org/onosproject/pathpainter/PathPainterTopovMessageHandler.java
+++ b/apps/pathpainter/src/main/java/org/onosproject/pathpainter/PathPainterTopovMessageHandler.java
@@ -28,7 +28,7 @@
 import org.onosproject.net.Path;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.topology.GeoDistanceLinkWeight;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.net.topology.PathService;
 import org.onosproject.net.topology.TopologyEvent;
 import org.onosproject.net.topology.TopologyListener;
@@ -78,7 +78,7 @@
 
     private Set<Link> allPathLinks;
     private boolean listenersRemoved;
-    private LinkWeight linkData;
+    private LinkWeigher linkData;
     private int highlightDelay;
 
     private enum Mode {
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
index d1e3d66..e7ef935 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
@@ -17,6 +17,8 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onosproject.net.DisjointPath;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -67,6 +69,7 @@
 import org.onosproject.net.link.LinkEvent;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.bandwidthmgr.api.BandwidthMgmtService;
+import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
 import org.onosproject.pce.pceservice.constraint.CapabilityConstraint.CapabilityType;
 import org.onosproject.pce.pceservice.constraint.CostConstraint;
@@ -74,7 +77,6 @@
 import org.onosproject.pce.pceservice.constraint.SharedBandwidthConstraint;
 import org.onosproject.net.resource.Resource;
 import org.onosproject.net.resource.ResourceAllocation;
-import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.PathService;
 import org.onosproject.net.topology.TopologyEdge;
 import org.onosproject.net.topology.TopologyEvent;
@@ -224,7 +226,7 @@
      * @param constraints path constraints
      * @return edge-weight function
      */
-    private LinkWeight weight(List<Constraint> constraints) {
+    private LinkWeigher weight(List<Constraint> constraints) {
         return new TeConstraintBasedLinkWeight(constraints);
     }
 
@@ -532,7 +534,8 @@
                 links.addAll(path.links());
                 totalCost = totalCost + path.cost();
             }
-            computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(), links, totalCost));
+            computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(), links,
+                    ScalarWeight.toWeight(totalCost)));
         } else {
             computedPathSet = computePath(src, dst, constraints);
         }
@@ -804,7 +807,7 @@
                 totalCost = totalCost + path.cost();
             }
             computedPathSet.add(new DefaultPath(finalComputedPath.iterator().next().providerId(),
-                    totalLinks, totalCost));
+                    totalLinks, ScalarWeight.toWeight(totalCost)));
         } else {
             computedPathSet = computePath(tunnel.path().src().deviceId(), tunnel.path().dst().deviceId(),
                     constraints);
@@ -955,7 +958,7 @@
         return value;
     }
 
-    protected class TeConstraintBasedLinkWeight implements LinkWeight {
+    protected class TeConstraintBasedLinkWeight implements LinkWeigher {
 
         private final List<Constraint> constraints;
 
@@ -974,10 +977,20 @@
         }
 
         @Override
-        public double weight(TopologyEdge edge) {
+        public Weight getInitialWeight() {
+            return ScalarWeight.toWeight(0.0);
+        }
+
+        @Override
+        public Weight getNonViableWeight() {
+            return ScalarWeight.toWeight(0.0);
+        }
+
+        @Override
+        public Weight weight(TopologyEdge edge) {
             if (!constraints.iterator().hasNext()) {
                 //Takes default cost/hopcount as 1 if no constraints specified
-                return 1.0;
+                return ScalarWeight.toWeight(1.0);
             }
 
             Iterator<Constraint> it = constraints.iterator();
@@ -1001,7 +1014,7 @@
                     cost = constraint.cost(edge.link(), null);
                 }
             }
-            return cost;
+            return ScalarWeight.toWeight(cost);
         }
     }
 
diff --git a/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PathComputationTest.java b/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PathComputationTest.java
index bdd593c..fd13454 100644
--- a/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PathComputationTest.java
+++ b/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PathComputationTest.java
@@ -29,6 +29,8 @@
 import org.onlab.graph.DijkstraGraphSearch;
 import org.onlab.graph.Graph;
 import org.onlab.graph.GraphPathSearch;
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onlab.packet.ChassisId;
 import org.onlab.util.Bandwidth;
 import org.onosproject.net.AnnotationKeys;
@@ -53,7 +55,7 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.topology.DefaultTopologyEdge;
 import org.onosproject.net.topology.DefaultTopologyVertex;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.net.topology.TopologyEdge;
 import org.onosproject.net.topology.TopologyVertex;
 import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
@@ -82,7 +84,6 @@
 import static org.onosproject.net.DeviceId.deviceId;
 import static org.onosproject.net.Link.State.ACTIVE;
 import static org.onosproject.net.Link.Type.DIRECT;
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 import static org.onosproject.pce.pceservice.constraint.CostConstraint.Type.COST;
 import static org.onosproject.pce.pceservice.constraint.CostConstraint.Type.TE_COST;
 
@@ -168,7 +169,7 @@
      * @param constraints path constraints
      * @return edge-weight function
      */
-    private LinkWeight weight(List<Constraint> constraints) {
+    private LinkWeigher weight(List<Constraint> constraints) {
         return new MockTeConstraintBasedLinkWeight(constraints);
     }
 
@@ -180,7 +181,7 @@
                    new DefaultTopologyEdge(D3, D4, link4)));
 
         GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
-                graphSearch().search(graph, D1, D4, adapt(weight(constraints)), ALL_PATHS);
+                graphSearch().search(graph, D1, D4, weight(constraints), ALL_PATHS);
         ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
         for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
             builder.add(networkPath(path));
@@ -211,7 +212,7 @@
         }
     }
 
-    private class MockTeConstraintBasedLinkWeight implements LinkWeight {
+    private class MockTeConstraintBasedLinkWeight implements LinkWeigher {
 
         private final List<Constraint> constraints;
 
@@ -230,10 +231,20 @@
         }
 
         @Override
-        public double weight(TopologyEdge edge) {
+        public Weight getInitialWeight() {
+            return ScalarWeight.toWeight(0.0);
+        }
+
+        @Override
+        public Weight getNonViableWeight() {
+            return ScalarWeight.NON_VIABLE_WEIGHT;
+        }
+
+        @Override
+        public Weight weight(TopologyEdge edge) {
             if (!constraints.iterator().hasNext()) {
                 //Takes default cost/hopcount as 1 if no constraints specified
-                return 1.0;
+                return ScalarWeight.toWeight(1.0);
             }
 
             Iterator<Constraint> it = constraints.iterator();
@@ -259,7 +270,7 @@
                     cost = constraint.cost(edge.link(), null);
                 }
             }
-            return cost;
+            return ScalarWeight.toWeight(cost);
         }
     }
 
@@ -1274,7 +1285,7 @@
                    new DefaultTopologyEdge(D4, D5, link5)));
 
         GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
-                graphSearch().search(graph, D1, D5, adapt(weight(constraints)), ALL_PATHS);
+                graphSearch().search(graph, D1, D5, weight(constraints), ALL_PATHS);
         ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
         for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
             builder.add(networkPath(path));
diff --git a/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PceManagerTest.java b/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PceManagerTest.java
index 432ffb6..9cf7069 100644
--- a/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PceManagerTest.java
+++ b/apps/pce/app/src/test/java/org/onosproject/pce/pceservice/PceManagerTest.java
@@ -56,7 +56,7 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.topology.DefaultTopologyEdge;
 import org.onosproject.net.topology.DefaultTopologyVertex;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.net.topology.PathServiceAdapter;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyEdge;
@@ -92,7 +92,6 @@
 import static org.onosproject.incubator.net.tunnel.Tunnel.State.ESTABLISHED;
 import static org.onosproject.incubator.net.tunnel.Tunnel.State.UNSTABLE;
 import static org.onosproject.net.MastershipRole.MASTER;
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 import static org.onosproject.pce.pceservice.LspType.SR_WITHOUT_SIGNALLING;
 import static org.onosproject.pce.pceservice.LspType.WITHOUT_SIGNALLING_AND_WITHOUT_SR;
 import static org.onosproject.pce.pceservice.LspType.WITH_SIGNALLING;
@@ -1476,7 +1475,7 @@
         }
 
         @Override
-        public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight) {
+        public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeigher weight) {
             DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
             DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
             Set<TopologyVertex> vertices = graph.getVertexes();
@@ -1486,7 +1485,7 @@
             }
 
             GraphPathSearch.Result<TopologyVertex, TopologyEdge> result = PathComputationTest.graphSearch()
-                    .search(graph, srcV, dstV, adapt(weight), ALL_PATHS);
+                    .search(graph, srcV, dstV, weight, ALL_PATHS);
             ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
             for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
                 builder.add(PathComputationTest.networkPath(path));
@@ -1521,7 +1520,7 @@
     private class MockPathService extends PathServiceAdapter {
         Set<Path> computedPaths;
         @Override
-        public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
+        public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weight) {
             // If either edge is null, bail with no paths.
             if (src == null || dst == null) {
                 return ImmutableSet.of();
diff --git a/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java b/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java
index 51f5c2d..1e35395 100644
--- a/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java
+++ b/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java
@@ -44,6 +44,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.junit.TestUtils;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.osgi.TestServiceDirectory;
@@ -165,7 +166,7 @@
        linkList.add(l4);
 
        // Path
-       path = new DefaultPath(providerId, linkList, 10);
+       path = new DefaultPath(providerId, linkList, ScalarWeight.toWeight(10));
 
        // Annotations
        DefaultAnnotations.Builder builderAnn = DefaultAnnotations.builder();
diff --git a/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovOverlay.java b/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovOverlay.java
index 1ab69eb..38cfead 100644
--- a/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovOverlay.java
+++ b/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovOverlay.java
@@ -165,6 +165,7 @@
             Thread.sleep(100);
         } catch (InterruptedException e) {
             log.error("Exception occurred while getting the bandwidth.");
+            Thread.currentThread().interrupt();
         }
         Set<Resource> resources = resService.getRegisteredResources(devResource.id());
         for (Resource res : resources) {
diff --git a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
index 7c91bf3..c290da3 100644
--- a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
+++ b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
@@ -207,6 +207,7 @@
         } catch (InterruptedException e) {
             List<Runnable> runningTasks = executorService.shutdownNow();
             log.warn("Unable to stop the following tasks: {}", runningTasks);
+            Thread.currentThread().interrupt();
         }
         scheduledExecutorService.shutdown();
         deviceService.removeListener(deviceListener);
@@ -297,7 +298,7 @@
                 Thread.sleep(CLEANUP_SLEEP);
             } catch (InterruptedException e) {
                 log.warn("Cleanup sleep interrupted!");
-                Thread.interrupted();
+                Thread.currentThread().interrupt();
             }
         }
 
diff --git a/apps/rabbitmq/src/main/java/org/onosproject/rabbitmq/util/MQUtil.java b/apps/rabbitmq/src/main/java/org/onosproject/rabbitmq/util/MQUtil.java
index f5f649b..cfcea12 100644
--- a/apps/rabbitmq/src/main/java/org/onosproject/rabbitmq/util/MQUtil.java
+++ b/apps/rabbitmq/src/main/java/org/onosproject/rabbitmq/util/MQUtil.java
@@ -225,7 +225,7 @@
             properties.load(is);
         } catch (Exception e) {
             log.error(ExceptionUtils.getFullStackTrace(e));
-            throw new RuntimeException(e);
+            throw new IllegalStateException(e);
         }
         return properties;
     }
diff --git a/apps/restconf/restconfmgr/src/main/java/org/onosproject/restconf/restconfmanager/RestconfManager.java b/apps/restconf/restconfmgr/src/main/java/org/onosproject/restconf/restconfmanager/RestconfManager.java
index 0ad6b25..3ef0aca 100644
--- a/apps/restconf/restconfmgr/src/main/java/org/onosproject/restconf/restconfmanager/RestconfManager.java
+++ b/apps/restconf/restconfmgr/src/main/java/org/onosproject/restconf/restconfmanager/RestconfManager.java
@@ -276,12 +276,12 @@
         ResourceId resourceId = rpcInputNode.resourceId();
         List<DataNode> inputDataNodeList = rpcInputNode.dataNodes();
         DataNode inputDataNode = inputDataNodeList.get(0);
-        RpcInput rpcInput = new RpcInput(inputDataNode);
+        RpcInput rpcInput = new RpcInput(resourceId, inputDataNode);
 
         RestconfRpcOutput restconfOutput = null;
         try {
             CompletableFuture<RpcOutput> rpcFuture =
-                    dynamicConfigService.invokeRpc(resourceId, rpcInput);
+                    dynamicConfigService.invokeRpc(rpcInput);
             RpcOutput rpcOutput = rpcFuture.get();
             restconfOutput = RestconfUtils.convertRpcOutput(resourceId, rpcOutput);
         } catch (InterruptedException e) {
diff --git a/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteManager.java b/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteManager.java
index 0dc5dbe..e1acc2c 100644
--- a/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteManager.java
+++ b/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteManager.java
@@ -343,6 +343,7 @@
                     listener.event(queue.take());
                 } catch (InterruptedException e) {
                     log.info("Route listener event thread shutting down: {}", e.getMessage());
+                    Thread.currentThread().interrupt();
                     break;
                 } catch (Exception e) {
                     log.warn("Exception during route event handler", e);
diff --git a/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteMonitor.java b/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteMonitor.java
index 24d2aff..ede60db 100644
--- a/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteMonitor.java
+++ b/apps/route-service/app/src/main/java/org/onosproject/routeservice/impl/RouteMonitor.java
@@ -19,11 +19,13 @@
 import org.onosproject.cluster.ClusterEvent;
 import org.onosproject.cluster.ClusterEventListener;
 import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.routeservice.ResolvedRoute;
 import org.onosproject.routeservice.Route;
 import org.onosproject.routeservice.RouteAdminService;
 import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.AsyncDistributedLock;
 import org.onosproject.store.service.DistributedPrimitive;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
@@ -31,6 +33,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.time.Duration;
 import java.util.Collection;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.stream.Collectors;
@@ -46,12 +49,15 @@
     private final Logger log = LoggerFactory.getLogger(this.getClass());
 
     private static final String TOPIC = "route-reaper";
+    private static final String LOCK_NAME = "route-monitor-lock";
     private static final int NUM_PARALLEL_JOBS = 10;
 
     private RouteAdminService routeService;
     private final ClusterService clusterService;
     private StorageService storageService;
 
+    private final AsyncDistributedLock asyncLock;
+
     private WorkQueue<NodeId> queue;
 
     private final InternalClusterListener clusterListener = new InternalClusterListener();
@@ -72,6 +78,8 @@
         this.clusterService = clusterService;
         this.storageService = storageService;
 
+        asyncLock = storageService.lockBuilder().withName(LOCK_NAME).build();
+
         clusterService.addListener(clusterListener);
 
         queue = storageService.getWorkQueue(TOPIC, Serializer.using(KryoNamespaces.API));
@@ -86,6 +94,7 @@
     public void shutdown() {
         stopProcessing();
         clusterService.removeListener(clusterListener);
+        asyncLock.unlock();
     }
 
     private void statusChange(DistributedPrimitive.Status status) {
@@ -112,16 +121,23 @@
 
     private void cleanRoutes(NodeId node) {
         log.info("Cleaning routes from unavailable node {}", node);
-
         Collection<Route> routes = routeService.getRouteTables().stream()
                 .flatMap(id -> routeService.getRoutes(id).stream())
                 .flatMap(route -> route.allRoutes().stream())
                 .map(ResolvedRoute::route)
                 .filter(r -> r.sourceNode().equals(node))
                 .collect(Collectors.toList());
+        if (node.equals(clusterService.getLocalNode().id())) {
+            log.debug("Do not remove routes from local nodes {}", node);
+            return;
+        }
+
+        if (clusterService.getState(node) == ControllerNode.State.READY) {
+            log.debug("Do not remove routes from active nodes {}", node);
+            return;
+        }
 
         log.debug("Withdrawing routes: {}", routes);
-
         routeService.withdraw(routes);
     }
 
@@ -133,7 +149,19 @@
             case INSTANCE_DEACTIVATED:
                 NodeId id = event.subject().id();
                 log.info("Node {} deactivated", id);
-                queue.addOne(id);
+
+                // DistributedLock is introduced to guarantee that minority nodes won't try to remove
+                // routes that originated from majority nodes.
+                // Adding 15 seconds retry for the leadership election to be completed.
+                asyncLock.tryLock(Duration.ofSeconds(15)).whenComplete((result, error) -> {
+                    if (result != null && result.isPresent()) {
+                        log.debug("Lock obtained. Put {} into removal queue", id);
+                        queue.addOne(id);
+                        asyncLock.unlock();
+                    } else {
+                        log.debug("Fail to obtain lock. Do not remove routes from {}", id);
+                    }
+                });
                 break;
             case INSTANCE_ADDED:
             case INSTANCE_REMOVED:
@@ -144,5 +172,4 @@
             }
         }
     }
-
 }
diff --git a/apps/route-service/app/src/test/java/org/onosproject/routeservice/impl/RouteManagerTest.java b/apps/route-service/app/src/test/java/org/onosproject/routeservice/impl/RouteManagerTest.java
index 3ba34da..c6c0f82 100644
--- a/apps/route-service/app/src/test/java/org/onosproject/routeservice/impl/RouteManagerTest.java
+++ b/apps/route-service/app/src/test/java/org/onosproject/routeservice/impl/RouteManagerTest.java
@@ -47,6 +47,9 @@
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.host.HostServiceAdapter;
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.service.AsyncDistributedLock;
+import org.onosproject.store.service.DistributedLock;
+import org.onosproject.store.service.DistributedLockBuilder;
 import org.onosproject.store.service.StorageService;
 import org.onosproject.store.service.WorkQueue;
 
@@ -104,6 +107,18 @@
         routeManager.clusterService = createNiceMock(ClusterService.class);
         replay(routeManager.clusterService);
         routeManager.storageService = createNiceMock(StorageService.class);
+
+        AsyncDistributedLock adl = createNiceMock(AsyncDistributedLock.class);
+        expect(adl.asLock()).andReturn(createNiceMock(DistributedLock.class));
+        replay(adl);
+
+        DistributedLockBuilder dlb = createNiceMock(DistributedLockBuilder.class);
+        expect(dlb.withName(anyString())).andReturn(dlb);
+        expect(dlb.build()).andReturn(adl);
+        replay(dlb);
+
+        expect(routeManager.storageService.lockBuilder())
+                .andReturn(dlb);
         expect(routeManager.storageService.getWorkQueue(anyString(), anyObject()))
                 .andReturn(createNiceMock(WorkQueue.class));
         replay(routeManager.storageService);
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmInfoService.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmInfoService.java
index a160fc0..c604707 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmInfoService.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmInfoService.java
@@ -36,4 +36,9 @@
      * @return true or false
      */
     boolean isPdPushEnabled();
+
+    /**
+     * Pushes all local FPM routes to route store.
+     */
+    void pushFpmRoutes();
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmManager.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmManager.java
index 0cf9935..455e546 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmManager.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/FpmManager.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.routing.fpm;
 
+import com.google.common.collect.Lists;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -47,6 +48,8 @@
 import org.onlab.util.KryoNamespace;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cluster.ClusterEvent;
+import org.onosproject.cluster.ClusterEventListener;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.CoreService;
@@ -62,6 +65,7 @@
 import org.onosproject.routing.fpm.protocol.RtNetlink;
 import org.onosproject.routing.fpm.protocol.RtProtocol;
 import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.AsyncDistributedLock;
 import org.onosproject.store.service.ConsistentMap;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
@@ -71,7 +75,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.net.InetSocketAddress;
-import java.util.ArrayList;
+import java.time.Duration;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
@@ -101,6 +105,7 @@
     private static final int FPM_PORT = 2620;
     private static final String APP_NAME = "org.onosproject.fpm";
     private static final int IDLE_TIMEOUT_SECS = 5;
+    private static final String LOCK_NAME = "fpm-manager-lock";
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
@@ -141,6 +146,8 @@
     private ServerBootstrap serverBootstrap;
     private Channel serverChannel;
     private ChannelGroup allChannels = new DefaultChannelGroup();
+    private final InternalClusterListener clusterListener = new InternalClusterListener();
+    private AsyncDistributedLock asyncLock;
 
     private ConsistentMap<FpmPeer, Set<FpmConnectionInfo>> peers;
 
@@ -219,6 +226,9 @@
 
         appId = coreService.registerApplication(APP_NAME, peers::destroy);
 
+        asyncLock = storageService.lockBuilder().withName(LOCK_NAME).build();
+        clusterService.addListener(clusterListener);
+
         log.info("Started");
     }
 
@@ -231,6 +241,10 @@
         stopServer();
         fpmRoutes.clear();
         componentConfigService.unregisterProperties(getClass(), false);
+
+        clusterService.removeListener(clusterListener);
+        asyncLock.unlock();
+
         log.info("Stopped");
     }
 
@@ -463,15 +477,19 @@
             break;
         }
 
-        routeService.withdraw(withdraws);
-        routeService.update(updates);
+        updateRouteStore(updates, withdraws);
+    }
+
+    private synchronized void updateRouteStore(Collection<Route> routesToAdd, Collection<Route> routesToRemove) {
+        routeService.withdraw(routesToRemove);
+        routeService.update(routesToAdd);
     }
 
     private void clearRoutes(FpmPeer peer) {
         log.info("Clearing all routes for peer {}", peer);
         Map<IpPrefix, Route> routes = fpmRoutes.remove(peer);
         if (routes != null) {
-            routeService.withdraw(routes.values());
+            updateRouteStore(Lists.newArrayList(), routes.values());
         }
     }
 
@@ -512,24 +530,23 @@
 
     private void sendRouteUpdateToChannel(boolean isAdd, IpPrefix prefix, Channel ch) {
 
-        int netLinkLength;
-        short addrFamily;
-        IpAddress pdPushNextHop;
-
         if (!pdPushEnabled) {
             return;
         }
 
         try {
-            // Construct list of route attributes.
-            List<RouteAttribute> attributes = new ArrayList<>();
+            int raLength;
+            short addrFamily;
+            IpAddress pdPushNextHop;
+
+            // Build route attributes.
             if (prefix.isIp4()) {
                 if (pdPushNextHopIPv4 == null) {
                     log.info("Prefix not pushed because ipv4 next-hop is null.");
                     return;
                 }
                 pdPushNextHop = pdPushNextHopIPv4;
-                netLinkLength =  Ip4Address.BYTE_LENGTH + RouteAttribute.ROUTE_ATTRIBUTE_HEADER_LENGTH;
+                raLength =  Ip4Address.BYTE_LENGTH + RouteAttribute.ROUTE_ATTRIBUTE_HEADER_LENGTH;
                 addrFamily = RtNetlink.RT_ADDRESS_FAMILY_INET;
             } else {
                 if (pdPushNextHopIPv6 == null) {
@@ -537,70 +554,48 @@
                     return;
                 }
                 pdPushNextHop = pdPushNextHopIPv6;
-                netLinkLength =  Ip6Address.BYTE_LENGTH + RouteAttribute.ROUTE_ATTRIBUTE_HEADER_LENGTH;
+                raLength =  Ip6Address.BYTE_LENGTH + RouteAttribute.ROUTE_ATTRIBUTE_HEADER_LENGTH;
                 addrFamily = RtNetlink.RT_ADDRESS_FAMILY_INET6;
             }
 
-            RouteAttributeDst raDst = new RouteAttributeDst(
-                netLinkLength,
-                RouteAttribute.RTA_DST,
-                prefix.address());
-            attributes.add(raDst);
+             RouteAttributeDst raDst = RouteAttributeDst.builder()
+                .length(raLength)
+                .type(RouteAttribute.RTA_DST)
+                .dstAddress(prefix.address())
+                .build();
 
-            RouteAttributeGateway raGateway = new RouteAttributeGateway(
-                netLinkLength,
-                RouteAttribute.RTA_GATEWAY,
-                pdPushNextHop);
-            attributes.add(raGateway);
+            RouteAttributeGateway raGateway = RouteAttributeGateway.builder()
+                .length(raLength)
+                .type(RouteAttribute.RTA_GATEWAY)
+                .gateway(pdPushNextHop)
+                .build();
 
-            // Add RtNetlink header.
-            int srcLength = 0;
-            short tos = 0;
-            short table = 0;
-            short scope = 0;
-            long rtFlags = 0;
+            // Build RtNetlink.
+            RtNetlink rtNetlink = RtNetlink.builder()
+                .addressFamily(addrFamily)
+                .dstLength(prefix.prefixLength())
+                .routeAttribute(raDst)
+                .routeAttribute(raGateway)
+                .build();
+
+            // Build Netlink.
             int messageLength = raDst.length() + raGateway.length() +
-                RtNetlink.RT_NETLINK_LENGTH;
+                                RtNetlink.RT_NETLINK_LENGTH + Netlink.NETLINK_HEADER_LENGTH;
+            Netlink netLink = Netlink.builder()
+                .length(messageLength)
+                .type(isAdd ? NetlinkMessageType.RTM_NEWROUTE : NetlinkMessageType.RTM_DELROUTE)
+                .flags(Netlink.NETLINK_REQUEST | Netlink.NETLINK_CREATE)
+                .rtNetlink(rtNetlink)
+                .build();
 
-            RtNetlink rtNetlink =  new RtNetlink(
-                addrFamily,
-                prefix.prefixLength(),
-                srcLength,
-                tos,
-                table,
-                RtProtocol.ZEBRA,
-                scope,
-                FpmHeader.FPM_TYPE_NETLINK,
-                rtFlags,
-                attributes);
-
-            // Add Netlink header.
-            NetlinkMessageType nlMsgType;
-            if (isAdd) {
-                nlMsgType = NetlinkMessageType.RTM_NEWROUTE;
-            } else {
-                nlMsgType = NetlinkMessageType.RTM_DELROUTE;
-            }
-            int flags = Netlink.NETLINK_REQUEST | Netlink.NETLINK_CREATE;
-            long sequence = 0;
-            long processPortId = 0;
-            messageLength += Netlink.NETLINK_HEADER_LENGTH;
-
-            Netlink netLink = new Netlink(messageLength,
-                nlMsgType,
-                flags,
-                sequence,
-                processPortId,
-                rtNetlink);
-
+            // Build FpmHeader.
             messageLength += FpmHeader.FPM_HEADER_LENGTH;
-
-            // Add FpmHeader.
-            FpmHeader fpmMessage = new FpmHeader(
-                FpmHeader.FPM_VERSION_1,
-                FpmHeader.FPM_TYPE_NETLINK,
-                messageLength,
-                netLink);
+            FpmHeader fpmMessage = FpmHeader.builder()
+                .version(FpmHeader.FPM_VERSION_1)
+                .type(FpmHeader.FPM_TYPE_NETLINK)
+                .length(messageLength)
+                .netlink(netLink)
+                .build();
 
             // Encode message in a channel buffer and transmit.
             ch.write(fpmMessage.encode());
@@ -730,4 +725,47 @@
             }
         }
     }
+
+    private class InternalClusterListener implements ClusterEventListener {
+        @Override
+        public void event(ClusterEvent event) {
+            log.debug("Receives ClusterEvent {} for {}", event.type(), event.subject().id());
+            switch (event.type()) {
+                case INSTANCE_READY:
+                    // When current node is healing from a network partition,
+                    // seeing INSTANCE_READY means current node has the ability to read from the cluster,
+                    // but it is possible that current node still can't write to the cluster at this moment.
+                    // The AsyncDistributedLock is introduced to ensure we attempt to push FPM routes
+                    // after current node can write.
+                    // Adding 15 seconds retry for the current node to be able to write.
+                    asyncLock.tryLock(Duration.ofSeconds(15)).whenComplete((result, error) -> {
+                        if (result != null && result.isPresent()) {
+                            log.debug("Lock obtained. Push local FPM routes to route store");
+                            // All FPM routes on current node will be pushed again even when current node is not
+                            // the one that becomes READY. A better way is to do this only on the minority nodes.
+                            pushFpmRoutes();
+                            asyncLock.unlock();
+                        } else {
+                            log.debug("Fail to obtain lock. Abort.");
+                        }
+                    });
+                    break;
+                case INSTANCE_DEACTIVATED:
+                case INSTANCE_ADDED:
+                case INSTANCE_REMOVED:
+                case INSTANCE_ACTIVATED:
+                default:
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public void pushFpmRoutes() {
+        Set<Route> routes = fpmRoutes.values().stream()
+                .map(Map::entrySet).flatMap(Set::stream).map(Map.Entry::getValue)
+                .collect(Collectors.toSet());
+        updateRouteStore(routes, Lists.newArrayList());
+        log.info("{} FPM routes have been updated to route store", routes.size());
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/cli/FpmPushRoutesCommand.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/cli/FpmPushRoutesCommand.java
new file mode 100644
index 0000000..29f0b63
--- /dev/null
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/cli/FpmPushRoutesCommand.java
@@ -0,0 +1,35 @@
+/*
+ * 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.routing.fpm.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.routing.fpm.FpmInfoService;
+
+
+/**
+ * Displays the current FPM connections.
+ */
+@Command(scope = "onos", name = "fpm-push-routes",
+        description = "Pushes all local FPM routes to route store")
+public class FpmPushRoutesCommand extends AbstractShellCommand {
+    @Override
+    protected void execute() {
+        FpmInfoService fpmInfo = get(FpmInfoService.class);
+        fpmInfo.pushFpmRoutes();
+    }
+}
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/FpmHeader.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/FpmHeader.java
index 607c9e1..abaaa88 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/FpmHeader.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/FpmHeader.java
@@ -63,7 +63,7 @@
      * @param length length
      * @param netlink netlink header
      */
-    public FpmHeader(short version, short type, int length, Netlink netlink) {
+    private FpmHeader(short version, short type, int length, Netlink netlink) {
         this.version = version;
         this.type = type;
         this.length = length;
@@ -169,4 +169,83 @@
         netlink.encode(cb);
         return cb;
     }
+
+    /**
+     * Returns a new FpmHeader builder.
+     *
+     * @return FpmHeader builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * FpmHeader Builder.
+     */
+    public static final class Builder {
+
+        private short version = FPM_VERSION_1;
+        private short type = FPM_TYPE_NETLINK;
+        private int length = 0;
+        private Netlink netlink = null;
+
+        /**
+        * Hide class constructor.
+        */
+        private Builder() {
+        }
+
+        /**
+         * Sets version for the FpmHeader that will be built.
+         *
+         * @param version to use for built FpmHeader
+         * @return this builder
+         */
+        public Builder version(short version) {
+            this.version = version;
+            return this;
+        }
+
+        /**
+         * Sets type for the FpmHeader that will be built.
+         *
+         * @param type to use for built FpmHeader
+         * @return this builder
+         */
+        public Builder type(short type) {
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Sets length for the FpmHeader that will be built.
+         *
+         * @param length to use for built FpmHeader
+         * @return this builder
+         */
+        public Builder length(int length) {
+            this.length = length;
+            return this;
+        }
+
+        /**
+         * Sets netlink for the FpmHeader that will be built.
+         *
+         * @param netlink to use for built FpmHeader
+         * @return this builder
+         */
+        public Builder netlink(Netlink netlink) {
+            this.netlink = netlink;
+            return this;
+        }
+
+        /**
+         * Builds the FpmHeader.
+         *
+         * @return FpmHeader reference
+         */
+        public FpmHeader build() {
+            return new FpmHeader(version, type, length, netlink);
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/Netlink.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/Netlink.java
index df84ed6..d7bdd26 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/Netlink.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/Netlink.java
@@ -55,7 +55,7 @@
      * @param processPortId port ID
      * @param rtNetlink netlink routing message
      */
-    public Netlink(long length, NetlinkMessageType type, int flags, long sequence,
+    private Netlink(long length, NetlinkMessageType type, int flags, long sequence,
                     long processPortId, RtNetlink rtNetlink) {
         this.length = length;
         this.type = type;
@@ -188,4 +188,106 @@
         rtNetlink.encode(cb);
     }
 
+    /**
+     * Returns a new Netlink builder.
+     *
+     * @return Netlink builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Netlink Builder.
+     */
+    public static final class Builder {
+
+        private long length = 0;
+        private NetlinkMessageType type = NetlinkMessageType.RTM_NEWROUTE;
+        private int flags = 0;
+        private long sequence = 0;
+        private long processPortId = 0;
+        private RtNetlink rtNetlink = null;
+
+        /**
+        * Hide class constructor.
+        */
+        private Builder() {
+        }
+
+        /**
+         * Sets length for the Netlink that will be built.
+         *
+         * @param length to use for built Netlink
+         * @return this builder
+         */
+        public Builder length(long length) {
+            this.length = length;
+            return this;
+        }
+
+        /**
+         * Sets type for the Netlink that will be built.
+         *
+         * @param type to use for built Netlink
+         * @return this builder
+         */
+        public Builder type(NetlinkMessageType type) {
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Sets flags for the Netlink that will be built.
+         *
+         * @param flags to use for built Netlink
+         * @return this builder
+         */
+        public Builder flags(int flags) {
+            this.flags = flags;
+            return this;
+        }
+
+        /**
+         * Sets sequence for the Netlink that will be built.
+         *
+         * @param sequence to use for built Netlink
+         * @return this builder
+         */
+        public Builder sequence(long sequence) {
+            this.sequence = sequence;
+            return this;
+        }
+
+        /**
+         * Sets processPortId for the Netlink that will be built.
+         *
+         * @param processPortId to use for built Netlink
+         * @return this builder
+         */
+        public Builder processPortId(long processPortId) {
+            this.processPortId = processPortId;
+            return this;
+        }
+
+        /**
+         * Sets rtNetlink for the Netlink that will be built.
+         *
+         * @param rtNetlink to use for built Netlink
+         * @return this builder
+         */
+        public Builder rtNetlink(RtNetlink rtNetlink) {
+            this.rtNetlink = rtNetlink;
+            return this;
+        }
+
+        /**
+         * Builds the Netlink.
+         *
+         * @return Netlink reference
+         */
+        public Netlink build() {
+            return new Netlink(length, type, flags, sequence, processPortId, rtNetlink);
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttribute.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttribute.java
index 43a21c0..280c678 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttribute.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttribute.java
@@ -121,6 +121,43 @@
      *
      * @param cb channelbuffer to be filled in
      */
-    public abstract void encode(ChannelBuffer cb);
+    public void encode(ChannelBuffer cb) {
+        cb.writeShort(Short.reverseBytes((short) length()));
+        cb.writeShort(Short.reverseBytes((short) type()));
+    }
 
+    /**
+     * RouteAttribute Builder.
+     */
+    public abstract static class Builder<T extends Builder<T>> {
+
+        protected int length;
+        protected int type;
+
+        public Builder() {}
+
+        public abstract T getThis();
+
+        /**
+         * Sets length for RouteAttribute that will be built.
+         *
+         * @param length to use for built RtNetlink
+         * @return this generic builder type
+         */
+        public T length(int length) {
+            this.length = length;
+            return getThis();
+        }
+
+        /**
+         * Sets type for RouteAttribute that will be built.
+         *
+         * @param type to use for built RtNetlink
+         * @return this generic builder type
+         */
+        public T type(int type) {
+            this.type = type;
+            return getThis();
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeDst.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeDst.java
index 2962c0b..f7e3d3b 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeDst.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeDst.java
@@ -38,7 +38,7 @@
      * @param type type
      * @param dstAddress destination address
      */
-    public RouteAttributeDst(int length, int type, IpAddress dstAddress) {
+    private RouteAttributeDst(int length, int type, IpAddress dstAddress) {
         super(length, type);
 
         this.dstAddress = dstAddress;
@@ -91,8 +91,7 @@
     @Override
     public void encode(ChannelBuffer cb) {
 
-        cb.writeShort(Short.reverseBytes((short) length()));
-        cb.writeShort(Short.reverseBytes((short) type()));
+        super.encode(cb);
 
         ChannelBuffer buffer =  ChannelBuffers.copiedBuffer(dstAddress.toOctets());
         if (length() == Ip6Address.BYTE_LENGTH +
@@ -105,4 +104,54 @@
             throw new IllegalArgumentException("Dst address length incorrect!");
         }
     }
+
+    /**
+     * Returns a new RouteAttributeDst builder.
+     *
+     * @return RouteAttributeDst builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * RouteAttributeDst Builder.
+     */
+    public static final class Builder extends RouteAttribute.Builder<Builder> {
+
+        private IpAddress dstAddress = null;
+
+        /**
+        * Hide class constructor.
+        */
+        private Builder() {}
+
+        /**
+         * Override abstract method.
+         */
+        @Override
+        public Builder getThis() {
+            return this;
+        }
+
+        /**
+         * Sets dstAddress for RouteAttributeDst that will be built.
+         *
+         * @param dstAddress to use for built RouteAttributeDst
+         * @return this builder
+         */
+        public Builder dstAddress(IpAddress dstAddress) {
+            this.dstAddress = dstAddress;
+            return this;
+        }
+
+        /**
+         * Builds the RouteAttributeDst.
+         *
+         * @return RouteAttributeDst reference
+         */
+        public RouteAttributeDst build() {
+            return new RouteAttributeDst(length, type, dstAddress);
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeGateway.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeGateway.java
index 3b1f5cd..ecf36d3 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeGateway.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeGateway.java
@@ -40,7 +40,7 @@
      * @param type type
      * @param gateway gateway address
      */
-    public RouteAttributeGateway(int length, int type, IpAddress gateway) {
+    private RouteAttributeGateway(int length, int type, IpAddress gateway) {
         super(length, type);
 
         this.gateway = gateway;
@@ -93,8 +93,7 @@
     @Override
     public void encode(ChannelBuffer cb) {
 
-        cb.writeShort(Short.reverseBytes((short) length()));
-        cb.writeShort(Short.reverseBytes((short) type()));
+        super.encode(cb);
 
         ChannelBuffer buffer =  ChannelBuffers.copiedBuffer(gateway.toOctets());
         if (length() == Ip6Address.BYTE_LENGTH +
@@ -107,4 +106,54 @@
             throw new IllegalArgumentException("Gateway address length incorrect!");
         }
     }
+
+    /**
+     * Returns a new RouteAttributeGateway builder.
+     *
+     * @return RouteAttributeGateway builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * RouteAttributeGateway Builder.
+     */
+    public static final class Builder extends RouteAttribute.Builder<Builder> {
+
+        private IpAddress gateway = null;
+
+        /**
+        * Hide class constructor.
+        */
+        private Builder() {}
+
+        /**
+         * Override abstract method.
+         */
+        @Override
+        public Builder getThis() {
+            return this;
+        }
+
+        /**
+         * Sets gateway for RouteAttributeGateway that will be built.
+         *
+         * @param gateway to use for built RouteAttributeGateway
+         * @return this builder
+         */
+        public Builder gateway(IpAddress gateway) {
+            this.gateway = gateway;
+            return this;
+        }
+
+        /**
+         * Builds the RouteAttributeGateway.
+         *
+         * @return RouteAttributeGateway reference
+         */
+        public RouteAttributeGateway build() {
+            return new RouteAttributeGateway(length, type, gateway);
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeOif.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeOif.java
index 49a12e8..e6becb7 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeOif.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributeOif.java
@@ -38,7 +38,7 @@
      * @param type type
      * @param outputInterface output interface
      */
-    public RouteAttributeOif(int length, int type, long outputInterface) {
+    private RouteAttributeOif(int length, int type, long outputInterface) {
         super(length, type);
 
         this.outputInterface = outputInterface;
@@ -87,8 +87,57 @@
     @Override
     public void encode(ChannelBuffer cb) {
 
-        cb.writeShort(Short.reverseBytes((short) length()));
-        cb.writeShort(Short.reverseBytes((short) type()));
+        super.encode(cb);
         cb.writeInt(Integer.reverseBytes((int) outputInterface));
     }
+
+    /**
+     * Returns a new RouteAttributeOif builder.
+     *
+     * @return RouteAttributeOif builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * RouteAttributeOif Builder.
+     */
+    public static final class Builder extends RouteAttribute.Builder<Builder> {
+
+        private long outputInterface = 0;
+
+        /**
+        * Hide class constructor.
+        */
+        private Builder() {}
+
+        /**
+         * Override abstract method.
+         */
+        @Override
+        public Builder getThis() {
+            return this;
+        }
+
+        /**
+         * Sets outputInterface for RouteAttributeOif that will be built.
+         *
+         * @param outputInterface to use for built RouteAttributeOif
+         * @return this builder
+         */
+        public Builder outputInterface(long outputInterface) {
+            this.outputInterface = outputInterface;
+            return this;
+        }
+
+        /**
+         * Builds the RouteAttributeOif.
+         *
+         * @return RouteAttributeOif reference
+         */
+        public RouteAttributeOif build() {
+            return new RouteAttributeOif(length, type, outputInterface);
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributePriority.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributePriority.java
index 2c45db0..89dad43 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributePriority.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RouteAttributePriority.java
@@ -38,7 +38,7 @@
      * @param type type
      * @param priority priority
      */
-    public RouteAttributePriority(int length, int type, long priority) {
+    private RouteAttributePriority(int length, int type, long priority) {
         super(length, type);
 
         this.priority = priority;
@@ -87,8 +87,57 @@
     @Override
     public void encode(ChannelBuffer cb) {
 
-        cb.writeShort(Short.reverseBytes((short) length()));
-        cb.writeShort(Short.reverseBytes((short) type()));
+        super.encode(cb);
         cb.writeInt(Integer.reverseBytes((int) priority));
     }
+
+    /**
+     * Returns a new RouteAttributePriority builder.
+     *
+     * @return RouteAttributePriority builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * RouteAttributePriority Builder.
+     */
+    public static final class Builder extends RouteAttribute.Builder<Builder> {
+
+        private long priority = 0;
+
+        /**
+        * Hide class constructor.
+        */
+        private Builder() {}
+
+        /**
+         * Override abstract method.
+         */
+        @Override
+        public Builder getThis() {
+            return this;
+        }
+
+        /**
+         * Sets priority for RouteAttributePriority that will be built.
+         *
+         * @param priority to use for built RouteAttributePriority
+         * @return this builder
+         */
+        public Builder priority(long priority) {
+            this.priority = priority;
+            return this;
+        }
+
+        /**
+         * Builds the RouteAttributePriority.
+         *
+         * @return RouteAttributePriority reference
+         */
+        public RouteAttributePriority build() {
+            return new RouteAttributePriority(length, type, priority);
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RtNetlink.java b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RtNetlink.java
index adaaf62..ef2faa4 100644
--- a/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RtNetlink.java
+++ b/apps/routing/fpm/app/src/main/java/org/onosproject/routing/fpm/protocol/RtNetlink.java
@@ -67,7 +67,7 @@
      * @param flags flags
      * @param attributes list of attributes
      */
-    public RtNetlink(short addressFamily,
+    private RtNetlink(short addressFamily,
                       int dstLength,
                       int srcLength,
                       short tos,
@@ -270,4 +270,163 @@
         }
     }
 
+    /**
+     * Returns a new RtNetlink builder.
+     *
+     * @return RtNetlink builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * RtNetlink Builder.
+     */
+    public static final class Builder {
+
+        private short addressFamily = RT_ADDRESS_FAMILY_INET;
+        private int dstLength = 0;
+        private int srcLength = 0;
+        private short tos = 0;
+        private short table = 0;
+        private RtProtocol protocol = RtProtocol.ZEBRA;
+        private short scope = 0;
+        private short type = FpmHeader.FPM_TYPE_NETLINK;
+        private long flags = 0;
+        private List<RouteAttribute> attributes = new ArrayList<>();
+
+        /**
+        * Hide class constructor.
+        */
+        private Builder() {
+        }
+
+        /**
+         * Sets addressFamily for the RtNetlink that will be built.
+         *
+         * @param addressFamily to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder addressFamily(short addressFamily) {
+            this.addressFamily = addressFamily;
+            return this;
+        }
+
+        /**
+         * Sets dstLength for the RtNetlink that will be built.
+         *
+         * @param dstLength to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder dstLength(int dstLength) {
+            this.dstLength = dstLength;
+            return this;
+        }
+
+        /**
+         * Sets srcLength for the RtNetlink that will be built.
+         *
+         * @param srcLength to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder srcLength(int srcLength) {
+            this.srcLength = srcLength;
+            return this;
+        }
+
+        /**
+         * Sets tos for the RtNetlink that will be built.
+         *
+         * @param tos to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder tos(short tos) {
+            this.tos = tos;
+            return this;
+        }
+
+        /**
+         * Sets table for the RtNetlink that will be built.
+         *
+         * @param table to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder table(short table) {
+            this.table = table;
+            return this;
+        }
+
+        /**
+         * Sets protocol for the RtNetlink that will be built.
+         *
+         * @param protocol to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder protocol(RtProtocol protocol) {
+            this.protocol = protocol;
+            return this;
+        }
+
+        /**
+         * Sets scope for the RtNetlink that will be built.
+         *
+         * @param scope to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder scope(short scope) {
+            this.scope = scope;
+            return this;
+        }
+
+        /**
+         * Sets type for the RtNetlink that will be built.
+         *
+         * @param type to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder type(short type) {
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Sets flags for the RtNetlink that will be built.
+         *
+         * @param flags to use for built RtNetlink
+         * @return this builder
+         */
+        public Builder flags(long flags) {
+            this.flags = flags;
+            return this;
+        }
+
+        /**
+         * Adds attribute for the RtNetlink that will be built.
+         *
+         * @param ra to add to list of route attributes
+         * @return this builder
+         */
+        public Builder routeAttribute(RouteAttribute ra) {
+            attributes.add(ra);
+            return this;
+        }
+
+        /**
+         * Builds the RtNetlink.
+         *
+         * @return RtNetlink reference
+         */
+        public RtNetlink build() {
+            return new RtNetlink(addressFamily,
+                                 dstLength,
+                                 srcLength,
+                                 tos,
+                                 table,
+                                 protocol,
+                                 scope,
+                                 type,
+                                 flags,
+                                 attributes);
+        }
+    }
 }
diff --git a/apps/routing/fpm/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/routing/fpm/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 3af7033..a227f6f 100644
--- a/apps/routing/fpm/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/routing/fpm/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -19,5 +19,8 @@
     <command>
       <action class="org.onosproject.routing.fpm.cli.FpmConnectionsList"/>
     </command>
+    <command>
+      <action class="org.onosproject.routing.fpm.cli.FpmPushRoutesCommand"/>
+    </command>
   </command-bundle>
 </blueprint>
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
index aa00738..19e898e 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
@@ -28,13 +28,11 @@
 import org.onlab.packet.VlanId;
 import org.onosproject.TestApplicationId;
 import org.onosproject.core.ApplicationId;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.intf.InterfaceListener;
-import org.onosproject.net.intf.InterfaceService;
 import org.onosproject.intentsync.IntentSynchronizationService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigService;
@@ -47,6 +45,9 @@
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intf.Interface;
+import org.onosproject.net.intf.InterfaceListener;
+import org.onosproject.net.intf.InterfaceService;
 import org.onosproject.routing.config.BgpConfig;
 import org.onosproject.sdnip.config.SdnIpConfig;
 
@@ -58,7 +59,13 @@
 import java.util.Optional;
 import java.util.Set;
 
-import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
 import static org.onosproject.routing.TestIntentServiceHelper.eqExceptId;
 
 /**
@@ -339,8 +346,8 @@
                 .key(key)
                 .selector(builder.build())
                 .treatment(treatment.build())
-                .ingressPoint(srcConnectPoint)
-                .egressPoint(dstConnectPoint)
+                .filteredIngressPoint(new FilteredConnectPoint(srcConnectPoint))
+                .filteredEgressPoint(new FilteredConnectPoint(dstConnectPoint))
                 .build();
 
         intentList.add(intent);
@@ -511,8 +518,8 @@
                 .key(key)
                 .selector(builder.build())
                 .treatment(treatment.build())
-                .ingressPoint(srcConnectPoint)
-                .egressPoint(dstConnectPoint)
+                .filteredIngressPoint(new FilteredConnectPoint(srcConnectPoint))
+                .filteredEgressPoint(new FilteredConnectPoint(dstConnectPoint))
                 .build();
 
         intentList.add(intent);
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 72243bb..882bbe7 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -52,7 +52,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static java.util.concurrent.Executors.newScheduledThreadPool;
@@ -67,7 +66,6 @@
     private static final long RETRY_INTERVAL_MS = 250L;
     private static final int RETRY_INTERVAL_SCALE = 1;
     private static final long STABLITY_THRESHOLD = 10; //secs
-    private static final int UPDATE_INTERVAL = 5; //secs
     private static Logger log = LoggerFactory.getLogger(DefaultRoutingHandler.class);
 
     private SegmentRoutingManager srManager;
@@ -261,8 +259,20 @@
             rulePopulator.resetCounter();
             log.info("Starting to populate routing rules for added routes, subnets={}, cpts={}",
                     subnets, cpts);
-            // Take snapshots of the topology
-            updatedEcmpSpgMap = new HashMap<>();
+            // In principle an update to a subnet/prefix should not require a
+            // new ECMPspg calculation as it is not a topology event. As a
+            // result, we use the current/existing ECMPspg in the updated map
+            // used by the redoRouting method.
+            if (updatedEcmpSpgMap == null) {
+                updatedEcmpSpgMap = new HashMap<>();
+            }
+            currentEcmpSpgMap.entrySet().forEach(entry -> {
+                updatedEcmpSpgMap.put(entry.getKey(), entry.getValue());
+                if (log.isTraceEnabled()) {
+                    log.trace("Root switch: {}", entry.getKey());
+                    log.trace("  Current/Existing SPG: {}", entry.getValue());
+                }
+            });
             Set<EdgePair> edgePairs = new HashSet<>();
             Set<ArrayList<DeviceId>> routeChanges = new HashSet<>();
             boolean handleRouting = false;
@@ -281,9 +291,13 @@
                     return;
                 }
                 for (ConnectPoint cp : cpts) {
-                    EcmpShortestPathGraph ecmpSpgUpdated =
+                    if (updatedEcmpSpgMap.get(cp.deviceId()) == null) {
+                        EcmpShortestPathGraph ecmpSpgUpdated =
                             new EcmpShortestPathGraph(cp.deviceId(), srManager);
-                    updatedEcmpSpgMap.put(cp.deviceId(), ecmpSpgUpdated);
+                        updatedEcmpSpgMap.put(cp.deviceId(), ecmpSpgUpdated);
+                        log.warn("populateSubnet: no updated graph for dev:{}"
+                                + " ... creating", cp.deviceId());
+                    }
                     DeviceId retId = shouldHandleRouting(cp.deviceId());
                     if (retId == null) {
                         continue;
@@ -293,9 +307,13 @@
             } else {
                 // single connect point
                 DeviceId dstSw = cpts.iterator().next().deviceId();
-                EcmpShortestPathGraph ecmpSpgUpdated =
+                if (updatedEcmpSpgMap.get(dstSw) == null) {
+                    EcmpShortestPathGraph ecmpSpgUpdated =
                         new EcmpShortestPathGraph(dstSw, srManager);
-                updatedEcmpSpgMap.put(dstSw, ecmpSpgUpdated);
+                    updatedEcmpSpgMap.put(dstSw, ecmpSpgUpdated);
+                    log.warn("populateSubnet: no updated graph for dev:{}"
+                            + " ... creating", dstSw);
+                }
                 if (srManager.mastershipService.isLocalMaster(dstSw)) {
                     handleRouting = true;
                 }
@@ -375,14 +393,12 @@
             return;
         }
         lastRoutingChange = Instant.now();
-        executorService.schedule(new UpdateMaps(), UPDATE_INTERVAL,
-                                 TimeUnit.SECONDS);
         statusLock.lock();
         try {
 
             if (populationStatus == Status.STARTED) {
                 log.warn("Previous rule population is not finished. Cannot"
-                        + " proceeed with routingRules for Link Status change");
+                        + " proceeed with routingRules for Topology change");
                 return;
             }
 
@@ -402,13 +418,14 @@
                 }
             }
 
-            log.info("Starting to populate routing rules from link status change");
+            log.info("Starting to populate routing rules from Topology change");
 
             Set<ArrayList<DeviceId>> routeChanges;
             log.debug("populateRoutingRulesForLinkStatusChange: "
                     + "populationStatus is STARTED");
             populationStatus = Status.STARTED;
-            rulePopulator.resetCounter();
+            rulePopulator.resetCounter(); //XXX maybe useful to have a rehash ctr
+            boolean hashGroupsChanged = false;
             // try optimized re-routing
             if (linkDown == null) {
                 // either a linkUp or a switchDown - compute all route changes by
@@ -429,6 +446,7 @@
                     processHashGroupChange(routeChanges, false, null);
                     // clear out routesChanges so a re-route is not attempted
                     routeChanges = ImmutableSet.of();
+                    hashGroupsChanged = true;
                 }
                 // for a linkUp of a never-seen-before link
                 // let it fall through to a reroute of the routeChanges
@@ -444,6 +462,7 @@
                     processHashGroupChange(routeChanges, true, switchDown);
                     // clear out routesChanges so a re-route is not attempted
                     routeChanges = ImmutableSet.of();
+                    hashGroupsChanged = true;
                 }
             } else {
                 // link has gone down
@@ -453,19 +472,29 @@
                     processHashGroupChange(routeChanges, true, null);
                     // clear out routesChanges so a re-route is not attempted
                     routeChanges = ImmutableSet.of();
+                    hashGroupsChanged = true;
                 }
             }
 
             // do full re-routing if optimized routing returns null routeChanges
             if (routeChanges == null) {
-                log.info("Optimized routing failed... opting for full reroute");
+                log.warn("Optimized routing failed... opting for full reroute");
                 populationStatus = Status.ABORTED;
                 populateAllRoutingRules();
                 return;
             }
 
             if (routeChanges.isEmpty()) {
-                log.info("No re-route attempted for the link status change");
+                if (hashGroupsChanged) {
+                    log.info("Hash-groups changed for link status change");
+                } else {
+                    log.info("No re-route or re-hash attempted for the link"
+                            + " status change");
+                    updatedEcmpSpgMap.keySet().forEach(devId -> {
+                        currentEcmpSpgMap.put(devId, updatedEcmpSpgMap.get(devId));
+                        log.debug("Updating ECMPspg for remaining dev:{}", devId);
+                    });
+                }
                 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
                 populationStatus = Status.SUCCEEDED;
                 return;
@@ -489,7 +518,6 @@
         }
     }
 
-
     /**
      * Processes a set a route-path changes by reprogramming routing rules and
      * creating new hash-groups or editing them if necessary. This method also
@@ -537,7 +565,9 @@
         }
 
         // whatever is left in changedRoutes is now processed for individual dsts.
-        if (!redoRoutingIndividualDests(subnets, changedRoutes)) {
+        Set<DeviceId> updatedDevices = Sets.newHashSet();
+        if (!redoRoutingIndividualDests(subnets, changedRoutes,
+                                        updatedDevices)) {
             return false; //abort routing and fail fast
         }
 
@@ -547,6 +577,15 @@
             currentEcmpSpgMap.put(ep.dev2, updatedEcmpSpgMap.get(ep.dev2));
             log.debug("Updating ECMPspg for edge-pair:{}-{}", ep.dev1, ep.dev2);
         }
+
+        // here is where we update all devices not touched by this instance
+        updatedEcmpSpgMap.keySet().stream()
+            .filter(devId -> !edgePairs.stream().anyMatch(ep -> ep.includes(devId)))
+            .filter(devId -> !updatedDevices.contains(devId))
+            .forEach(devId -> {
+                currentEcmpSpgMap.put(devId, updatedEcmpSpgMap.get(devId));
+                log.debug("Updating ECMPspg for remaining dev:{}", devId);
+            });
         return true;
     }
 
@@ -621,9 +660,14 @@
                                                          : subnets;
                 ipDev1 = (ipDev1 == null) ? Sets.newHashSet() : ipDev1;
                 ipDev2 = (ipDev2 == null) ? Sets.newHashSet() : ipDev2;
+                Set<DeviceId> nhDev1 = perDstNextHops.get(ep.dev1);
+                Set<DeviceId> nhDev2 = perDstNextHops.get(ep.dev2);
                 // handle routing to subnets common to edge-pair
-                // only if the targetSw is not part of the edge-pair
-                if (!ep.includes(targetSw)) {
+                // only if the targetSw is not part of the edge-pair and there
+                // exists a next hop to at least one of the devices in the edge-pair
+                if (!ep.includes(targetSw)
+                        && ((nhDev1 != null && !nhDev1.isEmpty())
+                                || (nhDev2 != null && !nhDev2.isEmpty()))) {
                     if (!populateEcmpRoutingRulePartial(
                              targetSw,
                              ep.dev1, ep.dev2,
@@ -632,11 +676,13 @@
                         return false; // abort everything and fail fast
                     }
                 }
-                // handle routing to subnets that only belong to dev1
+                // handle routing to subnets that only belong to dev1 only if
+                // a next-hop exists from the target to dev1
                 Set<IpPrefix> onlyDev1Subnets = Sets.difference(ipDev1, ipDev2);
-                if (!onlyDev1Subnets.isEmpty() && perDstNextHops.get(ep.dev1) != null) {
+                if (!onlyDev1Subnets.isEmpty()
+                        && nhDev1 != null  && !nhDev1.isEmpty()) {
                     Map<DeviceId, Set<DeviceId>> onlyDev1NextHops = new HashMap<>();
-                    onlyDev1NextHops.put(ep.dev1, perDstNextHops.get(ep.dev1));
+                    onlyDev1NextHops.put(ep.dev1, nhDev1);
                     if (!populateEcmpRoutingRulePartial(
                             targetSw,
                             ep.dev1, null,
@@ -645,11 +691,13 @@
                         return false; // abort everything and fail fast
                     }
                 }
-                // handle routing to subnets that only belong to dev2
+                // handle routing to subnets that only belong to dev2 only if
+                // a next-hop exists from the target to dev2
                 Set<IpPrefix> onlyDev2Subnets = Sets.difference(ipDev2, ipDev1);
-                if (!onlyDev2Subnets.isEmpty() && perDstNextHops.get(ep.dev2) != null) {
+                if (!onlyDev2Subnets.isEmpty()
+                        && nhDev2 != null && !nhDev2.isEmpty()) {
                     Map<DeviceId, Set<DeviceId>> onlyDev2NextHops = new HashMap<>();
-                    onlyDev2NextHops.put(ep.dev2, perDstNextHops.get(ep.dev2));
+                    onlyDev2NextHops.put(ep.dev2, nhDev2);
                     if (!populateEcmpRoutingRulePartial(
                             targetSw,
                             ep.dev2, null,
@@ -680,7 +728,8 @@
      * @return true if successful
      */
     private boolean redoRoutingIndividualDests(Set<IpPrefix> subnets,
-                                               Set<ArrayList<DeviceId>> changedRoutes) {
+                                               Set<ArrayList<DeviceId>> changedRoutes,
+                                               Set<DeviceId> updatedDevices) {
         // aggregate route-path changes for each dst device
         HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
                 new HashMap<>();
@@ -726,6 +775,7 @@
             //is updated here, without any flows being pushed.
             currentEcmpSpgMap.put(impactedDstDevice,
                                   updatedEcmpSpgMap.get(impactedDstDevice));
+            updatedDevices.add(impactedDstDevice);
             log.debug("Updating ECMPspg for impacted dev:{}", impactedDstDevice);
         }
         return true;
@@ -873,7 +923,8 @@
                 changedRoutes.add(route);
             }
         }
-
+        boolean someFailed = false;
+        Set<DeviceId> updatedDevices = Sets.newHashSet();
         for (ArrayList<DeviceId> route : changedRoutes) {
             DeviceId targetSw = route.get(0);
             DeviceId dstSw = route.get(1);
@@ -887,14 +938,20 @@
                     currentEcmpSpgMap.remove(targetSw);
                     log.debug("Updating ECMPspg for dst:{} removing failed switch "
                             + "target:{}", dstSw, targetSw);
+                    updatedDevices.add(targetSw);
+                    updatedDevices.add(dstSw);
                     continue;
                 }
                 //linkfailed - update both sides
                 if (success) {
                     currentEcmpSpgMap.put(targetSw, updatedEcmpSpgMap.get(targetSw));
                     currentEcmpSpgMap.put(dstSw, updatedEcmpSpgMap.get(dstSw));
-                    log.debug("Updating ECMPspg for dst:{} and target:{} for linkdown",
-                              dstSw, targetSw);
+                    log.debug("Updating ECMPspg for dst:{} and target:{} for linkdown"
+                            + " or switchdown", dstSw, targetSw);
+                    updatedDevices.add(targetSw);
+                    updatedDevices.add(dstSw);
+                } else {
+                    someFailed = true;
                 }
             } else {
                 //linkup of seen before link
@@ -904,9 +961,22 @@
                     currentEcmpSpgMap.put(dstSw, updatedEcmpSpgMap.get(dstSw));
                     log.debug("Updating ECMPspg for target:{} and dst:{} for linkup",
                               targetSw, dstSw);
+                    updatedDevices.add(targetSw);
+                    updatedDevices.add(dstSw);
+                } else {
+                    someFailed = true;
                 }
             }
         }
+        if (!someFailed) {
+            // here is where we update all devices not touched by this instance
+            updatedEcmpSpgMap.keySet().stream()
+                .filter(devId -> !updatedDevices.contains(devId))
+                .forEach(devId -> {
+                    currentEcmpSpgMap.put(devId, updatedEcmpSpgMap.get(devId));
+                    log.debug("Updating ECMPspg for remaining dev:{}", devId);
+            });
+        }
     }
 
     /**
@@ -1027,9 +1097,21 @@
      * @param deviceId the device for which graphs need to be purged
      */
     protected void purgeEcmpGraph(DeviceId deviceId) {
-        currentEcmpSpgMap.remove(deviceId); // XXX reconsider
-        if (updatedEcmpSpgMap != null) {
-            updatedEcmpSpgMap.remove(deviceId);
+        statusLock.lock();
+        try {
+
+            if (populationStatus == Status.STARTED) {
+                log.warn("Previous rule population is not finished. Cannot"
+                        + " proceeed with purgeEcmpGraph for {}", deviceId);
+                return;
+            }
+            log.debug("Updating ECMPspg for unavailable dev:{}", deviceId);
+            currentEcmpSpgMap.remove(deviceId);
+            if (updatedEcmpSpgMap != null) {
+                updatedEcmpSpgMap.remove(deviceId);
+            }
+        } finally {
+            statusLock.unlock();
         }
     }
 
@@ -1424,35 +1506,6 @@
         }
     }
 
-    /**
-     * Updates the currentEcmpSpgGraph for all devices.
-     */
-    private void updateEcmpSpgMaps() {
-        for (Device sw : srManager.deviceService.getDevices()) {
-            EcmpShortestPathGraph ecmpSpgUpdated =
-                    new EcmpShortestPathGraph(sw.id(), srManager);
-            currentEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
-        }
-    }
-
-    /**
-     * Ensures routing is stable before updating all ECMP SPG graphs.
-     *
-     * TODO: CORD-1843 will ensure maps are updated faster, potentially while
-     * topology/routing is still unstable
-     */
-    private final class UpdateMaps implements Runnable {
-        @Override
-        public void run() {
-            if (isRoutingStable()) {
-                updateEcmpSpgMaps();
-            } else {
-                executorService.schedule(new UpdateMaps(), UPDATE_INTERVAL,
-                                         TimeUnit.SECONDS);
-            }
-        }
-    }
-
     //////////////////////////////////////
     //  Filtering rule creation
     //////////////////////////////////////
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/EcmpShortestPathGraph.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/EcmpShortestPathGraph.java
index 49bf80f..c9bd596 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/EcmpShortestPathGraph.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/EcmpShortestPathGraph.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.segmentrouting;
 
+import org.onlab.graph.ScalarWeight;
 import org.onosproject.net.DefaultLink;
 import org.onosproject.net.DefaultPath;
 import org.onosproject.net.Device;
@@ -131,7 +132,7 @@
                 sofarLinks.addAll(path.links());
             }
             sofarLinks.add(upstreamLink);
-            sofarPath = new DefaultPath(ProviderId.NONE, sofarLinks, 0);
+            sofarPath = new DefaultPath(ProviderId.NONE, sofarLinks, ScalarWeight.toWeight(0));
             if (upstreamLink.src().deviceId().equals(rootDeviceDeviceId)) {
                 paths.add(sofarPath);
                 return;
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/LinkHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/LinkHandler.java
index ef9fb38..c643991 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/LinkHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/LinkHandler.java
@@ -20,6 +20,8 @@
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.HostLocation;
@@ -35,6 +37,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Sets;
 
 public class LinkHandler {
@@ -43,15 +46,11 @@
     protected LinkService linkService;
 
     // Local store for all links seen and their present status, used for
-    // optimized routing. The existence of the link in the keys is enough to
-    // know
+    // optimized routing. The existence of the link in the keys is enough to know
     // if the link has been "seen-before" by this instance of the controller.
     // The boolean value indicates if the link is currently up or not.
-    // XXX Currently the optimized routing logic depends on "forgetting" a link
-    // when a switch goes down, but "remembering" it when only the link goes
-    // down.
-    // Consider changing this logic so we can use the Link Service instead of
-    // a local cache.
+    // Currently the optimized routing logic depends on "forgetting" a link
+    // when a switch goes down, but "remembering" it when only the link goes down.
     private Map<Link, Boolean> seenLinks = new ConcurrentHashMap<>();
 
     private EventuallyConsistentMap<DeviceId, Set<PortNumber>> downedPortStore = null;
@@ -72,6 +71,7 @@
                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
                 .build();
         log.trace("Current size {}", downedPortStore.size());
+        init();
     }
 
     /**
@@ -86,6 +86,15 @@
     }
 
     /**
+     * Initialize LinkHandler.
+     */
+    private void init() {
+        log.info("Loading stored links");
+        srManager.linkService.getActiveLinks()
+                .forEach(link -> processLinkAdded(link));
+    }
+
+    /**
      * Preprocessing of added link before being sent for route-path handling.
      * Also performs post processing of link.
      *
@@ -96,8 +105,8 @@
         if (!isLinkValid(link)) {
             return;
         }
-        if (!srManager.deviceConfiguration
-                .isConfigured(link.src().deviceId())) {
+        if (srManager.deviceConfiguration == null ||
+                !srManager.deviceConfiguration.isConfigured(link.src().deviceId())) {
             updateSeenLink(link, true);
             // XXX revisit - what about devicePortMap
             log.warn("Source device of this link is not configured.. "
@@ -106,8 +115,7 @@
         }
 
         // Irrespective of whether the local is a MASTER or not for this device,
-        // create group handler instance and push default TTP flow rules if
-        // needed,
+        // create group handler instance and push default TTP flow rules if needed,
         // as in a multi-instance setup, instances can initiate groups for any
         // device.
         DefaultGroupHandler groupHandler = srManager.groupHandlerMap
@@ -151,12 +159,9 @@
             // handle edge-ports for dual-homed hosts
             updateDualHomedHostPorts(link, true);
 
-            // It's possible that linkUp causes no route-path change as ECMP
-            // graph does
+            // It's possible that linkUp causes no route-path change as ECMP graph does
             // not change if the link is a parallel link (same src-dst as
-            // another link.
-            // However we still need to update ECMP hash groups to include new
-            // buckets
+            // another link). However we still need to update ECMP hash groups to include new buckets
             // for the link that has come up.
             if (groupHandler != null) {
                 if (!seenBefore && isParallelLink(link)) {
@@ -193,6 +198,10 @@
         // when removing links, update seen links first, before doing route-path
         // changes
         updateSeenLink(link, false);
+        // handle edge-ports for dual-homed hosts
+        if (srManager.mastershipService.isLocalMaster(link.src().deviceId())) {
+            updateDualHomedHostPorts(link, false);
+        }
 
         // device availability check helps to ensure that multiple link-removed
         // events are actually treated as a single switch removed event.
@@ -209,11 +218,6 @@
             return;
         }
 
-        // handle edge-ports for dual-homed hosts
-        if (srManager.mastershipService.isLocalMaster(link.src().deviceId())) {
-            updateDualHomedHostPorts(link, false);
-        }
-
         log.debug("Starting optimized route-path processing for removed link "
                 + "{} --> {}", link.src(), link.dst());
         srManager.defaultRoutingHandler
@@ -268,6 +272,10 @@
             return false;
         }
         DeviceConfiguration devConfig = srManager.deviceConfiguration;
+        if (devConfig == null) {
+            log.warn("Cannot check validity of link without device config");
+            return true;
+        }
         try {
             if (!devConfig.isEdgeDevice(srcId)
                     && !devConfig.isEdgeDevice(dstId)) {
@@ -313,7 +321,7 @@
      * @param added true if link was added, false if link was removed
      */
     private void updateDualHomedHostPorts(Link link, boolean added) {
-        if (!lastUplink(link)) {
+        if (!onlyUplink(link)) {
             return;
         }
         if (added) {
@@ -349,7 +357,7 @@
     }
 
     /**
-     * Returns true if given link is the last active uplink from src-device of
+     * Returns true if given link is the only active uplink from src-device of
      * link. An uplink is defined as a unidirectional link with src as
      * edgeRouter and dst as non-edgeRouter.
      *
@@ -357,28 +365,35 @@
      * @return true if given link is-the-first/was-the-last uplink from the src
      *         device
      */
-    private boolean lastUplink(Link link) {
+    private boolean onlyUplink(Link link) {
         DeviceConfiguration devConfig = srManager.deviceConfiguration;
         try {
-            if (!devConfig.isEdgeDevice(link.src().deviceId())) {
+            if (!devConfig.isEdgeDevice(link.src().deviceId())
+                    || devConfig.isEdgeDevice(link.dst().deviceId())) {
                 return false;
             }
-            Set<Link> devLinks = srManager.linkService
-                    .getDeviceLinks(link.src().deviceId());
-            boolean foundOtherUplink = false;
+            // note that using linkservice here would cause race conditions as
+            // more links can show up while the app is still processing the first one
+            Set<Link> devLinks = seenLinks.entrySet().stream()
+                    .filter(entry -> entry.getKey().src().deviceId()
+                            .equals(link.src().deviceId()))
+                    .filter(entry -> entry.getValue())
+                    .filter(entry -> !entry.getKey().equals(link))
+                    .map(entry -> entry.getKey())
+                    .collect(Collectors.toSet());
+
             for (Link l : devLinks) {
-                if (devConfig.isEdgeDevice(l.dst().deviceId()) || l.equals(link)
-                        || l.state() == Link.State.INACTIVE) {
+                if (devConfig.isEdgeDevice(l.dst().deviceId())) {
                     continue;
                 }
-                foundOtherUplink = true;
-                break;
+                log.debug("Link {} is not the only active uplink. Found another"
+                        + "link {}", link, l);
+                return false;
             }
-            if (!foundOtherUplink) {
-                return true;
-            }
+            log.debug("Link {} is the only uplink", link);
+            return true;
         } catch (DeviceConfigNotFoundException e) {
-            log.warn("Unable to determine if link is last uplink"
+            log.warn("Unable to determine if link is only uplink"
                     + e.getMessage());
         }
         return false;
@@ -560,4 +575,12 @@
         downedPortStore.put(loc.deviceId(), p);
     }
 
+    ImmutableMap<Link, Boolean> getSeenLinks() {
+        return ImmutableMap.copyOf(seenLinks);
+    }
+
+    ImmutableMap<DeviceId, Set<PortNumber>> getDownedPorts() {
+        return ImmutableMap.copyOf(downedPortStore.entrySet());
+    }
+
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
index b0be4e3..fff2c92 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IpAddress;
@@ -25,6 +26,7 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
+import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.config.basics.McastConfig;
@@ -48,6 +50,7 @@
 import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.flowobjective.ObjectiveContext;
 import org.onosproject.net.mcast.McastEvent;
+import org.onosproject.net.mcast.McastRoute;
 import org.onosproject.net.mcast.McastRouteInfo;
 import org.onosproject.net.topology.TopologyService;
 import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
@@ -56,18 +59,27 @@
 import org.onosproject.store.service.ConsistentMap;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.time.Instant;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.Executors.newScheduledThreadPool;
+import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.segmentrouting.SegmentRoutingManager.INTERNAL_VLAN;
 
 /**
@@ -83,6 +95,49 @@
     private final KryoNamespace.Builder mcastKryo;
     private final ConsistentMap<McastStoreKey, McastRole> mcastRoleStore;
 
+    // Mcast lock to serialize local operations
+    private final Lock mcastLock = new ReentrantLock();
+
+    /**
+     * Acquires the lock used when making mcast changes.
+     */
+    private void mcastLock() {
+        mcastLock.lock();
+    }
+
+    /**
+     * Releases the lock used when making mcast changes.
+     */
+    private void mcastUnlock() {
+        mcastLock.unlock();
+    }
+
+    // Stability threshold for Mcast. Seconds
+    private static final long MCAST_STABLITY_THRESHOLD = 5;
+    // Last change done
+    private Instant lastMcastChange = Instant.now();
+
+    /**
+     * Determines if mcast in the network has been stable in the last
+     * MCAST_STABLITY_THRESHOLD seconds, by comparing the current time
+     * to the last mcast change timestamp.
+     *
+     * @return true if stable
+     */
+    private boolean isMcastStable() {
+        long last = (long) (lastMcastChange.toEpochMilli() / 1000.0);
+        long now = (long) (Instant.now().toEpochMilli() / 1000.0);
+        log.debug("Mcast stable since {}s", now - last);
+        return (now - last) > MCAST_STABLITY_THRESHOLD;
+    }
+
+    // Verify interval for Mcast
+    private static final long MCAST_VERIFY_INTERVAL = 30;
+
+    // Executor for mcast bucket corrector
+    private ScheduledExecutorService executorService
+            = newScheduledThreadPool(1, groupedThreads("mcastBktCorrector", "mcastbktC-%d", log));
+
     /**
      * Role in the multicast tree.
      */
@@ -125,6 +180,10 @@
                 .withName("onos-mcast-role-store")
                 .withSerializer(Serializer.using(mcastKryo.build("McastHandler-Role")))
                 .build();
+        // Init the executor service and the buckets corrector
+        executorService.scheduleWithFixedDelay(new McastBucketCorrector(), 10,
+                                               MCAST_VERIFY_INTERVAL,
+                                               TimeUnit.SECONDS);
     }
 
     /**
@@ -141,6 +200,13 @@
     }
 
     /**
+     * Clean up when deactivating the application.
+     */
+    protected void terminate() {
+        executorService.shutdown();
+    }
+
+    /**
      * Processes the SOURCE_ADDED event.
      *
      * @param event McastEvent with SOURCE_ADDED type
@@ -156,9 +222,7 @@
         Set<ConnectPoint> sinks = mcastRouteInfo.sinks();
         IpAddress mcastIp = mcastRouteInfo.route().group();
 
-        sinks.forEach(sink -> {
-            processSinkAddedInternal(source, sink, mcastIp);
-        });
+        sinks.forEach(sink -> processSinkAddedInternal(source, sink, mcastIp));
     }
 
     /**
@@ -196,43 +260,127 @@
         ConnectPoint sink = mcastRouteInfo.sink().orElse(null);
         IpAddress mcastIp = mcastRouteInfo.route().group();
 
-        // Continue only when this instance is the master of source device
-        if (!srManager.mastershipService.isLocalMaster(source.deviceId())) {
-            log.info("Skip {} due to lack of mastership of the source device {}",
-                    mcastIp, source.deviceId());
+        processSinkRemovedInternal(source, sink, mcastIp);
+    }
+
+    /**
+     * Processes the ROUTE_REMOVED event.
+     *
+     * @param event McastEvent with ROUTE_REMOVED type
+     */
+    protected void processRouteRemoved(McastEvent event) {
+        log.info("processRouteRemoved {}", event);
+        McastRouteInfo mcastRouteInfo = event.subject();
+        if (!mcastRouteInfo.source().isPresent()) {
+            log.info("Incompleted McastRouteInfo. Abort.");
             return;
         }
+        // Get group ip and ingress connect point
+        IpAddress mcastIp = mcastRouteInfo.route().group();
+        ConnectPoint source = mcastRouteInfo.source().get();
 
-        // When source and sink are on the same device
-        if (source.deviceId().equals(sink.deviceId())) {
-            // Source and sink are on even the same port. There must be something wrong.
-            if (source.port().equals(sink.port())) {
-                log.warn("Sink is on the same port of source. Abort");
+        processRouteRemovedInternal(source, mcastIp);
+    }
+
+    /**
+     * Removes the entire mcast tree related to this group.
+     *
+     * @param mcastIp multicast group IP address
+     */
+    private void processRouteRemovedInternal(ConnectPoint source, IpAddress mcastIp) {
+        lastMcastChange = Instant.now();
+        mcastLock();
+        try {
+            log.debug("Processing route down for group {}", mcastIp);
+
+            // Find out the ingress, transit and egress device of the affected group
+            DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS)
+                    .stream().findAny().orElse(null);
+            DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT)
+                    .stream().findAny().orElse(null);
+            Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS);
+
+            // Verify leadership on the operation
+            if (!isLeader(source)) {
+                log.debug("Skip {} due to lack of leadership", mcastIp);
                 return;
             }
-            removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(source));
-            return;
-        }
 
-        // Process the egress device
-        boolean isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(null));
-        if (isLast) {
-            mcastRoleStore.remove(new McastStoreKey(mcastIp, sink.deviceId()));
-        }
+            // If there are egress devices, sinks could be only on the ingress
+            if (!egressDevices.isEmpty()) {
+                egressDevices.forEach(
+                        deviceId -> removeGroupFromDevice(deviceId, mcastIp, assignedVlan(null))
+                );
+            }
+            // Transit could be null
+            if (transitDevice != null) {
+                removeGroupFromDevice(transitDevice, mcastIp, assignedVlan(null));
+            }
+            // Ingress device should be not null
+            if (ingressDevice != null) {
+                removeGroupFromDevice(ingressDevice, mcastIp, assignedVlan(source));
+            }
 
-        // If this is the last sink on the device, also update upstream
-        Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp);
-        if (mcastPath.isPresent()) {
-            List<Link> links = Lists.newArrayList(mcastPath.get().links());
-            Collections.reverse(links);
-            for (Link link : links) {
-                if (isLast) {
-                    isLast = removePortFromDevice(link.src().deviceId(), link.src().port(),
-                            mcastIp,
-                            assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
-                    mcastRoleStore.remove(new McastStoreKey(mcastIp, link.src().deviceId()));
+        } finally {
+            mcastUnlock();
+        }
+    }
+
+    /**
+     * Removes a path from source to sink for given multicast group.
+     *
+     * @param source connect point of the multicast source
+     * @param sink connection point of the multicast sink
+     * @param mcastIp multicast group IP address
+     */
+    private void processSinkRemovedInternal(ConnectPoint source, ConnectPoint sink,
+                                          IpAddress mcastIp) {
+        lastMcastChange = Instant.now();
+        mcastLock();
+        try {
+            // Verify leadership on the operation
+            if (!isLeader(source)) {
+                log.debug("Skip {} due to lack of leadership", mcastIp);
+                return;
+            }
+
+            // When source and sink are on the same device
+            if (source.deviceId().equals(sink.deviceId())) {
+                // Source and sink are on even the same port. There must be something wrong.
+                if (source.port().equals(sink.port())) {
+                    log.warn("Skip {} since sink {} is on the same port of source {}. Abort",
+                             mcastIp, sink, source);
+                    return;
+                }
+                removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(source));
+                return;
+            }
+
+            // Process the egress device
+            boolean isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(null));
+            if (isLast) {
+                mcastRoleStore.remove(new McastStoreKey(mcastIp, sink.deviceId()));
+            }
+
+            // If this is the last sink on the device, also update upstream
+            Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp);
+            if (mcastPath.isPresent()) {
+                List<Link> links = Lists.newArrayList(mcastPath.get().links());
+                Collections.reverse(links);
+                for (Link link : links) {
+                    if (isLast) {
+                        isLast = removePortFromDevice(
+                                link.src().deviceId(),
+                                link.src().port(),
+                                mcastIp,
+                                assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null)
+                        );
+                        mcastRoleStore.remove(new McastStoreKey(mcastIp, link.src().deviceId()));
+                    }
                 }
             }
+        } finally {
+            mcastUnlock();
         }
     }
 
@@ -245,54 +393,61 @@
      */
     private void processSinkAddedInternal(ConnectPoint source, ConnectPoint sink,
             IpAddress mcastIp) {
-        // Continue only when this instance is the master of source device
-        if (!srManager.mastershipService.isLocalMaster(source.deviceId())) {
-            log.info("Skip {} due to lack of mastership of the source device {}",
-                    source.deviceId());
-            return;
-        }
-
-        // Process the ingress device
-        addFilterToDevice(source.deviceId(), source.port(), assignedVlan(source), mcastIp);
-
-        // When source and sink are on the same device
-        if (source.deviceId().equals(sink.deviceId())) {
-            // Source and sink are on even the same port. There must be something wrong.
-            if (source.port().equals(sink.port())) {
-                log.warn("Sink is on the same port of source. Abort");
+        lastMcastChange = Instant.now();
+        mcastLock();
+        try {
+            // Continue only when this instance is the master of source device
+            if (!srManager.mastershipService.isLocalMaster(source.deviceId())) {
+                log.debug("Skip {} due to lack of mastership of the source device {}",
+                          mcastIp, source.deviceId());
                 return;
             }
-            addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(source));
-            mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()), McastRole.INGRESS);
-            return;
-        }
 
-        // Find a path. If present, create/update groups and flows for each hop
-        Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp);
-        if (mcastPath.isPresent()) {
-            List<Link> links = mcastPath.get().links();
-            checkState(links.size() == 2,
-                    "Path in leaf-spine topology should always be two hops: ", links);
+            // Process the ingress device
+            addFilterToDevice(source.deviceId(), source.port(), assignedVlan(source), mcastIp);
 
-            links.forEach(link -> {
-                addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
-                        assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
-                addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null), mcastIp);
-            });
+            // When source and sink are on the same device
+            if (source.deviceId().equals(sink.deviceId())) {
+                // Source and sink are on even the same port. There must be something wrong.
+                if (source.port().equals(sink.port())) {
+                    log.warn("Skip {} since sink {} is on the same port of source {}. Abort",
+                             mcastIp, sink, source);
+                    return;
+                }
+                addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(source));
+                mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()), McastRole.INGRESS);
+                return;
+            }
 
-            // Process the egress device
-            addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(null));
+            // Find a path. If present, create/update groups and flows for each hop
+            Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp);
+            if (mcastPath.isPresent()) {
+                List<Link> links = mcastPath.get().links();
+                checkState(links.size() == 2,
+                           "Path in leaf-spine topology should always be two hops: ", links);
 
-            // Setup mcast roles
-            mcastRoleStore.put(new McastStoreKey(mcastIp, source.deviceId()),
-                    McastRole.INGRESS);
-            mcastRoleStore.put(new McastStoreKey(mcastIp, links.get(0).dst().deviceId()),
-                    McastRole.TRANSIT);
-            mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()),
-                    McastRole.EGRESS);
-        } else {
-            log.warn("Unable to find a path from {} to {}. Abort sinkAdded",
-                    source.deviceId(), sink.deviceId());
+                links.forEach(link -> {
+                    addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
+                                    assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
+                    addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null), mcastIp);
+                });
+
+                // Process the egress device
+                addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(null));
+
+                // Setup mcast roles
+                mcastRoleStore.put(new McastStoreKey(mcastIp, source.deviceId()),
+                                   McastRole.INGRESS);
+                mcastRoleStore.put(new McastStoreKey(mcastIp, links.get(0).dst().deviceId()),
+                                   McastRole.TRANSIT);
+                mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()),
+                                   McastRole.EGRESS);
+            } else {
+                log.warn("Unable to find a path from {} to {}. Abort sinkAdded",
+                         source.deviceId(), sink.deviceId());
+            }
+        } finally {
+            mcastUnlock();
         }
     }
 
@@ -302,60 +457,160 @@
      * @param affectedLink Link that is going down
      */
     protected void processLinkDown(Link affectedLink) {
-        getAffectedGroups(affectedLink).forEach(mcastIp -> {
-            // Find out the ingress, transit and egress device of affected group
-            DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS)
-                    .stream().findAny().orElse(null);
-            DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT)
-                    .stream().findAny().orElse(null);
-            Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS);
-            ConnectPoint source = getSource(mcastIp);
+        lastMcastChange = Instant.now();
+        mcastLock();
+        try {
+            // Get groups affected by the link down event
+            getAffectedGroups(affectedLink).forEach(mcastIp -> {
+                // TODO Optimize when the group editing is in place
+                log.debug("Processing link down {} for group {}",
+                          affectedLink, mcastIp);
 
-            // Do not proceed if any of these info is missing
-            if (ingressDevice == null || transitDevice == null
-                    || egressDevices == null || source == null) {
-                log.warn("Missing ingress {}, transit {}, egress {} devices or source {}",
-                        ingressDevice, transitDevice, egressDevices, source);
-                return;
-            }
+                // Find out the ingress, transit and egress device of affected group
+                DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS)
+                        .stream().findAny().orElse(null);
+                DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT)
+                        .stream().findAny().orElse(null);
+                Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS);
+                ConnectPoint source = getSource(mcastIp);
 
-            // Continue only when this instance is the master of source device
-            if (!srManager.mastershipService.isLocalMaster(source.deviceId())) {
-                log.info("Skip {} due to lack of mastership of the source device {}",
-                        source.deviceId());
-                return;
-            }
+                // Do not proceed if any of these info is missing
+                if (ingressDevice == null || transitDevice == null
+                        || egressDevices == null || source == null) {
+                    log.warn("Missing ingress {}, transit {}, egress {} devices or source {}",
+                             ingressDevice, transitDevice, egressDevices, source);
+                    return;
+                }
 
-            // Remove entire transit
-            removeGroupFromDevice(transitDevice, mcastIp, assignedVlan(null));
+                // Continue only when this instance is the master of source device
+                if (!srManager.mastershipService.isLocalMaster(source.deviceId())) {
+                    log.debug("Skip {} due to lack of mastership of the source device {}",
+                             source.deviceId());
+                    return;
+                }
 
-            // Remove transit-facing port on ingress device
-            PortNumber ingressTransitPort = ingressTransitPort(mcastIp);
-            if (ingressTransitPort != null) {
-                removePortFromDevice(ingressDevice, ingressTransitPort, mcastIp, assignedVlan(source));
-                mcastRoleStore.remove(new McastStoreKey(mcastIp, transitDevice));
-            }
+                // Remove entire transit
+                removeGroupFromDevice(transitDevice, mcastIp, assignedVlan(null));
 
-            // Construct a new path for each egress device
-            egressDevices.forEach(egressDevice -> {
-                Optional<Path> mcastPath = getPath(ingressDevice, egressDevice, mcastIp);
-                if (mcastPath.isPresent()) {
-                    List<Link> links = mcastPath.get().links();
-                    links.forEach(link -> {
-                        addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
-                                assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
-                        addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null), mcastIp);
-                    });
-                    // Setup new transit mcast role
-                    mcastRoleStore.put(new McastStoreKey(mcastIp,
-                            links.get(0).dst().deviceId()), McastRole.TRANSIT);
+                // Remove transit-facing port on ingress device
+                PortNumber ingressTransitPort = ingressTransitPort(mcastIp);
+                if (ingressTransitPort != null) {
+                    removePortFromDevice(ingressDevice, ingressTransitPort, mcastIp, assignedVlan(source));
+                    mcastRoleStore.remove(new McastStoreKey(mcastIp, transitDevice));
+                }
+
+                // Construct a new path for each egress device
+                egressDevices.forEach(egressDevice -> {
+                    Optional<Path> mcastPath = getPath(ingressDevice, egressDevice, mcastIp);
+                    if (mcastPath.isPresent()) {
+                        installPath(mcastIp, source, mcastPath.get());
+                    } else {
+                        log.warn("Fail to recover egress device {} from link failure {}",
+                                 egressDevice, affectedLink);
+                        removeGroupFromDevice(egressDevice, mcastIp, assignedVlan(null));
+                    }
+                });
+            });
+        } finally {
+            mcastUnlock();
+        }
+    }
+
+    /**
+     * Process the DEVICE_DOWN event.
+     *
+     * @param deviceDown device going down
+     */
+    protected void processDeviceDown(DeviceId deviceDown) {
+        lastMcastChange = Instant.now();
+        mcastLock();
+        try {
+            // Get the mcast groups affected by the device going down
+            getAffectedGroups(deviceDown).forEach(mcastIp -> {
+                // TODO Optimize when the group editing is in place
+                log.debug("Processing device down {} for group {}",
+                          deviceDown, mcastIp);
+
+                // Find out the ingress, transit and egress device of affected group
+                DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS)
+                        .stream().findAny().orElse(null);
+                DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT)
+                        .stream().findAny().orElse(null);
+                Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS);
+                ConnectPoint source = getSource(mcastIp);
+
+                // Do not proceed if ingress device or source of this group are missing
+                // If sinks are in other leafs, we have ingress, transit, egress, and source
+                // If sinks are in the same leaf, we have just ingress and source
+                if (ingressDevice == null || source == null) {
+                    log.warn("Missing ingress {} or source {} for group {}",
+                             ingressDevice, source, mcastIp);
+                    return;
+                }
+
+                // Verify leadership on the operation
+                if (!isLeader(source)) {
+                    log.debug("Skip {} due to lack of leadership", mcastIp);
+                    return;
+                }
+
+                // If it exists, we have to remove it in any case
+                if (transitDevice != null) {
+                    // Remove entire transit
+                    removeGroupFromDevice(transitDevice, mcastIp, assignedVlan(null));
+                }
+                // If the ingress is down
+                if (ingressDevice.equals(deviceDown)) {
+                    // Remove entire ingress
+                    removeGroupFromDevice(ingressDevice, mcastIp, assignedVlan(source));
+                    // If other sinks different from the ingress exist
+                    if (!egressDevices.isEmpty()) {
+                        // Remove all the remaining egress
+                        egressDevices.forEach(
+                                egressDevice -> removeGroupFromDevice(egressDevice, mcastIp, assignedVlan(null))
+                        );
+                    }
                 } else {
-                    log.warn("Fail to recover egress device {} from link failure {}",
-                            egressDevice, affectedLink);
-                    removeGroupFromDevice(egressDevice, mcastIp, assignedVlan(null));
+                    // Egress or transit could be down at this point
+                    // Get the ingress-transit port if it exists
+                    PortNumber ingressTransitPort = ingressTransitPort(mcastIp);
+                    if (ingressTransitPort != null) {
+                        // Remove transit-facing port on ingress device
+                        removePortFromDevice(ingressDevice, ingressTransitPort, mcastIp, assignedVlan(source));
+                    }
+                    // One of the egress device is down
+                    if (egressDevices.contains(deviceDown)) {
+                        // Remove entire device down
+                        removeGroupFromDevice(deviceDown, mcastIp, assignedVlan(null));
+                        // Remove the device down from egress
+                        egressDevices.remove(deviceDown);
+                        // If there are no more egress and ingress does not have sinks
+                        if (egressDevices.isEmpty() && !hasSinks(ingressDevice, mcastIp)) {
+                            // Remove entire ingress
+                            mcastRoleStore.remove(new McastStoreKey(mcastIp, ingressDevice));
+                            // We have done
+                            return;
+                        }
+                    }
+                    // Construct a new path for each egress device
+                    egressDevices.forEach(egressDevice -> {
+                        Optional<Path> mcastPath = getPath(ingressDevice, egressDevice, mcastIp);
+                        // If there is a new path
+                        if (mcastPath.isPresent()) {
+                            // Let's install the new mcast path for this egress
+                            installPath(mcastIp, source, mcastPath.get());
+                        } else {
+                            // We were not able to find an alternative path for this egress
+                            log.warn("Fail to recover egress device {} from device down {}",
+                                     egressDevice, deviceDown);
+                            removeGroupFromDevice(egressDevice, mcastIp, assignedVlan(null));
+                        }
+                    });
                 }
             });
-        });
+        } finally {
+            mcastUnlock();
+        }
     }
 
     /**
@@ -399,9 +654,15 @@
             IpAddress mcastIp, VlanId assignedVlan) {
         McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId);
         ImmutableSet.Builder<PortNumber> portBuilder = ImmutableSet.builder();
+        NextObjective newNextObj;
         if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
             // First time someone request this mcast group via this device
             portBuilder.add(port);
+            // New nextObj
+            newNextObj = nextObjBuilder(mcastIp, assignedVlan,
+                                        portBuilder.build(), null).add();
+            // Store the new port
+            mcastNextObjStore.put(mcastStoreKey, newNextObj);
         } else {
             // This device already serves some subscribers of this mcast group
             NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
@@ -411,7 +672,18 @@
                 log.info("NextObj for {}/{} already exists. Abort", deviceId, port);
                 return;
             }
+            // Let's add the port and reuse the previous one
             portBuilder.addAll(existingPorts).add(port);
+            // Reuse previous nextObj
+            newNextObj = nextObjBuilder(mcastIp, assignedVlan,
+                                        portBuilder.build(), nextObj.id()).addToExisting();
+            // Store the final next objective and send only the difference to the driver
+            mcastNextObjStore.put(mcastStoreKey, newNextObj);
+            // Add just the new port
+            portBuilder = ImmutableSet.builder();
+            portBuilder.add(port);
+            newNextObj = nextObjBuilder(mcastIp, assignedVlan,
+                                        portBuilder.build(), nextObj.id()).addToExisting();
         }
         // Create, store and apply the new nextObj and fwdObj
         ObjectiveContext context = new DefaultObjectiveContext(
@@ -420,11 +692,8 @@
                 (objective, error) ->
                         log.warn("Failed to add {} on {}/{}, vlan {}: {}",
                                 mcastIp, deviceId, port.toLong(), assignedVlan, error));
-        NextObjective newNextObj =
-                nextObjBuilder(mcastIp, assignedVlan, portBuilder.build()).add();
         ForwardingObjective fwdObj =
                 fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(context);
-        mcastNextObjStore.put(mcastStoreKey, newNextObj);
         srManager.flowObjectiveService.next(deviceId, newNextObj);
         srManager.flowObjectiveService.forward(deviceId, fwdObj);
     }
@@ -462,13 +731,14 @@
         existingPorts.remove(port);
 
         NextObjective newNextObj;
+        ObjectiveContext context;
         ForwardingObjective fwdObj;
         if (existingPorts.isEmpty()) {
-            // If this is the last sink, remove flows and groups
+            // If this is the last sink, remove flows and last bucket
             // NOTE: Rely on GroupStore garbage collection rather than explicitly
             //       remove L3MG since there might be other flows/groups refer to
             //       the same L2IG
-            ObjectiveContext context = new DefaultObjectiveContext(
+            context = new DefaultObjectiveContext(
                     (objective) -> log.debug("Successfully remove {} on {}/{}, vlan {}",
                             mcastIp, deviceId, port.toLong(), assignedVlan),
                     (objective, error) ->
@@ -476,25 +746,28 @@
                                     mcastIp, deviceId, port.toLong(), assignedVlan, error));
             fwdObj = fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(context);
             mcastNextObjStore.remove(mcastStoreKey);
-            srManager.flowObjectiveService.forward(deviceId, fwdObj);
         } else {
             // If this is not the last sink, update flows and groups
-            ObjectiveContext context = new DefaultObjectiveContext(
+            context = new DefaultObjectiveContext(
                     (objective) -> log.debug("Successfully update {} on {}/{}, vlan {}",
                             mcastIp, deviceId, port.toLong(), assignedVlan),
                     (objective, error) ->
                             log.warn("Failed to update {} on {}/{}, vlan {}: {}",
                                     mcastIp, deviceId, port.toLong(), assignedVlan, error));
-            newNextObj = nextObjBuilder(mcastIp, assignedVlan, existingPorts).add();
+            // Here we store the next objective with the remaining port
+            newNextObj = nextObjBuilder(mcastIp, assignedVlan,
+                                        existingPorts, nextObj.id()).removeFromExisting();
             fwdObj = fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(context);
             mcastNextObjStore.put(mcastStoreKey, newNextObj);
-            srManager.flowObjectiveService.next(deviceId, newNextObj);
-            srManager.flowObjectiveService.forward(deviceId, fwdObj);
         }
+        // Let's modify the next objective removing the bucket
+        newNextObj = nextObjBuilder(mcastIp, assignedVlan,
+                                    ImmutableSet.of(port), nextObj.id()).removeFromExisting();
+        srManager.flowObjectiveService.next(deviceId, newNextObj);
+        srManager.flowObjectiveService.forward(deviceId, fwdObj);
         return existingPorts.isEmpty();
     }
 
-
     /**
      * Removes entire group on given device.
      *
@@ -526,28 +799,20 @@
         mcastRoleStore.remove(mcastStoreKey);
     }
 
-    /**
-     * Remove all groups on given device.
-     *
-     * @param deviceId device ID
-     */
-    public void removeDevice(DeviceId deviceId) {
-        mcastNextObjStore.entrySet().stream()
-                .filter(entry -> entry.getKey().deviceId().equals(deviceId))
-                .forEach(entry -> {
-                    ConnectPoint source = getSource(entry.getKey().mcastIp());
-                    removeGroupFromDevice(entry.getKey().deviceId(), entry.getKey().mcastIp(),
-                            assignedVlan(source != null && deviceId.equals(source.deviceId()) ? source : null));
-                    mcastNextObjStore.remove(entry.getKey());
-                });
-        log.debug("{} is removed from mcastNextObjStore", deviceId);
-
-        mcastRoleStore.entrySet().stream()
-                .filter(entry -> entry.getKey().deviceId().equals(deviceId))
-                .forEach(entry -> {
-                    mcastRoleStore.remove(entry.getKey());
-                });
-        log.debug("{} is removed from mcastRoleStore", deviceId);
+    private void installPath(IpAddress mcastIp, ConnectPoint source, Path mcastPath) {
+        // Get Links
+        List<Link> links = mcastPath.links();
+        // For each link, modify the next on the source device adding the src port
+        // and a new filter objective on the destination port
+        links.forEach(link -> {
+            addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
+                            assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
+            addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null),
+                              mcastIp);
+        });
+        // Setup new transit mcast role
+        mcastRoleStore.put(new McastStoreKey(mcastIp, links.get(0).dst().deviceId()),
+                           McastRole.TRANSIT);
     }
 
     /**
@@ -559,8 +824,11 @@
      * @return next objective builder
      */
     private NextObjective.Builder nextObjBuilder(IpAddress mcastIp,
-            VlanId assignedVlan, Set<PortNumber> outPorts) {
-        int nextId = srManager.flowObjectiveService.allocateNextId();
+            VlanId assignedVlan, Set<PortNumber> outPorts, Integer nextId) {
+        // If nextId is null allocate a new one
+        if (nextId == null) {
+            nextId = srManager.flowObjectiveService.allocateNextId();
+        }
 
         TrafficSelector metadata =
                 DefaultTrafficSelector.builder()
@@ -688,21 +956,75 @@
             return Optional.empty();
         }
 
-        // If one of the available path is used before, use the same path
-        McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, src);
-        if (mcastNextObjStore.containsKey(mcastStoreKey)) {
-            NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
-            Set<PortNumber> existingPorts = getPorts(nextObj.next());
-            for (Path path : allPaths) {
-                PortNumber srcPort = path.links().get(0).src().port();
-                if (existingPorts.contains(srcPort)) {
-                    return Optional.of(path);
+        // Create a map index of suitablity-to-list of paths. For example
+        // a path in the list associated to the index 1 shares only the
+        // first hop and it is less suitable of a path belonging to the index
+        // 2 that shares leaf-spine.
+        Map<Integer, List<Path>> eligiblePaths = Maps.newHashMap();
+        // Some init steps
+        int nhop;
+        McastStoreKey mcastStoreKey;
+        Link hop;
+        PortNumber srcPort;
+        Set<PortNumber> existingPorts;
+        NextObjective nextObj;
+        // Iterate over paths looking for eligible paths
+        for (Path path : allPaths) {
+            // Unlikely, it will happen...
+            if (!src.equals(path.links().get(0).src().deviceId())) {
+                continue;
+            }
+            nhop = 0;
+            // Iterate over the links
+            while (nhop < path.links().size()) {
+                // Get the link and verify if a next related
+                // to the src device exist in the store
+                hop = path.links().get(nhop);
+                mcastStoreKey = new McastStoreKey(mcastIp, hop.src().deviceId());
+                // It does not exist in the store, exit
+                if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
+                    break;
                 }
+                // Get the output ports on the next
+                nextObj = mcastNextObjStore.get(mcastStoreKey).value();
+                existingPorts = getPorts(nextObj.next());
+                // And the src port on the link
+                srcPort = hop.src().port();
+                // the src port is not used as output, exit
+                if (!existingPorts.contains(srcPort)) {
+                    break;
+                }
+                nhop++;
+            }
+            // n_hop defines the index
+            if (nhop > 0) {
+                eligiblePaths.compute(nhop, (index, paths) -> {
+                    paths = paths == null ? Lists.newArrayList() : paths;
+                    paths.add(path);
+                    return paths;
+                });
             }
         }
-        // Otherwise, randomly pick a path
-        Collections.shuffle(allPaths);
-        return allPaths.stream().findFirst();
+
+        // No suitable paths
+        if (eligiblePaths.isEmpty()) {
+            log.debug("No eligiblePath(s) found from {} to {}", src, dst);
+            // Otherwise, randomly pick a path
+            Collections.shuffle(allPaths);
+            return allPaths.stream().findFirst();
+        }
+
+        // Let's take the best ones
+        Integer bestIndex = eligiblePaths.keySet()
+                .stream()
+                .sorted(Comparator.reverseOrder())
+                .findFirst().orElse(null);
+        List<Path> bestPaths = eligiblePaths.get(bestIndex);
+        log.debug("{} eligiblePath(s) found from {} to {}",
+                  bestPaths.size(), src, dst);
+        // randomly pick a path on the highest index
+        Collections.shuffle(bestPaths);
+        return bestPaths.stream().findFirst();
     }
 
     /**
@@ -750,6 +1072,19 @@
     }
 
     /**
+     * Gets groups which are affected by the device down event.
+     *
+     * @param deviceId device going down
+     * @return a set of multicast IpAddress
+     */
+    private Set<IpAddress> getAffectedGroups(DeviceId deviceId) {
+        return mcastNextObjStore.entrySet().stream()
+                .filter(entry -> entry.getKey().deviceId().equals(deviceId))
+                .map(Map.Entry::getKey).map(McastStoreKey::mcastIp)
+                .collect(Collectors.toSet());
+    }
+
+    /**
      * Gets egress VLAN from McastConfig.
      *
      * @return egress VLAN or VlanId.NONE if not configured
@@ -808,6 +1143,40 @@
     }
 
     /**
+     * Verify if the given device has sinks
+     * for the multicast group.
+     *
+     * @param deviceId device Id
+     * @param mcastIp multicast IP
+     * @return true if the device has sink for the group.
+     * False otherwise.
+     */
+    private boolean hasSinks(DeviceId deviceId, IpAddress mcastIp) {
+        if (deviceId != null) {
+            // Get the nextobjective
+            Versioned<NextObjective> versionedNextObj = mcastNextObjStore.get(
+                    new McastStoreKey(mcastIp, deviceId)
+            );
+            // If it exists
+            if (versionedNextObj != null) {
+                NextObjective nextObj = versionedNextObj.value();
+                // Retrieves all the output ports
+                Set<PortNumber> ports = getPorts(nextObj.next());
+                // Tries to find at least one port that is not spine-facing
+                for (PortNumber port : ports) {
+                    // Spine-facing port should have no subnet and no xconnect
+                    if (srManager.deviceConfiguration != null &&
+                            (!srManager.deviceConfiguration.getPortSubnets(deviceId, port).isEmpty() ||
+                            srManager.xConnectHandler.hasXConnect(new ConnectPoint(deviceId, port)))) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Removes filtering objective for given device and port.
      *
      * @param deviceId device ID
@@ -837,7 +1206,9 @@
     }
 
     /**
-     * Adds or removes filtering objective for given device and port.
+     * Updates filtering objective for given device and port.
+     * It is called in general when the mcast config has been
+     * changed.
      *
      * @param deviceId device ID
      * @param portNum ingress port number
@@ -846,15 +1217,237 @@
      */
     protected void updateFilterToDevice(DeviceId deviceId, PortNumber portNum,
                                         VlanId vlanId, boolean install) {
-        srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> {
-            ConnectPoint source = srManager.multicastRouteService.fetchSource(mcastRoute);
-            if (source.deviceId().equals(deviceId) && source.port().equals(portNum)) {
-                if (install) {
-                    addFilterToDevice(deviceId, portNum, vlanId, mcastRoute.group());
+        lastMcastChange = Instant.now();
+        mcastLock();
+        try {
+            // Iterates over the route and updates properly the filtering objective
+            // on the source device.
+            srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> {
+                ConnectPoint source = srManager.multicastRouteService.fetchSource(mcastRoute);
+                if (source.deviceId().equals(deviceId) && source.port().equals(portNum)) {
+                    if (install) {
+                        addFilterToDevice(deviceId, portNum, vlanId, mcastRoute.group());
+                    } else {
+                        removeFilterToDevice(deviceId, portNum, vlanId, mcastRoute.group());
+                    }
+                }
+            });
+        } finally {
+            mcastUnlock();
+        }
+    }
+
+    private boolean isLeader(ConnectPoint source) {
+        // Continue only when we have the mastership on the operation
+        if (!srManager.mastershipService.isLocalMaster(source.deviceId())) {
+            // When the source is available we just check the mastership
+            if (srManager.deviceService.isAvailable(source.deviceId())) {
+                return false;
+            }
+            // Fallback with Leadership service
+            // source id is used a topic
+            NodeId leader = srManager.leadershipService.runForLeadership(
+                    source.deviceId().toString()).leaderNodeId();
+            // Verify if this node is the leader
+            if (!srManager.clusterService.getLocalNode().id().equals(leader)) {
+                return false;
+            }
+        }
+        // Done
+        return true;
+    }
+
+    /**
+     * Performs bucket verification operation for all mcast groups in the devices.
+     * Firstly, it verifies that mcast is stable before trying verification operation.
+     * Verification consists in creating new nexts with VERIFY operation. Actually,
+     * the operation is totally delegated to the driver.
+     */
+     private final class McastBucketCorrector implements Runnable {
+
+        @Override
+        public void run() {
+            // Verify if the Mcast has been stable for MCAST_STABLITY_THRESHOLD
+            if (!isMcastStable()) {
+                return;
+            }
+            // Acquires lock
+            mcastLock();
+            try {
+                // Iterates over the routes and verify the related next objectives
+                srManager.multicastRouteService.getRoutes()
+                    .stream()
+                    .map(McastRoute::group)
+                    .forEach(mcastIp -> {
+                        log.trace("Running mcast buckets corrector for mcast group: {}",
+                                  mcastIp);
+
+                        // For each group we get current information in the store
+                        // and issue a check of the next objectives in place
+                        DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS)
+                                .stream().findAny().orElse(null);
+                        DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT)
+                                .stream().findAny().orElse(null);
+                        Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS);
+                        ConnectPoint source = getSource(mcastIp);
+
+                        // Do not proceed if ingress device or source of this group are missing
+                        if (ingressDevice == null || source == null) {
+                            log.warn("Unable to run buckets corrector. " +
+                                             "Missing ingress {} or source {} for group {}",
+                                     ingressDevice, source, mcastIp);
+                            return;
+                        }
+
+                        // Continue only when this instance is the master of source device
+                        if (!srManager.mastershipService.isLocalMaster(source.deviceId())) {
+                            log.trace("Unable to run buckets corrector. " +
+                                             "Skip {} due to lack of mastership " +
+                                             "of the source device {}",
+                                     mcastIp, source.deviceId());
+                            return;
+                        }
+
+                        // Create the set of the devices to be processed
+                        ImmutableSet.Builder<DeviceId> devicesBuilder = ImmutableSet.builder();
+                        devicesBuilder.add(ingressDevice);
+                        if (transitDevice != null) {
+                            devicesBuilder.add(transitDevice);
+                        }
+                        if (!egressDevices.isEmpty()) {
+                            devicesBuilder.addAll(egressDevices);
+                        }
+                        Set<DeviceId> devicesToProcess = devicesBuilder.build();
+
+                        // Iterate over the devices
+                        devicesToProcess.forEach(deviceId -> {
+                            McastStoreKey currentKey = new McastStoreKey(mcastIp, deviceId);
+                            // If next exists in our store verify related next objective
+                            if (mcastNextObjStore.containsKey(currentKey)) {
+                                NextObjective currentNext = mcastNextObjStore.get(currentKey).value();
+                                // Get current ports
+                                Set<PortNumber> currentPorts = getPorts(currentNext.next());
+                                // Rebuild the next objective
+                                currentNext = nextObjBuilder(
+                                        mcastIp,
+                                        assignedVlan(deviceId.equals(source.deviceId()) ? source : null),
+                                        currentPorts,
+                                        currentNext.id()
+                                ).verify();
+                                // Send to the flowobjective service
+                                srManager.flowObjectiveService.next(deviceId, currentNext);
+                            } else {
+                                log.warn("Unable to run buckets corrector." +
+                                                 "Missing next for {} and group {}",
+                                         deviceId, mcastIp);
+                            }
+                        });
+
+                    });
+            } finally {
+                // Finally, it releases the lock
+                mcastUnlock();
+            }
+
+        }
+    }
+
+    public Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp) {
+        // If mcast ip is present
+        if (mcastIp != null) {
+            return mcastNextObjStore.entrySet().stream()
+                    .filter(mcastEntry -> mcastIp.equals(mcastEntry.getKey().mcastIp()))
+                    .collect(Collectors.toMap(Map.Entry::getKey,
+                                              entry -> entry.getValue().value().id()));
+        }
+        // Otherwise take all the groups
+        return mcastNextObjStore.entrySet().stream()
+                .collect(Collectors.toMap(Map.Entry::getKey,
+                                          entry -> entry.getValue().value().id()));
+    }
+
+    public Map<McastStoreKey, McastHandler.McastRole> getMcastRoles(IpAddress mcastIp) {
+        // If mcast ip is present
+        if (mcastIp != null) {
+            return mcastRoleStore.entrySet().stream()
+                    .filter(mcastEntry -> mcastIp.equals(mcastEntry.getKey().mcastIp()))
+                    .collect(Collectors.toMap(Map.Entry::getKey,
+                                              entry -> entry.getValue().value()));
+        }
+        // Otherwise take all the groups
+        return mcastRoleStore.entrySet().stream()
+                .collect(Collectors.toMap(Map.Entry::getKey,
+                                          entry -> entry.getValue().value()));
+    }
+
+    public Map<ConnectPoint, List<ConnectPoint>> getMcastPaths(IpAddress mcastIp) {
+        Map<ConnectPoint, List<ConnectPoint>> mcastPaths = Maps.newHashMap();
+        // Get the source
+        ConnectPoint source = getSource(mcastIp);
+        // Source cannot be null, we don't know the starting point
+        if (source != null) {
+            // Init steps
+            Set<DeviceId> visited = Sets.newHashSet();
+            List<ConnectPoint> currentPath = Lists.newArrayList(
+                    source
+            );
+            // Build recursively the mcast paths
+            buildMcastPaths(source.deviceId(), visited, mcastPaths, currentPath, mcastIp);
+        }
+        return mcastPaths;
+    }
+
+    private void buildMcastPaths(DeviceId toVisit, Set<DeviceId> visited,
+                                 Map<ConnectPoint, List<ConnectPoint>> mcastPaths,
+                                 List<ConnectPoint> currentPath, IpAddress mcastIp) {
+        // If we have visited the node to visit
+        // there is a loop
+        if (visited.contains(toVisit)) {
+            return;
+        }
+        // Visit next-hop
+        visited.add(toVisit);
+        McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, toVisit);
+        // Looking for next-hops
+        if (mcastNextObjStore.containsKey(mcastStoreKey)) {
+            // Build egress connectpoints
+            NextObjective nextObjective = mcastNextObjStore.get(mcastStoreKey).value();
+            // Get Ports
+            Set<PortNumber> outputPorts = getPorts(nextObjective.next());
+            // Build relative cps
+            ImmutableSet.Builder<ConnectPoint> cpBuilder = ImmutableSet.builder();
+            outputPorts.forEach(portNumber -> cpBuilder.add(new ConnectPoint(toVisit, portNumber)));
+            Set<ConnectPoint> egressPoints = cpBuilder.build();
+            // Define other variables for the next steps
+            Set<Link> egressLinks;
+            List<ConnectPoint> newCurrentPath;
+            Set<DeviceId> newVisited;
+            DeviceId newToVisit;
+            for (ConnectPoint egressPoint : egressPoints) {
+                egressLinks = srManager.linkService.getEgressLinks(egressPoint);
+                // If it does not have egress links, stop
+                if (egressLinks.isEmpty()) {
+                    // Add the connect points to the path
+                    newCurrentPath = Lists.newArrayList(currentPath);
+                    newCurrentPath.add(0, egressPoint);
+                    // Save in the map
+                    mcastPaths.put(egressPoint, newCurrentPath);
                 } else {
-                    removeFilterToDevice(deviceId, portNum, vlanId, mcastRoute.group());
+                    newVisited = Sets.newHashSet(visited);
+                    // Iterate over the egress links for the next hops
+                    for (Link egressLink : egressLinks) {
+                        // Update to visit
+                        newToVisit = egressLink.dst().deviceId();
+                        // Add the connect points to the path
+                        newCurrentPath = Lists.newArrayList(currentPath);
+                        newCurrentPath.add(0, egressPoint);
+                        newCurrentPath.add(0, egressLink.dst());
+                        // Go to the next hop
+                        buildMcastPaths(newToVisit, newVisited, mcastPaths, newCurrentPath, mcastIp);
+                    }
                 }
             }
-        });
+        }
     }
+
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PortAuthTracker.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PortAuthTracker.java
index 627ca7d..2127019 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PortAuthTracker.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PortAuthTracker.java
@@ -17,6 +17,7 @@
 package org.onosproject.segmentrouting;
 
 
+import com.google.common.base.Objects;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
@@ -333,5 +334,24 @@
             int result = Comparators.ELEMENT_ID_COMPARATOR.compare(d, o.d);
             return (result != 0) ? result : Long.signum(p.toLong() - o.p.toLong());
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final PortAuthTracker.PortAuthState that = (PortAuthTracker.PortAuthState) obj;
+
+            return Comparators.ELEMENT_ID_COMPARATOR.compare(this.d, that.d) == 0 &&
+                    p.toLong() == that.p.toLong();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(this.d, this.p);
+        }
     }
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RouteHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
index c80bc09..21870ee 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
@@ -161,25 +161,20 @@
         log.debug("RouteUpdated. populateSubnet {}, {}", allLocations, allPrefixes);
         srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);
 
-
         Set<ResolvedRoute> toBeRemoved = Sets.difference(oldRoutes, routes).immutableCopy();
         Set<ResolvedRoute> toBeAdded = Sets.difference(routes, oldRoutes).immutableCopy();
 
         toBeRemoved.forEach(route -> {
             srManager.nextHopLocations(route).forEach(oldLocation -> {
-               if (toBeAdded.stream().map(srManager::nextHopLocations)
-                       .flatMap(Set::stream).map(ConnectPoint::deviceId)
-                       .noneMatch(deviceId -> deviceId.equals(oldLocation.deviceId()))) {
-                   IpPrefix prefix = route.prefix();
-                   MacAddress nextHopMac = route.nextHopMac();
-                   VlanId nextHopVlan = route.nextHopVlan();
-
-                   log.debug("RouteUpdated. removeSubnet {}, {}", oldLocation, prefix);
-                   srManager.deviceConfiguration.removeSubnet(oldLocation, prefix);
-                   log.debug("RouteUpdated. revokeRoute {}, {}, {}, {}", oldLocation, prefix, nextHopMac, nextHopVlan);
-                   srManager.defaultRoutingHandler.revokeRoute(oldLocation.deviceId(), prefix,
-                           nextHopMac, nextHopVlan, oldLocation.port());
-               }
+                if (toBeAdded.stream().map(srManager::nextHopLocations)
+                        .flatMap(Set::stream).map(ConnectPoint::deviceId)
+                        .noneMatch(deviceId -> deviceId.equals(oldLocation.deviceId()))) {
+                    IpPrefix prefix = route.prefix();
+                    log.debug("RouteUpdated. removeSubnet {}, {}", oldLocation, prefix);
+                    srManager.deviceConfiguration.removeSubnet(oldLocation, prefix);
+                    // We don't remove the flow on the old location in occasion of two next hops becoming one
+                    // since the populateSubnet will point the old location to the new location via spine.
+                }
             });
         });
 
@@ -197,7 +192,6 @@
                         nextHopMac, nextHopVlan, location.port());
             });
         });
-
     }
 
     void processRouteRemoved(RouteEvent event) {
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 6dd60e9..f37caea 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -444,14 +444,17 @@
                 .withPriority(getPriorityFromPrefix(ipPrefix))
                 .withFlag(ForwardingObjective.Flag.SPECIFIC);
 
-        ObjectiveContext context = new DefaultObjectiveContext(
-                (objective) -> log.debug("IP rule for router {} revoked", ipPrefix),
-                (objective, error) ->
-                        log.warn("Failed to revoke IP rule for router {}: {}", ipPrefix, error));
-
-        srManager.deviceService.getAvailableDevices().forEach(device ->
-            srManager.flowObjectiveService.forward(device.id(), fwdBuilder.remove(context))
-        );
+        srManager.deviceService.getAvailableDevices().forEach(device -> {
+            if (srManager.mastershipService.isLocalMaster(device.id())) {
+                ObjectiveContext context = new DefaultObjectiveContext(
+                        (objective) -> log.debug("IP rule for router {} revoked from {}", ipPrefix, device.id()),
+                        (objective, error) -> log.warn("Failed to revoke IP rule for router {} from {}: {}",
+                                ipPrefix, device.id(), error));
+                srManager.flowObjectiveService.forward(device.id(), fwdBuilder.remove(context));
+            } else {
+                log.debug("Not the master of {}. Abort route {} removal", device.id(), ipPrefix);
+            }
+        });
 
         return true;
     }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 3242866..525f84a 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -40,6 +40,8 @@
 import org.onlab.util.KryoNamespace;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.event.Event;
@@ -103,6 +105,7 @@
 import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
 import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
 import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
+import org.onosproject.segmentrouting.storekey.McastStoreKey;
 import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
@@ -134,6 +137,8 @@
 import static com.google.common.base.Preconditions.checkState;
 import static org.onlab.packet.Ethernet.TYPE_ARP;
 import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REGISTERED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UNREGISTERED;
 
 /**
  * Segment routing manager.
@@ -196,6 +201,12 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     public InterfaceService interfaceService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    public ClusterService clusterService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    public LeadershipService leadershipService;
+
     @Property(name = "activeProbing", boolValue = true,
             label = "Enable active probing to discover dual-homed hosts.")
     boolean activeProbing = true;
@@ -417,7 +428,7 @@
         cfgService.registerConfigFactory(xConnectConfigFactory);
         cfgService.registerConfigFactory(mcastConfigFactory);
         cfgService.registerConfigFactory(pwaasConfigFactory);
-
+        log.info("Configuring network before adding listeners");
         cfgListener.configureNetwork();
 
         hostService.addListener(hostListener);
@@ -480,6 +491,8 @@
         portNextObjStore.destroy();
         tunnelStore.destroy();
         policyStore.destroy();
+
+        mcastHandler.terminate();
         log.info("Stopped");
     }
 
@@ -640,6 +653,31 @@
         }
     }
 
+    @Override
+    public ImmutableMap<Link, Boolean> getSeenLinks() {
+        return linkHandler.getSeenLinks();
+    }
+
+    @Override
+    public ImmutableMap<DeviceId, Set<PortNumber>> getDownedPortState() {
+        return linkHandler.getDownedPorts();
+    }
+
+    @Override
+    public Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp) {
+        return mcastHandler.getMcastNextIds(mcastIp);
+    }
+
+    @Override
+    public Map<McastStoreKey, McastHandler.McastRole> getMcastRoles(IpAddress mcastIp) {
+        return mcastHandler.getMcastRoles(mcastIp);
+    }
+
+    @Override
+    public Map<ConnectPoint, List<ConnectPoint>> getMcastPaths(IpAddress mcastIp) {
+        return mcastHandler.getMcastPaths(mcastIp);
+    }
+
     /**
      * Extracts the application ID from the manager.
      *
@@ -1020,8 +1058,8 @@
     private class InternalEventHandler implements Runnable {
         @Override
         public void run() {
-            try {
-                while (true) {
+            while (true) {
+                try {
                     @SuppressWarnings("rawtypes")
                     Event event;
                     synchronized (THREAD_SCHED_LOCK) {
@@ -1037,9 +1075,6 @@
                     }
                     if (event.type() == LinkEvent.Type.LINK_ADDED ||
                             event.type() == LinkEvent.Type.LINK_UPDATED) {
-                        // Note: do not update seenLinks here, otherwise every
-                        // link, even one seen for the first time, will be appear
-                        // to be a previously seen link
                         linkHandler.processLinkAdded((Link) event.subject());
                     } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
                         linkHandler.processLinkRemoved((Link) event.subject());
@@ -1053,7 +1088,7 @@
                             processDeviceAdded((Device) event.subject());
                         } else {
                             log.info("Processing device event {} for unavailable device {}",
-                                    event.type(), ((Device) event.subject()).id());
+                                     event.type(), ((Device) event.subject()).id());
                             processDeviceRemoved((Device) event.subject());
                         }
                     } else if (event.type() == DeviceEvent.Type.PORT_ADDED) {
@@ -1077,10 +1112,10 @@
                     } else {
                         log.warn("Unhandled event type: {}", event.type());
                     }
+                } catch (Exception e) {
+                    log.error("SegmentRouting event handler thread thrown an exception: {}",
+                              e.getMessage(), e);
                 }
-            } catch (Exception e) {
-                log.error("SegmentRouting event handler "
-                        + "thread thrown an exception: {}", e);
             }
         }
     }
@@ -1157,13 +1192,13 @@
         if (gh != null) {
             gh.shutdown();
         }
-        defaultRoutingHandler.purgeEcmpGraph(device.id());
         // Note that a switch going down is associated with all of its links
         // going down as well, but it is treated as a single switch down event
         // while the link-downs are ignored.
         defaultRoutingHandler
             .populateRoutingRulesForLinkStatusChange(null, null, device.id());
-        mcastHandler.removeDevice(device.id());
+        defaultRoutingHandler.purgeEcmpGraph(device.id());
+        mcastHandler.processDeviceDown(device.id());
         xConnectHandler.removeDevice(device.id());
     }
 
@@ -1240,8 +1275,10 @@
 
     private void createOrUpdateDeviceConfiguration() {
         if (deviceConfiguration == null) {
+            log.info("Creating new DeviceConfiguration");
             deviceConfiguration = new DeviceConfiguration(this);
         } else {
+            log.info("Updating DeviceConfiguration");
             deviceConfiguration.updateConfig();
         }
     }
@@ -1277,6 +1314,7 @@
          * Reads network config and initializes related data structure accordingly.
          */
         void configureNetwork() {
+            log.info("Configuring network ...");
             createOrUpdateDeviceConfiguration();
 
             arpHandler = new ArpHandler(srManager);
@@ -1292,6 +1330,7 @@
                                               tunnelHandler, policyStore);
             // add a small delay to absorb multiple network config added notifications
             if (!programmingScheduled.get()) {
+                log.info("Buffering config calls for {} secs", PROGRAM_DELAY);
                 programmingScheduled.set(true);
                 executorService.schedule(new ConfigChange(), PROGRAM_DELAY,
                                          TimeUnit.SECONDS);
@@ -1350,6 +1389,7 @@
                     default:
                         break;
                 }
+                log.info("App config event .. configuring network");
                 configureNetwork();
             } else if (event.configClass().equals(XConnectConfig.class)) {
                 checkState(xConnectHandler != null, "XConnectHandler is not initialized");
@@ -1386,21 +1426,29 @@
 
         @Override
         public boolean isRelevant(NetworkConfigEvent event) {
-            if (event.configClass().equals(SegmentRoutingDeviceConfig.class) ||
-                    event.configClass().equals(SegmentRoutingAppConfig.class) ||
-                    event.configClass().equals(InterfaceConfig.class) ||
-                    event.configClass().equals(XConnectConfig.class) ||
-                    event.configClass().equals(PwaasConfig.class)) {
-                return true;
+            if (event.type() == CONFIG_REGISTERED ||
+                    event.type() == CONFIG_UNREGISTERED) {
+                log.debug("Ignore event {} due to type mismatch", event);
+                return false;
             }
-            log.debug("Ignore irrelevant event class {}", event.configClass().getName());
-            return false;
+
+            if (!event.configClass().equals(SegmentRoutingDeviceConfig.class) &&
+                    !event.configClass().equals(SegmentRoutingAppConfig.class) &&
+                    !event.configClass().equals(InterfaceConfig.class) &&
+                    !event.configClass().equals(XConnectConfig.class) &&
+                    !event.configClass().equals(PwaasConfig.class)) {
+                log.debug("Ignore event {} due to class mismatch", event);
+                return false;
+            }
+
+            return true;
         }
 
         private final class ConfigChange implements Runnable {
             @Override
             public void run() {
                 programmingScheduled.set(false);
+                log.info("Reacting to config changes after buffer delay");
                 for (Device device : deviceService.getDevices()) {
                     processDeviceAdded(device);
                 }
@@ -1446,8 +1494,10 @@
                 case SINK_REMOVED:
                     mcastHandler.processSinkRemoved(event);
                     break;
-                case ROUTE_ADDED:
                 case ROUTE_REMOVED:
+                    mcastHandler.processRouteRemoved(event);
+                    break;
+                case ROUTE_ADDED:
                 default:
                     break;
             }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
index 4ef6079..00e7a6a 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
@@ -15,8 +15,12 @@
  */
 package org.onosproject.segmentrouting;
 
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
+import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
 import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
 import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
 import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
@@ -24,6 +28,7 @@
 import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
 
 import com.google.common.collect.ImmutableMap;
+import org.onosproject.segmentrouting.storekey.McastStoreKey;
 
 import java.util.List;
 import java.util.Map;
@@ -189,4 +194,47 @@
      * @param id the device identifier
      */
     void verifyGroups(DeviceId id);
+
+    /**
+     * Returns the internal link state as seen by this instance of the
+     * controller.
+     *
+     * @return the internal link state
+     */
+    ImmutableMap<Link, Boolean> getSeenLinks();
+
+    /**
+     * Returns the ports administratively disabled by the controller.
+     *
+     * @return a map of devices and port numbers for administratively disabled
+     *         ports. Does not include ports manually disabled by the operator.
+     */
+    ImmutableMap<DeviceId, Set<PortNumber>> getDownedPortState();
+
+   /**
+     * Returns the associated next ids to the mcast groups or to the single
+     * group if mcastIp is present.
+     *
+     * @param mcastIp the group ip
+     * @return the mapping mcastIp-device to next id
+     */
+    Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp);
+
+    /**
+     * Returns the associated roles to the mcast groups or to the single
+     * group if mcastIp is present.
+     *
+     * @param mcastIp the group ip
+     * @return the mapping mcastIp-device to mcast role
+     */
+    Map<McastStoreKey, McastHandler.McastRole> getMcastRoles(IpAddress mcastIp);
+
+    /**
+     * Returns the associated paths to the mcast group.
+     *
+     * @param mcastIp the group ip
+     * @return the mapping egress point to mcast path
+     */
+    Map<ConnectPoint, List<ConnectPoint>> getMcastPaths(IpAddress mcastIp);
+
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/LinkStateCommand.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/LinkStateCommand.java
new file mode 100644
index 0000000..ded4ae6
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/LinkStateCommand.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018-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.segmentrouting.cli;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+
+/**
+ * Command to read the current state of the DestinationSetNextObjectiveStore.
+ *
+ */
+@Command(scope = "onos", name = "sr-link-state", description = "Displays the current internal link state "
+        + "noted by this instance of the controller")
+public class LinkStateCommand extends AbstractShellCommand {
+    private static final String FORMAT_MAPPING = "  %s";
+
+    @Override
+    protected void execute() {
+        SegmentRoutingService srService = AbstractShellCommand
+                .get(SegmentRoutingService.class);
+        printLinkState(srService.getSeenLinks(),
+                       srService.getDownedPortState());
+    }
+
+    private void printLinkState(ImmutableMap<Link, Boolean> seenLinks,
+                                ImmutableMap<DeviceId, Set<PortNumber>> downedPortState) {
+        List<Link> a = Lists.newArrayList();
+        a.addAll(seenLinks.keySet());
+        a.sort(new CompLinks());
+
+        StringBuilder slbldr = new StringBuilder();
+        slbldr.append("\n Seen Links: ");
+        for (int i = 0; i < a.size(); i++) {
+            slbldr.append("\n "
+                    + (seenLinks.get(a.get(i)) == Boolean.TRUE ? "  up : "
+                                                               : "down : "));
+            slbldr.append(a.get(i).src() + " --> " + a.get(i).dst());
+        }
+        print(FORMAT_MAPPING, slbldr.toString());
+
+        StringBuilder dpbldr = new StringBuilder();
+        dpbldr.append("\n\n Administratively Disabled Ports: ");
+        downedPortState.entrySet().forEach(entry -> dpbldr
+                .append("\n " + entry.getKey() + entry.getValue()));
+        print(FORMAT_MAPPING, dpbldr.toString());
+    }
+
+    static class CompLinks implements Comparator<Link> {
+
+        @Override
+        public int compare(Link o1, Link o2) {
+            int res = o1.src().deviceId().toString()
+                    .compareTo(o2.src().deviceId().toString());
+            if (res < 0) {
+                return -1;
+            } else if (res > 0) {
+                return +1;
+            }
+            if (o1.src().port().toLong() < o2.src().port().toLong()) {
+                return -1;
+            }
+            return +1;
+        }
+
+    }
+
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java
new file mode 100644
index 0000000..341c87d
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018-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.segmentrouting.cli;
+
+import com.google.common.collect.Maps;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.storekey.McastStoreKey;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * Command to show the list of mcast nextids.
+ */
+@Command(scope = "onos", name = "sr-mcast-next",
+        description = "Lists all mcast nextids")
+public class McastNextListCommand extends AbstractShellCommand {
+
+    // Format for group line
+    private static final String FORMAT_MAPPING = "group=%s, deviceIds-nextIds=%s";
+
+    @Argument(index = 0, name = "mcastIp", description = "mcast Ip",
+            required = false, multiValued = false)
+    String mcastIp;
+
+    @Override
+    protected void execute() {
+        // Verify mcast group
+        IpAddress mcastGroup = null;
+        if (!isNullOrEmpty(mcastIp)) {
+            mcastGroup = IpAddress.valueOf(mcastIp);
+
+        }
+        // Get SR service
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        // Get the mapping
+        Map<McastStoreKey, Integer> keyToNextId = srService.getMcastNextIds(mcastGroup);
+        // Reduce to the set of mcast groups
+        Set<IpAddress> mcastGroups = keyToNextId.keySet().stream()
+                .map(McastStoreKey::mcastIp)
+                .collect(Collectors.toSet());
+        // Print the nextids for each group
+        mcastGroups.forEach(group -> {
+            // Create a new map for the group
+            Map<DeviceId, Integer> deviceIdNextMap = Maps.newHashMap();
+            keyToNextId.entrySet()
+                    .stream()
+                    // Filter only the elements related to this group
+                    .filter(entry -> entry.getKey().mcastIp().equals(group))
+                    // For each create a new entry in the group related map
+                    .forEach(entry -> deviceIdNextMap.put(entry.getKey().deviceId(), entry.getValue()));
+            // Print the map
+            printMcastNext(group, deviceIdNextMap);
+        });
+    }
+
+    private void printMcastNext(IpAddress mcastGroup, Map<DeviceId, Integer> deviceIdNextMap) {
+        print(FORMAT_MAPPING, mcastGroup, deviceIdNextMap);
+    }
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java
new file mode 100644
index 0000000..73cbb1a
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018-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.segmentrouting.cli;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.segmentrouting.McastHandler.McastRole;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.storekey.McastStoreKey;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onosproject.segmentrouting.McastHandler.McastRole.EGRESS;
+import static org.onosproject.segmentrouting.McastHandler.McastRole.INGRESS;
+import static org.onosproject.segmentrouting.McastHandler.McastRole.TRANSIT;
+
+/**
+ * Command to show the list of mcast trees.
+ */
+@Command(scope = "onos", name = "sr-mcast-tree",
+        description = "Lists all mcast trees")
+public class McastTreeListCommand extends AbstractShellCommand {
+
+    // Format for group line
+    private static final String G_FORMAT_MAPPING = "group=%s, ingress=%s, transit=%s, egress=%s";
+    // Format for sink line
+    private static final String S_FORMAT_MAPPING = "\tsink=%s\tpath=%s";
+
+    @Argument(index = 0, name = "mcastIp", description = "mcast Ip",
+            required = false, multiValued = false)
+    String mcastIp;
+
+    @Override
+    protected void execute() {
+        // Verify mcast group
+        IpAddress mcastGroup = null;
+        if (!isNullOrEmpty(mcastIp)) {
+            mcastGroup = IpAddress.valueOf(mcastIp);
+
+        }
+        // Get SR service
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        // Get the mapping
+        Map<McastStoreKey, McastRole> keyToRole = srService.getMcastRoles(mcastGroup);
+        // Reduce to the set of mcast groups
+        Set<IpAddress> mcastGroups = keyToRole.keySet().stream()
+                .map(McastStoreKey::mcastIp)
+                .collect(Collectors.toSet());
+        // Print the trees for each group
+        mcastGroups.forEach(group -> {
+            // Create a new map for the group
+            Multimap<McastRole, DeviceId> roleDeviceIdMap = ArrayListMultimap.create();
+            keyToRole.entrySet()
+                    .stream()
+                    // Filter only the elements related to this group
+                    .filter(entry -> entry.getKey().mcastIp().equals(group))
+                    // For each create a new entry in the group related map
+                    .forEach(entry -> roleDeviceIdMap.put(entry.getValue(), entry.getKey().deviceId()));
+            // Print the map
+            printMcastRole(group,
+                           roleDeviceIdMap.get(INGRESS),
+                           roleDeviceIdMap.get(TRANSIT),
+                           roleDeviceIdMap.get(EGRESS)
+            );
+            // Get sinks paths
+            Map<ConnectPoint, List<ConnectPoint>> mcastPaths = srService.getMcastPaths(group);
+            // Print the paths
+            mcastPaths.forEach(this::printMcastSink);
+        });
+    }
+
+    private void printMcastRole(IpAddress mcastGroup,
+                                Collection<DeviceId> ingress,
+                                Collection<DeviceId> transit,
+                                Collection<DeviceId> egress) {
+        print(G_FORMAT_MAPPING, mcastGroup, ingress, transit, egress);
+    }
+
+    private void printMcastSink(ConnectPoint sink, List<ConnectPoint> path) {
+        print(S_FORMAT_MAPPING, sink, path);
+    }
+}
diff --git a/apps/segmentrouting/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/segmentrouting/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 4e00481..cfd7502 100644
--- a/apps/segmentrouting/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/segmentrouting/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -35,10 +35,10 @@
         <command>
             <action class="org.onosproject.segmentrouting.cli.TunnelRemoveCommand"/>
         </command>
-        -->
         <command>
             <action class="org.onosproject.segmentrouting.cli.RerouteNetworkCommand"/>
         </command>
+        -->
         <command>
             <action class="org.onosproject.segmentrouting.cli.DeviceSubnetListCommand"/>
         </command>
@@ -66,10 +66,29 @@
         <command>
             <action class="org.onosproject.segmentrouting.cli.PseudowireAddCommand"/>
         </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.LinkStateCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.McastNextListCommand"/>
+            <completers>
+                <ref component-id="mcastGroupCompleter"/>
+                <ref component-id="nullCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.segmentrouting.cli.McastTreeListCommand"/>
+            <completers>
+                <ref component-id="mcastGroupCompleter"/>
+                <ref component-id="nullCompleter"/>
+            </completers>
+        </command>
     </command-bundle>
 
+    <bean id="nullCompleter" class="org.apache.karaf.shell.console.completer.NullCompleter"/>
     <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
     <bean id="pseudowireIdCompleter" class="org.onosproject.segmentrouting.cli.PseudowireIdCompleter"/>
+    <bean id="mcastGroupCompleter" class="org.onosproject.cli.net.McastGroupCompleter"/>
 
 </blueprint>
 
diff --git a/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java b/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
index 775e5ee..843ba6b 100644
--- a/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
+++ b/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
@@ -49,12 +49,18 @@
 import java.util.Map;
 import java.util.Set;
 
+import static org.easymock.EasyMock.reset;
 import static org.junit.Assert.*;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
 
 /**
  * Unit test for {@link RouteHandler}.
  */
 public class RouteHandlerTest {
+    private SegmentRoutingManager srManager;
     private RouteHandler routeHandler;
     private HostService hostService;
 
@@ -134,9 +140,9 @@
         mockNetworkConfigRegistry.applyConfig(dev2Config);
 
         // Initialize Segment Routing Manager
-        SegmentRoutingManager srManager = new MockSegmentRoutingManager(NEXT_TABLE);
+        srManager = new MockSegmentRoutingManager(NEXT_TABLE);
         srManager.cfgService = new NetworkConfigRegistryAdapter();
-        srManager.deviceConfiguration = new DeviceConfiguration(srManager);
+        srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
         srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
         srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
         srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE);
@@ -180,6 +186,11 @@
 
     @Test
     public void processRouteAdded() throws Exception {
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.addSubnet(CP1, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
         routeHandler.processRouteAdded(re);
 
@@ -191,17 +202,28 @@
 
         assertEquals(1, SUBNET_TABLE.size());
         assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
     public void processRouteUpdated() throws Exception {
         processRouteAdded();
 
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.removeSubnet(CP1, P1);
+        expectLastCall().once();
+        srManager.deviceConfiguration.addSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
                 Sets.newHashSet(RR1));
         routeHandler.processRouteUpdated(re);
 
-        assertEquals(1, ROUTING_TABLE.size());
+        // Note: We shouldn't remove the old nexthop during the occasion of route update
+        //       since the populate subnet will take care of it and point it to an ECMP group
+        assertEquals(2, ROUTING_TABLE.size());
         MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
         assertEquals(M2, rtv2.macAddress);
         assertEquals(V2, rtv2.vlanId);
@@ -209,21 +231,37 @@
 
         assertEquals(1, SUBNET_TABLE.size());
         assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
     public void processRouteRemoved() throws Exception {
         processRouteAdded();
 
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.removeSubnet(CP1, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
         routeHandler.processRouteRemoved(re);
 
         assertEquals(0, ROUTING_TABLE.size());
         assertEquals(0, SUBNET_TABLE.size());
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
     public void testTwoSingleHomedAdded() throws Exception {
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.addSubnet(CP1, P1);
+        expectLastCall().once();
+        srManager.deviceConfiguration.addSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
         routeHandler.processRouteAdded(re);
 
@@ -240,10 +278,19 @@
         assertEquals(2, SUBNET_TABLE.size());
         assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
         assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
     public void testOneDualHomedAdded() throws Exception {
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.addSubnet(CP1, P1);
+        expectLastCall().once();
+        srManager.deviceConfiguration.addSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
         routeHandler.processRouteAdded(re);
 
@@ -260,12 +307,19 @@
         assertEquals(2, SUBNET_TABLE.size());
         assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
         assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
     public void testOneSingleHomedToTwoSingleHomed() throws Exception {
         processRouteAdded();
 
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.addSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
                 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
         routeHandler.processAlternativeRoutesChanged(re);
@@ -283,17 +337,26 @@
         assertEquals(2, SUBNET_TABLE.size());
         assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
         assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
     public void testTwoSingleHomedToOneSingleHomed() throws Exception {
         testTwoSingleHomedAdded();
 
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.removeSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
                 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
         routeHandler.processAlternativeRoutesChanged(re);
 
-        assertEquals(1, ROUTING_TABLE.size());
+        // Note: We shouldn't remove the old nexthop during the occasion of route update
+        //       since the populate subnet will take care of it and point it to an ECMP group
+        assertEquals(2, ROUTING_TABLE.size());
         MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
         assertEquals(M1, rtv1.macAddress);
         assertEquals(V1, rtv1.vlanId);
@@ -301,8 +364,12 @@
 
         assertEquals(1, SUBNET_TABLE.size());
         assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
+
+        verify(srManager.deviceConfiguration);
     }
 
+    // TODO Add test cases for two single homed next hop at same location
+
     @Test
     public void testDualHomedSingleLocationFail() throws Exception {
         testOneDualHomedAdded();
@@ -332,11 +399,20 @@
 
         hostService = new MockHostService(HOSTS_ONE_FAIL);
 
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.removeSubnet(CP1, P1);
+        expectLastCall().once();
+        srManager.deviceConfiguration.removeSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
         routeHandler.processRouteRemoved(re);
 
         assertEquals(0, ROUTING_TABLE.size());
         assertEquals(0, SUBNET_TABLE.size());
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
@@ -345,21 +421,39 @@
 
         hostService = new MockHostService(HOSTS_BOTH_FAIL);
 
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.removeSubnet(CP1, P1);
+        expectLastCall().once();
+        srManager.deviceConfiguration.removeSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
         routeHandler.processRouteRemoved(re);
 
         assertEquals(0, ROUTING_TABLE.size());
         assertEquals(0, SUBNET_TABLE.size());
+
+        verify(srManager.deviceConfiguration);
     }
 
     @Test
     public void testOneDualHomeRemoved() throws Exception {
         testOneDualHomedAdded();
 
+        reset(srManager.deviceConfiguration);
+        srManager.deviceConfiguration.removeSubnet(CP1, P1);
+        expectLastCall().once();
+        srManager.deviceConfiguration.removeSubnet(CP2, P1);
+        expectLastCall().once();
+        replay(srManager.deviceConfiguration);
+
         RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
         routeHandler.processRouteRemoved(re);
 
         assertEquals(0, ROUTING_TABLE.size());
         assertEquals(0, SUBNET_TABLE.size());
+
+        verify(srManager.deviceConfiguration);
     }
 }
\ No newline at end of file
diff --git a/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricCommand.java b/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricCommand.java
index e5ed60e..b515259 100644
--- a/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricCommand.java
+++ b/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricCommand.java
@@ -26,8 +26,6 @@
          description = "Manages the SimpleFabric application")
 public class SimpleFabricCommand extends AbstractShellCommand {
 
-    protected static SimpleFabricService simpleFabric;
-
     @Argument(index = 0, name = "command",
               description = "Command: show|intents|reactive-intents|refresh|flush",
               required = true, multiValued = false)
@@ -35,9 +33,9 @@
 
     @Override
     protected void execute() {
-        if (simpleFabric == null) {
-            simpleFabric = get(SimpleFabricService.class);
-        }
+
+        SimpleFabricService simpleFabric = get(SimpleFabricService.class);
+
         if (command == null) {
             print("command not found", command);
             return;
diff --git a/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricManager.java b/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricManager.java
index 81dd602..470148b 100644
--- a/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricManager.java
+++ b/apps/simplefabric/src/main/java/org/onosproject/simplefabric/SimpleFabricManager.java
@@ -529,6 +529,8 @@
                         try {
                             refreshMonitor.wait(IDLE_INTERVAL_MSEC);
                         } catch (InterruptedException e) {
+                            log.warn("run thread interrupted", e);
+                            Thread.currentThread().interrupt();
                         }
                     }
                     doRefreshMarked = doRefresh;
diff --git a/apps/t3/src/main/java/org/onosproject/t3/api/GroupsInDevice.java b/apps/t3/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
index 3cfb41a..e63bdca 100644
--- a/apps/t3/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
+++ b/apps/t3/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
@@ -25,7 +25,7 @@
 /**
  * Class to represent the groups in a device for a given output and packet.
  */
-//FIXME consider removing.
+//FIXME consider name change.
 public class GroupsInDevice {
 
     private ConnectPoint output;
@@ -34,8 +34,9 @@
 
     /**
      * Saves the given groups for the output connect point and the selector.
-     * @param output the output connect point
-     * @param groups the groups
+     *
+     * @param output   the output connect point
+     * @param groups   the groups
      * @param selector the selector representing the final packet
      */
     public GroupsInDevice(ConnectPoint output, List<Group> groups, TrafficSelector selector) {
@@ -47,6 +48,7 @@
 
     /**
      * Returns the output connect point.
+     *
      * @return the connect point
      */
     public ConnectPoint getOutput() {
@@ -55,6 +57,7 @@
 
     /**
      * Returns the groups.
+     *
      * @return groups.
      */
     public List<Group> getGroups() {
@@ -63,12 +66,22 @@
 
     /**
      * Returns the final packet after traversing the network.
+     *
      * @return the selector with packet info
      */
     public TrafficSelector getFinalPacket() {
         return selector;
     }
 
+    /**
+     * Updates the final packet.
+     *
+     * @param updatedPacket the updated final packet
+     */
+    public void setFinalPacket(TrafficSelector updatedPacket) {
+        selector = updatedPacket;
+    }
+
     @Override
     public String toString() {
         return "GroupsInDevice{" +
diff --git a/apps/t3/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java b/apps/t3/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java
index c809065..587c748 100644
--- a/apps/t3/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java
+++ b/apps/t3/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.group.GroupBucket;
+import org.onosproject.t3.api.GroupsInDevice;
 import org.onosproject.t3.api.StaticPacketTrace;
 import org.onosproject.t3.api.TroubleshootService;
 
@@ -88,9 +89,18 @@
     @Option(name = "-ml", aliases = "--mplsLabel", description = "Mpls label of incoming packet")
     String mplsLabel = null;
 
-    @Option(name = "-mb", aliases = "--mplsBos", description = "MPLS BOS", valueToShowInHelp = "True")
+    @Option(name = "-mb", aliases = "--mplsBos", description = "MPLS BOS")
     String mplsBos = null;
 
+    @Option(name = "-ipp", aliases = "--ipProto", description = "IP Proto")
+    String ipProto = null;
+
+    @Option(name = "-udps", aliases = "--udpSrc", description = "UDP Source")
+    String udpSrc = null;
+
+    @Option(name = "-udpd", aliases = "--udpDst", description = "UDP Destination")
+    String udpDst = null;
+
     @Override
     protected void execute() {
         TroubleshootService service = get(TroubleshootService.class);
@@ -146,6 +156,19 @@
             selectorBuilder.matchMplsBos(Boolean.valueOf(mplsBos));
         }
 
+        if (ipProto != null) {
+            selectorBuilder.matchIPProtocol(Byte.valueOf(ipProto));
+        }
+
+        if (udpSrc != null) {
+            selectorBuilder.matchUdpSrc(TpPort.tpPort(Integer.parseInt(udpSrc)));
+        }
+
+        if (udpDst != null) {
+            selectorBuilder.matchUdpDst(TpPort.tpPort(Integer.parseInt(udpDst)));
+        }
+
+
         TrafficSelector packet = selectorBuilder.build();
 
         //Printing the created packet
@@ -185,6 +208,7 @@
                 }
                 previous = connectPoint;
             }
+            print("---------------------------------------------------------------\n");
         });
     }
 
@@ -197,33 +221,36 @@
                         f.table(), f.priority(), f.selector().criteria(),
                         printTreatment(f.treatment()));
             } else {
-                print("   flowId=%s, selector=%s ", f.id(), f.selector().criteria());
+                print("   flowId=%s, table=%s, selector=%s", f.id(), f.table(), f.selector().criteria());
             }
         });
     }
 
     //Prints the groups for a given trace and a specified level of verbosity
     private void printGroups(StaticPacketTrace trace, boolean verbose, ConnectPoint connectPoint) {
-        print("Groups");
-        trace.getGroupOuputs(connectPoint.deviceId()).forEach(output -> {
-            if (output.getOutput().equals(connectPoint)) {
-                output.getGroups().forEach(group -> {
-                    if (verbose) {
-                        print(GROUP_FORMAT, Integer.toHexString(group.id().id()), group.state(), group.type(),
-                                group.bytes(), group.packets(), group.appId().name(), group.referenceCount());
-                        int i = 0;
-                        for (GroupBucket bucket : group.buckets().buckets()) {
-                            print(GROUP_BUCKET_FORMAT, Integer.toHexString(group.id().id()), ++i,
-                                    bucket.bytes(), bucket.packets(),
-                                    bucket.treatment().allInstructions());
+        List<GroupsInDevice> groupsInDevice = trace.getGroupOuputs(connectPoint.deviceId());
+        if (groupsInDevice != null) {
+            print("Groups");
+            groupsInDevice.forEach(output -> {
+                if (output.getOutput().equals(connectPoint)) {
+                    output.getGroups().forEach(group -> {
+                        if (verbose) {
+                            print(GROUP_FORMAT, Integer.toHexString(group.id().id()), group.state(), group.type(),
+                                    group.bytes(), group.packets(), group.appId().name(), group.referenceCount());
+                            int i = 0;
+                            for (GroupBucket bucket : group.buckets().buckets()) {
+                                print(GROUP_BUCKET_FORMAT, Integer.toHexString(group.id().id()), ++i,
+                                        bucket.bytes(), bucket.packets(),
+                                        bucket.treatment().allInstructions());
+                            }
+                        } else {
+                            print("   groupId=%s", group.id());
                         }
-                    } else {
-                        print("   groupId=%s", group.id());
-                    }
-                });
-                print("Outgoing Packet %s", output.getFinalPacket());
-            }
-        });
+                    });
+                    print("Outgoing Packet %s", output.getFinalPacket());
+                }
+            });
+        }
     }
 
     private String printTreatment(TrafficTreatment treatment) {
diff --git a/apps/t3/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java b/apps/t3/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
index 1481c30..bbec3ea 100644
--- a/apps/t3/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
+++ b/apps/t3/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
@@ -24,6 +24,8 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.VlanId;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
@@ -43,6 +45,7 @@
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.EthTypeCriterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
@@ -59,6 +62,7 @@
 
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
@@ -67,7 +71,12 @@
 import java.util.stream.Collectors;
 
 import static org.onlab.packet.EthType.EtherType;
+import static org.onosproject.net.flow.TrafficSelector.Builder;
 import static org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsHeaderInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -99,6 +108,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceService deviceService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MastershipService mastershipService;
+
     @Override
     public StaticPacketTrace trace(TrafficSelector packet, ConnectPoint in) {
         log.info("Tracing packet {} coming in through {}", packet, in);
@@ -125,6 +137,8 @@
      */
     private StaticPacketTrace getTrace(List<ConnectPoint> completePath, ConnectPoint in, StaticPacketTrace trace) {
 
+        log.debug("------------------------------------------------------------");
+
         //if the trace already contains the input connect point there is a loop
         if (pathContainsDevice(completePath, in.deviceId())) {
             trace.addResultMessage("Loop encountered in device " + in.deviceId());
@@ -143,39 +157,65 @@
 
         //If the trace has ouputs we analyze them all
         for (GroupsInDevice outputPath : trace.getGroupOuputs(in.deviceId())) {
-            log.debug("Output path {}", outputPath.getOutput());
+
+            ConnectPoint cp = outputPath.getOutput();
+            log.debug("Connect point in {}", in);
+            log.debug("Output path {}", cp);
+
             //Hosts for the the given output
-            Set<Host> hostsList = hostService.getConnectedHosts(outputPath.getOutput());
+            Set<Host> hostsList = hostService.getConnectedHosts(cp);
             //Hosts queried from the original ip or mac
             Set<Host> hosts = getHosts(trace);
 
             //If the two host collections contain the same item it means we reached the proper output
             if (!Collections.disjoint(hostsList, hosts)) {
-                log.debug("Stopping here because host is expected destination");
-                trace.addResultMessage("Reached required destination Host");
+                log.debug("Stopping here because host is expected destination {}, reached through", completePath);
+                trace.addResultMessage("Reached required destination Host " + cp);
                 computePath(completePath, trace, outputPath.getOutput());
                 break;
-            } else {
-                ConnectPoint cp = outputPath.getOutput();
+            } else if (cp.port().equals(PortNumber.CONTROLLER)) {
+
+                //Getting the master when the packet gets sent as packet in
+                NodeId master = mastershipService.getMasterFor(cp.deviceId());
+                trace.addResultMessage("Packet goes to the controller " + master.id());
+                computePath(completePath, trace, outputPath.getOutput());
+                handleVlanToController(outputPath, trace);
+
+            } else if (linkService.getEgressLinks(cp).size() > 0) {
+
+                //TODO this can be optimized if we use a Tree structure for paths.
+                //if we already have outputs let's check if the one we are considering starts from one of the devices
+                // in any of the ones we have.
+                if (trace.getCompletePaths().size() > 0) {
+                    ConnectPoint inputForOutput = null;
+                    List<ConnectPoint> previousPath = new ArrayList<>();
+                    for (List<ConnectPoint> path : trace.getCompletePaths()) {
+                        for (ConnectPoint connect : path) {
+                            //if the path already contains the input for the output we've found we use it
+                            if (connect.equals(in)) {
+                                inputForOutput = connect;
+                                previousPath = path;
+                                break;
+                            }
+                        }
+                    }
+                    //we use the pre-existing path up to the point we fork to a new output
+                    if (inputForOutput != null && completePath.contains(inputForOutput)) {
+                        List<ConnectPoint> temp = new ArrayList<>(previousPath);
+                        completePath = temp.subList(0, previousPath.indexOf(inputForOutput) + 1);
+                    }
+                }
+
                 //let's add the ouput for the input
                 completePath.add(cp);
-                log.debug("------------------------------------------------------------");
-                log.debug("Connect Point out {}", cp);
                 //let's compute the links for the given output
                 Set<Link> links = linkService.getEgressLinks(cp);
                 log.debug("Egress Links {}", links);
-                //No links means that the packet gets dropped.
-                if (links.size() == 0) {
-                    log.warn("No links out of {}", cp);
-                    computePath(completePath, trace, cp);
-                    trace.addResultMessage("No links depart from " + cp + ". Packet is dropped");
-                    return trace;
-                }
                 //For each link we trace the corresponding device
                 for (Link link : links) {
                     ConnectPoint dst = link.dst();
                     //change in-port to the dst link in port
-                    TrafficSelector.Builder updatedPacket = DefaultTrafficSelector.builder();
+                    Builder updatedPacket = DefaultTrafficSelector.builder();
                     outputPath.getFinalPacket().criteria().forEach(updatedPacket::add);
                     updatedPacket.add(Criteria.matchInPort(dst.port()));
                     log.debug("DST Connect Point {}", dst);
@@ -185,12 +225,55 @@
                     getTrace(completePath, dst, trace);
                 }
 
+            } else if (deviceService.getPort(cp).isEnabled()) {
+                if (hostsList.isEmpty()) {
+                    trace.addResultMessage("Packet is " + ((EthTypeCriterion) outputPath.getFinalPacket()
+                            .getCriterion(Criterion.Type.ETH_TYPE)).ethType() + " and reached " +
+                            cp + " with no hosts connected ");
+                } else {
+                    trace.addResultMessage("Packet is " + ((EthTypeCriterion) outputPath.getFinalPacket()
+                            .getCriterion(Criterion.Type.ETH_TYPE)).ethType() + " and reached " +
+                            cp + " with hosts " + hostsList);
+                }
+                computePath(completePath, trace, outputPath.getOutput());
+
+            } else {
+                //No links means that the packet gets dropped.
+                log.warn("No links out of {}", cp);
+                computePath(completePath, trace, cp);
+                trace.addResultMessage("No links depart from " + cp + ". Packet is dropped");
             }
         }
         return trace;
     }
 
     /**
+     * If the initial packet comes tagged with a Vlan we output it with that to ONOS.
+     * If ONOS applied a vlan we remove it.
+     *
+     * @param outputPath the output
+     * @param trace      the trace we are building
+     */
+    private void handleVlanToController(GroupsInDevice outputPath, StaticPacketTrace trace) {
+
+        VlanIdCriterion initialVid = (VlanIdCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.VLAN_VID);
+        VlanIdCriterion finalVid = (VlanIdCriterion) outputPath.getFinalPacket().getCriterion(Criterion.Type.VLAN_VID);
+
+        if (initialVid != null && !initialVid.equals(finalVid) && initialVid.vlanId().equals(VlanId.NONE)) {
+
+            Set<Criterion> finalCriteria = new HashSet<>(outputPath.getFinalPacket().criteria());
+            //removing the final vlanId
+            finalCriteria.remove(finalVid);
+            Builder packetUpdated = DefaultTrafficSelector.builder();
+            finalCriteria.forEach(packetUpdated::add);
+            //Initial was none so we set it to that
+            packetUpdated.add(Criteria.matchVlanId(VlanId.NONE));
+            //Update final packet
+            outputPath.setFinalPacket(packetUpdated.build());
+        }
+    }
+
+    /**
      * Checks if the path contains the device.
      *
      * @param completePath the path
@@ -250,7 +333,6 @@
             traverseList.add(output);
         }
         trace.addCompletePath(traverseList);
-        completePath.clear();
     }
 
     /**
@@ -262,6 +344,12 @@
      * @return updated trace
      */
     private StaticPacketTrace traceInDevice(StaticPacketTrace trace, TrafficSelector packet, ConnectPoint in) {
+
+        //we already traversed this device.
+        if (trace.getGroupOuputs(in.deviceId()) != null) {
+            log.debug("Trace already contains device and given outputs");
+            return trace;
+        }
         log.debug("Packet {} coming in from {}", packet, in);
 
         //if device is not available exit here.
@@ -273,6 +361,8 @@
         List<FlowEntry> flows = new ArrayList<>();
         List<FlowEntry> outputFlows = new ArrayList<>();
 
+        List<Instruction> deferredInstructions = new ArrayList<>();
+
         FlowEntry nextTableIdEntry = findNextTableIdEntry(in.deviceId(), -1);
         if (nextTableIdEntry == null) {
             trace.addResultMessage("No flow rules for device " + in.deviceId() + ". Aborting");
@@ -294,7 +384,6 @@
             if (flowEntry == null && isOfdpaHardware) {
                 log.debug("Ofdpa Hw setup, no flow rule means table miss");
 
-                //Handling Hardware Specifics
                 if (((IndexTableId) tableId).id() == 27) {
                     //Apparently a miss but Table 27 on OFDPA is a fixed table
                     packet = handleOfdpa27FixedTable(trace, packet);
@@ -307,7 +396,7 @@
                 //FIXME find better solution that enable granularity greater than 0 or all rules
                 //(another possibility is max tableId)
                 if (nextTableIdEntry == null && flows.size() == 0) {
-                    trace.addResultMessage("No flow rules for device" + in.deviceId() + ". Aborting");
+                    trace.addResultMessage("No matching flow rules for device " + in.deviceId() + ". Aborting");
                     return trace;
 
                 } else if (nextTableIdEntry == null) {
@@ -323,12 +412,12 @@
                     tableId = nextTableIdEntry.table();
                 }
 
-
             } else if (flowEntry == null) {
                 trace.addResultMessage("Packet has no match on table " + tableId + " in device " +
                         in.deviceId() + ". Dropping");
                 return trace;
             } else {
+
                 //IF the table has a transition
                 if (flowEntry.treatment().tableTransition() != null) {
                     //update the next table we transitions to
@@ -342,86 +431,151 @@
                     outputFlows.add(flowEntry);
                     output = true;
                 }
-                //update the packet according to the actions of this flow rule.
-                packet = updatePacket(packet, flowEntry.treatment().allInstructions()).build();
+                //update the packet according to the immediate actions of this flow rule.
+                packet = updatePacket(packet, flowEntry.treatment().immediate()).build();
+
+                //save the deferred rules for later
+                deferredInstructions.addAll(flowEntry.treatment().deferred());
+
+                //If the flow requires to clear deferred actions we do so for all the ones we encountered.
+                if (flowEntry.treatment().clearedDeferred()) {
+                    deferredInstructions.clear();
+                }
+
+                //On table 10 OFDPA needs two rules to apply the vlan if none and then to transition to the next table.
+                if (needsSecondTable10Flow(flowEntry, isOfdpaHardware)) {
+
+                    //Let's get the packet vlanId instruction
+                    VlanIdCriterion packetVlanIdCriterion =
+                            (VlanIdCriterion) packet.getCriterion(Criterion.Type.VLAN_VID);
+
+                    //Let's get the flow entry vlan mod instructions
+                    ModVlanIdInstruction entryModVlanIdInstruction = (ModVlanIdInstruction) flowEntry.treatment()
+                            .immediate().stream()
+                            .filter(instruction -> instruction instanceof ModVlanIdInstruction)
+                            .findFirst().orElse(null);
+
+                    //If the entry modVlan is not null we need to make sure that the packet has been updated and there
+                    // is a flow rule that matches on same criteria and with updated vlanId
+                    if (entryModVlanIdInstruction != null) {
+
+                        FlowEntry secondVlanFlow = getSecondFlowEntryOnTable10(packet, in,
+                                packetVlanIdCriterion, entryModVlanIdInstruction);
+
+                        //We found the flow that we expected
+                        if (secondVlanFlow != null) {
+                            flows.add(secondVlanFlow);
+                        } else {
+                            trace.addResultMessage("Missing forwarding rule for tagged packet on " + in);
+                            return trace;
+                        }
+                    }
+
+                }
+
             }
         }
 
         //Creating a modifiable builder for the output packet
-        TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
+        Builder builder = DefaultTrafficSelector.builder();
         packet.criteria().forEach(builder::add);
+
         //Adding all the flows to the trace
-        trace.addFlowsForDevice(in.deviceId(), flows);
+        trace.addFlowsForDevice(in.deviceId(), ImmutableList.copyOf(flows));
 
-        log.debug("Flows traversed by {}", packet);
-        flows.forEach(entry -> {
-            log.debug("Flow {}", entry);
-        });
-
-        log.debug("Output Flows for {}", packet);
-        outputFlows.forEach(entry -> {
-            log.debug("Output Flow {}", entry);
-        });
         List<PortNumber> outputPorts = new ArrayList<>();
 
-        //Decide Output for packet when flow rule contains an OUTPUT instruction
-        Set<Instruction> outputFlowEntries = outputFlows.stream().flatMap(flow -> {
-            return flow.treatment().allInstructions().stream();
-        })
-                .filter(instruction -> {
-                    return instruction.type().equals(Instruction.Type.OUTPUT);
-                }).collect(Collectors.toSet());
-        log.debug("Output instructions {}", outputFlowEntries);
+        //TODO optimization
+        //outputFlows contains also last rule of device, so we need filtering for OUTPUT instructions.
+        List<FlowEntry> outputFlowEntries = outputFlows.stream().filter(flow -> flow.treatment()
+                .allInstructions().stream().filter(instruction -> instruction.type()
+                        .equals(Instruction.Type.OUTPUT)).count() > 0).collect(Collectors.toList());
 
-        if (outputFlowEntries.size() != 0) {
-            outputThroughFlows(trace, packet, in, builder, outputPorts, outputFlowEntries);
-
-        } else {
-            log.debug("Handling Groups");
-            //Analyze Groups
-            List<Group> groups = new ArrayList<>();
-
-            for (FlowEntry entry : flows) {
-                getGroupsFromInstructions(trace, groups, entry.treatment().allInstructions(),
-                        entry.deviceId(), builder, outputPorts, in);
-            }
-            packet = builder.build();
-            log.debug("Groups hit by packet {}", packet);
-            groups.forEach(group -> {
-                log.debug("Group {}", group);
-            });
+        if (outputFlowEntries.size() > 1) {
+            trace.addResultMessage("More than one flow rule with OUTPUT instruction");
+            log.warn("There cannot be more than one flow entry with OUTPUT instruction for {}", packet);
         }
-        log.debug("Output ports for packet {}", packet);
-        outputPorts.forEach(port -> {
-            log.debug("Port {}", port);
-        });
+
+        if (outputFlowEntries.size() == 1) {
+
+            OutputInstruction outputInstruction = (OutputInstruction) outputFlowEntries.get(0).treatment()
+                    .allInstructions().stream()
+                    .filter(instruction -> {
+                        return instruction.type().equals(Instruction.Type.OUTPUT);
+                    }).findFirst().get();
+
+            //FIXME using GroupsInDevice for output even if flows.
+            buildOutputFromDevice(trace, in, builder, outputPorts, outputInstruction, ImmutableList.of());
+
+        }
+        log.debug("Handling Groups");
+        //Analyze Groups
+        List<Group> groups = new ArrayList<>();
+
+        Collection<FlowEntry> nonOutputFlows = flows;
+        nonOutputFlows.removeAll(outputFlowEntries);
+
+        //Handling groups pointed at by immediate instructions
+        for (FlowEntry entry : flows) {
+            getGroupsFromInstructions(trace, groups, entry.treatment().immediate(),
+                    entry.deviceId(), builder, outputPorts, in);
+        }
+
+        //If we have deferred instructions at this point we handle them.
+        if (deferredInstructions.size() > 0) {
+            builder = handleDeferredActions(trace, packet, in, deferredInstructions, outputPorts, groups);
+
+        }
+        packet = builder.build();
+
         log.debug("Output Packet {}", packet);
         return trace;
     }
 
-    /**
-     * Method that saves the output if that si done via an OUTPUT treatment of a flow rule.
-     *
-     * @param trace             the trace
-     * @param packet            the packet coming in to this device
-     * @param in                the input connect point for this device
-     * @param builder           the updated packet0
-     * @param outputPorts       the list of output ports for this device
-     * @param outputFlowEntries the list of flow entries with OUTPUT treatment
-     */
-    private void outputThroughFlows(StaticPacketTrace trace, TrafficSelector packet, ConnectPoint in,
-                                    TrafficSelector.Builder builder, List<PortNumber> outputPorts,
-                                    Set<Instruction> outputFlowEntries) {
-        if (outputFlowEntries.size() > 1) {
-            log.warn("There cannot be more than one flow entry with OUTPUT instruction for {}", packet);
-        } else {
-            OutputInstruction outputInstruction = (OutputInstruction) outputFlowEntries.iterator().next();
-            //FIXME using GroupsInDevice for output even if flows.
-            buildOutputFromDevice(trace, in, builder, outputPorts, outputInstruction, ImmutableList.of());
-        }
+    private boolean needsSecondTable10Flow(FlowEntry flowEntry, boolean isOfdpaHardware) {
+        return isOfdpaHardware && flowEntry.table().equals(IndexTableId.of(10))
+                && flowEntry.selector().getCriterion(Criterion.Type.VLAN_VID) != null
+                && ((VlanIdCriterion) flowEntry.selector().getCriterion(Criterion.Type.VLAN_VID))
+                .vlanId().equals(VlanId.NONE);
     }
 
     /**
+     * Method that finds a flow rule on table 10 that matches the packet and the VLAN of the already
+     * found rule on table 10. This is because OFDPA needs two rules on table 10, first to apply the rule,
+     * second to transition to following table
+     *
+     * @param packet                    the incoming packet
+     * @param in                        the input connect point
+     * @param packetVlanIdCriterion     the vlan criterion from the packet
+     * @param entryModVlanIdInstruction the entry vlan instruction
+     * @return the second flow entry that matched
+     */
+    private FlowEntry getSecondFlowEntryOnTable10(TrafficSelector packet, ConnectPoint in,
+                                                  VlanIdCriterion packetVlanIdCriterion,
+                                                  ModVlanIdInstruction entryModVlanIdInstruction) {
+        FlowEntry secondVlanFlow = null;
+        //Check the packet has been update from the first rule.
+        if (packetVlanIdCriterion.vlanId().equals(entryModVlanIdInstruction.vlanId())) {
+            //find a rule on the same table that matches the vlan and
+            // also all the other elements of the flow such as input port
+            secondVlanFlow = Lists.newArrayList(flowRuleService.getFlowEntries(in.deviceId()).iterator())
+                    .stream()
+                    .filter(entry -> {
+                        return entry.table().equals(IndexTableId.of(10));
+                    })
+                    .filter(entry -> {
+                        VlanIdCriterion criterion = (VlanIdCriterion) entry.selector()
+                                .getCriterion(Criterion.Type.VLAN_VID);
+                        return criterion != null && match(packet, entry)
+                                && criterion.vlanId().equals(entryModVlanIdInstruction.vlanId());
+                    }).findFirst().orElse(null);
+
+        }
+        return secondVlanFlow;
+    }
+
+
+    /**
      * Handles table 27 in Ofpda which is a fixed table not visible to any controller that handles Mpls Labels.
      *
      * @param packet the incoming packet
@@ -461,6 +615,36 @@
                 .stream().filter(f -> ((IndexTableId) f.table()).id() > currentId).min(comparator).orElse(null);
     }
 
+    private Builder handleDeferredActions(StaticPacketTrace trace, TrafficSelector packet,
+                                          ConnectPoint in, List<Instruction> deferredInstructions,
+                                          List<PortNumber> outputPorts, List<Group> groups) {
+
+        //Update the packet with the deferred instructions
+        Builder builder = updatePacket(packet, deferredInstructions);
+
+        //Gather any output instructions from the deferred instruction
+        List<Instruction> outputFlowInstruction = deferredInstructions.stream().filter(instruction -> {
+            return instruction.type().equals(Instruction.Type.OUTPUT);
+        }).collect(Collectors.toList());
+
+        //We are considering deferred instructions from flows, there can only be one output.
+        if (outputFlowInstruction.size() > 1) {
+            trace.addResultMessage("More than one flow rule with OUTPUT instruction");
+            log.warn("There cannot be more than one flow entry with OUTPUT instruction for {}", packet);
+        }
+        //If there is one output let's go through that
+        if (outputFlowInstruction.size() == 1) {
+            buildOutputFromDevice(trace, in, builder, outputPorts, (OutputInstruction) outputFlowInstruction.get(0),
+                    ImmutableList.of());
+        }
+        //If there is no output let's see if there any deferred instruction point to groups.
+        if (outputFlowInstruction.size() == 0) {
+            getGroupsFromInstructions(trace, groups, deferredInstructions,
+                    in.deviceId(), builder, outputPorts, in);
+        }
+        return builder;
+    }
+
     /**
      * Gets group information from instructions.
      *
@@ -473,7 +657,7 @@
      */
     private void getGroupsFromInstructions(StaticPacketTrace trace, List<Group> groupsForDevice,
                                            List<Instruction> instructions, DeviceId deviceId,
-                                           TrafficSelector.Builder builder, List<PortNumber> outputPorts,
+                                           Builder builder, List<PortNumber> outputPorts,
                                            ConnectPoint in) {
         List<Instruction> groupInstructionlist = new ArrayList<>();
         for (Instruction instruction : instructions) {
@@ -523,13 +707,12 @@
      * @param builder           the packet builder
      * @param outputPorts       the list of output ports for this device
      * @param outputInstruction the output instruction
-     * @param groupsForDevice
+     * @param groupsForDevice   the groups we output from
      */
-    private void buildOutputFromDevice(StaticPacketTrace trace, ConnectPoint in, TrafficSelector.Builder builder,
+    private void buildOutputFromDevice(StaticPacketTrace trace, ConnectPoint in, Builder builder,
                                        List<PortNumber> outputPorts, OutputInstruction outputInstruction,
                                        List<Group> groupsForDevice) {
-        ConnectPoint output = ConnectPoint.deviceConnectPoint(in.deviceId() + "/" +
-                outputInstruction.port());
+        ConnectPoint output = new ConnectPoint(in.deviceId(), outputInstruction.port());
         if (output.equals(in)) {
             trace.addResultMessage("Connect point out " + output + " is same as initial input " +
                     trace.getInitialConnectPoint());
@@ -547,8 +730,8 @@
      * @param instructions the set of instructions
      * @return the packet with the applied instructions
      */
-    private TrafficSelector.Builder updatePacket(TrafficSelector packet, List<Instruction> instructions) {
-        TrafficSelector.Builder newSelector = DefaultTrafficSelector.builder();
+    private Builder updatePacket(TrafficSelector packet, List<Instruction> instructions) {
+        Builder newSelector = DefaultTrafficSelector.builder();
         packet.criteria().forEach(newSelector::add);
         //FIXME optimize
         for (Instruction instruction : instructions) {
@@ -564,7 +747,7 @@
      * @param instruction the instruction to be translated
      * @return the new selector with the applied instruction
      */
-    private TrafficSelector.Builder translateInstruction(TrafficSelector.Builder newSelector, Instruction instruction) {
+    private Builder translateInstruction(Builder newSelector, Instruction instruction) {
         log.debug("Translating instruction {}", instruction);
         log.debug("New Selector {}", newSelector.build());
         //TODO add as required
@@ -574,8 +757,8 @@
                 L2ModificationInstruction l2Instruction = (L2ModificationInstruction) instruction;
                 switch (l2Instruction.subtype()) {
                     case VLAN_ID:
-                        L2ModificationInstruction.ModVlanIdInstruction vlanIdInstruction =
-                                (L2ModificationInstruction.ModVlanIdInstruction) instruction;
+                        ModVlanIdInstruction vlanIdInstruction =
+                                (ModVlanIdInstruction) instruction;
                         VlanId id = vlanIdInstruction.vlanId();
                         criterion = Criteria.matchVlanId(id);
                         break;
@@ -583,19 +766,19 @@
                         criterion = Criteria.matchVlanId(VlanId.NONE);
                         break;
                     case MPLS_PUSH:
-                        L2ModificationInstruction.ModMplsHeaderInstruction mplsEthInstruction =
-                                (L2ModificationInstruction.ModMplsHeaderInstruction) instruction;
+                        ModMplsHeaderInstruction mplsEthInstruction =
+                                (ModMplsHeaderInstruction) instruction;
                         criterion = Criteria.matchEthType(mplsEthInstruction.ethernetType().toShort());
                         break;
                     case MPLS_POP:
-                        L2ModificationInstruction.ModMplsHeaderInstruction mplsPopInstruction =
-                                (L2ModificationInstruction.ModMplsHeaderInstruction) instruction;
+                        ModMplsHeaderInstruction mplsPopInstruction =
+                                (ModMplsHeaderInstruction) instruction;
                         criterion = Criteria.matchEthType(mplsPopInstruction.ethernetType().toShort());
 
                         //When popping MPLS we remove label and BOS
                         TrafficSelector temporaryPacket = newSelector.build();
                         if (temporaryPacket.getCriterion(Criterion.Type.MPLS_LABEL) != null) {
-                            TrafficSelector.Builder noMplsSelector = DefaultTrafficSelector.builder();
+                            Builder noMplsSelector = DefaultTrafficSelector.builder();
                             temporaryPacket.criteria().stream().filter(c -> {
                                 return !c.type().equals(Criterion.Type.MPLS_LABEL) &&
                                         !c.type().equals(Criterion.Type.MPLS_BOS);
@@ -605,19 +788,19 @@
 
                         break;
                     case MPLS_LABEL:
-                        L2ModificationInstruction.ModMplsLabelInstruction mplsLabelInstruction =
-                                (L2ModificationInstruction.ModMplsLabelInstruction) instruction;
+                        ModMplsLabelInstruction mplsLabelInstruction =
+                                (ModMplsLabelInstruction) instruction;
                         criterion = Criteria.matchMplsLabel(mplsLabelInstruction.label());
                         newSelector.matchMplsBos(true);
                         break;
                     case ETH_DST:
-                        L2ModificationInstruction.ModEtherInstruction modEtherDstInstruction =
-                                (L2ModificationInstruction.ModEtherInstruction) instruction;
+                        ModEtherInstruction modEtherDstInstruction =
+                                (ModEtherInstruction) instruction;
                         criterion = Criteria.matchEthDst(modEtherDstInstruction.mac());
                         break;
                     case ETH_SRC:
-                        L2ModificationInstruction.ModEtherInstruction modEtherSrcInstruction =
-                                (L2ModificationInstruction.ModEtherInstruction) instruction;
+                        ModEtherInstruction modEtherSrcInstruction =
+                                (ModEtherInstruction) instruction;
                         criterion = Criteria.matchEthSrc(modEtherSrcInstruction.mac());
                         break;
                     default:
diff --git a/apps/t3/src/test/java/org/onosproject/t3/impl/T3TestObjects.java b/apps/t3/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
index 15cee5f..abbe77e 100644
--- a/apps/t3/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
+++ b/apps/t3/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
@@ -51,7 +51,7 @@
  */
 final class T3TestObjects {
 
-    private T3TestObjects(){
+    private T3TestObjects() {
         //banning construction
     }
 
@@ -106,6 +106,28 @@
 
     static final ConnectPoint SAME_OUTPUT_FLOW_CP = ConnectPoint.deviceConnectPoint(SAME_OUTPUT_FLOW_DEVICE + "/" + 1);
 
+    //ARP
+    static final DeviceId ARP_FLOW_DEVICE = DeviceId.deviceId("ArpDevice");
+
+    private static final TrafficSelector ARP_FLOW_SELECTOR = DefaultTrafficSelector.builder()
+            .matchInPort(PortNumber.portNumber(1))
+            .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+            .build();
+
+    private static final TrafficTreatment ARP_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
+            .setOutput(PortNumber.CONTROLLER).build();
+    private static final FlowRule ARP_FLOW = DefaultFlowEntry.builder().forDevice(ARP_FLOW_DEVICE)
+            .forTable(0)
+            .withPriority(100)
+            .withSelector(ARP_FLOW_SELECTOR)
+            .withTreatment(ARP_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+    static final FlowEntry ARP_FLOW_ENTRY = new DefaultFlowEntry(ARP_FLOW);
+
+    static final ConnectPoint ARP_FLOW_CP = ConnectPoint.deviceConnectPoint(ARP_FLOW_DEVICE + "/" + 1);
+
 
     //Dual Flow Test
     static final DeviceId DUAL_FLOW_DEVICE = DeviceId.deviceId("DualFlowDevice");
@@ -322,11 +344,205 @@
 
     static final FlowEntry HARDWARE_ETH_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_ETH_FLOW);
 
+    //HW Double Rule on 10
 
+    static final DeviceId HARDWARE_DEVICE_10 = DeviceId.deviceId("HardwareDevice10");
 
+    static final ConnectPoint HARDWARE_DEVICE_10_IN_CP = ConnectPoint.deviceConnectPoint(HARDWARE_DEVICE_10 + "/" + 1);
+
+    static final ConnectPoint HARDWARE_DEVICE_10_OUT_CP = ConnectPoint.deviceConnectPoint(HARDWARE_DEVICE_10 + "/" + 2);
+
+    private static final TrafficSelector HARDWARE_10_FLOW_SELECTOR = DefaultTrafficSelector.builder()
+            .matchInPort(PortNumber.portNumber(1))
+            .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
+            .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
+            .matchVlanId(VlanId.NONE)
+            .build();
+
+    private static final TrafficTreatment HARDWARE_10_TRANSITION_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
+            .setVlanId(VlanId.vlanId("10"))
+            .transition(20)
+            .build();
+
+    private static final FlowRule HARDWARE_DEVICE_10_FLOW = DefaultFlowEntry.builder().forDevice(HARDWARE_DEVICE_10)
+            .forTable(10)
+            .withPriority(100)
+            .withSelector(HARDWARE_10_FLOW_SELECTOR)
+            .withTreatment(HARDWARE_10_TRANSITION_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+
+    static final FlowEntry HARDWARE_10_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_DEVICE_10_FLOW);
+
+    private static final TrafficSelector HARDWARE_10_SECOND_SELECTOR = DefaultTrafficSelector.builder()
+            .matchInPort(PortNumber.portNumber(1))
+            .matchVlanId(VlanId.vlanId("10"))
+            .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
+            .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
+            .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
+            .build();
+
+    private static final FlowRule HARDWARE_10_SECOND_FLOW = DefaultFlowEntry.builder().forDevice(HARDWARE_DEVICE_10)
+            .forTable(10)
+            .withPriority(100)
+            .withSelector(HARDWARE_10_SECOND_SELECTOR)
+            .withTreatment(HARDWARE_10_TRANSITION_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+
+    static final FlowEntry HARDWARE_10_SECOND_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_10_SECOND_FLOW);
+
+    private static final FlowRule HARDWARE_10_OUTPUT_FLOW = DefaultFlowEntry.builder().forDevice(HARDWARE_DEVICE_10)
+            .forTable(20)
+            .withPriority(100)
+            .withSelector(SINGLE_FLOW_SELECTOR)
+            .withTreatment(OUTPUT_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+
+    static final FlowEntry HARDWARE_10_OUTPUT_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_10_OUTPUT_FLOW);
+
+    //Dual Links
+    // - (1) Device 1 (2-3) - (1-4) Device 2 (2-3) - (1-2) Device 3 (3) -
+    static final DeviceId DUAL_LINK_1 = DeviceId.deviceId("DualLink1");
+    static final DeviceId DUAL_LINK_2 = DeviceId.deviceId("DualLink2");
+    static final DeviceId DUAL_LINK_3 = DeviceId.deviceId("DualLink3");
+
+    static final ConnectPoint DUAL_LINK_1_CP_1_IN = ConnectPoint.deviceConnectPoint(DUAL_LINK_1 + "/" + 1);
+    static final ConnectPoint DUAL_LINK_1_CP_2_OUT = ConnectPoint.deviceConnectPoint(DUAL_LINK_1 + "/" + 2);
+    static final ConnectPoint DUAL_LINK_1_CP_3_OUT = ConnectPoint.deviceConnectPoint(DUAL_LINK_1 + "/" + 3);
+    static final ConnectPoint DUAL_LINK_2_CP_1_IN = ConnectPoint.deviceConnectPoint(DUAL_LINK_2 + "/" + 1);
+    static final ConnectPoint DUAL_LINK_2_CP_4_IN = ConnectPoint.deviceConnectPoint(DUAL_LINK_2 + "/" + 4);
+    static final ConnectPoint DUAL_LINK_2_CP_2_OUT = ConnectPoint.deviceConnectPoint(DUAL_LINK_2 + "/" + 2);
+    static final ConnectPoint DUAL_LINK_2_CP_3_OUT = ConnectPoint.deviceConnectPoint(DUAL_LINK_2 + "/" + 3);
+    static final ConnectPoint DUAL_LINK_3_CP_1_IN = ConnectPoint.deviceConnectPoint(DUAL_LINK_3 + "/" + 1);
+    static final ConnectPoint DUAL_LINK_3_CP_2_IN = ConnectPoint.deviceConnectPoint(DUAL_LINK_3 + "/" + 2);
+    static final ConnectPoint DUAL_LINK_3_CP_3_OUT = ConnectPoint.deviceConnectPoint(DUAL_LINK_3 + "/" + 3);
+
+    //match on port 1 and point to group for device 1 and 2
+    private static final TrafficTreatment DUAL_LINK_1_GROUP_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
+            .pushMpls()
+            .setMpls(MplsLabel.mplsLabel(100))
+            .group(GROUP_ID)
+            .build();
+    private static final FlowRule DUAL_LINK_1_GROUP_FLOW = DefaultFlowEntry.builder().forDevice(DUAL_LINK_1)
+            .forTable(0)
+            .withPriority(100)
+            .withSelector(SINGLE_FLOW_SELECTOR)
+            .withTreatment(DUAL_LINK_1_GROUP_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+    static final FlowEntry DUAL_LINK_1_GROUP_FLOW_ENTRY = new DefaultFlowEntry(DUAL_LINK_1_GROUP_FLOW);
+
+    //Match on port 4 and point to group for device 2
+    private static final TrafficSelector DUAL_LINK_2_FLOW_SELECTOR = DefaultTrafficSelector.builder()
+            .matchInPort(PortNumber.portNumber(4))
+            .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
+            .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
+            .build();
+
+    private static final FlowRule DUAL_LINK_2_GROUP_FLOW = DefaultFlowEntry.builder().forDevice(DUAL_LINK_2)
+            .forTable(0)
+            .withPriority(100)
+            .withSelector(DUAL_LINK_2_FLOW_SELECTOR)
+            .withTreatment(DUAL_LINK_1_GROUP_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+    static final FlowEntry DUAL_LINK_2_GROUP_FLOW_ENTRY = new DefaultFlowEntry(DUAL_LINK_2_GROUP_FLOW);
+
+    //Flows for device 3 to ouput on port 3
+    private static final TrafficTreatment DUAL_LINK_1_OUTPUT_TREATMENT = DefaultTrafficTreatment.builder()
+            .popMpls(EthType.EtherType.IPV4.ethType())
+            .setOutput(PortNumber.portNumber(3)).build();
+
+    private static final TrafficSelector DUAL_LINK_3_FLOW_SELECTOR_1 = DefaultTrafficSelector.builder()
+            .matchInPort(PortNumber.portNumber(1))
+            .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
+            .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
+            .build();
+    private static final FlowRule DUAL_LINK_3_FLOW_1 = DefaultFlowEntry.builder().forDevice(DUAL_LINK_3)
+            .forTable(0)
+            .withPriority(100)
+            .withSelector(DUAL_LINK_3_FLOW_SELECTOR_1)
+            .withTreatment(DUAL_LINK_1_OUTPUT_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+
+    static final FlowEntry DUAL_LINK_3_FLOW_ENTRY = new DefaultFlowEntry(DUAL_LINK_3_FLOW_1);
+
+    private static final TrafficSelector DUAL_LINK_3_FLOW_SELECTOR_2 = DefaultTrafficSelector.builder()
+            .matchInPort(PortNumber.portNumber(2))
+            .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
+            .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
+            .build();
+    private static final FlowRule DUAL_LINK_3_FLOW_2 = DefaultFlowEntry.builder().forDevice(DUAL_LINK_3)
+            .forTable(0)
+            .withPriority(100)
+            .withSelector(DUAL_LINK_3_FLOW_SELECTOR_2)
+            .withTreatment(DUAL_LINK_1_OUTPUT_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+
+    static final FlowEntry DUAL_LINK_3_FLOW_ENTRY_2 = new DefaultFlowEntry(DUAL_LINK_3_FLOW_2);
+
+    //Group with two buckets to output on port 2 and 3 of device 1 and 2
+
+    private static final GroupBucket BUCKET_2_DUAL =
+            DefaultGroupBucket.createSelectGroupBucket(DUAL_LINK_1_OUTPUT_TREATMENT);
+
+    private static final GroupBuckets BUCKETS_DUAL = new GroupBuckets(ImmutableList.of(BUCKET, BUCKET_2_DUAL));
+
+    static final Group DUAL_LINK_GROUP = new DefaultGroup(GROUP_ID, DUAL_LINK_1, Group.Type.SELECT, BUCKETS_DUAL);
+
+    //Clear Deferred
+    static final DeviceId DEFERRED_1 = DeviceId.deviceId("Deferred");
+
+    static final ConnectPoint DEFERRED_CP_1_IN = ConnectPoint.deviceConnectPoint(DEFERRED_1 + "/" + 1);
+    static final ConnectPoint DEFERRED_CP_2_OUT = ConnectPoint.deviceConnectPoint(DEFERRED_1 + "/" + 2);
+
+    //match on port 1 and apply deferred actions
+    private static final TrafficTreatment DEFERRED_1_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
+            .transition(10)
+            .deferred()
+            .pushMpls()
+            .setMpls(MplsLabel.mplsLabel(100))
+            .build();
+    private static final FlowRule DEFERRED_FLOW = DefaultFlowEntry.builder().forDevice(DEFERRED_1)
+            .forTable(0)
+            .withPriority(100)
+            .withSelector(SINGLE_FLOW_SELECTOR)
+            .withTreatment(DEFERRED_1_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+    static final FlowEntry DEFERRED_FLOW_ENTRY = new DefaultFlowEntry(DEFERRED_FLOW);
+
+    //match on port 1, clear deferred actions and output
+    private static final TrafficTreatment DEFERRED_CLEAR_1_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
+            .wipeDeferred()
+            .setOutput(PortNumber.portNumber(2))
+            .build();
+    private static final FlowRule DEFERRED_CLEAR_FLOW = DefaultFlowEntry.builder().forDevice(DEFERRED_1)
+            .forTable(10)
+            .withPriority(100)
+            .withSelector(SINGLE_FLOW_SELECTOR)
+            .withTreatment(DEFERRED_CLEAR_1_FLOW_TREATMENT)
+            .fromApp(new DefaultApplicationId(0, "TestApp"))
+            .makePermanent()
+            .build();
+    static final FlowEntry DEFERRED_CLEAR_FLOW_ENTRY = new DefaultFlowEntry(DEFERRED_CLEAR_FLOW);
 
     //helper elements
 
+    static final String MASTER_1 = "Master1";
+
     static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(HOST_ONE), MacAddress.valueOf(100),
             VlanId.NONE, new HostLocation(SINGLE_FLOW_DEVICE, PortNumber.portNumber(2), 0),
             ImmutableSet.of(IpAddress.valueOf("127.0.0.2")));
@@ -340,6 +556,7 @@
             .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
             .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
             .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
+            .matchVlanId(VlanId.NONE)
             .build();
 
     static final TrafficSelector PACKET_OK_TOPO = DefaultTrafficSelector.builder()
@@ -348,6 +565,12 @@
             .matchIPDst(IpPrefix.valueOf("127.0.0.3/32"))
             .build();
 
+    static final TrafficSelector PACKET_ARP = DefaultTrafficSelector.builder()
+            .matchInPort(PortNumber.portNumber(1))
+            .matchIPDst(IpPrefix.valueOf("255.255.255.255/32"))
+            .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+            .build();
+
     static final TrafficSelector PACKET_FAIL = DefaultTrafficSelector.builder()
             .matchInPort(PortNumber.portNumber(1))
             .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
diff --git a/apps/t3/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java b/apps/t3/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
index a8f6524..9767730 100644
--- a/apps/t3/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
+++ b/apps/t3/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
@@ -24,6 +24,8 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.mastership.MastershipServiceAdapter;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DefaultDevice;
@@ -32,6 +34,7 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceServiceAdapter;
 import org.onosproject.net.driver.DefaultDriver;
 import org.onosproject.net.driver.Driver;
@@ -79,6 +82,7 @@
         mngr.driverService = new TestDriverService();
         mngr.groupService = new TestGroupService();
         mngr.deviceService = new TestDeviceService();
+        mngr.mastershipService = new TestMastershipService();
 
         assertNotNull("Manager should not be null", mngr);
 
@@ -120,6 +124,24 @@
         log.info("trace {}", traceFail.resultMessage());
     }
 
+    /**
+     * Tests ARP to controller.
+     */
+    @Test
+    public void arpToController() {
+        StaticPacketTrace traceSuccess = mngr.trace(PACKET_ARP, ARP_FLOW_CP);
+        assertNotNull("Trace should not be null", traceSuccess);
+        assertTrue("Trace should be successful",
+                traceSuccess.resultMessage().contains("Packet goes to the controller"));
+        assertTrue("Master should be Master1",
+                traceSuccess.resultMessage().contains(MASTER_1));
+        ConnectPoint connectPoint = traceSuccess.getGroupOuputs(ARP_FLOW_DEVICE).get(0).getOutput();
+        assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
+        assertNull("VlanId should be null", traceSuccess.getGroupOuputs(ARP_FLOW_DEVICE).get(0)
+                .getFinalPacket().getCriterion(Criterion.Type.VLAN_VID));
+        log.info("trace {}", traceSuccess.resultMessage());
+    }
+
 
     /**
      * Tests failure on device with no flows.
@@ -138,9 +160,9 @@
     @Test
     public void testSingleFlowRule() {
 
-        testSuccess(PACKET_OK, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE, SINGLE_FLOW_OUT_CP, 1);
+        testSuccess(PACKET_OK, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE, SINGLE_FLOW_OUT_CP, 1, 1);
 
-        testFaliure(PACKET_FAIL, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE);
+        testFailure(PACKET_FAIL, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE);
     }
 
     /**
@@ -152,7 +174,7 @@
         //Test Success
 
         StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE,
-                DUAL_FLOW_OUT_CP, 1);
+                DUAL_FLOW_OUT_CP, 1, 1);
 
         //Testing Vlan
         Criterion criterion = traceSuccess.getGroupOuputs(DUAL_FLOW_DEVICE).get(0).
@@ -164,7 +186,7 @@
         assertEquals("Vlan should be 100", VlanId.vlanId((short) 100), vlanIdCriterion.vlanId());
 
         //Test Faliure
-        testFaliure(PACKET_FAIL, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE);
+        testFailure(PACKET_FAIL, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE);
 
     }
 
@@ -175,7 +197,7 @@
     public void flowAndGroup() throws Exception {
 
         StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, GROUP_FLOW_IN_CP, GROUP_FLOW_DEVICE,
-                GROUP_FLOW_OUT_CP, 1);
+                GROUP_FLOW_OUT_CP, 1, 1);
 
         assertTrue("Wrong Output Group", traceSuccess.getGroupOuputs(GROUP_FLOW_DEVICE)
                 .get(0).getGroups().contains(GROUP));
@@ -196,7 +218,7 @@
     public void singlePathTopology() throws Exception {
 
         StaticPacketTrace traceSuccess = testSuccess(PACKET_OK_TOPO, TOPO_FLOW_1_IN_CP,
-                TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 1);
+                TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 1, 1);
 
         assertTrue("Incorrect path",
                 traceSuccess.getCompletePaths().get(0).contains(TOPO_FLOW_2_IN_CP));
@@ -214,7 +236,9 @@
     public void testGroupTopo() throws Exception {
 
         StaticPacketTrace traceSuccess = testSuccess(PACKET_OK_TOPO, TOPO_FLOW_IN_CP,
-                TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 2);
+                TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 2, 1);
+
+        log.info("{}", traceSuccess);
 
         assertTrue("Incorrect groups",
                 traceSuccess.getGroupOuputs(TOPO_GROUP_FLOW_DEVICE).get(0).getGroups().contains(TOPO_GROUP));
@@ -229,7 +253,7 @@
     public void hardwareTest() throws Exception {
 
         StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, HARDWARE_DEVICE_IN_CP,
-                HARDWARE_DEVICE, HARDWARE_DEVICE_OUT_CP, 1);
+                HARDWARE_DEVICE, HARDWARE_DEVICE_OUT_CP, 1, 1);
 
         assertEquals("wrong ETH type", EthType.EtherType.IPV4.ethType(),
                 ((EthTypeCriterion) traceSuccess.getGroupOuputs(HARDWARE_DEVICE).get(0).getFinalPacket()
@@ -237,8 +261,50 @@
 
     }
 
+    /**
+     * Test that HW has two rules on table 10 for untagged packets.
+     */
+    @Test
+    public void hardwareTable10Test() throws Exception {
+
+        StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, HARDWARE_DEVICE_10_IN_CP,
+                HARDWARE_DEVICE_10, HARDWARE_DEVICE_10_OUT_CP, 1, 1);
+
+        assertTrue("Second flow rule is absent", traceSuccess.getFlowsForDevice(HARDWARE_DEVICE_10)
+                .contains(HARDWARE_10_SECOND_FLOW_ENTRY));
+
+    }
+
+    /**
+     * Test dual links between 3 topology elements.
+     */
+    @Test
+    public void dualLinks() throws Exception {
+
+        StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DUAL_LINK_1_CP_1_IN,
+                DUAL_LINK_3, DUAL_LINK_3_CP_3_OUT, 4, 1);
+
+        //TODO tests
+
+    }
+
+    /**
+     * Test proper clear deferred behaviour.
+     */
+    @Test
+    public void clearDeferred() throws Exception {
+
+        StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DEFERRED_CP_1_IN,
+                DEFERRED_1, DEFERRED_CP_2_OUT, 1, 1);
+
+        assertNull("MPLS should have been not applied due to clear deferred", traceSuccess
+                .getGroupOuputs(DEFERRED_1).get(0).getFinalPacket().getCriterion(Criterion.Type.MPLS_LABEL));
+
+    }
+
+
     private StaticPacketTrace testSuccess(TrafficSelector packet, ConnectPoint in, DeviceId deviceId, ConnectPoint out,
-                                          int paths) {
+                                          int paths, int outputs) {
         StaticPacketTrace traceSuccess = mngr.trace(packet, in);
 
         log.info("trace {}", traceSuccess);
@@ -246,7 +312,8 @@
         log.info("trace {}", traceSuccess.resultMessage());
 
         assertNotNull("trace should not be null", traceSuccess);
-        assertEquals("Trace should have " + paths + " output", paths, traceSuccess.getGroupOuputs(deviceId).size());
+        assertEquals("Trace should have " + outputs + " output", outputs,
+                traceSuccess.getGroupOuputs(deviceId).size());
         assertEquals("Trace should only have " + paths + "output", paths, traceSuccess.getCompletePaths().size());
         assertTrue("Trace should be successful",
                 traceSuccess.resultMessage().contains("Reached required destination Host"));
@@ -256,7 +323,7 @@
         return traceSuccess;
     }
 
-    private void testFaliure(TrafficSelector packet, ConnectPoint in, DeviceId deviceId) {
+    private void testFailure(TrafficSelector packet, ConnectPoint in, DeviceId deviceId) {
         StaticPacketTrace traceFail = mngr.trace(packet, in);
 
         log.info("trace {}", traceFail.resultMessage());
@@ -285,6 +352,19 @@
                 return ImmutableList.of(HARDWARE_ETH_FLOW_ENTRY, HARDWARE_FLOW_ENTRY);
             } else if (deviceId.equals(SAME_OUTPUT_FLOW_DEVICE)) {
                 return ImmutableList.of(SAME_OUTPUT_FLOW_ENTRY);
+            } else if (deviceId.equals(ARP_FLOW_DEVICE)) {
+                return ImmutableList.of(ARP_FLOW_ENTRY);
+            } else if (deviceId.equals(DUAL_LINK_1)) {
+                return ImmutableList.of(DUAL_LINK_1_GROUP_FLOW_ENTRY);
+            } else if (deviceId.equals(DUAL_LINK_2)) {
+                return ImmutableList.of(DUAL_LINK_1_GROUP_FLOW_ENTRY, DUAL_LINK_2_GROUP_FLOW_ENTRY);
+            } else if (deviceId.equals(DUAL_LINK_3)) {
+                return ImmutableList.of(DUAL_LINK_3_FLOW_ENTRY, DUAL_LINK_3_FLOW_ENTRY_2);
+            } else if (deviceId.equals(DEFERRED_1)) {
+                return ImmutableList.of(DEFERRED_FLOW_ENTRY, DEFERRED_CLEAR_FLOW_ENTRY);
+            } else if (deviceId.equals(HARDWARE_DEVICE_10)) {
+                return ImmutableList.of(HARDWARE_10_FLOW_ENTRY, HARDWARE_10_SECOND_FLOW_ENTRY,
+                        HARDWARE_10_OUTPUT_FLOW_ENTRY);
             }
             return ImmutableList.of();
         }
@@ -293,7 +373,7 @@
     private class TestDriverService extends DriverServiceAdapter {
         @Override
         public Driver getDriver(DeviceId deviceId) {
-            if (deviceId.equals(HARDWARE_DEVICE)) {
+            if (deviceId.equals(HARDWARE_DEVICE) || deviceId.equals(HARDWARE_DEVICE_10)) {
                 return new DefaultDriver("ofdpa", ImmutableList.of(),
                         "test", "test", "test", new HashMap<>(), new HashMap<>());
             }
@@ -309,6 +389,8 @@
                 return ImmutableList.of(GROUP);
             } else if (deviceId.equals(TOPO_GROUP_FLOW_DEVICE)) {
                 return ImmutableList.of(TOPO_GROUP);
+            } else if (deviceId.equals(DUAL_LINK_1) || deviceId.equals(DUAL_LINK_2)) {
+                return ImmutableList.of(DUAL_LINK_GROUP);
             }
             return ImmutableList.of();
         }
@@ -319,6 +401,9 @@
         public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
             if (connectPoint.equals(TOPO_FLOW_3_OUT_CP)) {
                 return ImmutableSet.of(H2);
+            } else if (connectPoint.equals(DUAL_LINK_1_CP_2_OUT) || connectPoint.equals(DUAL_LINK_1_CP_3_OUT) ||
+                    connectPoint.equals(DUAL_LINK_2_CP_2_OUT) || connectPoint.equals(DUAL_LINK_2_CP_3_OUT)) {
+                return ImmutableSet.of();
             }
             return ImmutableSet.of(H1);
         }
@@ -376,6 +461,34 @@
                         .src(TOPO_FLOW_4_OUT_CP)
                         .dst(TOPO_FLOW_3_IN_2_CP)
                         .build());
+            } else if (connectPoint.equals(DUAL_LINK_1_CP_2_OUT)) {
+                return ImmutableSet.of(DefaultLink.builder()
+                        .providerId(ProviderId.NONE)
+                        .type(Link.Type.DIRECT)
+                        .src(DUAL_LINK_1_CP_2_OUT)
+                        .dst(DUAL_LINK_2_CP_1_IN)
+                        .build());
+            } else if (connectPoint.equals(DUAL_LINK_1_CP_3_OUT)) {
+                return ImmutableSet.of(DefaultLink.builder()
+                        .providerId(ProviderId.NONE)
+                        .type(Link.Type.DIRECT)
+                        .src(DUAL_LINK_1_CP_3_OUT)
+                        .dst(DUAL_LINK_2_CP_4_IN)
+                        .build());
+            } else if (connectPoint.equals(DUAL_LINK_2_CP_2_OUT)) {
+                return ImmutableSet.of(DefaultLink.builder()
+                        .providerId(ProviderId.NONE)
+                        .type(Link.Type.DIRECT)
+                        .src(DUAL_LINK_2_CP_2_OUT)
+                        .dst(DUAL_LINK_3_CP_1_IN)
+                        .build());
+            } else if (connectPoint.equals(DUAL_LINK_2_CP_3_OUT)) {
+                return ImmutableSet.of(DefaultLink.builder()
+                        .providerId(ProviderId.NONE)
+                        .type(Link.Type.DIRECT)
+                        .src(DUAL_LINK_2_CP_3_OUT)
+                        .dst(DUAL_LINK_3_CP_2_IN)
+                        .build());
             }
             return ImmutableSet.of();
         }
@@ -400,4 +513,11 @@
             return true;
         }
     }
+
+    private class TestMastershipService extends MastershipServiceAdapter {
+        @Override
+        public NodeId getMasterFor(DeviceId deviceId) {
+            return NodeId.nodeId(MASTER_1);
+        }
+    }
 }
\ No newline at end of file
diff --git a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
index f7e46cc..4784475 100644
--- a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
+++ b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
@@ -40,6 +40,7 @@
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -333,8 +334,8 @@
                 .key(key)
                 .selector(selector)
                 .treatment(treatment)
-                .ingressPoint(ingress)
-                .egressPoint(egress)
+                .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                .filteredEgressPoint(new FilteredConnectPoint(egress))
                 .build();
     }
 
diff --git a/apps/test/primitive-perf/src/main/java/org/onosproject/primitiveperf/PrimitivePerfApp.java b/apps/test/primitive-perf/src/main/java/org/onosproject/primitiveperf/PrimitivePerfApp.java
index 5e8900a..256edfc 100644
--- a/apps/test/primitive-perf/src/main/java/org/onosproject/primitiveperf/PrimitivePerfApp.java
+++ b/apps/test/primitive-perf/src/main/java/org/onosproject/primitiveperf/PrimitivePerfApp.java
@@ -256,6 +256,7 @@
                 workers.awaitTermination(10, TimeUnit.MILLISECONDS);
             } catch (InterruptedException e) {
                 log.warn("Failed to stop worker", e);
+                Thread.currentThread().interrupt();
             }
         }
 
diff --git a/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/DistributedTeTopologyStore.java b/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/DistributedTeTopologyStore.java
index c9a0b50..e3a63b3 100644
--- a/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/DistributedTeTopologyStore.java
+++ b/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/DistributedTeTopologyStore.java
@@ -410,6 +410,7 @@
                     mapEventQueue.put(mapEvent);
                 } catch (InterruptedException e) {
                     log.warn("Unable to queue event {} ", mapEvent, e);
+                    Thread.currentThread().interrupt();
                 }
             }
         }
@@ -446,6 +447,7 @@
                     mapEventQueue.put(mapEvent);
                 } catch (InterruptedException e) {
                     log.warn("Unable to queue event {} ", mapEvent, e);
+                    Thread.currentThread().interrupt();
                 }
             }
         }
@@ -487,6 +489,7 @@
                     mapEventQueue.put(mapEvent);
                 } catch (InterruptedException e) {
                     log.warn("Unable to queue event {} ", mapEvent, e);
+                    Thread.currentThread().interrupt();
                 }
             }
         }
@@ -528,6 +531,7 @@
                     mapEventQueue.put(mapEvent);
                 } catch (InterruptedException e) {
                     log.warn("Unable to queue event {} ", mapEvent, e);
+                    Thread.currentThread().interrupt();
                 }
             }
         }
@@ -568,6 +572,7 @@
                     mapEventQueue.put(mapEvent);
                 } catch (InterruptedException e) {
                     log.warn("Unable to queue event {} ", mapEvent, e);
+                    Thread.currentThread().interrupt();
                 }
             }
         }
@@ -608,6 +613,7 @@
                     mapEventQueue.put(mapEvent);
                 } catch (InterruptedException e) {
                     log.warn("Unable to queue event {} ", mapEvent, e);
+                    Thread.currentThread().interrupt();
                 }
             }
         }
diff --git a/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/TeTopologyManager.java b/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/TeTopologyManager.java
index 5ce27e3..5775a57 100644
--- a/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/TeTopologyManager.java
+++ b/apps/tetopology/app/src/main/java/org/onosproject/tetopology/management/impl/TeTopologyManager.java
@@ -437,6 +437,7 @@
                 }
             } catch (InterruptedException e) {
                 log.warn("TopologyMergerTask is interrupted");
+                Thread.currentThread().interrupt();
             } catch (Exception e) {
                 log.warn("Unable to merge topology", e);
             }
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
index c09d7cc..adc6966 100644
--- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
@@ -263,7 +263,7 @@
 
                 // Judge whether the prefix of this public IP address is used
                 // up, if so, update the IP prefix status.
-                int prefixLen = prefix.getKey().prefixLength();
+                double prefixLen = prefix.getKey().prefixLength();
                 int availableIpNum = (int) Math.pow(2,
                         IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
                 int usedIpNum = 0;
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
index 4f8e6d9..35ca7f9 100644
--- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
@@ -32,6 +32,7 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.Host;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -446,8 +447,8 @@
                 .key(key)
                 .selector(selector.build())
                 .treatment(treatment.build())
-                .egressPoint(dstConnectPoint)
-                .ingressPoint(srcConnectPoint)
+                .filteredEgressPoint(new FilteredConnectPoint(dstConnectPoint))
+                .filteredIngressPoint(new FilteredConnectPoint(srcConnectPoint))
                 .build();
 
         log.info("Generated a PointToPointIntent for traffic from local host "
@@ -496,8 +497,8 @@
                 .key(key)
                 .selector(selector.build())
                 .treatment(treatment.build())
-                .egressPoint(dstConnectPoint)
-                .ingressPoint(srcConnectPoint)
+                .filteredEgressPoint(new FilteredConnectPoint(dstConnectPoint))
+                .filteredIngressPoint(new FilteredConnectPoint(srcConnectPoint))
                 .build();
         log.info("Generated a PointToPointIntent for traffic to local host "
                 + ": {}", intent);
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/cli/completer/VplsNameCompleter.java b/apps/vpls/src/main/java/org/onosproject/vpls/cli/completer/VplsNameCompleter.java
index 468d7d6..d3ffb33 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/cli/completer/VplsNameCompleter.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/cli/completer/VplsNameCompleter.java
@@ -30,7 +30,7 @@
  */
 public class VplsNameCompleter extends AbstractChoicesCompleter {
 
-    protected static Vpls vpls;
+    protected Vpls vpls;
 
     @Override
     public List<String> choices() {
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfigManager.java b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfigManager.java
index d08d9e3..541953e 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfigManager.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfigManager.java
@@ -251,6 +251,7 @@
                     case CONFIG_REMOVED:
                     case CONFIG_UNREGISTERED:
                         vpls.removeAllVpls();
+                        break;
                     default:
                         break;
                 }
diff --git a/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FloatingIpWebResource.java b/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FloatingIpWebResource.java
index c510647..3c4daa5 100644
--- a/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FloatingIpWebResource.java
+++ b/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FloatingIpWebResource.java
@@ -170,8 +170,7 @@
         }
     }
 
-    private Collection<FloatingIp> createOrUpdateByInputStream(JsonNode subnode)
-            throws Exception {
+    private Collection<FloatingIp> createOrUpdateByInputStream(JsonNode subnode) {
         checkNotNull(subnode, JSON_NOT_NULL);
         Collection<FloatingIp> floatingIps = null;
         JsonNode floatingIpNodes = subnode.get("floatingips");
diff --git a/apps/yang/src/main/java/org/onosproject/yang/impl/YangLiveCompilerManager.java b/apps/yang/src/main/java/org/onosproject/yang/impl/YangLiveCompilerManager.java
index d109dc3..66d296a 100644
--- a/apps/yang/src/main/java/org/onosproject/yang/impl/YangLiveCompilerManager.java
+++ b/apps/yang/src/main/java/org/onosproject/yang/impl/YangLiveCompilerManager.java
@@ -227,6 +227,7 @@
             }
         } catch (InterruptedException e) {
             log.error("Interrupted executing command {}", command, e);
+            Thread.currentThread().interrupt();
         }
     }
 }
diff --git a/apps/yang/src/main/java/org/onosproject/yang/impl/YangRuntimeManager.java b/apps/yang/src/main/java/org/onosproject/yang/impl/YangRuntimeManager.java
index 950a63e..c338c33 100644
--- a/apps/yang/src/main/java/org/onosproject/yang/impl/YangRuntimeManager.java
+++ b/apps/yang/src/main/java/org/onosproject/yang/impl/YangRuntimeManager.java
@@ -26,6 +26,7 @@
 import org.onosproject.yang.YangClassLoaderRegistry;
 import org.onosproject.yang.model.ModelConverter;
 import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.model.ModelObjectId;
 import org.onosproject.yang.model.NodeKey;
 import org.onosproject.yang.model.ResourceData;
 import org.onosproject.yang.model.ResourceId;
@@ -163,7 +164,8 @@
     }
 
     @Override
-    public void registerAnydataSchema(Class id, Class id1) {
+    public void registerAnydataSchema(ModelObjectId arg0, ModelObjectId arg1)
+            throws IllegalArgumentException {
         throw new UnsupportedOperationException("registerAnydataSchema() needs to be implemented");
     }
 
diff --git a/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java b/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
index e427a8c..a45efcb 100644
--- a/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
@@ -92,7 +92,7 @@
         try {
             print("%s", mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root));
         } catch (JsonProcessingException e) {
-            throw new RuntimeException("Error writing JSON to string", e);
+            throw new IllegalStateException("Error writing JSON to string", e);
         }
     }
 
diff --git a/cli/src/main/java/org/onosproject/cli/net/AddPointToPointIntentCommand.java b/cli/src/main/java/org/onosproject/cli/net/AddPointToPointIntentCommand.java
index 99ed470..b14d956 100644
--- a/cli/src/main/java/org/onosproject/cli/net/AddPointToPointIntentCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/AddPointToPointIntentCommand.java
@@ -19,6 +19,7 @@
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.intent.Constraint;
@@ -92,8 +93,8 @@
                 .key(key())
                 .selector(selector)
                 .treatment(treatment)
-                .ingressPoint(ingress)
-                .egressPoint(egress)
+                .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                .filteredEgressPoint(new FilteredConnectPoint(egress))
                 .constraints(constraints)
                 .priority(priority())
                 .resourceGroup(resourceGroup())
diff --git a/cli/src/main/java/org/onosproject/cli/net/DeviceConfigGetterCommand.java b/cli/src/main/java/org/onosproject/cli/net/DeviceConfigGetterCommand.java
deleted file mode 100644
index 754d475..0000000
--- a/cli/src/main/java/org/onosproject/cli/net/DeviceConfigGetterCommand.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016-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 org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.behaviour.ConfigGetter;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
-
-/**
- * Command that gets the configuration of the specified type from the specified
- * device. If configuration cannot be retrieved it prints an error string.
- *
- * This is a temporary development tool for use until yang integration is complete.
- * This uses a not properly specified behavior. DO NOT USE AS AN EXAMPLE.
- *
- * @deprecated in 1.10.0
- */
-
-//FIXME this should eventually be removed.
-@Deprecated
-@Command(scope = "onos", name = "device-configuration",
-        description = "[Deprecated]Gets the configuration of the specified type from the" +
-                "specified device.")
-public class DeviceConfigGetterCommand extends AbstractShellCommand {
-
-    @Argument(index = 0, name = "uri", description = "Device ID",
-            required = true, multiValued = false)
-    String uri = null;
-    @Argument(index = 1, name = "cfgType", description = "Configuration type",
-            required = true, multiValued = false)
-    String cfgType = null;
-    private DeviceId deviceId;
-
-    @Override
-    protected void execute() {
-        print("[WARN] This command was marked deprecated in 1.10.0");
-        DriverService service = get(DriverService.class);
-        deviceId = DeviceId.deviceId(uri);
-        DriverHandler h = service.createHandler(deviceId);
-        ConfigGetter config = h.behaviour(ConfigGetter.class);
-        print(config.getConfiguration(cfgType));
-    }
-
-}
diff --git a/cli/src/main/java/org/onosproject/cli/net/DeviceConfigSetterCommand.java b/cli/src/main/java/org/onosproject/cli/net/DeviceConfigSetterCommand.java
deleted file mode 100644
index 4213e07..0000000
--- a/cli/src/main/java/org/onosproject/cli/net/DeviceConfigSetterCommand.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016-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 org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.behaviour.ConfigSetter;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Command that sets the configuration included in the specified file to the
- * specified device. It prints the response of the device.
- *
- * This is a temporary development tool for use until yang integration is complete.
- * This uses a not properly specified behavior. DO NOT USE AS AN EXAMPLE.
- *
- * @deprecated in 1.10.0
- */
-//Temporary Developer tool, NOT TO BE USED in production or as example for
-// future commands.
-//FIXME this should eventually be removed.
-@Deprecated
-@Command(scope = "onos", name = "device-setconfiguration",
-        description = "[Deprecated]Sets the configuration of the specified file to the " +
-                "specified device.")
-public class DeviceConfigSetterCommand extends AbstractShellCommand {
-
-    @Argument(index = 0, name = "uri", description = "Device ID",
-            required = true, multiValued = false)
-    private String uri = null;
-    @Argument(index = 1, name = "cfgFile", description = "Configuration file",
-            required = true, multiValued = false)
-    private String cfgFile = null;
-    private DeviceId deviceId;
-
-    @Override
-    protected void execute() {
-        print("[WARN] This command was marked deprecated in 1.10.0");
-        DriverService service = get(DriverService.class);
-        deviceId = DeviceId.deviceId(uri);
-        DriverHandler h = service.createHandler(deviceId);
-        ConfigSetter config = h.behaviour(ConfigSetter.class);
-        checkNotNull(cfgFile, "Configuration file cannot be null");
-        print(config.setConfiguration(cfgFile));
-    }
-
-}
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortGetterCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortGetterCommand.java
deleted file mode 100644
index e689a4d..0000000
--- a/cli/src/main/java/org/onosproject/cli/net/DevicePortGetterCommand.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016-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 org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.behaviour.PortDiscovery;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
-
-/**
- * Command that gets the configuration of the specified type from the specified
- * device. If configuration cannot be retrieved it prints an error string.
- *
- * This is a temporary development tool for use until yang integration is complete.
- * This uses a not properly specified behavior. DO NOT USE AS AN EXAMPLE.
- *
- * @deprecated in 1.10.0
- */
-@Deprecated
-@Command(scope = "onos", name = "device-ports",
-        description = "[Deprecated]Gets the ports of the specified device.")
-public class DevicePortGetterCommand extends AbstractShellCommand {
-
-    @Argument(index = 0, name = "uri", description = "Device ID",
-            required = true, multiValued = false)
-    String uri = null;
-    private DeviceId deviceId;
-
-    @Override
-    protected void execute() {
-        print("[WARN] This command was marked deprecated in 1.10.0");
-        DriverService service = get(DriverService.class);
-        deviceId = DeviceId.deviceId(uri);
-        DriverHandler h = service.createHandler(deviceId);
-        PortDiscovery portConfig = h.behaviour(PortDiscovery.class);
-        print(portConfig.getPorts().toString());
-    }
-
-}
diff --git a/cli/src/main/java/org/onosproject/cli/net/IntentCycleCommand.java b/cli/src/main/java/org/onosproject/cli/net/IntentCycleCommand.java
index db86d5f..fa764fb 100644
--- a/cli/src/main/java/org/onosproject/cli/net/IntentCycleCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/IntentCycleCommand.java
@@ -26,6 +26,7 @@
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -131,8 +132,8 @@
                         .key(Key.of(i + keyOffset, appId()))
                         .selector(selector)
                         .treatment(treatment)
-                        .ingressPoint(ingress)
-                        .egressPoint(egress)
+                        .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                        .filteredEgressPoint(new FilteredConnectPoint(egress))
                         .build());
 
 
diff --git a/cli/src/main/java/org/onosproject/cli/net/IntentPushTestCommand.java b/cli/src/main/java/org/onosproject/cli/net/IntentPushTestCommand.java
index 0b28f92..4fcb0c8 100644
--- a/cli/src/main/java/org/onosproject/cli/net/IntentPushTestCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/IntentPushTestCommand.java
@@ -24,6 +24,7 @@
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -143,8 +144,8 @@
                     .key(Key.of(i + keyOffset, appId()))
                     .selector(selector)
                     .treatment(treatment)
-                    .ingressPoint(ingress)
-                    .egressPoint(egress)
+                    .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                    .filteredEgressPoint(new FilteredConnectPoint(egress))
                     .build());
             keysForInstall.add(Key.of(i + keyOffset, appId()));
             keysForWithdraw.add(Key.of(i + keyOffset, appId()));
diff --git a/cli/src/main/java/org/onosproject/cli/net/McastDeleteCommand.java b/cli/src/main/java/org/onosproject/cli/net/McastDeleteCommand.java
index 5c34f9e..26dbfde 100644
--- a/cli/src/main/java/org/onosproject/cli/net/McastDeleteCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/McastDeleteCommand.java
@@ -30,6 +30,14 @@
         description = "Delete a multicast route flow")
 public class McastDeleteCommand extends AbstractShellCommand {
 
+    // Delete format for group line
+    private static final String D_FORMAT_MAPPING = "Deleted the mcast route: " +
+            "origin=%s, group=%s, source=%s";
+
+    // Update format for group line
+    private static final String U_FORMAT_MAPPING = "Updated the mcast route: " +
+            "origin=%s, group=%s, source=%s";
+
     @Argument(index = 0, name = "sAddr",
             description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry",
             required = true, multiValued = false)
@@ -61,12 +69,14 @@
 
         if (egressList == null) {
             mcastRouteManager.remove(mRoute);
+            print(D_FORMAT_MAPPING, mRoute.type(), mRoute.group(), mRoute.source());
         } else {
             // check list for validity before we begin to delete.
             for (String egress : egressList) {
                 ConnectPoint eCp = ConnectPoint.deviceConnectPoint(egress);
                 mcastRouteManager.removeSink(mRoute, eCp);
             }
+            print(U_FORMAT_MAPPING, mRoute.type(), mRoute.group(), mRoute.source());
         }
     }
 }
diff --git a/cli/src/main/java/org/onosproject/cli/net/McastGroupCompleter.java b/cli/src/main/java/org/onosproject/cli/net/McastGroupCompleter.java
new file mode 100644
index 0000000..6700b97
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/McastGroupCompleter.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018-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 org.onlab.packet.IpAddress;
+import org.onlab.util.Tools;
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.mcast.McastRoute;
+import org.onosproject.net.mcast.MulticastRouteService;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Mcast group Completer.
+ */
+public class McastGroupCompleter extends AbstractChoicesCompleter {
+
+    @Override
+    protected List<String> choices() {
+        MulticastRouteService service = AbstractShellCommand.get(MulticastRouteService.class);
+
+        return Tools.stream(service.getRoutes())
+            .map(McastRoute::group)
+            .map(IpAddress::toString)
+            .collect(Collectors.toList());
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/McastJoinCommand.java b/cli/src/main/java/org/onosproject/cli/net/McastJoinCommand.java
index f0dc33e..83969a8 100644
--- a/cli/src/main/java/org/onosproject/cli/net/McastJoinCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/McastJoinCommand.java
@@ -30,6 +30,10 @@
          description = "Installs a source, multicast group flow")
 public class McastJoinCommand extends AbstractShellCommand {
 
+    // Format for group line
+    private static final String FORMAT_MAPPING = "Added the mcast route: " +
+            "origin=%s, group=%s, source=%s";
+
     @Argument(index = 0, name = "sAddr",
               description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry",
               required = true, multiValued = false)
@@ -54,7 +58,6 @@
     protected void execute() {
         MulticastRouteService mcastRouteManager = get(MulticastRouteService.class);
 
-        //McastRoute mRoute = McastForwarding.createStaticRoute(sAddr, gAddr);
         McastRoute mRoute = new McastRoute(IpAddress.valueOf(sAddr),
                 IpAddress.valueOf(gAddr), McastRoute.Type.STATIC);
         mcastRouteManager.add(mRoute);
@@ -66,12 +69,15 @@
 
         if (ports != null) {
             for (String egCP : ports) {
-                log.debug("Egress port provided: " + egCP);
                 ConnectPoint egress = ConnectPoint.deviceConnectPoint(egCP);
                 mcastRouteManager.addSink(mRoute, egress);
 
             }
         }
-        print("Added the mcast route: %s", mRoute);
+        printMcastRoute(mRoute);
+    }
+
+    private void printMcastRoute(McastRoute mcastRoute) {
+        print(FORMAT_MAPPING, mcastRoute.type(), mcastRoute.group(), mcastRoute.source());
     }
 }
diff --git a/cli/src/main/java/org/onosproject/cli/net/McastRoutesListCommand.java b/cli/src/main/java/org/onosproject/cli/net/McastRoutesListCommand.java
new file mode 100644
index 0000000..003e53c
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/McastRoutesListCommand.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018-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 org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.mcast.McastRoute;
+import org.onosproject.net.mcast.MulticastRouteService;
+
+import java.util.Comparator;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Displays the source, multicast group flows entries.
+ */
+@Command(scope = "onos", name = "mcast-routes",
+        description = "Lists routes in the mcast route store")
+public class McastRoutesListCommand extends AbstractShellCommand {
+
+    // Format for total
+    private static final String FORMAT_TOTAL = "   Total: %d";
+
+    // Format for ipv4
+    private static final String FORMAT_ROUTE = "%-1s   %-18s %-15s %s   %s";
+    // Format for ipv6
+    private static final String FORMAT_ROUTE6 = "%-1s   %-40s %-36s %s   %s";
+
+    // Table header
+    private static final String FORMAT_TABLE = "Table: %s";
+    private static final String GROUP = "Group";
+    private static final String SOURCE = "Source";
+    private static final String ORIGIN = "Origin";
+    private static final String SINKS = "Sinks";
+
+    @Override
+    protected void execute() {
+        // Get the service
+        MulticastRouteService mcastService = get(MulticastRouteService.class);
+        // Get the routes
+        Set<McastRoute> routes = mcastService.getRoutes();
+        // Filter ipv4
+        Set<McastRoute> ipv4Routes = routes.stream()
+                .filter(mcastRoute -> mcastRoute.group().isIp4())
+                .collect(Collectors.toSet());
+        // Filter ipv6
+        Set<McastRoute> ipv6Routes = routes.stream()
+                .filter(mcastRoute -> mcastRoute.group().isIp6())
+                .collect(Collectors.toSet());
+        // Print header
+        print(FORMAT_TABLE, "ipv4");
+        print(FORMAT_ROUTE, "", GROUP, SOURCE, ORIGIN, SINKS);
+        // Print ipv4 mcast routing entries
+        ipv4Routes.stream()
+                .sorted(Comparator.comparing(McastRoute::group))
+                .forEach(route -> {
+                    // Get sinks
+                    Set<ConnectPoint> sinks = mcastService.fetchSinks(route);
+                    print(FORMAT_ROUTE, "", route.group(), route.source(),
+                          route.type(), sinks.size());
+                });
+        print(FORMAT_TOTAL, ipv4Routes.size());
+        print("");
+
+        // Print header
+        print(FORMAT_TABLE, "ipv6");
+        print(FORMAT_ROUTE6, "", GROUP, SOURCE, ORIGIN, SINKS);
+        // Print ipv6 mcast routing entries
+        ipv6Routes.stream()
+                .sorted(Comparator.comparing(McastRoute::group))
+                .forEach(route -> {
+                    // Get sinks
+                    Set<ConnectPoint> sinks = mcastService.fetchSinks(route);
+                    print(FORMAT_ROUTE6, "", route.group(), route.source(),
+                          route.type(), sinks.size());
+                });
+        print(FORMAT_TOTAL, ipv6Routes.size());
+        print("");
+    }
+
+
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/McastShowCommand.java b/cli/src/main/java/org/onosproject/cli/net/McastShowCommand.java
index cae0bd5..91ab0c4 100644
--- a/cli/src/main/java/org/onosproject/cli/net/McastShowCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/McastShowCommand.java
@@ -15,13 +15,19 @@
  */
 package org.onosproject.cli.net;
 
+import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.mcast.McastRoute;
 import org.onosproject.net.mcast.MulticastRouteService;
 
+import java.util.Comparator;
 import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
 
 /**
  * Displays the source, multicast group flows entries.
@@ -29,20 +35,61 @@
 @Command(scope = "onos", name = "mcast-show", description = "Displays the source, multicast group flows")
 public class McastShowCommand extends AbstractShellCommand {
 
-    private static final String FORMAT = "route=%s, source=%s, sinks=%s";
+    // Format for group line
+    private static final String FORMAT_MAPPING = "origin=%s, group=%s, source=%s, sinks=%s";
+
+    @Argument(index = 0, name = "mcastIp", description = "mcast Ip",
+            required = false, multiValued = false)
+    String mcastIp;
 
     @Override
     protected void execute() {
+        // Get the service
         MulticastRouteService mcastService = get(MulticastRouteService.class);
-
+        // Get the routes
         Set<McastRoute> routes = mcastService.getRoutes();
-
-        for (McastRoute route : routes) {
-            Set<ConnectPoint> sinks = mcastService.fetchSinks(route);
-            ConnectPoint source = mcastService.fetchSource(route);
-
-            print(FORMAT, route, source, sinks);
+        // Verify mcast group
+        if (!isNullOrEmpty(mcastIp)) {
+            // Let's find the group
+            IpAddress mcastGroup = IpAddress.valueOf(mcastIp);
+            McastRoute mcastRoute = routes.stream()
+                    .filter(route -> route.group().equals(mcastGroup))
+                    .findAny().orElse(null);
+            // If it exists
+            if (mcastRoute != null) {
+                // Get the sinks and print info
+                Set<ConnectPoint> sinks = mcastService.fetchSinks(mcastRoute);
+                print(FORMAT_MAPPING, mcastRoute.type(), mcastRoute.group(),
+                      mcastRoute.source(), sinks);
+            }
+            return;
         }
+        // Filter ipv4
+        Set<McastRoute> ipv4Routes = routes.stream()
+                .filter(mcastRoute -> mcastRoute.group().isIp4())
+                .collect(Collectors.toSet());
+        // Print ipv4 first
+        ipv4Routes.stream()
+                .sorted(Comparator.comparing(McastRoute::group))
+                .forEach(route -> {
+                    // Get sinks
+                    Set<ConnectPoint> sinks = mcastService.fetchSinks(route);
+                    print(FORMAT_MAPPING, route.type(), route.group(),
+                          route.source(), sinks);
+                });
+        // Filter ipv6
+        Set<McastRoute> ipv6Routes = routes.stream()
+                .filter(mcastRoute -> mcastRoute.group().isIp6())
+                .collect(Collectors.toSet());
+        // Then print ipv6
+        ipv6Routes.stream()
+                .sorted(Comparator.comparing(McastRoute::group))
+                .forEach(route -> {
+                    // Get sinks
+                    Set<ConnectPoint> sinks = mcastService.fetchSinks(route);
+                    print(FORMAT_MAPPING, route.type(), route.group(),
+                          route.source(), sinks);
+                });
     }
 
 }
diff --git a/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java b/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java
index cd42752..880621d 100644
--- a/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java
@@ -23,6 +23,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.Host;
 import org.onosproject.net.Link;
+import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.device.DeviceAdminService;
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.group.GroupService;
@@ -34,7 +35,9 @@
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.link.LinkAdminService;
 import org.onosproject.net.region.RegionAdminService;
+import org.onosproject.ui.UiExtensionService;
 import org.onosproject.ui.UiTopoLayoutService;
+
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -68,9 +71,11 @@
         wipeOutGroups();
         wipeOutDevices();
         wipeOutLinks();
+        wipeOutNetworkConfig();
 
         wipeOutLayouts();
         wipeOutRegions();
+        wipeOutUiCache();
     }
 
     private void wipeOutIntents() {
@@ -95,14 +100,12 @@
         intentService.addListener(listener);
         intentsToWithdrawn.forEach(intentService::withdraw);
         try {
-            // Wait 1.5 seconds for each Intent
-            completableFuture.get(intentsToWithdrawn.size() * 1500L, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            print("Got interrupted exception while withdrawn Intents " + e.toString());
-        } catch (ExecutionException e) {
-            print("Got execution exception while withdrawn Intents " + e.toString());
-        } catch (TimeoutException e) {
-            print("Got timeout exception while withdrawn Intents " + e.toString());
+            if (!intentsToWithdrawn.isEmpty()) {
+                // Wait 1.5 seconds for each Intent
+                completableFuture.get(intentsToWithdrawn.size() * 1500L, TimeUnit.MILLISECONDS);
+            }
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            print("Encountered exception while withdrawing intents: " + e.toString());
         } finally {
             intentService.removeListener(listener);
         }
@@ -186,4 +189,15 @@
         RegionAdminService service = get(RegionAdminService.class);
         service.getRegions().forEach(r -> service.removeRegion(r.id()));
     }
+
+    private void wipeOutNetworkConfig() {
+        print("Wiping network configs");
+        get(NetworkConfigService.class).removeConfig();
+    }
+
+    private void wipeOutUiCache() {
+        print("Wiping ui model cache");
+        get(UiExtensionService.class).refreshModel();
+    }
+
 }
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 c75fcc9..3fab2f9 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -116,12 +116,31 @@
 
         <command>
             <action class="org.onosproject.cli.net.McastShowCommand"/>
+            <completers>
+                <ref component-id="mcastGroupCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.McastRoutesListCommand"/>
+            <completers>
+                <ref component-id="mcastGroupCompleter"/>
+            </completers>
         </command>
         <command>
             <action class="org.onosproject.cli.net.McastJoinCommand"/>
+            <completers>
+                <ref component-id="placeholderCompleter"/>
+                <ref component-id="mcastGroupCompleter"/>
+                <ref component-id="connectPointCompleter"/>
+            </completers>
         </command>
         <command>
             <action class="org.onosproject.cli.net.McastDeleteCommand"/>
+            <completers>
+                <ref component-id="placeholderCompleter"/>
+                <ref component-id="mcastGroupCompleter"/>
+                <ref component-id="connectPointCompleter"/>
+            </completers>
         </command>
 
         <command>
@@ -166,27 +185,6 @@
             </completers>
         </command>
         <command>
-            <action class="org.onosproject.cli.net.DeviceConfigGetterCommand"/>
-            <completers>
-                <ref component-id="deviceIdCompleter"/>
-                <null/>
-            </completers>
-        </command>
-        <command>
-            <action class="org.onosproject.cli.net.DeviceConfigSetterCommand"/>
-            <completers>
-                <ref component-id="deviceIdCompleter"/>
-                <null/>
-            </completers>
-        </command>
-        <command>
-            <action class="org.onosproject.cli.net.DevicePortGetterCommand"/>
-            <completers>
-                <ref component-id="deviceIdCompleter"/>
-                <null/>
-            </completers>
-        </command>
-        <command>
             <action class="org.onosproject.cli.net.DeviceRemoveCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
@@ -269,6 +267,7 @@
             <action class="org.onosproject.cli.net.LinksListCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
+                <null/> <!-- no more arguments -->
             </completers>
         </command>
 
@@ -988,4 +987,6 @@
 
     <bean id="domainIdCompleter" class="org.onosproject.cli.net.DomainIdCompleter" />
 
+    <bean id="mcastGroupCompleter" class="org.onosproject.cli.net.McastGroupCompleter"/>
+
 </blueprint>
diff --git a/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java
index 0aa1b43..00e8eab 100644
--- a/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java
+++ b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java
@@ -15,8 +15,11 @@
  */
 package org.onosproject.cfg;
 
+import com.google.common.collect.ImmutableSet;
 import org.onosproject.store.Store;
 
+import java.util.Set;
+
 /**
  * Service for storing and distributing system-wide configurations for various
  * software components.
@@ -42,4 +45,26 @@
      */
     void unsetProperty(String componentName, String name);
 
+
+    /**
+     * Returns set of component configuration property names.
+     *
+     * @param component component name
+     * @return set of property names
+     */
+    default Set<String> getProperties(String component) {
+        return ImmutableSet.of();
+    }
+
+    /**
+     * Returns the string value of the given component configuration property.
+     *
+     * @param component component name
+     * @param name      property name; null if no property found
+     * @return set of property names
+     */
+    default String getProperty(String component, String name) {
+        return null;
+    }
+
 }
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultPath.java b/core/api/src/main/java/org/onosproject/net/DefaultPath.java
index aa0b697..3fd3ece 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultPath.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultPath.java
@@ -43,26 +43,6 @@
      * @param links      contiguous links that comprise the path
      * @param cost       unit-less path cost
      * @param annotations optional key/value annotations
-     *
-     * @deprecated in Junco (1.9.0)
-     */
-    @Deprecated
-    public DefaultPath(ProviderId providerId, List<Link> links, double cost,
-                       Annotations... annotations) {
-        super(providerId, source(links), destination(links), Type.INDIRECT,
-                State.ACTIVE, annotations);
-        this.links = ImmutableList.copyOf(links);
-        this.cost = new ScalarWeight(cost);
-    }
-
-    /**
-     * Creates a path from the specified source and destination using the
-     * supplied list of links.
-     *
-     * @param providerId provider identity
-     * @param links      contiguous links that comprise the path
-     * @param cost       unit-less path cost
-     * @param annotations optional key/value annotations
      */
     public DefaultPath(ProviderId providerId, List<Link> links, Weight cost,
                        Annotations... annotations) {
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java b/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java
index 945fd5b..a3b02a8 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java
@@ -104,6 +104,14 @@
     Optional<Boolean> disableInBand();
 
     /**
+     * Returns list of Control Protocol Versions supported on device.
+     * @return List of Control Protocol Versions enabled on bridge
+     */
+    Optional<List<ControlProtocolVersion>> controlProtocols();
+
+    /**
+
+    /**
      * Builder of bridge description entities.
      */
     interface Builder {
@@ -156,6 +164,13 @@
         Builder datapathType(String datapathType);
 
         /**
+         * Returns bridge description builder with given control protocol versions.
+         * @param controlProtocols List of control protocol
+         * @return bridge description builder
+         */
+        Builder controlProtocols(List<ControlProtocolVersion> controlProtocols);
+
+        /**
          * Returns bridge description builder with in-band control disabled.
          *
          * @return bridge description builder
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/ControlProtocolVersion.java b/core/api/src/main/java/org/onosproject/net/behaviour/ControlProtocolVersion.java
new file mode 100644
index 0000000..2b5ee7c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/ControlProtocolVersion.java
@@ -0,0 +1,78 @@
+/*
+ * 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.net.behaviour;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public enum ControlProtocolVersion {
+    OF_1_0("OpenFlow10"),
+    OF_1_1("OpenFlow11"),
+    OF_1_2("OpenFlow12"),
+    OF_1_3("OpenFlow13"),
+    OF_1_4("OpenFlow14"),
+    OF_1_5("OpenFlow15");
+
+    private final String versionString;
+
+    /**
+     * Creates the enum from a string representing the control protoocol version.
+     *
+     * @param versionString the text representing the control protocol version.
+     */
+    ControlProtocolVersion(final String versionString) {
+        this.versionString = versionString;
+    }
+
+    @Override
+    public String toString() {
+        return versionString;
+    }
+
+    /**
+     * Returns a list of control protocol version string values.
+     *
+     * @return the list of string values corresponding to the enums
+     */
+    public static List<String> toStringList() {
+        return Arrays.stream(values())
+                .map(ControlProtocolVersion::toString)
+                .collect(Collectors.toCollection(ArrayList::new));
+    }
+
+    /**
+     * Alternative method to valueOf. It returns the ControlProtocolVersion type
+     * corresponding to the given string. If the parameter does not match a
+     * constant name, or is null, null is returned.
+     *
+     * @param versionString the string representing the encapsulation type
+     * @return the EncapsulationType constant corresponding to the string given
+     */
+    public static ControlProtocolVersion enumFromString(String versionString) {
+        if (versionString != null && !versionString.isEmpty()) {
+            for (ControlProtocolVersion c : values()) {
+                if (versionString.equalsIgnoreCase(c.toString())) {
+                    return c;
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java b/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java
index 1d5f550..cc0b837 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java
@@ -39,6 +39,7 @@
     private final Optional<FailMode> failMode;
     private final Optional<String> datapathId;
     private final Optional<String> datapathType;
+    private final Optional<List<ControlProtocolVersion>> controlProtocols;
     private final Optional<Boolean> disableInBand;
 
     /* Adds more configurations */
@@ -49,7 +50,8 @@
                                      Optional<FailMode> failMode,
                                      Optional<String> datapathId,
                                      Optional<String> datapathType,
-                                     Optional<Boolean> disableInBand) {
+                                     Optional<Boolean> disableInBand,
+                                     Optional<List<ControlProtocolVersion>> controlProtocols) {
         this.name = checkNotNull(name);
         this.controllers = controllers;
         this.enableLocalController = enableLocalController;
@@ -57,6 +59,7 @@
         this.datapathId = datapathId;
         this.datapathType = datapathType;
         this.disableInBand = disableInBand;
+        this.controlProtocols = controlProtocols;
     }
 
     @Override
@@ -95,6 +98,11 @@
     }
 
     @Override
+    public Optional<List<ControlProtocolVersion>> controlProtocols() {
+        return controlProtocols;
+    }
+
+    @Override
     public Optional<DeviceId> deviceId() {
         if (datapathId.isPresent()) {
             return Optional.of(DeviceId.deviceId("of:" + datapathId.get()));
@@ -125,6 +133,7 @@
         private Optional<FailMode> failMode = Optional.empty();
         private Optional<String> datapathId = Optional.empty();
         private Optional<String> datapathType = Optional.empty();
+        private Optional<List<ControlProtocolVersion>> controlProtocols = Optional.empty();
         private Optional<Boolean> disableInBand = Optional.empty();
 
         private Builder() {
@@ -137,7 +146,8 @@
                                                 failMode,
                                                 datapathId,
                                                 datapathType,
-                                                disableInBand);
+                                                disableInBand,
+                                                controlProtocols);
         }
 
         @Override
@@ -180,6 +190,12 @@
         }
 
         @Override
+        public Builder controlProtocols(List<ControlProtocolVersion> controlProtocols) {
+            this.controlProtocols = Optional.ofNullable(controlProtocols);
+            return this;
+        }
+
+        @Override
         public Builder disableInBand() {
             this.disableInBand = Optional.of(Boolean.TRUE);
             return this;
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/PortConfig.java b/core/api/src/main/java/org/onosproject/net/behaviour/PortConfig.java
deleted file mode 100644
index 031c8b6b..0000000
--- a/core/api/src/main/java/org/onosproject/net/behaviour/PortConfig.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2015-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.net.behaviour;
-
-import com.google.common.primitives.UnsignedInteger;
-import org.onosproject.net.device.PortDescription;
-import org.onosproject.net.driver.HandlerBehaviour;
-
-/**
- * Means to configure a logical port at the device.
- * @deprecated in Junco (1.9.1), use PortConfigBehaviour instead
- */
-@Deprecated
-public interface PortConfig extends HandlerBehaviour {
-
-    /**
-     * Apply QoS configuration on a device.
-     * @param port a port description
-     * @param queueId an unsigned integer
-     */
-    void applyQoS(PortDescription port, UnsignedInteger queueId);
-
-    /**
-     * Remove a QoS configuration.
-     * @param port a port description
-     */
-    void removeQoS(PortDescription port);
-
-}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/PortDiscovery.java b/core/api/src/main/java/org/onosproject/net/behaviour/PortDiscovery.java
deleted file mode 100644
index 1e09c53..0000000
--- a/core/api/src/main/java/org/onosproject/net/behaviour/PortDiscovery.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016-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.net.behaviour;
-
-import org.onosproject.net.device.PortDescription;
-import org.onosproject.net.driver.HandlerBehaviour;
-
-import java.util.List;
-
-/**
- * Discovers the set of ports from a device through a device specific protocol.
- * The returned ports are not retrieved from the information stored in ONOS.
- *
- * @deprecated 1.6.0 Goldeneye. Use DeviceDescriptionDiscovery instead
- */
-@Deprecated
-public interface PortDiscovery extends HandlerBehaviour {
-
-    /**
-     * Retrieves the set of ports from a device.
-     *
-     * @return a set of port descriptions.
-     * @deprecated 1.6.0 Goldeneye. Use DeviceDescriptionDiscovery instead
-     */
-    @Deprecated
-    List<PortDescription> getPorts();
-}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/QueueConfig.java b/core/api/src/main/java/org/onosproject/net/behaviour/QueueConfig.java
deleted file mode 100644
index 550f3c5..0000000
--- a/core/api/src/main/java/org/onosproject/net/behaviour/QueueConfig.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2015-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.net.behaviour;
-
-import com.google.common.primitives.UnsignedInteger;
-
-import java.util.Set;
-
-/**
- * Means to alter a device's dataplane queues.
- * @deprecated in Junco (1.9.1), use QueueConfigBehaviour instead
- */
-@Deprecated
-public interface QueueConfig {
-
-    /**
-     * Obtain all queues configured on a device.
-     *
-     * @return a list of queue descriptions
-     */
-    Set<QueueInfo> getQueues();
-
-    /**
-     * Obtain a specific queue given a queue id.
-     *
-     * @param queueId an unsigned integer representing a queue id
-     * @return a queue description
-     */
-    QueueInfo getQueue(UnsignedInteger queueId);
-
-    /**
-     * Add a queue to a device.
-     *
-     * @param queue a queue description
-     */
-    void addQueue(QueueInfo queue);
-
-    /**
-     * Remove a queue from a device.
-     *
-     * @param queueId an unsigned integer
-     */
-    void removeQueue(UnsignedInteger queueId);
-
-}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/QueueInfo.java b/core/api/src/main/java/org/onosproject/net/behaviour/QueueInfo.java
deleted file mode 100644
index 8a92b98..0000000
--- a/core/api/src/main/java/org/onosproject/net/behaviour/QueueInfo.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2015-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.net.behaviour;
-
-import com.google.common.primitives.UnsignedInteger;
-
-/**
- * @deprecated in Junco Release (1.9.1), Use QueueDescription instead
- * {@link org.onosproject.net.behaviour.QueueDescription}
- */
-@Deprecated
-public class QueueInfo {
-
-    public enum Type {
-        /**
-         * Supports burst and priority as well as min and max rates.
-         */
-        FULL,
-
-        /**
-         * Only support min and max rates.
-         */
-        MINMAX
-    }
-
-    private final UnsignedInteger queueId;
-    private final Type type;
-    private final long minRate;
-    private final long maxRate;
-    private final long burst;
-    private final long priority;
-
-    public QueueInfo(UnsignedInteger queueId, Type type, long minRate,
-                     long maxRate, long burst, long priority) {
-        this.queueId = queueId;
-        this.type = type;
-        this.minRate = minRate;
-        this.maxRate = maxRate;
-        this.burst = burst;
-        this.priority = priority;
-    }
-
-    //TODO builder
-    // public static QueueInfoBuilder builder() {}
-}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/UnresolvedExtensionTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/UnresolvedExtensionTreatment.java
index 6c4a8c2..a7c5042 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/UnresolvedExtensionTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/UnresolvedExtensionTreatment.java
@@ -41,7 +41,7 @@
 
     @Override
     public ExtensionTreatmentType type() {
-        return ExtensionTreatmentType.ExtensionTreatmentTypes.UNRESOLVED_TYPE.type();
+        return unresolvedTreatmentType;
     }
 
     @Override
diff --git a/core/api/src/main/java/org/onosproject/net/intent/IntentUtils.java b/core/api/src/main/java/org/onosproject/net/intent/IntentUtils.java
index fb5fb34..1f1f894 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/IntentUtils.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/IntentUtils.java
@@ -77,8 +77,10 @@
             return Objects.equals(intent1.selector(), intent2.selector()) &&
                     Objects.equals(intent1.treatment(), intent2.treatment()) &&
                     Objects.equals(intent1.constraints(), intent2.constraints()) &&
-                    Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) &&
-                    Objects.equals(intent1.egressPoint(), intent2.egressPoint());
+                    Objects.equals(intent1.filteredIngressPoint().connectPoint(),
+                            intent2.filteredIngressPoint().connectPoint()) &&
+                    Objects.equals(intent1.filteredEgressPoint().connectPoint(),
+                            intent2.filteredEgressPoint().connectPoint());
         } else {
             log.error("Unimplemented intent type");
             return false;
diff --git a/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java b/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java
index 4b191ea..1a38bfd 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java
@@ -15,18 +15,16 @@
  */
 package org.onosproject.net.intent;
 
-import java.util.Collections;
-import java.util.List;
-
 import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
 import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.ResourceGroup;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 
-import com.google.common.base.MoreObjects;
+import java.util.Collections;
+import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -99,30 +97,6 @@
         }
 
         /**
-         * Sets the ingress point of the point to point intent that will be built.
-         *
-         * @param ingressPoint ingress connect point
-         * @return this builder
-         */
-        @Deprecated
-        public Builder ingressPoint(ConnectPoint ingressPoint) {
-            this.ingressPoint = new FilteredConnectPoint(ingressPoint);
-            return this;
-        }
-
-        /**
-         * Sets the egress point of the point to point intent that will be built.
-         *
-         * @param egressPoint egress connect point
-         * @return this builder
-         */
-        @Deprecated
-        public Builder egressPoint(ConnectPoint egressPoint) {
-            this.egressPoint = new FilteredConnectPoint(egressPoint);
-            return this;
-        }
-
-        /**
          * Sets the filtered ingress point of the point to
          * point intent that will be built.
          *
@@ -213,27 +187,6 @@
     }
 
     /**
-     * Returns the port on which the ingress traffic should be connected to
-     * the egress.
-     *
-     * @return ingress port
-     */
-    @Deprecated
-    public ConnectPoint ingressPoint() {
-        return ingressPoint.connectPoint();
-    }
-
-    /**
-     * Returns the port on which the traffic should egress.
-     *
-     * @return egress port
-     */
-    @Deprecated
-    public ConnectPoint egressPoint() {
-        return egressPoint.connectPoint();
-    }
-
-    /**
      * Returns the filtered port on which the ingress traffic should be connected to the
      * egress.
      *
diff --git a/core/api/src/main/java/org/onosproject/net/topology/AbstractPathService.java b/core/api/src/main/java/org/onosproject/net/topology/AbstractPathService.java
index 7c831e7..cf9a531 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/AbstractPathService.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/AbstractPathService.java
@@ -42,7 +42,6 @@
 import java.util.stream.Stream;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 
 /**
  * Helper class for path service.
@@ -60,18 +59,13 @@
     private static final PortNumber P0 = PortNumber.portNumber(0);
 
     protected static final LinkWeigher DEFAULT_WEIGHER =
-            adapt(new HopCountLinkWeight());
+            new HopCountLinkWeigher();
 
     protected TopologyService topologyService;
 
     protected HostService hostService;
 
     @Override
-    public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
-        return getPaths(src, dst, adapt(weight));
-    }
-
-    @Override
     public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
         checkNotNull(src, ELEMENT_ID_NULL);
         checkNotNull(dst, ELEMENT_ID_NULL);
@@ -140,11 +134,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) {
-        return getDisjointPaths(src, dst, adapt(weight));
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
         checkNotNull(src, ELEMENT_ID_NULL);
         checkNotNull(dst, ELEMENT_ID_NULL);
@@ -179,12 +168,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight,
-                                              Map<Link, Object> riskProfile) {
-        return getDisjointPaths(src, dst, adapt(weight), riskProfile);
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
                                               LinkWeigher weigher, Map<Link, Object> riskProfile) {
         checkNotNull(src, ELEMENT_ID_NULL);
diff --git a/core/api/src/main/java/org/onosproject/net/topology/AdapterLinkWeigher.java b/core/api/src/main/java/org/onosproject/net/topology/AdapterLinkWeigher.java
deleted file mode 100644
index 70260e3..0000000
--- a/core/api/src/main/java/org/onosproject/net/topology/AdapterLinkWeigher.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016-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.net.topology;
-
-import org.onlab.graph.DefaultEdgeWeigher;
-import org.onlab.graph.ScalarWeight;
-import org.onlab.graph.Weight;
-
-/**
- * Wrapper which transforms double-based link weigher to {@link Weight}-based
- * link weigher.
- */
-public final class AdapterLinkWeigher
-        extends DefaultEdgeWeigher<TopologyVertex, TopologyEdge>
-        implements LinkWeigher {
-
-    private final LinkWeight doubleWeigher;
-
-    private AdapterLinkWeigher(LinkWeight doubleWeigher) {
-        this.doubleWeigher = doubleWeigher;
-    }
-
-    @Override
-    public Weight weight(TopologyEdge edge) {
-        return new ScalarWeight(doubleWeigher.weight(edge));
-    }
-
-    /**
-     * Transforms double-based link weigher to {@link Weight}-based weigher.
-     *
-     * @param lw double-based weigher
-     * @return {@link Weight}-based weigher
-     */
-    public static LinkWeigher adapt(LinkWeight lw) {
-        return lw == null ? null : new AdapterLinkWeigher(lw);
-    }
-}
diff --git a/core/api/src/main/java/org/onosproject/net/topology/GeoDistanceLinkWeight.java b/core/api/src/main/java/org/onosproject/net/topology/GeoDistanceLinkWeight.java
index f30fc80..9d22b84 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/GeoDistanceLinkWeight.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/GeoDistanceLinkWeight.java
@@ -16,6 +16,8 @@
 
 package org.onosproject.net.topology;
 
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onlab.util.GeoLocation;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.Annotations;
@@ -29,7 +31,7 @@
  * Link weight for measuring link cost using the geo distance between link
  * vertices as determined by the element longitude/latitude annotation.
  */
-public class GeoDistanceLinkWeight implements LinkWeight {
+public class GeoDistanceLinkWeight implements LinkWeigher {
 
     private static final double MAX_KM = 40_075 / 2.0;
 
@@ -45,10 +47,20 @@
     }
 
     @Override
-    public double weight(TopologyEdge edge) {
+    public Weight getInitialWeight() {
+        return ScalarWeight.toWeight(0.0);
+    }
+
+    @Override
+    public Weight getNonViableWeight() {
+        return ScalarWeight.NON_VIABLE_WEIGHT;
+    }
+
+    @Override
+    public Weight weight(TopologyEdge edge) {
         GeoLocation src = getLocation(edge.link().src().deviceId());
         GeoLocation dst = getLocation(edge.link().dst().deviceId());
-        return src != null && dst != null ? src.kilometersTo(dst) : MAX_KM;
+        return ScalarWeight.toWeight(src != null && dst != null ? src.kilometersTo(dst) : MAX_KM);
     }
 
     private GeoLocation getLocation(DeviceId deviceId) {
diff --git a/core/api/src/main/java/org/onosproject/net/topology/HopCountLinkWeight.java b/core/api/src/main/java/org/onosproject/net/topology/HopCountLinkWeight.java
deleted file mode 100644
index 885cd67..0000000
--- a/core/api/src/main/java/org/onosproject/net/topology/HopCountLinkWeight.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2015-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.net.topology;
-
-import static org.onosproject.net.Link.State.ACTIVE;
-import static org.onosproject.net.Link.Type.INDIRECT;
-
-/**
- * Link weight for measuring link cost as hop count with indirect links
- * being as expensive as traversing the entire graph to assume the worst.
- */
-public class HopCountLinkWeight implements LinkWeight {
-    private final int indirectLinkCost;
-
-    /**
-     * Creates a new hop-count weight.
-     */
-    public HopCountLinkWeight() {
-        this.indirectLinkCost = Short.MAX_VALUE;
-    }
-
-    /**
-     * Creates a new hop-count weight with the specified cost of indirect links.
-     *
-     * @param indirectLinkCost indirect link cost
-     */
-    public HopCountLinkWeight(int indirectLinkCost) {
-        this.indirectLinkCost = indirectLinkCost;
-    }
-
-    @Override
-    public double weight(TopologyEdge edge) {
-        // To force preference to use direct paths first, make indirect
-        // links as expensive as the linear vertex traversal.
-        return edge.link().state() ==
-                ACTIVE ? (edge.link().type() ==
-                INDIRECT ? indirectLinkCost : 1) : -1;
-    }
-}
-
diff --git a/core/api/src/main/java/org/onosproject/net/topology/LinkWeight.java b/core/api/src/main/java/org/onosproject/net/topology/LinkWeight.java
deleted file mode 100644
index 944c843..0000000
--- a/core/api/src/main/java/org/onosproject/net/topology/LinkWeight.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2014-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.net.topology;
-
-/**
- * Entity capable of determining cost or weight of a specified topology
- * graph edge.
- * @deprecated in Junco (1.9.0), use {@link LinkWeigher} instead
- */
-@Deprecated
-public interface LinkWeight {
-
-    /**
-     * Returns the weight of the given edge.
-     *
-     * @param edge edge to be weighed
-     * @return edge weight
-     */
-    double weight(TopologyEdge edge);
-}
diff --git a/core/api/src/main/java/org/onosproject/net/topology/MetricLinkWeight.java b/core/api/src/main/java/org/onosproject/net/topology/MetricLinkWeight.java
index e24ea4a..e87f660 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/MetricLinkWeight.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/MetricLinkWeight.java
@@ -16,20 +16,32 @@
 
 package org.onosproject.net.topology;
 
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onosproject.net.AnnotationKeys;
 
 /**
  * Link weight for measuring link cost using the link metric annotation.
  */
-public class MetricLinkWeight implements LinkWeight {
+public class MetricLinkWeight implements LinkWeigher {
 
     @Override
-    public double weight(TopologyEdge edge) {
+    public Weight getInitialWeight() {
+        return ScalarWeight.toWeight(0.0);
+    }
+
+    @Override
+    public Weight getNonViableWeight() {
+        return ScalarWeight.NON_VIABLE_WEIGHT;
+    }
+
+    @Override
+    public Weight weight(TopologyEdge edge) {
         String v = edge.link().annotations().value(AnnotationKeys.METRIC);
         try {
-            return v != null ? Double.parseDouble(v) : 1;
+            return ScalarWeight.toWeight(v != null ? Double.parseDouble(v) : 1);
         } catch (NumberFormatException e) {
-            return 1;
+            return ScalarWeight.toWeight(1.0);
         }
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java b/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java
index fed0651..fb67c91 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/PathAdminService.java
@@ -28,18 +28,6 @@
      * If null is specified, the builtin default hop-count link-weight will be
      * used.
      *
-     * @param linkWeight default link-weight function
-     *
-     * @deprecated in Junco (1.9.0), use setDefaultLinkWeigher() instead
-     */
-    @Deprecated
-    void setDefaultLinkWeight(LinkWeight linkWeight);
-
-    /**
-     * Sets the specified link-weight function to be used as a default.
-     * If null is specified, the builtin default hop-count link-weight will be
-     * used.
-     *
      * @param linkWeigher link-weight function to be used as default
      */
     void setDefaultLinkWeigher(LinkWeigher linkWeigher);
diff --git a/core/api/src/main/java/org/onosproject/net/topology/PathService.java b/core/api/src/main/java/org/onosproject/net/topology/PathService.java
index ae2de8b..73f0149 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/PathService.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/PathService.java
@@ -48,21 +48,6 @@
      * destination network elements.  The path is computed using the supplied
      * edge-weight function.
      *
-     * @param src    source element
-     * @param dst    destination element
-     * @param weight edge-weight entity
-     * @return set of all shortest paths between the two element
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight);
-
-    /**
-     * Returns the set of all shortest paths between the specified source and
-     * destination network elements.  The path is computed using the supplied
-     * edge-weight function.
-     *
      * @param src     source element
      * @param dst     destination element
      * @param weigher edge-weight entity
@@ -113,22 +98,6 @@
      * specified source and destination elements. The path is computed using
      * the supplied edge-weight function.
      *
-     * @param src    source device
-     * @param dst    destination device
-     * @param weight edge-weight entity
-     * @return set of all shortest paths between the two devices
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
-                                       LinkWeight weight);
-
-    /**
-     * Returns the set of all disjoint shortest path pairs between the
-     * specified source and destination elements. The path is computed using
-     * the supplied edge-weight function.
-     *
      * @param src     source device
      * @param dst     destination device
      * @param weigher edge-weight entity
@@ -159,25 +128,6 @@
      *
      * @param src         source device
      * @param dst         destination device
-     * @param weight      edge-weight entity
-     * @param riskProfile map of edges to risk profiles
-     * @return set of all shortest paths between the two devices
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
-                                       LinkWeight weight,
-                                       Map<Link, Object> riskProfile);
-
-    /**
-     * Returns the set of all disjoint shortest path pairs between the
-     * specified source and destination elements and taking into consideration
-     * the provided risk profile. The path is computed using the supplied
-     * edge-weight function.
-     *
-     * @param src         source device
-     * @param dst         destination device
      * @param weigher     edge-weight entity
      * @param riskProfile map of edges to risk profiles
      * @return set of all shortest paths between the two devices
diff --git a/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java b/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
index 6d95a97..ee70ed7 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java
@@ -111,22 +111,6 @@
      * @param topology topology descriptor
      * @param src      source device
      * @param dst      destination device
-     * @param weight   edge-weight entity
-     * @return set of all shortest paths between the two devices
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
-                       LinkWeight weight);
-
-    /**
-     * Returns the set of all shortest paths, computed using the supplied
-     * edge-weight entity, between the specified source and destination devices.
-     *
-     * @param topology topology descriptor
-     * @param src      source device
-     * @param dst      destination device
      * @param weigher  edge-weight entity
      * @return set of all shortest paths between the two devices
      */
@@ -204,22 +188,6 @@
      * @param topology topology descriptor
      * @param src      source device
      * @param dst      destination device
-     * @param weight   edge-weight entity
-     * @return set of all shortest paths between the two devices
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                       LinkWeight weight);
-
-    /**
-     * Returns the set of all disjoint shortest path pairs, computed using the supplied
-     * edge-weight entity, between the specified source and destination devices.
-     *
-     * @param topology topology descriptor
-     * @param src      source device
-     * @param dst      destination device
      * @param weigher  edge-weight entity
      * @return set of all shortest paths between the two devices
      */
@@ -246,23 +214,6 @@
      * @param topology    topology descriptor
      * @param src         source device
      * @param dst         destination device
-     * @param weight      edge-weight entity
-     * @param riskProfile map of edges to risk profiles
-     * @return set of all shortest paths between the two devices
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                       LinkWeight weight, Map<Link, Object> riskProfile);
-
-    /**
-     * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count,
-     * between the specified source and destination devices.
-     *
-     * @param topology    topology descriptor
-     * @param src         source device
-     * @param dst         destination device
      * @param weigher     edge-weight entity
      * @param riskProfile map of edges to risk profiles
      * @return set of all shortest paths between the two devices
diff --git a/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java b/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java
index 99838c6..17957e1 100644
--- a/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java
+++ b/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java
@@ -109,21 +109,6 @@
      * @param topology topology descriptor
      * @param src      source device
      * @param dst      destination device
-     * @param weight   link weight function
-     * @return set of shortest paths
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
-                       LinkWeight weight);
-
-    /**
-     * Computes and returns the set of shortest paths between src and dest.
-     *
-     * @param topology topology descriptor
-     * @param src      source device
-     * @param dst      destination device
      * @param weigher  link weight function
      * @return set of shortest paths
      */
@@ -176,22 +161,6 @@
      * @param topology topology descriptor
      * @param src      source device
      * @param dst      destination device
-     * @param weight   link weight function
-     * @return set of shortest paths
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                       LinkWeight weight);
-
-    /**
-     * Computes and returns the set of disjoint shortest path pairs
-     * between src and dst.
-     *
-     * @param topology topology descriptor
-     * @param src      source device
-     * @param dst      destination device
      * @param weigher  link weight function
      * @return set of shortest paths
      */
@@ -216,24 +185,6 @@
      * @param topology    topology descriptor
      * @param src         source device
      * @param dst         destination device
-     * @param weight      link weight function
-     * @param riskProfile map of edges to objects. Edges that map to the same object will
-     * be treated as if they were in the same risk group.
-     * @return set of shortest paths
-     *
-     * @deprecated in Junco (1.9.0), use version with LinkWeigher instead
-     */
-    @Deprecated
-    Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                       LinkWeight weight, Map<Link, Object> riskProfile);
-
-    /**
-     * Computes and returns the set of SRLG disjoint shortest path pairs between source
-     * and dst, given a mapping of edges to SRLG risk groups.
-     *
-     * @param topology    topology descriptor
-     * @param src         source device
-     * @param dst         destination device
      * @param weigher     link weight function
      * @param riskProfile map of edges to objects. Edges that map to the same object will
      * be treated as if they were in the same risk group.
diff --git a/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java b/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java
index ed5de9f..25caabe 100644
--- a/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java
+++ b/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java
@@ -125,9 +125,38 @@
      * @return {@code DocumentPath} instance
      */
     public static DocumentPath from(List<String> elements, String child) {
-        elements = new ArrayList<>(elements);
-        elements.add(child);
-        return from(elements);
+        List<String> concat = new ArrayList<>(elements.size() + 1);
+        concat.addAll(elements);
+        concat.add(child);
+        return from(concat);
+    }
+
+    /**
+     * Creates a new {@code DocumentPath} from a list of path elements.
+     *
+     * @param elements path elements
+     * @param childElms child element
+     * @return {@code DocumentPath} instance
+     */
+    public static DocumentPath from(List<String> elements, String... childElms) {
+        List<String> concat = new ArrayList<>(elements.size() + childElms.length);
+        concat.addAll(elements);
+        concat.addAll(Arrays.asList(childElms));
+        return from(concat);
+    }
+
+    /**
+     * Creates a new DocumentPath element appending {@code childElm} to
+     * this path.
+     *
+     * @param childElms to append
+     * @return this + childElm
+     */
+    public DocumentPath append(List<String> childElms) {
+        List<String> concat = new ArrayList<>(pathElements.size() + childElms.size());
+        concat.addAll(pathElements);
+        concat.addAll(childElms);
+        return from(concat);
     }
 
     /**
@@ -172,7 +201,8 @@
      * @return {@code true} is yes; {@code false} otherwise.
      */
     public boolean isAncestorOf(DocumentPath other) {
-        return this.pathElements.size() < other.pathElements.size() &&
+        return other != null &&
+               this.pathElements.size() < other.pathElements.size() &&
                this.pathElements.equals(other.pathElements.subList(0, this.pathElements.size()));
     }
 
@@ -186,7 +216,8 @@
      * @return {@code true} is yes; {@code false} otherwise.
      */
     public boolean isDescendentOf(DocumentPath other) {
-        return other.equals(this) || other.isAncestorOf(this);
+        return other != null &&
+               (other.equals(this) || other.isAncestorOf(this));
     }
 
     /**
diff --git a/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java b/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java
index 3794af2..4764412 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java
@@ -59,4 +59,9 @@
      * @return the navigation localization bundle
      */
     LionBundle getNavLionBundle();
+
+    /**
+     * Refreshes the backing model.
+     */
+    void refreshModel();
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/lion/LionBundle.java b/core/api/src/main/java/org/onosproject/ui/lion/LionBundle.java
index 56fc4bc..619b99c 100644
--- a/core/api/src/main/java/org/onosproject/ui/lion/LionBundle.java
+++ b/core/api/src/main/java/org/onosproject/ui/lion/LionBundle.java
@@ -17,6 +17,7 @@
 
 package org.onosproject.ui.lion;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.ImmutableSortedSet;
 
@@ -206,6 +207,24 @@
             return key.compareTo(o.key);
         }
 
+        @Override
+        public boolean equals(Object obj) {
+
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final LionBundle.LionItem that = (LionBundle.LionItem) obj;
+            return Objects.equal(this.key, that.key);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(this.key);
+        }
+
         /**
          * Returns the key.
          *
diff --git a/core/api/src/test/java/org/onosproject/net/DefaultDisjointPathTest.java b/core/api/src/test/java/org/onosproject/net/DefaultDisjointPathTest.java
index ec62814..5c30c57 100644
--- a/core/api/src/test/java/org/onosproject/net/DefaultDisjointPathTest.java
+++ b/core/api/src/test/java/org/onosproject/net/DefaultDisjointPathTest.java
@@ -21,6 +21,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.testing.EqualsTester;
+import org.onlab.graph.ScalarWeight;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -53,15 +54,15 @@
 
     private static List<Link> links1 = ImmutableList.of(link1, link2);
     private static DefaultPath path1 =
-            new DefaultPath(PID, links1, 1.0);
+            new DefaultPath(PID, links1, ScalarWeight.toWeight(1.0));
 
     private static List<Link> links2 = ImmutableList.of(link2, link1);
     private static DefaultPath path2 =
-            new DefaultPath(PID, links2, 2.0);
+            new DefaultPath(PID, links2, ScalarWeight.toWeight(2.0));
 
     private static List<Link> links3 = ImmutableList.of(link1, link2, link3);
     private static DefaultPath path3 =
-            new DefaultPath(PID, links3, 3.0);
+            new DefaultPath(PID, links3, ScalarWeight.toWeight(3.0));
 
     private static DefaultDisjointPath disjointPath1 =
             new DefaultDisjointPath(PID, path1, path2);
diff --git a/core/api/src/test/java/org/onosproject/net/NetTestTools.java b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
index 8f161fc..dcc3e15 100644
--- a/core/api/src/test/java/org/onosproject/net/NetTestTools.java
+++ b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
@@ -16,6 +16,7 @@
 package org.onosproject.net;
 
 import com.google.common.collect.ImmutableList;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.junit.TestUtils;
 import org.onlab.packet.ChassisId;
 import org.onlab.packet.IpPrefix;
@@ -130,7 +131,7 @@
         for (int i = 0; i < ids.length - 1; i++) {
             links.add(link(ids[i], 2, ids[i + 1], 1));
         }
-        return new DefaultPath(PID, links, ids.length);
+        return new DefaultPath(PID, links, ScalarWeight.toWeight(ids.length));
     }
 
     // Creates a path that leads through the given hosts.
@@ -145,7 +146,7 @@
                 links.add(link(ids[i], 2, ids[i + 1], 1));
             }
         }
-        return new DefaultPath(PID, links, ids.length);
+        return new DefaultPath(PID, links, ScalarWeight.toWeight(ids.length));
     }
 
     // Creates OCh signal
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index 59aad9c..48b4a87 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -17,6 +17,7 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.Sets;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.graph.Weight;
 import org.onosproject.core.GroupId;
 import org.onosproject.net.DefaultPath;
@@ -290,7 +291,7 @@
             } else {
                 return result;
             }
-            path = new DefaultPath(providerId, links, 3);
+            path = new DefaultPath(providerId, links, ScalarWeight.toWeight(3));
             result.add(path);
 
             return result;
diff --git a/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java b/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java
index e55f21f..ec1fc1a 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java
@@ -19,6 +19,7 @@
 import java.util.Collections;
 
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultLink;
 import org.onosproject.net.DefaultPath;
@@ -133,7 +134,7 @@
                 .appId(APPID)
                 .selector(MATCH)
                 .treatment(NOP)
-                .path(new DefaultPath(provider1, Collections.singletonList(link1), cost))
+                .path(new DefaultPath(provider1, Collections.singletonList(link1), ScalarWeight.toWeight(cost)))
                 .build();
     }
 
@@ -147,7 +148,7 @@
                 .appId(APPID)
                 .selector(MATCH)
                 .treatment(NOP)
-                .path(new DefaultPath(provider1, Arrays.asList(link1, link2), cost))
+                .path(new DefaultPath(provider1, Arrays.asList(link1, link2), ScalarWeight.toWeight(cost)))
                 .build();
     }
 
diff --git a/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java b/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
index 02bfad6..3b170a0 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.intent;
 
 import org.junit.Test;
+import org.onosproject.net.FilteredConnectPoint;
 
 import static org.junit.Assert.assertEquals;
 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass;
@@ -38,14 +39,14 @@
         PointToPointIntent intent = createOne();
         assertEquals("incorrect id", APPID, intent.appId());
         assertEquals("incorrect match", MATCH, intent.selector());
-        assertEquals("incorrect ingress", P1, intent.ingressPoint());
-        assertEquals("incorrect egress", P2, intent.egressPoint());
+        assertEquals("incorrect ingress", P1, intent.filteredIngressPoint().connectPoint());
+        assertEquals("incorrect egress", P2, intent.filteredEgressPoint().connectPoint());
 
         intent = createWithResourceGroup();
         assertEquals("incorrect id", APPID, intent.appId());
         assertEquals("incorrect match", MATCH, intent.selector());
-        assertEquals("incorrect ingress", P1, intent.ingressPoint());
-        assertEquals("incorrect egress", P2, intent.egressPoint());
+        assertEquals("incorrect ingress", P1, intent.filteredIngressPoint().connectPoint());
+        assertEquals("incorrect egress", P2, intent.filteredEgressPoint().connectPoint());
         assertEquals("incorrect resource group", RESOURCE_GROUP, intent.resourceGroup());
     }
 
@@ -64,8 +65,8 @@
                 .appId(APPID)
                 .selector(MATCH)
                 .treatment(NOP)
-                .ingressPoint(P1)
-                .egressPoint(P2)
+                .filteredIngressPoint(new FilteredConnectPoint(P1))
+                .filteredEgressPoint(new FilteredConnectPoint(P2))
                 .build();
     }
 
@@ -74,8 +75,8 @@
                 .appId(APPID)
                 .selector(MATCH)
                 .treatment(NOP)
-                .ingressPoint(P1)
-                .egressPoint(P2)
+                .filteredIngressPoint(new FilteredConnectPoint(P1))
+                .filteredEgressPoint(new FilteredConnectPoint(P2))
                 .resourceGroup(RESOURCE_GROUP)
                 .build();
     }
@@ -86,8 +87,8 @@
                 .appId(APPID)
                 .selector(MATCH)
                 .treatment(NOP)
-                .ingressPoint(P2)
-                .egressPoint(P1)
+                .filteredIngressPoint(new FilteredConnectPoint(P2))
+                .filteredEgressPoint(new FilteredConnectPoint(P1))
                 .build();
     }
 
diff --git a/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java b/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java
index b035ee4..eada7bf 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java
@@ -18,6 +18,7 @@
 import com.google.common.testing.EqualsTester;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onosproject.net.Annotations;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DefaultLink;
@@ -83,7 +84,7 @@
                 .type(DIRECT)
                 .annotations(annotations2)
                 .build();
-        path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), 10);
+        path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), ScalarWeight.toWeight(10));
     }
 
     /**
diff --git a/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java b/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java
index 359555b..29e7c98 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java
@@ -22,6 +22,7 @@
 import com.google.common.testing.EqualsTester;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.onosproject.net.DefaultAnnotations;
@@ -100,9 +101,9 @@
         edgelink1 = createEdgeLink(host1, true);
         edgelink2 = createEdgeLink(host2, false);
 
-        path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), 10);
+        path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), ScalarWeight.toWeight(10));
         pathWithEdgeLink = new DefaultPath(PROVIDER_ID,
-                Arrays.asList(edgelink1, link1, link2, edgelink2), 10);
+                Arrays.asList(edgelink1, link1, link2, edgelink2), ScalarWeight.toWeight(10));
     }
 
     @Test
diff --git a/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java b/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java
index ffe96cd..060607b 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java
@@ -18,6 +18,7 @@
 import com.google.common.testing.EqualsTester;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onosproject.net.DefaultLink;
 import org.onosproject.net.DefaultPath;
 import org.onosproject.net.DeviceId;
@@ -75,7 +76,7 @@
                 .type(DIRECT)
                 .build();
 
-        path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), 10);
+        path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), ScalarWeight.toWeight(10));
     }
 
     /**
diff --git a/core/api/src/test/java/org/onosproject/net/topology/LinkWeigherAdapter.java b/core/api/src/test/java/org/onosproject/net/topology/LinkWeigherAdapter.java
new file mode 100644
index 0000000..bf3f934
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/topology/LinkWeigherAdapter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018-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.net.topology;
+
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
+
+public class LinkWeigherAdapter implements LinkWeigher {
+    final double weight;
+
+    public LinkWeigherAdapter(Double weight) {
+        this.weight = weight;
+    }
+    @Override
+    public Weight weight(TopologyEdge edge) {
+        return ScalarWeight.toWeight(weight);
+    }
+
+    @Override
+    public Weight getInitialWeight() {
+        return ScalarWeight.toWeight(0.0);
+    }
+
+    @Override
+    public Weight getNonViableWeight() {
+        return ScalarWeight.toWeight(0.0);
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java
index 1e18030..86a9405 100644
--- a/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java
@@ -33,11 +33,6 @@
     }
 
     @Override
-    public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
-        return null;
-    }
-
-    @Override
     public Set<Path> getPaths(ElementId src, ElementId dst,
                               LinkWeigher weigher) {
         return null;
@@ -50,12 +45,6 @@
 
     @Override
     public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
-                                              LinkWeight weight) {
-        return null;
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
                                               LinkWeigher weigher) {
         return null;
     }
@@ -68,13 +57,6 @@
 
     @Override
     public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
-                                              LinkWeight weight,
-                                              Map<Link, Object> riskProfile) {
-        return null;
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
                                               LinkWeigher weigher,
                                               Map<Link, Object> riskProfile) {
         return null;
diff --git a/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java
index a3266fb..b75dbb0 100644
--- a/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java
@@ -72,12 +72,6 @@
 
     @Override
     public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
-                              LinkWeight weight) {
-        return null;
-    }
-
-    @Override
-    public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
                               LinkWeigher weigher) {
         return null;
     }
@@ -111,13 +105,6 @@
     @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst,
-                                              LinkWeight weight) {
-        return null;
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
-                                              DeviceId dst,
                                               LinkWeigher weigher) {
         return null;
     }
@@ -131,13 +118,6 @@
 
     @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
-                                              DeviceId dst, LinkWeight weight,
-                                              Map<Link, Object> riskProfile) {
-        return null;
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst,
                                               LinkWeigher weigher,
                                               Map<Link, Object> riskProfile) {
diff --git a/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java b/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java
index 19c34bd..431f58f 100644
--- a/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java
+++ b/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java
@@ -60,6 +60,9 @@
         assertTrue(path3.isDescendentOf(path3));
         assertTrue(path3.isDescendentOf(path1));
         assertFalse(path3.isDescendentOf(path2));
+
+        assertFalse(path.isDescendentOf(null));
+        assertFalse(path.isAncestorOf(null));
     }
 
     @Rule
diff --git a/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java b/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java
index 673a531..4e25f4d 100644
--- a/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java
+++ b/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java
@@ -184,7 +184,9 @@
 
     @Override
     public void clear() {
-        map.keySet().forEach(this::remove);
+        for (K key : map.keySet().stream().collect(Collectors.toList())) {
+            remove(key);
+        }
     }
 
     @Override
diff --git a/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java b/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java
index 8a246dc..93bcf9f 100644
--- a/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java
@@ -45,4 +45,8 @@
     public LionBundle getNavLionBundle() {
         return null;
     }
+
+    @Override
+    public void refreshModel() {
+    }
 }
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java
index f9e7ebc..eb5305e 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java
@@ -18,6 +18,7 @@
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.intent.ConnectivityIntent;
 import org.onosproject.net.intent.PointToPointIntent;
 
@@ -45,9 +46,9 @@
         final JsonCodec<ConnectPoint> connectPointCodec =
                 context.codec(ConnectPoint.class);
         final ObjectNode ingress =
-                connectPointCodec.encode(intent.ingressPoint(), context);
+                connectPointCodec.encode(intent.filteredIngressPoint().connectPoint(), context);
         final ObjectNode egress =
-                connectPointCodec.encode(intent.egressPoint(), context);
+                connectPointCodec.encode(intent.filteredEgressPoint().connectPoint(), context);
 
         result.set(INGRESS_POINT, ingress);
         result.set(EGRESS_POINT, egress);
@@ -67,13 +68,13 @@
                 INGRESS_POINT + IntentCodec.MISSING_MEMBER_MESSAGE);
         ConnectPoint ingress = context.codec(ConnectPoint.class)
                 .decode(ingressJson, context);
-        builder.ingressPoint(ingress);
+        builder.filteredIngressPoint(new FilteredConnectPoint(ingress));
 
         ObjectNode egressJson = nullIsIllegal(get(json, EGRESS_POINT),
                 EGRESS_POINT + IntentCodec.MISSING_MEMBER_MESSAGE);
         ConnectPoint egress = context.codec(ConnectPoint.class)
                 .decode(egressJson, context);
-        builder.egressPoint(egress);
+        builder.filteredEgressPoint(new FilteredConnectPoint(egress));
 
         return builder.build();
     }
diff --git a/core/common/src/main/java/org/onosproject/common/DefaultTopology.java b/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
index 4b266a8..ecbb573 100644
--- a/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
+++ b/core/common/src/main/java/org/onosproject/common/DefaultTopology.java
@@ -49,7 +49,7 @@
 import org.onosproject.net.topology.DefaultTopologyCluster;
 import org.onosproject.net.topology.DefaultTopologyVertex;
 import org.onosproject.net.topology.GraphDescription;
-import org.onosproject.net.topology.HopCountLinkWeight;
+import org.onosproject.net.topology.HopCountLinkWeigher;
 import org.onosproject.net.topology.LinkWeigher;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyCluster;
@@ -73,7 +73,6 @@
 import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
 import static org.onosproject.net.Link.State.INACTIVE;
 import static org.onosproject.net.Link.Type.INDIRECT;
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 
 /**
  * Default implementation of the topology descriptor. This carries the backing
@@ -160,7 +159,7 @@
 
         this.clusterIndexes = Suppliers.memoize(this::buildIndexes);
 
-        this.hopCountWeigher = adapt(new HopCountLinkWeight(graph.getVertexes().size()));
+        this.hopCountWeigher = new HopCountLinkWeigher(graph.getVertexes().size());
         this.broadcastSets = Suppliers.memoize(this::buildBroadcastSets);
         this.infrastructurePoints = Suppliers.memoize(this::findInfrastructurePoints);
         this.computeCost = Math.max(0, System.nanoTime() - time);
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java
index 5de5e97..b257c5a 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java
@@ -33,6 +33,7 @@
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.GridType;
 import org.onosproject.net.HostId;
 import org.onosproject.net.Lambda;
@@ -136,8 +137,9 @@
                         .appId(appId)
                         .selector(emptySelector)
                         .treatment(emptyTreatment)
-                        .ingressPoint(ingress)
-                        .egressPoint(egress).build();
+                        .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                        .filteredEgressPoint(new FilteredConnectPoint(egress))
+                        .build();
 
         final JsonCodec<PointToPointIntent> intentCodec =
                 context.codec(PointToPointIntent.class);
@@ -187,8 +189,8 @@
                         .appId(appId)
                         .selector(selector)
                         .treatment(treatment)
-                        .ingressPoint(ingress)
-                        .egressPoint(egress)
+                        .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                        .filteredEgressPoint(new FilteredConnectPoint(egress))
                         .constraints(constraints)
                         .build();
 
@@ -235,10 +237,10 @@
 
         PointToPointIntent pointIntent = (PointToPointIntent) intent;
         assertThat(pointIntent.priority(), is(55));
-        assertThat(pointIntent.ingressPoint().deviceId(), is(did("0000000000000001")));
-        assertThat(pointIntent.ingressPoint().port(), is(PortNumber.portNumber(1)));
-        assertThat(pointIntent.egressPoint().deviceId(), is(did("0000000000000007")));
-        assertThat(pointIntent.egressPoint().port(), is(PortNumber.portNumber(2)));
+        assertThat(pointIntent.filteredIngressPoint().connectPoint().deviceId(), is(did("0000000000000001")));
+        assertThat(pointIntent.filteredIngressPoint().connectPoint().port(), is(PortNumber.portNumber(1)));
+        assertThat(pointIntent.filteredEgressPoint().connectPoint().deviceId(), is(did("0000000000000007")));
+        assertThat(pointIntent.filteredEgressPoint().connectPoint().port(), is(PortNumber.portNumber(2)));
 
         assertThat(pointIntent.constraints(), hasSize(1));
 
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java b/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java
index f192e44..0a48e30 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java
@@ -98,7 +98,7 @@
         final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
 
         // check ingress connection
-        final ConnectPoint ingress = pointToPointIntent.ingressPoint();
+        final ConnectPoint ingress = pointToPointIntent.filteredIngressPoint().connectPoint();
         final ConnectPointJsonMatcher ingressMatcher =
                 ConnectPointJsonMatcher.matchesConnectPoint(ingress);
         final JsonNode jsonIngress = jsonIntent.get("ingressPoint");
@@ -111,7 +111,7 @@
         }
 
         // check egress connection
-        final ConnectPoint egress = pointToPointIntent.egressPoint();
+        final ConnectPoint egress = pointToPointIntent.filteredEgressPoint().connectPoint();
         final ConnectPointJsonMatcher egressMatcher =
                 ConnectPointJsonMatcher.matchesConnectPoint(egress);
         final JsonNode jsonEgress = jsonIntent.get("egressPoint");
diff --git a/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java b/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java
index 8030869..cb34df1 100644
--- a/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java
+++ b/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java
@@ -30,7 +30,6 @@
 import org.onosproject.net.topology.ClusterId;
 import org.onosproject.net.topology.GraphDescription;
 import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyCluster;
 import org.onosproject.net.topology.TopologyEvent;
@@ -44,7 +43,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -112,12 +110,6 @@
     }
 
     @Override
-    public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
-                              LinkWeight weight) {
-        return getPaths(topology, src, dst, adapt(weight));
-    }
-
-    @Override
     public Set<Path> getPaths(Topology topology, DeviceId src,
                               DeviceId dst, LinkWeigher weigher) {
         return defaultTopology(topology).getPaths(src, dst, weigher);
@@ -129,12 +121,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                              LinkWeight weight) {
-        return getDisjointPaths(topology, src, dst, adapt(weight));
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst, LinkWeigher weigher) {
         return defaultTopology(topology).getDisjointPaths(src, dst, weigher);
@@ -147,12 +133,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                                  LinkWeight weight, Map<Link, Object> riskProfile) {
-        return getDisjointPaths(topology, src, dst, adapt(weight), riskProfile);
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst,
                                               LinkWeigher weigher,
diff --git a/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java b/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
index 321f5d6..b53646f 100644
--- a/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
+++ b/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
@@ -38,11 +38,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Dictionary;
-import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -84,7 +84,7 @@
     protected ConfigurationAdmin cfgAdmin;
 
     // Locally maintained catalog of definitions.
-    private final Map<String, Map<String, ConfigProperty>>  properties =
+    private final Map<String, Map<String, ConfigProperty>> properties =
             Maps.newConcurrentMap();
 
 
@@ -103,7 +103,6 @@
     @Override
     public Set<String> getComponentNames() {
         checkPermission(CONFIG_READ);
-
         return ImmutableSet.copyOf(properties.keySet());
     }
 
@@ -125,7 +124,7 @@
             defs.forEach(p -> map.put(p.name(), p));
 
             properties.put(componentName, map);
-            loadExistingValues(componentName);
+            loadExistingValues(componentName, map);
         } catch (IOException e) {
             log.error("Unable to read property definitions from resource " + resourceName, e);
         }
@@ -174,7 +173,6 @@
 
     @Override
     public void preSetProperty(String componentName, String name, String value) {
-
         checkPermission(CONFIG_WRITE);
 
         checkNotNull(componentName, COMPONENT_NULL);
@@ -246,9 +244,6 @@
                 return;
             }
         }
-
-        // If definition doesn't exist in local catalog, cache the property.
-        preSet(componentName, name, value);
     }
 
     // Locates the property in the component map and replaces it with an
@@ -267,21 +262,6 @@
         }
     }
 
-    // Stores non-existent property so that loadExistingValues() can load in future.
-    private void preSet(String componentName, String name, String value) {
-        try {
-            Configuration config = cfgAdmin.getConfiguration(componentName, null);
-            Dictionary<String, Object> property = config.getProperties();
-            if (property == null) {
-                property = new Hashtable<>();
-            }
-            property.put(name, value);
-            config.update(property);
-        } catch (IOException e) {
-            log.error("Failed to preset configuration for {}", componentName);
-        }
-    }
-
     // Checks whether the value of the specified configuration property is a valid one or not.
     private void checkValidity(String componentName, String name, String newValue) {
         Map<String, ConfigProperty> map = properties.get(componentName);
@@ -306,7 +286,7 @@
                     break;
                 case BOOLEAN:
                     if (!((newValue != null) && (newValue.equalsIgnoreCase("true") ||
-                                newValue.equalsIgnoreCase("false")))) {
+                            newValue.equalsIgnoreCase("false")))) {
                         throw new IllegalArgumentException("Invalid " + type + " value");
                     }
                     break;
@@ -320,30 +300,39 @@
 
             }
         } catch (NumberFormatException e) {
-                throw new NumberFormatException("Invalid " + type + " value");
+            throw new NumberFormatException("Invalid " + type + " value");
         }
     }
 
-    // Loads existing property values that may have been set.
-    private void loadExistingValues(String componentName) {
+    // Loads existing property values that may have been learned from other
+    // nodes in the cluster before the local property registration.
+    private void loadExistingValues(String componentName,
+                                    Map<String, ConfigProperty> map) {
         try {
             Configuration cfg = cfgAdmin.getConfiguration(componentName, null);
-            Map<String, ConfigProperty> map = properties.get(componentName);
-            Dictionary<String, Object> props = cfg.getProperties();
-            if (props != null) {
-                Enumeration<String> it = props.keys();
-                while (it.hasMoreElements()) {
-                    String name = it.nextElement();
-                    ConfigProperty p = map.get(name);
-                    try {
-                        if (p != null) {
-                            checkValidity(componentName, name, (String) props.get(name));
-                            map.put(name, ConfigProperty.setProperty(p, (String) props.get(name)));
-                        }
-                    } catch (IllegalArgumentException e) {
-                        log.warn("Default values will be applied " +
-                                "since presetted value is not a valid " + p.type());
+            Dictionary<String, Object> localProperties = cfg.getProperties();
+
+            // Iterate over all registered config properties...
+            for (ConfigProperty p : ImmutableSet.copyOf(map.values())) {
+                String name = p.name();
+                String globalValue = store.getProperty(componentName, name);
+                String localValue = localProperties != null ? (String) localProperties.get(name) : null;
+                try {
+                    // If the global value is the same as default, reset to
+                    // default locally.
+                    if (Objects.equals(globalValue, p.defaultValue())) {
+                        reset(componentName, name);
+
+                    } else if (!Objects.equals(globalValue, localValue)) {
+                        // If the local value is different from global value?
+                        // validate the global value and apply it locally.
+                        checkValidity(componentName, name, globalValue);
+                        set(componentName, name, globalValue);
                     }
+                } catch (IllegalArgumentException e) {
+                    log.warn("Value {} is not a valid {}; using default",
+                             globalValue, p.type());
+                    reset(componentName, name);
                 }
             }
         } catch (IOException e) {
@@ -360,7 +349,7 @@
             Configuration cfg = cfgAdmin.getConfiguration(componentName, null);
             Map<String, ConfigProperty> map = properties.get(componentName);
             Dictionary<String, Object> props = new Hashtable<>();
-            map.values().forEach(p -> props.put(p.name(), p.value()));
+            map.values().stream().filter(p -> p.value() != null).forEach(p -> props.put(p.name(), p.value()));
             cfg.update(props);
         } catch (IOException e) {
             log.warn("Unable to update configuration for " + componentName, e);
diff --git a/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java b/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java
index 99920f9..1773154 100644
--- a/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java
+++ b/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java
@@ -194,8 +194,9 @@
             }
 
             try {
-                Thread.sleep((int) Math.pow(2, iterations < 7 ? ++iterations : iterations) * 10);
+                Thread.sleep((int) Math.pow(2, iterations < 7 ? ++iterations : iterations) * 10L);
             } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
                 throw Throwables.propagate(e);
             }
         }
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index f499d1b..068c676 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -530,6 +530,11 @@
             PortDescriptionsConfig portConfig = networkConfigService.getConfig(deviceId, PortDescriptionsConfig.class);
             // Generate updated description and establish my Role
             deviceDescription = BasicDeviceOperator.combine(cfg, deviceDescription);
+            DeviceAnnotationConfig annoConfig = networkConfigService.getConfig(deviceId, DeviceAnnotationConfig.class);
+            if (annoConfig != null) {
+                deviceDescription = deviceAnnotationOp.combine(deviceId, deviceDescription, Optional.of(annoConfig));
+            }
+
             Futures.getUnchecked(mastershipService.requestRoleFor(deviceId)
                                          .thenAccept(role -> {
                                              log.info("Local role is {} for {}", role, deviceId);
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
index c623bf2..b877ef8 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
@@ -300,7 +300,7 @@
             }
         }
         if (queued) {
-            log.info("Queued forwarding objective {} for nextId {} meant for device {}",
+            log.debug("Queued forwarding objective {} for nextId {} meant for device {}",
                       fwd.id(), fwd.nextId(), deviceId);
         }
         return queued;
@@ -328,7 +328,7 @@
             }
         }
         if (queued) {
-            log.info("Queued next objective {} with operation {} meant for device {}",
+            log.debug("Queued next objective {} with operation {} meant for device {}",
                       next.id(), next.op(), deviceId);
         }
         return queued;
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index f694dee..35876d6 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -261,7 +261,7 @@
         // remove associated group if there is one
         if (intent instanceof PointToPointIntent) {
             PointToPointIntent pointIntent = (PointToPointIntent) intent;
-            DeviceId deviceId = pointIntent.ingressPoint().deviceId();
+            DeviceId deviceId = pointIntent.filteredIngressPoint().connectPoint().deviceId();
             GroupKey groupKey = PointToPointIntentCompiler.makeGroupKey(intent.id());
             groupService.removeGroup(deviceId, groupKey,
                                      intent.appId());
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java
index bf2b274..4ba0bfe 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java
@@ -102,7 +102,7 @@
         for (Link link : path.links()) {
             reverseLinks.add(0, reverseLink(link));
         }
-        return new DefaultPath(path.providerId(), reverseLinks, path.cost());
+        return new DefaultPath(path.providerId(), reverseLinks, path.weight());
     }
 
     // Produces a reverse variant of the specified link.
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
index d1b44ca..f86cdba 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
@@ -17,7 +17,6 @@
 package org.onosproject.net.intent.impl.compiler;
 
 import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -36,7 +35,6 @@
 import org.slf4j.Logger;
 
 import java.util.Map;
-import java.util.Set;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -87,22 +85,10 @@
             label = "Indicates whether or not to use copy ttl in the link collection compiler")
     private boolean useCopyTtl = DEFAULT_COPY_TTL;
 
-    /**
-     * Temporary for switching old compiler and new compiler.
-     * @deprecated 1.10 Kingfisher
-     */
-    private static final String DEFAULT_FLOW_OBJECTIVE_COMPILER =
-            "org.onosproject.net.intent.impl.compiler.LinkCollectionIntentFlowObjectiveCompiler";
-    @Deprecated
-    @Property(name = "defaultFlowObjectiveCompiler",
-            value = DEFAULT_FLOW_OBJECTIVE_COMPILER,
-            label = "Default compiler to generate flow objective")
-    private String defaultFlowObjectiveCompiler = DEFAULT_FLOW_OBJECTIVE_COMPILER;
-
     private final Map<Class<Intent>, IntentCompiler<Intent>> flowRuleBased = Maps.newConcurrentMap();
 
     // FIXME: temporary code for switching old compiler to new compiler
-    private final Map<Class<Intent>, Set<IntentCompiler<Intent>>> flowObjectiveBased = Maps.newConcurrentMap();
+    private final Map<Class<Intent>, IntentCompiler<Intent>> flowObjectiveBased = Maps.newConcurrentMap();
 
     @Activate
     public void activate() {
@@ -125,8 +111,6 @@
             log.info("Settings: useCopyTtl={}", useCopyTtl);
             log.info("Settings: optLabelSelection={}", optLabelSelection);
 
-            // FIXME: temporary code for switching old compiler to new compiler
-            log.info("Settings: defaultFlowObjectiveCompiler={}", defaultFlowObjectiveCompiler);
             return;
         }
 
@@ -144,21 +128,6 @@
             log.info("Settings: useFlowObjectives={}", useFlowObjectives);
         }
 
-        // FIXME: temporary code for switching old compiler to new compiler
-        String newDefaultFlowObjectiveCompiler;
-        try {
-            String s = Tools.get(context.getProperties(), "defaultFlowObjectiveCompiler");
-            newDefaultFlowObjectiveCompiler = isNullOrEmpty(s) ? defaultFlowObjectiveCompiler : s.trim();
-        } catch (ClassCastException e) {
-            newDefaultFlowObjectiveCompiler = defaultFlowObjectiveCompiler;
-        }
-
-        if (!defaultFlowObjectiveCompiler.equals(newDefaultFlowObjectiveCompiler)) {
-            defaultFlowObjectiveCompiler = newDefaultFlowObjectiveCompiler;
-            changeCompilers();
-            log.info("Settings: defaultFlowObjectiveCompiler={}", defaultFlowObjectiveCompiler);
-        }
-
         String newLabelSelection;
         try {
             String s = Tools.get(context.getProperties(), "labelSelection");
@@ -230,15 +199,7 @@
     <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler,
                                              boolean flowBased) {
         if (flowBased) {
-            // FIXME: temporary code for switching old compiler to new compiler
-            flowObjectiveBased.compute((Class<Intent>) cls, (clz, compilers) -> {
-                if (compilers == null) {
-                    compilers = Sets.newHashSet();
-                }
-
-                compilers.add((IntentCompiler<Intent>) compiler);
-                return compilers;
-            });
+            flowObjectiveBased.put((Class<Intent>) cls, (IntentCompiler<Intent>) compiler);
         } else {
             flowRuleBased.put((Class<Intent>) cls, (IntentCompiler<Intent>) compiler);
         }
@@ -269,14 +230,8 @@
     private void changeCompilers() {
         if (useFlowObjectives) {
             flowRuleBased.forEach((cls, compiler) -> extensionService.unregisterCompiler(cls));
-            // FIXME: temporary code for switching old compiler to new compiler
-            flowObjectiveBased.forEach((cls, compilers) -> {
-                compilers.forEach(compiler -> {
-                    // filter out flow objective compiler which doesn't match
-                    if (compiler.getClass().getName().equals(defaultFlowObjectiveCompiler)) {
-                        extensionService.registerCompiler(cls, compiler);
-                    }
-                });
+            flowObjectiveBased.forEach((cls, compiler) -> {
+                extensionService.registerCompiler(cls, compiler);
             });
         } else {
             flowObjectiveBased.forEach((cls, compiler) -> extensionService.unregisterCompiler(cls));
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
index 337f274..159a53e 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
@@ -16,8 +16,11 @@
 package org.onosproject.net.intent.impl.compiler;
 
 import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
 import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -28,9 +31,20 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.domain.DomainService;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.EthCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flowobjective.DefaultFilteringObjective;
 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
 import org.onosproject.net.flowobjective.DefaultNextObjective;
+import org.onosproject.net.flowobjective.FilteringObjective;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
 import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.net.flowobjective.NextObjective;
@@ -42,23 +56,27 @@
 import org.onosproject.net.intent.constraint.EncapsulationConstraint;
 import org.onosproject.net.resource.ResourceService;
 import org.onosproject.net.resource.impl.LabelAllocator;
+import org.slf4j.Logger;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.onosproject.net.domain.DomainId.LOCAL;
+import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Compiler to produce flow objectives from link collections.
- * @deprecated 1.10 Kingfisher
  */
-@Deprecated
 @Component(immediate = true)
 public class LinkCollectionIntentFlowObjectiveCompiler
         extends LinkCollectionCompiler<Objective>
         implements IntentCompiler<LinkCollectionIntent> {
+    private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected IntentConfigurableRegistrator registrator;
@@ -72,6 +90,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ResourceService resourceService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DomainService domainService;
+
     private ApplicationId appId;
 
     @Activate
@@ -81,7 +102,6 @@
         if (labelAllocator == null) {
             labelAllocator = new LabelAllocator(resourceService);
         }
-
     }
 
     @Deactivate
@@ -106,25 +126,36 @@
                                                        encapConstraint.get().encapType());
         }
 
+        ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
+        if (this.isDomainProcessingEnabled(intent)) {
+            intentList.addAll(this.getDomainIntents(intent, domainService));
+        }
+
         List<Objective> objectives = new ArrayList<>();
         List<DeviceId> devices = new ArrayList<>();
-        for (DeviceId deviceId: outputPorts.keys()) {
-            List<Objective> deviceObjectives =
-                    createRules(intent,
-                                deviceId,
-                                inputPorts.get(deviceId),
-                                outputPorts.get(deviceId),
-                                labels);
-            deviceObjectives.forEach(objective -> {
-                objectives.add(objective);
-                devices.add(deviceId);
-            });
+        for (DeviceId deviceId : outputPorts.keySet()) {
+            // add only objectives that are not inside of a domain
+            if (LOCAL.equals(domainService.getDomain(deviceId))) {
+                List<Objective> deviceObjectives =
+                        createRules(intent,
+                                    deviceId,
+                                    inputPorts.get(deviceId),
+                                    outputPorts.get(deviceId),
+                                    labels);
+                deviceObjectives.forEach(objective -> {
+                    objectives.add(objective);
+                    devices.add(deviceId);
+                });
+            }
         }
-        return Collections.singletonList(
-                new FlowObjectiveIntent(appId, intent.key(), devices,
-                                        objectives,
-                                        intent.resources(),
-                                        intent.resourceGroup()));
+        // if any objectives have been created
+        if (!objectives.isEmpty()) {
+            intentList.add(new FlowObjectiveIntent(appId, intent.key(), devices,
+                                                   objectives,
+                                                   intent.resources(),
+                                                   intent.resourceGroup()));
+        }
+        return intentList.build();
     }
 
     @Override
@@ -139,44 +170,220 @@
                                           Set<PortNumber> outPorts,
                                           Map<ConnectPoint, Identifier<?>> labels) {
 
-        List<Objective> objectives = new ArrayList<>(inPorts.size());
+        List<Objective> objectives = new ArrayList<>(inPorts.size() * 2);
 
         /*
          * Looking for the encapsulation constraint
          */
         Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
 
-        inPorts.forEach(inport -> {
+        inPorts.forEach(inPort -> {
 
             ForwardingInstructions instructions = this.createForwardingInstruction(
                     encapConstraint,
                     intent,
-                    inport,
+                    inPort,
                     outPorts,
                     deviceId,
                     labels
             );
 
-            NextObjective nextObjective = DefaultNextObjective.builder()
-                    .withId(flowObjectiveService.allocateNextId())
-                    .addTreatment(instructions.treatment())
-                    .withType(NextObjective.Type.SIMPLE)
-                    .fromApp(appId)
-                    .makePermanent().add();
-            objectives.add(nextObjective);
+            Set<TrafficTreatment> treatmentsWithDifferentPort =
+                    Sets.newHashSet();
 
-            objectives.add(DefaultForwardingObjective.builder()
-                    .withSelector(instructions.selector())
-                    .nextStep(nextObjective.id())
-                    .withPriority(intent.priority())
-                    .fromApp(appId)
-                    .makePermanent()
-                    .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                    .add());
+            TrafficTreatment.Builder treatmentBuilder =
+                    DefaultTrafficTreatment.builder();
+
+            for (Instruction inst : instructions.treatment().allInstructions()) {
+                if (inst.type() == OUTPUT) {
+                    treatmentBuilder.add(inst);
+                    treatmentsWithDifferentPort.add(treatmentBuilder.build());
+                    treatmentBuilder = DefaultTrafficTreatment.builder();
+                } else {
+                    treatmentBuilder.add(inst);
+                }
             }
-        );
+
+            EthCriterion ethDst = (EthCriterion) intent.selector().getCriterion(Criterion.Type.ETH_DST);
+            boolean broadcastObjective = ethDst != null &&
+                    (ethDst.mac().isBroadcast() || ethDst.mac().isMulticast());
+
+            FilteringObjective filteringObjective = buildFilteringObjective(intent,
+                                                                            instructions.selector(),
+                                                                            deviceId, inPort);
+            if (filteringObjective != null) {
+                objectives.add(filteringObjective);
+            }
+            if (treatmentsWithDifferentPort.size() < 2 && !broadcastObjective) {
+                objectives.addAll(createSimpleNextObjective(instructions, intent));
+            } else {
+                objectives.addAll(createBroadcastObjective(instructions,
+                                                           treatmentsWithDifferentPort,
+                                                           intent));
+            }
+        });
 
         return objectives;
     }
 
+    private List<Objective> createBroadcastObjective(ForwardingInstructions instructions,
+                                                     Set<TrafficTreatment> treatmentsWithDifferentPort,
+                                                     LinkCollectionIntent intent) {
+        List<Objective> objectives = Lists.newArrayList();
+        ForwardingObjective forwardingObjective;
+        NextObjective nextObjective;
+
+        Integer nextId = flowObjectiveService.allocateNextId();
+
+        forwardingObjective = buildForwardingObjective(instructions.selector(),
+                                                       nextId, intent.priority());
+
+        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
+        nxBuilder.withId(nextId)
+                .withMeta(instructions.selector())
+                .withType(NextObjective.Type.BROADCAST)
+                .fromApp(appId)
+                .withPriority(intent.priority())
+                .makePermanent();
+
+        treatmentsWithDifferentPort.forEach(nxBuilder::addTreatment);
+        nextObjective = nxBuilder.add();
+
+        objectives.add(forwardingObjective);
+        objectives.add(nextObjective);
+
+        return objectives;
+    }
+
+    private List<Objective> createSimpleNextObjective(ForwardingInstructions instructions,
+                                                      LinkCollectionIntent intent) {
+        List<Objective> objectives = Lists.newArrayList();
+        ForwardingObjective forwardingObjective;
+        NextObjective nextObjective;
+
+        Integer nextId = flowObjectiveService.allocateNextId();
+
+        forwardingObjective = buildForwardingObjective(instructions.selector(),
+                                                       nextId, intent.priority());
+
+        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
+        nextObjective = nxBuilder.withId(nextId)
+                .withMeta(instructions.selector())
+                .addTreatment(instructions.treatment())
+                .withType(NextObjective.Type.SIMPLE)
+                .fromApp(appId)
+                .makePermanent()
+                .withPriority(intent.priority())
+                .add();
+
+        objectives.add(forwardingObjective);
+        objectives.add(nextObjective);
+
+        return objectives;
+    }
+
+    private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
+                                                         Integer nextId, int priority) {
+        return DefaultForwardingObjective.builder()
+                .withMeta(selector)
+                .withSelector(selector)
+                .nextStep(nextId)
+                .fromApp(appId)
+                .withPriority(priority)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .makePermanent()
+                .add();
+    }
+
+    private FilteringObjective buildFilteringObjective(LinkCollectionIntent intent,
+                                                       TrafficSelector selector,
+                                                       DeviceId deviceId,
+                                                       PortNumber inPort) {
+        FilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+        builder.fromApp(appId)
+                .permit()
+                .makePermanent()
+                .withPriority(intent.priority());
+        Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
+        if (inPortCriterion != null) {
+            builder.withKey(inPortCriterion);
+        }
+
+        FilteredConnectPoint ingressPoint = intent.filteredIngressPoints().stream()
+                .filter(fcp -> fcp.connectPoint().equals(new ConnectPoint(deviceId, inPort)))
+                .filter(fcp -> selector.criteria().containsAll(fcp.trafficSelector().criteria()))
+                .findFirst()
+                .orElse(null);
+
+        AtomicBoolean emptyCondition = new AtomicBoolean(true);
+        if (ingressPoint != null) {
+            // ingress point, use criterion of it
+            ingressPoint.trafficSelector().criteria().forEach(criterion -> {
+                builder.addCondition(criterion);
+                emptyCondition.set(false);
+            });
+            if (emptyCondition.get()) {
+                return null;
+            }
+            return builder.add();
+        }
+        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
+        if (encapConstraint.isPresent() &&
+                !encapConstraint.get().encapType().equals(EncapsulationType.NONE)) {
+            // encapsulation enabled, use encapsulation label and tag.
+            EncapsulationConstraint encap = encapConstraint.get();
+            switch (encap.encapType()) {
+                case VLAN:
+                    builder.addCondition(selector.getCriterion(Criterion.Type.VLAN_VID));
+                    emptyCondition.set(false);
+                    break;
+                case MPLS:
+                    builder.addCondition(selector.getCriterion(Criterion.Type.MPLS_LABEL));
+                    emptyCondition.set(false);
+                    break;
+                default:
+                    log.warn("No filtering rule found because of unknown encapsulation type.");
+                    break;
+            }
+        } else {
+            // encapsulation not enabled, check if the treatment applied to the ingress or not
+            if (intent.applyTreatmentOnEgress()) {
+                // filtering criterion will be changed on egress point, use
+                // criterion of ingress point
+                ingressPoint = intent.filteredIngressPoints().stream()
+                        .findFirst()
+                        .orElse(null);
+                if (ingressPoint == null) {
+                    log.warn("No filtering rule found because no ingress point in the Intent");
+                } else {
+                    ingressPoint.trafficSelector().criteria().stream()
+                            .filter(criterion -> !criterion.type().equals(Criterion.Type.IN_PORT))
+                            .forEach(criterion -> {
+                                builder.addCondition(criterion);
+                                emptyCondition.set(false);
+                            });
+                }
+            } else {
+                // filtering criterion will be changed on ingress point, use
+                // criterion of egress point
+                FilteredConnectPoint egressPoint = intent.filteredEgressPoints().stream()
+                        .findFirst()
+                        .orElse(null);
+                if (egressPoint == null) {
+                    log.warn("No filtering rule found because no egress point in the Intent");
+                } else {
+                    egressPoint.trafficSelector().criteria().stream()
+                            .filter(criterion -> !criterion.type().equals(Criterion.Type.IN_PORT))
+                            .forEach(criterion -> {
+                                builder.addCondition(criterion);
+                                emptyCondition.set(false);
+                            });
+                }
+            }
+        }
+        if (emptyCondition.get()) {
+            return null;
+        }
+        return builder.add();
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompiler.java
deleted file mode 100644
index 533b2e8..0000000
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompiler.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright 2016-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.net.intent.impl.compiler;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.util.Identifier;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.EncapsulationType;
-import org.onosproject.net.FilteredConnectPoint;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.domain.DomainService;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.EthCriterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flowobjective.DefaultFilteringObjective;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.DefaultNextObjective;
-import org.onosproject.net.flowobjective.FilteringObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.intent.FlowObjectiveIntent;
-import org.onosproject.net.intent.Intent;
-import org.onosproject.net.intent.IntentCompiler;
-import org.onosproject.net.intent.LinkCollectionIntent;
-import org.onosproject.net.intent.constraint.EncapsulationConstraint;
-import org.onosproject.net.resource.ResourceService;
-import org.onosproject.net.resource.impl.LabelAllocator;
-import org.slf4j.Logger;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static org.onosproject.net.domain.DomainId.LOCAL;
-import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Compiler to produce flow objectives from link collections.
- */
-@Component(immediate = true)
-public class LinkCollectionIntentObjectiveCompiler
-        extends LinkCollectionCompiler<Objective>
-        implements IntentCompiler<LinkCollectionIntent> {
-    private final Logger log = getLogger(getClass());
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected IntentConfigurableRegistrator registrator;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CoreService coreService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected FlowObjectiveService flowObjectiveService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected ResourceService resourceService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DomainService domainService;
-
-    private ApplicationId appId;
-
-    @Activate
-    public void activate() {
-        appId = coreService.registerApplication("org.onosproject.net.intent");
-        registrator.registerCompiler(LinkCollectionIntent.class, this, true);
-        if (labelAllocator == null) {
-            labelAllocator = new LabelAllocator(resourceService);
-        }
-    }
-
-    @Deactivate
-    public void deactivate() {
-        registrator.unregisterCompiler(LinkCollectionIntent.class, true);
-    }
-
-    @Override
-    public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
-
-        SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
-        SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
-        Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
-
-        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
-
-        computePorts(intent, inputPorts, outputPorts);
-
-        if (encapConstraint.isPresent()) {
-            labels = labelAllocator.assignLabelToPorts(intent.links(),
-                                                       intent.key(),
-                                                       encapConstraint.get().encapType());
-        }
-
-        ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
-        if (this.isDomainProcessingEnabled(intent)) {
-            intentList.addAll(this.getDomainIntents(intent, domainService));
-        }
-
-        List<Objective> objectives = new ArrayList<>();
-        List<DeviceId> devices = new ArrayList<>();
-        for (DeviceId deviceId : outputPorts.keySet()) {
-            // add only objectives that are not inside of a domain
-            if (LOCAL.equals(domainService.getDomain(deviceId))) {
-                List<Objective> deviceObjectives =
-                        createRules(intent,
-                                    deviceId,
-                                    inputPorts.get(deviceId),
-                                    outputPorts.get(deviceId),
-                                    labels);
-                deviceObjectives.forEach(objective -> {
-                    objectives.add(objective);
-                    devices.add(deviceId);
-                });
-            }
-        }
-        // if any objectives have been created
-        if (!objectives.isEmpty()) {
-            intentList.add(new FlowObjectiveIntent(appId, intent.key(), devices,
-                                                   objectives,
-                                                   intent.resources(),
-                                                   intent.resourceGroup()));
-        }
-        return intentList.build();
-    }
-
-    @Override
-    boolean optimizeTreatments() {
-        return false;
-    }
-
-    @Override
-    protected List<Objective> createRules(LinkCollectionIntent intent,
-                                          DeviceId deviceId,
-                                          Set<PortNumber> inPorts,
-                                          Set<PortNumber> outPorts,
-                                          Map<ConnectPoint, Identifier<?>> labels) {
-
-        List<Objective> objectives = new ArrayList<>(inPorts.size() * 2);
-
-        /*
-         * Looking for the encapsulation constraint
-         */
-        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
-
-        inPorts.forEach(inPort -> {
-
-            ForwardingInstructions instructions = this.createForwardingInstruction(
-                    encapConstraint,
-                    intent,
-                    inPort,
-                    outPorts,
-                    deviceId,
-                    labels
-            );
-
-            Set<TrafficTreatment> treatmentsWithDifferentPort =
-                    Sets.newHashSet();
-
-            TrafficTreatment.Builder treatmentBuilder =
-                    DefaultTrafficTreatment.builder();
-
-            for (Instruction inst : instructions.treatment().allInstructions()) {
-                if (inst.type() == OUTPUT) {
-                    treatmentBuilder.add(inst);
-                    treatmentsWithDifferentPort.add(treatmentBuilder.build());
-                    treatmentBuilder = DefaultTrafficTreatment.builder();
-                } else {
-                    treatmentBuilder.add(inst);
-                }
-            }
-
-            EthCriterion ethDst = (EthCriterion) intent.selector().getCriterion(Criterion.Type.ETH_DST);
-            boolean broadcastObjective = ethDst != null &&
-                    (ethDst.mac().isBroadcast() || ethDst.mac().isMulticast());
-
-            FilteringObjective filteringObjective = buildFilteringObjective(intent,
-                                                                            instructions.selector(),
-                                                                            deviceId, inPort);
-            if (filteringObjective != null) {
-                objectives.add(filteringObjective);
-            }
-            if (treatmentsWithDifferentPort.size() < 2 && !broadcastObjective) {
-                objectives.addAll(createSimpleNextObjective(instructions, intent));
-            } else {
-                objectives.addAll(createBroadcastObjective(instructions,
-                                                           treatmentsWithDifferentPort,
-                                                           intent));
-            }
-        });
-
-        return objectives;
-    }
-
-    private List<Objective> createBroadcastObjective(ForwardingInstructions instructions,
-                                                     Set<TrafficTreatment> treatmentsWithDifferentPort,
-                                                     LinkCollectionIntent intent) {
-        List<Objective> objectives = Lists.newArrayList();
-        ForwardingObjective forwardingObjective;
-        NextObjective nextObjective;
-
-        Integer nextId = flowObjectiveService.allocateNextId();
-
-        forwardingObjective = buildForwardingObjective(instructions.selector(),
-                                                       nextId, intent.priority());
-
-        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
-        nxBuilder.withId(nextId)
-                .withMeta(instructions.selector())
-                .withType(NextObjective.Type.BROADCAST)
-                .fromApp(appId)
-                .withPriority(intent.priority())
-                .makePermanent();
-
-        treatmentsWithDifferentPort.forEach(nxBuilder::addTreatment);
-        nextObjective = nxBuilder.add();
-
-        objectives.add(forwardingObjective);
-        objectives.add(nextObjective);
-
-        return objectives;
-    }
-
-    private List<Objective> createSimpleNextObjective(ForwardingInstructions instructions,
-                                                      LinkCollectionIntent intent) {
-        List<Objective> objectives = Lists.newArrayList();
-        ForwardingObjective forwardingObjective;
-        NextObjective nextObjective;
-
-        Integer nextId = flowObjectiveService.allocateNextId();
-
-        forwardingObjective = buildForwardingObjective(instructions.selector(),
-                                                       nextId, intent.priority());
-
-        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
-        nextObjective = nxBuilder.withId(nextId)
-                .withMeta(instructions.selector())
-                .addTreatment(instructions.treatment())
-                .withType(NextObjective.Type.SIMPLE)
-                .fromApp(appId)
-                .makePermanent()
-                .withPriority(intent.priority())
-                .add();
-
-        objectives.add(forwardingObjective);
-        objectives.add(nextObjective);
-
-        return objectives;
-    }
-
-    private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
-                                                         Integer nextId, int priority) {
-        return DefaultForwardingObjective.builder()
-                .withMeta(selector)
-                .withSelector(selector)
-                .nextStep(nextId)
-                .fromApp(appId)
-                .withPriority(priority)
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .makePermanent()
-                .add();
-    }
-
-    private FilteringObjective buildFilteringObjective(LinkCollectionIntent intent,
-                                                       TrafficSelector selector,
-                                                       DeviceId deviceId,
-                                                       PortNumber inPort) {
-        FilteringObjective.Builder builder = DefaultFilteringObjective.builder();
-        builder.fromApp(appId)
-                .permit()
-                .makePermanent()
-                .withPriority(intent.priority());
-        Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
-        if (inPortCriterion != null) {
-            builder.withKey(inPortCriterion);
-        }
-
-        FilteredConnectPoint ingressPoint = intent.filteredIngressPoints().stream()
-                .filter(fcp -> fcp.connectPoint().equals(new ConnectPoint(deviceId, inPort)))
-                .filter(fcp -> selector.criteria().containsAll(fcp.trafficSelector().criteria()))
-                .findFirst()
-                .orElse(null);
-
-        AtomicBoolean emptyCondition = new AtomicBoolean(true);
-        if (ingressPoint != null) {
-            // ingress point, use criterion of it
-            ingressPoint.trafficSelector().criteria().forEach(criterion -> {
-                builder.addCondition(criterion);
-                emptyCondition.set(false);
-            });
-            if (emptyCondition.get()) {
-                return null;
-            }
-            return builder.add();
-        }
-        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
-        if (encapConstraint.isPresent() &&
-                !encapConstraint.get().encapType().equals(EncapsulationType.NONE)) {
-            // encapsulation enabled, use encapsulation label and tag.
-            EncapsulationConstraint encap = encapConstraint.get();
-            switch (encap.encapType()) {
-                case VLAN:
-                    builder.addCondition(selector.getCriterion(Criterion.Type.VLAN_VID));
-                    emptyCondition.set(false);
-                    break;
-                case MPLS:
-                    builder.addCondition(selector.getCriterion(Criterion.Type.MPLS_LABEL));
-                    emptyCondition.set(false);
-                    break;
-                default:
-                    log.warn("No filtering rule found because of unknown encapsulation type.");
-                    break;
-            }
-        } else {
-            // encapsulation not enabled, check if the treatment applied to the ingress or not
-            if (intent.applyTreatmentOnEgress()) {
-                // filtering criterion will be changed on egress point, use
-                // criterion of ingress point
-                ingressPoint = intent.filteredIngressPoints().stream()
-                        .findFirst()
-                        .orElse(null);
-                if (ingressPoint == null) {
-                    log.warn("No filtering rule found because no ingress point in the Intent");
-                } else {
-                    ingressPoint.trafficSelector().criteria().stream()
-                            .filter(criterion -> !criterion.type().equals(Criterion.Type.IN_PORT))
-                            .forEach(criterion -> {
-                                builder.addCondition(criterion);
-                                emptyCondition.set(false);
-                            });
-                }
-            } else {
-                // filtering criterion will be changed on ingress point, use
-                // criterion of egress point
-                FilteredConnectPoint egressPoint = intent.filteredEgressPoints().stream()
-                        .findFirst()
-                        .orElse(null);
-                if (egressPoint == null) {
-                    log.warn("No filtering rule found because no egress point in the Intent");
-                } else {
-                    egressPoint.trafficSelector().criteria().stream()
-                            .filter(criterion -> !criterion.type().equals(Criterion.Type.IN_PORT))
-                            .forEach(criterion -> {
-                                builder.addCondition(criterion);
-                                emptyCondition.set(false);
-                            });
-                }
-            }
-        }
-        if (emptyCondition.get()) {
-            return null;
-        }
-        return builder.add();
-    }
-}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java
index 0c47196..acdaddd 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java
@@ -21,6 +21,7 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.graph.ScalarWeight;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultPath;
 import org.onosproject.net.DeviceId;
@@ -150,7 +151,7 @@
                                              ConnectPoint egressPoint,
                                              PointToPointIntent intent) {
         List<Link> links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false));
-        return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST),
+        return asList(createPathIntent(new DefaultPath(PID, links, ScalarWeight.toWeight(DEFAULT_COST)),
                                        intent, PathIntent.ProtectionType.PRIMARY));
     }
 
@@ -159,31 +160,6 @@
                                        intent));
     }
 
-    /**
-     * Creates an unprotected intent.
-     * @param ingressPoint the ingress connect point
-     * @param egressPoint the egress connect point
-     * @param intent the original intent
-     * @return the compilation result
-     * @deprecated 1.10.0
-     */
-    @Deprecated
-    private List<Intent> createUnprotectedIntent(ConnectPoint ingressPoint,
-                                                 ConnectPoint egressPoint,
-                                                 PointToPointIntent intent) {
-        List<Link> links = new ArrayList<>();
-        Path path = getPathOrException(intent, ingressPoint.deviceId(),
-                                       egressPoint.deviceId());
-
-        links.add(createEdgeLink(ingressPoint, true));
-        links.addAll(path.links());
-        links.add(createEdgeLink(egressPoint, false));
-
-        return asList(createPathIntent(new DefaultPath(PID, links, path.cost(),
-                                                       path.annotations()), intent,
-                                       PathIntent.ProtectionType.PRIMARY));
-    }
-
     private List<Intent> createUnprotectedLinkCollectionIntent(PointToPointIntent intent) {
         Path path = getPathOrException(intent, intent.filteredIngressPoint().connectPoint().deviceId(),
                                        intent.filteredEgressPoint().connectPoint().deviceId());
@@ -253,23 +229,24 @@
             PortNumber primaryPort = getPrimaryPort(intent);
             if (primaryPort != null && !links.get(0).src().port().equals(primaryPort)) {
                 reusableIntents.add(createPathIntent(new DefaultPath(PID, links,
-                                                                     path.cost(), path.annotations()),
+                                                     path.weight(), path.annotations()),
                                                      intent, PathIntent.ProtectionType.BACKUP));
                 updateFailoverGroup(intent, links);
                 return reusableIntents;
 
             } else {
-                reusableIntents.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(),
-                                     path.backup().annotations()), intent, PathIntent.ProtectionType.BACKUP));
+                reusableIntents.add(createPathIntent(new DefaultPath(PID, backupLinks,
+                        path.backup().weight(),
+                        path.backup().annotations()), intent, PathIntent.ProtectionType.BACKUP));
                 updateFailoverGroup(intent, backupLinks);
                 return reusableIntents;
             }
         }
 
-        intentList.add(createPathIntent(new DefaultPath(PID, links, path.cost(),
+        intentList.add(createPathIntent(new DefaultPath(PID, links, path.weight(),
                                                         path.annotations()),
                                         intent, PathIntent.ProtectionType.PRIMARY));
-        intentList.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(),
+        intentList.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().weight(),
                                                         path.backup().annotations()),
                                         intent, PathIntent.ProtectionType.BACKUP));
 
@@ -335,7 +312,7 @@
             links.add(createEdgeLink(ingressPoint, true));
             links.addAll(onlyPath.links());
             links.add(createEdgeLink(egressPoint, false));
-            return asList(createPathIntent(new DefaultPath(PID, links, onlyPath.cost(),
+            return asList(createPathIntent(new DefaultPath(PID, links, onlyPath.weight(),
                                                            onlyPath.annotations()),
                                            intent, PathIntent.ProtectionType.PRIMARY));
         }
@@ -484,7 +461,7 @@
     private List<FlowRule> createFailoverFlowRules(PointToPointIntent intent) {
         List<FlowRule> flowRules = new ArrayList<>();
 
-        ConnectPoint ingress = intent.ingressPoint();
+        ConnectPoint ingress = intent.filteredIngressPoint().connectPoint();
         DeviceId deviceId = ingress.deviceId();
 
         // flow rule with failover traffic treatment
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ProtectedTransportIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ProtectedTransportIntentCompiler.java
index f7eceef..9020e5a 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ProtectedTransportIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ProtectedTransportIntentCompiler.java
@@ -299,7 +299,7 @@
         List<Link> revLinks = Lists.reverse(transform(path.links(), this::reverse));
         return new DefaultPath(path.providerId(),
                                revLinks,
-                               path.cost(),
+                               path.weight(),
                                path.annotations());
     }
 
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.java
index 9f3d4b0..753e04f 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.java
@@ -19,6 +19,7 @@
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.PointToPointIntent;
 import org.onosproject.net.intent.TwoWayP2PIntent;
@@ -50,8 +51,8 @@
                         .key(intent.key())
                         .selector(intent.selector())
                         .treatment(intent.treatment())
-                        .ingressPoint(intent.one())
-                        .egressPoint(intent.two())
+                        .filteredIngressPoint(new FilteredConnectPoint(intent.one()))
+                        .filteredEgressPoint(new FilteredConnectPoint(intent.two()))
                         .constraints(intent.constraints())
                         .priority(intent.priority())
                         .resourceGroup(intent.resourceGroup())
@@ -61,8 +62,8 @@
                         .key(intent.key())
                         .selector(intent.selector())
                         .treatment(intent.treatment())
-                        .ingressPoint(intent.two())
-                        .egressPoint(intent.one())
+                        .filteredIngressPoint(new FilteredConnectPoint(intent.two()))
+                        .filteredEgressPoint(new FilteredConnectPoint(intent.one()))
                         .constraints(intent.constraints())
                         .priority(intent.priority())
                         .resourceGroup(intent.resourceGroup())
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompiler.java
index 90ad393..bf92873 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompiler.java
@@ -31,6 +31,7 @@
 import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
 import org.onosproject.incubator.net.virtual.VirtualPort;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.Link;
 import org.onosproject.net.Path;
 import org.onosproject.net.intent.Intent;
@@ -175,8 +176,8 @@
         PointToPointIntent physicalIntent = PointToPointIntent.builder()
                 .key(intentKey)
                 .appId(intent.appId())
-                .ingressPoint(ingressPoint)
-                .egressPoint(egressPoint)
+                .filteredIngressPoint(new FilteredConnectPoint(ingressPoint))
+                .filteredEgressPoint(new FilteredConnectPoint(egressPoint))
                 .constraints(intent.constraints())
                 .selector(intent.selector())
                 .treatment(intent.treatment())
diff --git a/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java b/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java
index ec73c3b..cc9cc53 100644
--- a/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java
+++ b/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java
@@ -27,7 +27,6 @@
 import org.onosproject.net.Path;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.PathService;
 import org.onosproject.net.topology.TopologyService;
 import org.onosproject.net.topology.AbstractPathService;
@@ -80,12 +79,6 @@
     }
 
     @Override
-    public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
-        checkPermission(TOPOLOGY_READ);
-        return super.getPaths(src, dst, weight);
-    }
-
-    @Override
     public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
         checkPermission(TOPOLOGY_READ);
         return super.getPaths(src, dst, weigher);
@@ -105,12 +98,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) {
-        checkPermission(TOPOLOGY_READ);
-        return super.getDisjointPaths(src, dst, weight);
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
         checkPermission(TOPOLOGY_READ);
         return super.getDisjointPaths(src, dst, weigher);
@@ -124,13 +111,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight,
-                                              Map<Link, Object> riskProfile) {
-        checkPermission(TOPOLOGY_READ);
-        return super.getDisjointPaths(src, dst, weight, riskProfile);
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, LinkWeigher weigher,
                                               Map<Link, Object> riskProfile) {
         checkPermission(TOPOLOGY_READ);
diff --git a/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java b/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
index 522c23c..0d15645 100644
--- a/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
+++ b/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java
@@ -21,18 +21,17 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
-import org.onosproject.net.DisjointPath;
-import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.event.Event;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.DisjointPath;
 import org.onosproject.net.Link;
 import org.onosproject.net.Path;
+import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.onosproject.net.topology.ClusterId;
 import org.onosproject.net.topology.GraphDescription;
 import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyCluster;
 import org.onosproject.net.topology.TopologyEvent;
@@ -47,15 +46,14 @@
 import org.slf4j.Logger;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Stream;
-import java.util.Map;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 import static org.onosproject.security.AppGuard.checkPermission;
+import static org.onosproject.security.AppPermission.Type.TOPOLOGY_READ;
 import static org.slf4j.LoggerFactory.getLogger;
-import static org.onosproject.security.AppPermission.Type.*;
 
 
 /**
@@ -158,12 +156,6 @@
 
     @Override
     public Set<Path> getPaths(Topology topology, DeviceId src,
-                              DeviceId dst, LinkWeight weight) {
-        return getPaths(topology, src, dst, adapt(weight));
-    }
-
-    @Override
-    public Set<Path> getPaths(Topology topology, DeviceId src,
                               DeviceId dst, LinkWeigher weigher) {
         checkPermission(TOPOLOGY_READ);
 
@@ -214,13 +206,6 @@
     @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst,
-                                              LinkWeight weight) {
-        return getDisjointPaths(topology, src, dst, adapt(weight));
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
-                                              DeviceId dst,
                                               LinkWeigher weigher) {
         checkPermission(TOPOLOGY_READ);
         checkNotNull(topology, TOPOLOGY_NULL);
@@ -243,13 +228,6 @@
 
     @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
-                                              DeviceId dst, LinkWeight weight,
-                                              Map<Link, Object> riskProfile) {
-        return getDisjointPaths(topology, src, dst, adapt(weight), riskProfile);
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst,
                                               LinkWeigher weigher,
                                               Map<Link, Object> riskProfile) {
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompilerTest.java
similarity index 99%
rename from core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompilerTest.java
rename to core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompilerTest.java
index c8d3915..47d00e6 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompilerTest.java
@@ -68,11 +68,11 @@
 import static org.onosproject.net.flowobjective.NextObjective.Type.SIMPLE;
 import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
 
-public class LinkCollectionIntentObjectiveCompilerTest extends AbstractLinkCollectionTest {
+public class LinkCollectionIntentFlowObjectiveCompilerTest extends AbstractLinkCollectionTest {
     private static final VlanId VLAN_1 = VlanId.vlanId("1");
     private static final VlanId VLAN_100 = VlanId.vlanId("100");
 
-    private LinkCollectionIntentObjectiveCompiler compiler;
+    private LinkCollectionIntentFlowObjectiveCompiler compiler;
     private FlowObjectiveServiceAdapter flowObjectiveService;
 
     private NextObjective nextObjective;
@@ -83,7 +83,7 @@
 
     @Before
     public void setUp() {
-        compiler = new LinkCollectionIntentObjectiveCompiler();
+        compiler = new LinkCollectionIntentFlowObjectiveCompiler();
         coreService = createMock(CoreService.class);
         expect(coreService.registerApplication("org.onosproject.net.intent"))
                 .andReturn(appId);
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
index 6d015ae..e37ae41 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.ImmutableList;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
@@ -172,7 +173,7 @@
                 .selector(selector)
                 .treatment(treatment)
                 .priority(PRIORITY)
-                .path(new DefaultPath(pid, links, hops))
+                .path(new DefaultPath(pid, links, ScalarWeight.toWeight(hops)))
                 .build();
 
         //Intent with VLAN encap without egress VLAN
@@ -182,7 +183,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, links, hops))
+                .path(new DefaultPath(pid, links, ScalarWeight.toWeight(hops)))
                 .build();
 
         //Intent with VLAN encap with ingress and egress VLAN
@@ -192,7 +193,7 @@
                 .treatment(vlanTreatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, links, hops))
+                .path(new DefaultPath(pid, links, ScalarWeight.toWeight(hops)))
                 .build();
 
         constraintMplsIntent = PathIntent.builder()
@@ -201,7 +202,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.MPLS)))
-                .path(new DefaultPath(pid, links, hops))
+                .path(new DefaultPath(pid, links, ScalarWeight.toWeight(hops)))
                 .build();
 
         edgeIntentNoVlan = PathIntent.builder()
@@ -210,7 +211,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, edgeNet, edgeHops))
+                .path(new DefaultPath(pid, edgeNet, ScalarWeight.toWeight(edgeHops)))
                 .build();
 
         edgeIntentIngressVlan = PathIntent.builder()
@@ -219,7 +220,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, edgeNet, edgeHops))
+                .path(new DefaultPath(pid, edgeNet, ScalarWeight.toWeight(edgeHops)))
                 .build();
 
         edgeIntentEgressVlan = PathIntent.builder()
@@ -228,7 +229,7 @@
                 .treatment(vlanTreatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, edgeNet, edgeHops))
+                .path(new DefaultPath(pid, edgeNet, ScalarWeight.toWeight(edgeHops)))
                 .build();
 
         edgeIntentVlan = PathIntent.builder()
@@ -237,7 +238,7 @@
                 .treatment(vlanTreatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, edgeNet, edgeHops))
+                .path(new DefaultPath(pid, edgeNet, ScalarWeight.toWeight(edgeHops)))
                 .build();
 
         singleHopIndirectIntentNoVlan = PathIntent.builder()
@@ -246,7 +247,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopIndirect, singleHopIndirectHops))
+                .path(new DefaultPath(pid, singleHopIndirect, ScalarWeight.toWeight(singleHopIndirectHops)))
                 .build();
 
         singleHopIndirectIntentIngressVlan = PathIntent.builder()
@@ -255,7 +256,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopIndirect, singleHopIndirectHops))
+                .path(new DefaultPath(pid, singleHopIndirect, ScalarWeight.toWeight(singleHopIndirectHops)))
                 .build();
 
         singleHopIndirectIntentEgressVlan = PathIntent.builder()
@@ -264,7 +265,7 @@
                 .treatment(vlanTreatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopIndirect, singleHopIndirectHops))
+                .path(new DefaultPath(pid, singleHopIndirect, ScalarWeight.toWeight(singleHopIndirectHops)))
                 .build();
 
         singleHopIndirectIntentVlan = PathIntent.builder()
@@ -273,7 +274,7 @@
                 .treatment(vlanTreatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopIndirect, singleHopIndirectHops))
+                .path(new DefaultPath(pid, singleHopIndirect, ScalarWeight.toWeight(singleHopIndirectHops)))
                 .build();
 
         singleHopDirectIntentNoVlan = PathIntent.builder()
@@ -282,7 +283,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopDirect, singleHopDirectHops))
+                .path(new DefaultPath(pid, singleHopDirect, ScalarWeight.toWeight(singleHopDirectHops)))
                 .build();
 
         singleHopDirectIntentIngressVlan = PathIntent.builder()
@@ -291,7 +292,7 @@
                 .treatment(treatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopDirect, singleHopDirectHops))
+                .path(new DefaultPath(pid, singleHopDirect, ScalarWeight.toWeight(singleHopDirectHops)))
                 .build();
 
         singleHopDirectIntentEgressVlan = PathIntent.builder()
@@ -300,7 +301,7 @@
                 .treatment(vlanTreatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopDirect, singleHopDirectHops))
+                .path(new DefaultPath(pid, singleHopDirect, ScalarWeight.toWeight(singleHopDirectHops)))
                 .build();
 
         singleHopDirectIntentVlan = PathIntent.builder()
@@ -309,7 +310,7 @@
                 .treatment(vlanTreatment)
                 .priority(PRIORITY)
                 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
-                .path(new DefaultPath(pid, singleHopDirect, singleHopDirectHops))
+                .path(new DefaultPath(pid, singleHopDirect, ScalarWeight.toWeight(singleHopDirectHops)))
                 .build();
 
         intentExtensionService = createMock(IntentExtensionService.class);
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java
index 982a4f9..a4c5674 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java
@@ -17,12 +17,14 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onosproject.TestApplicationId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.IdGenerator;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultLink;
 import org.onosproject.net.DefaultPath;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.Link;
 import org.onosproject.net.Path;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -67,7 +69,7 @@
 
     private final List<Link> links = Collections.singletonList(
             DefaultLink.builder().providerId(pid).src(cp2).dst(cp4).type(DIRECT).build());
-    private final Path path = new DefaultPath(pid, links, 10);
+    private final Path path = new DefaultPath(pid, links, ScalarWeight.toWeight(10));
 
     private PointToPointIntent input;
     private PathIntent compiled;
@@ -88,8 +90,8 @@
                 .appId(appId)
                 .selector(selector)
                 .treatment(treatment)
-                .ingressPoint(cp1)
-                .egressPoint(cp3)
+                .filteredIngressPoint(new FilteredConnectPoint(cp1))
+                .filteredEgressPoint(new FilteredConnectPoint(cp3))
                 .build();
         compiled = PathIntent.builder()
                 .appId(appId)
diff --git a/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java b/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
index b350144..3516058 100644
--- a/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
@@ -28,7 +28,8 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.topology.DefaultGraphDescription;
 import org.onosproject.net.topology.GraphDescription;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
+import org.onosproject.net.topology.LinkWeigherAdapter;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyCluster;
 import org.onosproject.net.topology.TopologyEvent;
@@ -174,7 +175,7 @@
     public void onDemandPath() {
         submitTopologyGraph();
         Topology topology = service.currentTopology();
-        LinkWeight weight = edge -> 3.3;
+        LinkWeigher weight = new LinkWeigherAdapter(3.3);
 
         Set<Path> paths = service.getPaths(topology, did("a"), did("c"), weight);
         assertEquals("wrong path count", 2, paths.size());
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 243c3c2..564c3be 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
@@ -610,6 +610,7 @@
             }
         } catch (InterruptedException e) {
             log.warn("Interrupted while fetching bits for application {}", app.id().name());
+            Thread.currentThread().interrupt();
         }
     }
 
diff --git a/core/store/dist/src/main/java/org/onosproject/store/cfg/DistributedComponentConfigStore.java b/core/store/dist/src/main/java/org/onosproject/store/cfg/DistributedComponentConfigStore.java
index 5a82a8a..85e826f 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/cfg/DistributedComponentConfigStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/cfg/DistributedComponentConfigStore.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.store.cfg;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -31,8 +32,12 @@
 import org.onosproject.store.service.MapEventListener;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
 import org.slf4j.Logger;
 
+import java.util.Objects;
+import java.util.Set;
+
 import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_SET;
 import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_UNSET;
 import static org.onosproject.store.service.MapEvent.Type.INSERT;
@@ -59,7 +64,7 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected StorageService storageService;
 
-    InternalPropertiesListener propertiesListener = new InternalPropertiesListener();
+    private InternalPropertiesListener propertiesListener = new InternalPropertiesListener();
 
     @Activate
     public void activate() {
@@ -90,6 +95,22 @@
         properties.remove(key(componentName, name));
     }
 
+    @Override
+    public Set<String> getProperties(String componentName) {
+        ImmutableSet.Builder<String> names = ImmutableSet.builder();
+        properties.keySet().stream()
+                .filter((String k) -> Objects.equals(componentName, k.substring(0, k.indexOf(SEP))))
+                .map((String k) -> k.substring(k.indexOf(SEP) + 1))
+                .forEach(names::add);
+        return names.build();
+    }
+
+    @Override
+    public String getProperty(String componentName, String name) {
+        Versioned<String> v = properties.get(key(componentName, name));
+        return v != null ? v.value() : null;
+    }
+
     /**
      * Listener to component configuration properties distributed map changes.
      */
diff --git a/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedLeadershipStore.java b/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedLeadershipStore.java
index b1bae21..746142e 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedLeadershipStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedLeadershipStore.java
@@ -170,10 +170,11 @@
                 groupedThreads("onos/store/dist/cluster/leadership", "status-change-handler", log));
         localNodeId = clusterService.getLocalNode().id();
         leaderElector = storageService.leaderElectorBuilder()
-                .withName("onos-leadership-elections")
-                .withElectionTimeout(electionTimeoutMillis)
-                .build()
-                .asLeaderElector();
+                      .withName("onos-leadership-elections")
+                      .withElectionTimeout(electionTimeoutMillis)
+                      .withRelaxedReadConsistency()
+                      .build()
+                      .asLeaderElector();
         leaderElector.addChangeListener(leadershipChangeListener);
         leaderElector.addStatusChangeListener(clientStatusListener);
         upgradeService.addListener(upgradeListener);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java b/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
index d7e478b..b035d61 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
@@ -51,6 +51,7 @@
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
+import com.google.common.base.Throwables;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.collect.Lists;
@@ -359,27 +360,36 @@
         finalFuture.whenComplete((channel, error) -> {
             if (error == null) {
                 if (!channel.isActive()) {
+                    CompletableFuture<Channel> currentFuture;
                     synchronized (channelPool) {
-                        CompletableFuture<Channel> currentFuture = channelPool.get(offset);
+                        currentFuture = channelPool.get(offset);
                         if (currentFuture == finalFuture) {
                             channelPool.set(offset, null);
-                            getChannel(endpoint, messageType).whenComplete((recursiveResult, recursiveError) -> {
-                                if (recursiveError == null) {
-                                    future.complete(recursiveResult);
-                                } else {
-                                    future.completeExceptionally(recursiveError);
-                                }
-                            });
-                        } else {
-                            currentFuture.whenComplete((recursiveResult, recursiveError) -> {
-                                if (recursiveError == null) {
-                                    future.complete(recursiveResult);
-                                } else {
-                                    future.completeExceptionally(recursiveError);
-                                }
-                            });
                         }
                     }
+
+                    ClientConnection connection = clientConnections.remove(channel);
+                    if (connection != null) {
+                        connection.close();
+                    }
+
+                    if (currentFuture == finalFuture) {
+                        getChannel(endpoint, messageType).whenComplete((recursiveResult, recursiveError) -> {
+                            if (recursiveError == null) {
+                                future.complete(recursiveResult);
+                            } else {
+                                future.completeExceptionally(recursiveError);
+                            }
+                        });
+                    } else {
+                        currentFuture.whenComplete((recursiveResult, recursiveError) -> {
+                            if (recursiveError == null) {
+                                future.complete(recursiveResult);
+                            } else {
+                                future.completeExceptionally(recursiveError);
+                            }
+                        });
+                    }
                 } else {
                     future.complete(channel);
                 }
@@ -424,6 +434,13 @@
                     if (sendError == null) {
                         executor.execute(() -> future.complete(result));
                     } else {
+                        Throwable cause = Throwables.getRootCause(sendError);
+                        if (!(cause instanceof TimeoutException) && !(cause instanceof MessagingException)) {
+                            channel.close().addListener(f -> {
+                                connection.close();
+                                clientConnections.remove(channel);
+                            });
+                        }
                         executor.execute(() -> future.completeExceptionally(sendError));
                     }
                 });
@@ -652,6 +669,20 @@
             context.close();
         }
 
+        @Override
+        public void channelInactive(ChannelHandlerContext context) throws Exception {
+            RemoteClientConnection clientConnection = clientConnections.remove(context.channel());
+            if (clientConnection != null) {
+                clientConnection.close();
+            }
+
+            RemoteServerConnection serverConnection = serverConnections.remove(context.channel());
+            if (serverConnection != null) {
+                serverConnection.close();
+            }
+            context.close();
+        }
+
         /**
          * Returns true if the given message should be handled.
          *
@@ -798,7 +829,6 @@
         @Override
         public void close() {
             if (closed.compareAndSet(false, true)) {
-                timeoutFuture.cancel(false);
                 for (Callback callback : futures.values()) {
                     callback.completeExceptionally(new ConnectException());
                 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java b/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java
index ded0f31..7f593e7 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java
@@ -255,6 +255,7 @@
             }
         } catch (InterruptedException e) {
             log.error("Error during executor shutdown", e);
+            Thread.currentThread().interrupt();
         }
 
         deviceDescs.clear();
@@ -867,7 +868,7 @@
                                                        DeviceId deviceId) {
         Map<ProviderId, DeviceDescriptions> descs = this.deviceDescs.get(deviceId);
         if (descs == null) {
-            return null;
+            return Stream.empty();
         }
         // inner-Map(=descs) is HashMap, thus requires synchronization even for reads
         final Optional<DeviceDescriptions> devDescs;
diff --git a/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java b/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
index f820feb..1335087 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
@@ -435,7 +435,7 @@
         // Check if a group is existing with the same key
         Group existingGroup = getGroup(groupDesc.deviceId(), groupDesc.appCookie());
         if (existingGroup != null) {
-            log.info("Group already exists with the same key {} in dev:{} with id:0x{}",
+            log.debug("Group already exists with the same key {} in dev:{} with id:0x{}",
                      groupDesc.appCookie(), groupDesc.deviceId(),
                      Integer.toHexString(existingGroup.id().id()));
             return;
diff --git a/core/store/dist/src/main/java/org/onosproject/store/mcast/impl/DistributedMcastStore.java b/core/store/dist/src/main/java/org/onosproject/store/mcast/impl/DistributedMcastStore.java
index 6b1eff5..b9fb869 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/mcast/impl/DistributedMcastStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/mcast/impl/DistributedMcastStore.java
@@ -41,6 +41,7 @@
 import org.onosproject.store.service.Versioned;
 import org.slf4j.Logger;
 
+import java.util.Collections;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -156,8 +157,15 @@
                     }
                     break;
                 case REMOVE:
+                    // Verify old data is not null
+                    checkNotNull(oldData);
+                    // Create a route removed event with just the route
+                    // and the source connect point
                     notifyDelegate(new McastEvent(McastEvent.Type.ROUTE_REMOVED,
-                                                      mcastRouteInfo(route)));
+                                                      mcastRouteInfo(route,
+                                                                     Collections.emptySet(),
+                                                                     oldData.source()
+                                                                     )));
                     break;
                 default:
                     log.warn("Unknown mcast operation type: {}", event.type());
diff --git a/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java b/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
index c59d30d..b6e6d04 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java
@@ -41,7 +41,6 @@
 import org.onosproject.net.topology.GeoDistanceLinkWeight;
 import org.onosproject.net.topology.GraphDescription;
 import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.MetricLinkWeight;
 import org.onosproject.net.topology.PathAdminService;
 import org.onosproject.net.topology.Topology;
@@ -74,7 +73,6 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.onlab.util.Tools.get;
 import static org.onlab.util.Tools.isNullOrEmpty;
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -165,11 +163,11 @@
         if (newLinkWeightFunction != null &&
                 !Objects.equals(newLinkWeightFunction, linkWeightFunction)) {
             linkWeightFunction = newLinkWeightFunction;
-            LinkWeight weight = linkWeightFunction.equals(LINK_METRIC) ?
+            LinkWeigher weight = linkWeightFunction.equals(LINK_METRIC) ?
                     new MetricLinkWeight() :
                     linkWeightFunction.equals(GEO_DISTANCE) ?
                             new GeoDistanceLinkWeight(deviceService) : null;
-            setDefaultLinkWeight(weight);
+            setDefaultLinkWeigher(weight);
         }
         log.info(FORMAT, linkWeightFunction);
     }
@@ -215,11 +213,6 @@
         return defaultTopology(topology).getPaths(src, dst);
     }
 
-    @Override
-    public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
-                              LinkWeight weight) {
-        return getPaths(topology, src, dst, adapt(weight));
-    }
 
     @Override
     public Set<Path> getPaths(Topology topology, DeviceId src,
@@ -249,12 +242,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                              LinkWeight weight) {
-        return getDisjointPaths(topology, src, dst, adapt(weight));
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst, LinkWeigher weigher) {
         return defaultTopology(topology).getDisjointPaths(src, dst, weigher);
@@ -267,12 +254,6 @@
     }
 
     @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src, DeviceId dst,
-                                              LinkWeight weight, Map<Link, Object> riskProfile) {
-        return getDisjointPaths(topology, src, dst, adapt(weight), riskProfile);
-    }
-
-    @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst, LinkWeigher weigher,
                                               Map<Link, Object> riskProfile) {
@@ -352,11 +333,6 @@
     }
 
     @Override
-    public void setDefaultLinkWeight(LinkWeight linkWeight) {
-        DefaultTopology.setDefaultLinkWeigher(adapt(linkWeight));
-    }
-
-    @Override
     public void setDefaultLinkWeigher(LinkWeigher linkWeigher) {
         DefaultTopology.setDefaultLinkWeigher(linkWeigher);
     }
diff --git a/core/store/dist/src/test/java/org/onosproject/store/cfg/DistributedComponentConfigStoreTest.java b/core/store/dist/src/test/java/org/onosproject/store/cfg/DistributedComponentConfigStoreTest.java
new file mode 100644
index 0000000..ddefb02
--- /dev/null
+++ b/core/store/dist/src/test/java/org/onosproject/store/cfg/DistributedComponentConfigStoreTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018-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.store.cfg;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigEvent;
+import org.onosproject.store.service.TestStorageService;
+
+import static org.junit.Assert.*;
+
+public class DistributedComponentConfigStoreTest {
+
+    private static final String C1 = "c1";
+    private static final String C2 = "c2";
+
+    private TestStore store;
+    private ComponentConfigEvent event;
+
+    /**
+     * Sets up the device key store and the storage service test harness.
+     */
+    @Before
+    public void setUp() {
+        store = new TestStore();
+        store.storageService = new TestStorageService();
+        store.setDelegate(e -> this.event = e);
+        store.activate();
+    }
+
+    /**
+     * Tears down the device key store.
+     */
+    @After
+    public void tearDown() {
+        store.deactivate();
+    }
+
+    @Test
+    public void basics() {
+        assertNull("property should not be found", store.getProperty(C1, "bar"));
+        store.setProperty(C1, "foo", "yo");
+        store.setProperty(C1, "bar", "true");
+        store.setProperty(C2, "goo", "6.28");
+        assertEquals("incorrect event", ComponentConfigEvent.Type.PROPERTY_SET, event.type());
+        assertEquals("incorrect event key", "goo", event.name());
+        assertEquals("incorrect event value", "6.28", event.value());
+
+        assertEquals("incorrect property value", "true", store.getProperty(C1, "bar"));
+        assertEquals("incorrect property count", ImmutableSet.of("foo", "bar"),
+                     store.getProperties(C1));
+
+        store.unsetProperty(C1, "bar");
+        assertEquals("incorrect event", ComponentConfigEvent.Type.PROPERTY_UNSET, event.type());
+        assertEquals("incorrect event key", "bar", event.name());
+        assertNull("incorrect event value", event.value());
+
+        assertNull("property should not be found", store.getProperty(C1, "bar"));
+        assertEquals("incorrect property count", ImmutableSet.of("foo"),
+                     store.getProperties(C1));
+    }
+
+    class TestStore extends DistributedComponentConfigStore {
+    }
+}
\ No newline at end of file
diff --git a/core/store/primitives/pom.xml b/core/store/primitives/pom.xml
index 5e2b75f..aaa9bdf 100644
--- a/core/store/primitives/pom.xml
+++ b/core/store/primitives/pom.xml
@@ -69,7 +69,7 @@
         <dependency>
             <groupId>io.atomix</groupId>
             <artifactId>atomix</artifactId>
-            <version>2.0.14</version>
+            <version>2.0.18</version>
         </dependency>
 
         <dependency>
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/CachingAsyncLeaderElector.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/CachingAsyncLeaderElector.java
new file mode 100644
index 0000000..91dcca5
--- /dev/null
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/CachingAsyncLeaderElector.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2018-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.store.primitives.impl;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import org.onosproject.cluster.Leadership;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.event.Change;
+import org.onosproject.store.service.AsyncLeaderElector;
+
+/**
+ * Caching async leader elector.
+ */
+public class CachingAsyncLeaderElector extends DelegatingAsyncLeaderElector {
+    private final LoadingCache<String, CompletableFuture<Leadership>> cache;
+    private final Consumer<Change<Leadership>> cacheUpdater;
+    private final Consumer<Status> statusListener;
+
+    public CachingAsyncLeaderElector(AsyncLeaderElector delegateLeaderElector) {
+        super(delegateLeaderElector);
+        cache = CacheBuilder.newBuilder()
+            .maximumSize(1000)
+            .build(CacheLoader.from(super::getLeadership));
+
+        cacheUpdater = change -> {
+            Leadership leadership = change.newValue();
+            cache.put(leadership.topic(), CompletableFuture.completedFuture(leadership));
+        };
+        statusListener = status -> {
+            if (status == Status.SUSPENDED || status == Status.INACTIVE) {
+                cache.invalidateAll();
+            }
+        };
+        addChangeListener(cacheUpdater);
+        addStatusChangeListener(statusListener);
+    }
+
+    @Override
+    public CompletableFuture<Leadership> getLeadership(String topic) {
+        return cache.getUnchecked(topic)
+            .whenComplete((r, e) -> {
+                if (e != null) {
+                    cache.invalidate(topic);
+                }
+            });
+    }
+
+    @Override
+    public CompletableFuture<Leadership> run(String topic, NodeId nodeId) {
+        return super.run(topic, nodeId).whenComplete((r, e) -> cache.invalidate(topic));
+    }
+
+    @Override
+    public CompletableFuture<Void> withdraw(String topic) {
+        return super.withdraw(topic).whenComplete((r, e) -> cache.invalidate(topic));
+    }
+
+    @Override
+    public CompletableFuture<Boolean> anoint(String topic, NodeId nodeId) {
+        return super.anoint(topic, nodeId).whenComplete((r, e) -> cache.invalidate(topic));
+    }
+
+    @Override
+    public CompletableFuture<Boolean> promote(String topic, NodeId nodeId) {
+        return super.promote(topic, nodeId).whenComplete((r, e) -> cache.invalidate(topic));
+    }
+
+    @Override
+    public CompletableFuture<Void> evict(NodeId nodeId) {
+        return super.evict(nodeId).whenComplete((r, e) -> cache.invalidateAll());
+    }
+
+    @Override
+    public CompletableFuture<Void> destroy() {
+        removeStatusChangeListener(statusListener);
+        return removeChangeListener(cacheUpdater);
+    }
+}
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DefaultLeaderElectorBuilder.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DefaultLeaderElectorBuilder.java
index 9cef490..21ddf03 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DefaultLeaderElectorBuilder.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DefaultLeaderElectorBuilder.java
@@ -15,12 +15,12 @@
  */
 package org.onosproject.store.primitives.impl;
 
-import java.util.concurrent.TimeUnit;
-
 import org.onosproject.store.primitives.DistributedPrimitiveCreator;
 import org.onosproject.store.service.AsyncLeaderElector;
 import org.onosproject.store.service.LeaderElectorBuilder;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Default implementation of {@code LeaderElectorBuilder}.
  */
@@ -34,6 +34,11 @@
 
     @Override
     public AsyncLeaderElector build() {
-        return primitiveCreator.newAsyncLeaderElector(name(), electionTimeoutMillis(), TimeUnit.MILLISECONDS);
+        AsyncLeaderElector leaderElector = primitiveCreator.newAsyncLeaderElector(name(), electionTimeoutMillis(),
+                                                                                  TimeUnit.MILLISECONDS);
+        if (relaxedReadConsistency()) {
+            leaderElector = new CachingAsyncLeaderElector(leaderElector);
+        }
+        return leaderElector;
     }
 }
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncLeaderElector.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncLeaderElector.java
new file mode 100644
index 0000000..0235616
--- /dev/null
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncLeaderElector.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018-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.store.primitives.impl;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import org.onosproject.cluster.Leadership;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.event.Change;
+import org.onosproject.store.service.AsyncLeaderElector;
+
+/**
+ * Delegating leader elector.
+ */
+public class DelegatingAsyncLeaderElector extends DelegatingDistributedPrimitive implements AsyncLeaderElector {
+
+    private final AsyncLeaderElector delegateLeaderElector;
+
+    public DelegatingAsyncLeaderElector(AsyncLeaderElector delegateLeaderElector) {
+        super(delegateLeaderElector);
+        this.delegateLeaderElector = delegateLeaderElector;
+    }
+
+    @Override
+    public CompletableFuture<Leadership> run(String topic, NodeId nodeId) {
+        return delegateLeaderElector.run(topic, nodeId);
+    }
+
+    @Override
+    public CompletableFuture<Void> withdraw(String topic) {
+        return delegateLeaderElector.withdraw(topic);
+    }
+
+    @Override
+    public CompletableFuture<Boolean> anoint(String topic, NodeId nodeId) {
+        return delegateLeaderElector.anoint(topic, nodeId);
+    }
+
+    @Override
+    public CompletableFuture<Void> evict(NodeId nodeId) {
+        return delegateLeaderElector.evict(nodeId);
+    }
+
+    @Override
+    public CompletableFuture<Boolean> promote(String topic, NodeId nodeId) {
+        return delegateLeaderElector.promote(topic, nodeId);
+    }
+
+    @Override
+    public CompletableFuture<Leadership> getLeadership(String topic) {
+        return delegateLeaderElector.getLeadership(topic);
+    }
+
+    @Override
+    public CompletableFuture<Map<String, Leadership>> getLeaderships() {
+        return delegateLeaderElector.getLeaderships();
+    }
+
+    @Override
+    public CompletableFuture<Void> addChangeListener(Consumer<Change<Leadership>> consumer) {
+        return delegateLeaderElector.addChangeListener(consumer);
+    }
+
+    @Override
+    public CompletableFuture<Void> removeChangeListener(Consumer<Change<Leadership>> consumer) {
+        return delegateLeaderElector.removeChangeListener(consumer);
+    }
+}
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionClient.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionClient.java
index c5d281a..7c8dee8 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionClient.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionClient.java
@@ -278,7 +278,7 @@
 
     @Override
     public AsyncLeaderElector newAsyncLeaderElector(String name, long leaderTimeout, TimeUnit timeUnit) {
-        AtomixLeaderElector leaderElector = new AtomixLeaderElector(client.newProxyBuilder()
+        return new AtomixLeaderElector(client.newProxyBuilder()
                 .withName(name)
                 .withServiceType(DistributedPrimitive.Type.LEADER_ELECTOR.name())
                 .withReadConsistency(ReadConsistency.LINEARIZABLE)
@@ -289,8 +289,6 @@
                 .build()
                 .open()
                 .join());
-        leaderElector.setupCache().join();
-        return leaderElector;
     }
 
     @Override
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java
index 1b201cd..eb48f66 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java
@@ -206,8 +206,8 @@
                 .withElectionThreshold(ELECTION_THRESHOLD)
                 .withStorage(RaftStorage.newBuilder()
                         .withPrefix(String.format("partition-%s", partition.getId()))
-                        .withStorageLevel(StorageLevel.DISK)
-                        .withFlushOnCommit()
+                        .withStorageLevel(StorageLevel.MAPPED)
+                        .withFlushOnCommit(false)
                         .withSerializer(new AtomixSerializerAdapter(Serializer.using(StorageNamespaces.RAFT_STORAGE)))
                         .withDirectory(partition.getDataFolder())
                         .withMaxSegmentSize(MAX_SEGMENT_SIZE)
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLock.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLock.java
index c5a4250..c234be3 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLock.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLock.java
@@ -16,22 +16,29 @@
 package org.onosproject.store.primitives.resources.impl;
 
 import java.time.Duration;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
+import com.google.common.collect.Maps;
 import io.atomix.protocols.raft.proxy.RaftProxy;
-import io.atomix.utils.concurrent.Futures;
 import org.onlab.util.KryoNamespace;
+import org.onlab.util.OrderedExecutor;
+import org.onlab.util.SharedScheduledExecutors;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.AsyncDistributedLock;
 import org.onosproject.store.service.Serializer;
-import org.onosproject.store.service.StorageException;
 import org.onosproject.store.service.Version;
 
+import static org.onlab.util.Tools.orderedFuture;
+import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockEvents.FAILED;
+import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockEvents.LOCKED;
 import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockOperations.LOCK;
 import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockOperations.Lock;
 import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockOperations.UNLOCK;
@@ -39,6 +46,9 @@
 
 /**
  * Atomix lock implementation.
+ * <p>
+ * This {@link org.onosproject.store.service.DistributedLock} implementation uses a {@link RaftProxy} to interact
+ * with a {@link AtomixDistributedLockService} replicated state machine.
  */
 public class AtomixDistributedLock extends AbstractRaftPrimitive implements AsyncDistributedLock {
     private static final Serializer SERIALIZER = Serializer.using(KryoNamespace.newBuilder()
@@ -47,108 +57,125 @@
         .register(AtomixDistributedLockEvents.NAMESPACE)
         .build());
 
-    private final Map<Integer, CompletableFuture<Version>> futures = new ConcurrentHashMap<>();
+    private final ScheduledExecutorService scheduledExecutor;
+    private final Executor orderedExecutor;
+    private final Map<Integer, LockAttempt> attempts = Maps.newConcurrentMap();
     private final AtomicInteger id = new AtomicInteger();
-    private int lock;
+    private final AtomicInteger lock = new AtomicInteger();
 
     public AtomixDistributedLock(RaftProxy proxy) {
         super(proxy);
-        proxy.addStateChangeListener(this::handleStateChange);
-        proxy.addEventListener(AtomixDistributedLockEvents.LOCK, SERIALIZER::decode, this::handleLocked);
-        proxy.addEventListener(AtomixDistributedLockEvents.FAIL, SERIALIZER::decode, this::handleFailed);
+        this.scheduledExecutor = SharedScheduledExecutors.getPoolThreadExecutor();
+        this.orderedExecutor = new OrderedExecutor(scheduledExecutor);
+        proxy.addEventListener(LOCKED, SERIALIZER::decode, this::handleLocked);
+        proxy.addEventListener(FAILED, SERIALIZER::decode, this::handleFailed);
     }
 
+    /**
+     * Handles a {@code LOCKED} event.
+     *
+     * @param event the event to handle
+     */
     private void handleLocked(LockEvent event) {
-        CompletableFuture<Version> future = futures.remove(event.id());
-        if (future != null) {
-            this.lock = event.id();
-            future.complete(new Version(event.version()));
+        // Remove the LockAttempt from the attempts map and complete it with the lock version if it exists.
+        // If the attempt no longer exists, it likely was expired by a client-side timer.
+        LockAttempt attempt = attempts.remove(event.id());
+        if (attempt != null) {
+            attempt.complete(new Version(event.version()));
         }
     }
 
+    /**
+     * Handles a {@code FAILED} event.
+     *
+     * @param event the event to handle
+     */
     private void handleFailed(LockEvent event) {
-        CompletableFuture<Version> future = futures.remove(event.id());
-        if (future != null) {
-            future.complete(null);
-        }
-    }
-
-    private void handleStateChange(RaftProxy.State state) {
-        if (state != RaftProxy.State.CONNECTED) {
-            Iterator<Map.Entry<Integer, CompletableFuture<Version>>> iterator = futures.entrySet().iterator();
-            while (iterator.hasNext()) {
-                Map.Entry<Integer, CompletableFuture<Version>> entry = iterator.next();
-                entry.getValue().completeExceptionally(new StorageException.Unavailable());
-                proxy.invoke(UNLOCK, SERIALIZER::encode, new Unlock(entry.getKey()));
-                iterator.remove();
-            }
-            lock = 0;
+        // Remove the LockAttempt from the attempts map and complete it with a null value if it exists.
+        // If the attempt no longer exists, it likely was expired by a client-side timer.
+        LockAttempt attempt = attempts.remove(event.id());
+        if (attempt != null) {
+            attempt.complete(null);
         }
     }
 
     @Override
     public CompletableFuture<Version> lock() {
-        RaftProxy.State state = proxy.getState();
-        if (state != RaftProxy.State.CONNECTED) {
-            return Futures.exceptionalFuture(new StorageException.Unavailable());
-        }
-
-        CompletableFuture<Version> future = new CompletableFuture<>();
-        int id = this.id.incrementAndGet();
-        futures.put(id, future);
-        proxy.invoke(LOCK, SERIALIZER::encode, new Lock(id, -1)).whenComplete((result, error) -> {
+        // Create and register a new attempt and invoke the LOCK operation on the replicated state machine.
+        LockAttempt attempt = new LockAttempt();
+        proxy.invoke(LOCK, SERIALIZER::encode, new Lock(attempt.id(), -1)).whenComplete((result, error) -> {
             if (error != null) {
-                futures.remove(id);
-                future.completeExceptionally(error);
+                attempt.completeExceptionally(error);
             }
         });
-        return future;
+
+        // Return an ordered future that can safely be blocked inside the executor thread.
+        return orderedFuture(attempt, orderedExecutor, scheduledExecutor);
     }
 
     @Override
     public CompletableFuture<Optional<Version>> tryLock() {
+        // If the proxy is currently disconnected from the cluster, we can just fail the lock attempt here.
         RaftProxy.State state = proxy.getState();
         if (state != RaftProxy.State.CONNECTED) {
-            return Futures.exceptionalFuture(new StorageException.Unavailable());
+            return CompletableFuture.completedFuture(Optional.empty());
         }
 
-        CompletableFuture<Version> future = new CompletableFuture<>();
-        int id = this.id.incrementAndGet();
-        futures.put(id, future);
-        proxy.invoke(LOCK, SERIALIZER::encode, new Lock(id, 0)).whenComplete((result, error) -> {
+        // Create and register a new attempt and invoke the LOCK operation on teh replicated state machine with
+        // a 0 timeout. The timeout will cause the state machine to immediately reject the request if the lock is
+        // already owned by another process.
+        LockAttempt attempt = new LockAttempt();
+        proxy.invoke(LOCK, SERIALIZER::encode, new Lock(attempt.id(), 0)).whenComplete((result, error) -> {
             if (error != null) {
-                futures.remove(id);
-                future.completeExceptionally(error);
+                attempt.completeExceptionally(error);
             }
         });
-        return future.thenApply(Optional::ofNullable);
+
+        // Return an ordered future that can safely be blocked inside the executor thread.
+        return orderedFuture(attempt, orderedExecutor, scheduledExecutor)
+            .thenApply(Optional::ofNullable);
     }
 
     @Override
     public CompletableFuture<Optional<Version>> tryLock(Duration timeout) {
-        RaftProxy.State state = proxy.getState();
-        if (state != RaftProxy.State.CONNECTED) {
-            return Futures.exceptionalFuture(new StorageException.Unavailable());
-        }
-
-        CompletableFuture<Version> future = new CompletableFuture<>();
-        int id = this.id.incrementAndGet();
-        futures.put(id, future);
-        proxy.invoke(LOCK, SERIALIZER::encode, new Lock(id, timeout.toMillis())).whenComplete((result, error) -> {
-            if (error != null) {
-                futures.remove(id);
-                future.completeExceptionally(error);
-            }
+        // Create a lock attempt with a client-side timeout and fail the lock if the timer expires.
+        // Because time does not progress at the same rate on different nodes, we can't guarantee that
+        // the lock won't be granted to this process after it's expired here. Thus, if this timer expires and
+        // we fail the lock on the client, we also still need to send an UNLOCK command to the cluster in case it's
+        // later granted by the cluster. Note that the semantics of the Raft client will guarantee this operation
+        // occurs after any prior LOCK attempt, and the Raft client will retry the UNLOCK request until successful.
+        // Additionally, sending the unique lock ID with the command ensures we won't accidentally unlock a different
+        // lock call also granted to this process.
+        LockAttempt attempt = new LockAttempt(timeout, a -> {
+            a.complete(null);
+            proxy.invoke(UNLOCK, SERIALIZER::encode, new Unlock(a.id()));
         });
-        return future.thenApply(Optional::ofNullable);
+
+        // Invoke the LOCK operation on the replicated state machine with the given timeout. If the lock is currently
+        // held by another process, the state machine will add the attempt to a queue and publish a FAILED event if
+        // the timer expires before this process can be granted the lock. If the client cannot reach the Raft cluster,
+        // the client-side timer will expire the attempt.
+        proxy.invoke(LOCK, SERIALIZER::encode, new Lock(attempt.id(), timeout.toMillis()))
+            .whenComplete((result, error) -> {
+                if (error != null) {
+                    attempt.completeExceptionally(error);
+                }
+            });
+
+        // Return an ordered future that can safely be blocked inside the executor thread.
+        return orderedFuture(attempt, orderedExecutor, scheduledExecutor)
+            .thenApply(Optional::ofNullable);
     }
 
     @Override
     public CompletableFuture<Void> unlock() {
-        int lock = this.lock;
-        this.lock = 0;
+        // Use the current lock ID to ensure we only unlock the lock currently held by this process.
+        int lock = this.lock.getAndSet(0);
         if (lock != 0) {
-            return proxy.invoke(UNLOCK, SERIALIZER::encode, new Unlock(lock));
+            return orderedFuture(
+                proxy.invoke(UNLOCK, SERIALIZER::encode, new Unlock(lock)),
+                orderedExecutor,
+                scheduledExecutor);
         }
         return CompletableFuture.completedFuture(null);
     }
@@ -161,4 +188,60 @@
     public CompletableFuture<Void> close() {
         return proxy.close();
     }
+
+    /**
+     * Lock attempt.
+     */
+    private class LockAttempt extends CompletableFuture<Version> {
+        private final int id;
+        private final ScheduledFuture<?> scheduledFuture;
+
+        LockAttempt() {
+            this(null, null);
+        }
+
+        LockAttempt(Duration duration, Consumer<LockAttempt> callback) {
+            this.id = AtomixDistributedLock.this.id.incrementAndGet();
+            this.scheduledFuture = duration != null && callback != null
+                ? scheduledExecutor.schedule(() -> callback.accept(this), duration.toMillis(), TimeUnit.MILLISECONDS)
+                : null;
+            attempts.put(id, this);
+        }
+
+        /**
+         * Returns the lock attempt ID.
+         *
+         * @return the lock attempt ID
+         */
+        int id() {
+            return id;
+        }
+
+        @Override
+        public boolean complete(Version version) {
+            if (isDone()) {
+                return super.complete(null);
+            }
+            cancel();
+            if (version != null) {
+                lock.set(id);
+                return super.complete(version);
+            } else {
+                return super.complete(null);
+            }
+        }
+
+        @Override
+        public boolean completeExceptionally(Throwable ex) {
+            cancel();
+            return super.completeExceptionally(ex);
+        }
+
+        private void cancel() {
+            if (scheduledFuture != null) {
+                scheduledFuture.cancel(false);
+            }
+            attempts.remove(id);
+        }
+    }
 }
\ No newline at end of file
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockEvents.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockEvents.java
index 0ef9270..e6d2b2a 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockEvents.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockEvents.java
@@ -23,8 +23,8 @@
  * Raft value events.
  */
 public enum AtomixDistributedLockEvents implements EventType {
-    LOCK("lock"),
-    FAIL("fail");
+    LOCKED("lock"),
+    FAILED("fail");
 
     private final String id;
 
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockService.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockService.java
index a2dab95..e730ffd 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockService.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockService.java
@@ -33,7 +33,8 @@
 import org.onosproject.store.service.Serializer;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
-import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockEvents.FAIL;
+import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockEvents.FAILED;
+import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockEvents.LOCKED;
 import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockOperations.LOCK;
 import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockOperations.Lock;
 import static org.onosproject.store.primitives.resources.impl.AtomixDistributedLockOperations.UNLOCK;
@@ -71,6 +72,9 @@
     public void install(SnapshotReader reader) {
         lock = reader.readObject(SERIALIZER::decode);
         queue = reader.readObject(SERIALIZER::decode);
+
+        // After the snapshot is installed, we need to cancel any existing timers and schedule new ones based on the
+        // state provided by the snapshot.
         timers.values().forEach(Scheduled::cancel);
         timers.clear();
         for (LockHolder holder : queue) {
@@ -82,7 +86,7 @@
                             queue.remove(holder);
                             RaftSession session = sessions().getSession(holder.session);
                             if (session != null && session.getState().active()) {
-                                session.publish(FAIL, SERIALIZER::encode, new LockEvent(holder.id, holder.index));
+                                session.publish(FAILED, SERIALIZER::encode, new LockEvent(holder.id, holder.index));
                             }
                         }));
             }
@@ -105,6 +109,9 @@
      * @param commit the lock commit
      */
     protected void lock(Commit<Lock> commit) {
+        // If the lock is not already owned, immediately grant the lock to the requester.
+        // Note that we still have to publish an event to the session. The event is guaranteed to be received
+        // by the client-side primitive after the LOCK response.
         if (lock == null) {
             lock = new LockHolder(
                 commit.value().id(),
@@ -112,11 +119,14 @@
                 commit.session().sessionId().id(),
                 0);
             commit.session().publish(
-                AtomixDistributedLockEvents.LOCK,
+                LOCKED,
                 SERIALIZER::encode,
                 new LockEvent(commit.value().id(), commit.index()));
+        // If the timeout is 0, that indicates this is a tryLock request. Immediately fail the request.
         } else if (commit.value().timeout() == 0) {
-            commit.session().publish(FAIL, SERIALIZER::encode, new LockEvent(commit.value().id(), commit.index()));
+            commit.session().publish(FAILED, SERIALIZER::encode, new LockEvent(commit.value().id(), commit.index()));
+        // If a timeout exists, add the request to the queue and set a timer. Note that the lock request expiration
+        // time is based on the *state machine* time - not the system time - to ensure consistency across servers.
         } else if (commit.value().timeout() > 0) {
             LockHolder holder = new LockHolder(
                 commit.value().id(),
@@ -125,15 +135,19 @@
                 wallClock().getTime().unixTimestamp() + commit.value().timeout());
             queue.add(holder);
             timers.put(commit.index(), scheduler().schedule(Duration.ofMillis(commit.value().timeout()), () -> {
+                // When the lock request timer expires, remove the request from the queue and publish a FAILED
+                // event to the session. Note that this timer is guaranteed to be executed in the same thread as the
+                // state machine commands, so there's no need to use a lock here.
                 timers.remove(commit.index());
                 queue.remove(holder);
                 if (commit.session().getState().active()) {
                     commit.session().publish(
-                        FAIL,
+                        FAILED,
                         SERIALIZER::encode,
                         new LockEvent(commit.value().id(), commit.index()));
                 }
             }));
+        // If the lock is -1, just add the request to the queue with no expiration.
         } else {
             LockHolder holder = new LockHolder(
                 commit.value().id(),
@@ -151,24 +165,35 @@
      */
     protected void unlock(Commit<Unlock> commit) {
         if (lock != null) {
+            // If the commit's session does not match the current lock holder, ignore the request.
             if (lock.session != commit.session().sessionId().id()) {
                 return;
             }
 
+            // If the current lock ID does not match the requested lock ID, ignore the request. This ensures that
+            // internal releases of locks that were never acquired by the client-side primitive do not cause
+            // legitimate locks to be unlocked.
+            if (lock.id != commit.value().id()) {
+                return;
+            }
+
+            // The lock has been released. Populate the lock from the queue.
             lock = queue.poll();
             while (lock != null) {
+                // If the waiter has a lock timer, cancel the timer.
                 Scheduled timer = timers.remove(lock.index);
                 if (timer != null) {
                     timer.cancel();
                 }
 
+                // If the lock session is for some reason inactive, continue on to the next waiter. Otherwise,
+                // publish a LOCKED event to the new lock holder's session.
                 RaftSession session = sessions().getSession(lock.session);
-                if (session == null || session.getState() == RaftSession.State.EXPIRED
-                    || session.getState() == RaftSession.State.CLOSED) {
+                if (session == null || !session.getState().active()) {
                     lock = queue.poll();
                 } else {
                     session.publish(
-                        AtomixDistributedLockEvents.LOCK,
+                        LOCKED,
                         SERIALIZER::encode,
                         new LockEvent(lock.id, commit.index()));
                     break;
@@ -177,29 +202,41 @@
         }
     }
 
+    /**
+     * Handles a session that has been closed by a client or expired by the cluster.
+     * <p>
+     * When a session is removed, if the session is the current lock holder then the lock is released and the next
+     * session waiting in the queue is granted the lock. Additionally, all pending lock requests for the session
+     * are removed from the lock queue.
+     *
+     * @param session the closed session
+     */
     private void releaseSession(RaftSession session) {
+        // Remove all instances of the session from the lock queue.
+        queue.removeIf(lock -> lock.session == session.sessionId().id());
+
+        // If the removed session is the current holder of the lock, nullify the lock and attempt to grant it
+        // to the next waiter in the queue.
         if (lock != null && lock.session == session.sessionId().id()) {
             lock = queue.poll();
             while (lock != null) {
-                if (lock.session == session.sessionId().id()) {
+                // If the waiter has a lock timer, cancel the timer.
+                Scheduled timer = timers.remove(lock.index);
+                if (timer != null) {
+                    timer.cancel();
+                }
+
+                // If the lock session is inactive, continue on to the next waiter. Otherwise,
+                // publish a LOCKED event to the new lock holder's session.
+                RaftSession lockSession = sessions().getSession(lock.session);
+                if (lockSession == null || !lockSession.getState().active()) {
                     lock = queue.poll();
                 } else {
-                    Scheduled timer = timers.remove(lock.index);
-                    if (timer != null) {
-                        timer.cancel();
-                    }
-
-                    RaftSession lockSession = sessions().getSession(lock.session);
-                    if (lockSession == null || lockSession.getState() == RaftSession.State.EXPIRED
-                        || lockSession.getState() == RaftSession.State.CLOSED) {
-                        lock = queue.poll();
-                    } else {
-                        lockSession.publish(
-                            AtomixDistributedLockEvents.LOCK,
-                            SERIALIZER::encode,
-                            new LockEvent(lock.id, lock.index));
-                        break;
-                    }
+                    lockSession.publish(
+                        LOCKED,
+                        SERIALIZER::encode,
+                        new LockEvent(lock.id, lock.index));
+                    break;
                 }
             }
         }
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElector.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElector.java
index f2f4a36..53c7094 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElector.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElector.java
@@ -21,9 +21,6 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Consumer;
 
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
 import com.google.common.collect.Sets;
 import io.atomix.protocols.raft.proxy.RaftProxy;
 import org.onlab.util.KryoNamespace;
@@ -63,29 +60,9 @@
             .build());
 
     private final Set<Consumer<Change<Leadership>>> leadershipChangeListeners = Sets.newCopyOnWriteArraySet();
-    private final Consumer<Change<Leadership>> cacheUpdater;
-    private final Consumer<Status> statusListener;
-
-    private final LoadingCache<String, CompletableFuture<Leadership>> cache;
 
     public AtomixLeaderElector(RaftProxy proxy) {
         super(proxy);
-        cache = CacheBuilder.newBuilder()
-                .maximumSize(1000)
-                .build(CacheLoader.from(topic -> proxy.invoke(
-                        GET_LEADERSHIP, SERIALIZER::encode, new GetLeadership(topic), SERIALIZER::decode)));
-
-        cacheUpdater = change -> {
-            Leadership leadership = change.newValue();
-            cache.put(leadership.topic(), CompletableFuture.completedFuture(leadership));
-        };
-        statusListener = status -> {
-            if (status == Status.SUSPENDED || status == Status.INACTIVE) {
-                cache.invalidateAll();
-            }
-        };
-        addStatusChangeListener(statusListener);
-
         proxy.addStateChangeListener(state -> {
             if (state == RaftProxy.State.CONNECTED && isListening()) {
                 proxy.invoke(ADD_LISTENER);
@@ -94,43 +71,29 @@
         proxy.addEventListener(CHANGE, SERIALIZER::decode, this::handleEvent);
     }
 
-    @Override
-    public CompletableFuture<Void> destroy() {
-        removeStatusChangeListener(statusListener);
-        return removeChangeListener(cacheUpdater);
-    }
-
-    public CompletableFuture<AtomixLeaderElector> setupCache() {
-        return addChangeListener(cacheUpdater).thenApply(v -> this);
-    }
-
     private void handleEvent(List<Change<Leadership>> changes) {
         changes.forEach(change -> leadershipChangeListeners.forEach(l -> l.accept(change)));
     }
 
     @Override
     public CompletableFuture<Leadership> run(String topic, NodeId nodeId) {
-        return proxy.<Run, Leadership>invoke(RUN, SERIALIZER::encode, new Run(topic, nodeId), SERIALIZER::decode)
-                .whenComplete((r, e) -> cache.invalidate(topic));
+        return proxy.<Run, Leadership>invoke(RUN, SERIALIZER::encode, new Run(topic, nodeId), SERIALIZER::decode);
     }
 
     @Override
     public CompletableFuture<Void> withdraw(String topic) {
-        return proxy.invoke(WITHDRAW, SERIALIZER::encode, new Withdraw(topic))
-                .whenComplete((r, e) -> cache.invalidate(topic));
+        return proxy.invoke(WITHDRAW, SERIALIZER::encode, new Withdraw(topic));
     }
 
     @Override
     public CompletableFuture<Boolean> anoint(String topic, NodeId nodeId) {
-        return proxy.<Anoint, Boolean>invoke(ANOINT, SERIALIZER::encode, new Anoint(topic, nodeId), SERIALIZER::decode)
-                .whenComplete((r, e) -> cache.invalidate(topic));
+        return proxy.<Anoint, Boolean>invoke(ANOINT, SERIALIZER::encode, new Anoint(topic, nodeId), SERIALIZER::decode);
     }
 
     @Override
     public CompletableFuture<Boolean> promote(String topic, NodeId nodeId) {
         return proxy.<Promote, Boolean>invoke(
-                PROMOTE, SERIALIZER::encode, new Promote(topic, nodeId), SERIALIZER::decode)
-                .whenComplete((r, e) -> cache.invalidate(topic));
+                PROMOTE, SERIALIZER::encode, new Promote(topic, nodeId), SERIALIZER::decode);
     }
 
     @Override
@@ -140,12 +103,7 @@
 
     @Override
     public CompletableFuture<Leadership> getLeadership(String topic) {
-        return cache.getUnchecked(topic)
-                .whenComplete((r, e) -> {
-                    if (e != null) {
-                        cache.invalidate(topic);
-                    }
-                });
+        return proxy.invoke(GET_LEADERSHIP, SERIALIZER::encode, new GetLeadership(topic), SERIALIZER::decode);
     }
 
     @Override
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixAtomicCounterMapServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixAtomicCounterMapServiceTest.java
index 698f015..9d58758 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixAtomicCounterMapServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixAtomicCounterMapServiceTest.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.store.primitives.resources.impl;
 
-import io.atomix.protocols.raft.service.ServiceId;
 import io.atomix.protocols.raft.service.impl.DefaultCommit;
 import io.atomix.protocols.raft.session.impl.RaftSessionContext;
 import io.atomix.protocols.raft.storage.RaftStorage;
@@ -42,7 +41,7 @@
                 .withPrefix("test")
                 .withStorageLevel(StorageLevel.MEMORY)
                 .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         AtomixAtomicCounterMapService service = new AtomixAtomicCounterMapService();
         service.put(new DefaultCommit<>(
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapServiceTest.java
index 09ac5ec..c292959 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapServiceTest.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.store.primitives.resources.impl;
 
-import io.atomix.protocols.raft.service.ServiceId;
 import io.atomix.protocols.raft.service.impl.DefaultCommit;
 import io.atomix.protocols.raft.session.impl.RaftSessionContext;
 import io.atomix.protocols.raft.storage.RaftStorage;
@@ -46,7 +45,7 @@
                 .withPrefix("test")
                 .withStorageLevel(StorageLevel.MEMORY)
                 .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         AtomixConsistentMapService service = new AtomixConsistentMapService();
         service.put(new DefaultCommit<>(
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentSetMultimapServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentSetMultimapServiceTest.java
index 66173d0..f9418a4 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentSetMultimapServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentSetMultimapServiceTest.java
@@ -18,7 +18,6 @@
 import java.util.Collection;
 import java.util.Collections;
 
-import io.atomix.protocols.raft.service.ServiceId;
 import io.atomix.protocols.raft.service.impl.DefaultCommit;
 import io.atomix.protocols.raft.session.impl.RaftSessionContext;
 import io.atomix.protocols.raft.storage.RaftStorage;
@@ -50,7 +49,7 @@
                 .withPrefix("test")
                 .withStorageLevel(StorageLevel.MEMORY)
                 .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         AtomixConsistentSetMultimapService service = new AtomixConsistentSetMultimapService();
         service.put(new DefaultCommit<>(
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixCounterServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixCounterServiceTest.java
index fa7161f..4dd4148 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixCounterServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixCounterServiceTest.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.store.primitives.resources.impl;
 
-import io.atomix.protocols.raft.service.ServiceId;
 import io.atomix.protocols.raft.service.impl.DefaultCommit;
 import io.atomix.protocols.raft.session.impl.RaftSessionContext;
 import io.atomix.protocols.raft.storage.RaftStorage;
@@ -42,7 +41,7 @@
                 .withPrefix("test")
                 .withStorageLevel(StorageLevel.MEMORY)
                 .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         AtomixCounterService service = new AtomixCounterService();
         service.set(new DefaultCommit<>(
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockServiceTest.java
index 69942a7..fb92eba 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDistributedLockServiceTest.java
@@ -20,6 +20,7 @@
 import io.atomix.protocols.raft.ReadConsistency;
 import io.atomix.protocols.raft.cluster.MemberId;
 import io.atomix.protocols.raft.impl.RaftContext;
+import io.atomix.protocols.raft.impl.RaftServiceManager;
 import io.atomix.protocols.raft.operation.OperationType;
 import io.atomix.protocols.raft.protocol.RaftServerProtocol;
 import io.atomix.protocols.raft.service.ServiceId;
@@ -55,19 +56,21 @@
             .withPrefix("test")
             .withStorageLevel(StorageLevel.MEMORY)
             .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         AtomicLong index = new AtomicLong();
         DefaultServiceContext context = mock(DefaultServiceContext.class);
         expect(context.serviceType()).andReturn(ServiceType.from(LEADER_ELECTOR.name())).anyTimes();
         expect(context.serviceName()).andReturn("test").anyTimes();
         expect(context.serviceId()).andReturn(ServiceId.from(1)).anyTimes();
-        expect(context.executor()).andReturn(mock(ThreadContext.class)).anyTimes();
         expect(context.currentIndex()).andReturn(index.get()).anyTimes();
         expect(context.currentOperation()).andReturn(OperationType.COMMAND).anyTimes();
 
         RaftContext server = mock(RaftContext.class);
-        expect(server.getProtocol()).andReturn(mock(RaftServerProtocol.class));
+        expect(server.getProtocol()).andReturn(mock(RaftServerProtocol.class)).anyTimes();
+        RaftServiceManager manager = mock(RaftServiceManager.class);
+        expect(manager.executor()).andReturn(mock(ThreadContext.class)).anyTimes();
+        expect(server.getServiceManager()).andReturn(manager).anyTimes();
 
         replay(context, server);
 
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDocumentTreeServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDocumentTreeServiceTest.java
index fd92e2b..21c5621 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDocumentTreeServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixDocumentTreeServiceTest.java
@@ -17,7 +17,6 @@
 
 import java.util.Optional;
 
-import io.atomix.protocols.raft.service.ServiceId;
 import io.atomix.protocols.raft.service.impl.DefaultCommit;
 import io.atomix.protocols.raft.session.impl.RaftSessionContext;
 import io.atomix.protocols.raft.storage.RaftStorage;
@@ -59,7 +58,7 @@
                 .withPrefix("test")
                 .withStorageLevel(StorageLevel.MEMORY)
                 .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         AtomixDocumentTreeService service = new AtomixDocumentTreeService(ordering);
         service.update(new DefaultCommit<>(
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElectorServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElectorServiceTest.java
index e422436..4f7aa72 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElectorServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixLeaderElectorServiceTest.java
@@ -34,7 +34,6 @@
 import io.atomix.time.WallClockTimestamp;
 import io.atomix.utils.concurrent.AtomixThreadFactory;
 import io.atomix.utils.concurrent.SingleThreadContextFactory;
-import io.atomix.utils.concurrent.ThreadContext;
 import org.junit.Test;
 import org.onosproject.cluster.Leadership;
 import org.onosproject.cluster.NodeId;
@@ -58,13 +57,12 @@
                 .withPrefix("test")
                 .withStorageLevel(StorageLevel.MEMORY)
                 .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         DefaultServiceContext context = mock(DefaultServiceContext.class);
         expect(context.serviceType()).andReturn(ServiceType.from(LEADER_ELECTOR.name())).anyTimes();
         expect(context.serviceName()).andReturn("test").anyTimes();
         expect(context.serviceId()).andReturn(ServiceId.from(1)).anyTimes();
-        expect(context.executor()).andReturn(mock(ThreadContext.class)).anyTimes();
 
         RaftContext server = mock(RaftContext.class);
         expect(server.getProtocol()).andReturn(mock(RaftServerProtocol.class));
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixWorkQueueServiceTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixWorkQueueServiceTest.java
index 2529523..fdc1d97 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixWorkQueueServiceTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixWorkQueueServiceTest.java
@@ -37,7 +37,6 @@
 import io.atomix.time.WallClockTimestamp;
 import io.atomix.utils.concurrent.AtomixThreadFactory;
 import io.atomix.utils.concurrent.SingleThreadContextFactory;
-import io.atomix.utils.concurrent.ThreadContext;
 import org.junit.Test;
 import org.onosproject.store.service.Task;
 
@@ -61,13 +60,12 @@
                 .withPrefix("test")
                 .withStorageLevel(StorageLevel.MEMORY)
                 .build());
-        Snapshot snapshot = store.newSnapshot(ServiceId.from(1), "test", 2, new WallClockTimestamp());
+        Snapshot snapshot = store.newSnapshot(2, new WallClockTimestamp());
 
         DefaultServiceContext context = mock(DefaultServiceContext.class);
         expect(context.serviceType()).andReturn(ServiceType.from(WORK_QUEUE.name())).anyTimes();
         expect(context.serviceName()).andReturn("test").anyTimes();
         expect(context.serviceId()).andReturn(ServiceId.from(1)).anyTimes();
-        expect(context.executor()).andReturn(mock(ThreadContext.class)).anyTimes();
 
         RaftContext server = mock(RaftContext.class);
         expect(server.getProtocol()).andReturn(mock(RaftServerProtocol.class));
diff --git a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaFlowRuleProgrammable.java b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaFlowRuleProgrammable.java
index d0e78fc..5e05232 100644
--- a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaFlowRuleProgrammable.java
+++ b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaFlowRuleProgrammable.java
@@ -30,6 +30,7 @@
 import java.util.List;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import static org.slf4j.LoggerFactory.getLogger;
@@ -62,8 +63,8 @@
         }
         // Apply the valid rules on the device
         Collection<FlowRule> added = rules.stream()
-                .map(r -> createCrossConnectFlowRule(r))
-                .filter(xc -> installCrossConnect(xc))
+                .map(this::createCrossConnectFlowRule)
+                .filter(this::installCrossConnect)
                 .collect(Collectors.toList());
         restCiena.setCrossConnectCache(added);
         return added;
@@ -79,8 +80,8 @@
             return Collections.emptyList();
         }
         Collection<FlowRule> removed = rules.stream()
-                .map(r -> createCrossConnectFlowRule(r))
-                .filter(xc -> xc != null)
+                .map(this::createCrossConnectFlowRule)
+                .filter(Objects::nonNull)
                 .collect(Collectors.toList());
         restCiena.removeCrossConnectCache(removed);
         return removed;
@@ -88,7 +89,7 @@
 
     private CrossConnectFlowRule createCrossConnectFlowRule(FlowRule r) {
         List<PortNumber> linePorts = CienaRestDevice.getLinesidePortId().stream()
-                .map(p -> PortNumber.portNumber(p))
+                .map(PortNumber::portNumber)
                 .collect(Collectors.toList());
         try {
             return new CrossConnectFlowRule(r, linePorts);
@@ -129,7 +130,7 @@
         /*
          * rule is installed in three steps
          * 1- disable port
-         * 2- change channel
+         * 2- change frequency
          * 3- enable port
          */
         try {
@@ -143,8 +144,8 @@
         if (!restCiena.disablePort(outPort)) {
             return false;
         }
-        //2- change channel
-        if (!restCiena.changeChannel(signal, outPort)) {
+        //2- change frequency
+        if (!restCiena.changeFrequency(signal, outPort)) {
             return false;
         }
         //3- enable port
diff --git a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaRestDevice.java b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaRestDevice.java
index 0fce654..361d538 100644
--- a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaRestDevice.java
+++ b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaRestDevice.java
@@ -67,7 +67,7 @@
 import static org.slf4j.LoggerFactory.getLogger;
 
 public class CienaRestDevice {
-    private static final Frequency BASE_FREQUENCY = Frequency.ofGHz(193_950);
+    private static final Frequency CENTER_FREQUENCY = Frequency.ofGHz(195_950);
     private static final String ENABLED = "enabled";
     private static final String DISABLED = "disabled";
     private static final String VALUE = "value";
@@ -101,6 +101,7 @@
     private static final String CHANNEL_URI = TRANSMITTER_URI + "/" + LINE_SYSTEM_CHANNEL_NUMBER;
     private static final String ACTIVE_ALARMS_URL = ALARM_KEY + "/" + ACTIVE;
     private static final List<String> LINESIDE_PORT_ID = ImmutableList.of("4", "48");
+    private static final ChannelSpacing CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ;
 
     private final Logger log = getLogger(getClass());
 
@@ -166,10 +167,10 @@
 
     }
 
-    private String genFrequencyChangeRequest(long frequency) {
+    private String genFrequencyChangeRequest(double frequency) {
         String request = "{\n" +
                 "\"" + FREQUENCY_KEY + "\": {\n" +
-                "\"" + VALUE + "\": " + Long.toString(frequency) + "\n" +
+                "\"" + VALUE + "\": " + Double.toString(frequency) + "\n" +
                 "}\n" +
                 "}";
         log.debug("request:\n{}", request);
@@ -249,7 +250,7 @@
 
     public final boolean changeFrequency(OchSignal signal, PortNumber outPort) {
         String uri = genUri(FREQUENCY_URI, outPort);
-        long frequency = toFrequency(signal);
+        double frequency = signal.centralFrequency().asGHz();
         String request = genFrequencyChangeRequest(frequency);
         boolean response = putNoReply(uri, request);
         if (!response) {
@@ -271,13 +272,7 @@
         return response;
     }
 
-    private final long toFrequency(OchSignal signal) {
-        double frequency = BASE_FREQUENCY.asGHz() +
-                (signal.channelSpacing().frequency().asGHz() * (double) signal.slotGranularity());
-        return Double.valueOf(frequency).longValue();
-    }
-
-    private final int getChannel(PortNumber port) {
+    private int getChannel(PortNumber port) {
         try {
             String uri = genUri(CHANNEL_URI, port);
             JsonNode response = get(uri);
@@ -290,6 +285,25 @@
 
     }
 
+    private int getChannelFromFrequency(Frequency frequency) {
+        return (int) CENTER_FREQUENCY.subtract(frequency)
+                .floorDivision(CHANNEL_SPACING.frequency().asHz()).asHz();
+
+    }
+
+    private Frequency getFrequency(PortNumber port) {
+        try {
+            String uri = genUri(FREQUENCY_URI, port);
+            JsonNode response = get(uri);
+            return Frequency.ofGHz(response.get(FREQUENCY_KEY).get(VALUE).asDouble());
+        } catch (IOException e) {
+            // this is expected for client side ports as they don't contain channel data
+            log.error("unable to get frequency for port {} on device {}:\n{}", port, deviceId, e);
+            return null;
+        }
+
+    }
+
     private AlarmEntityId getAlarmSource(String instance) {
         AlarmEntityId source;
         if (instance.contains(PORT)) {
@@ -346,8 +360,8 @@
         try {
             List<JsonNode> alarms = Lists.newArrayList(get(ACTIVE_ALARMS_URL).get(ACTIVE).elements());
             return alarms.stream()
-                    .map(a -> newAlarmFromJsonNode(a))
-                    .filter(a -> a != null)
+                    .map(this::newAlarmFromJsonNode)
+                    .filter(Objects::nonNull)
                     .collect(Collectors.toList());
         } catch (IOException e) {
             log.error("unable to get active alarms for device {}:\n", deviceId, e);
@@ -362,17 +376,17 @@
         return ports.stream()
                 .filter(p -> LINESIDE_PORT_ID.contains(p.number().name()))
                 .map(p -> fetchRule(p.number()))
-                .filter(p -> p != null)
+                .filter(Objects::nonNull)
                 .map(fr -> new DefaultFlowEntry(fr, FlowEntry.FlowEntryState.ADDED, 0, 0, 0))
                 .collect(Collectors.toList());
     }
 
     private FlowRule fetchRule(PortNumber port) {
-        int channel = getChannel(port);
-        if (channel == -1) {
+        Frequency frequency = getFrequency(port);
+        if (frequency == null) {
             return null;
         }
-
+        int channel = getChannelFromFrequency(frequency);
         /*
          * both inPort and outPort will be same as WaveServer only deal with same port ptp-indexes
          * channel and spaceMultiplier are same.
@@ -382,7 +396,7 @@
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchInPort(port)
                 .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
-                .add(Criteria.matchLambda(OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, channel)))
+                .add(Criteria.matchLambda(OchSignal.newDwdmSlot(CHANNEL_SPACING, channel)))
                 .build();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .setOutput(port)
@@ -394,7 +408,7 @@
             return null;
         }
 
-        FlowRule fr = DefaultFlowRule.builder()
+        return DefaultFlowRule.builder()
                 .forDevice(deviceId)
                 .makePermanent()
                 .withSelector(selector)
@@ -402,8 +416,6 @@
                 .withPriority(lookup.getRight())
                 .withCookie(lookup.getLeft().value())
                 .build();
-
-        return fr;
     }
 
     public List<Alarm> getAlarms() {
diff --git a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaWaveserverDeviceDescription.java b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaWaveserverDeviceDescription.java
index 8a6113b..bd411c1 100644
--- a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaWaveserverDeviceDescription.java
+++ b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaWaveserverDeviceDescription.java
@@ -40,6 +40,7 @@
 import org.onosproject.protocol.rest.RestSBController;
 import org.slf4j.Logger;
 
+import javax.ws.rs.core.MediaType;
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -119,7 +120,7 @@
         DeviceId deviceId = handler().data().deviceId();
 
         HierarchicalConfiguration config = XmlConfigParser.
-                loadXml(controller.get(deviceId, PORT_REQUEST, XML));
+                loadXml(controller.get(deviceId, PORT_REQUEST, MediaType.APPLICATION_XML_TYPE));
         List<HierarchicalConfiguration> portsConfig =
                 parseWaveServerCienaPorts(config);
         portsConfig.forEach(sub -> {
diff --git a/drivers/cisco/netconf/src/main/java/org/onosproject/drivers/cisco/TextBlockParserCisco.java b/drivers/cisco/netconf/src/main/java/org/onosproject/drivers/cisco/TextBlockParserCisco.java
index 6e0be07..a4a68ec 100644
--- a/drivers/cisco/netconf/src/main/java/org/onosproject/drivers/cisco/TextBlockParserCisco.java
+++ b/drivers/cisco/netconf/src/main/java/org/onosproject/drivers/cisco/TextBlockParserCisco.java
@@ -94,7 +94,7 @@
         String processor = SPACE;
         int i;
         for (i = 0; i < textStr.length; i++) {
-            if (textStr[i].indexOf(PHRASE) > 0) {
+            if (textStr[i].contains(PHRASE)) {
                 String[] lineStr = textStr[i].trim().split(SPACE);
                 processor = lineStr[1];
                 break;
@@ -114,7 +114,7 @@
         String[] textStr = version.split(NEWLINE_SPLITTER);
         int i;
         for (i = 0; i < textStr.length; i++) {
-            if (textStr[i].indexOf(VERSION) > 0) {
+            if (textStr[i].contains(VERSION)) {
                 break;
             }
         }
@@ -141,7 +141,7 @@
         String[] textStr = version.split(NEWLINE_SPLITTER);
         int i;
         for (i = 0; i < textStr.length; i++) {
-            if (textStr[i].indexOf(PROCESSOR_BOARD) > 0) {
+            if (textStr[i].contains(PROCESSOR_BOARD)) {
                 break;
             }
         }
@@ -264,7 +264,7 @@
     private static String getPort(String[] textStr) {
         String port;
         try {
-            if (textStr[0].indexOf(PORT_DELIMITER) > 0) {
+            if (textStr[0].contains(PORT_DELIMITER)) {
                 port = textStr[0].substring(textStr[0].lastIndexOf(PORT_DELIMITER) + 1,
                                             textStr[0].indexOf(SPACE));
             } else {
@@ -286,7 +286,7 @@
         String result;
         int lastLine = textStr.length - 1;
         for (int i = 0; i < lastLine; i++) {
-            if ((textStr[i].indexOf(BANDWIDTH) > 0) && (textStr[i].indexOf(SPEED) > 0)) {
+            if (textStr[i].contains(BANDWIDTH) && textStr[i].contains(SPEED)) {
                 result = textStr[i].substring(textStr[i].indexOf(BANDWIDTH) + 3, textStr[i].indexOf(SPEED));
                 portSpeed = Long.valueOf(result);
                 break;
diff --git a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV3.java b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV3.java
index 3eb6261..347bb44 100644
--- a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV3.java
+++ b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV3.java
@@ -118,6 +118,7 @@
                     break;
                 case OUTPUT:
                     isPresentOutpuPort = true;
+                    break;
                 default:
             }
         }
diff --git a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java
index 9a684f5..8c9e5e9 100644
--- a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java
+++ b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java
@@ -271,6 +271,7 @@
                     break;
                 case OUTPUT:
                     isPresentOutpuPort = true;
+                    break;
                 default:
             }
         }
diff --git a/drivers/default/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java b/drivers/default/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java
index 1b9bad8..edc8a1e 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java
@@ -472,25 +472,25 @@
                             case SRC_ARP_SPA:
                                 return NiciraMoveTreatmentFactory
                                         .createNiciraMovArpSpaToTpa();
-                    case NSH_C1:
-                        return NiciraMoveTreatmentFactory.createNiciraMovNshC1ToC1();
-                    case NSH_C2:
-                        if (Long.valueOf(moveAction.getDst()).intValue() == TUN_ID) {
-                            return NiciraMoveTreatmentFactory.createNiciraMovNshC2ToTunId();
-                        }
-                        return NiciraMoveTreatmentFactory.createNiciraMovNshC2ToC2();
-                    case NSH_C3:
-                        return NiciraMoveTreatmentFactory.createNiciraMovNshC3ToC3();
-                    case NSH_C4:
-                        return NiciraMoveTreatmentFactory.createNiciraMovNshC4ToC4();
-                    case TUN_IPV4_DST:
-                        return NiciraMoveTreatmentFactory.createNiciraMovTunDstToTunDst();
-                    case TUN_ID:
-                        return NiciraMoveTreatmentFactory.createNiciraMovTunIdToTunId();
+                            case NSH_C1:
+                                return NiciraMoveTreatmentFactory.createNiciraMovNshC1ToC1();
+                            case NSH_C2:
+                                if (Long.valueOf(moveAction.getDst()).intValue() == TUN_ID) {
+                                    return NiciraMoveTreatmentFactory.createNiciraMovNshC2ToTunId();
+                                }
+                                return NiciraMoveTreatmentFactory.createNiciraMovNshC2ToC2();
+                            case NSH_C3:
+                                return NiciraMoveTreatmentFactory.createNiciraMovNshC3ToC3();
+                            case NSH_C4:
+                                return NiciraMoveTreatmentFactory.createNiciraMovNshC4ToC4();
+                            case TUN_IPV4_DST:
+                                return NiciraMoveTreatmentFactory.createNiciraMovTunDstToTunDst();
+                            case TUN_ID:
+                                return NiciraMoveTreatmentFactory.createNiciraMovTunIdToTunId();
                             default:
                                 throw new UnsupportedOperationException("Driver does not support move from "
-                                + moveAction.getSrc() + " to " + moveAction.getDst() + "of length "
-                                + moveAction.getNBits());
+                                        + moveAction.getSrc() + " to " + moveAction.getDst() + "of length "
+                                        + moveAction.getNBits());
                         }
                     case SUB_TYPE_RESUBMIT:
                         OFActionNiciraResubmit resubmitAction = (OFActionNiciraResubmit) nicira;
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java
index f9c9f22..e41ca4c 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java
@@ -300,7 +300,7 @@
 
         }
 
-        if (mplsSwap) {
+        if (mplsSwap && !isPw) {
             log.debug("Creating a MPLS Swap - MPLS Interface - L2 Interface group chain.");
 
             // break up simple next objective to GroupChain objects
@@ -804,9 +804,9 @@
         });
     }
 
-    private void createL3MulticastGroup(NextObjective nextObj, VlanId vlanId,
-                                        List<GroupInfo> groupInfos) {
+    private List<GroupBucket> createL3MulticastBucket(List<GroupInfo> groupInfos) {
         List<GroupBucket> l3McastBuckets = new ArrayList<>();
+        // For each inner group
         groupInfos.forEach(groupInfo -> {
             // Points to L3 interface group if there is one.
             // Otherwise points to L2 interface group directly.
@@ -817,6 +817,15 @@
             GroupBucket abucket = DefaultGroupBucket.createAllGroupBucket(ttb.build());
             l3McastBuckets.add(abucket);
         });
+        // Done return the new list of buckets
+        return l3McastBuckets;
+    }
+
+
+    private void createL3MulticastGroup(NextObjective nextObj, VlanId vlanId,
+                                        List<GroupInfo> groupInfos) {
+        // Let's create a new list mcast buckets
+        List<GroupBucket> l3McastBuckets = createL3MulticastBucket(groupInfos);
 
         int l3MulticastIndex = getNextAvailableIndex();
         int l3MulticastGroupId = L3_MULTICAST_TYPE |
@@ -1337,18 +1346,8 @@
                                              List<Deque<GroupKey>> allActiveKeys,
                                              List<GroupInfo> groupInfos,
                                              VlanId assignedVlan) {
-        // create the buckets to add to the outermost L3 Multicast group
-        List<GroupBucket> newBuckets = Lists.newArrayList();
-        groupInfos.forEach(groupInfo -> {
-            // Points to L3 interface group if there is one.
-            // Otherwise points to L2 interface group directly.
-            GroupDescription nextGroupDesc = (groupInfo.nextGroupDesc() != null) ?
-                    groupInfo.nextGroupDesc() : groupInfo.innerMostGroupDesc();
-            TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
-            treatmentBuilder.group(new GroupId(nextGroupDesc.givenGroupId()));
-            GroupBucket newBucket = DefaultGroupBucket.createAllGroupBucket(treatmentBuilder.build());
-            newBuckets.add(newBucket);
-        });
+        // Create the buckets to add to the outermost L3 Multicast group
+        List<GroupBucket> newBuckets = createL3MulticastBucket(groupInfos);
 
         // get the group being edited
         Group l3mcastGroup = retrieveTopLevelGroup(allActiveKeys, nextObj.id());
@@ -1589,8 +1588,8 @@
      *             modified to match the given next objective
      */
     protected void verifyGroup(NextObjective nextObjective, NextGroup next) {
-        if (nextObjective.type() != NextObjective.Type.HASHED) {
-            log.warn("verification not supported for {} group", nextObjective.type());
+        if (nextObjective.type() == NextObjective.Type.SIMPLE) {
+            log.warn("verification not supported for indirect group");
             fail(nextObjective, ObjectiveError.UNSUPPORTED);
             return;
         }
@@ -1598,6 +1597,9 @@
         List<Deque<GroupKey>> allActiveKeys = appKryo.deserialize(next.data());
         List<TrafficTreatment> bucketsToCreate = Lists.newArrayList();
         List<Integer> indicesToRemove = Lists.newArrayList();
+
+        // Iterating over the treatments of the next objective allows
+        // to detect missing buckets and/or duplicate buckets (to be removed)
         for (TrafficTreatment bkt : nextObjective.next()) {
             PortNumber portNumber = readOutPortFromTreatment(bkt);
             int label = readLabelFromTreatment(bkt);
@@ -1622,17 +1624,41 @@
             }
         }
 
+        // Detect situation where the next data has more buckets
+        // (not duplicates) respect to the next objective
+        if (allActiveKeys.size() > nextObjective.next().size()) {
+            log.warn("Mismatch detected between next and flowobjstore for device {}: " +
+                             "nextId:{}, nextObjective-size:{} next-size:{} .. correcting",
+                     deviceId, nextObjective.id(), nextObjective.next().size(), allActiveKeys.size());
+            List<Integer> otherIndices = indicesToRemoveFromNextGroup(allActiveKeys, nextObjective,
+                                                                      groupService, deviceId);
+            // Filter out the indices not present
+            otherIndices = otherIndices.stream()
+                    .filter(index -> !indicesToRemove.contains(index))
+                    .collect(Collectors.toList());
+            // Add all to the final list
+            indicesToRemove.addAll(otherIndices);
+        }
+
+        log.debug("Buckets to create {}", bucketsToCreate);
+        log.debug("Indices to remove {}", indicesToRemove);
+
         if (!bucketsToCreate.isEmpty()) {
             log.info("creating {} buckets as part of nextId: {} verification",
                      bucketsToCreate.size(), nextObjective.id());
             //create a nextObjective only with these buckets
             NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
                     .withId(nextObjective.id())
-                    .withType(NextObjective.Type.HASHED)
+                    .withType(nextObjective.type())
                     .withMeta(nextObjective.meta())
                     .fromApp(nextObjective.appId());
-            bucketsToCreate.forEach(bucket -> nextObjBuilder.addTreatment(bucket));
-            addBucketToHashGroup(nextObjBuilder.addToExisting(), allActiveKeys);
+            bucketsToCreate.forEach(nextObjBuilder::addTreatment);
+            // According to the next type we call the proper add function
+            if (nextObjective.type() == NextObjective.Type.HASHED) {
+                addBucketToHashGroup(nextObjBuilder.addToExisting(), allActiveKeys);
+            } else {
+                addBucketToBroadcastGroup(nextObjBuilder.addToExisting(), allActiveKeys);
+            }
         }
 
         if (!indicesToRemove.isEmpty()) {
@@ -1649,9 +1675,9 @@
             // Nevertheless groupStore may not be in sync due to bug in the store
             // - see CORD-1844. XXX When this bug is fixed, the rest of this verify
             // method will not be required.
-            GroupKey hashGroupKey = allActiveKeys.get(0).peekFirst();
-            Group hashGroup = groupService.getGroup(deviceId, hashGroupKey);
-            int actualGroupSize = hashGroup.buckets().buckets().size();
+            GroupKey topGroupKey = allActiveKeys.get(0).peekFirst();
+            Group topGroup = groupService.getGroup(deviceId, topGroupKey);
+            int actualGroupSize = topGroup.buckets().buckets().size();
             int objGroupSize = nextObjective.next().size();
             if (actualGroupSize != objGroupSize) {
                 log.warn("Mismatch detected in device:{}, nextId:{}, nextObjective-size"
@@ -1659,9 +1685,10 @@
                         objGroupSize, actualGroupSize);
             }
             if (actualGroupSize > objGroupSize) {
+                // Group in the device has more chains
                 List<GroupBucket> bucketsToRemove = Lists.newArrayList();
                 //check every bucket in the actual group
-                for (GroupBucket bucket : hashGroup.buckets().buckets()) {
+                for (GroupBucket bucket : topGroup.buckets().buckets()) {
                     GroupInstruction g = (GroupInstruction) bucket.treatment()
                                             .allInstructions().iterator().next();
                     GroupId gidToCheck = g.groupId(); // the group pointed to
@@ -1689,11 +1716,12 @@
                             + "buckets to remove");
                 } else {
                     GroupBuckets removeBuckets = new GroupBuckets(bucketsToRemove);
-                    groupService.removeBucketsFromGroup(deviceId, hashGroupKey,
-                                                        removeBuckets, hashGroupKey,
+                    groupService.removeBucketsFromGroup(deviceId, topGroupKey,
+                                                        removeBuckets, topGroupKey,
                                                         nextObjective.appId());
                 }
             } else if (actualGroupSize < objGroupSize) {
+                // Group in the device has less chains
                 // should also add buckets not in group-store but in obj-store
                 List<GroupBucket> bucketsToAdd = Lists.newArrayList();
                 //check every bucket in the obj
@@ -1709,7 +1737,7 @@
                         continue;
                     }
                     boolean matches = false;
-                    for (GroupBucket bucket : hashGroup.buckets().buckets()) {
+                    for (GroupBucket bucket : topGroup.buckets().buckets()) {
                         GroupInstruction g = (GroupInstruction) bucket.treatment()
                                                 .allInstructions().iterator().next();
                         GroupId gidToCheck = g.groupId(); // the group pointed to
@@ -1723,7 +1751,12 @@
                         TrafficTreatment t = DefaultTrafficTreatment.builder()
                                                 .group(pointedGroup.id())
                                                 .build();
-                        bucketsToAdd.add(DefaultGroupBucket.createSelectGroupBucket(t));
+                        // Create the proper bucket according to the next type
+                        if (nextObjective.type() == NextObjective.Type.HASHED) {
+                            bucketsToAdd.add(DefaultGroupBucket.createSelectGroupBucket(t));
+                        } else {
+                            bucketsToAdd.add(DefaultGroupBucket.createAllGroupBucket(t));
+                        }
                     }
                 }
                 if (bucketsToAdd.isEmpty()) {
@@ -1731,8 +1764,8 @@
                             + "buckets to add");
                 } else {
                     GroupBuckets addBuckets = new GroupBuckets(bucketsToAdd);
-                    groupService.addBucketsToGroup(deviceId, hashGroupKey,
-                                                   addBuckets, hashGroupKey,
+                    groupService.addBucketsToGroup(deviceId, topGroupKey,
+                                                   addBuckets, topGroupKey,
                                                    nextObjective.appId());
                 }
             }
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 ff9f2c0..661d3e9 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
@@ -252,6 +252,16 @@
         return true;
     }
 
+    /**
+     * Determines whether this driver should continue to retry flows that point
+     * to empty groups. See CORD-554.
+     *
+     * @return true if the driver should retry flows
+     */
+    protected boolean shouldRetry() {
+        return true;
+    }
+
     //////////////////////////////////////
     //  Flow Objectives
     //////////////////////////////////////
@@ -1276,11 +1286,14 @@
                     return Collections.emptySet();
                 }
                 tb.deferred().group(group.id());
-                // check if group is empty
+                // retrying flows may be necessary due to bug CORD-554
                 if (gkeys.size() == 1 && gkeys.get(0).size() == 1) {
-                    log.warn("Found empty group 0x{} in dev:{} .. will retry fwd:{}",
-                             Integer.toHexString(group.id().id()), deviceId, fwd.id());
-                    emptyGroup = true;
+                    if (shouldRetry()) {
+                        log.warn("Found empty group 0x{} in dev:{} .. will retry fwd:{}",
+                                 Integer.toHexString(group.id().id()), deviceId,
+                                 fwd.id());
+                        emptyGroup = true;
+                    }
                 }
             } else {
                 log.warn("Cannot find group for nextId:{} in dev:{}. Aborting fwd:{}",
@@ -1322,7 +1335,7 @@
             );
             log.debug("Default rule 0.0.0.0/0 is being installed two rules");
         }
-        // XXX retrying flows may be necessary due to bug CORD-554
+
         if (emptyGroup) {
             executorService.schedule(new RetryFlows(fwd, flowRuleCollection),
                                      RETRY_MS, TimeUnit.MILLISECONDS);
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
index cbd6fb7..0059b64 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
@@ -89,6 +89,11 @@
     }
 
     @Override
+    protected boolean shouldRetry() {
+        return false;
+    }
+
+    @Override
     protected void processFilter(FilteringObjective filteringObjective,
                                  boolean install,
                                  ApplicationId applicationId) {
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OfdpaGroupHandlerUtility.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OfdpaGroupHandlerUtility.java
index df03656..e9c97bc 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OfdpaGroupHandlerUtility.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OfdpaGroupHandlerUtility.java
@@ -263,6 +263,67 @@
         return indices;
     }
 
+
+    /**
+     * Get indices to remove comparing next group with next objective.
+     *
+     * @param allActiveKeys the representation of the group
+     * @param nextObjective the next objective to verify
+     * @param groupService groups service for querying group information
+     * @param deviceId the device id for the device that contains the group
+     * @return a list of indexes in the allActiveKeys to remove.
+     */
+    public static List<Integer> indicesToRemoveFromNextGroup(List<Deque<GroupKey>> allActiveKeys,
+                                                       NextObjective nextObjective,
+                                                       GroupService groupService,
+                                                       DeviceId deviceId) {
+        List<Integer> indicesToRemove = Lists.newArrayList();
+        int index = 0;
+        // Iterate over the chain in the next data
+        for (Deque<GroupKey> keyChain : allActiveKeys) {
+            // Valid chain should have at least two elements
+            if (keyChain.size() >= 2) {
+                // Get last group (l2if) and retrieve port number
+                GroupKey ifaceGroupKey = keyChain.peekLast();
+                Group ifaceGroup = groupService.getGroup(deviceId, ifaceGroupKey);
+                if (ifaceGroup != null && !ifaceGroup.buckets().buckets().isEmpty()) {
+                    PortNumber portNumber = readOutPortFromTreatment(
+                            ifaceGroup.buckets().buckets().iterator().next().treatment());
+                    // If there is not a port number continue
+                    if (portNumber != null) {
+                        // check for label in the 2nd group of this chain
+                        GroupKey secondKey = (GroupKey) keyChain.toArray()[1];
+                        Group secondGroup = groupService.getGroup(deviceId, secondKey);
+                        // If there is not a second group or there are no buckets continue
+                        if (secondGroup != null && !secondGroup.buckets().buckets().isEmpty()) {
+                            // Get label or -1
+                            int label = readLabelFromTreatment(
+                                    secondGroup.buckets().buckets()
+                                            .iterator().next().treatment());
+                            // Iterate over the next treatments looking for the port and the label
+                            boolean matches = false;
+                            for (TrafficTreatment t : nextObjective.next()) {
+                                PortNumber tPort = readOutPortFromTreatment(t);
+                                int tLabel = readLabelFromTreatment(t);
+                                if (tPort != null && tPort.equals(portNumber) && tLabel == label) {
+                                    // We found it, exit
+                                    matches = true;
+                                    break;
+                                }
+                            }
+                            // Not found, we have to remove it
+                            if (!matches) {
+                                indicesToRemove.add(index);
+                            }
+                        }
+                    }
+                }
+            }
+            index++;
+        }
+        return indicesToRemove;
+    }
+
     /**
      * The purpose of this function is to verify if the hashed next
      * objective is supported by the current pipeline.
diff --git a/drivers/default/src/main/resources/onos-drivers.xml b/drivers/default/src/main/resources/onos-drivers.xml
index 180c852..4ba788e 100644
--- a/drivers/default/src/main/resources/onos-drivers.xml
+++ b/drivers/default/src/main/resources/onos-drivers.xml
@@ -117,15 +117,15 @@
 
     <!-- Driver for OFDPA Premium version -->
     <driver name="as7712-32x-premium" extends="ofdpa3"
-            manufacturer="Broadcom Ltd\." hwVersion="as7712-32x" swVersion="OF-DPA Premium.*">
+            manufacturer="^Broadcom Ltd\.$" hwVersion=".*[Aa][Ss]7712-32[Xx].*" swVersion="^OF-DPA Premium.*">
     </driver>
 
     <driver name="as5912-54x-premium" extends="qmx-ofdpa3"
-            manufacturer="Broadcom Ltd\." hwVersion="as5912-54x" swVersion="OF-DPA Premium.*">
+            manufacturer="^Broadcom Ltd\.$" hwVersion=".*[Aa][Ss]5912-54[Xx].*" swVersion="^OF-DPA Premium.*">
     </driver>
 
     <driver name="as5916-54x-premium" extends="qmx-ofdpa3"
-            manufacturer="Broadcom Ltd\." hwVersion="as5916-54x" swVersion="OF-DPA Premium.*">
+            manufacturer="^Broadcom Ltd\.$" hwVersion=".*[Aa][Ss]5916-54[Xx].*" swVersion="^OF-DPA Premium.*">
     </driver>
 
     <!-- OFDPA drivers from vendors -->
diff --git a/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltAlarmConsumer.java b/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltAlarmConsumer.java
index 01df800..991b7f7 100644
--- a/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltAlarmConsumer.java
+++ b/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltAlarmConsumer.java
@@ -22,6 +22,7 @@
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
@@ -190,6 +191,7 @@
                         log.warn("Unknown severity: {}", severity);
                     }
                     DefaultAlarm.Builder alarmBuilder = new DefaultAlarm.Builder(
+                            AlarmId.alarmId(ncDeviceId, Long.toString(timeRaised)),
                             ncDeviceId, alertType.toUpperCase(), alarmLevel, timeRaised)
                             .forSource(AlarmEntityId.alarmEntityId(alarmSrc));
                     alarms.add(alarmBuilder.build());
diff --git a/drivers/huawei/src/main/java/org/onosproject/drivers/huawei/HuaweiXmlParser.java b/drivers/huawei/src/main/java/org/onosproject/drivers/huawei/HuaweiXmlParser.java
index 5ba8b059..111d1a9 100644
--- a/drivers/huawei/src/main/java/org/onosproject/drivers/huawei/HuaweiXmlParser.java
+++ b/drivers/huawei/src/main/java/org/onosproject/drivers/huawei/HuaweiXmlParser.java
@@ -201,7 +201,7 @@
         if (!portName.contains(DELIMITER)) {
             portInc++;
             port = String.valueOf(portInc) + portName;
-        } else if (portName.indexOf(DELIMITER) > 0) {
+        } else if (portName.contains(DELIMITER)) {
             try {
                 port = portName.substring(
                         portName.lastIndexOf(DELIMITER) + 1);
diff --git a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
index 4f23b79..d4c709e 100644
--- a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
+++ b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
@@ -348,7 +348,7 @@
         long portSpeed = toMbps(phyIntf.getString(SPEED));
 
         portDescriptions.add(new DefaultPortDescription(portNumber,
-                                                        admUp & opUp,
+                                                        admUp && opUp,
                                                         Type.COPPER,
                                                         portSpeed,
                                                         annotations.build()));
@@ -395,7 +395,7 @@
             boolean lEnabled = logIntf.getString("if-config-flags.iff-up") != null;
 
             portDescriptions.add(new DefaultPortDescription(lPortNumber,
-                                                            admUp & opUp & lEnabled,
+                                                            admUp && opUp && lEnabled,
                                                             Type.COPPER,
                                                             portSpeed,
                                                             lannotations.build()));
diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumAlarmConsumer.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumAlarmConsumer.java
index bdd0c94..91289e3 100644
--- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumAlarmConsumer.java
+++ b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumAlarmConsumer.java
@@ -68,11 +68,11 @@
         snmp.get(ALARMS_TABLE_OID)
                 .forEach(alarm -> snmp.get(ALARMS_ID_OID).forEach(alarmIdEvent -> {
                     int alarmId = getAlarmId(alarmIdEvent);
-                    alarms.add(new DefaultAlarm.Builder(deviceId, getMessage(alarmId),
+                    alarms.add(new DefaultAlarm.Builder(AlarmId.alarmId(deviceId, String.valueOf(alarmId)),
+                                                        deviceId, getMessage(alarmId),
                                                         getSeverity(alarmId),
                                                         System.currentTimeMillis())
-                                       .withId(AlarmId.alarmId(deviceId, String.valueOf(alarmId)))
-                                       .build());
+                                                    .build());
                 }));
         return ImmutableList.copyOf(alarms);
     }
diff --git a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumSnmpDevice.java b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumSnmpDevice.java
index 47b98e2..cd6ba1a 100644
--- a/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumSnmpDevice.java
+++ b/drivers/lumentum/src/main/java/org/onosproject/drivers/lumentum/LumentumSnmpDevice.java
@@ -85,7 +85,7 @@
         target.setCommunity(new OctetString("public"));
         target.setAddress(targetAddress);
         target.setRetries(3);
-        target.setTimeout(1000 * 3);
+        target.setTimeout(1000L * 3L);
         target.setVersion(SnmpConstants.version2c);
         target.setMaxSizeRequestPDU(MAX_SIZE_RESPONSE_PDU);
     }
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java
index 9b28d1d..03405d7 100644
--- a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java
@@ -214,6 +214,7 @@
                                 session, DatastoreId.RUNNING);
                         return; //If it did not throw an exception
                     } catch (InterruptedException e1) {
+                        Thread.currentThread().interrupt();
                         log.debug("Error when deleting BWP profile on EA1000" +
                                 " - trying again in 1 sec", e1);
                     } catch (NetconfException e1) {
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java
index 34274e2..faf2007 100644
--- a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java
@@ -109,9 +109,7 @@
                 latitudeStr = augmentedSystem.latitude().toPlainString();
             }
         } catch (NetconfException e) {
-            log.error("Unable to retrieve init data from device: " + handler().data().deviceId().toString()
-                    + " Error: " + e.getMessage());
-            e.printStackTrace();
+            log.error("Unable to retrieve init data from device: " + handler().data().deviceId().toString(), e);
         }
 
         DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
diff --git a/drivers/microsemi/src/test/java/org/onosproject/yang/MockYangRuntimeManager.java b/drivers/microsemi/src/test/java/org/onosproject/yang/MockYangRuntimeManager.java
index 3bebf4c..5cfa3ef 100644
--- a/drivers/microsemi/src/test/java/org/onosproject/yang/MockYangRuntimeManager.java
+++ b/drivers/microsemi/src/test/java/org/onosproject/yang/MockYangRuntimeManager.java
@@ -23,6 +23,7 @@
 import org.onosproject.drivers.netconf.MockCoreService;
 import org.onosproject.yang.model.ModelConverter;
 import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.model.ModelObjectId;
 import org.onosproject.yang.model.NodeKey;
 import org.onosproject.yang.model.ResourceData;
 import org.onosproject.yang.model.ResourceId;
@@ -109,17 +110,17 @@
             return modelRegistry.getModels();
         }
 
-    @Override
-    public YangModel getModel(String s) {
-        return modelRegistry.getModel(s);
-    }
+        @Override
+        public YangModel getModel(String s) {
+            return modelRegistry.getModel(s);
+        }
 
-    @Override
-    public YangModule getModule(YangModuleId yangModuleId) {
-        return modelRegistry.getModule(yangModuleId);
-    }
+        @Override
+        public YangModule getModule(YangModuleId yangModuleId) {
+            return modelRegistry.getModule(yangModuleId);
+        }
 
-    @Override
+        @Override
         public void registerSerializer(YangSerializer ys) {
             serializerRegistry.registerSerializer(ys);
         }
@@ -130,7 +131,7 @@
         }
 
         @Override
-        public void registerAnydataSchema(Class id, Class id1) {
+        public void registerAnydataSchema(ModelObjectId arg0, ModelObjectId arg1) {
             throw new UnsupportedOperationException("registerAnydataSchema() needs to be implemented");
         }
 
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/query/CalientLambdaQuery.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/query/CalientLambdaQuery.java
index bcc5982..c715c98 100644
--- a/drivers/optical/src/main/java/org/onosproject/driver/optical/query/CalientLambdaQuery.java
+++ b/drivers/optical/src/main/java/org/onosproject/driver/optical/query/CalientLambdaQuery.java
@@ -41,7 +41,7 @@
         // Wavelength range: 1260 - 1630 nm
         long startSpacingMultiplier = Spectrum.U_BAND_MIN.subtract(Spectrum.CENTER_FREQUENCY).asHz() /
                 ChannelSpacing.CHL_12P5GHZ.frequency().asHz();
-        long stopSpacingMultiplier = Spectrum.O_BAND_MAX.subtract(Spectrum.CENTER_FREQUENCY).asHz() /
+        long stopSpacingMultiplier = Spectrum.O_BAND_MIN.subtract(Spectrum.CENTER_FREQUENCY).asHz() /
                 ChannelSpacing.CHL_12P5GHZ.frequency().asHz();
 
         // Only consider odd values for the multiplier (for easy mapping to fixed grid)
diff --git a/drivers/optical/src/main/java/org/onosproject/driver/optical/query/OpenFlowLambdaQuery.java b/drivers/optical/src/main/java/org/onosproject/driver/optical/query/OpenFlowLambdaQuery.java
new file mode 100644
index 0000000..f901c0d
--- /dev/null
+++ b/drivers/optical/src/main/java/org/onosproject/driver/optical/query/OpenFlowLambdaQuery.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018 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.driver.optical.query;
+
+import org.onlab.util.GuavaCollectors;
+import org.onlab.util.Spectrum;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.LambdaQuery;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+
+import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.OpenFlowController;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortDescProp;
+import org.projectfloodlight.openflow.protocol.OFPortDescPropOptical;
+
+import org.slf4j.Logger;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+import static org.onosproject.openflow.controller.Dpid.dpid;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Lambda query implementation for OpenFlow Optical Circuit Switch.
+ */
+public class OpenFlowLambdaQuery extends AbstractHandlerBehaviour implements LambdaQuery {
+
+    private static final Logger log = getLogger(OpenFlowLambdaQuery.class);
+
+    @Override
+    public Set<OchSignal> queryLambdas(PortNumber port) {
+        Set<OchSignal> signals = new LinkedHashSet<>();
+        for (OFPortDesc pd : getPortDescs()) {
+            if (pd.getPortNo().getPortNumber() == port.toLong()) {
+                for (OFPortDescProp prop : pd.getProperties()) {
+                    if (prop instanceof OFPortDescPropOptical) {
+                        OFPortDescPropOptical oprop = (OFPortDescPropOptical) prop;
+                        long txMin = oprop.getTxMinFreqLmda();
+                        long txMax = oprop.getTxMaxFreqLmda();
+                        long txGrid = oprop.getTxGridFreqLmda();
+                        signals.addAll(signals(txMin, txMax, txGrid));
+                        long rxMin = oprop.getRxMinFreqLmda();
+                        long rxMax = oprop.getRxMaxFreqLmda();
+                        long rxGrid = oprop.getRxGridFreqLmda();
+                        signals.addAll(signals(rxMin, rxMax, rxGrid));
+                    }
+                }
+            }
+        }
+        return signals;
+
+    }
+
+    private Set<OchSignal> signals(long min, long max, long grid) {
+        if (Spectrum.O_BAND_MIN.asMHz() > min) {
+            log.warn("Out of range frequency (below the O-band minimum)");
+        }
+        if (Spectrum.U_BAND_MAX.asMHz() < max) {
+            log.warn("Out of range frequency (above the U-band maximum)");
+        }
+
+        double centerFrequencyMHz = Spectrum.CENTER_FREQUENCY.asMHz();
+        long startSpacingMultiplier = (long) (min - centerFrequencyMHz) / grid;
+        long stopSpacingMultiplier = (long) (max - centerFrequencyMHz) / grid;
+
+        Set<OchSignal> signals = new LinkedHashSet<>();
+
+        if (grid == ChannelSpacing.CHL_100GHZ.frequency().asMHz()) {
+            signals = IntStream.rangeClosed((int) startSpacingMultiplier,
+                        (int) stopSpacingMultiplier)
+                    .mapToObj(i -> new OchSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, i, 8))
+                    .collect(GuavaCollectors.toImmutableSet());
+        } else if (grid == ChannelSpacing.CHL_50GHZ.frequency().asMHz()) {
+            signals = IntStream.rangeClosed((int) startSpacingMultiplier,
+                        (int) stopSpacingMultiplier)
+                    .mapToObj(i -> new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, i, 4))
+                    .collect(GuavaCollectors.toImmutableSet());
+        } else if (grid == ChannelSpacing.CHL_25GHZ.frequency().asMHz()) {
+            signals = IntStream.rangeClosed((int) startSpacingMultiplier,
+                        (int) stopSpacingMultiplier)
+                    .mapToObj(i -> new OchSignal(GridType.DWDM, ChannelSpacing.CHL_25GHZ, i, 2))
+                    .collect(GuavaCollectors.toImmutableSet());
+        } else if (grid == ChannelSpacing.CHL_12P5GHZ.frequency().asMHz()) {
+            signals = IntStream.rangeClosed((int) startSpacingMultiplier,
+                        (int) stopSpacingMultiplier)
+                    .mapToObj(i -> new OchSignal(GridType.DWDM, ChannelSpacing.CHL_6P25GHZ, i, 1))
+                    .collect(GuavaCollectors.toImmutableSet());
+        } else if (grid == ChannelSpacing.CHL_6P25GHZ.frequency().asMHz()) {
+            // Only consider odd values for the multiplier (for easy mapping to fixed grid)
+            signals = IntStream.rangeClosed((int) startSpacingMultiplier,
+                        (int) stopSpacingMultiplier)
+                    .filter(i -> i % 2 == 1)
+                    .mapToObj(i -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_6P25GHZ, i, 1))
+                    .collect(GuavaCollectors.toImmutableSet());
+        } else {
+            log.warn("Unsupported channel spacing");
+        }
+
+        return signals;
+    }
+
+   private List<OFPortDesc> getPortDescs() {
+        final Dpid dpid = dpid(handler().data().deviceId().uri());
+        OpenFlowSwitch sw = handler().get(OpenFlowController.class).getSwitch(dpid);
+        return sw.getPorts();
+    }
+}
diff --git a/drivers/optical/src/main/resources/optical-drivers.xml b/drivers/optical/src/main/resources/optical-drivers.xml
index b1b98a2..1c2c418 100644
--- a/drivers/optical/src/main/resources/optical-drivers.xml
+++ b/drivers/optical/src/main/resources/optical-drivers.xml
@@ -101,9 +101,8 @@
                    impl="org.onosproject.driver.optical.handshaker.PolatisHandshaker"/>
         <behaviour api="org.onosproject.net.behaviour.PowerConfig"
                    impl="org.onosproject.driver.optical.power.OpenFlowPowerConfig"/>
-        <!-- TODO use OF1.4 reported information when ready -->
         <behaviour api="org.onosproject.net.behaviour.LambdaQuery"
-                   impl="org.onosproject.driver.optical.query.ConfigLambdaQuery"/>
+                   impl="org.onosproject.driver.optical.query.OpenFlowLambdaQuery"/>
         <property name="meterCapable">false</property>
     </driver>
 
diff --git a/drivers/polatis/netconf/src/main/java/org/onosproject/drivers/polatis/netconf/PolatisFlowRuleProgrammable.java b/drivers/polatis/netconf/src/main/java/org/onosproject/drivers/polatis/netconf/PolatisFlowRuleProgrammable.java
index 46b6a87..d5a025c 100644
--- a/drivers/polatis/netconf/src/main/java/org/onosproject/drivers/polatis/netconf/PolatisFlowRuleProgrammable.java
+++ b/drivers/polatis/netconf/src/main/java/org/onosproject/drivers/polatis/netconf/PolatisFlowRuleProgrammable.java
@@ -143,7 +143,7 @@
     private String parseKeyPairCompat() {
         String rev = opticalRevision(handler());
         if (rev == null) {
-            throw new RuntimeException(new NetconfException("Failed to obtain the revision."));
+            throw new IllegalStateException(new NetconfException("Failed to obtain the revision."));
         }
         String keyPairCompat;
         try {
@@ -156,7 +156,7 @@
                 keyPairCompat = KEY_PAIR;
             }
         } catch (ParseException e) {
-            throw new RuntimeException(new NetconfException(String.format("Incorrect date format: %s", rev)));
+            throw new IllegalArgumentException(new NetconfException(String.format("Incorrect date format: %s", rev)));
         }
         return keyPairCompat;
     }
diff --git a/features/features.xml b/features/features.xml
index 567eda2..e538d9f 100644
--- a/features/features.xml
+++ b/features/features.xml
@@ -59,7 +59,7 @@
         <bundle>mvn:com.typesafe/config/1.2.1</bundle>
         <bundle>mvn:com.googlecode.concurrent-trees/concurrent-trees/2.6.0</bundle>
         <bundle>mvn:commons-io/commons-io/2.4</bundle>
-        <bundle>mvn:io.atomix/atomix/2.0.14</bundle>
+        <bundle>mvn:io.atomix/atomix/2.0.18</bundle>
 
         <bundle>mvn:org.glassfish.jersey.core/jersey-client/2.25.1</bundle>
 
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java
index 0c8c255..8dd76f6 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java
@@ -33,18 +33,6 @@
      * Update book-keeping (ie administrative) fields for the alarm matching the specified identifier.
      *
      * @param id             alarm identifier
-     * @param isAcknowledged new acknowledged state
-     * @param assignedUser   new assigned user, null clear
-     * @return updated alarm (including any recent device-derived changes)
-     * @deprecated 1.10.0 Kingfisher
-     */
-    @Deprecated
-    Alarm updateBookkeepingFields(AlarmId id, boolean isAcknowledged, String assignedUser);
-
-    /**
-     * Update book-keeping (ie administrative) fields for the alarm matching the specified identifier.
-     *
-     * @param id             alarm identifier
      * @param clear          ture if the alarm has to be cleared
      * @param isAcknowledged new acknowledged state
      * @param assignedUser   new assigned user, null clear
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java
index fd4bad0..53784b0 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java
@@ -277,28 +277,6 @@
         /**
          * Constructs a Builder to create a Default Alarm.
          *
-         * @param deviceId    the device ID
-         * @param description the Alarm description
-         * @param severity    the severity
-         * @param timeRaised  when the alarm was raised
-         * @deprecated 1.10.0 - Kingfisher
-         */
-        @Deprecated
-        public Builder(final DeviceId deviceId,
-                       final String description, final SeverityLevel severity, final long timeRaised) {
-            super();
-            this.deviceId = deviceId;
-            this.description = description;
-            this.severity = severity;
-            this.timeRaised = timeRaised;
-            // Unless specified time-updated is same as raised.
-            this.timeUpdated = timeRaised;
-            this.id = AlarmId.alarmId(deviceId, Long.toString(timeRaised));
-        }
-
-        /**
-         * Constructs a Builder to create a Default Alarm.
-         *
          * @param id          the AlarmId
          * @param deviceId    the device ID
          * @param description the Alarm description
@@ -351,19 +329,6 @@
         }
 
         /**
-         * Sets the new alarm Id.
-         *
-         * @param id the id
-         * @return self for chaining
-         * @deprecated 1.10.0- Kingfisher
-         */
-        @Deprecated
-        public Builder withId(final AlarmId id) {
-            this.id = id;
-            return this;
-        }
-
-        /**
          * Clears the alarm that is being created.
          *
          * @return self for chaining
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManager.java
index a9ee2ab..f21493f 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManager.java
@@ -29,7 +29,6 @@
 import org.onosproject.net.topology.ClusterId;
 import org.onosproject.net.topology.DefaultGraphDescription;
 import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyCluster;
 import org.onosproject.net.topology.TopologyEvent;
@@ -44,7 +43,6 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.incubator.net.virtual.DefaultVirtualLink.PID;
-import static org.onosproject.net.topology.AdapterLinkWeigher.adapt;
 
 /**
  * Topology service implementation built on the virtual network service.
@@ -139,12 +137,6 @@
 
     @Override
     public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
-                              LinkWeight weight) {
-        return getPaths(topology, src, dst, adapt(weight));
-    }
-
-    @Override
-    public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
                               LinkWeigher weigher) {
         checkNotNull(src, DEVICE_ID_NULL);
         checkNotNull(dst, DEVICE_ID_NULL);
@@ -162,12 +154,6 @@
 
     @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
-                                              DeviceId dst, LinkWeight weight) {
-        return getDisjointPaths(topology, src, dst, adapt(weight));
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst,
                                               LinkWeigher weigher) {
         checkNotNull(src, DEVICE_ID_NULL);
@@ -187,13 +173,6 @@
 
     @Override
     public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
-                                              DeviceId dst, LinkWeight weight,
-                                              Map<Link, Object> riskProfile) {
-        return getDisjointPaths(topology, src, dst, adapt(weight), riskProfile);
-    }
-
-    @Override
-    public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
                                               DeviceId dst,
                                               LinkWeigher weigher,
                                               Map<Link, Object> riskProfile) {
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java
index a103024..77cac78 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java
@@ -25,6 +25,8 @@
 import org.onosproject.incubator.net.virtual.provider.VirtualProviderService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.provider.ProviderId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -47,6 +49,7 @@
     private final Map<ProviderId, VirtualProviderService> servicesWithProvider = new HashMap<>();
     private final Map<String, VirtualProvider> providersByScheme = new HashMap<>();
     private final Map<NetworkId, Set<VirtualProviderService>> servicesByNetwork = new HashMap<>();
+    private static Logger log = LoggerFactory.getLogger(VirtualProviderManager.class);
 
     @Override
     public synchronized void registerProvider(VirtualProvider virtualProvider) {
@@ -160,7 +163,7 @@
         try {
             return Class.forName(pramType);
         } catch (ClassNotFoundException e) {
-            e.printStackTrace();
+            log.warn("getProviderClass()", e);
         }
 
         return null;
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPathManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPathManagerTest.java
index adfca6d..cf49106 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPathManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPathManagerTest.java
@@ -37,7 +37,8 @@
 import org.onosproject.net.Path;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.TestDeviceParams;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigher;
+import org.onosproject.net.topology.LinkWeigherAdapter;
 import org.onosproject.net.topology.PathService;
 import org.onosproject.store.service.TestStorageService;
 
@@ -161,7 +162,7 @@
         Set<Path> paths = pathService.getPaths(DID1, DID3);
         validatePaths(paths, 1, 1, DID1, DID3, 1.0);
 
-        LinkWeight linkWeight = edge -> 2.0;
+        LinkWeigher linkWeight = new LinkWeigherAdapter(2.0);
         paths = pathService.getPaths(DID1, DID3, linkWeight);
         validatePaths(paths, 1, 1, DID1, DID3, 2.0);
 
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManagerTest.java
index 6218a15..ed51f94 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyManagerTest.java
@@ -42,7 +42,7 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.TestDeviceParams;
 import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.LinkWeigherAdapter;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyCluster;
 import org.onosproject.net.topology.TopologyService;
@@ -414,7 +414,7 @@
         assertEquals("The paths size did not match.", 1, paths.size());
 
         // test the getPaths() by weight method.
-        LinkWeight weight = edge -> 1.0;
+        LinkWeigher weight = new LinkWeigherAdapter(1.0);
         Set<Path> paths1 = topologyService.getPaths(topology, srcVirtualDevice.id(), dstVirtualDevice.id(), weight);
         assertNotNull("The paths should not be null.", paths1);
         assertEquals("The paths size did not match.", 1, paths1.size());
@@ -472,7 +472,7 @@
 
         // test the getDisjointPaths() method using a null weight.
         Set<DisjointPath> paths = topologyService.getDisjointPaths(topology, srcVirtualDevice.id(),
-                                                                   dstVirtualDevice.id(), (LinkWeight) null);
+                                                                   dstVirtualDevice.id(), (LinkWeigher) null);
     }
 
     /**
@@ -513,7 +513,7 @@
         assertEquals("The paths size did not match.", 1, paths.size());
 
         // test the getDisjointPaths() method using a weight.
-        LinkWeight weight = edge -> 1.0;
+        LinkWeigher weight = new LinkWeigherAdapter(1.0);
         Set<DisjointPath> paths1 = topologyService.getDisjointPaths(topology, srcVirtualDevice.id(),
                                                                     dstVirtualDevice.id(), weight);
         assertNotNull("The paths should not be null.", paths1);
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java
index 94bc091..c157a54 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java
@@ -21,6 +21,8 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.core.DefaultApplicationId;
@@ -60,7 +62,6 @@
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyServiceAdapter;
 
@@ -332,18 +333,11 @@
 
     private static class TestTopologyService extends TopologyServiceAdapter {
 
+        Weight oneHundred = ScalarWeight.toWeight(100);
         @Override
         public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst) {
             DefaultPath path = new DefaultPath(PID, ImmutableList.of(LINK1),
-                                               100, ANNOTATIONS);
-            return ImmutableSet.of(path);
-        }
-
-        @Override
-        public Set<Path> getPaths(Topology topology, DeviceId src,
-                                  DeviceId dst, LinkWeight weight) {
-            DefaultPath path = new DefaultPath(PID, ImmutableList.of(LINK1),
-                                               100, ANNOTATIONS);
+                                               oneHundred, ANNOTATIONS);
             return ImmutableSet.of(path);
         }
 
@@ -351,7 +345,7 @@
         public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
                                   LinkWeigher weigher) {
             DefaultPath path = new DefaultPath(PID, ImmutableList.of(LINK1),
-                                               100, ANNOTATIONS);
+                                               oneHundred, ANNOTATIONS);
             return ImmutableSet.of(path);
         }
 
diff --git a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/ConnectPointProtoTranslator.java b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/ConnectPointProtoTranslator.java
index 6620096..fd149b1 100644
--- a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/ConnectPointProtoTranslator.java
+++ b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/ConnectPointProtoTranslator.java
@@ -75,7 +75,7 @@
             return ConnectPointProto.newBuilder().setHostId(connectPoint.hostId().toString())
                     .setPortNumber(connectPoint.port().toString())
                     .build();
-        } else if (connectPoint.ipElementId() instanceof IpElementId) {
+        } else if (connectPoint.ipElementId() != null) {
             return ConnectPointProto.newBuilder().setIpElementId(connectPoint.ipElementId().toString())
                     .setPortNumber(connectPoint.port().toString())
                     .build();
diff --git a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/FlowEntryEnumsProtoTranslator.java b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/FlowEntryEnumsProtoTranslator.java
new file mode 100644
index 0000000..1c61a68
--- /dev/null
+++ b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/FlowEntryEnumsProtoTranslator.java
@@ -0,0 +1,140 @@
+/*
+ * 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.incubator.protobuf.models.net.flow;
+
+import org.onosproject.grpc.net.flow.models.FlowEntryEnumsProto;
+import org.onosproject.net.flow.FlowEntry.FlowEntryState;
+import org.onosproject.net.flow.FlowEntry.FlowLiveType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+
+/**
+ * gRPC FlowEntryEnumsProto message to equivalant ONOS FlowRule enums conversion related utilities.
+ */
+public final class FlowEntryEnumsProtoTranslator {
+
+    private static final Logger log = LoggerFactory.getLogger(FlowEntryEnumsProtoTranslator.class);
+
+    /**
+     * Translates {@link FlowEntryState} to gRPC FlowEntryState.
+     *
+     * @param flowEntryState {@link FlowEntryState}
+     * @return gRPC message
+     */
+    public static FlowEntryEnumsProto.FlowEntryStateProto translate(FlowEntryState flowEntryState) {
+
+        switch (flowEntryState) {
+            case PENDING_ADD:
+                return FlowEntryEnumsProto.FlowEntryStateProto.PENDING_ADD;
+            case ADDED:
+                return FlowEntryEnumsProto.FlowEntryStateProto.ADDED;
+            case PENDING_REMOVE:
+                return FlowEntryEnumsProto.FlowEntryStateProto.PENDING_REMOVE;
+            case REMOVED:
+                return FlowEntryEnumsProto.FlowEntryStateProto.REMOVED;
+            case FAILED:
+                return FlowEntryEnumsProto.FlowEntryStateProto.FAILED;
+
+            default:
+                log.warn("Unexpected flow entry state: {}", flowEntryState);
+                return FlowEntryEnumsProto.FlowEntryStateProto.UNRECOGNIZED;
+        }
+    }
+
+    /**
+     * Translates gRPC FlowEntryState to {@link FlowEntryState}.
+     *
+     * @param flowEntryState gRPC message
+     * @return {@link FlowEntryState}
+     */
+    public static Optional<Object> translate(FlowEntryEnumsProto.FlowEntryStateProto flowEntryState) {
+
+        switch (flowEntryState) {
+            case PENDING_ADD:
+                return Optional.of(FlowEntryState.PENDING_ADD);
+            case ADDED:
+                return Optional.of(FlowEntryState.ADDED);
+            case PENDING_REMOVE:
+                return Optional.of(FlowEntryState.PENDING_REMOVE);
+            case REMOVED:
+                return Optional.of(FlowEntryState.REMOVED);
+            case FAILED:
+                return Optional.of(FlowEntryState.FAILED);
+
+            default:
+                log.warn("Unexpected flow entry state: {}", flowEntryState);
+                return Optional.empty();
+        }
+    }
+
+    /**
+     * Translates {@link FlowLiveType} to gRPC FlowLiveType.
+     *
+     * @param flowLiveType {@link FlowLiveType}
+     * @return gRPC message
+     */
+    public static FlowEntryEnumsProto.FlowLiveTypeProto translate(FlowLiveType flowLiveType) {
+
+        switch (flowLiveType) {
+            case IMMEDIATE:
+                return FlowEntryEnumsProto.FlowLiveTypeProto.IMMEDIATE;
+            case SHORT:
+                return FlowEntryEnumsProto.FlowLiveTypeProto.SHORT;
+            case MID:
+                return FlowEntryEnumsProto.FlowLiveTypeProto.MID;
+            case LONG:
+                return FlowEntryEnumsProto.FlowLiveTypeProto.LONG;
+            case UNKNOWN:
+                return FlowEntryEnumsProto.FlowLiveTypeProto.UNKNOWN;
+
+            default:
+                log.warn("Unexpected flow live type : {}", flowLiveType);
+                return FlowEntryEnumsProto.FlowLiveTypeProto.UNRECOGNIZED;
+        }
+    }
+
+    /**
+     * Translates gRPC FlowLiveType to {@link FlowLiveType}.
+     *
+     * @param flowLiveType gRPC message
+     * @return {@link FlowLiveType}
+     */
+    public static Optional<Object> translate(FlowEntryEnumsProto.FlowLiveTypeProto flowLiveType) {
+
+        switch (flowLiveType) {
+            case IMMEDIATE:
+                return Optional.of(FlowLiveType.IMMEDIATE);
+            case SHORT:
+                return Optional.of(FlowLiveType.SHORT);
+            case MID:
+                return Optional.of(FlowLiveType.MID);
+            case LONG:
+                return Optional.of(FlowLiveType.LONG);
+            case UNKNOWN:
+                return Optional.of(FlowLiveType.UNKNOWN);
+
+            default:
+                log.warn("Unexpected flow live type : {}", flowLiveType);
+                return Optional.empty();
+        }
+    }
+
+    // Utility class not intended for instantiation.
+    private FlowEntryEnumsProtoTranslator() {}
+}
diff --git a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/FlowEntryProtoTranslator.java b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/FlowEntryProtoTranslator.java
new file mode 100644
index 0000000..9082f27
--- /dev/null
+++ b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/FlowEntryProtoTranslator.java
@@ -0,0 +1,79 @@
+/*
+ * 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.incubator.protobuf.models.net.flow;
+
+import org.onosproject.grpc.net.flow.models.FlowEntryProtoOuterClass.FlowEntryProto;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * gRPC FlowEntryProto message to equivalent ONOS FlowEntry conversion related utilities.
+ */
+public final class FlowEntryProtoTranslator {
+
+    private static final Logger log = LoggerFactory.getLogger(FlowEntryProtoTranslator.class);
+
+    /**
+     * Translates {@link FlowRule} to gRPC FlowRuleProto.
+     *
+     * @param flowEntry {@link FlowRule}
+     * @return gRPC message
+     */
+    public static FlowEntryProto translate(FlowEntry flowEntry) {
+
+        if (flowEntry != null) {
+            FlowEntryProto.Builder builder = FlowEntryProto.newBuilder();
+            builder.setLife(flowEntry.life())
+                    .setPackets(flowEntry.packets())
+                    .setBytes(flowEntry.bytes())
+                    .setLastSeen(flowEntry.lastSeen())
+                    .setErrType(flowEntry.errType())
+                    .setErrCode(flowEntry.errCode())
+                    .setState(FlowEntryEnumsProtoTranslator.translate(flowEntry.state()))
+                    .setLiveType(FlowEntryEnumsProtoTranslator.translate(flowEntry.liveType()));
+            return builder.build();
+        }
+
+        return FlowEntryProto.getDefaultInstance();
+    }
+
+    /**
+     * Translates gRPC FlowRule to {@link FlowRule}.
+     *
+     * @param flowEntry gRPC message
+     * @return {@link FlowRule}
+     */
+    public static FlowEntry translate(FlowEntryProto flowEntry) {
+        if (flowEntry.equals(FlowEntryProto.getDefaultInstance())) {
+            return null;
+        }
+
+        FlowEntry.FlowEntryState state = (FlowEntry.FlowEntryState)
+                FlowEntryEnumsProtoTranslator.translate(flowEntry.getState()).get();
+        FlowEntry.FlowLiveType liveType = (FlowEntry.FlowLiveType)
+                FlowEntryEnumsProtoTranslator.translate(flowEntry.getLiveType()).get();
+
+        // TODO: need to instantiate FlowRule later
+        return new DefaultFlowEntry(null, state, flowEntry.getLife(), liveType,
+                flowEntry.getPackets(), flowEntry.getBytes());
+    }
+
+    // Utility class not intended for instantiation.
+    private FlowEntryProtoTranslator() {}
+}
diff --git a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/package-info.java b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/package-info.java
new file mode 100644
index 0000000..08d0df9
--- /dev/null
+++ b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/flow/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+/**
+ * Utilities to handle ProtoBuf version of ONOS flow models.
+ */
+package org.onosproject.incubator.protobuf.models.net.flow;
\ No newline at end of file
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryEnumsProto.proto b/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryEnumsProto.proto
new file mode 100644
index 0000000..2bb6768
--- /dev/null
+++ b/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryEnumsProto.proto
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+syntax = "proto3";
+option java_package = "org.onosproject.grpc.net.flow.models";
+
+package net.flow;
+
+// Corresponds to org.onosproject.net.flow.FlowEntry.
+enum FlowEntryStateProto {
+
+    // Indicates that this rule has been submitted for addition.
+    // Not necessarily in the flow table.
+    PENDING_ADD = 0;
+
+    // Rule has been added which means it is in the flow table.
+    ADDED = 1;
+
+    // Flow has been marked for removal, might still be in flow table.
+    PENDING_REMOVE = 2;
+
+    // Flow has been removed from flow table and can be purged.
+    REMOVED = 3;
+
+    // Indicates that the installation of this flow has failed.
+    FAILED = 4;
+}
+
+enum FlowLiveTypeProto {
+
+    // Indicates that this rule has been submitted for addition immediately.
+    // Not necessarily collecting flow stats.
+    IMMEDIATE = 0;
+
+    // Indicates that this rule has been submitted for a short time.
+    // Collecting flow stats every SHORT interval, defined by the implementation.
+    SHORT = 1;
+
+    // Indicates that this rule has been submitted for a mid time.
+    // Collecting flow stats every MID interval, defined by the implementation.
+    MID = 2;
+
+    // Indicates that this rule has been submitted for a long time.
+    // Collecting flow stats every LONG interval, defined by the implementation.
+    LONG = 3;
+
+    // Indicates that this rule has been submitted for UNKNOWN or ERROR.
+    // Not necessarily collecting flow stats.
+    UNKNOWN = 4;
+}
\ No newline at end of file
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryProto.proto b/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryProto.proto
new file mode 100644
index 0000000..c28a624
--- /dev/null
+++ b/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryProto.proto
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+syntax = "proto3";
+option java_package = "org.onosproject.grpc.net.flow.models";
+
+package net.flow;
+
+import "net/flow/FlowEntryEnumsProto.proto";
+
+// Corresponds to org.onosproject.net.flow.DefaultFlowEntry.
+message FlowEntryProto {
+    int64 life = 1;
+    int64 packets = 2;
+    int64 bytes = 3;
+    int64 last_seen = 4;
+    int32 err_type = 5;
+    int32 err_code = 6;
+
+    net.flow.FlowEntryStateProto state = 7;
+    net.flow.FlowLiveTypeProto live_type = 8;
+}
\ No newline at end of file
diff --git a/incubator/protobuf/registry/src/main/java/org/onosproject/protobuf/registry/GrpcServiceRegistryImpl.java b/incubator/protobuf/registry/src/main/java/org/onosproject/protobuf/registry/GrpcServiceRegistryImpl.java
index ada1253..2c2d864 100644
--- a/incubator/protobuf/registry/src/main/java/org/onosproject/protobuf/registry/GrpcServiceRegistryImpl.java
+++ b/incubator/protobuf/registry/src/main/java/org/onosproject/protobuf/registry/GrpcServiceRegistryImpl.java
@@ -151,6 +151,7 @@
         } catch (InterruptedException e) {
             log.error("Awaiting server termination failed with error {}",
                       e.getMessage());
+            Thread.currentThread().interrupt();
         }
         if (!server.isTerminated()) {
             server.shutdownNow();
@@ -159,6 +160,7 @@
             } catch (InterruptedException e) {
                 log.error("Server failed to terminate as expected with error" +
                                   " {}", e.getMessage());
+                Thread.currentThread().interrupt();
             }
         }
         return server.isTerminated();
diff --git a/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java b/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java
index 28cc7ba..7124a1f 100644
--- a/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/meter/impl/DistributedMeterStore.java
@@ -202,6 +202,7 @@
         try {
             meters.put(key, data);
         } catch (StorageException e) {
+            futures.remove(key);
             future.completeExceptionally(e);
         }
         // Done, return the future
@@ -226,6 +227,7 @@
                 future.complete(MeterStoreResult.success());
             }
         } catch (StorageException e) {
+            futures.remove(key);
             future.completeExceptionally(e);
         }
         // Done, return the future
@@ -268,6 +270,7 @@
                 future.complete(MeterStoreResult.fail(MeterFailReason.INVALID_METER));
             }
         } catch (StorageException e) {
+            futures.remove(key);
             future.completeExceptionally(e);
         }
         return future;
diff --git a/lib/BUCK b/lib/BUCK
index 860b5de..8021a3d 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -1,4 +1,4 @@
-# ***** This file was auto-generated at Tue, 23 Jan 2018 20:38:59 GMT. Do not edit this file manually. *****
+# ***** This file was auto-generated at Fri, 16 Feb 2018 17:18:31 GMT. Do not edit this file manually. *****
 # ***** Use onos-lib-gen *****
 
 pass_thru_pom(
@@ -207,10 +207,10 @@
 
 remote_jar (
   name = 'atomix',
-  out = 'atomix-2.0.14.jar',
-  url = 'mvn:io.atomix:atomix:jar:2.0.14',
-  sha1 = 'b2deb5601c8385c0eaabc952a19241c772f0984c',
-  maven_coords = 'io.atomix:atomix:2.0.14',
+  out = 'atomix-2.0.18.jar',
+  url = 'mvn:io.atomix:atomix:jar:2.0.18',
+  sha1 = 'e5a9ea68155a7c97c591a4c40d608bf5f80e5c73',
+  maven_coords = 'io.atomix:atomix:2.0.18',
   visibility = [ 'PUBLIC' ],
 )
 
@@ -1232,82 +1232,163 @@
 
 remote_jar (
   name = 'openstack4j-core',
-  out = 'openstack4j-core-2.11.jar',
-  url = 'mvn:org.pacesys:openstack4j-core:jar:2.11',
-  sha1 = '583f508c55f5dceb90504a4a8a0590afb8a8a03a',
-  maven_coords = 'org.pacesys:openstack4j-core:2.11',
+  out = 'openstack4j-core-3.1.0.jar',
+  url = 'mvn:org.pacesys:openstack4j-core:jar:3.1.0',
+  sha1 = '634c2ad6728bb6e4cd91c950dd654aacb6f107a6',
+  maven_coords = 'org.pacesys:openstack4j-core:3.1.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'openstack4j-http-connector',
-  out = 'openstack4j-http-connector-2.11.jar',
-  url = 'mvn:org.pacesys.openstack4j.connectors:openstack4j-http-connector:jar:2.11',
-  sha1 = 'a153800e114916b4125de2cdb743497c0f99aef5',
-  maven_coords = 'org.pacesys.openstack4j.connectors:openstack4j-http-connector:2.11',
+  out = 'openstack4j-http-connector-3.1.0.jar',
+  url = 'mvn:org.pacesys.openstack4j.connectors:openstack4j-http-connector:jar:3.1.0',
+  sha1 = '5bbd558313f13daac819bbbe56ae8432e64409d9',
+  maven_coords = 'org.pacesys.openstack4j.connectors:openstack4j-http-connector:3.1.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'openstack4j-httpclient',
-  out = 'openstack4j-httpclient-2.11.jar',
-  url = 'mvn:org.pacesys.openstack4j.connectors:openstack4j-httpclient:jar:2.11',
-  sha1 = 'd050e21295959a4ce2c07ca193ccbe28d8bfa3c1',
-  maven_coords = 'org.pacesys.openstack4j.connectors:openstack4j-httpclient:2.11',
+  out = 'openstack4j-httpclient-3.1.0.jar',
+  url = 'mvn:org.pacesys.openstack4j.connectors:openstack4j-httpclient:jar:3.1.0',
+  sha1 = 'acb413e27cc43f4bbcee99300befffcf667de579',
+  maven_coords = 'org.pacesys.openstack4j.connectors:openstack4j-httpclient:3.1.0',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'json-patch',
+  out = 'json-patch-1.9.jar',
+  url = 'mvn:com.github.fge:json-patch:jar:1.9',
+  sha1 = '0a4c3c97a0f5965dec15795acf40d3fbc897af4b',
+  maven_coords = 'com.github.fge:json-patch:1.9',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'jackson-coreutils',
+  out = 'jackson-coreutils-1.6.jar',
+  url = 'mvn:com.github.fge:jackson-coreutils:jar:1.6',
+  sha1 = '9e6af56eb7cc2a65700b289abc7ee2bd170fd231',
+  maven_coords = 'com.github.fge:jackson-coreutils:1.6',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'btf',
+  out = 'btf-1.2.jar',
+  url = 'mvn:com.github.fge:btf:jar:1.2',
+  sha1 = '9e66651022eb86301b348d57e6f59459effc343b',
+  maven_coords = 'com.github.fge:btf:1.2',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'msg-simple',
+  out = 'msg-simple-1.1.jar',
+  url = 'mvn:com.github.fge:msg-simple:jar:1.1',
+  sha1 = 'f261263e13dd4cfa93cc6b83f1f58f619097a2c4',
+  maven_coords = 'com.github.fge:msg-simple:1.1',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'spifly-bundle',
+  out = 'org.apache.aries.spifly.dynamic.bundle-1.0.10.jar',
+  url = 'mvn:org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:jar:1.0.10',
+  sha1 = '0431cb51cd15566375e8b2bab366f611c8ea4175',
+  maven_coords = 'org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.0.10',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'spifly-weaver',
+  out = 'org.apache.aries.spifly.weaver-internal-1.0.10.jar',
+  url = 'mvn:org.apache.aries.spifly:org.apache.aries.spifly.weaver-internal:jar:1.0.10',
+  sha1 = 'c599c8b8bf33a0ce485c4af11f1ec5e8cabf993c',
+  maven_coords = 'org.apache.aries.spifly:org.apache.aries.spifly.weaver-internal:jar:NON-OSGI:1.0.10',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'spifly-core',
+  out = 'org.apache.aries.spifly.core-internal-1.0.10.jar',
+  url = 'mvn:org.apache.aries.spifly:org.apache.aries.spifly.core-internal:jar:1.0.10',
+  sha1 = '63b43dbb8a0675f3236fcc3cabb161ae105992cf',
+  maven_coords = 'org.apache.aries.spifly:org.apache.aries.spifly.core-internal:jar:NON-OSGI:1.0.10',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'aries-util',
+  out = 'org.apache.aries.util-1.1.1.jar',
+  url = 'mvn:org.apache.aries:org.apache.aries.util:jar:1.1.1',
+  sha1 = '74f3f1c6cc23a737d5f323e05f4f3b55d8bd0eb8',
+  maven_coords = 'org.apache.aries:org.apache.aries.util:1.1.1',
+  visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+  name = 'guava20',
+  out = 'guava-20.0.jar',
+  url = 'mvn:com.google.guava:guava:jar:20.0',
+  sha1 = '89507701249388e1ed5ddcf8c41f4ce1be7831ef',
+  maven_coords = 'com.google.guava:guava:20.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-model',
-  out = 'onos-yang-model-2.3.1.jar',
-  url = 'mvn:org.onosproject:onos-yang-model:jar:2.3.1',
-  sha1 = 'ffe8a79368ae816220a47bb9cad39e2d48ae415d',
-  maven_coords = 'org.onosproject:onos-yang-model:2.3.1',
+  out = 'onos-yang-model-2.4.1.jar',
+  url = 'mvn:org.onosproject:onos-yang-model:jar:2.4.1',
+  sha1 = '3e9bce9e34b8cd48e35db9f5f1b7bcf02272cc94',
+  maven_coords = 'org.onosproject:onos-yang-model:2.4.1',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-compiler-api',
-  out = 'onos-yang-compiler-api-2.3.1.jar',
-  url = 'mvn:org.onosproject:onos-yang-compiler-api:jar:2.3.1',
-  sha1 = '11edae3442f9fc8b4cb69aec2004203189fb3034',
-  maven_coords = 'org.onosproject:onos-yang-compiler-api:2.3.1',
+  out = 'onos-yang-compiler-api-2.4.1.jar',
+  url = 'mvn:org.onosproject:onos-yang-compiler-api:jar:2.4.1',
+  sha1 = '84c8a4ff5275673bb250aee386ad101efa9ffd1f',
+  maven_coords = 'org.onosproject:onos-yang-compiler-api:2.4.1',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-runtime',
-  out = 'onos-yang-runtime-2.3.1.jar',
-  url = 'mvn:org.onosproject:onos-yang-runtime:jar:2.3.1',
-  sha1 = 'b5da218f5841a39787aff51a58d154a76f07d249',
-  maven_coords = 'org.onosproject:onos-yang-runtime:2.3.1',
+  out = 'onos-yang-runtime-2.4.1.jar',
+  url = 'mvn:org.onosproject:onos-yang-runtime:jar:2.4.1',
+  sha1 = '1bafc4fa6121a8f5704875f5f314651d368edf4a',
+  maven_coords = 'org.onosproject:onos-yang-runtime:2.4.1',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-serializers-json',
-  out = 'onos-yang-serializers-json-2.3.1.jar',
-  url = 'mvn:org.onosproject:onos-yang-serializers-json:jar:2.3.1',
-  sha1 = '8f101d36ebcb14176121ddfddd15599c07967138',
-  maven_coords = 'org.onosproject:onos-yang-serializers-json:2.3.1',
+  out = 'onos-yang-serializers-json-2.4.1.jar',
+  url = 'mvn:org.onosproject:onos-yang-serializers-json:jar:2.4.1',
+  sha1 = '78fa5693549453c1ead06404196c14db06abb82e',
+  maven_coords = 'org.onosproject:onos-yang-serializers-json:2.4.1',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-serializers-xml',
-  out = 'onos-yang-serializers-xml-2.3.1.jar',
-  url = 'mvn:org.onosproject:onos-yang-serializers-xml:jar:2.3.1',
-  sha1 = '58090e77105c6f0cbf594b7130263056d4f9a473',
-  maven_coords = 'org.onosproject:onos-yang-serializers-xml:2.3.1',
+  out = 'onos-yang-serializers-xml-2.4.1.jar',
+  url = 'mvn:org.onosproject:onos-yang-serializers-xml:jar:2.4.1',
+  sha1 = '42e43a7ede05451d94107d185d6658c57a72baf5',
+  maven_coords = 'org.onosproject:onos-yang-serializers-xml:2.4.1',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-serializers-utils',
-  out = 'onos-yang-serializers-utils-2.3.1.jar',
-  url = 'mvn:org.onosproject:onos-yang-serializers-utils:jar:2.3.1',
-  sha1 = '58d6d3a6b10e236b1b65230a02cd7c2389478645',
-  maven_coords = 'org.onosproject:onos-yang-serializers-utils:2.3.1',
+  out = 'onos-yang-serializers-utils-2.4.1.jar',
+  url = 'mvn:org.onosproject:onos-yang-serializers-utils:jar:2.4.1',
+  sha1 = '8fa9c76821c976f42b548794caeda69e9391facc',
+  maven_coords = 'org.onosproject:onos-yang-serializers-utils:2.4.1',
   visibility = [ 'PUBLIC' ],
 )
 
diff --git a/lib/deps.json b/lib/deps.json
index 0d98ca2..ede7521 100644
--- a/lib/deps.json
+++ b/lib/deps.json
@@ -116,7 +116,7 @@
     "aopalliance-repackaged": "mvn:org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b32",
     "amqp-client": "mvn:com.rabbitmq:amqp-client:jar:3.6.1",
     "asm": "mvn:org.ow2.asm:asm:5.0.4",
-    "atomix": "mvn:io.atomix:atomix:2.0.14",
+    "atomix": "mvn:io.atomix:atomix:2.0.18",
     "commons-codec": "mvn:commons-codec:commons-codec:1.10",
     "commons-collections": "mvn:commons-collections:commons-collections:3.2.2",
     "commons-configuration": "mvn:commons-configuration:commons-configuration:1.10",
@@ -234,16 +234,26 @@
     "mibs-net-snmp": "mvn:org.onosproject:mibbler-mibs-net-snmp:1.0-20151221.1",
     "mibs-rfc": "mvn:org.onosproject:mibbler-mibs-rfc:1.0-20151221.1",
     // Openstack4j related jars
-    "openstack4j-core": "mvn:org.pacesys:openstack4j-core:2.11",
-    "openstack4j-http-connector": "mvn:org.pacesys.openstack4j.connectors:openstack4j-http-connector:2.11",
-    "openstack4j-httpclient": "mvn:org.pacesys.openstack4j.connectors:openstack4j-httpclient:2.11",
-    // Note: update BVER in tools/dev/bin/patch-yang-libs
-    "onos-yang-model":"mvn:org.onosproject:onos-yang-model:2.3.1",
-    "onos-yang-compiler-api":"mvn:org.onosproject:onos-yang-compiler-api:2.3.1",
-    "onos-yang-runtime":"mvn:org.onosproject:onos-yang-runtime:2.3.1",
-    "onos-yang-serializers-json":"mvn:org.onosproject:onos-yang-serializers-json:2.3.1",
-    "onos-yang-serializers-xml":"mvn:org.onosproject:onos-yang-serializers-xml:2.3.1",
-    "onos-yang-serializers-utils":"mvn:org.onosproject:onos-yang-serializers-utils:2.3.1",
+    "openstack4j-core": "mvn:org.pacesys:openstack4j-core:3.1.0",
+    "openstack4j-http-connector": "mvn:org.pacesys.openstack4j.connectors:openstack4j-http-connector:3.1.0",
+    "openstack4j-httpclient": "mvn:org.pacesys.openstack4j.connectors:openstack4j-httpclient:3.1.0",
+    "json-patch": "mvn:com.github.fge:json-patch:1.9",
+    "jackson-coreutils": "mvn:com.github.fge:jackson-coreutils:1.6",
+    "btf": "mvn:com.github.fge:btf:1.2",
+    "msg-simple": "mvn:com.github.fge:msg-simple:1.1",
+    "spifly-bundle": "mvn:org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.0.10",
+    "spifly-weaver": "mvn:org.apache.aries.spifly:org.apache.aries.spifly.weaver-internal:1.0.10",
+    "spifly-core": "mvn:org.apache.aries.spifly:org.apache.aries.spifly.core-internal:1.0.10",
+    "aries-util": "mvn:org.apache.aries:org.apache.aries.util:1.1.1",
+    "guava20": "mvn:com.google.guava:guava:20.0",
+
+    // Note update BVER in tools/dev/bin/patch-yang-libs and YANG_VER in tools/build/onos-buck
+    "onos-yang-model":"mvn:org.onosproject:onos-yang-model:2.4.1",
+    "onos-yang-compiler-api":"mvn:org.onosproject:onos-yang-compiler-api:2.4.1",
+    "onos-yang-runtime":"mvn:org.onosproject:onos-yang-runtime:2.4.1",
+    "onos-yang-serializers-json":"mvn:org.onosproject:onos-yang-serializers-json:2.4.1",
+    "onos-yang-serializers-xml":"mvn:org.onosproject:onos-yang-serializers-xml:2.4.1",
+    "onos-yang-serializers-utils":"mvn:org.onosproject:onos-yang-serializers-utils:2.4.1",
     "org.apache.servicemix.bundles.dom4j":"mvn:org.apache.servicemix.bundles:org.apache.servicemix.bundles.dom4j:1.6.1_5",
     "plexus-utils": "mvn:org.codehaus.plexus:plexus-utils:3.0.24",
     "sshd-core": "mvn:org.apache.sshd:sshd-core:1.4.0",
diff --git a/lib/pom.xml b/lib/pom.xml
index 8cc00c4..95f5640 100644
--- a/lib/pom.xml
+++ b/lib/pom.xml
@@ -40,7 +40,7 @@
         <netty4.version>4.1.8.Final</netty4.version>
         <openflowj.version>3.2.0.onos</openflowj.version>
         <onos-maven-plugin.version>1.11</onos-maven-plugin.version>
-        <onos-yang-tools.version>2.3.1</onos-yang-tools.version>
+        <onos-yang-tools.version>2.4</onos-yang-tools.version>
         <osgi.version>5.0.0</osgi.version>
         <karaf.version>3.0.8</karaf.version>
         <jersey.version>2.25.1</jersey.version>
diff --git a/models/tapi/src/main/yang/tapi-common@2017-05-31.yang b/models/tapi/src/main/yang/tapi-common@2017-05-31.yang
index fa7145e..eb3ce4f 100644
--- a/models/tapi/src/main/yang/tapi-common@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-common@2017-05-31.yang
@@ -47,27 +47,6 @@
             }

             description "The TAPI GlobalComponent serves as the super class for all TAPI entities that can be directly retrieved by their ID. As such, these are first class entities and their ID is expected to be globally unique. ";

         }

-        grouping layer-protocol {

-            leaf layer-protocol-name {

-                type layer-protocol-name;

-                description "Indicate the specific layer-protocol described by the LayerProtocol entity.";

-            }

-            leaf termination-direction {

-                type termination-direction;

-                description "The overall directionality of the LP. 

-                    - A BIDIRECTIONAL LP will have some SINK and/or SOURCE flowss.

-                    - A SINK LP can only contain elements with SINK flows or CONTRA_DIRECTION_SOURCE flows

-                    - A SOURCE LP can only contain SOURCE flows or CONTRA_DIRECTION_SINK flows";

-            }

-            leaf termination-state {

-                type termination-state;

-                description "Indicates whether the layer is terminated and if so how.";

-            }

-            uses local-class;

-            description "Each transport layer is represented by a LayerProtocol (LP) instance. The LayerProtocol instances it can be used for controlling termination and monitoring functionality. 

-                It can also be used for controlling the adaptation (i.e. encapsulation and/or multiplexing of client signal), tandem connection monitoring, traffic conditioning and/or shaping functionality at an intermediate point along a connection. 

-                Where the client – server relationship is fixed 1:1 and immutable, the layers can be encapsulated in a single LTP instance. Where the is a n:1 relationship between client and server, the layers must be split over two separate instances of LTP. ";

-        }

         grouping lifecycle-state-pac {

             leaf lifecycle-state {

                 type lifecycle-state;

@@ -103,10 +82,10 @@
         }

         container context {

         	presence "TAPI";

-            uses context;

+            uses _context;

             description "none";

         }

-        grouping context {

+        grouping _context {

             list service-interface-point {

                 key 'uuid';

                 min-elements 2;

@@ -125,21 +104,15 @@
             description "none";

         }

         grouping service-interface-point {

-            list layer-protocol {

-                key 'local-id';

+            leaf-list layer-protocol-name {

+                type layer-protocol-name;

+                config false;

                 min-elements 1;

-                uses layer-protocol;

-                description "Usage of layerProtocol [>1]  in the ServiceInterfacePoint should be considered experimental";

-            }

-            container state {

-                uses admin-state-pac;

-                description "none";

-            }

-            container capacity {

-                uses capacity-pac;

-                description "none";

+                description "Usage of layerProtocolName [>1]  in the ServiceInterfacePoint should be considered experimental";

             }

             uses resource-spec;

+            uses tapi-common:admin-state-pac;

+            uses tapi-common:capacity-pac;

             description "The LogicalTerminationPoint (LTP) object class encapsulates the termination and adaptation functions of one or more transport layers. 

                 The structure of LTP supports all transport protocols including circuit and packet forms.";

         }

@@ -161,39 +134,34 @@
                 Represents the capacity available to user (client) along with client interaction and usage. 

                 A TopologicalEntity may reflect one or more client protocols and one or more members for each profile.";

         }

+        grouping termination-pac {

+            leaf termination-direction {

+                type termination-direction;

+                config false;

+                description "The overall directionality of the LP. 

+                    - A BIDIRECTIONAL LP will have some SINK and/or SOURCE flowss.

+                    - A SINK LP can only contain elements with SINK flows or CONTRA_DIRECTION_SOURCE flows

+                    - A SOURCE LP can only contain SOURCE flows or CONTRA_DIRECTION_SINK flows";

+            }

+            leaf termination-state {

+                type termination-state;

+                config false;

+                description "Indicates whether the layer is terminated and if so how.";

+            }

+            description "Each transport layer is represented by a LayerProtocol (LP) instance. The LayerProtocol instances it can be used for controlling termination and monitoring functionality. 

+                It can also be used for controlling the adaptation (i.e. encapsulation and/or multiplexing of client signal), tandem connection monitoring, traffic conditioning and/or shaping functionality at an intermediate point along a connection. 

+                Where the client – server relationship is fixed 1:1 and immutable, the layers can be encapsulated in a single LTP instance. Where the is a n:1 relationship between client and server, the layers must be split over two separate instances of LTP. ";

+        }

 

     /***********************

     * package type-definitions

     **********************/ 

-        identity layer-protocol-name {

-            description "none";

-        }

-        identity otsi-a {

-            base layer-protocol-name;

-            description "none";

-        }

-        identity otu {

-            base layer-protocol-name;

-            description "none";

-        }

-        identity odu {

-            base layer-protocol-name;

-            description "none";

-        }

-        identity eth {

-            base layer-protocol-name;

-            description "none";

-        }

-        identity ety {

-            base layer-protocol-name;

-            description "none";

-        }

         typedef administrative-state {

             type enumeration {

-                enum locked {

+                enum LOCKED {

                     description "Users are administratively prohibited from making use of the resource.";

                 }

-                enum unlocked {

+                enum UNLOCKED {

                     description "Users are allowed to use the resource";

                 }

             }

@@ -217,19 +185,19 @@
         }

         typedef directive-value {

             type enumeration {

-                enum minimize {

+                enum MINIMIZE {

                     description "none";

                 }

-                enum maximize {

+                enum MAXIMIZE {

                     description "none";

                 }

-                enum allow {

+                enum ALLOW {

                     description "none";

                 }

-                enum disallow {

+                enum DISALLOW {

                     description "none";

                 }

-                enum dont-care {

+                enum DONT_CARE {

                     description "none";

                 }

             }

@@ -237,21 +205,38 @@
         }

         typedef forwarding-direction {

             type enumeration {

-                enum bidirectional {

+                enum BIDIRECTIONAL {

                     description "The Fowarding entity supports both BIDIRECTIONAL flows at all Ports (i.e. all Ports have both an INPUT flow and an OUTPUT flow defined)";

                 }

-                enum unidirectional {

+                enum UNIDIRECTIONAL {

                     description "The Forwarding entity has Ports that are either INPUT or OUTPUT. It has no BIDIRECTIONAL Ports.";

                 }

-                enum undefined-or-unknown {

+                enum UNDEFINED_OR_UNKNOWN {

                     description "Not a normal state. The system is unable to determine the correct value.";

                 }

             }

             description "The directionality of a Forwarding entity.";

         }

         typedef layer-protocol-name {

-            type identityref {

-                base layer-protocol-name;

+            type enumeration {

+                enum OTSiA {

+                    description "Models the OTSiA layer as per ITU-T G.872 (2017) version 4";

+                }

+                enum OCH {

+                    description "Models the legacy OCH layer as per ITU-T G.872";

+                }

+                enum OTU {

+                    description "Models the OTU layer as per ITU-T G.872";

+                }

+                enum ODU {

+                    description "Models the ODU layer as per ITU-T G.872";

+                }

+                enum ETH {

+                    description "Models the ETH layer as per ITU-T G.8010";

+                }

+                enum ETY {

+                    description "Models the ETY layer as per ITU-T G.8010";

+                }

             }

             description "Provides a controlled list of layer protocol names and indicates the naming authority.

                 Note that it is expected that attributes will be added to this structure to convey the naming authority name, the name of the layer protocol using a human readable string and any particular standard reference.

@@ -262,18 +247,23 @@
         }

         typedef lifecycle-state {

             type enumeration {

-                enum planned {

+                enum PLANNED {

                     description "The resource is planned but is not present in the network.";

                 }

-                enum potential {

+                enum POTENTIAL_AVAILABLE {

                     description "The supporting resources are present in the network but are shared with other clients; or require further configuration before they can be used; or both.

                         o    When a potential resource is configured and allocated to a client it is moved to the “installed” state for that client.

                         o    If the potential resource has been consumed (e.g. allocated to another client) it is moved to the “planned” state for all other clients.";

                 }

-                enum installed {

+                enum POTENTIAL_BUSY {

+                    description "The supporting resources are present in the network but are shared with other clients; or require further configuration before they can be used; or both.

+                        o    When a potential resource is configured and allocated to a client it is moved to the “installed” state for that client.

+                        o    If the potential resource has been consumed (e.g. allocated to another client) it is moved to the “planned” state for all other clients.";

+                }

+                enum INSTALLED {

                     description "The resource is present in the network and is capable of providing the service expected.";

                 }

-                enum pending-removal {

+                enum PENDING_REMOVAL {

                     description "The resource has been marked for removal";

                 }

             }

@@ -292,10 +282,10 @@
         }

         typedef operational-state {

             type enumeration {

-                enum disabled {

+                enum DISABLED {

                     description "The resource is unable to meet the SLA of the user of the resource. If no (explicit) SLA is defined the resource is disabled if it is totally inoperable and unable to provide service to the user.";

                 }

-                enum enabled {

+                enum ENABLED {

                     description "The resource is partially or fully operable and available for use";

                 }

             }

@@ -303,16 +293,16 @@
         }

         typedef port-direction {

             type enumeration {

-                enum bidirectional {

+                enum BIDIRECTIONAL {

                     description "The Port has both an INPUT flow and an OUTPUT flow defined.";

                 }

-                enum input {

+                enum INPUT {

                     description "The Port only has definition for a flow into the Forwarding entity (i.e. an ingress flow).";

                 }

-                enum output {

+                enum OUTPUT {

                     description "The Port only has definition for a flow out of the Forwarding entity (i.e. an egress flow).";

                 }

-                enum unidentified-or-unknown {

+                enum UNIDENTIFIED_OR_UNKNOWN {

                     description "Not a normal state. The system is unable to determine the correct value.";

                 }

             }

@@ -320,19 +310,19 @@
         }

         typedef port-role {

             type enumeration {

-                enum symmetric {

+                enum SYMMETRIC {

                     description "none";

                 }

-                enum root {

+                enum ROOT {

                     description "none";

                 }

-                enum leaf {

+                enum LEAF {

                     description "none";

                 }

-                enum trunk {

+                enum TRUNK {

                     description "none";

                 }

-                enum unknown {

+                enum UNKNOWN {

                     description "none";

                 }

             }

@@ -340,10 +330,10 @@
         }

         typedef termination-direction {

             type enumeration {

-                enum bidirectional {

+                enum BIDIRECTIONAL {

                     description "A Termination with both SINK and SOURCE flows.";

                 }

-                enum sink {

+                enum SINK {

                     description "The flow is up the layer stack from the server side to the client side. 

                         Considering an example of a Termination function within the termination entity, a SINK flow:

                         - will arrive at at the base of the termination function (the server side) where it is essentially at an INPUT to the termination component

@@ -352,7 +342,7 @@
                         A SINK termination is one that only supports a SINK flow.

                         A SINK termiation can be bound to an OUTPUT Port of a Forwarding entity";

                 }

-                enum source {

+                enum SOURCE {

                     description "The flow is down the layer stack from the server side to the client side. 

                         Considering an example of a Termination function within the termination entity, a SOURCE flow:

                         - will arrive at at the top of the termination function (the client side) where it is essentially at an INPUT to the termination component

@@ -361,7 +351,7 @@
                         A SOURCE termination is one that only supports a SOURCE flow.

                         A SOURCE termiation can be bound to an INPUT Port of a Forwarding entity";

                 }

-                enum undefined-or-unknown {

+                enum UNDEFINED_OR_UNKNOWN {

                     description "Not a normal state. The system is unable to determine the correct value.";

                 }

             }

@@ -369,25 +359,25 @@
         }

         typedef termination-state {

             type enumeration {

-                enum lp-can-never-terminate {

+                enum LP_CAN_NEVER_TERMINATE {

                     description "A non-flexible case that can never be terminated.";

                 }

-                enum lt-not-terminated {

+                enum LT_NOT_TERMINATED {

                     description "A flexible termination that can terminate but is currently not terminated.";

                 }

-                enum terminated-server-to-client-flow {

+                enum TERMINATED_SERVER_TO_CLIENT_FLOW {

                     description "A flexible termination that is currently terminated for server to client flow only.";

                 }

-                enum terminated-client-to-server-flow {

+                enum TERMINATED_CLIENT_TO_SERVER_FLOW {

                     description "A flexible termination that is currently terminated for client to server flow only.";

                 }

-                enum terminated-bidirectional {

+                enum TERMINATED_BIDIRECTIONAL {

                     description "A flexible termination that is currently terminated in both directions of flow.";

                 }

-                enum lt-permenantly-terminated {

+                enum LT_PERMENANTLY_TERMINATED {

                     description "A non-flexible termination that is always terminated (in both directions of flow for a bidirectional case and in the one direction of flow for both unidirectional cases).";

                 }

-                enum termination-state-unknown {

+                enum TERMINATION_STATE_UNKNOWN {

                     description "There TerminationState cannot be determined.";

                 }

             }

@@ -456,13 +446,28 @@
         }

         typedef capacity-unit {

             type enumeration {

-                enum gbps {

+                enum TB {

+                    description "Indicates that the integer CapacityValue is in TeraBytes";

+                }

+                enum TBPS {

+                    description "Indicates that the integer CapacityValue is in Terabit-per-second";

+                }

+                enum GB {

+                    description "Indicates that the integer CapacityValue is in GigaBytes";

+                }

+                enum GBPS {

                     description "Indicates that the integer CapacityValue is in Gigabit-per-second";

                 }

-                enum mbps {

+                enum MB {

+                    description "Indicates that the integer CapacityValue is in MegaBytes";

+                }

+                enum MBPS {

                     description "Indicates that the integer CapacityValue is in Megabit-per-second";

                 }

-                enum kbps {

+                enum KB {

+                    description "Indicates that the integer CapacityValue is in KiloBytes";

+                }

+                enum KBPS {

                     description "Indicates that the integer CapacityValue is in Kilobit-per-second";

                 }

             }

@@ -470,16 +475,16 @@
         }

         typedef bandwidth-profile-type {

             type enumeration {

-                enum mef-10.x {

+                enum MEF_10.x {

                     description "none";

                 }

-                enum rfc-2697 {

+                enum RFC_2697 {

                     description "none";

                 }

-                enum rfc-2698 {

+                enum RFC_2698 {

                     description "none";

                 }

-                enum rfc-4115 {

+                enum RFC_4115 {

                     description "none";

                 }

             }

diff --git a/models/tapi/src/main/yang/tapi-connectivity@2017-05-31.yang b/models/tapi/src/main/yang/tapi-connectivity@2017-05-31.yang
index 3957f0d..8f223d0 100644
--- a/models/tapi/src/main/yang/tapi-connectivity@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-connectivity@2017-05-31.yang
@@ -50,19 +50,6 @@
                     Connection aggregation reflects Node/Topology aggregation. 

                     The FC represents a Cross-Connection in an NE. The Cross-Connection in an NE is not necessarily the lowest level of FC partitioning.";

             }

-            leaf-list supported-link {

-                type leafref {

-                    path '/tapi-common:context/tapi-topology:topology/tapi-topology:link/tapi-topology:uuid';

-                }

-                description "An Connection that spans between CEPs that terminate the LayerProtocol usually supports one or more links in the client layer.";

-            }

-            leaf container-node {

-                type leafref {

-                    path '/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:uuid';

-                }

-                config false;

-                description "none";

-            }

             list route {

                 key 'local-id';

                 config false;

@@ -75,11 +62,6 @@
                 uses switch-control;

                 description "none";

             }

-            container state {

-                config false;

-                uses tapi-common:operational-state-pac;

-                description "none";

-            }

             leaf direction {

                 type tapi-common:forwarding-direction;

                 config false;

@@ -91,15 +73,28 @@
                 description "none";

             }

             uses tapi-common:resource-spec;

+            uses tapi-common:operational-state-pac;

             description "The ForwardingConstruct (FC) object class models enabled potential for forwarding between two or more LTPs and like the LTP supports any transport protocol including all circuit and packet forms.

                 At the lowest level of recursion, a FC represents a cross-connection within an NE.";

         }

         grouping connection-end-point {

-            list layer-protocol {

-                key 'local-id';

+            leaf layer-protocol-name {

+                type tapi-common:layer-protocol-name;

+                config false;

+                description "none";

+            }

+            leaf connectivity-service-end-point {

+                type leafref {

+                    path '/tapi-common:context/tapi-connectivity:connectivity-service/tapi-connectivity:end-point/tapi-connectivity:local-id';

+                }

+                description "none";

+            }

+            leaf-list parent-node-edge-point {

+                type leafref {

+                    path '/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point/tapi-topology:uuid';

+                }

                 config false;

                 min-elements 1;

-                uses tapi-common:layer-protocol;

                 description "none";

             }

             leaf-list client-node-edge-point {

@@ -109,31 +104,6 @@
                 config false;

                 description "none";

             }

-            leaf server-node-edge-point {

-                type leafref {

-                    path '/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point/tapi-topology:uuid';

-                }

-                config false;

-                description "none";

-            }

-            leaf peer-connection-end-point {

-                type leafref {

-                    path '/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point/tapi-connectivity:connection-end-point/tapi-connectivity:uuid';

-                }

-                config false;

-                description "none";

-            }

-            leaf-list associated-route {

-                type leafref {

-                    path '/tapi-common:context/tapi-connectivity:connection/tapi-connectivity:route/tapi-connectivity:local-id';

-                }

-                description "none";

-            }

-            container state {

-                config false;

-                uses tapi-common:operational-state-pac;

-                description "none";

-            }

             leaf connection-port-direction {

                 type tapi-common:port-direction;

                 config false;

@@ -145,6 +115,8 @@
                 description "Each EP of the FC has a role (e.g., working, protection, protected, symmetric, hub, spoke, leaf, root)  in the context of the FC with respect to the FC function. ";

             }

             uses tapi-common:resource-spec;

+            uses tapi-common:operational-state-pac;

+            uses tapi-common:termination-pac;

             description "The LogicalTerminationPoint (LTP) object class encapsulates the termination and adaptation functions of one or more transport layers. 

                 The structure of LTP supports all transport protocols including circuit and packet forms.";

         }

@@ -185,10 +157,6 @@
                 uses tapi-topology:latency-characteristic;

                 description "The effect on the latency of a queuing process. This only has significant effect for packet based systems and has a complex characteristic.";

             }

-            container route-compute-policy {

-                uses route-compute-policy;

-                description "none";

-            }

             leaf coroute-inclusion {

                 type leafref {

                     path '/tapi-common:context/tapi-connectivity:connectivity-service/tapi-connectivity:uuid';

@@ -203,7 +171,7 @@
                 config false;

                 description "none";

             }

-            uses tapi-common:local-class;

+            uses tapi-connectivity:route-compute-policy;

             description "none";

         }

         grouping connectivity-service {

@@ -220,18 +188,6 @@
                 config false;

                 description "none";

             }

-            container conn-constraint {

-                uses connectivity-constraint;

-                description "none";

-            }

-            container topo-constraint {

-                uses topology-constraint;

-                description "none";

-            }

-            container state {

-                uses tapi-common:admin-state-pac;

-                description "none";

-            }

             leaf direction {

                 type tapi-common:forwarding-direction;

                 description "none";

@@ -240,39 +196,25 @@
                 type tapi-common:layer-protocol-name;

                 description "none";

             }

-            list resilience-constraint {

-                key 'local-id';

-                uses resilience-constraint;

-                description "none";

-            }

             uses tapi-common:service-spec;

+            uses tapi-connectivity:connectivity-constraint;

+            uses tapi-connectivity:topology-constraint;

+            uses tapi-common:admin-state-pac;

+            uses tapi-connectivity:resilience-constraint;

             description "The ForwardingConstruct (FC) object class models enabled potential for forwarding between two or more LTPs and like the LTP supports any transport protocol including all circuit and packet forms.

                 At the lowest level of recursion, a FC represents a cross-connection within an NE.";

         }

         grouping connectivity-service-end-point {

+            leaf layer-protocol-name {

+                type tapi-common:layer-protocol-name;

+                description "none";

+            }

             leaf service-interface-point {

                 type leafref {

                     path '/tapi-common:context/tapi-common:service-interface-point/tapi-common:uuid';

                 }

                 description "none";

             }

-            leaf-list connection-end-point {

-                type leafref {

-                    path '/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point/tapi-connectivity:connection-end-point/tapi-connectivity:uuid';

-                }

-                config false;

-                description "none";

-            }

-            list layer-protocol {

-                key 'local-id';

-                min-elements 1;

-                uses tapi-common:layer-protocol;

-                description "none";

-            }

-            container state {

-                uses tapi-common:admin-state-pac;

-                description "none";

-            }

             container capacity {

                 uses tapi-common:capacity-pac;

                 description "none";

@@ -290,6 +232,7 @@
                 description "To specify the protection role of this Port when create or update ConnectivityService.";

             }

             uses tapi-common:local-class;

+            uses tapi-common:admin-state-pac;

             description "The association of the FC to LTPs is made via EndPoints.

                 The EndPoint (EP) object class models the access to the FC function. 

                 The traffic forwarding between the associated EPs of the FC depends upon the type of FC and may be associated with FcSwitch object instances.  

@@ -380,11 +323,8 @@
                 uses switch;

                 description "none";

             }

-            container control-parameters {

-                uses resilience-constraint;

-                description "none";

-            }

             uses tapi-common:local-class;

+            uses tapi-connectivity:resilience-constraint;

             description "Represents the capability to control and coordinate switches, to add/delete/modify FCs and to add/delete/modify LTPs/LPs so as to realize a protection scheme.";

         }

         grouping resilience-constraint {

@@ -438,7 +378,6 @@
                 type tapi-common:layer-protocol-name;

                 description "Indicate which layer this resilience parameters package configured for.";

             }

-            uses tapi-common:local-class;

             description "A list of control parameters to apply to a switch.";

         }

         grouping topology-constraint {

@@ -503,7 +442,6 @@
                 config false;

                 description "soft constraint requested by client to indicate the layer(s) of transport connection that it prefers to carry the service. This could be same as the service layer or one of the supported server layers";

             }

-            uses tapi-common:local-class;

             description "none";

         }

         grouping cep-list {

@@ -531,16 +469,16 @@
     **********************/ 

         typedef service-type {

             type enumeration {

-                enum point-to-point-connectivity {

+                enum POINT_TO_POINT_CONNECTIVITY {

                     description "none";

                 }

-                enum point-to-multipoint-connectivity {

+                enum POINT_TO_MULTIPOINT_CONNECTIVITY {

                     description "none";

                 }

-                enum multipoint-connectivity {

+                enum MULTIPOINT_CONNECTIVITY {

                     description "none";

                 }

-                enum rooted-multipoint-connectivity {

+                enum ROOTED_MULTIPOINT_CONNECTIVITY {

                     description "none";

                 }

             }

@@ -548,10 +486,10 @@
         }

         typedef reversion-mode {

             type enumeration {

-                enum revertive {

+                enum REVERTIVE {

                     description "An FC switched to a lower priority (non-preferred) resource will revert to a higher priority (preferred) resource when that recovers (potentially after some hold-off time).";

                 }

-                enum non-revertive {

+                enum NON-REVERTIVE {

                     description "An FC switched to a lower priority (non-preferred) resource will not revert to a higher priority (preferred) resource when that recovers.";

                 }

             }

@@ -559,19 +497,19 @@
         }

         typedef selection-control {

             type enumeration {

-                enum lock-out {

+                enum LOCK_OUT {

                     description "The resource is configured to temporarily not be available for use in the protection scheme(s) it is part of.

                         This overrides all other protection control states including forced.

                         If the item is locked out then it cannot be used under any circumstances.

                         Note: Only relevant when part of a protection scheme.";

                 }

-                enum normal {

+                enum NORMAL {

                     description "none";

                 }

-                enum manual {

+                enum MANUAL {

                     description "none";

                 }

-                enum forced {

+                enum FORCED {

                     description "none";

                 }

             }

@@ -579,25 +517,25 @@
         }

         typedef selection-reason {

             type enumeration {

-                enum lockout {

+                enum LOCKOUT {

                     description "none";

                 }

-                enum normal {

+                enum NORMAL {

                     description "none";

                 }

-                enum manual {

+                enum MANUAL {

                     description "none";

                 }

-                enum forced {

+                enum FORCED {

                     description "none";

                 }

-                enum wait-to-revert {

+                enum WAIT_TO_REVERT {

                     description "none";

                 }

-                enum signal-degrade {

+                enum SIGNAL_DEGRADE {

                     description "none";

                 }

-                enum signal-fail {

+                enum SIGNAL_FAIL {

                     description "none";

                 }

             }

@@ -605,13 +543,13 @@
         }

         typedef coordinate-type {

             type enumeration {

-                enum no-coordinate {

+                enum NO_COORDINATE {

                     description "none";

                 }

-                enum hold-off-time {

+                enum HOLD_OFF_TIME {

                     description "none";

                 }

-                enum wait-for-notification {

+                enum WAIT_FOR_NOTIFICATION {

                     description "none";

                 }

             }

@@ -619,25 +557,25 @@
         }

         typedef route-objective-function {

             type enumeration {

-                enum min-work-route-hop {

+                enum MIN_WORK_ROUTE_HOP {

                     description "none";

                 }

-                enum min-work-route-cost {

+                enum MIN_WORK_ROUTE_COST {

                     description "none";

                 }

-                enum min-work-route-latency {

+                enum MIN_WORK_ROUTE_LATENCY {

                     description "none";

                 }

-                enum min-sum-of-work-and-protection-route-hop {

+                enum MIN_SUM_OF_WORK_AND_PROTECTION_ROUTE_HOP {

                     description "none";

                 }

-                enum min-sum-of-work-and-protection-route-cost {

+                enum MIN_SUM_OF_WORK_AND_PROTECTION_ROUTE_COST {

                     description "none";

                 }

-                enum min-sum-of-work-and-protection-route-latency {

+                enum MIN_SUM_OF_WORK_AND_PROTECTION_ROUTE_LATENCY {

                     description "none";

                 }

-                enum load-balance-max-unused-capacity {

+                enum LOAD_BALANCE_MAX_UNUSED_CAPACITY {

                     description "none";

                 }

             }

@@ -645,19 +583,19 @@
         }

         typedef diversity-policy {

             type enumeration {

-                enum srlg {

+                enum SRLG {

                     description "none";

                 }

-                enum srng {

+                enum SRNG {

                     description "none";

                 }

-                enum sng {

+                enum SNG {

                     description "none";

                 }

-                enum node {

+                enum NODE {

                     description "none";

                 }

-                enum link {

+                enum LINK {

                     description "none";

                 }

             }

@@ -665,22 +603,22 @@
         }

         typedef protection-role {

             type enumeration {

-                enum work {

+                enum WORK {

                     description "none";

                 }

-                enum protect {

+                enum PROTECT {

                     description "none";

                 }

-                enum protected {

+                enum PROTECTED {

                     description "none";

                 }

-                enum na {

+                enum NA {

                     description "none";

                 }

-                enum work-restore {

+                enum WORK_RESTORE {

                     description "none";

                 }

-                enum protect-restore {

+                enum PROTECT_RESTORE {

                     description "none";

                 }

             }

diff --git a/models/tapi/src/main/yang/tapi-eth@2017-05-31.yang b/models/tapi/src/main/yang/tapi-eth@2017-05-31.yang
index 500430f..d4509e1 100644
--- a/models/tapi/src/main/yang/tapi-eth@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-eth@2017-05-31.yang
@@ -21,18 +21,18 @@
         description "TAPI SDK 2.0-alpha";

         reference "ONF-TR-527, ONF-TR-512, ONF-TR-531, RFC 6020 and RFC 6087";

     }

-    augment "/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point/tapi-connectivity:connection-end-point/tapi-connectivity:layer-protocol" {

-        uses connection-end-point-lp-spec;

-        description "Augments the base LayerProtocol information in ConnectionEndPoint with ETH-specific information";

+    augment "/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point" {

+        uses eth-node-edge-point-spec;

+        description "Augments the base LayerProtocol information in NodeEndPoint with ETH-specific information";

     }

-    augment "/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point/tapi-topology:layer-protocol" {

-        uses node-edge-point-lp-spec;

-        description "Augments the base LayerProtocol information in NodeEdgePoint with ETH-specific information";

+    augment "/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:owned-node-edge-point/tapi-connectivity:connection-end-point" {

+        uses eth-connection-end-point-spec;

+        description "Augments the base LayerProtocol information in ConnectionEndPoint with ETH-specific information";

     }

     /***********************

     * package object-classes

     **********************/ 

-        grouping connection-point-and-adapter-pac {

+        grouping eth-ctp-pac {

             leaf-list auxiliary-function-position-sequence {

                 type uint64;

                 description "This attribute indicates the positions (i.e., the relative order) of all the MEP, MIP, and TCS objects which are associated with the CTP.";

@@ -143,25 +143,13 @@
                 description "This attribute models the combination of all CSF related MI signals (MI_CSF_Enable, MI_CSFrdifdi_Enable, MI_CSFdci_Enable) as defined in G.8021.

                     range of type : true, false";

             }

-            container traffic-shaping {

-                uses traffic-shaping-pac;

-                description "none";

-            }

-            container traffic-conditioning {

-                uses traffic-conditioning-pac;

-                description "none";

-            }

+            uses tapi-eth:traffic-shaping-pac;

+            uses tapi-eth:traffic-conditioning-pac;

             description "none";

         }

-        grouping connection-end-point-lp-spec {

-            container termination-spec {

-                uses eth-termination-pac;

-                description "none";

-            }

-            container adapter-spec {

-                uses connection-point-and-adapter-pac;

-                description "none";

-            }

+        grouping eth-connection-end-point-spec {

+            uses tapi-eth:eth-termination-pac;

+            uses tapi-eth:eth-ctp-pac;

             description "none";

         }

         grouping eth-termination-pac {

@@ -173,7 +161,7 @@
                 type vlan-type;

                 description "This attribute models the ETHx/ETH-m _A_Sk_MI_Etype information defined in G.8021.";

             }

-            leaf-list filter-config {

+            leaf-list filter-config-1 {

                 type mac-address;

                 description "This attribute models the ETHx/ETH-m_A_Sk_MI_Filter_Config information defined in G.8021.

                     It indicates the configured filter action for each of the 33 group MAC addresses for control frames.

@@ -232,7 +220,7 @@
             description "none";

         }

         grouping traffic-conditioning-pac {

-            list prio-config-list {

+            list prio-config-list-1 {

                 config false;

                 uses priority-configuration;

                 description "This attribute indicates the Priority Splitter function for the mapping of the Ethernet frame priority (ETH_CI_P) values to the output queue.";

@@ -249,7 +237,7 @@
                     - Coupling flag (CF): 0 or 1

                     - Color mode (CM): color-blind and color-aware.";

             }

-            leaf codirectional {

+            leaf codirectional-1 {

                 type boolean;

                 config false;

                 description "This attribute indicates the direction of the conditioner. The value of true means that the conditioner (modeled as a TCS Sink according to G.8021) is associated with the sink part of the containing CTP. The value of false means that the conditioner (modeled as a TCS Sink according to G.8021) is associated with the source part of the containing CTP.";

@@ -283,11 +271,8 @@
             description "This object class models the ETH traffic shaping function as defined in G.8021.

                 Basic attribute: codirectional, prioConfigList, queueConfigList, schedConfig";

         }

-        grouping node-edge-point-lp-spec {

-            container termination-spec {

-                uses ety-termination-pac;

-                description "none";

-            }

+        grouping eth-node-edge-point-spec {

+            uses tapi-eth:ety-termination-pac;

             description "none";

         }

 

@@ -600,10 +585,10 @@
         }

         typedef admin-state {

             type enumeration {

-                enum lock {

+                enum LOCK {

                     description "none";

                 }

-                enum normal {

+                enum NORMAL {

                     description "none";

                 }

             }

@@ -611,10 +596,10 @@
         }

         typedef colour-mode {

             type enumeration {

-                enum colour-blind {

+                enum COLOUR_BLIND {

                     description "none";

                 }

-                enum colour-aware {

+                enum COLOUR_AWARE {

                     description "none";

                 }

             }

@@ -622,31 +607,31 @@
         }

         typedef csf-config {

             type enumeration {

-                enum disabled {

+                enum DISABLED {

                     description "This literal covers the following states of the CSF related MI informations:

                         - MI_CSF_Enable is false

                         - MI_CSFrdifdi_Enable is false

                         - MI_CSFdci_Enable is false.";

                 }

-                enum enabled {

+                enum ENABLED {

                     description "This literal covers the following states of the CSF related MI informations:

                         - MI_CSF_Enable is true

                         - MI_CSFrdifdi_Enable is false

                         - MI_CSFdci_Enable is false.";

                 }

-                enum enabled-with-rdi-fdi {

+                enum ENABLED_WITH_RDI_FDI {

                     description "This literal covers the following states of the CSF related MI informations:

                         - MI_CSF_Enable is true

                         - MI_CSFrdifdi_Enable is true

                         - MI_CSFdci_Enable is false.";

                 }

-                enum enabled-with-rdi-fdi-dci {

+                enum ENABLED_WITH_RDI_FDI_DCI {

                     description "This literal covers the following states of the CSF related MI informations:

                         - MI_CSF_Enable is true

                         - MI_CSFrdifdi_Enable is true

                         - MI_CSFdci_Enable is true.";

                 }

-                enum enabled-with-dci {

+                enum ENABLED_WITH_DCI {

                     description "This literal covers the following states of the CSF related MI informations:

                         - MI_CSF_Enable is true

                         - MI_CSFrdifdi_Enable is false

@@ -657,46 +642,46 @@
         }

         typedef ety-phy-type {

             type enumeration {

-                enum other {

+                enum OTHER {

                     description "none";

                 }

-                enum unknown {

+                enum UNKNOWN {

                     description "none";

                 }

-                enum none {

+                enum NONE {

                     description "none";

                 }

-                enum 2-base-tl {

+                enum 2BASE_TL {

                     description "none";

                 }

-                enum 10-mbit-s {

+                enum 10MBIT_S {

                     description "none";

                 }

-                enum 10-pass-ts {

+                enum 10PASS_TS {

                     description "none";

                 }

-                enum 100-base-t-4 {

+                enum 100BASE_T4 {

                     description "none";

                 }

-                enum 100-base-x {

+                enum 100BASE_X {

                     description "none";

                 }

-                enum 100-base-t-2 {

+                enum 100BASE_T2 {

                     description "none";

                 }

-                enum 1000-base-x {

+                enum 1000BASE_X {

                     description "none";

                 }

-                enum 1000-base-t {

+                enum 1000BASE_T {

                     description "none";

                 }

-                enum 10-gbase-x {

+                enum 10GBASE-X {

                     description "none";

                 }

-                enum 10-gbase-r {

+                enum 10GBASE_R {

                     description "none";

                 }

-                enum 10-gbase-w {

+                enum 10GBASE_W {

                     description "none";

                 }

             }

@@ -704,13 +689,13 @@
         }

         typedef frame-type {

             type enumeration {

-                enum admit-only-vlan-tagged-frames {

+                enum ADMIT_ONLY_VLAN_TAGGED_FRAMES {

                     description "none";

                 }

-                enum admit-only-untagged-and-priority-tagged-frames {

+                enum ADMIT_ONLY_UNTAGGED_AND_PRIORITY_TAGGED_FRAMES {

                     description "none";

                 }

-                enum admit-all-frames {

+                enum ADMIT_ALL_FRAMES {

                     description "none";

                 }

             }

@@ -718,25 +703,25 @@
         }

         typedef oam-period {

             type enumeration {

-                enum 3-33-ms {

+                enum 3_33MS {

                     description "Default for protection.";

                 }

-                enum 10-ms {

+                enum 10MS {

                     description "none";

                 }

-                enum 100-ms {

+                enum 100MS {

                     description "none";

                 }

-                enum 1-s {

+                enum 1S {

                     description "none";

                 }

-                enum 10-s {

+                enum 10S {

                     description "none";

                 }

-                enum 1-min {

+                enum 1MIN {

                     description "none";

                 }

-                enum 10-min {

+                enum 10MIN {

                     description "none";

                 }

             }

@@ -744,19 +729,19 @@
         }

         typedef pcp-coding {

             type enumeration {

-                enum 8-p-0-d {

+                enum 8P0D {

                     description "none";

                 }

-                enum 7-p-1-d {

+                enum 7P1D {

                     description "none";

                 }

-                enum 6-p-2-d {

+                enum 6P2D {

                     description "none";

                 }

-                enum 5-p-3-d {

+                enum 5P3D {

                     description "none";

                 }

-                enum dei {

+                enum DEI {

                     description "This enumeration value means that all priorities should be drop eligible.

                         DEI = Drop Eligibility Indicator";

                 }

@@ -765,13 +750,13 @@
         }

         typedef vlan-type {

             type enumeration {

-                enum c-tag {

+                enum C_Tag {

                     description "0x8100";

                 }

-                enum s-tag {

+                enum S_Tag {

                     description "0x88a8";

                 }

-                enum i-tag {

+                enum I_Tag {

                     description "88-e7";

                 }

             }

diff --git a/models/tapi/src/main/yang/tapi-notification@2017-05-31.yang b/models/tapi/src/main/yang/tapi-notification@2017-05-31.yang
index 1ca3f52..2b4e526 100644
--- a/models/tapi/src/main/yang/tapi-notification@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-notification@2017-05-31.yang
@@ -245,71 +245,71 @@
         }

         typedef notification-type {

             type enumeration {

-                enum object-creation {

+                enum OBJECT_CREATION {

                     description "Not a normal state. The system is unable to determine the correct value.";

                 }

-                enum object-deletion {

+                enum OBJECT_DELETION {

                     description "none";

                 }

-                enum attribute-value-change {

+                enum ATTRIBUTE_VALUE_CHANGE {

                     description "none";

                 }

-                enum alarm-event {

+                enum ALARM_EVENT {

                     description "none";

                 }

-                enum threshold-crossing-alert {

+                enum THRESHOLD_CROSSING_ALERT {

                     description "none";

                 }

             }

-            description "The orientation of flow at the Port of a Forwarding entity";

+            description "List of supported Notifications types.";

         }

         typedef object-type {

             type enumeration {

-                enum topology {

+                enum TOPOLOGY {

                     description "none";

                 }

-                enum node {

+                enum NODE {

                     description "none";

                 }

-                enum link {

+                enum LINK {

                     description "none";

                 }

-                enum connection {

+                enum CONNECTION {

                     description "none";

                 }

-                enum path {

+                enum PATH {

                     description "none";

                 }

-                enum connectivity-service {

+                enum CONNECTIVITY_SERVICE {

                     description "none";

                 }

-                enum virtual-network-service {

+                enum VIRTUAL_NETWORK_SERVICE {

                     description "none";

                 }

-                enum path-computation-service {

+                enum PATH_COMPUTATION_SERVICE {

                     description "none";

                 }

-                enum node-edge-point {

+                enum NODE_EDGE_POINT {

                     description "none";

                 }

-                enum service-interface-point {

+                enum SERVICE_INTERFACE_POINT {

                     description "none";

                 }

-                enum connection-end-point {

+                enum CONNECTION_END_POINT {

                     description "none";

                 }

             }

-            description "The orientation of flow at the Port of a Forwarding entity";

+            description "The list of TAPI Global Object Class types on which Notifications can be raised.";

         }

         typedef source-indicator {

             type enumeration {

-                enum resource-operation {

+                enum RESOURCE_OPERATION {

                     description "none";

                 }

-                enum management-operation {

+                enum MANAGEMENT_OPERATION {

                     description "none";

                 }

-                enum unknown {

+                enum UNKNOWN {

                     description "none";

                 }

             }

@@ -317,10 +317,10 @@
         }

         typedef subscription-state {

             type enumeration {

-                enum suspended {

+                enum SUSPENDED {

                     description "none";

                 }

-                enum active {

+                enum ACTIVE {

                     description "none";

                 }

             }

@@ -328,19 +328,19 @@
         }

         typedef perceived-serverity-type {

             type enumeration {

-                enum critical {

+                enum CRITICAL {

                     description "none";

                 }

-                enum major {

+                enum MAJOR {

                     description "none";

                 }

-                enum minor {

+                enum MINOR {

                     description "none";

                 }

-                enum warning {

+                enum WARNING {

                     description "none";

                 }

-                enum cleared {

+                enum CLEARED {

                     description "none";

                 }

             }

@@ -348,13 +348,13 @@
         }

         typedef threshold-crossing-type {

             type enumeration {

-                enum threshold-above {

+                enum THRESHOLD_ABOVE {

                     description "none";

                 }

-                enum threshold-below {

+                enum THRESHOLD_BELOW {

                     description "none";

                 }

-                enum cleared {

+                enum CLEARED {

                     description "none";

                 }

             }

@@ -362,13 +362,13 @@
         }

         typedef service-affecting {

             type enumeration {

-                enum service-affecting {

+                enum SERVICE_AFFECTING {

                     description "none";

                 }

-                enum not-service-affecting {

+                enum NOT_SERVICE_AFFECTING {

                     description "none";

                 }

-                enum unknown {

+                enum UNKNOWN {

                     description "none";

                 }

             }

diff --git a/models/tapi/src/main/yang/tapi-oam@2017-05-31.yang b/models/tapi/src/main/yang/tapi-oam@2017-05-31.yang
index da16273..506eec9 100644
--- a/models/tapi/src/main/yang/tapi-oam@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-oam@2017-05-31.yang
@@ -80,19 +80,13 @@
             description "none";

         }

         grouping on-demand-measurement-job {

-            container state {

-                uses tapi-common:admin-state-pac;

-                description "none";

-            }

             uses tapi-common:local-class;

+            uses tapi-common:admin-state-pac;

             description "none";

         }

         grouping pro-active-measurement-job {

-            container state {

-                uses tapi-common:admin-state-pac;

-                description "none";

-            }

             uses tapi-common:local-class;

+            uses tapi-common:admin-state-pac;

             description "none";

         }

         grouping meg {

diff --git a/models/tapi/src/main/yang/tapi-odu@2017-05-31.yang b/models/tapi/src/main/yang/tapi-odu@2017-05-31.yang
index 2d5496b..00a5bc9 100644
--- a/models/tapi/src/main/yang/tapi-odu@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-odu@2017-05-31.yang
@@ -75,25 +75,10 @@
                 It is present only if the CEP contains a TTP";

         }

         grouping odu-connection-end-point-spec {

-            container odu-common {

-                uses odu-common-pac;

-                description "none";

-            }

-            container odu-term-and-adapter {

-                config false;

-                uses odu-termination-and-client-adaptation-pac;

-                description "none";

-            }

-            container odu-ctp {

-                config false;

-                uses odu-ctp-pac;

-                description "none";

-            }

-            container odu-protection {

-                config false;

-                uses odu-protection-pac;

-                description "none";

-            }

+            uses tapi-odu:odu-common-pac;

+            uses tapi-odu:odu-termination-and-client-adaptation-pac;

+            uses tapi-odu:odu-ctp-pac;

+            uses tapi-odu:odu-protection-pac;

             description "none";

         }

         grouping odu-pool-pac {

@@ -114,11 +99,7 @@
             description "none";

         }

         grouping odu-node-edge-point-spec {

-            container odu-pool {

-                config false;

-                uses odu-pool-pac;

-                description "none";

-            }

+            uses tapi-odu:odu-pool-pac;

             description "none";

         }

         grouping odu-ctp-pac {

@@ -151,28 +132,11 @@
                 It is present only if the CEP contains a CTP";

         }

         grouping odu-mep-spec {

-            container odu-mep {

-                uses odu-mep-pac;

-                description "none";

-            }

-            container odu-ncm {

-                config false;

-                uses odu-ncm-pac;

-                description "none";

-            }

-            container odu-tcm {

-                config false;

-                uses odu-tcm-mep-pac;

-                description "none";

-            }

-            container odu-defect {

-                uses odu-defect-pac;

-                description "none";

-            }

-            container odu-pm {

-                uses odu-pm-pac;

-                description "none";

-            }

+            uses tapi-odu:odu-mep-pac;

+            uses tapi-odu:odu-ncm-pac;

+            uses tapi-odu:odu-tcm-mep-pac;

+            uses tapi-odu:odu-defect-pac;

+            uses tapi-odu:odu-pm-pac;

             description "none";

         }

         grouping odu-protection-pac {

@@ -231,29 +195,11 @@
             description "none";

         }

         grouping odu-mip-spec {

-            container odu-mip {

-                config false;

-                uses odu-mip-pac;

-                description "none";

-            }

-            container odu-ncm {

-                config false;

-                uses odu-ncm-pac;

-                description "none";

-            }

-            container odu-tcm {

-                config false;

-                uses odu-tcm-mip-pac;

-                description "none";

-            }

-            container odu-pm {

-                uses odu-pm-pac;

-                description "none";

-            }

-            container odu-defect {

-                uses odu-defect-pac;

-                description "none";

-            }

+            uses tapi-odu:odu-mip-pac;

+            uses tapi-odu:odu-ncm-pac;

+            uses tapi-odu:odu-tcm-mip-pac;

+            uses tapi-odu:odu-pm-pac;

+            uses tapi-odu:odu-defect-pac;

             description "none";

         }

         grouping odu-mip-pac {

@@ -403,136 +349,30 @@
     /***********************

     * package type-definitions

     **********************/ 

-        identity deg-thr-type {

-            description "none";

-        }

-        identity percentage {

-            base deg-thr-type;

-            description "Choice of % or Number of errored blocks";

-        }

-        identity number-errored-blocks {

-            base deg-thr-type;

-            description "Number of % or blocks";

-        }

-        identity tcm-status {

-            description "none";

-        }

-        identity no-source-tc {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 0 0 0, No source Tandem Connection";

-        }

-        identity in-use-without-iae {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 0 0 1,  In use without IAE (Incoming Alignment Error)";

-        }

-        identity in-use-with-iae {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 0 1 0, In use with IAE (Incoming Alignment Error)";

-        }

-        identity reserved-1 {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 0 1 1, Reserved for future international standardization";

-        }

-        identity reserved-2 {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 1 0 0, Reserved for future international standardization";

-        }

-        identity lck {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 1 0 1, Maintenance signal: ODU-LCK";

-        }

-        identity oci {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 1 1 0, Maintenance signal: ODU-OCI";

-        }

-        identity ais {

-            base tcm-status;

-            description "TCM byte 3 (bits 6 7 8) -- 1 1 1, Maintenance signal: ODU-AIS";

-        }

-        identity tcm-mode {

-            description "none";

-        }

-        identity operational {

-            base tcm-mode;

-            description "none";

-        }

-        identity transparent {

-            base tcm-mode;

-            description "none";

-        }

-        identity monitor {

-            base tcm-mode;

-            description "none";

-        }

-        identity tcm-monitoring {

-            description "none";

-        }

-        identity intrusive {

-            base tcm-monitoring;

-            description "none";

-        }

-        identity non-intrusive {

-            base tcm-monitoring;

-            description "none";

-        }

-        identity tcm-extension {

-            description "none";

-        }

-        identity normal {

-            base tcm-extension;

-            description "none";

-        }

-        identity pass-through {

-            base tcm-extension;

-            description "none";

-        }

-        identity erase {

-            base tcm-extension;

-            description "none";

-        }

-        identity percentage-granularity {

-            description "none";

-        }

-        identity ones {

-            base percentage-granularity;

-            description "none";

-        }

-        identity one-tenths {

-            base percentage-granularity;

-            description "value * (1/10)";

-        }

-        identity one-hundredths {

-            base percentage-granularity;

-            description "value * (1/100)";

-        }

-        identity one-thousandths {

-            base percentage-granularity;

-            description "value * (1/1000)";

-        }

         typedef odu-type {

             type enumeration {

-                enum odu-0 {

+                enum ODU0 {

                     description "none";

                 }

-                enum odu-1 {

+                enum ODU1 {

                     description "none";

                 }

-                enum odu-2 {

+                enum ODU2 {

                     description "none";

                 }

-                enum odu-2-e {

+                enum ODU2E {

                     description "none";

                 }

-                enum odu-3 {

+                enum ODU3 {

                     description "none";

                 }

-                enum odu-4 {

+                enum ODU4 {

                     description "none";

                 }

-                enum odu-flex {

+                enum ODU_FLEX {

                     description "none";

                 }

-                enum odu-cn {

+                enum ODU_CN {

                     description "none";

                 }

             }

@@ -540,22 +380,22 @@
         }

         typedef mapping-type {

             type enumeration {

-                enum amp {

+                enum AMP {

                     description "none";

                 }

-                enum bmp {

+                enum BMP {

                     description "none";

                 }

-                enum gfp-f {

+                enum GFP-F {

                     description "none";

                 }

-                enum gmp {

+                enum GMP {

                     description "none";

                 }

-                enum ttp-gfp-bmp {

+                enum TTP_GFP_BMP {

                     description "none";

                 }

-                enum null {

+                enum NULL {

                     description "none";

                 }

             }

@@ -563,16 +403,16 @@
         }

         typedef tim-det-mo {

             type enumeration {

-                enum dapi {

+                enum DAPI {

                     description "none";

                 }

-                enum sapi {

+                enum SAPI {

                     description "none";

                 }

-                enum both {

+                enum BOTH {

                     description "none";

                 }

-                enum off {

+                enum OFF {

                     description "none";

                 }

             }

@@ -580,10 +420,10 @@
         }

         typedef odu-slot-size {

             type enumeration {

-                enum 1-g-25 {

+                enum 1G25 {

                     description "none";

                 }

-                enum 2-g-5 {

+                enum 2G5 {

                     description "none";

                 }

             }

@@ -602,10 +442,10 @@
         }

         typedef odu-named-payload-type {

             type enumeration {

-                enum unknown {

+                enum UNKNOWN {

                     description "none";

                 }

-                enum uninterpretable {

+                enum UNINTERPRETABLE {

                     description "none";

                 }

             }

@@ -633,38 +473,98 @@
                 Number of Errored Blocks is captured in an integer value.";

         }

         typedef deg-thr-type {

-            type identityref {

-                base deg-thr-type;

+            type enumeration {

+                enum PERCENTAGE {

+                    description "Choice of % or Number of errored blocks";

+                }

+                enum NUMBER_ERRORED_BLOCKS {

+                    description "Number of % or blocks";

+                }

             }

             description "The value of the threshold can be provisioned in terms of number of errored blocks or in terms of percentage of errored blocks. For percentage-based specification, in order to support provision of less than 1%, the specification consists of two fields. The first field indicates the granularity of percentage. For examples, in 1%, in 0.1%, or in 0.01%, etc. The second field indicates the multiple of the granularity. For number of errored block based, the value is a positive integer.";

         }

         typedef tcm-status {

-            type identityref {

-                base tcm-status;

+            type enumeration {

+                enum NO_SOURCE_TC {

+                    description "TCM byte 3 (bits 6 7 8) -- 0 0 0, No source Tandem Connection";

+                }

+                enum IN_USE_WITHOUT_IAE {

+                    description "TCM byte 3 (bits 6 7 8) -- 0 0 1,  In use without IAE (Incoming Alignment Error)";

+                }

+                enum IN_USE_WITH_IAE {

+                    description "TCM byte 3 (bits 6 7 8) -- 0 1 0, In use with IAE (Incoming Alignment Error)";

+                }

+                enum RESERVED_1 {

+                    description "TCM byte 3 (bits 6 7 8) -- 0 1 1, Reserved for future international standardization";

+                }

+                enum RESERVED_2 {

+                    description "TCM byte 3 (bits 6 7 8) -- 1 0 0, Reserved for future international standardization";

+                }

+                enum LCK {

+                    description "TCM byte 3 (bits 6 7 8) -- 1 0 1, Maintenance signal: ODU-LCK";

+                }

+                enum OCI {

+                    description "TCM byte 3 (bits 6 7 8) -- 1 1 0, Maintenance signal: ODU-OCI";

+                }

+                enum AIS {

+                    description "TCM byte 3 (bits 6 7 8) -- 1 1 1, Maintenance signal: ODU-AIS";

+                }

             }

             description "See Table 15-5/G.709/Y.1331 ";

         }

         typedef tcm-mode {

-            type identityref {

-                base tcm-mode;

+            type enumeration {

+                enum OPERATIONAL {

+                    description "none";

+                }

+                enum TRANSPARENT {

+                    description "none";

+                }

+                enum MONITOR {

+                    description "none";

+                }

             }

             description "List of value modes for the sink side of the tandem connection monitoring function.";

         }

         typedef tcm-monitoring {

-            type identityref {

-                base tcm-monitoring;

+            type enumeration {

+                enum INTRUSIVE {

+                    description "none";

+                }

+                enum NON-INTRUSIVE {

+                    description "none";

+                }

             }

             description "Monitoring types for the tandem connection monitoring function.";

         }

         typedef tcm-extension {

-            type identityref {

-                base tcm-extension;

+            type enumeration {

+                enum NORMAL {

+                    description "none";

+                }

+                enum PASS-THROUGH {

+                    description "none";

+                }

+                enum ERASE {

+                    description "none";

+                }

             }

             description "none";

         }

         typedef percentage-granularity {

-            type identityref {

-                base percentage-granularity;

+            type enumeration {

+                enum ONES {

+                    description "none";

+                }

+                enum ONE_TENTHS {

+                    description "value * (1/10)";

+                }

+                enum ONE_HUNDREDTHS {

+                    description "value * (1/100)";

+                }

+                enum ONE_THOUSANDTHS {

+                    description "value * (1/1000)";

+                }

             }

             description "none";

         }

diff --git a/models/tapi/src/main/yang/tapi-otsi@2017-05-31.yang b/models/tapi/src/main/yang/tapi-otsi@2017-05-31.yang
index 13c95c8..861daff 100644
--- a/models/tapi/src/main/yang/tapi-otsi@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-otsi@2017-05-31.yang
@@ -36,45 +36,35 @@
             description "none";

         }

         grouping otsi-connection-end-point-spec {

-            container otsi-adapter {

-                config false;

-                uses otsi-a-client-adaptation-pac;

-                description "none";

-            }

-            list otsi-termination {

-                config false;

-                uses otsi-termination-pac;

-                description "none";

-            }

-            container otsi-ctp {

-                config false;

-                uses otsi-g-ctp-pac;

-                description "none";

-            }

+            uses tapi-otsi:otsi-a-client-adaptation-pac;

+            uses tapi-otsi:otsi-termination-pac;

+            uses tapi-otsi:otsi-g-ctp-pac;

             description "none";

         }

         grouping otsi-termination-pac {

-            container selected-nominal-central-frequency {

+            list selected-nominal-central-frequency {

+                config false;

                 uses nominal-central-frequency-or-wavelength;

                 description "This attribute indicates the nominal central frequency or wavelength of the optical channel associated with the OCh Trail Termination function. The value of this attribute is a pair {LinkType, Integer}, in which LinkType is DWDM, or CWDM, or NO_WDM. When LinkType is DWDM, the integer represents the nominal central frequency in unit of MHz. When LinkType is CWDM, the integer represents the nominal central wavelength in unit of pm (picometer). When LinkType is NO_WDM, the Integer field is null. For frequency and wavelength, the value shall be within the range of the maximum and minimum central frequencies or wavelengths specified for the corresponding application code used at the OCh Trail Termination.

                     This attribute is required for the OCh Trial Termination Point Source at the transmitter.  For the OCh Trail Termination Point Sink at the receiver, this attribute may not be needed since the receiver is required to operate at any frequency/wavelength between the maximum and minimum range for the standard application code.

                     ";

             }

-            container supportable-lower-nominal-central-frequency {

+            list supportable-lower-nominal-central-frequency {

                 config false;

                 uses nominal-central-frequency-or-wavelength;

                 description "none";

             }

-            container supportable-upper-nominal-central-frequency {

+            list supportable-upper-nominal-central-frequency {

                 config false;

                 uses nominal-central-frequency-or-wavelength;

                 description "none";

             }

-            container selected-application-identifier {

+            list selected-application-identifier {

+                config false;

                 uses application-identifier;

                 description "This attribute indicates the selected Application Identifier that is used by the OCh trail termination function. The syntax of ApplicationIdentifier is a pair {ApplicationIdentifierType, PrintableString}. The value of ApplicationIdentifierType is either STANDARD or PROPRIETARY. The value of PrintableString represents the standard application code as defined in the ITU-T Recommendations or a vendor-specific proprietary code. If the ApplicationIdentifierType is STANDARD the value of PrintableString represents a standard application code as defined in the ITU-T Recommendations. If the ApplicationIdentifierType is PROPRIETARY, the first six characters of the PrintableString must contain the Hexadecimal representation of an OUI assigned to the vendor whose implementation generated the Application Identifier; the remaining octets of the PrintableString are unspecified. The value of this attribute of an object instance has to be one of the values identified in the attribute SupportableApplicationIdentifierList of the same object instance. The values and value ranges of the optical interface parameters of a standard application code must be consistent with those values specified in the ITU-T Recommendation for that application code.";

             }

-            container supportable-application-identifier {

+            list supportable-application-identifier {

                 config false;

                 uses application-identifier;

                 description "none";

@@ -95,11 +85,7 @@
             description "none";

         }

         grouping otsi-node-edge-point-spec {

-            container otsi-pool {

-                config false;

-                uses otsi-a-pool-pac;

-                description "none";

-            }

+            uses tapi-otsi:otsi-a-pool-pac;

             description "none";

         }

         grouping otsi-routing-spec {

@@ -111,6 +97,7 @@
         }

         grouping otsi-g-ctp-pac {

             list selected-frequency-slot {

+                config false;

                 uses frequency-slot;

                 description "none";

             }

@@ -123,81 +110,6 @@
     /***********************

     * package type-definitions

     **********************/ 

-        identity application-identifier-type {

-            description "none";

-        }

-        identity proprietary {

-            base application-identifier-type;

-            description "none";

-        }

-        identity itut-g-959-1 {

-            base application-identifier-type;

-            description "none";

-        }

-        identity itut-g-698-1 {

-            base application-identifier-type;

-            description "none";

-        }

-        identity itut-g-698-2 {

-            base application-identifier-type;

-            description "none";

-        }

-        identity itut-g-696-1 {

-            base application-identifier-type;

-            description "none";

-        }

-        identity itut-g-695 {

-            base application-identifier-type;

-            description "none";

-        }

-        identity grid-type {

-            description "none";

-        }

-        identity dwdm {

-            base grid-type;

-            description "Fixed frequency grid in C & L bands as specified in ITU-T G.694.1

-                ";

-        }

-        identity cwdm {

-            base grid-type;

-            description "Fixed frequency grid as specified in ITU-T G.694.2";

-        }

-        identity flex {

-            base grid-type;

-            description "Flexible frequency grid as specified in ITU-T G.694.1. In this case,

-                - the allowed frequency slots have a nominal central frequency (in THz) defined by:

-                193.1 + n × 0.00625 where n is a positive or negative integer including 0 and 0.00625 is the nominal central frequency granularity in THz

-                - and a slot width defined by:

-                12.5 × m where m is a positive integer and 12.5 is the slot width granularity in GHz.

-                Any combination of frequency slots is allowed as long as no two frequency slots overlap.";

-        }

-        identity unspecified {

-            base grid-type;

-            description "Unspecified/proprietary frequency grid";

-        }

-        identity adjustment-granularity {

-            description "none";

-        }

-        identity g-100-ghz {

-            base adjustment-granularity;

-            description "0.1 THz";

-        }

-        identity g-50-ghz {

-            base adjustment-granularity;

-            description "0.05 THz";

-        }

-        identity g-25-ghz {

-            base adjustment-granularity;

-            description "0.025 THz";

-        }

-        identity g-12-5-ghz {

-            base adjustment-granularity;

-            description "0.0125 THz";

-        }

-        identity g-6-25-ghz {

-            base adjustment-granularity;

-            description "0.00625 THz";

-        }

         grouping application-identifier {

             leaf application-identifier-type {

                 type application-identifier-type;

@@ -231,39 +143,87 @@
         }

         typedef optical-routing-strategy {

             type enumeration {

-                enum optimal-osnr {

+                enum OPTIMAL_OSNR {

                     description "none";

                 }

-                enum no-relay {

+                enum NO_RELAY {

                     description "none";

                 }

-                enum min-relay {

+                enum MIN_RELAY {

                     description "none";

                 }

-                enum preferred-no-change-wavelength-as-restore {

+                enum PREFERRED_NO_CHANGE_WAVELENGTH_AS_RESTORE {

                     description "none";

                 }

-                enum preferred-no-skipping-wavelength {

+                enum PREFERRED_NO_SKIPPING_WAVELENGTH {

                     description "none";

                 }

             }

             description "none";

         }

         typedef application-identifier-type {

-            type identityref {

-                base application-identifier-type;

+            type enumeration {

+                enum PROPRIETARY {

+                    description "none";

+                }

+                enum ITUT_G959_1 {

+                    description "none";

+                }

+                enum ITUT_G698_1 {

+                    description "none";

+                }

+                enum ITUT_G698_2 {

+                    description "none";

+                }

+                enum ITUT_G696_1 {

+                    description "none";

+                }

+                enum ITUT_G695 {

+                    description "none";

+                }

             }

             description "none";

         }

         typedef grid-type {

-            type identityref {

-                base grid-type;

+            type enumeration {

+                enum DWDM {

+                    description "Fixed frequency grid in C & L bands as specified in ITU-T G.694.1

+                        ";

+                }

+                enum CWDM {

+                    description "Fixed frequency grid as specified in ITU-T G.694.2";

+                }

+                enum FLEX {

+                    description "Flexible frequency grid as specified in ITU-T G.694.1. In this case,

+                        - the allowed frequency slots have a nominal central frequency (in THz) defined by:

+                        193.1 + n × 0.00625 where n is a positive or negative integer including 0 and 0.00625 is the nominal central frequency granularity in THz

+                        - and a slot width defined by:

+                        12.5 × m where m is a positive integer and 12.5 is the slot width granularity in GHz.

+                        Any combination of frequency slots is allowed as long as no two frequency slots overlap.";

+                }

+                enum UNSPECIFIED {

+                    description "Unspecified/proprietary frequency grid";

+                }

             }

             description "The frequency grid standard that specify reference set of frequencies used to denote allowed nominal central frequencies that may be used for defining applications.";

         }

         typedef adjustment-granularity {

-            type identityref {

-                base adjustment-granularity;

+            type enumeration {

+                enum G_100GHZ {

+                    description "0.1 THz";

+                }

+                enum G_50GHZ {

+                    description "0.05 THz";

+                }

+                enum G_25GHZ {

+                    description "0.025 THz";

+                }

+                enum G_12_5GHZ {

+                    description "0.0125 THz";

+                }

+                enum G_6_25GHZ {

+                    description "0.00625 THz";

+                }

             }

             description "Adjustment granularity in Gigahertz. As per ITU-T G.694.1, it is used to calculate nominal central frequency (in THz)";

         }

diff --git a/models/tapi/src/main/yang/tapi-topology@2017-05-31.yang b/models/tapi/src/main/yang/tapi-topology@2017-05-31.yang
index a5b6c3e..5134883 100644
--- a/models/tapi/src/main/yang/tapi-topology@2017-05-31.yang
+++ b/models/tapi/src/main/yang/tapi-topology@2017-05-31.yang
@@ -31,54 +31,6 @@
                 min-elements 2;

                 description "none";

             }

-            leaf-list node {

-                type leafref {

-                    path '/tapi-common:context/tapi-topology:topology/tapi-topology:node/tapi-topology:uuid';

-                }

-                config false;

-                min-elements 2;

-                description "none";

-            }

-            container state {

-                config false;

-                uses tapi-common:admin-state-pac;

-                description "none";

-            }

-            container transfer-capacity {

-                config false;

-                uses tapi-common:capacity-pac;

-                description "none";

-            }

-            container transfer-cost {

-                config false;

-                uses transfer-cost-pac;

-                description "none";

-            }

-            container transfer-integrity {

-                config false;

-                uses transfer-integrity-pac;

-                description "none";

-            }

-            container transfer-timing {

-                config false;

-                uses transfer-timing-pac;

-                description "none";

-            }

-            container risk-parameter {

-                config false;

-                uses risk-parameter-pac;

-                description "none";

-            }

-            container validation {

-                config false;

-                uses validation-pac;

-                description "none";

-            }

-            container lp-transition {

-                config false;

-                uses layer-protocol-transition-pac;

-                description "none";

-            }

             leaf-list layer-protocol-name {

                 type tapi-common:layer-protocol-name;

                 config false;

@@ -97,6 +49,14 @@
                 description "none";

             }

             uses tapi-common:resource-spec;

+            uses tapi-common:admin-state-pac;

+            uses tapi-common:capacity-pac;

+            uses tapi-topology:transfer-cost-pac;

+            uses tapi-topology:transfer-integrity-pac;

+            uses tapi-topology:transfer-timing-pac;

+            uses tapi-topology:risk-parameter-pac;

+            uses tapi-topology:validation-pac;

+            uses tapi-topology:layer-protocol-transition-pac;

             description "The Link object class models effective adjacency between two or more ForwardingDomains (FD). ";

         }

         grouping node {

@@ -125,31 +85,6 @@
                 config false;

                 description "none";

             }

-            container state {

-                config false;

-                uses tapi-common:admin-state-pac;

-                description "none";

-            }

-            container transfer-capacity {

-                config false;

-                uses tapi-common:capacity-pac;

-                description "none";

-            }

-            container transfer-cost {

-                config false;

-                uses transfer-cost-pac;

-                description "none";

-            }

-            container transfer-integrity {

-                config false;

-                uses transfer-integrity-pac;

-                description "none";

-            }

-            container transfer-timing {

-                config false;

-                uses transfer-timing-pac;

-                description "none";

-            }

             leaf-list layer-protocol-name {

                 type tapi-common:layer-protocol-name;

                 config false;

@@ -157,6 +92,11 @@
                 description "none";

             }

             uses tapi-common:resource-spec;

+            uses tapi-common:admin-state-pac;

+            uses tapi-common:capacity-pac;

+            uses tapi-topology:transfer-cost-pac;

+            uses tapi-topology:transfer-integrity-pac;

+            uses tapi-topology:transfer-timing-pac;

             description "The ForwardingDomain (FD) object class models the “ForwardingDomain” topological component which is used to effect forwarding of transport characteristic information and offers the potential to enable forwarding. 

                 At the lowest level of recursion, an FD (within a network element (NE)) represents a switch matrix (i.e., a fabric). Note that an NE can encompass multiple switch matrices (FDs). ";

         }

@@ -196,11 +136,9 @@
                 Links that included details in this Pac are often referred to as Transitional Links.";

         }

         grouping node-edge-point {

-            list layer-protocol {

-                key 'local-id';

+            leaf layer-protocol-name {

+                type tapi-common:layer-protocol-name;

                 config false;

-                min-elements 1;

-                uses tapi-common:layer-protocol;

                 description "none";

             }

             leaf-list aggregated-node-edge-point {

@@ -216,11 +154,6 @@
                 }

                 description "NodeEdgePoint mapped to more than ServiceInterfacePoint (slicing/virtualizing) or a ServiceInterfacePoint mapped to more than one NodeEdgePoint (load balancing/Resilience) should be considered experimental";

             }

-            container state {

-                config false;

-                uses tapi-common:admin-state-pac;

-                description "none";

-            }

             leaf link-port-direction {

                 type tapi-common:port-direction;

                 config false;

@@ -232,6 +165,8 @@
                 description "Each LinkEnd of the Link has a role (e.g., symmetric, hub, spoke, leaf, root)  in the context of the Link with respect to the Link function. ";

             }

             uses tapi-common:resource-spec;

+            uses tapi-common:admin-state-pac;

+            uses tapi-common:termination-pac;

             description "The LogicalTerminationPoint (LTP) object class encapsulates the termination and adaptation functions of one or more transport layers. 

                 The structure of LTP supports all transport protocols including circuit and packet forms.";

         }

@@ -367,23 +302,11 @@
                 min-elements 2;

                 description "none";

             }

-            container transfer-capacity {

-                uses tapi-common:capacity-pac;

-                description "none";

-            }

-            container transfer-cost {

-                uses transfer-cost-pac;

-                description "none";

-            }

-            container transfer-timing {

-                uses transfer-timing-pac;

-                description "none";

-            }

-            container risk-parameter {

-                uses risk-parameter-pac;

-                description "none";

-            }

             uses tapi-common:resource-spec;

+            uses tapi-common:capacity-pac;

+            uses tapi-topology:transfer-cost-pac;

+            uses tapi-topology:transfer-timing-pac;

+            uses tapi-topology:risk-parameter-pac;

             description "none";

         }

         grouping node-rule-group {

@@ -411,23 +334,11 @@
                 uses inter-rule-group;

                 description "none";

             }

-            container transfer-capacity {

-                uses tapi-common:capacity-pac;

-                description "none";

-            }

-            container transfer-cost {

-                uses transfer-cost-pac;

-                description "none";

-            }

-            container transfer-timing {

-                uses transfer-timing-pac;

-                description "none";

-            }

-            container risk-parameter {

-                uses risk-parameter-pac;

-                description "none";

-            }

             uses tapi-common:resource-spec;

+            uses tapi-common:capacity-pac;

+            uses tapi-topology:transfer-cost-pac;

+            uses tapi-topology:transfer-timing-pac;

+            uses tapi-topology:risk-parameter-pac;

             description "none";

         }

         grouping rule {

@@ -524,16 +435,16 @@
         }

         typedef forwarding-rule {

             type enumeration {

-                enum may-forward-across-group {

+                enum MAY_FORWARD_ACROSS_GROUP {

                     description "none";

                 }

-                enum must-forward-across-group {

+                enum MUST_FORWARD_ACROSS_GROUP {

                     description "none";

                 }

-                enum cannot-forward-across-group {

+                enum CANNOT_FORWARD_ACROSS_GROUP {

                     description "none";

                 }

-                enum no-statement-on-forwarding {

+                enum NO_STATEMENT_ON_FORWARDING {

                     description "none";

                 }

             }

@@ -541,22 +452,22 @@
         }

         typedef rule-type {

             type enumeration {

-                enum forwarding {

+                enum FORWARDING {

                     description "none";

                 }

-                enum capacity {

+                enum CAPACITY {

                     description "none";

                 }

-                enum cost {

+                enum COST {

                     description "none";

                 }

-                enum timing {

+                enum TIMING {

                     description "none";

                 }

-                enum risk {

+                enum RISK {

                     description "none";

                 }

-                enum grouping {

+                enum GROUPING {

                     description "none";

                 }

             }

@@ -575,13 +486,13 @@
         }

         typedef restoration-policy {

             type enumeration {

-                enum per-domain-restoration {

+                enum PER_DOMAIN_RESTORATION {

                     description "none";

                 }

-                enum end-to-end-restoration {

+                enum END_TO_END_RESTORATION {

                     description "none";

                 }

-                enum na {

+                enum NA {

                     description "none";

                 }

             }

@@ -589,25 +500,25 @@
         }

         typedef protection-type {

             type enumeration {

-                enum no-protecton {

+                enum NO_PROTECTON {

                     description "none";

                 }

-                enum one-plus-one-protection {

+                enum ONE_PLUS_ONE_PROTECTION {

                     description "none";

                 }

-                enum one-plus-one-protection-with-dynamic-restoration {

+                enum ONE_PLUS_ONE_PROTECTION_WITH_DYNAMIC_RESTORATION {

                     description "none";

                 }

-                enum permanent-one-plus-one-protection {

+                enum PERMANENT_ONE_PLUS_ONE_PROTECTION {

                     description "none";

                 }

-                enum one-for-one-protection {

+                enum ONE_FOR_ONE_PROTECTION {

                     description "none";

                 }

-                enum dynamic-restoration {

+                enum DYNAMIC_RESTORATION {

                     description "none";

                 }

-                enum pre-computed-restoration {

+                enum PRE_COMPUTED_RESTORATION {

                     description "none";

                 }

             }

diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
index 030d2ff..4a62311 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
@@ -93,7 +93,7 @@
         try {
             return P4InfoParser.parse(p4InfoUrl);
         } catch (P4InfoParserException e) {
-            throw new RuntimeException(e);
+            throw new IllegalStateException(e);
         }
     }
 }
diff --git a/pipelines/fabric/src/main/resources/include/control/forwarding.p4 b/pipelines/fabric/src/main/resources/include/control/forwarding.p4
index de46115..f0bfd5c 100644
--- a/pipelines/fabric/src/main/resources/include/control/forwarding.p4
+++ b/pipelines/fabric/src/main/resources/include/control/forwarding.p4
@@ -30,7 +30,6 @@
     direct_counter(CounterType.packets_and_bytes) bridging_counter;
     direct_counter(CounterType.packets_and_bytes) mpls_counter;
     direct_counter(CounterType.packets_and_bytes) unicast_v4_counter;
-    direct_counter(CounterType.packets_and_bytes) multicast_v4_counter;
     direct_counter(CounterType.packets_and_bytes) acl_counter;
 
     action drop() {
@@ -84,6 +83,9 @@
         counters = unicast_v4_counter;
     }
 
+#ifdef WITH_MULTICAST
+    direct_counter(CounterType.packets_and_bytes) multicast_v4_counter;
+
     table multicast_v4 {
         key = {
             hdr.vlan_tag.vlan_id: exact;
@@ -95,10 +97,10 @@
         }
         counters = multicast_v4_counter;
     }
+#endif // WITH_MULTICAST
 
 #ifdef WITH_IPV6
     direct_counter(CounterType.packets_and_bytes) unicast_v6_counter;
-    direct_counter(CounterType.packets_and_bytes) multicast_v6_counter;
 
     table unicast_v6 {
         key = {
@@ -111,6 +113,9 @@
         counters = unicast_v6_counter;
     }
 
+#ifdef WITH_MULTICAST
+    direct_counter(CounterType.packets_and_bytes) multicast_v6_counter;
+
     table multicast_v6 {
         key = {
             hdr.vlan_tag.vlan_id: exact;
@@ -122,6 +127,7 @@
         }
         counters = multicast_v6_counter;
     }
+#endif // WITH_MULTICAST
 #endif // WITH_IPV6
 
     table acl {
@@ -163,10 +169,14 @@
             fabric_metadata.original_ether_type = ETHERTYPE_IPV4;
         }
         else if (fabric_metadata.fwd_type == FWD_IPV4_UNICAST) unicast_v4.apply();
+#ifdef WITH_MULTICAST
         else if (fabric_metadata.fwd_type == FWD_IPV4_MULTICAST) multicast_v4.apply();
+#endif // WITH_MULTICAST
 #ifdef WITH_IPV6
         else if (fabric_metadata.fwd_type == FWD_IPV6_UNICAST) unicast_v6.apply();
+#ifdef WITH_MULTICAST
         else if (fabric_metadata.fwd_type == FWD_IPV6_MULTICAST) multicast_v6.apply();
+#endif // WITH_MULTICAST
 #endif // WITH_IPV6
         acl.apply();
     }
diff --git a/pipelines/fabric/src/main/resources/include/control/next.p4 b/pipelines/fabric/src/main/resources/include/control/next.p4
index c76fc65..7d551dd 100644
--- a/pipelines/fabric/src/main/resources/include/control/next.p4
+++ b/pipelines/fabric/src/main/resources/include/control/next.p4
@@ -27,7 +27,6 @@
     action_selector(HashAlgorithm.crc16, 32w64, 32w16) ecmp_selector;
     direct_counter(CounterType.packets_and_bytes) simple_counter;
     direct_counter(CounterType.packets_and_bytes) hashed_counter;
-    direct_counter(CounterType.packets_and_bytes) broadcast_counter;
 
     action output(port_num_t port_num) {
         standard_metadata.egress_spec = port_num;
@@ -55,11 +54,6 @@
         output(port_num);
     }
 
-    action set_mcast_group(group_id_t gid, mac_addr_t smac) {
-        standard_metadata.mcast_grp = gid;
-        rewrite_smac(smac);
-    }
-
     action push_mpls (mpls_label_t label, bit<3> tc) {
         // Suppose that the maximum number of label is one.
         hdr.mpls.setValid();
@@ -120,18 +114,27 @@
         counters = hashed_counter;
     }
 
+#ifdef WITH_MULTICAST
     /*
      * Work in progress
      */
-    table broadcast {
+    action set_mcast_group(group_id_t gid, mac_addr_t smac) {
+        standard_metadata.mcast_grp = gid;
+        rewrite_smac(smac);
+    }
+
+    direct_counter(CounterType.packets_and_bytes) multicast_counter;
+
+    table multicast {
         key = {
             fabric_metadata.next_id: exact;
         }
         actions = {
             set_mcast_group;
         }
-        counters = broadcast_counter;
+        counters = multicast_counter;
     }
+#endif // WITH_MULTICAST
 
     apply {
         if (simple.apply().hit) {
@@ -147,7 +150,9 @@
             }
         }
         hashed.apply();
-        broadcast.apply();
+#ifdef WITH_MULTICAST
+        multicast.apply();
+#endif // WITH_MULTICAST
     }
 }
 
diff --git a/pipelines/fabric/src/main/resources/include/header.p4 b/pipelines/fabric/src/main/resources/include/header.p4
index 7b61cec..6cff586 100644
--- a/pipelines/fabric/src/main/resources/include/header.p4
+++ b/pipelines/fabric/src/main/resources/include/header.p4
@@ -133,6 +133,7 @@
 struct spgw_meta_t {
     bool              do_spgw;
     direction_t       direction;
+    bit<16>           ipv4_len;
     bit<32>           teid;
     bit<32>           s1u_enb_addr;
     bit<32>           s1u_sgw_addr;
diff --git a/pipelines/fabric/src/main/resources/include/spgw.p4 b/pipelines/fabric/src/main/resources/include/spgw.p4
index 5637adf..87839f6 100644
--- a/pipelines/fabric/src/main/resources/include/spgw.p4
+++ b/pipelines/fabric/src/main/resources/include/spgw.p4
@@ -194,6 +194,9 @@
             }
             ue_cdr_table.apply();
         }
+
+        // Don't ask why... we'll need this later.
+        spgw_meta.ipv4_len = ipv4.total_len;
     }
 }
 
@@ -212,7 +215,7 @@
         gtpu_ipv4.version = IP_VERSION_4;
         gtpu_ipv4.ihl = IPV4_MIN_IHL;
         gtpu_ipv4.diffserv = 0;
-        gtpu_ipv4.total_len = ipv4.total_len
+        gtpu_ipv4.total_len = spgw_meta.ipv4_len
                 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
         gtpu_ipv4.identification = 0x1513; /* From NGIC */
         gtpu_ipv4.flags = 0;
@@ -226,7 +229,7 @@
         gtpu_udp.setValid();
         gtpu_udp.src_port = UDP_PORT_GTPU;
         gtpu_udp.dst_port = UDP_PORT_GTPU;
-        gtpu_udp.len = ipv4.total_len
+        gtpu_udp.len = spgw_meta.ipv4_len
                 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
         gtpu_udp.checksum = 0; // Updated later
 
@@ -238,7 +241,7 @@
         gtpu.seq_flag = 0;
         gtpu.npdu_flag = 0;
         gtpu.msgtype = GTP_GPDU;
-        gtpu.msglen = ipv4.total_len;
+        gtpu.msglen = spgw_meta.ipv4_len;
         gtpu.teid = spgw_meta.teid;
     }
 
diff --git a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.json b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.json
index 3b8aeed..6a023a5 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.json
@@ -313,12 +313,12 @@
   "header_union_stacks" : [],
   "field_lists" : [],
   "errors" : [
-    ["NoError", 0],
-    ["PacketTooShort", 1],
-    ["NoMatch", 2],
-    ["StackOutOfBounds", 3],
-    ["HeaderTooShort", 4],
-    ["ParserTimeout", 5]
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
   ],
   "enums" : [],
   "parsers" : [
@@ -842,7 +842,7 @@
       "name" : "deparser",
       "id" : 0,
       "source_info" : {
-        "filename" : "./include/parser.p4",
+        "filename" : "include/parser.p4",
         "line" : 164,
         "column" : 8,
         "source_fragment" : "FabricDeparser"
@@ -889,40 +889,28 @@
       "binding" : "forwarding.unicast_v4"
     },
     {
-      "name" : "forwarding.multicast_v4_counter",
-      "id" : 6,
-      "is_direct" : true,
-      "binding" : "forwarding.multicast_v4"
-    },
-    {
       "name" : "forwarding.acl_counter",
-      "id" : 7,
+      "id" : 6,
       "is_direct" : true,
       "binding" : "forwarding.acl"
     },
     {
       "name" : "next.simple_counter",
-      "id" : 8,
+      "id" : 7,
       "is_direct" : true,
       "binding" : "next.simple"
     },
     {
       "name" : "next.hashed_counter",
-      "id" : 9,
+      "id" : 8,
       "is_direct" : true,
       "binding" : "next.hashed"
     },
     {
-      "name" : "next.broadcast_counter",
-      "id" : 10,
-      "is_direct" : true,
-      "binding" : "next.broadcast"
-    },
-    {
       "name" : "port_counters_control.egress_port_counter",
-      "id" : 11,
+      "id" : 9,
       "source_info" : {
-        "filename" : "./include/control/port_counter.p4",
+        "filename" : "include/control/port_counter.p4",
         "line" : 23,
         "column" : 48,
         "source_fragment" : "egress_port_counter"
@@ -932,9 +920,9 @@
     },
     {
       "name" : "port_counters_control.ingress_port_counter",
-      "id" : 12,
+      "id" : 10,
       "source_info" : {
-        "filename" : "./include/control/port_counter.p4",
+        "filename" : "include/control/port_counter.p4",
         "line" : 24,
         "column" : 48,
         "source_fragment" : "ingress_port_counter"
@@ -949,7 +937,7 @@
       "name" : "calc",
       "id" : 0,
       "source_info" : {
-        "filename" : "./include/checksum.p4",
+        "filename" : "include/checksum.p4",
         "line" : 56,
         "column" : 8,
         "source_fragment" : "verify_checksum(hdr.ipv4.isValid(), ..."
@@ -1006,7 +994,7 @@
       "name" : "calc_0",
       "id" : 1,
       "source_info" : {
-        "filename" : "./include/checksum.p4",
+        "filename" : "include/checksum.p4",
         "line" : 28,
         "column" : 8,
         "source_fragment" : "update_checksum(hdr.ipv4.isValid(), ..."
@@ -1063,8 +1051,8 @@
       "name" : "calc_1",
       "id" : 2,
       "source_info" : {
-        "filename" : "./include/control/../spgw.p4",
-        "line" : 292,
+        "filename" : "include/spgw.p4",
+        "line" : 293,
         "column" : 8,
         "source_fragment" : "update_checksum(gtpu_ipv4.isValid(), ..."
       },
@@ -1115,68 +1103,6 @@
           "value" : ["gtpu_ipv4", "dst_addr"]
         }
       ]
-    },
-    {
-      "name" : "calc_2",
-      "id" : 3,
-      "source_info" : {
-        "filename" : "./include/control/../spgw.p4",
-        "line" : 311,
-        "column" : 8,
-        "source_fragment" : "update_checksum_with_payload(gtpu_udp.isValid(), ..."
-      },
-      "algo" : "csum16",
-      "input" : [
-        {
-          "type" : "field",
-          "value" : ["gtpu_ipv4", "src_addr"]
-        },
-        {
-          "type" : "field",
-          "value" : ["gtpu_ipv4", "dst_addr"]
-        },
-        {
-          "type" : "hexstr",
-          "value" : "0x00",
-          "bitwidth" : 8
-        },
-        {
-          "type" : "field",
-          "value" : ["gtpu_ipv4", "protocol"]
-        },
-        {
-          "type" : "field",
-          "value" : ["gtpu_udp", "len"]
-        },
-        {
-          "type" : "field",
-          "value" : ["gtpu_udp", "src_port"]
-        },
-        {
-          "type" : "field",
-          "value" : ["gtpu_udp", "dst_port"]
-        },
-        {
-          "type" : "field",
-          "value" : ["gtpu_udp", "len"]
-        },
-        {
-          "type" : "header",
-          "value" : "gtpu"
-        },
-        {
-          "type" : "header",
-          "value" : "ipv4"
-        },
-        {
-          "type" : "header",
-          "value" : "udp"
-        },
-        {
-          "type" : "payload",
-          "value" : null
-        }
-      ]
     }
   ],
   "learn_lists" : [],
@@ -1236,39 +1162,27 @@
       "primitives" : []
     },
     {
-      "name" : "NoAction",
+      "name" : "nop",
       "id" : 9,
       "runtime_data" : [],
       "primitives" : []
     },
     {
-      "name" : "NoAction",
+      "name" : "nop",
       "id" : 10,
       "runtime_data" : [],
       "primitives" : []
     },
     {
-      "name" : "nop",
-      "id" : 11,
-      "runtime_data" : [],
-      "primitives" : []
-    },
-    {
-      "name" : "nop",
-      "id" : 12,
-      "runtime_data" : [],
-      "primitives" : []
-    },
-    {
       "name" : "spgw_ingress.drop_now",
-      "id" : 13,
+      "id" : 11,
       "runtime_data" : [],
       "primitives" : [
         {
           "op" : "drop",
           "parameters" : [],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 33,
             "column" : 8,
             "source_fragment" : "mark_to_drop()"
@@ -1278,7 +1192,7 @@
           "op" : "exit",
           "parameters" : [],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 34,
             "column" : 8,
             "source_fragment" : "exit"
@@ -1288,7 +1202,7 @@
     },
     {
       "name" : "spgw_ingress.gtpu_decap",
-      "id" : 14,
+      "id" : 12,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -1300,7 +1214,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 38,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.setInvalid()"
@@ -1315,7 +1229,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 39,
             "column" : 8,
             "source_fragment" : "gtpu_udp.setInvalid()"
@@ -1330,7 +1244,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 40,
             "column" : 8,
             "source_fragment" : "gtpu.setInvalid()"
@@ -1340,7 +1254,7 @@
     },
     {
       "name" : "spgw_ingress.set_dl_sess_info",
-      "id" : 15,
+      "id" : 13,
       "runtime_data" : [
         {
           "name" : "teid",
@@ -1369,7 +1283,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 46,
             "column" : 8,
             "source_fragment" : "spgw_meta.teid = teid"
@@ -1388,7 +1302,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 47,
             "column" : 8,
             "source_fragment" : "spgw_meta.s1u_enb_addr = s1u_enb_addr"
@@ -1407,7 +1321,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 48,
             "column" : 8,
             "source_fragment" : "spgw_meta.s1u_sgw_addr = s1u_sgw_addr"
@@ -1417,20 +1331,20 @@
     },
     {
       "name" : "spgw_ingress.update_ue_cdr",
-      "id" : 16,
+      "id" : 14,
       "runtime_data" : [],
       "primitives" : []
     },
     {
       "name" : "filtering.drop",
-      "id" : 17,
+      "id" : 15,
       "runtime_data" : [],
       "primitives" : [
         {
           "op" : "drop",
           "parameters" : [],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 31,
             "column" : 8,
             "source_fragment" : "mark_to_drop()"
@@ -1440,7 +1354,7 @@
     },
     {
       "name" : "filtering.set_vlan",
-      "id" : 18,
+      "id" : 16,
       "runtime_data" : [
         {
           "name" : "new_vlan_id",
@@ -1461,7 +1375,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 35,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.vlan_id = new_vlan_id"
@@ -1471,7 +1385,7 @@
     },
     {
       "name" : "filtering.push_internal_vlan",
-      "id" : 19,
+      "id" : 17,
       "runtime_data" : [
         {
           "name" : "new_vlan_id",
@@ -1488,7 +1402,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 41,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.setValid()"
@@ -1507,7 +1421,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 42,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.cfi = 0"
@@ -1526,7 +1440,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 43,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.pri = 0"
@@ -1545,7 +1459,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.ether_type = hdr.ethernet.ether_type"
@@ -1564,7 +1478,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 32,
             "column" : 31,
             "source_fragment" : "0x8100; ..."
@@ -1583,7 +1497,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 35,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.vlan_id = new_vlan_id; ..."
@@ -1612,7 +1526,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 49,
             "column" : 8,
             "source_fragment" : "fabric_metadata.pop_vlan_at_egress = true"
@@ -1622,7 +1536,7 @@
     },
     {
       "name" : "filtering.set_forwarding_type",
-      "id" : 20,
+      "id" : 18,
       "runtime_data" : [
         {
           "name" : "fwd_type",
@@ -1643,7 +1557,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 53,
             "column" : 8,
             "source_fragment" : "fabric_metadata.fwd_type = fwd_type"
@@ -1653,15 +1567,15 @@
     },
     {
       "name" : "forwarding.drop",
-      "id" : 21,
+      "id" : 19,
       "runtime_data" : [],
       "primitives" : [
         {
           "op" : "drop",
           "parameters" : [],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 37,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 36,
             "column" : 8,
             "source_fragment" : "mark_to_drop()"
           }
@@ -1670,6 +1584,68 @@
     },
     {
       "name" : "forwarding.set_next_id",
+      "id" : 20,
+      "runtime_data" : [
+        {
+          "name" : "next_id",
+          "bitwidth" : 32
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "fabric_metadata_t.next_id"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/forwarding.p4",
+            "line" : 40,
+            "column" : 8,
+            "source_fragment" : "fabric_metadata.next_id = next_id"
+          }
+        }
+      ]
+    },
+    {
+      "name" : "forwarding.set_next_id",
+      "id" : 21,
+      "runtime_data" : [
+        {
+          "name" : "next_id",
+          "bitwidth" : 32
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "fabric_metadata_t.next_id"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/forwarding.p4",
+            "line" : 40,
+            "column" : 8,
+            "source_fragment" : "fabric_metadata.next_id = next_id"
+          }
+        }
+      ]
+    },
+    {
+      "name" : "forwarding.set_next_id",
       "id" : 22,
       "runtime_data" : [
         {
@@ -1691,101 +1667,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id"
-          }
-        }
-      ]
-    },
-    {
-      "name" : "forwarding.set_next_id",
-      "id" : 23,
-      "runtime_data" : [
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id"
-          }
-        }
-      ]
-    },
-    {
-      "name" : "forwarding.set_next_id",
-      "id" : 24,
-      "runtime_data" : [
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id"
-          }
-        }
-      ]
-    },
-    {
-      "name" : "forwarding.set_next_id",
-      "id" : 25,
-      "runtime_data" : [
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 40,
             "column" : 8,
             "source_fragment" : "fabric_metadata.next_id = next_id"
           }
@@ -1794,7 +1677,7 @@
     },
     {
       "name" : "forwarding.pop_mpls_and_next",
-      "id" : 26,
+      "id" : 23,
       "runtime_data" : [
         {
           "name" : "next_id",
@@ -1811,8 +1694,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 45,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.mpls.setInvalid()"
           }
@@ -1830,8 +1713,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 46,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 45,
             "column" : 8,
             "source_fragment" : "fabric_metadata.next_id = next_id"
           }
@@ -1840,7 +1723,7 @@
     },
     {
       "name" : "forwarding.duplicate_to_controller",
-      "id" : 27,
+      "id" : 24,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -1856,8 +1739,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 50,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 49,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = 255"
           }
@@ -1866,7 +1749,7 @@
     },
     {
       "name" : "next.output",
-      "id" : 28,
+      "id" : 25,
       "runtime_data" : [
         {
           "name" : "port_num",
@@ -1887,8 +1770,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num"
           }
@@ -1897,7 +1780,7 @@
     },
     {
       "name" : "next.set_vlan_output",
-      "id" : 29,
+      "id" : 26,
       "runtime_data" : [
         {
           "name" : "new_vlan_id",
@@ -1922,8 +1805,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 37,
+            "filename" : "include/control/next.p4",
+            "line" : 36,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.vlan_id = new_vlan_id"
           }
@@ -1951,8 +1834,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 40,
+            "filename" : "include/control/next.p4",
+            "line" : 39,
             "column" : 8,
             "source_fragment" : "fabric_metadata.pop_vlan_at_egress = false"
           }
@@ -1970,8 +1853,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
           }
@@ -1980,6 +1863,351 @@
     },
     {
       "name" : "next.l3_routing",
+      "id" : 27,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 44,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 48,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 32,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "next.l3_routing",
+      "id" : 28,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 44,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 48,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 32,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "next.mpls_routing_v4",
+      "id" : 29,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 44,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 48,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 32,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        },
+        {
+          "op" : "add_header",
+          "parameters" : [
+            {
+              "type" : "header",
+              "value" : "mpls"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 59,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.setValid()"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["vlan_tag", "ether_type"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x8847"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 33,
+            "column" : 31,
+            "source_fragment" : "0x8847; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "label"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 3
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 61,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.label = label; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "tc"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x00"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 62,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.tc = tc; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "bos"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 63,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.bos = 1w1"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "ttl"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x40"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 67,
+            "column" : 32,
+            "source_fragment" : "64; ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "next.mpls_routing_v4",
       "id" : 30,
       "runtime_data" : [
         {
@@ -1993,6 +2221,10 @@
         {
           "name" : "dmac",
           "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
         }
       ],
       "primitives" : [
@@ -2009,8 +2241,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
+            "filename" : "include/control/next.p4",
+            "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
           }
@@ -2028,8 +2260,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
+            "filename" : "include/control/next.p4",
+            "line" : 48,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
           }
@@ -2047,16 +2279,126 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
           }
+        },
+        {
+          "op" : "add_header",
+          "parameters" : [
+            {
+              "type" : "header",
+              "value" : "mpls"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 59,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.setValid()"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["vlan_tag", "ether_type"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x8847"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 33,
+            "column" : 31,
+            "source_fragment" : "0x8847; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "label"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 3
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 61,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.label = label; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "tc"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x00"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 62,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.tc = tc; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "bos"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 63,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.bos = 1w1"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "ttl"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x40"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 67,
+            "column" : 32,
+            "source_fragment" : "64; ..."
+          }
         }
       ]
     },
     {
-      "name" : "next.l3_routing",
+      "name" : "next.mpls_routing_v6",
       "id" : 31,
       "runtime_data" : [
         {
@@ -2070,6 +2412,10 @@
         {
           "name" : "dmac",
           "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
         }
       ],
       "primitives" : [
@@ -2086,8 +2432,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
+            "filename" : "include/control/next.p4",
+            "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
           }
@@ -2105,8 +2451,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
+            "filename" : "include/control/next.p4",
+            "line" : 48,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
           }
@@ -2124,159 +2470,24 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
           }
-        }
-      ]
-    },
-    {
-      "name" : "next.set_mcast_group",
-      "id" : 32,
-      "runtime_data" : [
-        {
-          "name" : "gid",
-          "bitwidth" : 16
         },
         {
-          "name" : "smac",
-          "bitwidth" : 48
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
+          "op" : "add_header",
           "parameters" : [
             {
-              "type" : "field",
-              "value" : ["standard_metadata", "mcast_grp"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
+              "type" : "header",
+              "value" : "mpls"
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
+            "filename" : "include/control/next.p4",
             "line" : 59,
             "column" : 8,
-            "source_fragment" : "standard_metadata.mcast_grp = gid"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        }
-      ]
-    },
-    {
-      "name" : "next.mpls_routing_v4",
-      "id" : 33,
-      "runtime_data" : [
-        {
-          "name" : "port_num",
-          "bitwidth" : 9
-        },
-        {
-          "name" : "smac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "dmac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "dst_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 2
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["standard_metadata", "egress_spec"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
-            "column" : 8,
-            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 65,
-            "column" : 8,
             "source_fragment" : "hdr.mpls.setValid()"
           }
         },
@@ -2293,7 +2504,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 33,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
@@ -2312,8 +2523,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 67,
+            "filename" : "include/control/next.p4",
+            "line" : 61,
             "column" : 8,
             "source_fragment" : "hdr.mpls.label = label; ..."
           }
@@ -2331,8 +2542,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 68,
+            "filename" : "include/control/next.p4",
+            "line" : 62,
             "column" : 8,
             "source_fragment" : "hdr.mpls.tc = tc; ..."
           }
@@ -2350,8 +2561,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 69,
+            "filename" : "include/control/next.p4",
+            "line" : 63,
             "column" : 8,
             "source_fragment" : "hdr.mpls.bos = 1w1"
           }
@@ -2369,389 +2580,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 67,
-            "column" : 32,
-            "source_fragment" : "64; ..."
-          }
-        }
-      ]
-    },
-    {
-      "name" : "next.mpls_routing_v4",
-      "id" : 34,
-      "runtime_data" : [
-        {
-          "name" : "port_num",
-          "bitwidth" : 9
-        },
-        {
-          "name" : "smac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "dmac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "dst_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 2
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["standard_metadata", "egress_spec"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
-            "column" : 8,
-            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 65,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.setValid()"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["vlan_tag", "ether_type"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x8847"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 33,
-            "column" : 31,
-            "source_fragment" : "0x8847; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "label"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 3
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 67,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.label = label; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "tc"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x00"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 68,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.tc = tc; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "bos"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x01"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 69,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.bos = 1w1"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "ttl"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x40"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 67,
-            "column" : 32,
-            "source_fragment" : "64; ..."
-          }
-        }
-      ]
-    },
-    {
-      "name" : "next.mpls_routing_v6",
-      "id" : 35,
-      "runtime_data" : [
-        {
-          "name" : "port_num",
-          "bitwidth" : 9
-        },
-        {
-          "name" : "smac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "dmac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "dst_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 2
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["standard_metadata", "egress_spec"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
-            "column" : 8,
-            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 65,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.setValid()"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["vlan_tag", "ether_type"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x8847"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 33,
-            "column" : 31,
-            "source_fragment" : "0x8847; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "label"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 3
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 67,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.label = label; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "tc"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x00"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 68,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.tc = tc; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "bos"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x01"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 69,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.bos = 1w1"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "ttl"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x40"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 67,
             "column" : 32,
             "source_fragment" : "64; ..."
@@ -2761,7 +2590,7 @@
     },
     {
       "name" : "act",
-      "id" : 36,
+      "id" : 32,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2777,7 +2606,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 26,
             "column" : 12,
             "source_fragment" : "standard_metadata.egress_spec = hdr.packet_out.egress_port"
@@ -2792,7 +2621,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 27,
             "column" : 12,
             "source_fragment" : "hdr.packet_out.setInvalid()"
@@ -2802,7 +2631,7 @@
     },
     {
       "name" : "act_0",
-      "id" : 37,
+      "id" : 33,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2832,7 +2661,7 @@
     },
     {
       "name" : "act_1",
-      "id" : 38,
+      "id" : 34,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2862,7 +2691,7 @@
     },
     {
       "name" : "act_2",
-      "id" : 39,
+      "id" : 35,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2878,7 +2707,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 152,
             "column" : 12,
             "source_fragment" : "spgw_meta.s1u_enb_addr = ipv4.src_addr"
@@ -2897,7 +2726,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 153,
             "column" : 12,
             "source_fragment" : "spgw_meta.s1u_sgw_addr = ipv4.dst_addr"
@@ -2916,7 +2745,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 154,
             "column" : 17,
             "source_fragment" : "= gtpu_ipv4; ..."
@@ -2935,7 +2764,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 155,
             "column" : 16,
             "source_fragment" : "= gtpu_udp; ..."
@@ -2945,7 +2774,7 @@
     },
     {
       "name" : "act_3",
-      "id" : 40,
+      "id" : 36,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2971,7 +2800,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 159,
             "column" : 16,
             "source_fragment" : "spgw_meta.do_spgw = true"
@@ -2990,7 +2819,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 88,
             "column" : 31,
             "source_fragment" : "1w0; ..."
@@ -3000,7 +2829,7 @@
     },
     {
       "name" : "act_4",
-      "id" : 41,
+      "id" : 37,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3030,7 +2859,7 @@
     },
     {
       "name" : "act_5",
-      "id" : 42,
+      "id" : 38,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3060,7 +2889,7 @@
     },
     {
       "name" : "act_6",
-      "id" : 43,
+      "id" : 39,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3086,7 +2915,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 163,
             "column" : 12,
             "source_fragment" : "spgw_meta.do_spgw = true"
@@ -3105,7 +2934,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 89,
             "column" : 33,
             "source_fragment" : "1w1; ..."
@@ -3115,7 +2944,7 @@
     },
     {
       "name" : "act_7",
-      "id" : 44,
+      "id" : 40,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3164,7 +2993,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 146,
             "column" : 8,
             "source_fragment" : "spgw_meta.do_spgw = false"
@@ -3174,7 +3003,7 @@
     },
     {
       "name" : "act_8",
-      "id" : 45,
+      "id" : 41,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3200,7 +3029,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 169,
             "column" : 12,
             "source_fragment" : "return"
@@ -3210,7 +3039,7 @@
     },
     {
       "name" : "act_9",
-      "id" : 46,
+      "id" : 42,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3240,7 +3069,7 @@
     },
     {
       "name" : "act_10",
-      "id" : 47,
+      "id" : 43,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3270,7 +3099,7 @@
     },
     {
       "name" : "act_11",
-      "id" : 48,
+      "id" : 44,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3286,7 +3115,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 35,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
@@ -3305,7 +3134,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 35,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
@@ -3315,7 +3144,7 @@
     },
     {
       "name" : "act_12",
-      "id" : 49,
+      "id" : 45,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3345,7 +3174,7 @@
     },
     {
       "name" : "act_13",
-      "id" : 50,
+      "id" : 46,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3375,7 +3204,7 @@
     },
     {
       "name" : "act_14",
-      "id" : 51,
+      "id" : 47,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3414,8 +3243,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 140,
+            "filename" : "include/control/next.p4",
+            "line" : 143,
             "column" : 20,
             "source_fragment" : "hdr.ipv4.ttl = hdr.ipv4.ttl - 1"
           }
@@ -3424,7 +3253,7 @@
     },
     {
       "name" : "act_15",
-      "id" : 52,
+      "id" : 48,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3466,7 +3295,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 28,
             "column" : 12,
             "source_fragment" : "egress_port_counter.count((bit<32>)standard_metadata.egress_spec)"
@@ -3476,7 +3305,7 @@
     },
     {
       "name" : "act_16",
-      "id" : 53,
+      "id" : 49,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3518,7 +3347,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 31,
             "column" : 12,
             "source_fragment" : "ingress_port_counter.count((bit<32>)standard_metadata.ingress_port)"
@@ -3528,7 +3357,7 @@
     },
     {
       "name" : "act_17",
-      "id" : 54,
+      "id" : 50,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3544,8 +3373,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 162,
+            "filename" : "include/control/next.p4",
+            "line" : 167,
             "column" : 12,
             "source_fragment" : "hdr.ethernet.ether_type = hdr.vlan_tag.ether_type"
           }
@@ -3559,8 +3388,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 163,
+            "filename" : "include/control/next.p4",
+            "line" : 168,
             "column" : 12,
             "source_fragment" : "hdr.vlan_tag.setInvalid()"
           }
@@ -3569,7 +3398,7 @@
     },
     {
       "name" : "spgw_egress.gtpu_encap",
-      "id" : 55,
+      "id" : 51,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -3581,8 +3410,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 210,
+            "filename" : "include/spgw.p4",
+            "line" : 211,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.setValid()"
           }
@@ -3600,8 +3429,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 211,
+            "filename" : "include/spgw.p4",
+            "line" : 212,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.version = 4"
           }
@@ -3619,7 +3448,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 54,
             "column" : 28,
             "source_fragment" : "5; ..."
@@ -3638,8 +3467,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 213,
+            "filename" : "include/spgw.p4",
+            "line" : 214,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.diffserv = 0"
           }
@@ -3662,82 +3491,12 @@
                     "value" : {
                       "op" : "+",
                       "left" : {
-                        "type" : "expression",
-                        "value" : {
-                          "op" : "&",
-                          "left" : {
-                            "type" : "expression",
-                            "value" : {
-                              "op" : "+",
-                              "left" : {
-                                "type" : "expression",
-                                "value" : {
-                                  "op" : "&",
-                                  "left" : {
-                                    "type" : "expression",
-                                    "value" : {
-                                      "op" : "+",
-                                      "left" : {
-                                        "type" : "expression",
-                                        "value" : {
-                                          "op" : "&",
-                                          "left" : {
-                                            "type" : "expression",
-                                            "value" : {
-                                              "op" : "+",
-                                              "left" : {
-                                                "type" : "expression",
-                                                "value" : {
-                                                  "op" : "&",
-                                                  "left" : {
-                                                    "type" : "field",
-                                                    "value" : ["standard_metadata", "packet_length"]
-                                                  },
-                                                  "right" : {
-                                                    "type" : "hexstr",
-                                                    "value" : "0xffff"
-                                                  }
-                                                }
-                                              },
-                                              "right" : {
-                                                "type" : "hexstr",
-                                                "value" : "0xfff2"
-                                              }
-                                            }
-                                          },
-                                          "right" : {
-                                            "type" : "hexstr",
-                                            "value" : "0xffff"
-                                          }
-                                        }
-                                      },
-                                      "right" : {
-                                        "type" : "hexstr",
-                                        "value" : "0x0014"
-                                      }
-                                    }
-                                  },
-                                  "right" : {
-                                    "type" : "hexstr",
-                                    "value" : "0xffff"
-                                  }
-                                }
-                              },
-                              "right" : {
-                                "type" : "hexstr",
-                                "value" : "0x0008"
-                              }
-                            }
-                          },
-                          "right" : {
-                            "type" : "hexstr",
-                            "value" : "0xffff"
-                          }
-                        }
+                        "type" : "field",
+                        "value" : ["ipv4", "total_len"]
                       },
                       "right" : {
                         "type" : "hexstr",
-                        "value" : "0x0008"
+                        "value" : "0x0024"
                       }
                     }
                   },
@@ -3750,10 +3509,10 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 214,
+            "filename" : "include/spgw.p4",
+            "line" : 215,
             "column" : 8,
-            "source_fragment" : "gtpu_ipv4.total_len = ((bit<16>)std_meta.packet_length ..."
+            "source_fragment" : "gtpu_ipv4.total_len = ipv4.total_len ..."
           }
         },
         {
@@ -3769,8 +3528,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 216,
+            "filename" : "include/spgw.p4",
+            "line" : 217,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.identification = 0x1513"
           }
@@ -3788,8 +3547,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 217,
+            "filename" : "include/spgw.p4",
+            "line" : 218,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.flags = 0"
           }
@@ -3807,8 +3566,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 218,
+            "filename" : "include/spgw.p4",
+            "line" : 219,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.frag_offset = 0"
           }
@@ -3826,7 +3585,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 78,
             "column" : 32,
             "source_fragment" : "64; ..."
@@ -3845,7 +3604,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 51,
             "column" : 25,
             "source_fragment" : "17; ..."
@@ -3864,8 +3623,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 221,
+            "filename" : "include/spgw.p4",
+            "line" : 222,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.dst_addr = spgw_meta.s1u_enb_addr"
           }
@@ -3883,8 +3642,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 222,
+            "filename" : "include/spgw.p4",
+            "line" : 223,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.src_addr = spgw_meta.s1u_sgw_addr"
           }
@@ -3902,8 +3661,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 223,
+            "filename" : "include/spgw.p4",
+            "line" : 224,
             "column" : 8,
             "source_fragment" : "gtpu_ipv4.hdr_checksum = 0"
           }
@@ -3917,8 +3676,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 225,
+            "filename" : "include/spgw.p4",
+            "line" : 226,
             "column" : 8,
             "source_fragment" : "gtpu_udp.setValid()"
           }
@@ -3936,8 +3695,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 226,
+            "filename" : "include/spgw.p4",
+            "line" : 227,
             "column" : 8,
             "source_fragment" : "gtpu_udp.src_port = 2152"
           }
@@ -3955,8 +3714,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 227,
+            "filename" : "include/spgw.p4",
+            "line" : 228,
             "column" : 8,
             "source_fragment" : "gtpu_udp.dst_port = 2152"
           }
@@ -3979,62 +3738,12 @@
                     "value" : {
                       "op" : "+",
                       "left" : {
-                        "type" : "expression",
-                        "value" : {
-                          "op" : "&",
-                          "left" : {
-                            "type" : "expression",
-                            "value" : {
-                              "op" : "+",
-                              "left" : {
-                                "type" : "expression",
-                                "value" : {
-                                  "op" : "&",
-                                  "left" : {
-                                    "type" : "expression",
-                                    "value" : {
-                                      "op" : "+",
-                                      "left" : {
-                                        "type" : "expression",
-                                        "value" : {
-                                          "op" : "&",
-                                          "left" : {
-                                            "type" : "field",
-                                            "value" : ["standard_metadata", "packet_length"]
-                                          },
-                                          "right" : {
-                                            "type" : "hexstr",
-                                            "value" : "0xffff"
-                                          }
-                                        }
-                                      },
-                                      "right" : {
-                                        "type" : "hexstr",
-                                        "value" : "0xfff2"
-                                      }
-                                    }
-                                  },
-                                  "right" : {
-                                    "type" : "hexstr",
-                                    "value" : "0xffff"
-                                  }
-                                }
-                              },
-                              "right" : {
-                                "type" : "hexstr",
-                                "value" : "0x0008"
-                              }
-                            }
-                          },
-                          "right" : {
-                            "type" : "hexstr",
-                            "value" : "0xffff"
-                          }
-                        }
+                        "type" : "field",
+                        "value" : ["ipv4", "total_len"]
                       },
                       "right" : {
                         "type" : "hexstr",
-                        "value" : "0x0008"
+                        "value" : "0x0010"
                       }
                     }
                   },
@@ -4047,10 +3756,10 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 228,
+            "filename" : "include/spgw.p4",
+            "line" : 229,
             "column" : 8,
-            "source_fragment" : "gtpu_udp.len = ((bit<16>)std_meta.packet_length ..."
+            "source_fragment" : "gtpu_udp.len = ipv4.total_len ..."
           }
         },
         {
@@ -4066,8 +3775,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 230,
+            "filename" : "include/spgw.p4",
+            "line" : 231,
             "column" : 8,
             "source_fragment" : "gtpu_udp.checksum = 0"
           }
@@ -4081,8 +3790,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 232,
+            "filename" : "include/spgw.p4",
+            "line" : 233,
             "column" : 8,
             "source_fragment" : "gtpu.setValid()"
           }
@@ -4100,8 +3809,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 233,
+            "filename" : "include/spgw.p4",
+            "line" : 234,
             "column" : 8,
             "source_fragment" : "gtpu.version = 0x01"
           }
@@ -4119,8 +3828,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 234,
+            "filename" : "include/spgw.p4",
+            "line" : 235,
             "column" : 8,
             "source_fragment" : "gtpu.pt = 0x01"
           }
@@ -4138,8 +3847,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 235,
+            "filename" : "include/spgw.p4",
+            "line" : 236,
             "column" : 8,
             "source_fragment" : "gtpu.spare = 0"
           }
@@ -4157,8 +3866,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 236,
+            "filename" : "include/spgw.p4",
+            "line" : 237,
             "column" : 8,
             "source_fragment" : "gtpu.ex_flag = 0"
           }
@@ -4176,8 +3885,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 237,
+            "filename" : "include/spgw.p4",
+            "line" : 238,
             "column" : 8,
             "source_fragment" : "gtpu.seq_flag = 0"
           }
@@ -4195,8 +3904,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 238,
+            "filename" : "include/spgw.p4",
+            "line" : 239,
             "column" : 8,
             "source_fragment" : "gtpu.npdu_flag = 0"
           }
@@ -4214,8 +3923,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 239,
+            "filename" : "include/spgw.p4",
+            "line" : 240,
             "column" : 8,
             "source_fragment" : "gtpu.msgtype = 0xff"
           }
@@ -4228,48 +3937,15 @@
               "value" : ["gtpu", "msglen"]
             },
             {
-              "type" : "expression",
-              "value" : {
-                "type" : "expression",
-                "value" : {
-                  "op" : "&",
-                  "left" : {
-                    "type" : "expression",
-                    "value" : {
-                      "op" : "+",
-                      "left" : {
-                        "type" : "expression",
-                        "value" : {
-                          "op" : "&",
-                          "left" : {
-                            "type" : "field",
-                            "value" : ["standard_metadata", "packet_length"]
-                          },
-                          "right" : {
-                            "type" : "hexstr",
-                            "value" : "0xffff"
-                          }
-                        }
-                      },
-                      "right" : {
-                        "type" : "hexstr",
-                        "value" : "0xfff2"
-                      }
-                    }
-                  },
-                  "right" : {
-                    "type" : "hexstr",
-                    "value" : "0xffff"
-                  }
-                }
-              }
+              "type" : "field",
+              "value" : ["ipv4", "total_len"]
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 240,
+            "filename" : "include/spgw.p4",
+            "line" : 241,
             "column" : 8,
-            "source_fragment" : "gtpu.msglen = ((bit<16>)std_meta.packet_length - 14"
+            "source_fragment" : "gtpu.msglen = ipv4.total_len"
           }
         },
         {
@@ -4285,8 +3961,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 241,
+            "filename" : "include/spgw.p4",
+            "line" : 242,
             "column" : 8,
             "source_fragment" : "gtpu.teid = spgw_meta.teid"
           }
@@ -4295,7 +3971,7 @@
     },
     {
       "name" : "act_18",
-      "id" : 56,
+      "id" : 52,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -4307,7 +3983,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 39,
             "column" : 12,
             "source_fragment" : "hdr.packet_in.setValid()"
@@ -4326,7 +4002,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 40,
             "column" : 12,
             "source_fragment" : "hdr.packet_in.ingress_port = standard_metadata.ingress_port"
@@ -4336,7 +4012,7 @@
     },
     {
       "name" : "act_19",
-      "id" : 57,
+      "id" : 53,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -4350,7 +4026,7 @@
           "source_info" : {
             "filename" : "fabric.p4",
             "line" : 69,
-            "column" : 26,
+            "column" : 36,
             "source_fragment" : "hdr.gtpu_ipv4"
           }
         },
@@ -4365,7 +4041,7 @@
           "source_info" : {
             "filename" : "fabric.p4",
             "line" : 69,
-            "column" : 41,
+            "column" : 51,
             "source_fragment" : "hdr.gtpu_udp"
           }
         },
@@ -4380,7 +4056,7 @@
           "source_info" : {
             "filename" : "fabric.p4",
             "line" : 69,
-            "column" : 55,
+            "column" : 65,
             "source_fragment" : "hdr.gtpu"
           }
         }
@@ -4409,14 +4085,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [36],
+          "action_ids" : [32],
           "actions" : ["act"],
           "base_default_next" : null,
           "next_tables" : {
             "act" : null
           },
           "default_entry" : {
-            "action_id" : 36,
+            "action_id" : 32,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4432,14 +4108,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [44],
+          "action_ids" : [40],
           "actions" : ["act_7"],
           "base_default_next" : "node_5",
           "next_tables" : {
             "act_7" : "node_5"
           },
           "default_entry" : {
-            "action_id" : 44,
+            "action_id" : 40,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4455,14 +4131,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [39],
+          "action_ids" : [35],
           "actions" : ["act_2"],
           "base_default_next" : "spgw_ingress.s1u_filter_table",
           "next_tables" : {
             "act_2" : "spgw_ingress.s1u_filter_table"
           },
           "default_entry" : {
-            "action_id" : 39,
+            "action_id" : 35,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4472,7 +4148,7 @@
           "name" : "spgw_ingress.s1u_filter_table",
           "id" : 3,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 65,
             "column" : 10,
             "source_fragment" : "s1u_filter_table"
@@ -4514,14 +4190,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [37],
+          "action_ids" : [33],
           "actions" : ["act_0"],
           "base_default_next" : "node_10",
           "next_tables" : {
             "act_0" : "node_10"
           },
           "default_entry" : {
-            "action_id" : 37,
+            "action_id" : 33,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4537,14 +4213,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [38],
+          "action_ids" : [34],
           "actions" : ["act_1"],
           "base_default_next" : "node_10",
           "next_tables" : {
             "act_1" : "node_10"
           },
           "default_entry" : {
-            "action_id" : 38,
+            "action_id" : 34,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4560,14 +4236,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [40],
+          "action_ids" : [36],
           "actions" : ["act_3"],
           "base_default_next" : "node_17",
           "next_tables" : {
             "act_3" : "node_17"
           },
           "default_entry" : {
-            "action_id" : 40,
+            "action_id" : 36,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4577,7 +4253,7 @@
           "name" : "spgw_ingress.ue_filter_table",
           "id" : 7,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 55,
             "column" : 10,
             "source_fragment" : "ue_filter_table"
@@ -4619,14 +4295,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [41],
+          "action_ids" : [37],
           "actions" : ["act_4"],
           "base_default_next" : "node_15",
           "next_tables" : {
             "act_4" : "node_15"
           },
           "default_entry" : {
-            "action_id" : 41,
+            "action_id" : 37,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4642,14 +4318,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [42],
+          "action_ids" : [38],
           "actions" : ["act_5"],
           "base_default_next" : "node_15",
           "next_tables" : {
             "act_5" : "node_15"
           },
           "default_entry" : {
-            "action_id" : 42,
+            "action_id" : 38,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4665,14 +4341,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [43],
+          "action_ids" : [39],
           "actions" : ["act_6"],
           "base_default_next" : "node_17",
           "next_tables" : {
             "act_6" : "node_17"
           },
           "default_entry" : {
-            "action_id" : 43,
+            "action_id" : 39,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4688,14 +4364,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [45],
+          "action_ids" : [41],
           "actions" : ["act_8"],
           "base_default_next" : "node_19",
           "next_tables" : {
             "act_8" : "node_19"
           },
           "default_entry" : {
-            "action_id" : 45,
+            "action_id" : 41,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4711,14 +4387,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [14],
+          "action_ids" : [12],
           "actions" : ["spgw_ingress.gtpu_decap"],
           "base_default_next" : "node_22",
           "next_tables" : {
             "spgw_ingress.gtpu_decap" : "node_22"
           },
           "default_entry" : {
-            "action_id" : 14,
+            "action_id" : 12,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4728,7 +4404,7 @@
           "name" : "spgw_ingress.dl_sess_lookup",
           "id" : 13,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 124,
             "column" : 10,
             "source_fragment" : "dl_sess_lookup"
@@ -4746,7 +4422,7 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [15, 2],
+          "action_ids" : [13, 2],
           "actions" : ["spgw_ingress.set_dl_sess_info", "NoAction"],
           "base_default_next" : null,
           "next_tables" : {
@@ -4770,14 +4446,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [46],
+          "action_ids" : [42],
           "actions" : ["act_9"],
           "base_default_next" : "node_26",
           "next_tables" : {
             "act_9" : "node_26"
           },
           "default_entry" : {
-            "action_id" : 46,
+            "action_id" : 42,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4793,14 +4469,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [47],
+          "action_ids" : [43],
           "actions" : ["act_10"],
           "base_default_next" : "node_26",
           "next_tables" : {
             "act_10" : "node_26"
           },
           "default_entry" : {
-            "action_id" : 47,
+            "action_id" : 43,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4816,14 +4492,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [13],
+          "action_ids" : [11],
           "actions" : ["spgw_ingress.drop_now"],
           "base_default_next" : "spgw_ingress.ue_cdr_table",
           "next_tables" : {
             "spgw_ingress.drop_now" : "spgw_ingress.ue_cdr_table"
           },
           "default_entry" : {
-            "action_id" : 13,
+            "action_id" : 11,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4833,7 +4509,7 @@
           "name" : "spgw_ingress.ue_cdr_table",
           "id" : 17,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 134,
             "column" : 10,
             "source_fragment" : "ue_cdr_table"
@@ -4851,7 +4527,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [16, 3],
+          "action_ids" : [14, 3],
           "actions" : ["spgw_ingress.update_ue_cdr", "NoAction"],
           "base_default_next" : "filtering.ingress_port_vlan",
           "next_tables" : {
@@ -4869,7 +4545,7 @@
           "name" : "filtering.ingress_port_vlan",
           "id" : 18,
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 57,
             "column" : 10,
             "source_fragment" : "ingress_port_vlan"
@@ -4897,7 +4573,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [19, 18, 11, 17],
+          "action_ids" : [17, 16, 9, 15],
           "actions" : ["filtering.push_internal_vlan", "filtering.set_vlan", "nop", "filtering.drop"],
           "base_default_next" : "filtering.fwd_classifier",
           "next_tables" : {
@@ -4907,7 +4583,7 @@
             "filtering.drop" : "filtering.fwd_classifier"
           },
           "default_entry" : {
-            "action_id" : 11,
+            "action_id" : 9,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -4917,7 +4593,7 @@
           "name" : "filtering.fwd_classifier",
           "id" : 19,
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 76,
             "column" : 10,
             "source_fragment" : "fwd_classifier"
@@ -4945,14 +4621,14 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [20],
+          "action_ids" : [18],
           "actions" : ["filtering.set_forwarding_type"],
           "base_default_next" : "node_31",
           "next_tables" : {
             "filtering.set_forwarding_type" : "node_31"
           },
           "default_entry" : {
-            "action_id" : 20,
+            "action_id" : 18,
             "action_const" : true,
             "action_data" : ["0x0"],
             "action_entry_const" : true
@@ -4962,8 +4638,8 @@
           "name" : "forwarding.bridging",
           "id" : 20,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 53,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 52,
             "column" : 10,
             "source_fragment" : "bridging"
           },
@@ -4985,7 +4661,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [22, 4],
+          "action_ids" : [20, 4],
           "actions" : ["forwarding.set_next_id", "NoAction"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
@@ -5003,8 +4679,8 @@
           "name" : "forwarding.mpls",
           "id" : 21,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 65,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 64,
             "column" : 10,
             "source_fragment" : "mpls"
           },
@@ -5021,7 +4697,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [26, 5],
+          "action_ids" : [23, 5],
           "actions" : ["forwarding.pop_mpls_and_next", "NoAction"],
           "base_default_next" : "tbl_act_11",
           "next_tables" : {
@@ -5045,14 +4721,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [48],
+          "action_ids" : [44],
           "actions" : ["act_11"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
             "act_11" : "forwarding.acl"
           },
           "default_entry" : {
-            "action_id" : 48,
+            "action_id" : 44,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -5062,8 +4738,8 @@
           "name" : "forwarding.unicast_v4",
           "id" : 23,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 76,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 75,
             "column" : 10,
             "source_fragment" : "unicast_v4"
           },
@@ -5080,7 +4756,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [23, 6],
+          "action_ids" : [21, 6],
           "actions" : ["forwarding.set_next_id", "NoAction"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
@@ -5095,52 +4771,11 @@
           }
         },
         {
-          "name" : "forwarding.multicast_v4",
+          "name" : "forwarding.acl",
           "id" : 24,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 87,
-            "column" : 10,
-            "source_fragment" : "multicast_v4"
-          },
-          "key" : [
-            {
-              "match_type" : "exact",
-              "target" : ["vlan_tag", "vlan_id"],
-              "mask" : null
-            },
-            {
-              "match_type" : "lpm",
-              "target" : ["ipv4", "dst_addr"],
-              "mask" : null
-            }
-          ],
-          "match_type" : "lpm",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : true,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [24, 7],
-          "actions" : ["forwarding.set_next_id", "NoAction"],
-          "base_default_next" : "forwarding.acl",
-          "next_tables" : {
-            "forwarding.set_next_id" : "forwarding.acl",
-            "NoAction" : "forwarding.acl"
-          },
-          "default_entry" : {
-            "action_id" : 7,
-            "action_const" : false,
-            "action_data" : [],
-            "action_entry_const" : false
-          }
-        },
-        {
-          "name" : "forwarding.acl",
-          "id" : 25,
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 127,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 133,
             "column" : 10,
             "source_fragment" : "acl"
           },
@@ -5212,7 +4847,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [25, 27, 21, 12],
+          "action_ids" : [22, 24, 19, 10],
           "actions" : ["forwarding.set_next_id", "forwarding.duplicate_to_controller", "forwarding.drop", "nop"],
           "base_default_next" : "next.simple",
           "next_tables" : {
@@ -5222,7 +4857,7 @@
             "nop" : "next.simple"
           },
           "default_entry" : {
-            "action_id" : 12,
+            "action_id" : 10,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -5230,10 +4865,10 @@
         },
         {
           "name" : "next.simple",
-          "id" : 26,
+          "id" : 25,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 89,
+            "filename" : "include/control/next.p4",
+            "line" : 83,
             "column" : 10,
             "source_fragment" : "simple"
           },
@@ -5250,7 +4885,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [28, 29, 30, 33, 8],
+          "action_ids" : [25, 26, 27, 29, 7],
           "actions" : ["next.output", "next.set_vlan_output", "next.l3_routing", "next.mpls_routing_v4", "NoAction"],
           "base_default_next" : null,
           "next_tables" : {
@@ -5258,7 +4893,7 @@
             "__MISS__" : "tbl_act_13"
           },
           "default_entry" : {
-            "action_id" : 8,
+            "action_id" : 7,
             "action_const" : false,
             "action_data" : [],
             "action_entry_const" : false
@@ -5266,6 +4901,29 @@
         },
         {
           "name" : "tbl_act_12",
+          "id" : 26,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [45],
+          "actions" : ["act_12"],
+          "base_default_next" : "node_42",
+          "next_tables" : {
+            "act_12" : "node_42"
+          },
+          "default_entry" : {
+            "action_id" : 45,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_act_13",
           "id" : 27,
           "key" : [],
           "match_type" : "exact",
@@ -5274,21 +4932,21 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [49],
-          "actions" : ["act_12"],
-          "base_default_next" : "node_44",
+          "action_ids" : [46],
+          "actions" : ["act_13"],
+          "base_default_next" : "node_42",
           "next_tables" : {
-            "act_12" : "node_44"
+            "act_13" : "node_42"
           },
           "default_entry" : {
-            "action_id" : 49,
+            "action_id" : 46,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
           }
         },
         {
-          "name" : "tbl_act_13",
+          "name" : "tbl_act_14",
           "id" : 28,
           "key" : [],
           "match_type" : "exact",
@@ -5297,37 +4955,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [50],
-          "actions" : ["act_13"],
-          "base_default_next" : "node_44",
-          "next_tables" : {
-            "act_13" : "node_44"
-          },
-          "default_entry" : {
-            "action_id" : 50,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_act_14",
-          "id" : 29,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [51],
+          "action_ids" : [47],
           "actions" : ["act_14"],
           "base_default_next" : "next.hashed",
           "next_tables" : {
             "act_14" : "next.hashed"
           },
           "default_entry" : {
-            "action_id" : 51,
+            "action_id" : 47,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -5335,10 +4970,10 @@
         },
         {
           "name" : "next.hashed",
-          "id" : 30,
+          "id" : 29,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 103,
+            "filename" : "include/control/next.p4",
+            "line" : 97,
             "column" : 10,
             "source_fragment" : "hashed"
           },
@@ -5356,54 +4991,64 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [31, 34, 35, 9],
+          "action_ids" : [28, 30, 31, 8],
           "actions" : ["next.l3_routing", "next.mpls_routing_v4", "next.mpls_routing_v6", "NoAction"],
-          "base_default_next" : "next.broadcast",
+          "base_default_next" : "node_47",
           "next_tables" : {
-            "next.l3_routing" : "next.broadcast",
-            "next.mpls_routing_v4" : "next.broadcast",
-            "next.mpls_routing_v6" : "next.broadcast",
-            "NoAction" : "next.broadcast"
-          }
-        },
-        {
-          "name" : "next.broadcast",
-          "id" : 31,
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 126,
-            "column" : 10,
-            "source_fragment" : "broadcast"
-          },
-          "key" : [
-            {
-              "match_type" : "exact",
-              "target" : ["scalars", "fabric_metadata_t.next_id"],
-              "mask" : null
-            }
-          ],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : true,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [32, 10],
-          "actions" : ["next.set_mcast_group", "NoAction"],
-          "base_default_next" : "node_50",
-          "next_tables" : {
-            "next.set_mcast_group" : "node_50",
-            "NoAction" : "node_50"
-          },
-          "default_entry" : {
-            "action_id" : 10,
-            "action_const" : false,
-            "action_data" : [],
-            "action_entry_const" : false
+            "next.l3_routing" : "node_47",
+            "next.mpls_routing_v4" : "node_47",
+            "next.mpls_routing_v6" : "node_47",
+            "NoAction" : "node_47"
           }
         },
         {
           "name" : "tbl_act_15",
+          "id" : 30,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [48],
+          "actions" : ["act_15"],
+          "base_default_next" : "node_49",
+          "next_tables" : {
+            "act_15" : "node_49"
+          },
+          "default_entry" : {
+            "action_id" : 48,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_act_16",
+          "id" : 31,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [49],
+          "actions" : ["act_16"],
+          "base_default_next" : "node_51",
+          "next_tables" : {
+            "act_16" : "node_51"
+          },
+          "default_entry" : {
+            "action_id" : 49,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_act_17",
           "id" : 32,
           "key" : [],
           "match_type" : "exact",
@@ -5412,60 +5057,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [52],
-          "actions" : ["act_15"],
-          "base_default_next" : "node_52",
-          "next_tables" : {
-            "act_15" : "node_52"
-          },
-          "default_entry" : {
-            "action_id" : 52,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_act_16",
-          "id" : 33,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [53],
-          "actions" : ["act_16"],
-          "base_default_next" : "node_54",
-          "next_tables" : {
-            "act_16" : "node_54"
-          },
-          "default_entry" : {
-            "action_id" : 53,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_act_17",
-          "id" : 34,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [54],
+          "action_ids" : [50],
           "actions" : ["act_17"],
           "base_default_next" : null,
           "next_tables" : {
             "act_17" : null
           },
           "default_entry" : {
-            "action_id" : 54,
+            "action_id" : 50,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -5509,7 +5108,7 @@
           "name" : "node_2",
           "id" : 0,
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 25,
             "column" : 12,
             "source_fragment" : "hdr.packet_out.isValid()"
@@ -5532,7 +5131,7 @@
           "name" : "node_5",
           "id" : 1,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 147,
             "column" : 12,
             "source_fragment" : "gtpu.isValid()"
@@ -5589,7 +5188,7 @@
           "name" : "node_17",
           "id" : 4,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 167,
             "column" : 12,
             "source_fragment" : "!spgw_meta.do_spgw"
@@ -5643,7 +5242,7 @@
           "name" : "node_20",
           "id" : 6,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 172,
             "column" : 12,
             "source_fragment" : "spgw_meta.direction == DIR_UPLINK"
@@ -5669,7 +5268,7 @@
           "name" : "node_22",
           "id" : 7,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 189,
             "column" : 12,
             "source_fragment" : "spgw_meta.direction == DIR_DOWNLINK"
@@ -5695,7 +5294,7 @@
           "name" : "node_26",
           "id" : 8,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
+            "filename" : "include/spgw.p4",
             "line" : 190,
             "column" : 16,
             "source_fragment" : "!dl_sess_lookup.apply().hit"
@@ -5725,8 +5324,8 @@
           "name" : "node_31",
           "id" : 9,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 157,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 163,
             "column" : 11,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_BRIDGING"
           },
@@ -5751,8 +5350,8 @@
           "name" : "node_33",
           "id" : 10,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 158,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 164,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_MPLS"
           },
@@ -5777,8 +5376,8 @@
           "name" : "node_36",
           "id" : 11,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 165,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 179,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV4_UNICAST"
           },
@@ -5797,37 +5396,11 @@
             }
           },
           "true_next" : "forwarding.unicast_v4",
-          "false_next" : "node_38"
-        },
-        {
-          "name" : "node_38",
-          "id" : 12,
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 166,
-            "column" : 17,
-            "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV4_MULTICAST"
-          },
-          "expression" : {
-            "type" : "expression",
-            "value" : {
-              "op" : "==",
-              "left" : {
-                "type" : "field",
-                "value" : ["scalars", "fabric_metadata_t.fwd_type"]
-              },
-              "right" : {
-                "type" : "hexstr",
-                "value" : "0x03"
-              }
-            }
-          },
-          "true_next" : "forwarding.multicast_v4",
           "false_next" : "forwarding.acl"
         },
         {
-          "name" : "node_44",
-          "id" : 13,
+          "name" : "node_42",
+          "id" : 12,
           "expression" : {
             "type" : "expression",
             "value" : {
@@ -5839,15 +5412,15 @@
               }
             }
           },
-          "true_next" : "node_45",
+          "true_next" : "node_43",
           "false_next" : "next.hashed"
         },
         {
-          "name" : "node_45",
-          "id" : 14,
+          "name" : "node_43",
+          "id" : 13,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 138,
+            "filename" : "include/control/next.p4",
+            "line" : 141,
             "column" : 16,
             "source_fragment" : "!hdr.mpls.isValid()"
           },
@@ -5869,15 +5442,15 @@
               }
             }
           },
-          "true_next" : "node_46",
+          "true_next" : "node_44",
           "false_next" : "next.hashed"
         },
         {
-          "name" : "node_46",
-          "id" : 15,
+          "name" : "node_44",
+          "id" : 14,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 139,
+            "filename" : "include/control/next.p4",
+            "line" : 142,
             "column" : 19,
             "source_fragment" : "hdr.ipv4.isValid()"
           },
@@ -5896,10 +5469,10 @@
           "false_next" : "next.hashed"
         },
         {
-          "name" : "node_50",
-          "id" : 16,
+          "name" : "node_47",
+          "id" : 15,
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 27,
             "column" : 12,
             "source_fragment" : "standard_metadata.egress_spec < 511"
@@ -5919,13 +5492,13 @@
             }
           },
           "true_next" : "tbl_act_15",
-          "false_next" : "node_52"
+          "false_next" : "node_49"
         },
         {
-          "name" : "node_52",
-          "id" : 17,
+          "name" : "node_49",
+          "id" : 16,
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 30,
             "column" : 12,
             "source_fragment" : "standard_metadata.ingress_port < 511"
@@ -5945,14 +5518,14 @@
             }
           },
           "true_next" : "tbl_act_16",
-          "false_next" : "node_54"
+          "false_next" : "node_51"
         },
         {
-          "name" : "node_54",
-          "id" : 18,
+          "name" : "node_51",
+          "id" : 17,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 161,
+            "filename" : "include/control/next.p4",
+            "line" : 166,
             "column" : 12,
             "source_fragment" : "fabric_metadata.pop_vlan_at_egress"
           },
@@ -5981,10 +5554,56 @@
         "column" : 8,
         "source_fragment" : "FabricEgress"
       },
-      "init_table" : "node_58",
+      "init_table" : "node_55",
       "tables" : [
         {
           "name" : "tbl_act_18",
+          "id" : 33,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [52],
+          "actions" : ["act_18"],
+          "base_default_next" : "tbl_act_19",
+          "next_tables" : {
+            "act_18" : "tbl_act_19"
+          },
+          "default_entry" : {
+            "action_id" : 52,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_act_19",
+          "id" : 34,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [53],
+          "actions" : ["act_19"],
+          "base_default_next" : "node_58",
+          "next_tables" : {
+            "act_19" : "node_58"
+          },
+          "default_entry" : {
+            "action_id" : 53,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_spgw_egress_gtpu_encap",
           "id" : 35,
           "key" : [],
           "match_type" : "exact",
@@ -5993,60 +5612,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [56],
-          "actions" : ["act_18"],
-          "base_default_next" : "tbl_act_19",
-          "next_tables" : {
-            "act_18" : "tbl_act_19"
-          },
-          "default_entry" : {
-            "action_id" : 56,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_act_19",
-          "id" : 36,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [57],
-          "actions" : ["act_19"],
-          "base_default_next" : "node_61",
-          "next_tables" : {
-            "act_19" : "node_61"
-          },
-          "default_entry" : {
-            "action_id" : 57,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_spgw_egress_gtpu_encap",
-          "id" : 37,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [55],
+          "action_ids" : [51],
           "actions" : ["spgw_egress.gtpu_encap"],
           "base_default_next" : null,
           "next_tables" : {
             "spgw_egress.gtpu_encap" : null
           },
           "default_entry" : {
-            "action_id" : 55,
+            "action_id" : 51,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -6056,10 +5629,10 @@
       "action_profiles" : [],
       "conditionals" : [
         {
-          "name" : "node_58",
-          "id" : 19,
+          "name" : "node_55",
+          "id" : 18,
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 38,
             "column" : 12,
             "source_fragment" : "standard_metadata.egress_port == 255"
@@ -6082,11 +5655,11 @@
           "false_next" : "tbl_act_19"
         },
         {
-          "name" : "node_61",
-          "id" : 20,
+          "name" : "node_58",
+          "id" : 19,
           "source_info" : {
-            "filename" : "./include/control/../spgw.p4",
-            "line" : 245,
+            "filename" : "include/spgw.p4",
+            "line" : 246,
             "column" : 12,
             "source_fragment" : "spgw_meta.do_spgw && spgw_meta.direction == DIR_DOWNLINK"
           },
@@ -6181,24 +5754,6 @@
           }
         }
       }
-    },
-    {
-      "name" : "cksum_2",
-      "id" : 3,
-      "target" : ["gtpu_udp", "checksum"],
-      "type" : "generic",
-      "calculation" : "calc_2",
-      "if_cond" : {
-        "type" : "expression",
-        "value" : {
-          "op" : "d2b",
-          "left" : null,
-          "right" : {
-            "type" : "field",
-            "value" : ["gtpu_udp", "$valid$"]
-          }
-        }
-      }
     }
   ],
   "force_arith" : [],
diff --git a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.p4info b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.p4info
index 848d0c0..47cdc57 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.p4info
+++ b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric-spgw.p4info
@@ -220,34 +220,6 @@
 }
 tables {
   preamble {
-    id: 33615204
-    name: "forwarding.multicast_v4"
-    alias: "multicast_v4"
-  }
-  match_fields {
-    id: 1
-    name: "hdr.vlan_tag.vlan_id"
-    bitwidth: 12
-    match_type: EXACT
-  }
-  match_fields {
-    id: 2
-    name: "hdr.ipv4.dst_addr"
-    bitwidth: 32
-    match_type: LPM
-  }
-  action_refs {
-    id: 16829931
-  }
-  action_refs {
-    id: 16800567
-    annotations: "@defaultonly()"
-  }
-  direct_resource_ids: 302009236
-  size: 1024
-}
-tables {
-  preamble {
     id: 33587782
     name: "forwarding.acl"
     alias: "acl"
@@ -400,28 +372,6 @@
   direct_resource_ids: 301993193
   size: 1024
 }
-tables {
-  preamble {
-    id: 33608545
-    name: "next.broadcast"
-    alias: "broadcast"
-  }
-  match_fields {
-    id: 1
-    name: "fabric_metadata.next_id"
-    bitwidth: 32
-    match_type: EXACT
-  }
-  action_refs {
-    id: 16778974
-  }
-  action_refs {
-    id: 16800567
-    annotations: "@defaultonly()"
-  }
-  direct_resource_ids: 301995093
-  size: 1024
-}
 actions {
   preamble {
     id: 16800567
@@ -613,23 +563,6 @@
 }
 actions {
   preamble {
-    id: 16778974
-    name: "next.set_mcast_group"
-    alias: "set_mcast_group"
-  }
-  params {
-    id: 1
-    name: "gid"
-    bitwidth: 16
-  }
-  params {
-    id: 2
-    name: "smac"
-    bitwidth: 48
-  }
-}
-actions {
-  preamble {
     id: 16841192
     name: "next.mpls_routing_v4"
     alias: "mpls_routing_v4"
@@ -789,17 +722,6 @@
 }
 direct_counters {
   preamble {
-    id: 302009236
-    name: "forwarding.multicast_v4_counter"
-    alias: "multicast_v4_counter"
-  }
-  spec {
-    unit: BOTH
-  }
-  direct_table_id: 33615204
-}
-direct_counters {
-  preamble {
     id: 302000008
     name: "forwarding.acl_counter"
     alias: "acl_counter"
@@ -831,17 +753,6 @@
   }
   direct_table_id: 33569488
 }
-direct_counters {
-  preamble {
-    id: 301995093
-    name: "next.broadcast_counter"
-    alias: "broadcast_counter"
-  }
-  spec {
-    unit: BOTH
-  }
-  direct_table_id: 33608545
-}
 controller_packet_metadata {
   preamble {
     id: 2868941301
diff --git a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json
index afa7f48..0462d6a 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json
@@ -254,12 +254,12 @@
   "header_union_stacks" : [],
   "field_lists" : [],
   "errors" : [
-    ["NoError", 0],
-    ["PacketTooShort", 1],
-    ["NoMatch", 2],
-    ["StackOutOfBounds", 3],
-    ["HeaderTooShort", 4],
-    ["ParserTimeout", 5]
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
   ],
   "enums" : [],
   "parsers" : [
@@ -672,7 +672,7 @@
       "name" : "deparser",
       "id" : 0,
       "source_info" : {
-        "filename" : "./include/parser.p4",
+        "filename" : "include/parser.p4",
         "line" : 164,
         "column" : 8,
         "source_fragment" : "FabricDeparser"
@@ -713,40 +713,28 @@
       "binding" : "forwarding.unicast_v4"
     },
     {
-      "name" : "forwarding.multicast_v4_counter",
-      "id" : 5,
-      "is_direct" : true,
-      "binding" : "forwarding.multicast_v4"
-    },
-    {
       "name" : "forwarding.acl_counter",
-      "id" : 6,
+      "id" : 5,
       "is_direct" : true,
       "binding" : "forwarding.acl"
     },
     {
       "name" : "next.simple_counter",
-      "id" : 7,
+      "id" : 6,
       "is_direct" : true,
       "binding" : "next.simple"
     },
     {
       "name" : "next.hashed_counter",
-      "id" : 8,
+      "id" : 7,
       "is_direct" : true,
       "binding" : "next.hashed"
     },
     {
-      "name" : "next.broadcast_counter",
-      "id" : 9,
-      "is_direct" : true,
-      "binding" : "next.broadcast"
-    },
-    {
       "name" : "port_counters_control.egress_port_counter",
-      "id" : 10,
+      "id" : 8,
       "source_info" : {
-        "filename" : "./include/control/port_counter.p4",
+        "filename" : "include/control/port_counter.p4",
         "line" : 23,
         "column" : 48,
         "source_fragment" : "egress_port_counter"
@@ -756,9 +744,9 @@
     },
     {
       "name" : "port_counters_control.ingress_port_counter",
-      "id" : 11,
+      "id" : 9,
       "source_info" : {
-        "filename" : "./include/control/port_counter.p4",
+        "filename" : "include/control/port_counter.p4",
         "line" : 24,
         "column" : 48,
         "source_fragment" : "ingress_port_counter"
@@ -773,7 +761,7 @@
       "name" : "calc",
       "id" : 0,
       "source_info" : {
-        "filename" : "./include/checksum.p4",
+        "filename" : "include/checksum.p4",
         "line" : 56,
         "column" : 8,
         "source_fragment" : "verify_checksum(hdr.ipv4.isValid(), ..."
@@ -830,7 +818,7 @@
       "name" : "calc_0",
       "id" : 1,
       "source_info" : {
-        "filename" : "./include/checksum.p4",
+        "filename" : "include/checksum.p4",
         "line" : 28,
         "column" : 8,
         "source_fragment" : "update_checksum(hdr.ipv4.isValid(), ..."
@@ -929,27 +917,15 @@
       "primitives" : []
     },
     {
-      "name" : "NoAction",
-      "id" : 7,
-      "runtime_data" : [],
-      "primitives" : []
-    },
-    {
-      "name" : "NoAction",
-      "id" : 8,
-      "runtime_data" : [],
-      "primitives" : []
-    },
-    {
       "name" : "filtering.drop",
-      "id" : 9,
+      "id" : 7,
       "runtime_data" : [],
       "primitives" : [
         {
           "op" : "drop",
           "parameters" : [],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 31,
             "column" : 8,
             "source_fragment" : "mark_to_drop()"
@@ -959,7 +935,7 @@
     },
     {
       "name" : "filtering.set_vlan",
-      "id" : 10,
+      "id" : 8,
       "runtime_data" : [
         {
           "name" : "new_vlan_id",
@@ -980,7 +956,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 35,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.vlan_id = new_vlan_id"
@@ -990,7 +966,7 @@
     },
     {
       "name" : "filtering.push_internal_vlan",
-      "id" : 11,
+      "id" : 9,
       "runtime_data" : [
         {
           "name" : "new_vlan_id",
@@ -1007,7 +983,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 41,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.setValid()"
@@ -1026,7 +1002,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 42,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.cfi = 0"
@@ -1045,7 +1021,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 43,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.pri = 0"
@@ -1064,7 +1040,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.ether_type = hdr.ethernet.ether_type"
@@ -1083,7 +1059,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 32,
             "column" : 31,
             "source_fragment" : "0x8100; ..."
@@ -1102,7 +1078,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 35,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.vlan_id = new_vlan_id; ..."
@@ -1131,7 +1107,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 49,
             "column" : 8,
             "source_fragment" : "fabric_metadata.pop_vlan_at_egress = true"
@@ -1141,7 +1117,7 @@
     },
     {
       "name" : "filtering.set_forwarding_type",
-      "id" : 12,
+      "id" : 10,
       "runtime_data" : [
         {
           "name" : "fwd_type",
@@ -1162,7 +1138,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 53,
             "column" : 8,
             "source_fragment" : "fabric_metadata.fwd_type = fwd_type"
@@ -1172,15 +1148,15 @@
     },
     {
       "name" : "forwarding.drop",
-      "id" : 13,
+      "id" : 11,
       "runtime_data" : [],
       "primitives" : [
         {
           "op" : "drop",
           "parameters" : [],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 37,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 36,
             "column" : 8,
             "source_fragment" : "mark_to_drop()"
           }
@@ -1189,6 +1165,68 @@
     },
     {
       "name" : "forwarding.set_next_id",
+      "id" : 12,
+      "runtime_data" : [
+        {
+          "name" : "next_id",
+          "bitwidth" : 32
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "fabric_metadata_t.next_id"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/forwarding.p4",
+            "line" : 40,
+            "column" : 8,
+            "source_fragment" : "fabric_metadata.next_id = next_id"
+          }
+        }
+      ]
+    },
+    {
+      "name" : "forwarding.set_next_id",
+      "id" : 13,
+      "runtime_data" : [
+        {
+          "name" : "next_id",
+          "bitwidth" : 32
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["scalars", "fabric_metadata_t.next_id"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/forwarding.p4",
+            "line" : 40,
+            "column" : 8,
+            "source_fragment" : "fabric_metadata.next_id = next_id"
+          }
+        }
+      ]
+    },
+    {
+      "name" : "forwarding.set_next_id",
       "id" : 14,
       "runtime_data" : [
         {
@@ -1210,101 +1248,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id"
-          }
-        }
-      ]
-    },
-    {
-      "name" : "forwarding.set_next_id",
-      "id" : 15,
-      "runtime_data" : [
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id"
-          }
-        }
-      ]
-    },
-    {
-      "name" : "forwarding.set_next_id",
-      "id" : 16,
-      "runtime_data" : [
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id"
-          }
-        }
-      ]
-    },
-    {
-      "name" : "forwarding.set_next_id",
-      "id" : 17,
-      "runtime_data" : [
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 41,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 40,
             "column" : 8,
             "source_fragment" : "fabric_metadata.next_id = next_id"
           }
@@ -1313,7 +1258,7 @@
     },
     {
       "name" : "forwarding.pop_mpls_and_next",
-      "id" : 18,
+      "id" : 15,
       "runtime_data" : [
         {
           "name" : "next_id",
@@ -1330,8 +1275,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 45,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.mpls.setInvalid()"
           }
@@ -1349,8 +1294,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 46,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 45,
             "column" : 8,
             "source_fragment" : "fabric_metadata.next_id = next_id"
           }
@@ -1359,7 +1304,7 @@
     },
     {
       "name" : "forwarding.duplicate_to_controller",
-      "id" : 19,
+      "id" : 16,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -1375,8 +1320,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 50,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 49,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = 255"
           }
@@ -1385,7 +1330,7 @@
     },
     {
       "name" : "next.output",
-      "id" : 20,
+      "id" : 17,
       "runtime_data" : [
         {
           "name" : "port_num",
@@ -1406,8 +1351,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num"
           }
@@ -1416,7 +1361,7 @@
     },
     {
       "name" : "next.set_vlan_output",
-      "id" : 21,
+      "id" : 18,
       "runtime_data" : [
         {
           "name" : "new_vlan_id",
@@ -1441,8 +1386,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 37,
+            "filename" : "include/control/next.p4",
+            "line" : 36,
             "column" : 8,
             "source_fragment" : "hdr.vlan_tag.vlan_id = new_vlan_id"
           }
@@ -1470,8 +1415,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 40,
+            "filename" : "include/control/next.p4",
+            "line" : 39,
             "column" : 8,
             "source_fragment" : "fabric_metadata.pop_vlan_at_egress = false"
           }
@@ -1489,8 +1434,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
           }
@@ -1499,6 +1444,351 @@
     },
     {
       "name" : "next.l3_routing",
+      "id" : 19,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 44,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 48,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 32,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "next.l3_routing",
+      "id" : 20,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 44,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 48,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 32,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "next.mpls_routing_v4",
+      "id" : 21,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 44,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 48,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 32,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        },
+        {
+          "op" : "add_header",
+          "parameters" : [
+            {
+              "type" : "header",
+              "value" : "mpls"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 59,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.setValid()"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["vlan_tag", "ether_type"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x8847"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 33,
+            "column" : 31,
+            "source_fragment" : "0x8847; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "label"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 3
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 61,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.label = label; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "tc"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x00"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 62,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.tc = tc; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "bos"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 63,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.bos = 1w1"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "ttl"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x40"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 67,
+            "column" : 32,
+            "source_fragment" : "64; ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "next.mpls_routing_v4",
       "id" : 22,
       "runtime_data" : [
         {
@@ -1512,6 +1802,10 @@
         {
           "name" : "dmac",
           "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
         }
       ],
       "primitives" : [
@@ -1528,8 +1822,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
+            "filename" : "include/control/next.p4",
+            "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
           }
@@ -1547,8 +1841,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
+            "filename" : "include/control/next.p4",
+            "line" : 48,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
           }
@@ -1566,16 +1860,126 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
           }
+        },
+        {
+          "op" : "add_header",
+          "parameters" : [
+            {
+              "type" : "header",
+              "value" : "mpls"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 59,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.setValid()"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["vlan_tag", "ether_type"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x8847"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 33,
+            "column" : 31,
+            "source_fragment" : "0x8847; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "label"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 3
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 61,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.label = label; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "tc"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x00"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 62,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.tc = tc; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "bos"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 63,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.bos = 1w1"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "ttl"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x40"
+            }
+          ],
+          "source_info" : {
+            "filename" : "include/control/../define.p4",
+            "line" : 67,
+            "column" : 32,
+            "source_fragment" : "64; ..."
+          }
         }
       ]
     },
     {
-      "name" : "next.l3_routing",
+      "name" : "next.mpls_routing_v6",
       "id" : 23,
       "runtime_data" : [
         {
@@ -1589,6 +1993,10 @@
         {
           "name" : "dmac",
           "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
         }
       ],
       "primitives" : [
@@ -1605,8 +2013,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
+            "filename" : "include/control/next.p4",
+            "line" : 44,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
           }
@@ -1624,8 +2032,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
+            "filename" : "include/control/next.p4",
+            "line" : 48,
             "column" : 8,
             "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
           }
@@ -1643,159 +2051,24 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
+            "filename" : "include/control/next.p4",
+            "line" : 32,
             "column" : 8,
             "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
           }
-        }
-      ]
-    },
-    {
-      "name" : "next.set_mcast_group",
-      "id" : 24,
-      "runtime_data" : [
-        {
-          "name" : "gid",
-          "bitwidth" : 16
         },
         {
-          "name" : "smac",
-          "bitwidth" : 48
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
+          "op" : "add_header",
           "parameters" : [
             {
-              "type" : "field",
-              "value" : ["standard_metadata", "mcast_grp"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
+              "type" : "header",
+              "value" : "mpls"
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
+            "filename" : "include/control/next.p4",
             "line" : 59,
             "column" : 8,
-            "source_fragment" : "standard_metadata.mcast_grp = gid"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        }
-      ]
-    },
-    {
-      "name" : "next.mpls_routing_v4",
-      "id" : 25,
-      "runtime_data" : [
-        {
-          "name" : "port_num",
-          "bitwidth" : 9
-        },
-        {
-          "name" : "smac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "dmac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "dst_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 2
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["standard_metadata", "egress_spec"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
-            "column" : 8,
-            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 65,
-            "column" : 8,
             "source_fragment" : "hdr.mpls.setValid()"
           }
         },
@@ -1812,7 +2085,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 33,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
@@ -1831,8 +2104,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 67,
+            "filename" : "include/control/next.p4",
+            "line" : 61,
             "column" : 8,
             "source_fragment" : "hdr.mpls.label = label; ..."
           }
@@ -1850,8 +2123,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 68,
+            "filename" : "include/control/next.p4",
+            "line" : 62,
             "column" : 8,
             "source_fragment" : "hdr.mpls.tc = tc; ..."
           }
@@ -1869,8 +2142,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 69,
+            "filename" : "include/control/next.p4",
+            "line" : 63,
             "column" : 8,
             "source_fragment" : "hdr.mpls.bos = 1w1"
           }
@@ -1888,389 +2161,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 67,
-            "column" : 32,
-            "source_fragment" : "64; ..."
-          }
-        }
-      ]
-    },
-    {
-      "name" : "next.mpls_routing_v4",
-      "id" : 26,
-      "runtime_data" : [
-        {
-          "name" : "port_num",
-          "bitwidth" : 9
-        },
-        {
-          "name" : "smac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "dmac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "dst_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 2
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["standard_metadata", "egress_spec"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
-            "column" : 8,
-            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 65,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.setValid()"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["vlan_tag", "ether_type"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x8847"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 33,
-            "column" : 31,
-            "source_fragment" : "0x8847; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "label"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 3
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 67,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.label = label; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "tc"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x00"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 68,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.tc = tc; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "bos"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x01"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 69,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.bos = 1w1"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "ttl"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x40"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 67,
-            "column" : 32,
-            "source_fragment" : "64; ..."
-          }
-        }
-      ]
-    },
-    {
-      "name" : "next.mpls_routing_v6",
-      "id" : 27,
-      "runtime_data" : [
-        {
-          "name" : "port_num",
-          "bitwidth" : 9
-        },
-        {
-          "name" : "smac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "dmac",
-          "bitwidth" : 48
-        },
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "src_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 45,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "dst_addr"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 2
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 49,
-            "column" : 8,
-            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["standard_metadata", "egress_spec"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 33,
-            "column" : 8,
-            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 65,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.setValid()"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["vlan_tag", "ether_type"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x8847"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 33,
-            "column" : 31,
-            "source_fragment" : "0x8847; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "label"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 3
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 67,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.label = label; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "tc"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x00"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 68,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.tc = tc; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "bos"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x01"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 69,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.bos = 1w1"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "ttl"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x40"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 67,
             "column" : 32,
             "source_fragment" : "64; ..."
@@ -2280,7 +2171,7 @@
     },
     {
       "name" : "act",
-      "id" : 28,
+      "id" : 24,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2296,7 +2187,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 26,
             "column" : 12,
             "source_fragment" : "standard_metadata.egress_spec = hdr.packet_out.egress_port"
@@ -2311,7 +2202,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 27,
             "column" : 12,
             "source_fragment" : "hdr.packet_out.setInvalid()"
@@ -2321,7 +2212,7 @@
     },
     {
       "name" : "act_0",
-      "id" : 29,
+      "id" : 25,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2337,7 +2228,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 35,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
@@ -2356,7 +2247,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../define.p4",
+            "filename" : "include/control/../define.p4",
             "line" : 35,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
@@ -2366,7 +2257,7 @@
     },
     {
       "name" : "act_1",
-      "id" : 30,
+      "id" : 26,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2396,7 +2287,7 @@
     },
     {
       "name" : "act_2",
-      "id" : 31,
+      "id" : 27,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2426,7 +2317,7 @@
     },
     {
       "name" : "act_3",
-      "id" : 32,
+      "id" : 28,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2465,8 +2356,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 140,
+            "filename" : "include/control/next.p4",
+            "line" : 143,
             "column" : 20,
             "source_fragment" : "hdr.ipv4.ttl = hdr.ipv4.ttl - 1"
           }
@@ -2475,7 +2366,7 @@
     },
     {
       "name" : "act_4",
-      "id" : 33,
+      "id" : 29,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2517,7 +2408,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 28,
             "column" : 12,
             "source_fragment" : "egress_port_counter.count((bit<32>)standard_metadata.egress_spec)"
@@ -2527,7 +2418,7 @@
     },
     {
       "name" : "act_5",
-      "id" : 34,
+      "id" : 30,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2569,7 +2460,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 31,
             "column" : 12,
             "source_fragment" : "ingress_port_counter.count((bit<32>)standard_metadata.ingress_port)"
@@ -2579,7 +2470,7 @@
     },
     {
       "name" : "act_6",
-      "id" : 35,
+      "id" : 31,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2595,8 +2486,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 162,
+            "filename" : "include/control/next.p4",
+            "line" : 167,
             "column" : 12,
             "source_fragment" : "hdr.ethernet.ether_type = hdr.vlan_tag.ether_type"
           }
@@ -2610,8 +2501,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 163,
+            "filename" : "include/control/next.p4",
+            "line" : 168,
             "column" : 12,
             "source_fragment" : "hdr.vlan_tag.setInvalid()"
           }
@@ -2620,7 +2511,7 @@
     },
     {
       "name" : "act_7",
-      "id" : 36,
+      "id" : 32,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2632,7 +2523,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 39,
             "column" : 12,
             "source_fragment" : "hdr.packet_in.setValid()"
@@ -2651,7 +2542,7 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 40,
             "column" : 12,
             "source_fragment" : "hdr.packet_in.ingress_port = standard_metadata.ingress_port"
@@ -2682,14 +2573,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [28],
+          "action_ids" : [24],
           "actions" : ["act"],
           "base_default_next" : null,
           "next_tables" : {
             "act" : null
           },
           "default_entry" : {
-            "action_id" : 28,
+            "action_id" : 24,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -2699,7 +2590,7 @@
           "name" : "filtering.ingress_port_vlan",
           "id" : 1,
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 57,
             "column" : 10,
             "source_fragment" : "ingress_port_vlan"
@@ -2727,7 +2618,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [11, 10, 0, 9],
+          "action_ids" : [9, 8, 0, 7],
           "actions" : ["filtering.push_internal_vlan", "filtering.set_vlan", "nop", "filtering.drop"],
           "base_default_next" : "filtering.fwd_classifier",
           "next_tables" : {
@@ -2747,7 +2638,7 @@
           "name" : "filtering.fwd_classifier",
           "id" : 2,
           "source_info" : {
-            "filename" : "./include/control/filtering.p4",
+            "filename" : "include/control/filtering.p4",
             "line" : 76,
             "column" : 10,
             "source_fragment" : "fwd_classifier"
@@ -2775,14 +2666,14 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [12],
+          "action_ids" : [10],
           "actions" : ["filtering.set_forwarding_type"],
           "base_default_next" : "node_6",
           "next_tables" : {
             "filtering.set_forwarding_type" : "node_6"
           },
           "default_entry" : {
-            "action_id" : 12,
+            "action_id" : 10,
             "action_const" : true,
             "action_data" : ["0x0"],
             "action_entry_const" : true
@@ -2792,8 +2683,8 @@
           "name" : "forwarding.bridging",
           "id" : 3,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 53,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 52,
             "column" : 10,
             "source_fragment" : "bridging"
           },
@@ -2815,7 +2706,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [14, 2],
+          "action_ids" : [12, 2],
           "actions" : ["forwarding.set_next_id", "NoAction"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
@@ -2833,8 +2724,8 @@
           "name" : "forwarding.mpls",
           "id" : 4,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 65,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 64,
             "column" : 10,
             "source_fragment" : "mpls"
           },
@@ -2851,7 +2742,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [18, 3],
+          "action_ids" : [15, 3],
           "actions" : ["forwarding.pop_mpls_and_next", "NoAction"],
           "base_default_next" : "tbl_act_0",
           "next_tables" : {
@@ -2875,14 +2766,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [29],
+          "action_ids" : [25],
           "actions" : ["act_0"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
             "act_0" : "forwarding.acl"
           },
           "default_entry" : {
-            "action_id" : 29,
+            "action_id" : 25,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -2892,8 +2783,8 @@
           "name" : "forwarding.unicast_v4",
           "id" : 6,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 76,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 75,
             "column" : 10,
             "source_fragment" : "unicast_v4"
           },
@@ -2910,7 +2801,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [15, 4],
+          "action_ids" : [13, 4],
           "actions" : ["forwarding.set_next_id", "NoAction"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
@@ -2925,53 +2816,12 @@
           }
         },
         {
-          "name" : "forwarding.multicast_v4",
+          "name" : "forwarding.acl",
           "id" : 7,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 87,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 133,
             "column" : 10,
-            "source_fragment" : "multicast_v4"
-          },
-          "key" : [
-            {
-              "match_type" : "exact",
-              "target" : ["vlan_tag", "vlan_id"],
-              "mask" : null
-            },
-            {
-              "match_type" : "lpm",
-              "target" : ["ipv4", "dst_addr"],
-              "mask" : null
-            }
-          ],
-          "match_type" : "lpm",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : true,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [16, 5],
-          "actions" : ["forwarding.set_next_id", "NoAction"],
-          "base_default_next" : "forwarding.acl",
-          "next_tables" : {
-            "forwarding.set_next_id" : "forwarding.acl",
-            "NoAction" : "forwarding.acl"
-          },
-          "default_entry" : {
-            "action_id" : 5,
-            "action_const" : false,
-            "action_data" : [],
-            "action_entry_const" : false
-          }
-        },
-        {
-          "name" : "forwarding.acl",
-          "id" : 8,
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 127,
-            "column" : 7,
             "source_fragment" : "acl"
           },
           "key" : [
@@ -3042,7 +2892,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [17, 19, 13, 1],
+          "action_ids" : [14, 16, 11, 1],
           "actions" : ["forwarding.set_next_id", "forwarding.duplicate_to_controller", "forwarding.drop", "nop"],
           "base_default_next" : "next.simple",
           "next_tables" : {
@@ -3060,10 +2910,10 @@
         },
         {
           "name" : "next.simple",
-          "id" : 9,
+          "id" : 8,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 89,
+            "filename" : "include/control/next.p4",
+            "line" : 83,
             "column" : 10,
             "source_fragment" : "simple"
           },
@@ -3080,7 +2930,7 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [20, 21, 22, 25, 6],
+          "action_ids" : [17, 18, 19, 21, 5],
           "actions" : ["next.output", "next.set_vlan_output", "next.l3_routing", "next.mpls_routing_v4", "NoAction"],
           "base_default_next" : null,
           "next_tables" : {
@@ -3088,7 +2938,7 @@
             "__MISS__" : "tbl_act_2"
           },
           "default_entry" : {
-            "action_id" : 6,
+            "action_id" : 5,
             "action_const" : false,
             "action_data" : [],
             "action_entry_const" : false
@@ -3096,6 +2946,29 @@
         },
         {
           "name" : "tbl_act_1",
+          "id" : 9,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [26],
+          "actions" : ["act_1"],
+          "base_default_next" : "node_17",
+          "next_tables" : {
+            "act_1" : "node_17"
+          },
+          "default_entry" : {
+            "action_id" : 26,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_act_2",
           "id" : 10,
           "key" : [],
           "match_type" : "exact",
@@ -3104,21 +2977,21 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [30],
-          "actions" : ["act_1"],
-          "base_default_next" : "node_19",
+          "action_ids" : [27],
+          "actions" : ["act_2"],
+          "base_default_next" : "node_17",
           "next_tables" : {
-            "act_1" : "node_19"
+            "act_2" : "node_17"
           },
           "default_entry" : {
-            "action_id" : 30,
+            "action_id" : 27,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
           }
         },
         {
-          "name" : "tbl_act_2",
+          "name" : "tbl_act_3",
           "id" : 11,
           "key" : [],
           "match_type" : "exact",
@@ -3127,37 +3000,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [31],
-          "actions" : ["act_2"],
-          "base_default_next" : "node_19",
-          "next_tables" : {
-            "act_2" : "node_19"
-          },
-          "default_entry" : {
-            "action_id" : 31,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_act_3",
-          "id" : 12,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [32],
+          "action_ids" : [28],
           "actions" : ["act_3"],
           "base_default_next" : "next.hashed",
           "next_tables" : {
             "act_3" : "next.hashed"
           },
           "default_entry" : {
-            "action_id" : 32,
+            "action_id" : 28,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -3165,10 +3015,10 @@
         },
         {
           "name" : "next.hashed",
-          "id" : 13,
+          "id" : 12,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 103,
+            "filename" : "include/control/next.p4",
+            "line" : 97,
             "column" : 10,
             "source_fragment" : "hashed"
           },
@@ -3186,54 +3036,64 @@
           "with_counters" : true,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [23, 26, 27, 7],
+          "action_ids" : [20, 22, 23, 6],
           "actions" : ["next.l3_routing", "next.mpls_routing_v4", "next.mpls_routing_v6", "NoAction"],
-          "base_default_next" : "next.broadcast",
+          "base_default_next" : "node_22",
           "next_tables" : {
-            "next.l3_routing" : "next.broadcast",
-            "next.mpls_routing_v4" : "next.broadcast",
-            "next.mpls_routing_v6" : "next.broadcast",
-            "NoAction" : "next.broadcast"
-          }
-        },
-        {
-          "name" : "next.broadcast",
-          "id" : 14,
-          "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 126,
-            "column" : 10,
-            "source_fragment" : "broadcast"
-          },
-          "key" : [
-            {
-              "match_type" : "exact",
-              "target" : ["scalars", "fabric_metadata_t.next_id"],
-              "mask" : null
-            }
-          ],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : true,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [24, 8],
-          "actions" : ["next.set_mcast_group", "NoAction"],
-          "base_default_next" : "node_25",
-          "next_tables" : {
-            "next.set_mcast_group" : "node_25",
-            "NoAction" : "node_25"
-          },
-          "default_entry" : {
-            "action_id" : 8,
-            "action_const" : false,
-            "action_data" : [],
-            "action_entry_const" : false
+            "next.l3_routing" : "node_22",
+            "next.mpls_routing_v4" : "node_22",
+            "next.mpls_routing_v6" : "node_22",
+            "NoAction" : "node_22"
           }
         },
         {
           "name" : "tbl_act_4",
+          "id" : 13,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [29],
+          "actions" : ["act_4"],
+          "base_default_next" : "node_24",
+          "next_tables" : {
+            "act_4" : "node_24"
+          },
+          "default_entry" : {
+            "action_id" : 29,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_act_5",
+          "id" : 14,
+          "key" : [],
+          "match_type" : "exact",
+          "type" : "simple",
+          "max_size" : 1024,
+          "with_counters" : false,
+          "support_timeout" : false,
+          "direct_meters" : null,
+          "action_ids" : [30],
+          "actions" : ["act_5"],
+          "base_default_next" : "node_26",
+          "next_tables" : {
+            "act_5" : "node_26"
+          },
+          "default_entry" : {
+            "action_id" : 30,
+            "action_const" : true,
+            "action_data" : [],
+            "action_entry_const" : true
+          }
+        },
+        {
+          "name" : "tbl_act_6",
           "id" : 15,
           "key" : [],
           "match_type" : "exact",
@@ -3242,60 +3102,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [33],
-          "actions" : ["act_4"],
-          "base_default_next" : "node_27",
-          "next_tables" : {
-            "act_4" : "node_27"
-          },
-          "default_entry" : {
-            "action_id" : 33,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_act_5",
-          "id" : 16,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [34],
-          "actions" : ["act_5"],
-          "base_default_next" : "node_29",
-          "next_tables" : {
-            "act_5" : "node_29"
-          },
-          "default_entry" : {
-            "action_id" : 34,
-            "action_const" : true,
-            "action_data" : [],
-            "action_entry_const" : true
-          }
-        },
-        {
-          "name" : "tbl_act_6",
-          "id" : 17,
-          "key" : [],
-          "match_type" : "exact",
-          "type" : "simple",
-          "max_size" : 1024,
-          "with_counters" : false,
-          "support_timeout" : false,
-          "direct_meters" : null,
-          "action_ids" : [35],
+          "action_ids" : [31],
           "actions" : ["act_6"],
           "base_default_next" : null,
           "next_tables" : {
             "act_6" : null
           },
           "default_entry" : {
-            "action_id" : 35,
+            "action_id" : 31,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -3339,7 +3153,7 @@
           "name" : "node_2",
           "id" : 0,
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 25,
             "column" : 12,
             "source_fragment" : "hdr.packet_out.isValid()"
@@ -3362,8 +3176,8 @@
           "name" : "node_6",
           "id" : 1,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 157,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 163,
             "column" : 11,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_BRIDGING"
           },
@@ -3388,8 +3202,8 @@
           "name" : "node_8",
           "id" : 2,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 158,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 164,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_MPLS"
           },
@@ -3414,8 +3228,8 @@
           "name" : "node_11",
           "id" : 3,
           "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 165,
+            "filename" : "include/control/forwarding.p4",
+            "line" : 179,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV4_UNICAST"
           },
@@ -3434,37 +3248,11 @@
             }
           },
           "true_next" : "forwarding.unicast_v4",
-          "false_next" : "node_13"
-        },
-        {
-          "name" : "node_13",
-          "id" : 4,
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 166,
-            "column" : 17,
-            "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV4_MULTICAST"
-          },
-          "expression" : {
-            "type" : "expression",
-            "value" : {
-              "op" : "==",
-              "left" : {
-                "type" : "field",
-                "value" : ["scalars", "fabric_metadata_t.fwd_type"]
-              },
-              "right" : {
-                "type" : "hexstr",
-                "value" : "0x03"
-              }
-            }
-          },
-          "true_next" : "forwarding.multicast_v4",
           "false_next" : "forwarding.acl"
         },
         {
-          "name" : "node_19",
-          "id" : 5,
+          "name" : "node_17",
+          "id" : 4,
           "expression" : {
             "type" : "expression",
             "value" : {
@@ -3476,15 +3264,15 @@
               }
             }
           },
-          "true_next" : "node_20",
+          "true_next" : "node_18",
           "false_next" : "next.hashed"
         },
         {
-          "name" : "node_20",
-          "id" : 6,
+          "name" : "node_18",
+          "id" : 5,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 138,
+            "filename" : "include/control/next.p4",
+            "line" : 141,
             "column" : 16,
             "source_fragment" : "!hdr.mpls.isValid()"
           },
@@ -3506,15 +3294,15 @@
               }
             }
           },
-          "true_next" : "node_21",
+          "true_next" : "node_19",
           "false_next" : "next.hashed"
         },
         {
-          "name" : "node_21",
-          "id" : 7,
+          "name" : "node_19",
+          "id" : 6,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 139,
+            "filename" : "include/control/next.p4",
+            "line" : 142,
             "column" : 19,
             "source_fragment" : "hdr.ipv4.isValid()"
           },
@@ -3533,10 +3321,10 @@
           "false_next" : "next.hashed"
         },
         {
-          "name" : "node_25",
-          "id" : 8,
+          "name" : "node_22",
+          "id" : 7,
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 27,
             "column" : 12,
             "source_fragment" : "standard_metadata.egress_spec < 511"
@@ -3556,13 +3344,13 @@
             }
           },
           "true_next" : "tbl_act_4",
-          "false_next" : "node_27"
+          "false_next" : "node_24"
         },
         {
-          "name" : "node_27",
-          "id" : 9,
+          "name" : "node_24",
+          "id" : 8,
           "source_info" : {
-            "filename" : "./include/control/port_counter.p4",
+            "filename" : "include/control/port_counter.p4",
             "line" : 30,
             "column" : 12,
             "source_fragment" : "standard_metadata.ingress_port < 511"
@@ -3582,14 +3370,14 @@
             }
           },
           "true_next" : "tbl_act_5",
-          "false_next" : "node_29"
+          "false_next" : "node_26"
         },
         {
-          "name" : "node_29",
-          "id" : 10,
+          "name" : "node_26",
+          "id" : 9,
           "source_info" : {
-            "filename" : "./include/control/next.p4",
-            "line" : 161,
+            "filename" : "include/control/next.p4",
+            "line" : 166,
             "column" : 12,
             "source_fragment" : "fabric_metadata.pop_vlan_at_egress"
           },
@@ -3618,11 +3406,11 @@
         "column" : 8,
         "source_fragment" : "FabricEgress"
       },
-      "init_table" : "node_33",
+      "init_table" : "node_30",
       "tables" : [
         {
           "name" : "tbl_act_7",
-          "id" : 18,
+          "id" : 16,
           "key" : [],
           "match_type" : "exact",
           "type" : "simple",
@@ -3630,14 +3418,14 @@
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [36],
+          "action_ids" : [32],
           "actions" : ["act_7"],
           "base_default_next" : null,
           "next_tables" : {
             "act_7" : null
           },
           "default_entry" : {
-            "action_id" : 36,
+            "action_id" : 32,
             "action_const" : true,
             "action_data" : [],
             "action_entry_const" : true
@@ -3647,10 +3435,10 @@
       "action_profiles" : [],
       "conditionals" : [
         {
-          "name" : "node_33",
-          "id" : 11,
+          "name" : "node_30",
+          "id" : 10,
           "source_info" : {
-            "filename" : "./include/control/packetio.p4",
+            "filename" : "include/control/packetio.p4",
             "line" : 38,
             "column" : 12,
             "source_fragment" : "standard_metadata.egress_port == 255"
diff --git a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info
index d028872..76c24ca 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info
+++ b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info
@@ -143,34 +143,6 @@
 }
 tables {
   preamble {
-    id: 33615204
-    name: "forwarding.multicast_v4"
-    alias: "multicast_v4"
-  }
-  match_fields {
-    id: 1
-    name: "hdr.vlan_tag.vlan_id"
-    bitwidth: 12
-    match_type: EXACT
-  }
-  match_fields {
-    id: 2
-    name: "hdr.ipv4.dst_addr"
-    bitwidth: 32
-    match_type: LPM
-  }
-  action_refs {
-    id: 16829931
-  }
-  action_refs {
-    id: 16800567
-    annotations: "@defaultonly()"
-  }
-  direct_resource_ids: 302009236
-  size: 1024
-}
-tables {
-  preamble {
     id: 33587782
     name: "forwarding.acl"
     alias: "acl"
@@ -323,28 +295,6 @@
   direct_resource_ids: 301993193
   size: 1024
 }
-tables {
-  preamble {
-    id: 33608545
-    name: "next.broadcast"
-    alias: "broadcast"
-  }
-  match_fields {
-    id: 1
-    name: "fabric_metadata.next_id"
-    bitwidth: 32
-    match_type: EXACT
-  }
-  action_refs {
-    id: 16778974
-  }
-  action_refs {
-    id: 16800567
-    annotations: "@defaultonly()"
-  }
-  direct_resource_ids: 301995093
-  size: 1024
-}
 actions {
   preamble {
     id: 16819938
@@ -493,23 +443,6 @@
 }
 actions {
   preamble {
-    id: 16778974
-    name: "next.set_mcast_group"
-    alias: "set_mcast_group"
-  }
-  params {
-    id: 1
-    name: "gid"
-    bitwidth: 16
-  }
-  params {
-    id: 2
-    name: "smac"
-    bitwidth: 48
-  }
-}
-actions {
-  preamble {
     id: 16841192
     name: "next.mpls_routing_v4"
     alias: "mpls_routing_v4"
@@ -651,17 +584,6 @@
 }
 direct_counters {
   preamble {
-    id: 302009236
-    name: "forwarding.multicast_v4_counter"
-    alias: "multicast_v4_counter"
-  }
-  spec {
-    unit: BOTH
-  }
-  direct_table_id: 33615204
-}
-direct_counters {
-  preamble {
     id: 302000008
     name: "forwarding.acl_counter"
     alias: "acl_counter"
@@ -693,17 +615,6 @@
   }
   direct_table_id: 33569488
 }
-direct_counters {
-  preamble {
-    id: 301995093
-    name: "next.broadcast_counter"
-    alias: "broadcast_counter"
-  }
-  spec {
-    unit: BOTH
-  }
-  direct_table_id: 33608545
-}
 controller_packet_metadata {
   preamble {
     id: 2868941301
diff --git a/pipelines/fabric/src/test/p4/fabric-spgw/downlink-post-mpls.pcap b/pipelines/fabric/src/test/p4/fabric-spgw/downlink-post-mpls.pcap
new file mode 100644
index 0000000..0f2d27b
--- /dev/null
+++ b/pipelines/fabric/src/test/p4/fabric-spgw/downlink-post-mpls.pcap
Binary files differ
diff --git a/pipelines/fabric/src/test/p4/fabric-spgw/entries-mpls-dl.json b/pipelines/fabric/src/test/p4/fabric-spgw/entries-mpls-dl.json
new file mode 100644
index 0000000..6bc9bce
--- /dev/null
+++ b/pipelines/fabric/src/test/p4/fabric-spgw/entries-mpls-dl.json
@@ -0,0 +1,130 @@
+{
+  "fabric-spgw": {
+    "addr": "localhost:50051",
+    "flows": [
+      {
+        "table_name": "filtering.ingress_port_vlan",
+        "match_fields": {
+          "standard_metadata.ingress_port": 1,
+          "hdr.vlan_tag.is_valid": 0,
+          "hdr.vlan_tag.vlan_id": [0, 0]
+        },
+        "action_name": "filtering.push_internal_vlan",
+        "action_params": {
+          "new_vlan_id": 4094
+        }
+      },
+      {
+        "table_name": "filtering.fwd_classifier",
+        "match_fields": {
+          "standard_metadata.ingress_port": 1,
+          "hdr.ethernet.dst_addr": "c2:42:59:2d:3a:84",
+          "fabric_metadata.original_ether_type": 2048
+        },
+        "action_name": "filtering.set_forwarding_type",
+        "action_params": {
+          "fwd_type": 2
+        }
+      },
+      {
+        "table_name": "forwarding.unicast_v4",
+        "match_fields": {
+          "hdr.ipv4.dst_addr": ["192.168.103.11", 32]
+        },
+        "action_name": "forwarding.set_next_id",
+        "action_params": {
+          "next_id": 1
+        }
+      },
+      {
+        "table_name": "next.simple",
+        "match_fields": {
+          "fabric_metadata.next_id": 1
+        },
+        "action_name": "next.l3_routing",
+        "action_params": {
+          "port_num": 2,
+          "smac": "3a:c1:e2:53:e1:50",
+          "dmac": "52:54:00:29:c9:b7"
+        }
+      },
+      {
+        "table_name": "filtering.ingress_port_vlan",
+        "match_fields": {
+          "standard_metadata.ingress_port": 2,
+          "hdr.vlan_tag.is_valid": 0,
+          "hdr.vlan_tag.vlan_id": [0, 0]
+        },
+        "action_name": "filtering.push_internal_vlan",
+        "action_params": {
+          "new_vlan_id": 20
+        }
+      },
+      {
+        "table_name": "filtering.fwd_classifier",
+        "match_fields": {
+          "standard_metadata.ingress_port": 2,
+          "hdr.ethernet.dst_addr": "3a:c1:e2:53:e1:50",
+          "fabric_metadata.original_ether_type": 2048
+        },
+        "action_name": "filtering.set_forwarding_type",
+        "action_params": {
+          "fwd_type": 2
+        }
+      },
+      {
+        "table_name": "forwarding.unicast_v4",
+        "match_fields": {
+          "hdr.ipv4.dst_addr": ["16.255.255.252", 32]
+        },
+        "action_name": "forwarding.set_next_id",
+        "action_params": {
+          "next_id": 2
+        }
+      },
+      {
+        "table_name": "next.simple",
+        "match_fields": {
+          "fabric_metadata.next_id": 2
+        },
+        "action_name": "next.mpls_routing_v4",
+        "action_params": {
+          "port_num": 1,
+          "smac": "c2:42:59:2d:3a:84",
+          "dmac": "52:54:00:05:7b:59",
+          "label": 204
+        }
+      },
+      {
+        "table_name": "spgw_ingress.ue_filter_table",
+        "match_fields": {
+          "ipv4.dst_addr": ["16.255.255.252", 32]
+        },
+        "action_name": "NoAction",
+        "action_params": {
+        }
+      },
+      {
+        "table_name": "spgw_ingress.s1u_filter_table",
+        "match_fields": {
+          "spgw_meta.s1u_sgw_addr": "192.168.102.13"
+        },
+        "action_name": "NoAction",
+        "action_params": {
+        }
+      },
+      {
+        "table_name": "spgw_ingress.dl_sess_lookup",
+        "match_fields": {
+          "ipv4.dst_addr": "16.255.255.252"
+        },
+        "action_name": "spgw_ingress.set_dl_sess_info",
+        "action_params": {
+          "teid": 1,
+          "s1u_enb_addr": "192.168.102.11",
+          "s1u_sgw_addr": "192.168.102.13"
+        }
+      }
+    ]
+  }
+}
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityInteger.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityInteger.java
index 745a831..cabe74d 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityInteger.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityInteger.java
@@ -104,9 +104,7 @@
 
         while (listIterator.hasNext()) {
             Integer integer = listIterator.next();
-            if (integer instanceof Integer) {
-                c.writeInt(integer);
-            }
+            c.writeInt(integer);
         }
 
         int length = c.writerIndex() - iLengthIndex;
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityIpV4Neighbour.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityIpV4Neighbour.java
index 96f4540..fa4ad67 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityIpV4Neighbour.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/WideCommunityIpV4Neighbour.java
@@ -96,10 +96,8 @@
 
         while (listIterator.hasNext()) {
             IpV4Neighbour speaker = listIterator.next();
-            if (speaker instanceof IpV4Neighbour) {
-                c.writeBytes(speaker.localSpeaker().toOctets());
-                c.writeBytes(speaker.remoteSpeaker().toOctets());
-            }
+            c.writeBytes(speaker.localSpeaker().toOctets());
+            c.writeBytes(speaker.remoteSpeaker().toOctets());
         }
 
         int length = c.writerIndex() - iLengthIndex;
diff --git a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java
index 036d8e6..01b7378 100644
--- a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java
+++ b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java
@@ -352,7 +352,7 @@
         }
 
         // set handshake completion status
-        public void setHandshakeComplete(boolean handshakeComplete) {
+        private void setHandshakeComplete(boolean handshakeComplete) {
             this.handshakeComplete = handshakeComplete;
         }
 
diff --git a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
index bbcd99f..6f233c8 100644
--- a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
+++ b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
@@ -171,6 +171,7 @@
             } catch (InterruptedException e) {
                 log.warn("Channel {} didn't shut down in time.");
                 channel.shutdownNow();
+                Thread.currentThread().interrupt();
             }
 
             channels.remove(channelId);
diff --git a/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java
index e8dc9f0..8e1006e 100644
--- a/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java
+++ b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java
@@ -94,9 +94,8 @@
      * Updates the processes configuration.
      *
      * @param jsonNode json node instance
-     * @throws Exception might throws parse exception
      */
-    public void updateConfig(JsonNode jsonNode) throws Exception {
+    public void updateConfig(JsonNode jsonNode) {
         log.debug("Controller::UpdateConfig called");
         configPacket = new byte[IsisConstants.CONFIG_LENGTH];
         byte numberOfInterface = 0; // number of interfaces to configure
diff --git a/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/IsisChannelHandler.java b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/IsisChannelHandler.java
index da0c946..937935b 100644
--- a/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/IsisChannelHandler.java
+++ b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/IsisChannelHandler.java
@@ -236,9 +236,8 @@
      *
      * @param isisMessage received ISIS message
      * @param ctx         channel handler context instance.
-     * @throws Exception might throws exception
      */
-    public void processIsisMessage(IsisMessage isisMessage, ChannelHandlerContext ctx) throws Exception {
+    public void processIsisMessage(IsisMessage isisMessage, ChannelHandlerContext ctx) {
         log.debug("IsisChannelHandler::processIsisMessage...!!!");
         int interfaceIndex = isisMessage.interfaceIndex();
         IsisInterface isisInterface = isisInterfaceMap.get(interfaceIndex);
diff --git a/protocols/isis/isisio/src/main/java/org/onosproject/isis/io/isispacket/IsisMessageReader.java b/protocols/isis/isisio/src/main/java/org/onosproject/isis/io/isispacket/IsisMessageReader.java
index 09cac03..883a892 100644
--- a/protocols/isis/isisio/src/main/java/org/onosproject/isis/io/isispacket/IsisMessageReader.java
+++ b/protocols/isis/isisio/src/main/java/org/onosproject/isis/io/isispacket/IsisMessageReader.java
@@ -40,9 +40,9 @@
      *
      * @param channelBuffer buffer
      * @return ISIS message
-     * @throws Exception exception
+     * @throws IsisParseException exception
      */
-    public IsisMessage readFromBuffer(ChannelBuffer channelBuffer) throws Exception {
+    public IsisMessage readFromBuffer(ChannelBuffer channelBuffer) throws IsisParseException {
 
         int dataLength = channelBuffer.readableBytes();
         log.debug("IsisMessageReader::readFromBuffer Data length {}", dataLength);
@@ -103,7 +103,6 @@
      *
      * @param channelBuffer ISIS header
      * @return ISIS header
-     * @throws Exception
      */
     private IsisHeader getIsisHeader(ChannelBuffer channelBuffer) {
 
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
index 3ebb982..8d16873 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
@@ -23,16 +23,15 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.OptionalInt;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Represents a Netconf device information.
  */
@@ -46,9 +45,6 @@
     private IpAddress ipAddress;
     private int port;
     private char[] key;
-    //File keyFile @deprecated 1.9.0
-    @Deprecated
-    private File keyFile;
     private Optional<NetconfSshClientLib> sshClientLib;
     private OptionalInt connectTimeoutSec;
     private OptionalInt replyTimeoutSec;
@@ -88,10 +84,6 @@
      * @param port      the tcp port
      * @param keyString the string containing a DSA or RSA private key
      *                  of the user in OpenSSH key format
-     *                  <br>
-     *                  (Pre 1.9.0 behaviour: {@code keyString} can be file path
-     *                  to a file containing DSA or RSA private key of the user
-     *                  in OpenSSH key format)
      */
     public NetconfDeviceInfo(String name, String password, IpAddress ipAddress,
                              int port, String keyString) {
@@ -103,7 +95,6 @@
         this.ipAddress = ipAddress;
         this.port = port;
         this.key = keyString.toCharArray();
-        this.keyFile = new File(keyString);
         this.sshClientLib = Optional.empty();
         this.connectTimeoutSec = OptionalInt.empty();
         this.replyTimeoutSec = OptionalInt.empty();
@@ -126,7 +117,6 @@
         if (netconfConfig.sshKey() != null && !netconfConfig.sshKey().isEmpty()) {
             this.key = netconfConfig.sshKey().toCharArray();
         }
-        this.keyFile = new File(netconfConfig.sshKey());
         if (netconfConfig.sshClient().isPresent()) {
             this.sshClientLib = Optional.of(NetconfSshClientLib.getEnum(netconfConfig.sshClient().get()));
         } else {
@@ -221,19 +211,6 @@
     }
 
     /**
-     * Exposes the keyFile of the controller.
-     *
-     * @return File object pointing to a file containing a DSA or RSA
-     *         private key of the user in OpenSSH key format,
-     *         or null if device is not configured to use public key authentication
-     * @deprecated 1.9.0
-     */
-    @Deprecated
-    public File getKeyFile() {
-        return keyFile;
-    }
-
-    /**
      * Exposes the Client library implementation.
      *
      * @return Enumerated value
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 a38b6df..0a478fe 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
@@ -20,6 +20,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 
@@ -59,6 +61,70 @@
         return request(request);
     }
 
+    /**
+     * Retrieves the specified configuration.
+     *
+     * @param datastore to retrieve configuration from
+     * @return specified configuration
+     *
+     * @throws NetconfException when there is a problem in the communication process on
+     * the underlying connection
+     */
+    default CompletableFuture<CharSequence> asyncGetConfig(DatastoreId datastore) throws NetconfException {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
+        rpc.append("<get-config>\n");
+        rpc.append("<source>\n");
+        rpc.append('<').append(checkNotNull(datastore)).append("/>");
+        rpc.append("</source>");
+        // filter here
+        rpc.append("</get-config>\n");
+        rpc.append("</rpc>");
+
+        return rpc(rpc.toString())
+                .thenApply(msg -> {
+                    // crude way of removing rpc-reply envelope
+                    int begin = msg.indexOf("<data>");
+                    int end = msg.lastIndexOf("</data>");
+                    if (begin != -1 && end != -1) {
+                        return msg.subSequence(begin + "<data>".length(), end);
+                    } else {
+                        // FIXME probably should exceptionally fail here.
+                        return msg;
+                    }
+                });
+    }
+
+    /**
+     * Retrieves running configuration and device state.
+     *
+     * @return running configuration and device state
+     *
+     * @throws NetconfException when there is a problem in the communication process on
+     * the underlying connection
+     */
+    default CompletableFuture<CharSequence> asyncGet() throws NetconfException {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
+        rpc.append("<get>\n");
+        // filter here
+        rpc.append("</get>\n");
+        rpc.append("</rpc>");
+        return rpc(rpc.toString())
+                .thenApply(msg -> {
+                    // crude way of removing rpc-reply envelope
+                    int begin = msg.indexOf("<data>");
+                    int end = msg.lastIndexOf("</data>");
+                    if (begin != -1 && end != -1) {
+                        return msg.subSequence(begin + "<data>".length(), end);
+                    } else {
+                        // FIXME probably should exceptionally fail here.
+                        return msg;
+                    }
+                });
+
+    }
+
 
     /**
      * Retrieves the requested configuration, different from get-config.
@@ -109,7 +175,10 @@
      * @return specified configuration.
      * @throws NetconfException when there is a problem in the communication process on
      * the underlying connection
+     *
+     * @deprecated in 1.13.0 use async version instead.
      */
+    @Deprecated
     String getConfig(DatastoreId netconfTargetConfig) throws NetconfException;
 
     /**
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfConfigGetCommand.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfGetCommand.java
similarity index 65%
copy from protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfConfigGetCommand.java
copy to protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfGetCommand.java
index bac6bef..2d29fcd 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfConfigGetCommand.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfGetCommand.java
@@ -16,10 +16,13 @@
 package org.onosproject.netconf.cli.impl;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.netconf.DatastoreId.datastore;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.DeviceId;
 import org.onosproject.netconf.NetconfController;
@@ -28,29 +31,26 @@
 import org.onosproject.netconf.NetconfSession;
 
 /**
- * Command that gets the configuration of the specified type from the specified
- * device. If configuration cannot be retrieved it prints an error string.
+ * Command that retrieves running configuration and device state.
+ * If configuration cannot be retrieved it prints an error string.
  */
-@Command(scope = "onos", name = "netconf-get-config",
-        description = "Gets the configuration of the specified type from the" +
-                "specified device.")
-public class NetconfConfigGetCommand extends AbstractShellCommand {
+@Command(scope = "onos", name = "netconf-get",
+        description = "Retrieve running configuration and "
+                + "device state information from specified device.")
+public class NetconfGetCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "uri", description = "Device ID",
+    @Argument(index = 0, name = "deviceId", description = "Device ID",
             required = true, multiValued = false)
     String uri = null;
 
-    @Argument(index = 1, name = "cfgType",
-              description = "Configuration datastore name (running, etc.)",
-              required = true, multiValued = false)
-    String cfgType = null;
-
-
-    private DeviceId deviceId;
+    @Option(name = "--timeout",
+            description = "Timeout in seconds",
+            required = false)
+    long timeoutSec = 30;
 
     @Override
     protected void execute() {
-        deviceId = DeviceId.deviceId(uri);
+        DeviceId deviceId = DeviceId.deviceId(uri);
 
         NetconfController controller = get(NetconfController.class);
         checkNotNull(controller, "Netconf controller is null");
@@ -68,9 +68,10 @@
         }
 
         try {
-            String res = session.getConfig(datastore(cfgType.toLowerCase()));
+            CharSequence res = session.asyncGet()
+                    .get(timeoutSec, TimeUnit.SECONDS);
             print("%s", res);
-        } catch (NetconfException e) {
+        } catch (NetconfException | InterruptedException | ExecutionException | TimeoutException e) {
             log.error("Configuration could not be retrieved", e);
             print("Error occurred retrieving configuration");
         }
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfConfigGetCommand.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfGetConfigCommand.java
similarity index 74%
rename from protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfConfigGetCommand.java
rename to protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfGetConfigCommand.java
index bac6bef..2aedaa9 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfConfigGetCommand.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/cli/impl/NetconfGetConfigCommand.java
@@ -18,8 +18,13 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.netconf.DatastoreId.datastore;
 
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.DeviceId;
 import org.onosproject.netconf.NetconfController;
@@ -34,17 +39,21 @@
 @Command(scope = "onos", name = "netconf-get-config",
         description = "Gets the configuration of the specified type from the" +
                 "specified device.")
-public class NetconfConfigGetCommand extends AbstractShellCommand {
+public class NetconfGetConfigCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "uri", description = "Device ID",
+    @Argument(index = 0, name = "deviceId", description = "Device ID",
             required = true, multiValued = false)
     String uri = null;
 
-    @Argument(index = 1, name = "cfgType",
+    @Argument(index = 1, name = "datastore",
               description = "Configuration datastore name (running, etc.)",
-              required = true, multiValued = false)
-    String cfgType = null;
+              required = false, multiValued = false)
+    String datastore = "running";
 
+    @Option(name = "--timeout",
+            description = "Timeout in seconds",
+            required = false)
+    long timeoutSec = 30;
 
     private DeviceId deviceId;
 
@@ -68,9 +77,10 @@
         }
 
         try {
-            String res = session.getConfig(datastore(cfgType.toLowerCase()));
+            CharSequence res = session.asyncGetConfig(datastore(datastore.toLowerCase()))
+                                .get(timeoutSec, TimeUnit.SECONDS);
             print("%s", res);
-        } catch (NetconfException e) {
+        } catch (NetconfException | InterruptedException | ExecutionException | TimeoutException e) {
             log.error("Configuration could not be retrieved", e);
             print("Error occurred retrieving configuration");
         }
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
index e54e6cd..51a8cfd 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
@@ -184,13 +184,7 @@
             }
             boolean isAuthenticated;
             try {
-                if (deviceInfo.getKeyFile() != null && deviceInfo.getKeyFile().canRead()) {
-                    log.debug("Authenticating with key file to device {} with username {}",
-                            deviceInfo.getDeviceId(), deviceInfo.name());
-                    isAuthenticated = netconfConnection.authenticateWithPublicKey(
-                            deviceInfo.name(), deviceInfo.getKeyFile(),
-                            deviceInfo.password().equals("") ? null : deviceInfo.password());
-                } else if (deviceInfo.getKey() != null) {
+                if (deviceInfo.getKey() != null) {
                     log.debug("Authenticating with key to device {} with username {}",
                             deviceInfo.getDeviceId(), deviceInfo.name());
                     isAuthenticated = netconfConnection.authenticateWithPublicKey(
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java
index e80e214..12eedfa 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfStreamThread.java
@@ -243,7 +243,7 @@
             try {
                 bufferReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
             } catch (UnsupportedEncodingException e) {
-                e.printStackTrace();
+                throw new IllegalStateException(e);
             }
         }
 
diff --git a/protocols/netconf/ctl/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/protocols/netconf/ctl/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 73993ce..019014e 100644
--- a/protocols/netconf/ctl/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/protocols/netconf/ctl/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -26,7 +26,7 @@
         </command>
 
         <command>
-            <action class="org.onosproject.netconf.cli.impl.NetconfConfigGetCommand"/>
+            <action class="org.onosproject.netconf.cli.impl.NetconfGetConfigCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
                 <ref component-id="targetConfigurationsCompleter"/>
@@ -35,6 +35,14 @@
         </command>
 
         <command>
+            <action class="org.onosproject.netconf.cli.impl.NetconfGetCommand"/>
+            <completers>
+                <ref component-id="deviceIdCompleter"/>
+                <null/>
+            </completers>
+        </command>
+
+        <command>
             <action class="org.onosproject.netconf.cli.impl.NetconfRpcTestCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
index 578dae0..324e06d 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java
@@ -38,8 +38,6 @@
 import org.onosproject.openflow.controller.driver.OpenFlowAgent;
 import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFFactories;
-import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -77,17 +75,6 @@
 
     private static final Logger log = LoggerFactory.getLogger(Controller.class);
 
-   /**
-    * @deprecated in 1.10.0
-    */
-    @Deprecated
-    protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
-    /**
-     * @deprecated in 1.10.0
-     */
-    @Deprecated
-    protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
-
     private static final boolean TLS_DISABLED = false;
     private static final short MIN_KS_LENGTH = 6;
 
@@ -119,29 +106,6 @@
     private DriverService driverService;
     private boolean enableOfTls = TLS_DISABLED;
 
-    // ***************
-    // Getters/Setters
-    // ***************
-
-    /**
-     * @return OF1.0 factory
-     * @deprecated in 1.10.0
-     */
-    @Deprecated
-    public OFFactory getOFMessageFactory10() {
-        return FACTORY10;
-    }
-
-
-    /**
-     * @return OF1.3 factory
-     * @deprecated in 1.10.0
-     */
-    @Deprecated
-    public OFFactory getOFMessageFactory13() {
-        return FACTORY13;
-    }
-
     // **************
     // Initialization
     // **************
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
index a9455b6..5f2c13f 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java
@@ -141,13 +141,6 @@
     protected OFVersion ofVersion;
     protected OFFactory factory;
 
-    // deprecated in 1.10.0
-    @Deprecated
-    protected OFFactory factory13;
-    // deprecated in 1.10.0
-    @Deprecated
-    protected OFFactory factory10;
-
     /** transaction Ids to use during handshake. Since only one thread
      * calls into an OFChannelHandler instance, we don't need atomic.
      * We will count down
@@ -195,8 +188,6 @@
         this.state = ChannelState.INIT;
         this.pendingPortStatusMsg = new CopyOnWriteArrayList<>();
         this.portDescReplies = new ArrayList<>();
-        factory13 = OFFactories.getFactory(OFVersion.OF_13);
-        factory10 = OFFactories.getFactory(OFVersion.OF_10);
         duplicateDpidFound = Boolean.FALSE;
     }
 
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java
index c541a9b..e208c3b 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java
@@ -47,7 +47,7 @@
 
     protected final void encode(ChannelHandlerContext ctx,
                           Iterable<OFMessage> msgs,
-                          ByteBuf out) throws Exception {
+                          ByteBuf out) {
 
         msgs.forEach(msg -> msg.writeTo(out));
     }
diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java
index 794d623..ea10996 100644
--- a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java
+++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java
@@ -197,6 +197,7 @@
                     //remove from bin
                     lsaBin.removeOspfLsa((String) key, lsa);
                 } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
                     log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage());
                 }
             }
@@ -215,6 +216,7 @@
                 //remove from bin
                 maxAgeBin.removeOspfLsa((String) key, lsa);
             } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
                 log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage());
             }
         }
@@ -249,6 +251,7 @@
                     lsaBin.removeOspfLsa((String) key, lsa);
                 }
             } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
                 log.debug("Error::LSDBAge::refreshLsa::{}", e.getMessage());
             }
         }
@@ -272,6 +275,7 @@
                 try {
                     lsaQueue.put(lsa);
                 } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
                     log.debug("Error::LSDBAge::checkAges::{}", e.getMessage());
                 }
             }
diff --git a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java
index 34c2d43..6bddef3 100644
--- a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java
+++ b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java
@@ -20,16 +20,16 @@
 import org.onosproject.net.behaviour.BridgeDescription;
 import org.onosproject.net.behaviour.BridgeDescription.FailMode;
 import org.onosproject.net.behaviour.ControllerInfo;
-
+import org.onosproject.net.behaviour.ControlProtocolVersion;
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static org.onosproject.ovsdb.controller.OvsdbConstant.DATAPATH_ID;
 import static org.onosproject.ovsdb.controller.OvsdbConstant.DISABLE_INBAND;
-
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 
+
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -47,6 +47,9 @@
     /* Adds more properties */
     private final Optional<String> datapathType;
 
+    /* Add control protocol version property */
+    private final Optional<List<ControlProtocolVersion>> controlProtocols;
+
     /* other optional configs */
     private final Map<String, String> otherConfigs;
 
@@ -57,16 +60,19 @@
      * @param failMode openflow controller fail mode policy
      * @param controllers list of openflow controllers
      * @param datapathType ovs datapath_type
+     * @param controlProtocols list of control protocols
      * @param otherConfigs other configs
      */
     private OvsdbBridge(String name, Optional<FailMode> failMode,
                        List<ControllerInfo> controllers,
                        Optional<String> datapathType,
+                       Optional<List<ControlProtocolVersion>> controlProtocols,
                        Map<String, String> otherConfigs) {
         this.name = checkNotNull(name);
         this.failMode = failMode;
         this.controllers = controllers;
         this.datapathType = datapathType;
+        this.controlProtocols = controlProtocols;
         this.otherConfigs = otherConfigs;
     }
 
@@ -107,6 +113,14 @@
     }
 
     /**
+     *  Returns Control protocol versions of the bridge.
+     * @return List of Control protocols
+     */
+    public Optional<List<ControlProtocolVersion>> controlProtocols() {
+        return controlProtocols;
+    }
+
+    /**
      * Returns other configurations of the bridge.
      *
      * @return map of configurations
@@ -148,6 +162,7 @@
                 .add("failMode", failMode)
                 .add("controllers", controllers)
                 .add("datapathType", datapathType)
+                .add("controlProtocols", controlProtocols)
                 .add("otherConfigs", otherConfigs)
                 .toString();
     }
@@ -180,6 +195,7 @@
         private List<ControllerInfo> controllers = Lists.newArrayList();
         private Optional<String> datapathType = Optional.empty();
         private Map<String, String> otherConfigs = Maps.newHashMap();
+        private Optional<List<ControlProtocolVersion>> controlProtocols = Optional.empty();
 
         private Builder() {
         }
@@ -200,6 +216,9 @@
             if (bridgeDesc.datapathType().isPresent()) {
                 this.datapathType = bridgeDesc.datapathType();
             }
+            if (bridgeDesc.controlProtocols().isPresent()) {
+                this.controlProtocols = bridgeDesc.controlProtocols();
+            }
             this.name = bridgeDesc.name();
             this.failMode = bridgeDesc.failMode();
             this.controllers = Lists.newArrayList(bridgeDesc.controllers());
@@ -211,7 +230,7 @@
          * @return ovsdb bridge
          */
         public OvsdbBridge build() {
-            return new OvsdbBridge(name, failMode, controllers, datapathType, otherConfigs);
+            return new OvsdbBridge(name, failMode, controllers, datapathType, controlProtocols, otherConfigs);
         }
 
         /**
@@ -292,6 +311,16 @@
         }
 
         /**
+         * Returns OVSDB bridge builder with  given control protocol Versions.
+         * @param controlProtocols list of control protocols
+         * @return ovsdb bridge builder
+         */
+        public Builder controlProtocols(List<ControlProtocolVersion> controlProtocols) {
+            this.controlProtocols = Optional.ofNullable(controlProtocols);
+            return this;
+        }
+
+        /**
          * Returns OVSDB bridge builder with a given disable in-band config.
          *
          * @return ovsdb bridge builder
diff --git a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
index 54c5fcb..f74186e 100644
--- a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
+++ b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbConstant.java
@@ -45,6 +45,7 @@
     // other configs
     public static final String DATAPATH_ID = "datapath-id";
     public static final String DISABLE_INBAND = "disable-in-band";
+    public static final String PROTOCOLS = "protocols";
 
     /** Port table. */
     public static final String PORT = "Port";
diff --git a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
index b36032b..6056be2 100644
--- a/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
+++ b/protocols/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
@@ -29,6 +29,7 @@
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.ControlProtocolVersion;
 import org.onosproject.net.behaviour.ControllerInfo;
 import org.onosproject.net.behaviour.MirroringName;
 import org.onosproject.net.behaviour.MirroringStatistics;
@@ -485,6 +486,12 @@
             bridge.setDatapathType(datapathType);
         }
 
+        if (ovsdbBridge.controlProtocols().isPresent()) {
+            bridge.setProtocols(ovsdbBridge.controlProtocols().get().stream()
+                    .map(ControlProtocolVersion::toString)
+                    .collect(Collectors.toCollection(HashSet::new)));
+        }
+
         String bridgeUuid = getBridgeUuid(ovsdbBridge.name());
         if (bridgeUuid == null) {
             bridge.setName(ovsdbBridge.name());
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index 534ef06..905a690 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -774,6 +774,7 @@
                 executorService.awaitTermination(5, TimeUnit.SECONDS);
             } catch (InterruptedException e) {
                 log.warn("Executor service didn't shutdown in time.");
+                Thread.currentThread().interrupt();
             }
         } finally {
             writeLock.unlock();
diff --git a/protocols/p4runtime/proto/pom.xml b/protocols/p4runtime/proto/pom.xml
index a11ff1e..c774b41 100644
--- a/protocols/p4runtime/proto/pom.xml
+++ b/protocols/p4runtime/proto/pom.xml
@@ -72,7 +72,7 @@
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>exec-maven-plugin</artifactId>
-                <version>1.1.1</version>
+                <version>1.6.0</version>
                 <executions>
                     <execution>
                         <id>clone pi</id>
@@ -88,6 +88,8 @@
                                 <!--<argument>&#45;&#45;quiet</argument>-->
                                 <argument>${piBaseUrl}</argument>
                             </arguments>
+                            <!-- 128: if it was already there, treat as ok -->
+                            <successCodes>0,128</successCodes>
                         </configuration>
                     </execution>
                     <execution>
@@ -102,7 +104,7 @@
                             <arguments>
                                 <argument>checkout</argument>
                                 <!--<argument>&#45;&#45;quiet</argument>-->
-                                <argument>-b</argument>
+                                <argument>-B</argument>
                                 <argument>buck-build</argument>
                                 <argument>${piCommit}</argument>
                             </arguments>
diff --git a/protocols/pcep/server/ctl/src/main/java/org/onosproject/pcep/server/impl/PcepChannelHandler.java b/protocols/pcep/server/ctl/src/main/java/org/onosproject/pcep/server/impl/PcepChannelHandler.java
index 596a633..ce8b04b 100644
--- a/protocols/pcep/server/ctl/src/main/java/org/onosproject/pcep/server/impl/PcepChannelHandler.java
+++ b/protocols/pcep/server/ctl/src/main/java/org/onosproject/pcep/server/impl/PcepChannelHandler.java
@@ -709,7 +709,7 @@
          *
          * @param handshakeComplete status of handshake
          */
-        public void setHandshakeComplete(boolean handshakeComplete) {
+        private void setHandshakeComplete(boolean handshakeComplete) {
             this.handshakeComplete = handshakeComplete;
         }
 
diff --git a/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/BasicPceccHandlerTest.java b/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/BasicPceccHandlerTest.java
index 201b701..7b3a92c 100644
--- a/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/BasicPceccHandlerTest.java
+++ b/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/BasicPceccHandlerTest.java
@@ -27,6 +27,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.IpAddress;
 import org.onosproject.core.GroupId;
 import org.onosproject.incubator.net.tunnel.Tunnel;
@@ -192,7 +193,7 @@
        linkList.add(l4);
 
        // Path
-       path = new DefaultPath(providerId, linkList, 10);
+       path = new DefaultPath(providerId, linkList, ScalarWeight.toWeight(10));
 
        // Tunnel
        tunnel = new DefaultTunnel(producerName, src, dst, Tunnel.Type.VXLAN,
diff --git a/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/PceccSrTeBeHandlerTest.java b/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/PceccSrTeBeHandlerTest.java
index 38ea63a..a9bc3bc 100644
--- a/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/PceccSrTeBeHandlerTest.java
+++ b/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/label/PceccSrTeBeHandlerTest.java
@@ -27,6 +27,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.IpAddress;
 import org.onosproject.incubator.net.resource.label.LabelResourceId;
 import org.onosproject.incubator.net.resource.label.LabelResourceAdminService;
@@ -224,7 +225,7 @@
         linkList.add(link4);
 
         // Path
-        path1 = new DefaultPath(providerId, linkList, 10);
+        path1 = new DefaultPath(providerId, linkList, ScalarWeight.toWeight(10));
     }
 
     @After
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/HttpSBController.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/HttpSBController.java
index f8d23c8..ada5496 100644
--- a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/HttpSBController.java
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/HttpSBController.java
@@ -76,89 +76,6 @@
      * @param request url of the request
      * @param payload payload of the request as an InputStream
      * @param mediaType type of content in the payload i.e. application/json
-     * @return true if operation returned 200, 201, 202, false otherwise
-     *
-     * @deprecated in Kingfisher (1.10.0)
-     */
-    @Deprecated
-    boolean post(DeviceId device, String request, InputStream payload, String mediaType);
-
-    /**
-     * Does a HTTP POST request with specified parameters to the device.
-     *
-     * @param <T> post return type
-     * @param device device to make the request to
-     * @param request url of the request
-     * @param payload payload of the request as an InputStream
-     * @param mediaType type of content in the payload i.e. application/json
-     * @param responseClass the type of response object we are interested in,
-     *            such as String, InputStream.
-     * @return Object of type requested via responseClass.
-     */
-    @Deprecated
-    <T> T post(DeviceId device, String request, InputStream payload, String mediaType, Class<T> responseClass);
-
-    /**
-     * Does a HTTP PUT request with specified parameters to the device.
-     *
-     * @param device device to make the request to
-     * @param request resource path of the request
-     * @param payload payload of the request as an InputStream
-     * @param mediaType type of content in the payload i.e. application/json
-     * @return true if operation returned 200, 201, 202, false otherwise
-     *
-     * @deprecated in Kingfisher (1.10.0)
-     */
-    @Deprecated
-    boolean put(DeviceId device, String request, InputStream payload, String mediaType);
-
-    /**
-     *
-     * Does a HTTP GET request with specified parameters to the device.
-     *
-     * @param device device to make the request to
-     * @param request url of the request
-     * @param mediaType format to retrieve the content in
-     * @return an inputstream of data from the reply.
-     */
-    @Deprecated
-    InputStream get(DeviceId device, String request, String mediaType);
-
-    /**
-     * Does a HTTP PATCH request with specified parameters to the device.
-     *
-     * @param device device to make the request to
-     * @param request url of the request
-     * @param payload payload of the request as an InputStream
-     * @param mediaType format to retrieve the content in
-     * @return true if operation returned 200, 201, 202, false otherwise
-     *
-     * @deprecated in Kingfisher (1.10.0)
-     */
-    @Deprecated
-    boolean patch(DeviceId device, String request, InputStream payload, String mediaType);
-
-    /**
-     * Does a HTTP DELETE request with specified parameters to the device.
-     *
-     * @param device device to make the request to
-     * @param request url of the request
-     * @param payload payload of the request as an InputStream
-     * @param mediaType type of content in the payload i.e. application/json
-     * @return true if operation returned 200 false otherwise
-     *
-     * @deprecated in Kingfisher (1.10.0)
-     */
-    @Deprecated
-    boolean delete(DeviceId device, String request, InputStream payload, String mediaType);
-
-    /**
-     * Does a HTTP POST request with specified parameters to the device.
-     *
-     * @param device device to make the request to
-     * @param request url of the request
-     * @param payload payload of the request as an InputStream
-     * @param mediaType type of content in the payload i.e. application/json
      * @return status Commonly used status codes defined by HTTP
      */
     int post(DeviceId device, String request, InputStream payload, MediaType mediaType);
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/HttpSBControllerImpl.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/HttpSBControllerImpl.java
index c546c49..aef15f6 100644
--- a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/HttpSBControllerImpl.java
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/HttpSBControllerImpl.java
@@ -123,11 +123,6 @@
     }
 
     @Override
-    public boolean post(DeviceId device, String request, InputStream payload, String mediaType) {
-        return checkStatusCode(post(device, request, payload, typeOfMediaType(mediaType)));
-    }
-
-    @Override
     public int post(DeviceId device, String request, InputStream payload, MediaType mediaType) {
         Response response = getResponse(device, request, payload, mediaType);
         if (response == null) {
@@ -137,11 +132,6 @@
     }
 
     @Override
-    public <T> T post(DeviceId device, String request, InputStream payload, String mediaType, Class<T> responseClass) {
-        return post(device, request, payload, typeOfMediaType(mediaType), responseClass);
-    }
-
-    @Override
     public <T> T post(DeviceId device, String request, InputStream payload, MediaType mediaType,
                       Class<T> responseClass) {
         Response response = getResponse(device, request, payload, mediaType);
@@ -173,11 +163,6 @@
     }
 
     @Override
-    public boolean put(DeviceId device, String request, InputStream payload, String mediaType) {
-        return checkStatusCode(put(device, request, payload, typeOfMediaType(mediaType)));
-    }
-
-    @Override
     public int put(DeviceId device, String request, InputStream payload, MediaType mediaType) {
 
         WebTarget wt = getWebTarget(device, request);
@@ -201,11 +186,6 @@
     }
 
     @Override
-    public InputStream get(DeviceId device, String request, String mediaType) {
-        return get(device, request, typeOfMediaType(mediaType));
-    }
-
-    @Override
     public InputStream get(DeviceId device, String request, MediaType mediaType) {
         WebTarget wt = getWebTarget(device, request);
 
@@ -218,11 +198,6 @@
     }
 
     @Override
-    public boolean patch(DeviceId device, String request, InputStream payload, String mediaType) {
-        return checkStatusCode(patch(device, request, payload, typeOfMediaType(mediaType)));
-    }
-
-    @Override
     public int patch(DeviceId device, String request, InputStream payload, MediaType mediaType) {
 
         try {
@@ -257,11 +232,6 @@
     }
 
     @Override
-    public boolean delete(DeviceId device, String request, InputStream payload, String mediaType) {
-        return checkStatusCode(delete(device, request, payload, typeOfMediaType(mediaType)));
-    }
-
-    @Override
     public int delete(DeviceId device, String request, InputStream payload, MediaType mediaType) {
 
         WebTarget wt = getWebTarget(device, request);
@@ -377,7 +347,7 @@
                 }
             } }, new java.security.SecureRandom());
         } catch (NoSuchAlgorithmException | KeyManagementException e) {
-            e.printStackTrace();
+            throw new IllegalStateException(e);
         }
 
         return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build();
diff --git a/protocols/restconf/client/ctl/src/main/java/org/onosproject/protocol/restconf/ctl/RestConfSBControllerImpl.java b/protocols/restconf/client/ctl/src/main/java/org/onosproject/protocol/restconf/ctl/RestConfSBControllerImpl.java
index 4dc7ac4..38f296d 100644
--- a/protocols/restconf/client/ctl/src/main/java/org/onosproject/protocol/restconf/ctl/RestConfSBControllerImpl.java
+++ b/protocols/restconf/client/ctl/src/main/java/org/onosproject/protocol/restconf/ctl/RestConfSBControllerImpl.java
@@ -32,7 +32,6 @@
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.Response;
-import java.io.InputStream;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
@@ -109,53 +108,6 @@
     }
 
     @Override
-    public boolean post(DeviceId device, String request, InputStream payload,
-                        String mediaType) {
-        request = discoverRootResource(device) + RESOURCE_PATH_PREFIX
-                + request;
-        return super.post(device, request, payload, mediaType);
-    }
-
-    @Override
-    public <T> T post(DeviceId device, String request, InputStream payload,
-                      String mediaType, Class<T> responseClass) {
-        request = discoverRootResource(device) + RESOURCE_PATH_PREFIX
-                + request;
-        return super.post(device, request, payload, mediaType, responseClass);
-    }
-
-    @Override
-    public boolean put(DeviceId device, String request, InputStream payload,
-                       String mediaType) {
-        request = discoverRootResource(device) + RESOURCE_PATH_PREFIX
-                + request;
-        return super.put(device, request, payload, mediaType);
-    }
-
-    @Override
-    public InputStream get(DeviceId device, String request, String mediaType) {
-        request = discoverRootResource(device) + RESOURCE_PATH_PREFIX
-                + request;
-        return super.get(device, request, mediaType);
-    }
-
-    @Override
-    public boolean patch(DeviceId device, String request, InputStream payload,
-                         String mediaType) {
-        request = discoverRootResource(device) + RESOURCE_PATH_PREFIX
-                + request;
-        return super.patch(device, request, payload, mediaType);
-    }
-
-    @Override
-    public boolean delete(DeviceId device, String request, InputStream payload,
-                          String mediaType) {
-        request = discoverRootResource(device) + RESOURCE_PATH_PREFIX
-                + request;
-        return super.delete(device, request, payload, mediaType);
-    }
-
-    @Override
     public void enableNotifications(DeviceId device, String request,
                                     String mediaType,
                                     RestconfNotificationEventListener listener) {
diff --git a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java
index 5703e82..8ddbb6b 100644
--- a/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java
+++ b/protocols/snmp/ctl/src/main/java/org/onosproject/snmp/ctl/DefaultSnmpController.java
@@ -27,6 +27,7 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Service;
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
 import org.onosproject.net.DeviceId;
 import org.onosproject.snmp.SnmpController;
@@ -122,9 +123,10 @@
 
     @Override
     public DefaultAlarm buildWalkFailedAlarm(DeviceId deviceId) {
+        long timeRaised = System.currentTimeMillis();
         return new DefaultAlarm.Builder(
+                AlarmId.alarmId(deviceId, Long.toString(timeRaised)),
                 deviceId, "SNMP alarm retrieval failed",
-                Alarm.SeverityLevel.CRITICAL,
-                System.currentTimeMillis()).build();
+                Alarm.SeverityLevel.CRITICAL, timeRaised).build();
     }
 }
diff --git a/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java
index ff1aa03..a649633 100644
--- a/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java
+++ b/protocols/snmp/ctl/src/test/java/org/onosproject/snmp/ctl/DefaultSnmpControllerTest.java
@@ -23,6 +23,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
 
 import java.io.IOException;
@@ -42,10 +43,12 @@
 
     ISnmpSession snmpSession = new ISnmpSessionAdapter();
 
+    long time = System.currentTimeMillis();
     DefaultAlarm alarm = new DefaultAlarm.Builder(
+            AlarmId.alarmId(device.deviceId(), Long.toString(time)),
             device.deviceId(), "SNMP alarm retrieval failed",
             Alarm.SeverityLevel.CRITICAL,
-            System.currentTimeMillis()).build();
+            time).build();
 
     @Before
     public void setUp() {
diff --git a/providers/netconf/alarm/src/main/java/org/onosproject/provider/netconf/alarm/NetconfAlarmTranslator.java b/providers/netconf/alarm/src/main/java/org/onosproject/provider/netconf/alarm/NetconfAlarmTranslator.java
index 4636704..10c653c 100644
--- a/providers/netconf/alarm/src/main/java/org/onosproject/provider/netconf/alarm/NetconfAlarmTranslator.java
+++ b/providers/netconf/alarm/src/main/java/org/onosproject/provider/netconf/alarm/NetconfAlarmTranslator.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableSet;
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmTranslator;
 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
 import org.onosproject.net.DeviceId;
@@ -71,7 +72,8 @@
             while (descriptionNode != null) {
                 if (descriptionNode.getNodeType() == Node.ELEMENT_NODE) {
                     String description = nodeToString(descriptionNode);
-                    alarms.add(new DefaultAlarm.Builder(deviceId, description,
+                    alarms.add(new DefaultAlarm.Builder(AlarmId.alarmId(deviceId, Long.toString(timeStamp)),
+                                                        deviceId, description,
                                                         Alarm.SeverityLevel.WARNING,
                                                         timeStamp).build());
                     descriptionNode = null;
diff --git a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
index 99c8ebd..9cf81d0 100644
--- a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
+++ b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
@@ -16,11 +16,8 @@
 
 package org.onosproject.provider.netconf.device.impl;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -33,18 +30,16 @@
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
-import org.onosproject.net.Port;
-import org.onosproject.net.behaviour.PortAdmin;
-import org.onosproject.net.config.ConfigException;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.SparseAnnotations;
-import org.onosproject.net.behaviour.PortDiscovery;
+import org.onosproject.net.behaviour.PortAdmin;
 import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
@@ -82,7 +77,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Dictionary;
-import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -97,7 +91,6 @@
 
 import static java.util.concurrent.Executors.newScheduledThreadPool;
 import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -170,7 +163,7 @@
     private final Map<DeviceId, AtomicInteger> retriedPortDiscoveryMap = new ConcurrentHashMap<>();
     protected ScheduledFuture<?> scheduledTask;
 
-    protected final List<ConfigFactory> factories = ImmutableList.of(
+    protected final ConfigFactory factory =
             // TODO consider moving Config registration to NETCONF ctl bundle
             new ConfigFactory<DeviceId, NetconfDeviceConfig>(
                     SubjectFactories.DEVICE_SUBJECT_FACTORY,
@@ -179,16 +172,7 @@
                 public NetconfDeviceConfig createConfig() {
                     return new NetconfDeviceConfig();
                 }
-            },
-            new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
-                                                                    NetconfProviderConfig.class,
-                                                                    "netconf_devices",
-                                                                    true) {
-                @Override
-                public NetconfProviderConfig createConfig() {
-                    return new NetconfProviderConfig();
-                }
-            });
+            };
 
     protected final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
     private ApplicationId appId;
@@ -201,11 +185,10 @@
         componentConfigService.registerProperties(getClass());
         providerService = providerRegistry.register(this);
         appId = coreService.registerApplication(APP_NAME);
-        factories.forEach(cfgService::registerConfigFactory);
+        cfgService.registerConfigFactory(factory);
         cfgService.addListener(cfgListener);
         controller.addDeviceListener(innerNodeListener);
         deviceService.addListener(deviceListener);
-        translateConfig();
         executor.execute(NetconfDeviceProvider.this::connectDevices);
         modified(context);
         log.info("Started");
@@ -226,7 +209,7 @@
         providerRegistry.unregister(this);
         providerService = null;
         retriedPortDiscoveryMap.clear();
-        factories.forEach(cfgService::unregisterConfigFactory);
+        cfgService.unregisterConfigFactory(factory);
         scheduledTask.cancel(true);
         executor.shutdown();
         log.info("Stopped");
@@ -591,11 +574,7 @@
     private void discoverPorts(DeviceId deviceId) {
         Device device = deviceService.getDevice(deviceId);
         //TODO remove when PortDiscovery is removed from master
-        if (device.is(PortDiscovery.class)) {
-            PortDiscovery portConfig = device.as(PortDiscovery.class);
-            providerService.updatePorts(deviceId,
-                                        portConfig.getPorts());
-        } else if (device.is(DeviceDescriptionDiscovery.class)) {
+        if (device.is(DeviceDescriptionDiscovery.class)) {
             DeviceDescriptionDiscovery deviceDescriptionDiscovery =
                     device.as(DeviceDescriptionDiscovery.class);
             providerService.updatePorts(deviceId,
@@ -624,38 +603,6 @@
         }
     }
 
-
-    protected void translateConfig() {
-        NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
-        if (cfg != null) {
-            try {
-                cfg.getDevicesAddresses().forEach(addr -> {
-                    DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
-                    log.info("Translating config for device {}", deviceId);
-                    if (cfgService.getConfig(deviceId, NetconfDeviceConfig.class) == null) {
-                        ObjectMapper mapper = new ObjectMapper();
-                        ObjectNode device = mapper.createObjectNode();
-                        device.put("ip", addr.ip().toString());
-                        device.put("port", addr.port());
-                        device.put("username", addr.name());
-                        device.put("password", addr.password());
-                        device.put("sshkey", addr.sshkey());
-                        cfgService.applyConfig(deviceId, NetconfDeviceConfig.class, device);
-                    } else {
-                        // This is a corner case where new updated config is
-                        // pushed with old /app tree after an initial with the
-                        // new device/ tree. Since old method will be deprecated
-                        // it's ok to ignore
-                        log.warn("Config for device {} already exists, ignoring", deviceId);
-                    }
-
-                });
-            } catch (ConfigException e) {
-                log.error("Cannot read config error " + e);
-            }
-        }
-    }
-
     /**
      * Listener for configuration events.
      */
@@ -669,15 +616,13 @@
             } else {
                 log.warn("Injecting device via this Json is deprecated, " +
                                  "please put configuration under devices/ as shown in the wiki");
-                translateConfig();
             }
 
         }
 
         @Override
         public boolean isRelevant(NetworkConfigEvent event) {
-            return (event.configClass().equals(NetconfDeviceConfig.class) ||
-                    event.configClass().equals(NetconfProviderConfig.class)) &&
+            return (event.configClass().equals(NetconfDeviceConfig.class)) &&
                     (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
                             event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
         }
diff --git a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfProviderConfig.java b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfProviderConfig.java
deleted file mode 100644
index 94190fa..0000000
--- a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfProviderConfig.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2015-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.provider.netconf.device.impl;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.ConfigException;
-import org.onosproject.net.config.Config;
-
-import java.util.Set;
-
-/**
- * Configuration for Netconf provider.
- * @deprecated 1.10.0 Kingfisher
- */
-@Beta
-@Deprecated
-public class NetconfProviderConfig extends Config<ApplicationId> {
-
-    public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
-    private static final String IP = "ip";
-    private static final int DEFAULT_TCP_PORT = 830;
-    private static final String PORT = "port";
-    private static final String NAME = "username";
-    private static final String PASSWORD = "password";
-    private static final String SSHKEY = "sshkey";
-
-    public Set<NetconfDeviceAddress> getDevicesAddresses() throws ConfigException {
-        Set<NetconfDeviceAddress> devicesAddresses = Sets.newHashSet();
-        try {
-            for (JsonNode node : array) {
-                String ip = node.path(IP).asText();
-                IpAddress ipAddr = ip.isEmpty() ? null : IpAddress.valueOf(ip);
-                int port = node.path(PORT).asInt(DEFAULT_TCP_PORT);
-                String name = node.path(NAME).asText();
-                String password = node.path(PASSWORD).asText();
-                String sshkey = node.path(SSHKEY).asText();
-                devicesAddresses.add(new NetconfDeviceAddress(ipAddr, port, name, password, sshkey));
-
-            }
-        } catch (IllegalArgumentException e) {
-            throw new ConfigException(CONFIG_VALUE_ERROR, e);
-        }
-
-        return devicesAddresses;
-    }
-
-    public class
-    NetconfDeviceAddress {
-        private final IpAddress ip;
-        private final int port;
-        private final String name;
-        private final String password;
-        private final String sshkey;
-
-        public NetconfDeviceAddress(IpAddress ip, int port, String name, String password) {
-            this.ip = ip;
-            this.port = port;
-            this.name = name;
-            this.password = password;
-            this.sshkey = "";
-        }
-
-        public NetconfDeviceAddress(IpAddress ip, int port, String name, String password, String sshkey) {
-            this.ip = ip;
-            this.port = port;
-            this.name = name;
-            this.password = password;
-            this.sshkey = sshkey;
-        }
-
-        public IpAddress ip() {
-            return ip;
-        }
-
-        public int port() {
-            return port;
-        }
-
-        public String name() {
-            return name;
-        }
-
-        public String password() {
-            return password;
-        }
-
-        public String sshkey() {
-            return sshkey;
-        }
-    }
-
-}
diff --git a/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProviderTest.java b/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProviderTest.java
index 802c002..c16de45 100644
--- a/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProviderTest.java
+++ b/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProviderTest.java
@@ -19,19 +19,16 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.MoreExecutors;
 import org.apache.commons.lang.StringUtils;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.DefaultApplicationId;
-import org.onosproject.net.config.ConfigException;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.mastership.MastershipServiceAdapter;
 import org.onosproject.net.AbstractProjectableModel;
@@ -84,6 +81,7 @@
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.CountDownLatch;
+
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
@@ -126,15 +124,10 @@
                                    DeviceId.deviceId(NETCONF_DEVICE_ID_STRING),
                                    netconfDeviceConfig, null,
                                    NetconfDeviceConfig.class);
-
-    private final NetworkConfigEvent deviceAddedEventOld =
-            new NetworkConfigEvent(NetworkConfigEvent.Type.CONFIG_ADDED,
-                                   null, NetconfProviderConfig.class);
     private final NetworkConfigEvent deviceAddedEventTranslated =
             new NetworkConfigEvent(NetworkConfigEvent.Type.CONFIG_ADDED,
                                    DeviceId.deviceId(NETCONF_DEVICE_ID_STRING_OLD),
                                    NetconfDeviceConfig.class);
-    private final NetconfProviderConfig netconfProviderConfig = new MockNetconfProviderConfig();
     private static final String NETCONF_DEVICE_ID_STRING = "netconf:1.1.1.1:830";
     private static final String NETCONF_DEVICE_ID_STRING_OLD = "netconf:1.1.1.2:1";
     private static final String NETCONF_DEVICE_ID_STRING_IPV6 = "netconf:2001:0db8:0000:0000:0000:ff00:0042:8329:830";
@@ -214,7 +207,7 @@
         assertTrue("Provider should be registered", deviceRegistry.getProviders().contains(provider.id()));
         assertEquals("Incorrect device service", deviceService, provider.deviceService);
         assertEquals("Incorrect provider service", providerService, provider.providerService);
-        assertTrue("Incorrect config factories", cfgFactories.containsAll(provider.factories));
+        assertTrue("Incorrect config factories", cfgFactories.contains(provider.factory));
         assertNotNull("Device listener should be added", deviceService.listener);
         assertFalse("Thread to connect device should be running",
                     provider.executor.isShutdown() || provider.executor.isTerminated());
@@ -264,30 +257,11 @@
     }
 
     @Test
-    @Ignore("Test is brittle")
-    public void addDeviceOld() throws InterruptedException {
-        // expecting 1 device add
-        deviceAdded = new CountDownLatch(1);
-        assertNotNull(providerService);
-        assertTrue("Event should be relevant", provider.cfgListener.isRelevant(deviceAddedEvent));
-        assertTrue("Event should be relevant", provider.cfgListener.isRelevant(deviceAddedEventOld));
-        available = true;
-        provider.cfgListener.event(deviceAddedEventOld);
-
-        deviceAdded.await();
-        assertEquals("Device should be added", 1, deviceStore.getDeviceCount());
-        assertTrue("Device incorrectly added" + NETCONF_DEVICE_ID_STRING_OLD,
-                   devices.containsKey(DeviceId.deviceId(NETCONF_DEVICE_ID_STRING_OLD)));
-        devices.clear();
-    }
-
-    @Test
     public void addDeviceNew() throws InterruptedException {
         // expecting 1 device add
         deviceAdded = new CountDownLatch(1);
         assertNotNull(providerService);
         assertTrue("Event should be relevant", provider.cfgListener.isRelevant(deviceAddedEvent));
-        assertTrue("Event should be relevant", provider.cfgListener.isRelevant(deviceAddedEventOld));
         available = true;
         provider.cfgListener.event(deviceAddedEvent);
 
@@ -475,9 +449,6 @@
         @Override
         public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
             if (available) {
-                if (configClass.equals(NetconfProviderConfig.class)) {
-                    return (C) netconfProviderConfig;
-                }
                 DeviceId did = (DeviceId) subject;
                 if (configClass.equals(NetconfDeviceConfig.class)
                         && did.equals(DeviceId.deviceId(NETCONF_DEVICE_ID_STRING))) {
@@ -526,15 +497,6 @@
 
     }
 
-    private class MockNetconfProviderConfig extends NetconfProviderConfig {
-        final NetconfDeviceAddress deviceInfo = new NetconfDeviceAddress(IP_OLD, 1, TEST, TEST);
-
-        @Override
-        public Set<NetconfProviderConfig.NetconfDeviceAddress> getDevicesAddresses() throws ConfigException {
-            return ImmutableSet.of(deviceInfo);
-        }
-    }
-
     private class MockDevice extends DefaultDevice {
 
         MockDevice(DeviceId id) {
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/CustomTopologySimulator.java b/providers/null/src/main/java/org/onosproject/provider/nil/CustomTopologySimulator.java
index cf1e22d..52883a2 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/CustomTopologySimulator.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/CustomTopologySimulator.java
@@ -27,6 +27,7 @@
 import org.onosproject.net.host.DefaultHostDescription;
 
 import java.util.Map;
+import java.util.Set;
 
 import static org.onlab.util.Tools.toHex;
 import static org.onosproject.provider.nil.NullProviders.SCHEME;
@@ -96,6 +97,19 @@
         hostProviderService.hostDetected(hostId, description, false);
     }
 
+    /**
+     * Creates a simulated multi-homed host.
+     *
+     * @param hostId   host identifier
+     * @param locations host locations
+     * @param hostIps   host IP addresses
+     */
+    public void createHost(HostId hostId, Set<HostLocation> locations, Set<IpAddress> hostIps) {
+        DefaultHostDescription description =
+                new DefaultHostDescription(hostId.mac(), hostId.vlanId(), locations, hostIps, false);
+        hostProviderService.hostDetected(hostId, description, false);
+    }
+
     @Override
     protected void createDevices() {
     }
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
index 1250877..7313f12 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java
@@ -439,8 +439,9 @@
 
         @Override
         public boolean isReachable(DeviceId deviceId) {
-            return topoShape.equals("custom") ||
-                    (simulator != null && simulator.contains(deviceId) &&
+            return simulator != null &&
+                    (simulator.contains(deviceId) || !deviceService.getPorts(deviceId).isEmpty()) &&
+                    (simulator instanceof CustomTopologySimulator ||
                             topologyMutationDriver.isReachable(deviceId));
         }
 
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/TopologySimulator.java b/providers/null/src/main/java/org/onosproject/provider/nil/TopologySimulator.java
index 8152da3..2c79288 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/TopologySimulator.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/TopologySimulator.java
@@ -177,9 +177,7 @@
      * @param i index of the device id in the list.
      */
     protected void createDevice(int i) {
-        DeviceId id = DeviceId.deviceId(SCHEME + ":" + toHex(i));
-        deviceIds.add(id);
-        createDevice(id, i);
+        createDevice(DeviceId.deviceId(SCHEME + ":" + toHex(i)), i);
     }
 
     /**
@@ -205,6 +203,7 @@
                 new DefaultDeviceDescription(id.uri(), type,
                                              "ON.Lab", "0.1", "0.1", "1234",
                                              new ChassisId(chassisId));
+        deviceIds.add(id);
         deviceProviderService.deviceConnected(id, desc);
         deviceProviderService.updatePorts(id, buildPorts(portCount));
     }
@@ -289,6 +288,7 @@
             deviceLatch.await(maxWaitSeconds, TimeUnit.SECONDS);
         } catch (InterruptedException e) {
             log.warn("Device events did not arrive in time");
+            Thread.currentThread().interrupt();
         }
         deviceService.removeListener(deviceEventCounter);
     }
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java
index b6c668f..4d081f8 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java
@@ -17,7 +17,6 @@
 
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
-import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.config.NetworkConfigService;
@@ -31,34 +30,32 @@
  */
 @Command(scope = "onos", name = "null-create-device",
         description = "Adds a simulated device to the custom topology simulation")
-public class CreateNullDevice extends AbstractShellCommand {
-    private static final String GEO = "geo";
-    private static final String GRID = "grid";
+public class CreateNullDevice extends CreateNullEntity {
 
     @Argument(index = 0, name = "type", description = "Device type, e.g. switch, roadm",
-            required = true, multiValued = false)
+            required = true)
     String type = null;
 
     @Argument(index = 1, name = "name", description = "Device name",
-            required = true, multiValued = false)
+            required = true)
     String name = null;
 
     @Argument(index = 2, name = "portCount", description = "Port count",
-            required = true, multiValued = false)
+            required = true)
     Integer portCount = null;
 
     @Argument(index = 3, name = "latOrY",
             description = "Geo latitude / Grid y-coord",
-            required = true, multiValued = false)
+            required = false)
     Double latOrY = null;
 
     @Argument(index = 4, name = "longOrX",
             description = "Geo longitude / Grid x-coord",
-            required = true, multiValued = false)
+            required = false)
     Double longOrX = null;
 
     @Argument(index = 5, name = "locType", description = "Location type {geo|grid}",
-            required = false, multiValued = false)
+            required = false)
     String locType = GEO;
 
     @Override
@@ -67,28 +64,15 @@
         NetworkConfigService cfgService = get(NetworkConfigService.class);
 
         TopologySimulator simulator = service.currentSimulator();
-        if (!(simulator instanceof CustomTopologySimulator)) {
-            error("Custom topology simulator is not active.");
-            return;
-        }
-
-        if (!(GEO.equals(locType) || GRID.equals(locType))) {
-            error("locType must be 'geo' or 'grid'.");
+        if (!validateSimulator(simulator) || !validateLocType(locType)) {
             return;
         }
 
         CustomTopologySimulator sim = (CustomTopologySimulator) simulator;
         DeviceId deviceId = sim.nextDeviceId();
         BasicDeviceConfig cfg = cfgService.addConfig(deviceId, BasicDeviceConfig.class);
-        cfg.name(name)
-                .locType(locType);
-
-        if (GEO.equals(locType)) {
-            cfg.latitude(latOrY).longitude(longOrX);
-        } else {
-            cfg.gridX(longOrX).gridY(latOrY);
-        }
-        cfg.apply();
+        cfg.name(name);
+        setUiCoordinates(cfg, locType, latOrY, longOrX);
 
         sim.createDevice(deviceId, name, Device.Type.valueOf(type.toUpperCase()), portCount);
     }
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullEntity.java b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullEntity.java
new file mode 100644
index 0000000..ed68dfc
--- /dev/null
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullEntity.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2018-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.provider.nil.cli;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.primitives.Longs;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.basics.BasicElementConfig;
+import org.onosproject.net.edge.EdgePortService;
+import org.onosproject.net.host.HostService;
+import org.onosproject.provider.nil.CustomTopologySimulator;
+import org.onosproject.provider.nil.TopologySimulator;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Base command for adding simulated entities to the custom topology simulation.
+ */
+public abstract class CreateNullEntity extends AbstractShellCommand {
+    protected static final String GEO = "geo";
+    protected static final String GRID = "grid";
+
+    /**
+     * Validates that the simulator is custom.
+     *
+     * @param simulator topology simulator
+     * @return true if valid
+     */
+    protected boolean validateSimulator(TopologySimulator simulator) {
+        if (!(simulator instanceof CustomTopologySimulator)) {
+            error("Custom topology simulator is not active.");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Validates that the location type is valid.
+     *
+     * @param locType location type
+     * @return true if valid
+     */
+    protected boolean validateLocType(String locType) {
+        if (!(GEO.equals(locType) || GRID.equals(locType))) {
+            error("locType must be 'geo' or 'grid'.");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Sets the UI location coordinates appropriately.
+     *
+     * @param cfg     element config
+     * @param locType location type
+     * @param latOrY  latitude or Y grid
+     * @param longOrX longitude or X grid
+     */
+    protected void setUiCoordinates(BasicElementConfig cfg,
+                                    String locType, Double latOrY, Double longOrX) {
+        if (latOrY != null && longOrX != null) {
+            cfg.locType(locType);
+            if (GEO.equals(locType)) {
+                cfg.latitude(latOrY).longitude(longOrX);
+            } else {
+                cfg.gridX(longOrX).gridY(latOrY);
+            }
+        }
+        cfg.apply();
+    }
+
+    /**
+     * Finds an available connect point among edge ports of the specified device.
+     *
+     * @param deviceId   device identifier
+     * @param otherPoint optional other point to be excluded from search
+     * @return connect point available for link or host attachment
+     */
+    protected ConnectPoint findAvailablePort(DeviceId deviceId, ConnectPoint otherPoint) {
+        EdgePortService eps = get(EdgePortService.class);
+        HostService hs = get(HostService.class);
+
+        List<ConnectPoint> points = ImmutableList
+                .sortedCopyOf((l, r) -> Longs.compare(l.port().toLong(), r.port().toLong()),
+                              eps.getEdgePoints(deviceId));
+        return points.stream()
+                .filter(p -> !Objects.equals(p, otherPoint) && hs.getConnectedHosts(p).isEmpty())
+                .findFirst().orElse(null);
+    }
+}
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java
index 5197e79..e1eb5dd 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java
@@ -16,54 +16,51 @@
 
 package org.onosproject.provider.nil.cli;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.onlab.packet.IpAddress;
-import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.config.basics.BasicHostConfig;
-import org.onosproject.net.edge.EdgePortService;
-import org.onosproject.net.host.HostService;
 import org.onosproject.provider.nil.CustomTopologySimulator;
 import org.onosproject.provider.nil.NullProviders;
 import org.onosproject.provider.nil.TopologySimulator;
 
-import java.util.HashSet;
-import java.util.Iterator;
+import java.util.Set;
+
+import static java.util.Objects.requireNonNull;
 
 /**
  * Adds a simulated end-station host to the custom topology simulation.
  */
 @Command(scope = "onos", name = "null-create-host",
         description = "Adds a simulated end-station host to the custom topology simulation")
-public class CreateNullHost extends AbstractShellCommand {
-    private static final String GEO = "geo";
-    private static final String GRID = "grid";
+public class CreateNullHost extends CreateNullEntity {
 
-    @Argument(index = 0, name = "deviceName", description = "Name of device where host is attached",
-            required = true, multiValued = false)
-    String deviceName = null;
+    @Argument(index = 0, name = "deviceNames", description = "Name of device where host is attached; comma-separated",
+            required = true)
+    String deviceNames = null;
 
-    @Argument(index = 1, name = "hostIp", description = "Host IP address",
-            required = true, multiValued = false)
-    String hostIp = null;
+    @Argument(index = 1, name = "hostIps", description = "Host IP addresses; comma-separated",
+            required = true)
+    String hostIps = null;
 
     @Argument(index = 2, name = "latOrY",
             description = "Geo latitude / Grid y-coord",
-            required = true, multiValued = false)
+            required = false)
     Double latOrY = null;
 
     @Argument(index = 3, name = "longOrX",
             description = "Geo longitude / Grid x-coord",
-            required = true, multiValued = false)
+            required = false)
     Double longOrX = null;
 
     @Argument(index = 4, name = "locType", description = "Location type {geo|grid}",
-            required = false, multiValued = false)
+            required = false)
     String locType = GEO;
 
     @Override
@@ -72,48 +69,43 @@
         NetworkConfigService cfgService = get(NetworkConfigService.class);
 
         TopologySimulator simulator = service.currentSimulator();
-        if (!(simulator instanceof CustomTopologySimulator)) {
-            error("Custom topology simulator is not active.");
-            return;
-        }
-
-        if (!(GEO.equals(locType) || GRID.equals(locType))) {
-            error("locType must be 'geo' or 'grid'.");
+        if (!validateSimulator(simulator) || !validateLocType(locType)) {
             return;
         }
 
         CustomTopologySimulator sim = (CustomTopologySimulator) simulator;
-        DeviceId deviceId = sim.deviceId(deviceName);
         HostId id = sim.nextHostId();
-        HostLocation location = findAvailablePort(deviceId);
+        Set<HostLocation> locations = getLocations(sim, deviceNames);
+        Set<IpAddress> ips = getIps(hostIps);
+
         BasicHostConfig cfg = cfgService.addConfig(id, BasicHostConfig.class);
+        setUiCoordinates(cfg, locType, latOrY, longOrX);
 
-        cfg.locType(locType);
-        cfg.setLocations(new HashSet<HostLocation>() {{ add(location); }});
+        sim.createHost(id, locations, ips);
+    }
 
-        if (GEO.equals(locType)) {
-            cfg.latitude(latOrY).longitude(longOrX);
-        } else {
-            cfg.gridX(longOrX).gridY(latOrY);
+    private Set<IpAddress> getIps(String hostIps) {
+        ImmutableSet.Builder<IpAddress> ips = ImmutableSet.builder();
+        String[] csv = hostIps.split(",");
+        for (String s : csv) {
+            ips.add(IpAddress.valueOf(s));
         }
-        cfg.apply();
+        return ips.build();
+    }
 
-        sim.createHost(id, location, IpAddress.valueOf(hostIp));
+    private Set<HostLocation> getLocations(CustomTopologySimulator sim, String deviceNames) {
+        ImmutableSet.Builder<HostLocation> locations = ImmutableSet.builder();
+        String[] csv = deviceNames.split(",");
+        for (String s : csv) {
+            locations.add(requireNonNull(findAvailablePort(sim.deviceId(s))));
+        }
+        return locations.build();
     }
 
     // Finds an available connect point among edge ports of the specified device
     private HostLocation findAvailablePort(DeviceId deviceId) {
-        EdgePortService eps = get(EdgePortService.class);
-        HostService hs = get(HostService.class);
-        Iterator<ConnectPoint> points = eps.getEdgePoints(deviceId).iterator();
-
-        while (points.hasNext()) {
-            ConnectPoint point = points.next();
-            if (hs.getConnectedHosts(point).isEmpty()) {
-                return new HostLocation(point, System.currentTimeMillis());
-            }
-        }
-        return null;
+        ConnectPoint point = findAvailablePort(deviceId, null);
+        return point == null ? null : new HostLocation(point, System.currentTimeMillis());
     }
 
 }
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullLink.java b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullLink.java
index 1b609cf..72e1781 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullLink.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullLink.java
@@ -19,40 +19,32 @@
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
-import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
-import org.onosproject.net.edge.EdgePortService;
-import org.onosproject.net.host.HostService;
 import org.onosproject.provider.nil.CustomTopologySimulator;
 import org.onosproject.provider.nil.NullProviders;
 import org.onosproject.provider.nil.TopologySimulator;
 
-import java.util.Iterator;
-import java.util.Objects;
-
 /**
  * Adds a simulated link to the custom topology simulation.
  */
 @Command(scope = "onos", name = "null-create-link",
         description = "Adds a simulated link to the custom topology simulation")
-public class CreateNullLink extends AbstractShellCommand {
+public class CreateNullLink extends CreateNullEntity {
 
     @Argument(index = 0, name = "type", description = "Link type, e.g. direct, indirect, optical",
-            required = true, multiValued = false)
+            required = true)
     String type = null;
 
     @Argument(index = 1, name = "src", description = "Source device name",
-            required = true, multiValued = false)
+            required = true)
     String src = null;
 
     @Argument(index = 2, name = "dst", description = "Destination device name",
-            required = true, multiValued = false)
+            required = true)
     String dst = null;
 
-    @Option(name = "-u", aliases = "--unidirectional", description = "Unidirectional link only",
-            required = false, multiValued = false)
+    @Option(name = "-u", aliases = "--unidirectional", description = "Unidirectional link only")
     private boolean unidirectional = false;
 
     @Override
@@ -71,19 +63,4 @@
         sim.createLink(one, two, Link.Type.valueOf(type.toUpperCase()), !unidirectional);
     }
 
-    // Finds an available connect point among edge ports of the specified device
-    private ConnectPoint findAvailablePort(DeviceId deviceId, ConnectPoint otherPoint) {
-        EdgePortService eps = get(EdgePortService.class);
-        HostService hs = get(HostService.class);
-        Iterator<ConnectPoint> points = eps.getEdgePoints(deviceId).iterator();
-
-        while (points.hasNext()) {
-            ConnectPoint point = points.next();
-            if (!Objects.equals(point, otherPoint) && hs.getConnectedHosts(point).isEmpty()) {
-                return point;
-            }
-        }
-        return null;
-    }
-
 }
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index b007af1..cfaf107 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -1471,6 +1471,7 @@
                         if (((OFErrorMsg) msg).getErrType() == OFErrorType.PORT_MOD_FAILED) {
                             LOG.error("port mod failed");
                         }
+                        break;
                     default:
                         break;
                 }
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
index f2e7137..0f2ed27 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
@@ -65,7 +65,7 @@
         this.pollInterval = pollInterval;
         task.cancel();
         task = new InternalTimerTask();
-        timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000);
+        timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000L);
     }
 
     private class InternalTimerTask extends TimerTask {
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
index 699a1b7..c67f2e9 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
@@ -306,6 +306,7 @@
                               sw.getStringId());
                     // for exiting while loop gracefully
                     interrupted = true;
+                    Thread.currentThread().interrupt();
                 }
             } else {
                 log.debug("ofFlowStatsRequestFlowSend: previous FlowStatsRequestAll (xid={})" +
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
index 73dabeb..a3644d2 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/TableStatisticsCollector.java
@@ -63,7 +63,7 @@
         this.pollInterval = pollInterval;
         task.cancel();
         task = new InternalTimerTask();
-        timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000);
+        timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000L);
     }
 
     private class InternalTimerTask extends TimerTask {
diff --git a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
index b536fda..df1bb6a 100644
--- a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
+++ b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
@@ -65,6 +65,7 @@
 import org.onosproject.openflow.controller.RoleState;
 import org.osgi.service.component.ComponentContext;
 import org.projectfloodlight.openflow.protocol.OFBucketCounter;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
 import org.projectfloodlight.openflow.protocol.OFErrorType;
 import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
@@ -237,33 +238,45 @@
 
     private void pushGroupMetrics(Dpid dpid, OFStatsReply statsReply) {
         DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
+        OpenFlowSwitch sw = controller.getSwitch(dpid);
+        boolean containsGroupStats = false;
+        if (sw != null && sw.features() != null) {
+            containsGroupStats = sw.features()
+                                   .getCapabilities()
+                                   .contains(OFCapabilities.GROUP_STATS);
+        }
 
         OFGroupStatsReply groupStatsReply = null;
         OFGroupDescStatsReply groupDescStatsReply = null;
 
-        synchronized (groupStats) {
-            if (statsReply.getStatsType() == OFStatsType.GROUP) {
-                OFStatsReply reply = groupStats.get(statsReply.getXid() + 1);
-                if (reply != null) {
-                    groupStatsReply = (OFGroupStatsReply) statsReply;
-                    groupDescStatsReply = (OFGroupDescStatsReply) reply;
-                    groupStats.remove(statsReply.getXid() + 1);
-                } else {
-                    groupStats.put(statsReply.getXid(), statsReply);
-                }
-            } else if (statsReply.getStatsType() == OFStatsType.GROUP_DESC) {
-                OFStatsReply reply = groupStats.get(statsReply.getXid() - 1);
-                if (reply != null) {
-                    groupStatsReply = (OFGroupStatsReply) reply;
-                    groupDescStatsReply = (OFGroupDescStatsReply) statsReply;
-                    groupStats.remove(statsReply.getXid() - 1);
-                } else {
-                    groupStats.put(statsReply.getXid(), statsReply);
+        if (containsGroupStats) {
+            synchronized (groupStats) {
+                if (statsReply.getStatsType() == OFStatsType.GROUP) {
+                    OFStatsReply reply = groupStats.get(statsReply.getXid() + 1);
+                    if (reply != null) {
+                        groupStatsReply = (OFGroupStatsReply) statsReply;
+                        groupDescStatsReply = (OFGroupDescStatsReply) reply;
+                        groupStats.remove(statsReply.getXid() + 1);
+                    } else {
+                        groupStats.put(statsReply.getXid(), statsReply);
+                    }
+                } else if (statsReply.getStatsType() == OFStatsType.GROUP_DESC) {
+                    OFStatsReply reply = groupStats.get(statsReply.getXid() - 1);
+                    if (reply != null) {
+                        groupStatsReply = (OFGroupStatsReply) reply;
+                        groupDescStatsReply = (OFGroupDescStatsReply) statsReply;
+                        groupStats.remove(statsReply.getXid() - 1);
+                    } else {
+                        groupStats.put(statsReply.getXid(), statsReply);
+                    }
                 }
             }
+        } else if (statsReply.getStatsType() == OFStatsType.GROUP_DESC) {
+            // We are only requesting group desc stats; see GroupStatsCollector.java:sendGroupStatisticRequests()
+            groupDescStatsReply = (OFGroupDescStatsReply) statsReply;
         }
 
-        if (providerService != null && groupStatsReply != null) {
+        if (providerService != null && groupDescStatsReply != null) {
             Collection<Group> groups = buildGroupMetrics(deviceId,
                     groupStatsReply, groupDescStatsReply);
             providerService.pushGroupMetrics(deviceId, groups);
@@ -291,6 +304,10 @@
             groups.put(id, group);
         }
 
+        if (groupStatsReply == null) {
+            return groups.values();
+        }
+
         for (OFGroupStatsEntry entry: groupStatsReply.getEntries()) {
             int groupId = entry.getGroup().getGroupNumber();
             DefaultGroup group = (DefaultGroup) groups.get(groupId);
diff --git a/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java b/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java
index ced2c2c..d439766 100644
--- a/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java
+++ b/providers/ovsdb/device/src/main/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProvider.java
@@ -221,6 +221,7 @@
             executor.awaitTermination(5, TimeUnit.SECONDS);
         } catch (InterruptedException e) {
             log.error("Timeout while waiting for child threads to finish because: " + e.getMessage());
+            Thread.currentThread().interrupt();
         }
     }
 }
diff --git a/providers/ovsdb/tunnel/src/test/java/org/onosproject/ovsdb/provider/tunnel/OvsdbTunnelProviderTest.java b/providers/ovsdb/tunnel/src/test/java/org/onosproject/ovsdb/provider/tunnel/OvsdbTunnelProviderTest.java
index 84a1855..7801c4a 100644
--- a/providers/ovsdb/tunnel/src/test/java/org/onosproject/ovsdb/provider/tunnel/OvsdbTunnelProviderTest.java
+++ b/providers/ovsdb/tunnel/src/test/java/org/onosproject/ovsdb/provider/tunnel/OvsdbTunnelProviderTest.java
@@ -26,6 +26,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.IpAddress;
 import org.onosproject.core.GroupId;
 import org.onosproject.incubator.net.tunnel.DefaultTunnelDescription;
@@ -94,7 +95,8 @@
                                                                 new GroupId(0),
                                                                 this.provider.id(),
                                                                 TunnelName.tunnelName("tunnel12"),
-                                                                new DefaultPath(this.provider.id(), links, 0.3),
+                                                                new DefaultPath(this.provider.id(), links,
+                                                                        ScalarWeight.toWeight(0.3)),
                                                                 annotations);
         provider.tunnelAdded(tunnel);
         assertEquals(1, providerService.tunnelSet.size());
@@ -119,7 +121,8 @@
                                                                 new GroupId(0),
                                                                 this.provider.id(),
                                                                 TunnelName.tunnelName("tunnel1"),
-                                                                new DefaultPath(this.provider.id(), links, 0.3),
+                                                                new DefaultPath(this.provider.id(), links,
+                                                                        ScalarWeight.toWeight(0.3)),
                                                                 annotations);
         provider.tunnelRemoved(tunnel);
         assertEquals(0, providerService.tunnelSet.size());
diff --git a/providers/pcep/cli/src/main/java/org/onosproject/pcep/cli/PcepSessionCommand.java b/providers/pcep/cli/src/main/java/org/onosproject/pcep/cli/PcepSessionCommand.java
index 086138e..c46a9a1 100644
--- a/providers/pcep/cli/src/main/java/org/onosproject/pcep/cli/PcepSessionCommand.java
+++ b/providers/pcep/cli/src/main/java/org/onosproject/pcep/cli/PcepSessionCommand.java
@@ -194,8 +194,10 @@
                                     System.out.print(sessionEstablishmentFailureMap.get(sessionFailureKey));
                                 }
                             }
+                            break;
                         case CAPABALITYNOTSUPPORTED:
                             System.out.print("Capability not supported");
+                            break;
                         case UNKNOWNOBJECT:
                             unknownObjectMap =  pcepErrorDetail.unknownObject();
                             Set<Integer> unknownObjectKeySet = unknownObjectMap.keySet();
@@ -204,6 +206,7 @@
                                     System.out.print(unknownObjectMap.get(unknownObjectKey));
                                 }
                             }
+                            break;
                         case NOTSUPPORTEDOBJECT:
                             notSupportedObjectMap =  pcepErrorDetail.notSupportedObject();
                             Set<Integer> notSupportedObjectKeySet = notSupportedObjectMap.keySet();
@@ -212,6 +215,7 @@
                                     System.out.print(notSupportedObjectMap.get(notSupportedObjectKey));
                                 }
                             }
+                            break;
                         case POLICYVIOLATION:
                             policyViolationMap =  pcepErrorDetail.policyViolation();
                             Set<Integer> policyViolationKeySet = policyViolationMap.keySet();
@@ -220,6 +224,7 @@
                                     System.out.print(policyViolationMap.get(policyViolationKey));
                                 }
                             }
+                            break;
                         case MANDATORYOBJECTMISSING:
                             mandatoryObjectMissingMap =  pcepErrorDetail.mandatoryObjectMissing();
                             Set<Integer> mandatoryObjectMissingKeySet = mandatoryObjectMissingMap.keySet();
@@ -228,12 +233,16 @@
                                     System.out.print(mandatoryObjectMissingMap.get(mandatoryObjectMissingKey));
                                 }
                             }
+                            break;
                         case SYNCHRONIZEDPATHCOMPUTATIONREQUESTMISSING:
                             System.out.print("Synchronized path computation request missing");
+                            break;
                         case UNKNOWNREQUESTREFERENCE:
                             System.out.print("Unknown request reference");
+                            break;
                         case ESTABLISHINGSECONDPCEPSESSION:
                             System.out.print("Attempt to establish a second PCEP session");
+                            break;
                         case RECEPTIONOFINVALIDOBJECT:
                             receptionOfInvalidObjectMap =  pcepErrorDetail.receptionOfInvalidObject();
                             Set<Integer> receptionOfInvalidObjectKeySet = receptionOfInvalidObjectMap.keySet();
@@ -242,6 +251,7 @@
                                     System.out.print(receptionOfInvalidObjectMap.get(receptionOfInvalidObjectKey));
                                 }
                             }
+                            break;
                         case INVALIDOPERATION:
                             invalidOperationMap =  pcepErrorDetail.invalidOperation();
                             Set<Integer> invalidOperationKeySet = invalidOperationMap.keySet();
@@ -250,10 +260,13 @@
                                     System.out.print(invalidOperationMap.get(invalidOperationKey));
                                 }
                             }
+                            break;
                         case VIRTUALNETWORKTLVMISSING:
                             System.out.print("VIRTUAL-NETWORK TLV missing");
+                            break;
                         default:
                             System.out.print("Unknown error message");
+                            break;
                     }
                 }
             }
diff --git a/providers/pcep/tunnel/src/main/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProvider.java b/providers/pcep/tunnel/src/main/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProvider.java
index d1afdc6..4b7b605 100644
--- a/providers/pcep/tunnel/src/main/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProvider.java
+++ b/providers/pcep/tunnel/src/main/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProvider.java
@@ -24,6 +24,7 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cfg.ComponentConfigService;
@@ -295,7 +296,7 @@
         // Get the pcc client
         PcepClient pc = pcepClientController.getClient(PccId.pccId(((IpTunnelEndPoint) tunnel.src()).ip()));
 
-        if (!(pc instanceof PcepClient)) {
+        if (pc == null) {
             log.error("There is no PCC connected with ip addresss {}"
                               + ((IpTunnelEndPoint) tunnel.src()).ip().toString());
             return;
@@ -352,7 +353,7 @@
 
         PcepClient pc = pcepClientController.getClient(PccId.pccId(((IpTunnelEndPoint) tunnel.src()).ip()));
 
-        if (!(pc instanceof PcepClient)) {
+        if (pc == null) {
             log.error("There is no PCC connected with this device {}"
                     + srcElement.toString());
             return;
@@ -382,7 +383,7 @@
 
         PcepClient pc = pcepClientController.getClient(PccId.pccId(((IpTunnelEndPoint) tunnel.src()).ip()));
 
-        if (!(pc instanceof PcepClient)) {
+        if (pc == null) {
             log.error("There is no PCC connected with ip addresss {}"
                     + ((IpTunnelEndPoint) tunnel.src()).ip().toString());
             return;
@@ -415,7 +416,7 @@
 
         PcepClient pc = pcepClientController.getClient(PccId.pccId(((IpElementId) srcElement).ipAddress()));
 
-        if (!(pc instanceof PcepClient)) {
+        if (pc == null) {
             log.error("There is no PCC connected with ip addresss {}"
                     + ((IpElementId) srcElement).ipAddress().toString());
             return;
@@ -459,7 +460,7 @@
 
         PcepClient pc = pcepClientController.getClient(PccId.pccId(((IpTunnelEndPoint) tunnel.src()).ip()));
 
-        if (!(pc instanceof PcepClient)) {
+        if (pc == null) {
             log.error("There is no PCC connected with ip addresss {}"
                     + ((IpTunnelEndPoint) tunnel.src()).ip().toString());
             return;
@@ -514,7 +515,7 @@
 
         PcepClient pc = pcepClientController.getClient(PccId.pccId(((IpElementId) srcElement).ipAddress()));
 
-        if (!(pc instanceof PcepClient)) {
+        if (pc == null) {
             log.error("There is no PCC connected with ip addresss {}"
                     + ((IpElementId) srcElement).ipAddress().toString());
             return;
@@ -735,7 +736,7 @@
                 .set("pathNum", String.valueOf(hopNum))
                 .set("pathState", String.valueOf(pathState))
                 .set("pathType", String.valueOf(pathtype)).build();
-        return new DefaultPath(id(), links, hopNum, extendAnnotations);
+        return new DefaultPath(id(), links, ScalarWeight.toWeight(hopNum), extendAnnotations);
     }
 
     // convert the path description to a string.
@@ -1316,7 +1317,7 @@
                         srpObj = stateRpt.getSrpObject();
                         lspObj = stateRpt.getLspObject();
 
-                        if (srpObj instanceof PcepSrpObject) {
+                        if (srpObj != null) {
                             srpId = srpObj.getSrpID();
                         }
 
@@ -1531,7 +1532,7 @@
             }
             Path path = null;
             if (!links.isEmpty()) {
-                path = new DefaultPath(providerId, links, cost, EMPTY);
+                path = new DefaultPath(providerId, links, ScalarWeight.toWeight(cost), EMPTY);
             } else if (!lspObj.getRFlag()) {
                 return;
             }
@@ -1969,6 +1970,7 @@
                     executor.awaitTermination(WAIT_TIME, TimeUnit.SECONDS);
                 } catch (InterruptedException e) {
                     log.error("updating delegation failed");
+                    Thread.currentThread().interrupt();
                 }
             }
         }
diff --git a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepReleaseTunnelProviderTest.java b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepReleaseTunnelProviderTest.java
index cfede30..121557a 100644
--- a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepReleaseTunnelProviderTest.java
+++ b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepReleaseTunnelProviderTest.java
@@ -32,6 +32,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.core.GroupId;
@@ -115,7 +116,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITH_SIGNALLING.name())
@@ -171,7 +172,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITH_SIGNALLING.name())
@@ -227,7 +228,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, SR_WITHOUT_SIGNALLING.name())
@@ -283,7 +284,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITHOUT_SIGNALLING_AND_WITHOUT_SR.name())
diff --git a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepSetupTunnelProviderTest.java b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepSetupTunnelProviderTest.java
index 375b08f8..b02e3e3 100644
--- a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepSetupTunnelProviderTest.java
+++ b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepSetupTunnelProviderTest.java
@@ -32,6 +32,8 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
+import org.onlab.graph.Weight;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.core.GroupId;
@@ -68,6 +70,8 @@
     private final TunnelServiceAdapter  tunnelService = new TunnelServiceAdapter();
     private final DeviceServiceAdapter  deviceService = new DeviceServiceAdapter();
     private final MastershipServiceAdapter  mastershipService = new MastershipServiceAdapter();
+    private static final Weight TEN_WEIGHT = ScalarWeight.toWeight(10);
+
 
     @Before
     public void setUp() throws IOException {
@@ -110,7 +114,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 10, EMPTY);
+        path = new DefaultPath(pid, links, TEN_WEIGHT, EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITH_SIGNALLING.name())
@@ -155,7 +159,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 10, EMPTY);
+        path = new DefaultPath(pid, links, TEN_WEIGHT, EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITH_SIGNALLING.name())
@@ -200,7 +204,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 10, EMPTY);
+        path = new DefaultPath(pid, links, TEN_WEIGHT, EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, SR_WITHOUT_SIGNALLING.name())
@@ -245,7 +249,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 10, EMPTY);
+        path = new DefaultPath(pid, links, TEN_WEIGHT, EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITHOUT_SIGNALLING_AND_WITHOUT_SR.name())
diff --git a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProviderTest.java b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProviderTest.java
index 15bb705..cb4123d 100644
--- a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProviderTest.java
+++ b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepTunnelProviderTest.java
@@ -28,6 +28,7 @@
 
 import org.junit.After;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.IpAddress;
 import org.onosproject.core.GroupId;
 import org.onosproject.incubator.net.tunnel.DefaultTunnel;
@@ -98,7 +99,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 10, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(10), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITH_SIGNALLING.name())
diff --git a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepUpdateTunnelProviderTest.java b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepUpdateTunnelProviderTest.java
index abef403..8d9f4e6 100644
--- a/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepUpdateTunnelProviderTest.java
+++ b/providers/pcep/tunnel/src/test/java/org/onosproject/provider/pcep/tunnel/impl/PcepUpdateTunnelProviderTest.java
@@ -31,6 +31,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.graph.ScalarWeight;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.core.GroupId;
@@ -111,7 +112,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(PLSP_ID, "1")
@@ -171,7 +172,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITH_SIGNALLING.name())
@@ -231,7 +232,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, SR_WITHOUT_SIGNALLING.name())
@@ -291,7 +292,7 @@
                 .type(Link.Type.DIRECT).build();
         links.add(link);
 
-        path = new DefaultPath(pid, links, 20, EMPTY);
+        path = new DefaultPath(pid, links, ScalarWeight.toWeight(20), EMPTY);
 
         Annotations annotations = DefaultAnnotations.builder()
                 .set(LSP_SIG_TYPE, WITHOUT_SIGNALLING_AND_WITHOUT_SR.name())
diff --git a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
index 5e33c1d..bb30b3a 100644
--- a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
+++ b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
@@ -38,7 +38,6 @@
 import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.behaviour.DevicesDiscovery;
 import org.onosproject.net.behaviour.PortAdmin;
-import org.onosproject.net.behaviour.PortDiscovery;
 import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
@@ -422,15 +421,9 @@
 
     private void discoverPorts(DeviceId deviceId) {
         Device device = deviceService.getDevice(deviceId);
-        //TODO remove when PortDiscovery is removed from master
-        if (device.is(PortDiscovery.class)) {
-            PortDiscovery portConfig = device.as(PortDiscovery.class);
-            providerService.updatePorts(deviceId, portConfig.getPorts());
-        } else {
-            DeviceDescriptionDiscovery deviceDescriptionDiscovery =
-                    device.as(DeviceDescriptionDiscovery.class);
-            providerService.updatePorts(deviceId, deviceDescriptionDiscovery.discoverPortDetails());
-        }
+        DeviceDescriptionDiscovery deviceDescriptionDiscovery =
+                device.as(DeviceDescriptionDiscovery.class);
+        providerService.updatePorts(deviceId, deviceDescriptionDiscovery.discoverPortDetails());
     }
 
     private boolean testDeviceConnection(RestSBDevice dev) {
@@ -453,6 +446,7 @@
                 return false;
             } catch (InterruptedException ex) {
                 log.warn("Connection to device {} interrupted", dev.deviceId());
+                Thread.currentThread().interrupt();
                 return false;
             } catch (ExecutionException ex) {
                 log.warn("Connection to device {} had a execution exception", dev.deviceId());
diff --git a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java b/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
index 281a7b3..c4fdcd1 100644
--- a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
+++ b/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProvider.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.provider.snmp.device.impl;
 
-import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -25,7 +24,6 @@
 import org.onlab.packet.ChassisId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
-import org.onosproject.net.config.ConfigException;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
@@ -54,14 +52,12 @@
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -106,16 +102,7 @@
     protected final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
 
 
-    protected final List<ConfigFactory> factories = ImmutableList.of(
-            new ConfigFactory<ApplicationId, SnmpProviderConfig>(APP_SUBJECT_FACTORY,
-                                                                 SnmpProviderConfig.class,
-                                                                 "snmp_devices",
-                                                                 true) {
-                @Override
-                public SnmpProviderConfig createConfig() {
-                    return new SnmpProviderConfig();
-                }
-            },
+    protected final ConfigFactory factory =
             new ConfigFactory<DeviceId, SnmpDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
                                                           SnmpDeviceConfig.class,
                                                           SCHEME) {
@@ -123,7 +110,7 @@
                 public SnmpDeviceConfig createConfig() {
                     return new SnmpDeviceConfig();
                 }
-            });
+            };
 
 
     /**
@@ -139,10 +126,9 @@
 
         providerService = providerRegistry.register(this);
         appId = coreService.registerApplication(APP_NAME);
-        factories.forEach(netCfgService::registerConfigFactory);
+        netCfgService.registerConfigFactory(factory);
         netCfgService.addListener(cfgLister);
         connectDevices();
-        addOrRemoveDevicesConfig();
         modified(context);
         log.info("Started");
     }
@@ -156,10 +142,11 @@
             });
             deviceBuilderExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
             log.error("Device builder did not terminate");
         }
         deviceBuilderExecutor.shutdownNow();
-        factories.forEach(netCfgService::unregisterConfigFactory);
+        netCfgService.unregisterConfigFactory(factory);
         netCfgService.removeListener(cfgLister);
         providerRegistry.unregister(this);
         providerService = null;
@@ -171,23 +158,6 @@
         log.info("Modified");
     }
 
-    //Old method to register devices provided via net-cfg under apps/snmp/ tree
-    private void addOrRemoveDevicesConfig() {
-        SnmpProviderConfig cfg = netCfgService.getConfig(appId, SnmpProviderConfig.class);
-        if (cfg != null) {
-            try {
-                cfg.getDevicesInfo().forEach(info -> {
-                    buildDevice(new DefaultSnmpDevice(info.ip().toString(),
-                                                      info.port(), info.username(),
-                                                      info.password()));
-
-                });
-            } catch (ConfigException e) {
-                log.error("Cannot read config error " + e);
-            }
-        }
-    }
-
     //Method to register devices provided via net-cfg under devices/ tree
     private void connectDevices() {
         Set<DeviceId> deviceSubjects =
@@ -343,14 +313,12 @@
             } else {
                 log.warn("Injecting device via this Json is deprecated, " +
                                  "please put configuration under devices/");
-                addOrRemoveDevicesConfig();
             }
         }
 
         @Override
         public boolean isRelevant(NetworkConfigEvent event) {
-            return (event.configClass().equals(SnmpDeviceConfig.class) ||
-                    event.configClass().equals(SnmpProviderConfig.class)) &&
+            return (event.configClass().equals(SnmpDeviceConfig.class)) &&
                     (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
                             event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
         }
diff --git a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpProviderConfig.java b/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpProviderConfig.java
deleted file mode 100644
index 43f4ad7..0000000
--- a/providers/snmp/device/src/main/java/org/onosproject/provider/snmp/device/impl/SnmpProviderConfig.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2016-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.provider.snmp.device.impl;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.ConfigException;
-import org.onosproject.net.config.Config;
-
-import java.util.Set;
-
-/**
- * Configuration decoder for SNMP provider.
- * @deprecated 1.10.0 Kingfisher
- */
-@Deprecated
-@Beta
-public class SnmpProviderConfig extends Config<ApplicationId> {
-
-    public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
-    private static final String IP = "ip";
-    private static final int DEFAULT_TCP_PORT = 830;
-    private static final String PORT = "port";
-    private static final String NAME = "username";
-    private static final String PASSWORD = "password";
-
-    /**
-     * Retrieves a set of SnmpDeviceInfo containing all the device
-     * configuration pertaining to the SNMP device provider.
-     * @return set of device configurations.
-     *
-     * @throws ConfigException if configuration can't be read
-     */
-    public Set<SnmpDeviceInfo> getDevicesInfo() throws ConfigException {
-        Set<SnmpDeviceInfo> deviceInfos = Sets.newHashSet();
-
-        try {
-            for (JsonNode node : array) {
-                String ip = node.path(IP).asText();
-                IpAddress ipAddr = ip.isEmpty() ? null : IpAddress.valueOf(ip);
-                int port = node.path(PORT).asInt(DEFAULT_TCP_PORT);
-                String name = node.path(NAME).asText();
-                String password = node.path(PASSWORD).asText();
-                deviceInfos.add(new SnmpDeviceInfo(ipAddr, port, name, password));
-
-            }
-        } catch (IllegalArgumentException e) {
-            throw new ConfigException(CONFIG_VALUE_ERROR, e);
-        }
-
-        return deviceInfos;
-    }
-
-    /**
-     * Contains information about a SNMP device retrieved form the net-cfg subsystem.
-     */
-    public class SnmpDeviceInfo {
-        private final IpAddress ip;
-        private final int port;
-        private final String username;
-        private final String password;
-
-        /**
-         * Build an information object containing the given device specifics.
-         * @param ip ip
-         * @param port port
-         * @param username username
-         * @param password password (a.k.a community in SNMP)
-         */
-        public SnmpDeviceInfo(IpAddress ip, int port, String username, String password) {
-            this.ip = ip;
-            this.port = port;
-            this.username = username;
-            this.password = password;
-        }
-
-        /**
-         * Returns IpAddress of the device.
-         * @return ip
-         */
-        public IpAddress ip() {
-            return ip;
-        }
-
-        /**
-         * Returns port of the device.
-         * @return port
-         */
-        public int port() {
-            return port;
-        }
-
-        /**
-         * Returns username of the device.
-         * @return username
-         */
-        public String username() {
-            return username;
-        }
-
-        /**
-         * Returns password of the device.
-         * @return password
-         */
-        public String password() {
-            return password;
-        }
-    }
-
-}
-
diff --git a/providers/snmp/device/src/test/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProviderTest.java b/providers/snmp/device/src/test/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProviderTest.java
index c9e20b2..49374cc 100644
--- a/providers/snmp/device/src/test/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProviderTest.java
+++ b/providers/snmp/device/src/test/java/org/onosproject/provider/snmp/device/impl/SnmpDeviceProviderTest.java
@@ -21,12 +21,10 @@
 import com.google.common.collect.ImmutableSet;
 import org.junit.Before;
 import org.junit.Test;
-import org.onlab.packet.IpAddress;
 import org.onosproject.TestApplicationId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.CoreServiceAdapter;
-import org.onosproject.net.config.ConfigException;
 import org.onosproject.net.AbstractProjectableModel;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DefaultDevice;
@@ -60,7 +58,11 @@
 import java.util.HashSet;
 import java.util.Set;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.onlab.junit.TestTools.assertAfter;
 
 /**
@@ -79,14 +81,10 @@
     protected CoreService coreService = new MockCoreService();
     private final DeviceProviderService deviceProviderService = new MockDeviceProviderService();
     private final TestApplicationId applicationId = new TestApplicationId("TestAppId");
-    private final SnmpProviderConfig snmpProviderConfig = new MockSnmpProviderConfig();
     private final DeviceId deviceId = DeviceId.deviceId("snmp:1.1.1.1:1");
     private final DeviceId wrongDeviceId = DeviceId.deviceId("snmp:2.2.2.2:2");
     private final Set<ConfigFactory> cfgFactories = new HashSet<>();
     private final Set<NetworkConfigListener> netCfgListeners = new HashSet<>();
-    private final NetworkConfigEvent deviceAddedEvent =
-            new NetworkConfigEvent(NetworkConfigEvent.Type.CONFIG_ADDED,
-                                   null, SnmpProviderConfig.class);
     private final NetworkConfigEvent deviceAddedIrrelevantEvent =
             new NetworkConfigEvent(NetworkConfigEvent.Type.CONFIG_ADDED,
                                    null, BasicDeviceConfig.class);
@@ -119,7 +117,7 @@
     public void testActivate() {
         assertEquals("Incorrect provider service", deviceProviderService, provider.providerService);
         assertEquals("Incorrect application id", applicationId, provider.appId);
-        assertTrue("Incorrect config factories", cfgFactories.containsAll(provider.factories));
+        assertTrue("Incorrect config factories", cfgFactories.contains(provider.factory));
         assertTrue("Incorrect network config listener", netCfgListeners.contains(provider.cfgLister));
 
 
@@ -145,8 +143,6 @@
 
     @Test
     public void addDevice() {
-        assertTrue("Event should be relevant", provider.cfgLister.isRelevant(deviceAddedEvent));
-        provider.cfgLister.event(deviceAddedEvent);
         AbstractProjectableModel.setDriverService(null, new MockDriverService());
         //FIXME this needs sleep
         assertAfter(DELAY, TEST_DURATION, () ->
@@ -219,9 +215,7 @@
 
         @Override
         public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
-            if (configClass.equals(SnmpProviderConfig.class)) {
-                return (C) snmpProviderConfig;
-            } else if (configClass.equals(SnmpDeviceConfig.class)) {
+            if (configClass.equals(SnmpDeviceConfig.class)) {
                 return (C) config;
             } else {
                 return (C) new BasicDeviceConfig();
@@ -271,16 +265,6 @@
         }
     }
 
-    private class MockSnmpProviderConfig extends SnmpProviderConfig {
-        protected SnmpDeviceInfo deviceInfo = new SnmpDeviceInfo(IpAddress.valueOf("1.1.1.1"), 1, "test", "test");
-
-        @Override
-        public Set<SnmpProviderConfig.SnmpDeviceInfo> getDevicesInfo() throws ConfigException {
-            return ImmutableSet.of(deviceInfo);
-        }
-
-    }
-
     private class MockDriverService extends DriverServiceAdapter {
 
     }
diff --git a/providers/tl1/device/src/main/java/org/onosproject/provider/tl1/device/impl/Tl1DeviceProvider.java b/providers/tl1/device/src/main/java/org/onosproject/provider/tl1/device/impl/Tl1DeviceProvider.java
index 1dceeb5..04c3120 100644
--- a/providers/tl1/device/src/main/java/org/onosproject/provider/tl1/device/impl/Tl1DeviceProvider.java
+++ b/providers/tl1/device/src/main/java/org/onosproject/provider/tl1/device/impl/Tl1DeviceProvider.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.provider.tl1.device.impl;
 
-import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -24,7 +23,6 @@
 import org.onlab.packet.ChassisId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
-import org.onosproject.net.config.ConfigException;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
@@ -59,11 +57,9 @@
 import java.net.Socket;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
-import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -109,16 +105,7 @@
     private Tl1Listener tl1Listener = new InnerTl1Listener();
     private DeviceProviderService providerService;
 
-    private final List<ConfigFactory> factories = ImmutableList.of(
-            new ConfigFactory<ApplicationId, Tl1ProviderConfig>(APP_SUBJECT_FACTORY,
-                                                                Tl1ProviderConfig.class,
-                                                                "tl1_devices",
-                                                                true) {
-                @Override
-                public Tl1ProviderConfig createConfig() {
-                    return new Tl1ProviderConfig();
-                }
-            },
+    private final ConfigFactory factory =
             new ConfigFactory<DeviceId, Tl1DeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
                                                          Tl1DeviceConfig.class,
                                                          Tl1DeviceConfig.TL1) {
@@ -126,7 +113,7 @@
                 public Tl1DeviceConfig createConfig() {
                     return new Tl1DeviceConfig();
                 }
-            });
+            };
 
     @Activate
     public void activate() {
@@ -134,8 +121,7 @@
         providerService = providerRegistry.register(this);
         cfgRegistry.addListener(cfgListener);
         controller.addListener(tl1Listener);
-        factories.forEach(cfgRegistry::registerConfigFactory);
-        registerDevices();
+        cfgRegistry.registerConfigFactory(factory);
         connectDevices();
         log.info("Started");
     }
@@ -149,7 +135,7 @@
             deviceAdminService.removeDevice(deviceId);
         });
         providerRegistry.unregister(this);
-        factories.forEach(cfgRegistry::unregisterConfigFactory);
+        cfgRegistry.unregisterConfigFactory(factory);
         providerService = null;
         log.info("Stopped");
     }
@@ -210,21 +196,6 @@
         // TODO
     }
 
-    //Old method to register devices provided via net-cfg under apps/tl1/ tree
-    void registerDevices() {
-        Tl1ProviderConfig cfg = cfgRegistry.getConfig(appId, Tl1ProviderConfig.class);
-
-        if (cfg == null) {
-            return;
-        }
-
-        try {
-            cfg.readDevices().forEach(this::connectDevice);
-        } catch (ConfigException e) {
-            log.error("Cannot parse network configuration", e);
-        }
-    }
-
     //Method to register devices provided via net-cfg under devices/ tree
     private void connectDevices() {
         Set<DeviceId> deviceSubjects =
@@ -302,7 +273,6 @@
                 } else {
                     log.warn("Injecting device via this Json is deprecated, " +
                                      "please put configuration under devices/");
-                    registerDevices();
                 }
             } else if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
                 // TODO: calculate delta
@@ -311,7 +281,6 @@
                 } else {
                     log.warn("Injecting device via this Json is deprecated, " +
                                      "please put configuration under devices/");
-                    registerDevices();
                 }
             } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
                 controller.getDeviceIds().forEach(deviceId -> {
@@ -323,8 +292,7 @@
 
         @Override
         public boolean isRelevant(NetworkConfigEvent event) {
-            return (event.configClass().equals(Tl1DeviceConfig.class) ||
-                    event.configClass().equals(Tl1ProviderConfig.class)) &&
+            return (event.configClass().equals(Tl1DeviceConfig.class)) &&
                     (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
                             event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED ||
                             event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED);
diff --git a/providers/tl1/device/src/main/java/org/onosproject/provider/tl1/device/impl/Tl1ProviderConfig.java b/providers/tl1/device/src/main/java/org/onosproject/provider/tl1/device/impl/Tl1ProviderConfig.java
deleted file mode 100644
index a2dc587..0000000
--- a/providers/tl1/device/src/main/java/org/onosproject/provider/tl1/device/impl/Tl1ProviderConfig.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016-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.provider.tl1.device.impl;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.ConfigException;
-import org.onosproject.net.config.Config;
-import org.onosproject.tl1.DefaultTl1Device;
-import org.onosproject.tl1.Tl1Device;
-
-import java.util.Set;
-
-/**
- * Configuration for TL1 provider.
- * @deprecated 1.10.0 Kingfisher
- *
- */
-@Deprecated
-public class Tl1ProviderConfig extends Config<ApplicationId> {
-    public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
-    private static final String IP = "ip";
-    private static final String PORT = "port";
-    private static final String USERNAME = "username";
-    private static final String PASSWORD = "password";
-
-    Set<Tl1Device> readDevices() throws ConfigException {
-        Set<Tl1Device> devices = Sets.newHashSet();
-
-        try {
-            for (JsonNode node : array) {
-                String ip = node.path(IP).asText();
-                IpAddress ipAddress = IpAddress.valueOf(ip);
-                int port = node.path(PORT).asInt();
-                String username = node.path(USERNAME).asText();
-                String password = node.path(PASSWORD).asText();
-                devices.add(new DefaultTl1Device(ipAddress, port, username, password));
-            }
-        } catch (IllegalArgumentException e) {
-            throw new ConfigException(CONFIG_VALUE_ERROR, e);
-        }
-
-        return devices;
-    }
-}
diff --git a/tools/build/onos-buck b/tools/build/onos-buck
index 7312f72..70c4414 100755
--- a/tools/build/onos-buck
+++ b/tools/build/onos-buck
@@ -5,8 +5,11 @@
 
 set -e
 
-BUCK_URL="http://repo1.maven.org/maven2/org/onosproject/onos-buck/v2018.01.17.01/buck-v2018.01.17.01.zip"
-BUCK_SHA="4a70a84ef40a06762a7248db25590696e80af9fe"
+BUCK_URL="http://repo1.maven.org/maven2/org/onosproject/onos-buck/v2018.02.09.01/buck-v2018.02.09.01.zip"
+BUCK_SHA="45d8bd28f441991257babf89f7a317edb3a2b536"
+
+# onos-yang-tools buck plugin version
+YANG_VER="2.4.1"
 
 [  "-U" = "$1" ] && shift && FORCE_UPDATE=True
 
@@ -39,6 +42,45 @@
     rm -rf $ROOT_DIR/buck-out
     printf "Successfully updated Buck in $ROOT_DIR/bin/buck to $BUCK_FILE\n\n"
 fi
+
+# Fetch & install onos yang tools buck plugin
+YANG_PLUGIN_CACHE="cache/onos-yang-compiler-buck-plugin-$YANG_VER.jar"
+if hash mvn 2>/dev/null; then
+  if [[ $YANG_VER = *"-SNAPSHOT" ]] || [ ! -f "$YANG_PLUGIN_CACHE" ]; then
+    ARTIFACT="org.onosproject:onos-yang-compiler-buck-plugin:$YANG_VER"
+    mvn org.apache.maven.plugins:maven-dependency-plugin:3.0.2:copy \
+        -Dartifact=$ARTIFACT \
+        -Dtransitive=false -Dmdep.overWriteSnapshots=true \
+        -DoutputDirectory=cache > /dev/null
+  fi
+else
+  if [ ! -f "$YANG_PLUGIN_CACHE" ]; then
+    if [[ $YANG_VER = *"-SNAPSHOT" ]]; then
+      echo "mvn command must be installed to handle SNAPSHOT version"
+      exit 1
+    fi
+
+    curl -o "$YANG_PLUGIN_CACHE" \
+      -L https://repo1.maven.org/maven2/org/onosproject/onos-yang-compiler-buck-plugin/$YANG_VER/onos-yang-compiler-buck-plugin-$YANG_VER.jar
+  fi
+
+  if [[ $YANG_VER != *"-SNAPSHOT" ]] && hash shasum 2>/dev/null; then
+    SHA=$(shasum $YANG_PLUGIN_CACHE | cut -d' ' -f1)
+    if [ ! -f "$YANG_PLUGIN_CACHE".sha1 ]; then
+      curl -o "$YANG_PLUGIN_CACHE".sha1 \
+        -L https://repo1.maven.org/maven2/org/onosproject/onos-yang-compiler-buck-plugin/$YANG_VER/onos-yang-compiler-buck-plugin-$YANG_VER.jar.sha1
+    fi
+    YANG_PLUGIN_SHA=$(cat "$YANG_PLUGIN_CACHE".sha1)
+    if [ "$SHA" != "$YANG_PLUGIN_SHA" ]; then
+       echo "ERROR: Downloaded SHA ($SHA) did not match expected SHA ($YANG_PLUGIN_SHA)" &&
+       rm -f $YANG_PLUGIN_CACHE $YANG_PLUGIN_CACHE.sha1 && exit 1
+     fi
+  else
+    echo "SHA verification skipped"
+  fi
+fi
+install -Cv "$YANG_PLUGIN_CACHE" plugins/yang.jar
+
 popd > /dev/null
 
 BUCK=$ROOT_DIR/bin/buck
@@ -47,5 +89,10 @@
   export NO_BUCKD=1
 fi
 
+# HACK: Clean-up frequent problem-causers from buck-out
+rm -fr \
+    $ONOS_ROOT/buck-out/bin/lib/.netty \
+    $ONOS_ROOT/buck-out/bin/lib/.KRYO
+
 # Finally, run the Buck command...
 $BUCK "$@"
diff --git a/tools/dev/bash_profile b/tools/dev/bash_profile
index 3dc3f89..aca8a2c 100644
--- a/tools/dev/bash_profile
+++ b/tools/dev/bash_profile
@@ -64,6 +64,9 @@
 alias op='onos-package'
 alias ot='onos-test'
 
+alias obr='while ! ob; do echo "retrying"; done'
+alias opr='while ! op; do echo "retrying"; done'
+
 alias deprecatedAlias='echo "This alias has been deprecated."'
 alias obi=deprecatedAlias
 alias obs=deprecatedAlias
diff --git a/tools/dev/bin/patch-yang-libs b/tools/dev/bin/patch-yang-libs
index 9e590d7..2686836 100755
--- a/tools/dev/bin/patch-yang-libs
+++ b/tools/dev/bin/patch-yang-libs
@@ -3,8 +3,8 @@
 # Patches lib/BUCK file to use locally built YANG tools.
 # -----------------------------------------------------------------------------
 
-BVER=2.3.1
-SVER=2.4-SNAPSHOT
+BVER=2.4
+SVER=2.5-SNAPSHOT
 
 YANG_TOOLS_ROOT=${YANG_TOOLS_ROOT:-~/onos-yang-tools}
 
@@ -45,6 +45,12 @@
 if [ ! -f "$YANG_PLUGIN_SRC" ]; then
     mvn -f $YANG_TOOLS_ROOT/pom.xml -am -pl :onos-yang-compiler-buck-plugin install -DskipTests -Dcheckstyle.skip
 fi
-# Patch the YANG BUCK plugin
-cp -p $YANG_PLUGIN_SRC \
-        $ONOS_ROOT/bin/plugins/yang.jar
+# populate buck plugin cache with SNAPSHOT version
+ARTIFACT="org.onosproject:onos-yang-compiler-buck-plugin:$SVER"
+mvn org.apache.maven.plugins:maven-dependency-plugin:3.0.2:copy \
+    -Dartifact=$ARTIFACT \
+    -Dtransitive=false -Dmdep.overWriteSnapshots=true \
+    -DoutputDirectory=$ONOS_ROOT/bin/cache > /dev/null
+
+# Patch the YANG BUCK plugin version specified
+sed -i.bak "s/YANG_VER=\"$BVER\"/YANG_VER=\"$SVER\"/" $ONOS_ROOT/tools/build/onos-buck
diff --git a/tools/dev/mininet/bmv2.py b/tools/dev/mininet/bmv2.py
index 87ed1ba..ad3d248 100644
--- a/tools/dev/mininet/bmv2.py
+++ b/tools/dev/mininet/bmv2.py
@@ -83,7 +83,8 @@
     def __init__(self, name, json=None, debugger=False, loglevel="warn",
                  elogger=False, grpcPort=None, cpuPort=255,
                  thriftPort=None, netcfg=True, dryrun=False, pipeconfId="",
-                 pktdump=False, valgrind=False, injectPorts=False, **kwargs):
+                 pktdump=False, valgrind=False, withGnmi=False,
+                 injectPorts=True, **kwargs):
         Switch.__init__(self, name, **kwargs)
         self.grpcPort = pickUnusedPort() if not grpcPort else grpcPort
         self.thriftPort = pickUnusedPort() if not thriftPort else thriftPort
@@ -108,6 +109,7 @@
         self.netcfgfile = '/tmp/bmv2-%d-netcfg.json' % self.deviceId
         self.pipeconfId = pipeconfId
         self.injectPorts = parseBoolean(injectPorts)
+        self.withGnmi = parseBoolean(withGnmi)
         self.longitude = kwargs['longitude'] if 'longitude' in kwargs else None
         self.latitude = kwargs['latitude'] if 'latitude' in kwargs else None
         self.onosDeviceId = "device:bmv2:%d" % self.deviceId
@@ -147,10 +149,6 @@
                     "port": self.grpcPort,
                     "deviceId": self.deviceId,
                     "deviceKeyId": "p4runtime:%s" % self.onosDeviceId
-                },
-                "gnmi": {
-                    "ip": srcIP,
-                    "port": self.grpcPort
                 }
             },
             "piPipeconf": {
@@ -159,7 +157,13 @@
             "basic": basicCfg
         }
 
-        if(self.injectPorts):
+        if self.withGnmi:
+            cfgData["generalprovider"]["gnmi"] = {
+                "ip": srcIP,
+                "port": self.grpcPort
+            }
+
+        if self.injectPorts:
             portData = {}
             portId = 1
             for intfName in self.intfNames():
diff --git a/tools/dev/p4vm/README.md b/tools/dev/p4vm/README.md
index de9edb7..11cccd3 100644
--- a/tools/dev/p4vm/README.md
+++ b/tools/dev/p4vm/README.md
@@ -88,7 +88,7 @@
 
 ```bash
 cd $ONOS_ROOT/tools/dev/p4vm
-./build-ova.sh
+./export-ova.sh
 ```
 
 This script will:
diff --git a/tools/dev/p4vm/export-ova.sh b/tools/dev/p4vm/export-ova.sh
index 7b94f23..757f94b 100755
--- a/tools/dev/p4vm/export-ova.sh
+++ b/tools/dev/p4vm/export-ova.sh
@@ -15,13 +15,11 @@
     ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
     -p ${SSH_PORT} sdn@127.0.0.1 "bash /vagrant/pre-ova-cleanup.sh"
 
-# Wait for VM to power off
-sleep 10
-
-# Make sure VM is not running
-vagrant halt
-
 sleep 5
+vboxmanage controlvm ${VB_UUID} acpipowerbutton
+
+# Wait for VM to power off
+sleep 30
 
 # Remove vagrant shared folder
 vboxmanage sharedfolder remove ${VB_UUID} -name "vagrant"
diff --git a/tools/dev/p4vm/install-p4-tools.sh b/tools/dev/p4vm/install-p4-tools.sh
index f3df6a4..8797707 100755
--- a/tools/dev/p4vm/install-p4-tools.sh
+++ b/tools/dev/p4vm/install-p4-tools.sh
@@ -259,12 +259,15 @@
     git submodule update --init --recursive
 
     ./autogen.sh
-    ./configure --with-proto --with-sysrepo 'CXXFLAGS=-O0 -g'
+    # FIXME: re-enable --with-sysrepo when gNMI support becomes more stable
+    # ./configure --with-proto --with-sysrepo 'CXXFLAGS=-O0 -g'
+    ./configure --with-proto 'CXXFLAGS=-O0 -g'
     make -j${NUM_CORES}
     sudo make install
     sudo ldconfig
 
-    sudo proto/sysrepo/install_yangs.sh
+    # FIXME: re-enable when gNMI support becomes more stable
+    # sudo proto/sysrepo/install_yangs.sh
 }
 
 function do_bmv2 {
@@ -279,7 +282,10 @@
     # Simple_switch_grpc target
     cd targets/simple_switch_grpc
     ./autogen.sh
-    ./configure --with-sysrepo --with-thrift 'CXXFLAGS=-O0 -g'
+
+    # FIXME: re-enable --with-sysrepo when gNMI support becomes more stable
+    # ./configure --with-sysrepo --with-thrift 'CXXFLAGS=-O0 -g'
+    ./configure --with-thrift 'CXXFLAGS=-O0 -g'
     make -j${NUM_CORES}
     sudo make install
     sudo ldconfig
@@ -381,8 +387,9 @@
 # In dependency order.
 check_and_do ${PROTOBUF_COMMIT} protobuf do_protobuf protobuf
 check_and_do ${GRPC_COMMIT} grpc do_grpc grpc
-check_and_do ${LIBYANG_COMMIT} libyang do_libyang libyang
-check_and_do ${SYSREPO_COMMIT} sysrepo do_sysrepo sysrepo
+# FIXME: re-enable when gNMI support becomes more stable
+# check_and_do ${LIBYANG_COMMIT} libyang do_libyang libyang
+# check_and_do ${SYSREPO_COMMIT} sysrepo do_sysrepo sysrepo
 check_and_do ${BMV2_COMMIT} bmv2 do_pi_bmv2_deps bmv2-deps
 check_and_do ${PI_COMMIT} p4runtime do_p4runtime p4runtime
 check_and_do ${BMV2_COMMIT} bmv2 do_bmv2 bmv2
diff --git a/tools/dev/p4vm/pre-ova-cleanup.sh b/tools/dev/p4vm/pre-ova-cleanup.sh
index dcfecc9..1f52148 100755
--- a/tools/dev/p4vm/pre-ova-cleanup.sh
+++ b/tools/dev/p4vm/pre-ova-cleanup.sh
@@ -16,5 +16,3 @@
 rm -rf ~/p4tools/sysrepo/build
 
 cat /dev/null > ~/.bash_history
-
-sudo poweroff
diff --git a/tools/package/bin/onos-user-key b/tools/package/bin/onos-user-key
index ec496f6..a9924ce 100755
--- a/tools/package/bin/onos-user-key
+++ b/tools/package/bin/onos-user-key
@@ -28,4 +28,4 @@
 (umask 077; touch "$HOME/.ssh/known_hosts")
 
 # Also, remove any previous known keys for the localhost.
-ssh-keygen -f "$HOME/.ssh/known_hosts" -R [localhost]:8101
+which ssh-keygen >/dev/null && ssh-keygen -f "$HOME/.ssh/known_hosts" -R [localhost]:8101
diff --git a/tools/test/bin/onos-fetch-db b/tools/test/bin/onos-fetch-db
index 0073465..b25adbf 100755
--- a/tools/test/bin/onos-fetch-db
+++ b/tools/test/bin/onos-fetch-db
@@ -39,5 +39,6 @@
 for node in $nodes; do
     echo "fetching from ${node}..."
     mkdir -p ${node}
-    scp -p -r $ONOS_USER@${node}:$ONOS_INSTALL_DIR/karaf/data/db/partitions/* ./${node}/
+    scp -p -r $ONOS_USER@${node}:$ONOS_INSTALL_DIR/karaf/data/partitions/* ./${node}/
 done
+
diff --git a/tools/test/bin/onos-remove-cell-sshkeys b/tools/test/bin/onos-remove-cell-sshkeys
new file mode 100755
index 0000000..3c7b70c
--- /dev/null
+++ b/tools/test/bin/onos-remove-cell-sshkeys
@@ -0,0 +1,9 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Removes known_host entries about current ONOS cell.
+# -----------------------------------------------------------------------------
+
+for host in $OCT $OCN $(env | egrep "^OC[0-9]+" | cut -d '=' -f 2); do
+  ssh-keygen -F "$host" >/dev/null && ssh-keygen -R "$host"
+  ssh-keygen -F "[$host]:8101" >/dev/null && ssh-keygen -R "[$host]:8101"
+done
diff --git a/tools/test/bin/onos-verify-cell b/tools/test/bin/onos-verify-cell
index 7361616..8999ad4 100755
--- a/tools/test/bin/onos-verify-cell
+++ b/tools/test/bin/onos-verify-cell
@@ -7,5 +7,5 @@
 . $ONOS_ROOT/tools/build/envDefaults
 
 for node in $OCT $OCN $(env | sort | egrep "^OC[0-9]+" | cut -d= -f2); do
-    printf "%s: " $node; ssh -n -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o PasswordAuthentication=no $ONOS_USER@$node hostname
+    printf "%s: " $node; ssh -n -q -o StrictHostKeyChecking=no -o PasswordAuthentication=no $ONOS_USER@$node hostname
 done
diff --git a/tools/test/bin/stc-warden b/tools/test/bin/stc-warden
index 20baff2..24a924a 100755
--- a/tools/test/bin/stc-warden
+++ b/tools/test/bin/stc-warden
@@ -11,6 +11,10 @@
 for slave in $CELL_SLAVES; do
     echo "========================================================"
     echo "$slave:"
+    ssh sdn@$slave "touch foo && echo 'Disk OK' || echo 'Disk READ-ONLY'"
+    let ok=ok+$?
+    ssh sdn@$slave "df -h /"
+    let ok=ok+$?
     ssh sdn@$slave sudo lxc-ls --fancy
     let ok=ok+$?
 done
diff --git a/tools/test/topos/cfab-null b/tools/test/topos/cfab-null
new file mode 100755
index 0000000..8993d2e
--- /dev/null
+++ b/tools/test/topos/cfab-null
@@ -0,0 +1,85 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Creates a spine-leaf fabric with large number of hosts using null providers
+# -----------------------------------------------------------------------------
+
+# config
+node=${1:-$OCI}
+
+# Create the script of ONOS commands first and then execute it all at once.
+export CMDS="/tmp/fab-onos.cmds"
+rm $CMDS
+
+function sim {
+    echo "$@" >> $CMDS
+}
+
+sim "wipe-out please"
+
+spinePorts=48
+leafPorts=64
+accessPorts=1024
+
+# Create spines
+for spine in {1..2}; do
+    sim "null-create-device switch Spine-${spine} ${spinePorts}"
+done
+
+# Create 2 leaf pairs with dual links to the spines and a link between the pair
+for pair in A B; do
+    sim "null-create-device switch Leaf-${pair}1 ${leafPorts}"
+    sim "null-create-device switch Leaf-${pair}2 ${leafPorts}"
+    sim "null-create-link direct Leaf-${pair}1 Leaf-${pair}2"
+
+    for spine in {1..2}; do
+        for link in {1..2}; do
+            sim "null-create-link direct Spine-${spine} Leaf-${pair}1"
+            sim "null-create-link direct Spine-${spine} Leaf-${pair}2"
+        done
+    done
+
+    # Create hosts for each leaf group; multi-homed to each leaf in the pair
+    [ $pair = A ] && pn=1 || pn=2
+    for host in {1..10}; do
+        sim "null-create-host Leaf-${pair}1,Leaf-${pair}2 10.${pn}.1.${host}"
+    done
+done
+
+# Create 8 single leafs with dual links to the spines
+for access in {1..8}; do
+    sim "null-create-device switch Access-${access} ${accessPorts}"
+
+    for spine in {1..2}; do
+        for link in {1..2}; do
+            sim "null-create-link direct Spine-${spine} Access-${access}"
+        done
+    done
+
+    # Create hosts for each single leaf
+    for host in {1..25}; do
+        sim "null-create-host Access-${access} 10.0.${access}.${host}"
+    done
+done
+
+
+
+# make sure null providers are activated
+onos ${node} app activate org.onosproject.null
+
+sleep 2
+
+# start custom simulation..
+onos ${node} null-simulation start custom
+
+# Generate the recipe using the following:
+# 2 spines, can potentially be few more
+# 12 leaves in total
+#     2 leaf pair
+#     8 non-paired
+# Host per leaf up to 1K
+
+sleep 5
+
+# Add devices, links, and hosts
+cat $CMDS | onos ${node}
+
diff --git a/tools/test/topos/onosnet.py b/tools/test/topos/onosnet.py
index f8e4f6a..adb4a10 100644
--- a/tools/test/topos/onosnet.py
+++ b/tools/test/topos/onosnet.py
@@ -49,6 +49,7 @@
         Mininet.start( self )
         if self.gratArp:
             self.waitConnected( timeout=5 )
+            sleep(2)
             info ( '*** Sending a gratuitious ARP from each host\n' )
             self.gratuitousArp()
 
diff --git a/tools/test/topos/tower b/tools/test/topos/tower
deleted file mode 100755
index 8244bae..0000000
--- a/tools/test/topos/tower
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-cd ~/topos && sudo mn --custom tower.py --topo tower --controller remote,${1:-192.168.56.101} --mac
diff --git a/tools/test/topos/tower.json b/tools/test/topos/tower.json
new file mode 100644
index 0000000..358daf3
--- /dev/null
+++ b/tools/test/topos/tower.json
@@ -0,0 +1,13 @@
+{
+  "devices": {
+    "of:0000000000000001": { "basic": { "name": "Spine-1" }},
+    "of:0000000000000002": { "basic": { "name": "Spine-2" }},
+    "of:000000000000000b": { "basic": { "name": "Leaf-1" }},
+    "of:000000000000000c": { "basic": { "name": "Leaf-2" }},
+    "of:000000000000000d": { "basic": { "name": "Leaf-3" }},
+    "of:000000000000000e": { "basic": { "name": "Leaf-4" }}
+  },
+
+  "hosts": {
+  }
+}
diff --git a/tools/test/topos/tower.py b/tools/test/topos/tower.py
index b75bfe4..22d515b 100755
--- a/tools/test/topos/tower.py
+++ b/tools/test/topos/tower.py
@@ -1,55 +1,42 @@
 #!/usr/bin/env python
 
+"""
+"""
 from mininet.topo import Topo
-from mininet.cli import CLI
-from mininet.net import Mininet
-from mininet.node import RemoteController, OVSKernelSwitch
-from mininet.log import setLogLevel
 
+class Tower( Topo ):
+    "Internet Topology Zoo Specimen."
 
-class TowerTopo( Topo ):
-    """Create a tower topology"""
+    def addSwitch( self, name, **opts ):
+        kwargs = { 'protocols' : 'OpenFlow13' }
+        kwargs.update( opts )
+        return super(Tower, self).addSwitch( name, **kwargs )
 
-    def build( self, k=4, h=6 ):
+    def __init__( self ):
+        "Create a topology."
+
+        # Initialize Topology
+        Topo.__init__( self )
+
         spines = []
-        leaves = []
-        hosts = []
 
         # Create the two spine switches
-        spines.append(self.addSwitch('s1'))
-        spines.append(self.addSwitch('s2'))
+        spines.append(self.addSwitch( 's1' ))
+        spines.append(self.addSwitch( 's2' ))
 
-        # Create two links between the spine switches
-        self.addLink(spines[0], spines[1])
-        #TODO add second link between spines when multi-link topos are supported
-        #self.addLink(spines[0], spines[1])
-        
         # Now create the leaf switches, their hosts and connect them together
-        i = 1
-        c = 0
-        while i <= k:
-            leaves.append(self.addSwitch('s1%d' % i))
+        for i in range(4):
+            sn = i + 1
+            leaf = self.addSwitch( 's1%d' % sn )
             for spine in spines:
-                self.addLink(leaves[i-1], spine)
+                self.addLink(leaf, spine)
 
-            j = 1
-            while j <= h:
-                hosts.append(self.addHost('h%d%d' % (i, j)))
-                self.addLink(hosts[c], leaves[i-1])
-                j+=1
-                c+=1
+            for j in range(5):
+                host = self.addHost( 'h%d%d' % (sn, j + 1) )
+                self.addLink( host, leaf )
 
-            i+=1
-
-topos = { 'tower': TowerTopo }
-
-def run():
-    topo = TowerTopo()
-    net = Mininet( topo=topo, controller=RemoteController, autoSetMacs=True )
-    net.start()
-    CLI( net )
-    net.stop()
+topos = { 'tower': ( lambda: Tower() ) }
 
 if __name__ == '__main__':
-    setLogLevel( 'info' )
-    run()
+    from onosnet import run
+    run( Tower() )
diff --git a/tools/test/topos/tower.recipe b/tools/test/topos/tower.recipe
new file mode 100644
index 0000000..d6ba508
--- /dev/null
+++ b/tools/test/topos/tower.recipe
@@ -0,0 +1,14 @@
+# Default US MPLS topology recipe
+export OTD=6
+export OTL=16
+export OTH=20
+
+
+# Variables for the pingall scenario.
+export OPALL=380
+
+# Variables for link-up-down-up scenario.
+export OPS=h11
+export OPD=h21
+export OPL1="s1 s12"
+export OPL2="s2 s12"
\ No newline at end of file
diff --git a/tools/tutorials/vm/cluster.json b/tools/tutorials/vm/cluster.json
new file mode 100644
index 0000000..59dc1b3
--- /dev/null
+++ b/tools/tutorials/vm/cluster.json
@@ -0,0 +1 @@
+{"name":"default","nodes":[{"id":"172.17.0.4","ip":"172.17.0.4","port":9876},{"id":"172.17.0.2","ip":"172.17.0.2","port":9876},{"id":"172.17.0.3","ip":"172.17.0.3","port":9876}],"partitions":[{"id":3,"members":["172.17.0.2","172.17.0.3","172.17.0.4"]},{"id":2,"members":["172.17.0.2","172.17.0.3","172.17.0.4"]},{"id":1,"members":["172.17.0.2","172.17.0.3","172.17.0.4"]}]}
diff --git a/tools/tutorials/vm/createCluster b/tools/tutorials/vm/createCluster
new file mode 100755
index 0000000..4f3c8f3
--- /dev/null
+++ b/tools/tutorials/vm/createCluster
@@ -0,0 +1,42 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Creates the ONOS cluster using 3 docker container instances.
+# -----------------------------------------------------------------------------
+export PATH="$PATH:bin:onos/bin"
+
+# Creates ONOS cluster using ONOS docker images
+ONOS_IMAGE=onosproject/onos:1.12.0
+SSH_KEY=$(cut -d\  -f2 ~/.ssh/id_rsa.pub)
+
+for i in {1..3}; do
+    echo "Setting up onos-$i..."
+    docker container run --detach --name onos-$i --hostname onos-$i --restart always $ONOS_IMAGE
+    docker exec -i onos-$i /bin/bash -c "mkdir config; cat > config/cluster.json" < $(dirname $0)/cluster.json
+    docker exec -it onos-$i bin/onos-user-key sdn $SSH_KEY  >/dev/null 2>&1
+    docker exec -it onos-$i bin/onos-user-password onos rocks >/dev/null 2>&1
+done
+
+function waitForStart {
+    sleep 5
+    for i in {1..3}; do
+        echo "Waiting for onos-$i startup..."
+        ip=$(docker container inspect onos-$i | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+        for t in {1..30}; do
+            curl --fail -sS http://$ip:8181/onos/v1/cluster --user onos:rocks 1>/dev/null 2>&1 && break;
+            sleep 1;
+        done
+        onos $ip summary >/dev/null 2>&1
+    done
+}
+
+OC1=$(docker container inspect onos-1 | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+OC2=$(docker container inspect onos-2 | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+OC3=$(docker container inspect onos-3 | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+ONOS_INSTANCES="$OC1 $OC2 $OC3"
+
+waitForStart
+
+echo "Activating OpenFlow and ProxyARP applications..."
+onos $OC1 app activate openflow proxyarp
+onos $OC1
+
diff --git a/tools/tutorials/vm/destroyCluster b/tools/tutorials/vm/destroyCluster
new file mode 100755
index 0000000..9bc3a74
--- /dev/null
+++ b/tools/tutorials/vm/destroyCluster
@@ -0,0 +1,15 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Destroys the ONOS cluster by stopping the 3 docker containers.
+# -----------------------------------------------------------------------------
+
+# Creates ONOS cluster using ONOS docker images
+ONOS_IMAGE=onosproject/onos:1.12.0
+SSH_KEY=$(cut -d\  -f2 ~/.ssh/id_rsa.pub)
+
+for i in {1..3}; do
+    echo "Destroying onos-$i..."
+    docker stop onos-$i
+done
+
+docker container prune --force
diff --git a/tools/tutorials/vm/exportVM b/tools/tutorials/vm/exportVM
new file mode 100755
index 0000000..48420c9
--- /dev/null
+++ b/tools/tutorials/vm/exportVM
@@ -0,0 +1,12 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Exports the ONOS Tutorial VM into an OVA file for publishing.
+# -----------------------------------------------------------------------------
+
+export VER=1.12.0
+export OVA=/tmp/onos-tutorial-$VER.ova
+rm -f $OVA
+vboxmanage export "ONOS Tutorial" --output $OVA --manifest \
+	--vsys 0 --product "ONOS" --vendor "Open Networking Foundation" --version "$VER" \
+        --description "ONOS Basic Tutorial VM; 3 node cluster using docker; mininet topologies"
+wc -c $OVA
\ No newline at end of file
diff --git a/tools/tutorials/vm/prepForExport b/tools/tutorials/vm/prepForExport
new file mode 100755
index 0000000..fb944a7
--- /dev/null
+++ b/tools/tutorials/vm/prepForExport
@@ -0,0 +1,10 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Prepars the ONOS Tutorial VM for export; run from the VM.
+# -----------------------------------------------------------------------------
+sudo chattr +i ~/.config/xfce4/desktop/icons*
+destroyCluster
+sudo mn -c
+sudo dd if=/dev/zero of=zerofillfile bs=1M
+rm -f zerofillfile /tmp/*
+sudo shutdown now
diff --git a/tools/tutorials/vm/uploadToS3 b/tools/tutorials/vm/uploadToS3
new file mode 100755
index 0000000..3a0e2cb
--- /dev/null
+++ b/tools/tutorials/vm/uploadToS3
@@ -0,0 +1,7 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Publishes the ONOS Tutorial OVA file.
+# -----------------------------------------------------------------------------
+export VER=1.12.0
+export OVA=/tmp/onos-tutorial-$VER.ova
+uploadToS3.py $OVA --secret $AWS_SECRET_ACCESS_KEY --key $AWS_ACCESS_KEY_ID --bucket onos --dest vm/
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 8dbd1dc..50b11a1 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
@@ -19,11 +19,13 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
+import org.onlab.packet.dhcp.Dhcp6ClientDataOption;
 import org.onlab.packet.dhcp.Dhcp6ClientIdOption;
 import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
 import org.onlab.packet.dhcp.Dhcp6IaNaOption;
 import org.onlab.packet.dhcp.Dhcp6IaTaOption;
 import org.onlab.packet.dhcp.Dhcp6IaPdOption;
+import org.onlab.packet.dhcp.Dhcp6LeaseQueryOption;
 import org.onlab.packet.dhcp.Dhcp6Option;
 import org.onlab.packet.dhcp.Dhcp6RelayOption;
 import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
@@ -60,7 +62,12 @@
     // Relay message types
     public static final Set<Byte> RELAY_MSG_TYPES =
             ImmutableSet.of(MsgType.RELAY_FORW.value,
-                            MsgType.RELAY_REPL.value);
+                            MsgType.RELAY_REPL.value
+            );
+    public static final Set<Byte> LEASEQUERY_MSG_TYPES =
+            ImmutableSet.of(MsgType.LEASEQUERY.value,
+                            MsgType.LEASEQUERY_REPLY.value
+            );
 
     /**
      * DHCPv6 message type.
@@ -70,7 +77,8 @@
         CONFIRM((byte) 4), RENEW((byte) 5), REBIND((byte) 6),
         REPLY((byte) 7), RELEASE((byte) 8), DECLINE((byte) 9),
         RECONFIGURE((byte) 10), INFORMATION_REQUEST((byte) 11),
-        RELAY_FORW((byte) 12), RELAY_REPL((byte) 13);
+        RELAY_FORW((byte) 12), RELAY_REPL((byte) 13), LEASEQUERY((byte) 14),
+        LEASEQUERY_REPLY((byte) 15);
 
         protected byte value;
         MsgType(final byte value) {
@@ -107,6 +115,10 @@
                     return RELAY_FORW;
                 case 13:
                     return RELAY_REPL;
+                case 14:
+                    return LEASEQUERY;
+                case 15:
+                    return LEASEQUERY_REPLY;
                 default:
                     return null;
             }
@@ -155,7 +167,8 @@
         STATUS_CODE((short) 13), RAPID_COMMIT((short) 14), USER_CLASS((short) 15),
         VENDOR_CLASS((short) 16), VENDOR_OPTS((short) 17), INTERFACE_ID((short) 18),
         RECONF_MSG((short) 19), RECONF_ACCEPT((short) 20), IA_PD((short) 25), IAPREFIX((short) 26),
-        SUBSCRIBER_ID((short) 38);
+        SUBSCRIBER_ID((short) 38), OPTION_ERO((short) 43), LEASE_QUERY((short) 44),
+        CLIENT_DATA((short) 45),  CLIENT_LT((short) 48);
 
         protected short value;
         OptionCode(final short value) {
@@ -175,6 +188,8 @@
                             .put(OptionCode.CLIENTID.value, Dhcp6ClientIdOption.deserializer())
                             .put(OptionCode.IA_PD.value, Dhcp6IaPdOption.deserializer())
                             .put(OptionCode.INTERFACE_ID.value, Dhcp6InterfaceIdOption.deserializer())
+                            .put(OptionCode.LEASE_QUERY.value, Dhcp6LeaseQueryOption.deserializer())
+                            .put(OptionCode.CLIENT_DATA.value, Dhcp6ClientDataOption.deserializer())
                     .build();
 
     // general field
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6CLTOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6CLTOption.java
new file mode 100644
index 0000000..c509ee3
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6CLTOption.java
@@ -0,0 +1,141 @@
+/*
+ * 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.dhcp;
+
+import org.onlab.packet.DHCP6;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.Deserializer;
+
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+public final class Dhcp6CLTOption extends Dhcp6Option {
+    public static final int DEFAULT_LEN = 4;
+    private int clt; // client last transaction time
+
+    @Override
+    public short getCode() {
+        return DHCP6.OptionCode.CLIENT_LT.value();
+    }
+
+    @Override
+    public short getLength() {
+        return (short) (DEFAULT_LEN);
+    }
+
+    /**
+     * Gets Client Last Transaction Time.
+     *
+     * @return Client Last Transaction Time
+     */
+    public int getClt() {
+        return clt;
+    }
+
+    /**
+     * Sets Identity Association ID.
+     *
+     * @param clt the Client Last Transaction Time.
+     */
+    public void setClt(int clt) {
+        this.clt = clt;
+    }
+
+
+    /**
+     * Default constructor.
+     */
+    public Dhcp6CLTOption() {
+    }
+
+    /**
+     * Constructs a DHCPv6  Client Last Transaction Time option.
+     *
+     * @param dhcp6Option the DHCPv6 option
+     */
+    public Dhcp6CLTOption(Dhcp6Option dhcp6Option) {
+        super(dhcp6Option);
+    }
+
+    /**
+     * Gets deserializer.
+     *
+     * @return the deserializer
+     */
+    public static Deserializer<Dhcp6Option> deserializer() {
+        return (data, offset, length) -> {
+            Dhcp6Option dhcp6Option =
+                    Dhcp6Option.deserializer().deserialize(data, offset, length);
+            if (dhcp6Option.getLength() < DEFAULT_LEN) {
+                throw new DeserializationException("Invalid CLT option data");
+            }
+            Dhcp6CLTOption cltOption = new Dhcp6CLTOption(dhcp6Option);
+            byte[] optionData = cltOption.getData();
+            ByteBuffer bb = ByteBuffer.wrap(optionData);
+            cltOption.clt = bb.getInt();
+
+            return cltOption;
+        };
+    }
+
+    @Override
+    public byte[] serialize() {
+        int payloadLen = DEFAULT_LEN;
+        int len = Dhcp6Option.DEFAULT_LEN + payloadLen;
+        ByteBuffer bb = ByteBuffer.allocate(len);
+        bb.putShort(DHCP6.OptionCode.CLIENT_LT.value());
+        bb.putShort((short) payloadLen);
+        bb.putInt(clt);
+        return bb.array();
+    }
+
+
+    @Override
+    public String toString() {
+        return getToStringHelper()
+                .add("clt", clt)
+                .toString();
+    }
+
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), clt);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Dhcp6CLTOption)) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        final Dhcp6CLTOption other = (Dhcp6CLTOption) obj;
+
+        return Objects.equals(getCode(), other.getCode()) &&
+                Objects.equals(getLength(), other.getLength()) &&
+                Objects.equals(clt, other.clt);
+    }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6ClientDataOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6ClientDataOption.java
new file mode 100644
index 0000000..01b4cc3
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6ClientDataOption.java
@@ -0,0 +1,161 @@
+/*
+ * 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.dhcp;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Lists;
+import org.onlab.packet.DHCP6;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.Deserializer;
+import org.onlab.packet.Ip6Address;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * DHCPv6 Client Data Option.
+ */
+public final class Dhcp6ClientDataOption extends Dhcp6Option {
+    private List<Dhcp6Option> options;
+    private Ip6Address clientIaAddress;
+    public static final int DEFAULT_LEN = 1 + 16;
+
+    public Dhcp6ClientDataOption(Dhcp6Option dhcp6Option) {
+        super(dhcp6Option);
+    }
+
+    @Override
+    public short getCode() {
+        return DHCP6.OptionCode.CLIENT_DATA.value();
+    }
+
+    @Override
+    public short getLength() {
+        //return (short) (DEFAULT_LEN + options.stream()
+        //        .mapToInt(opt -> (int) opt.getLength() + Dhcp6Option.DEFAULT_LEN)
+        //        .sum());
+        return (short) payload.serialize().length;
+    }
+
+    @Override
+    public byte[] getData() {
+        return payload.serialize();
+    }
+
+    public List<Dhcp6Option> getOptions() {
+        return options;
+    }
+
+    public Ip6Address getIaAddress() {
+        return clientIaAddress;
+    }
+
+    public static Deserializer<Dhcp6Option> deserializer() {
+        return (data, offset, length) -> {
+            Dhcp6Option dhcp6Option = Dhcp6Option.deserializer().deserialize(data, offset, length);
+            Dhcp6ClientDataOption clientData = new Dhcp6ClientDataOption(dhcp6Option);
+
+            if (dhcp6Option.getLength() < DEFAULT_LEN) {
+                throw new DeserializationException("Invalid length of Client Id option");
+            }
+
+            byte[] optionData = clientData.getData();
+
+            clientData.options = Lists.newArrayList();
+
+            ByteBuffer bb = ByteBuffer.wrap(optionData);
+
+            while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
+                Dhcp6Option option;
+                ByteBuffer optByteBuffer = ByteBuffer.wrap(optionData,
+                                                           bb.position(),
+                                                           optionData.length - bb.position());
+                short code = optByteBuffer.getShort();
+                short len = optByteBuffer.getShort();
+                int optLen = UNSIGNED_SHORT_MASK & len;
+                byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + optLen];
+                bb.get(subOptData);
+
+                // TODO: put more sub-options?
+                if (code == DHCP6.OptionCode.IAADDR.value()) {
+                    option = Dhcp6IaAddressOption.deserializer()
+                            .deserialize(subOptData, 0, subOptData.length);
+                    clientData.clientIaAddress  = ((Dhcp6IaAddressOption) option).getIp6Address();
+                } else if (code == DHCP6.OptionCode.CLIENTID.value()) {
+                    option = Dhcp6ClientIdOption.deserializer()
+                            .deserialize(subOptData, 0, subOptData.length);
+                } else if (code == DHCP6.OptionCode.CLIENT_LT.value()) {
+                    option = Dhcp6CLTOption.deserializer()
+                            .deserialize(subOptData, 0, subOptData.length);
+                } else {
+                    option = Dhcp6Option.deserializer()
+                            .deserialize(subOptData, 0, subOptData.length);
+                }
+                clientData.options.add(option);
+            }
+            return clientData;
+        };
+    }
+
+    @Override
+    public byte[] serialize() {
+        ByteBuffer bb = ByteBuffer.allocate(this.getLength() + Dhcp6Option.DEFAULT_LEN);
+        bb.putShort(getCode());
+        bb.putShort(getLength());
+        bb.put(payload.serialize());
+        return bb.array();
+    }
+
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("code", getCode())
+                .add("length", getLength())
+                .add("clientAddr", getIaAddress())
+                .toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), clientIaAddress, options);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Dhcp6ClientDataOption)) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        final Dhcp6ClientDataOption other = (Dhcp6ClientDataOption) obj;
+
+        return Objects.equals(getCode(), other.getCode()) &&
+                Objects.equals(getLength(), other.getLength()) &&
+                Objects.equals(clientIaAddress, other.clientIaAddress) &&
+                Objects.equals(options, other.options);
+    }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6LeaseQueryOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6LeaseQueryOption.java
new file mode 100644
index 0000000..5bcc8ba
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6LeaseQueryOption.java
@@ -0,0 +1,153 @@
+/*
+ * 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.dhcp;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Lists;
+import org.onlab.packet.DHCP6;
+import org.onlab.packet.Deserializer;
+import org.onlab.packet.Ip6Address;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * DHCPv6 Lease Query Option.
+ */
+public final class Dhcp6LeaseQueryOption extends Dhcp6Option {
+
+    public static final int DEFAULT_LEN = 1 + 16;
+    //public short QueryType;
+    public Ip6Address linkAddress;
+    private List<Dhcp6Option> options;
+
+    public Dhcp6LeaseQueryOption(Dhcp6Option dhcp6Option) {
+        super(dhcp6Option);
+    }
+
+    @Override
+    public short getCode() {
+        return DHCP6.OptionCode.LEASE_QUERY.value();
+    }
+
+    @Override
+    public short getLength() {
+        //return (short) payload.serialize().length;
+        return (short) (DEFAULT_LEN + options.stream()
+                .mapToInt(opt -> (int) opt.getLength() + Dhcp6Option.DEFAULT_LEN)
+                .sum());
+    }
+
+    @Override
+    public byte[] getData() {
+        return payload.serialize();
+    }
+
+
+    public static Deserializer<Dhcp6Option> deserializer() {
+        return (data, offset, length) -> {
+            Dhcp6Option dhcp6Option = Dhcp6Option.deserializer().deserialize(data, offset, length);
+            Dhcp6LeaseQueryOption lQ6Option = new Dhcp6LeaseQueryOption(dhcp6Option);
+
+            byte[] optionData = lQ6Option.getData();
+            if (optionData.length >= 61) { // 61 is LQ option length + 4 header
+                ByteBuffer bb = ByteBuffer.wrap(optionData);
+                // fetch the Query type - just pop the byte from the byte buffer for subsequent parsing...
+                bb.get();
+                byte[] ipv6Addr = new byte[16];
+                bb.get(ipv6Addr);
+                lQ6Option.linkAddress = Ip6Address.valueOf(ipv6Addr);
+                //int optionsLen = dhcp6Option.getLength() - 1 - 16; // query type (1) + link address (16)
+
+                lQ6Option.options = Lists.newArrayList();
+
+                while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
+                    Dhcp6Option option;
+                    ByteBuffer optByteBuffer = ByteBuffer.wrap(optionData,
+                                                               bb.position(),
+                                                               optionData.length - bb.position());
+                    short code = optByteBuffer.getShort();
+                    short len = optByteBuffer.getShort();
+                    int optLen = UNSIGNED_SHORT_MASK & len;
+                    byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + optLen];
+                    bb.get(subOptData);
+
+                    // TODO: put more sub-options?
+                    if (code == DHCP6.OptionCode.IAADDR.value()) {
+                        option = Dhcp6IaAddressOption.deserializer()
+                                .deserialize(subOptData, 0, subOptData.length);
+                    } else if (code == DHCP6.OptionCode.ORO.value()) {
+                        option = Dhcp6Option.deserializer()
+                                    .deserialize(subOptData, 0, subOptData.length);
+                    } else {
+                        option = Dhcp6Option.deserializer()
+                                .deserialize(subOptData, 0, subOptData.length);
+                    }
+                    lQ6Option.options.add(option);
+                }
+            }
+            return lQ6Option;
+        };
+    }
+
+    @Override
+    public byte[] serialize() {
+        ByteBuffer bb = ByteBuffer.allocate(this.getLength() + Dhcp6Option.DEFAULT_LEN);
+        bb.putShort(getCode());
+        bb.putShort(getLength());
+        bb.put(payload.serialize());
+        return bb.array();
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("code", getCode())
+                .add("length", getLength())
+                .toString();
+    }
+
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), linkAddress, options);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Dhcp6LeaseQueryOption)) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        final Dhcp6LeaseQueryOption other = (Dhcp6LeaseQueryOption) obj;
+
+        return Objects.equals(getCode(), other.getCode()) &&
+                Objects.equals(getLength(), other.getLength()) &&
+                Objects.equals(linkAddress, other.linkAddress) &&
+                Objects.equals(options, other.options);
+    }
+}
diff --git a/utils/misc/src/main/java/org/onlab/util/Tools.java b/utils/misc/src/main/java/org/onlab/util/Tools.java
index 4b2cac9..69baf47 100644
--- a/utils/misc/src/main/java/org/onlab/util/Tools.java
+++ b/utils/misc/src/main/java/org/onlab/util/Tools.java
@@ -388,6 +388,7 @@
         try {
             Thread.sleep(ms);
         } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
             throw new IllegalStateException("Interrupted", e);
         }
     }
@@ -460,6 +461,7 @@
         try {
             Thread.sleep(random.nextInt(ms));
         } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
             throw new IllegalStateException("Interrupted", e);
         }
     }
@@ -474,6 +476,7 @@
         try {
             Thread.sleep(ms, nanos);
         } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
             throw new IllegalStateException("Interrupted", e);
         }
     }
diff --git a/utils/misc/src/main/java/org/onlab/util/XmlString.java b/utils/misc/src/main/java/org/onlab/util/XmlString.java
index 9ffc0e2..2286747 100644
--- a/utils/misc/src/main/java/org/onlab/util/XmlString.java
+++ b/utils/misc/src/main/java/org/onlab/util/XmlString.java
@@ -18,6 +18,7 @@
 import java.io.IOException;
 import java.io.StringWriter;
 
+import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
@@ -34,6 +35,9 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.io.CharSource;
@@ -64,9 +68,33 @@
 
     private String prettyPrintXml(CharSource inputXml) {
         try {
-            Document document = DocumentBuilderFactory.newInstance()
-                    .newDocumentBuilder()
-                    .parse(new InputSource(inputXml.openStream()));
+            Document document;
+            boolean wasFragment = false;
+
+            DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance()
+                    .newDocumentBuilder();
+            // do not print error to stderr
+            docBuilder.setErrorHandler(new DefaultHandler());
+
+            try {
+                document = docBuilder
+                        .parse(new InputSource(inputXml.openStream()));
+            } catch (SAXException e) {
+                log.debug("will retry assuming input is XML fragment", e);
+                // attempt to parse XML fragments, adding virtual root
+                try {
+                    document = docBuilder
+                            .parse(new InputSource(CharSource.concat(CharSource.wrap("<vroot>"),
+                                                                     inputXml,
+                                                                     CharSource.wrap("</vroot>")
+                                                                     ).openStream()));
+                    wasFragment = true;
+                } catch (SAXException e1) {
+                    log.debug("SAXException after retry", e1);
+                    // Probably wasn't fragment issue, throwing original
+                    throw e;
+                }
+            }
 
             document.normalize();
 
@@ -89,7 +117,15 @@
 
             // Return pretty print xml string
             StringWriter strWriter = new StringWriter();
-            t.transform(new DOMSource(document), new StreamResult(strWriter));
+            if (wasFragment) {
+                // print everything but virtual root node added
+                NodeList children = document.getDocumentElement().getChildNodes();
+                for (int i = 0; i < children.getLength(); ++i) {
+                    t.transform(new DOMSource(children.item(i)), new StreamResult(strWriter));
+                }
+            } else {
+                t.transform(new DOMSource(document), new StreamResult(strWriter));
+            }
             return strWriter.toString();
         } catch (Exception e) {
             log.warn("Pretty printing failed", e);
diff --git a/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java b/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java
index b09c44d..16954e5 100644
--- a/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java
+++ b/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java
@@ -41,4 +41,12 @@
         assertEquals(input, XmlString.prettifyXml(input).toString());
     }
 
+    @Test
+    public void fragments() {
+        String input = "<root/>   <a some='foo '/>";
+        String expected = "<root/>\n"
+                        + "<a some=\"foo \"/>\n";
+        assertEquals(expected, XmlString.prettifyXml(input).toString());
+    }
+
 }
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/DiagnosticsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/DiagnosticsWebResource.java
index 6b951e0..f11522d 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/DiagnosticsWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/DiagnosticsWebResource.java
@@ -69,6 +69,7 @@
             }
         } catch (InterruptedException e) {
             log.error("Interrupted executing command {}", command, e);
+            Thread.currentThread().interrupt();
         }
     }
 }
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
index 463f822..278fa07 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
@@ -355,6 +355,7 @@
                 latch.await(WITHDRAW_EVENT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
             } catch (InterruptedException e) {
                 log.info("REST Delete operation timed out waiting for intent {}", k);
+                Thread.currentThread().interrupt();
             }
             // double check the state
             IntentState state = service.getIntentState(k);
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/IntentViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/IntentViewMessageHandler.java
index a9c1887..b32695d 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/IntentViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/IntentViewMessageHandler.java
@@ -221,8 +221,8 @@
 
             private void buildPointToPointDetails(PointToPointIntent intent,
                                                   StringBuilder sb) {
-                ConnectPoint ingress = intent.ingressPoint();
-                ConnectPoint egress = intent.egressPoint();
+                ConnectPoint ingress = intent.filteredIngressPoint().connectPoint();
+                ConnectPoint egress = intent.filteredEgressPoint().connectPoint();
                 sb.append(" Ingress: ")
                         .append(ingress.elementId())
                         .append('/')
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java
index 205be39..e0af5c9 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java
@@ -125,9 +125,6 @@
                         ds.getPortDeltaStatistics(deviceId) :
                         ds.getPortStatistics(deviceId);
                 for (PortStatistics stat : stats) {
-                    if (nz && stat.isZero()) {
-                        continue;
-                    }
                     populateRow(tm.addRow(), stat);
                 }
             }
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
index a50fd1b..9b7472b 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
@@ -61,6 +61,7 @@
 import org.onosproject.ui.impl.topo.Topo2TrafficMessageHandler;
 import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
 import org.onosproject.ui.impl.topo.Traffic2Overlay;
+import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
 import org.onosproject.ui.lion.LionBundle;
 import org.onosproject.ui.lion.LionUtils;
 import org.slf4j.Logger;
@@ -119,6 +120,7 @@
             "core.view.App",
             "core.view.Cluster",
             "core.view.Topo",
+            "core.view.Flow",
 
             // TODO: More to come...
     };
@@ -144,6 +146,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected StorageService storageService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private UiSharedTopologyModel sharedModel;
+
     // User preferences
     private ConsistentMap<String, ObjectNode> prefsConsistentMap;
     private Map<String, ObjectNode> prefs;
@@ -344,6 +349,11 @@
     }
 
     @Override
+    public void refreshModel() {
+        sharedModel.reload();
+    }
+
+    @Override
     public Set<String> getUserNames() {
         ImmutableSet.Builder<String> builder = ImmutableSet.builder();
         prefs.keySet().forEach(k -> builder.add(userName(k)));
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/lion/LionConfig.java b/web/gui/src/main/java/org/onosproject/ui/impl/lion/LionConfig.java
index d1a2bb2..e6d73d3 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/lion/LionConfig.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/lion/LionConfig.java
@@ -17,6 +17,7 @@
 
 package org.onosproject.ui.impl.lion;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.io.CharStreams;
@@ -337,6 +338,24 @@
         public int compareTo(CmdAlias o) {
             return alias.compareTo(o.alias);
         }
+
+        @Override
+        public boolean equals(Object obj) {
+
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final CmdAlias that = (CmdAlias) obj;
+            return Objects.equal(this.alias, that.alias);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(this.alias);
+        }
     }
 
     /**
@@ -392,6 +411,24 @@
             return rawRes.compareTo(o.rawRes);
         }
 
+        @Override
+        public boolean equals(Object obj) {
+
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final CmdFrom that = (CmdFrom) obj;
+            return Objects.equal(this.rawRes, that.rawRes);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(this.rawRes);
+        }
+
         /**
          * Returns the resource bundle name from which to import things.
          *
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
index 28f4aa9..4ec61ce 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
@@ -577,6 +577,7 @@
             addIps(node, h);
             addProps(node, h);
             addGeoGridLocation(node, h);
+            node.put("configured", h.configured());
         }
         addMetaUi(node, ridStr, host.idAsString());
 
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java
index f9f4436..14d29ac 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java
@@ -224,6 +224,14 @@
     //  Methods for topo session (or CLI) to use to get information from us
 
     /**
+     * Reloads the cache's internal state.
+     */
+    public void reload() {
+        cache.clear();
+        cache.load();
+    }
+
+    /**
      * Refreshes the cache's internal state.
      */
     public void refresh() {
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/util/TopoIntentFilter.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/util/TopoIntentFilter.java
index 436bc0d..4565a4e 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/util/TopoIntentFilter.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/util/TopoIntentFilter.java
@@ -260,8 +260,8 @@
                                      Iterable<ConnectPoint> edgePoints) {
         for (ConnectPoint point : edgePoints) {
             // Bail if intent does not involve this edge point.
-            if (!point.equals(intent.egressPoint()) &&
-                    !point.equals(intent.ingressPoint())) {
+            if (!point.equals(intent.filteredEgressPoint().connectPoint()) &&
+                    !point.equals(intent.filteredIngressPoint().connectPoint())) {
                 return false;
             }
         }
diff --git a/web/gui/src/main/resources/org/onosproject/ui/lion/_config/core.view.Flow.lioncfg b/web/gui/src/main/resources/org/onosproject/ui/lion/_config/core.view.Flow.lioncfg
new file mode 100644
index 0000000..b863100
--- /dev/null
+++ b/web/gui/src/main/resources/org/onosproject/ui/lion/_config/core.view.Flow.lioncfg
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+#
+
+bundle core.view.Flow
+
+alias cv core.view
+alias cc core.common
+
+from cv.Flow import *
+
+from cc.State import total
+from cc.Props import state
diff --git a/web/gui/src/main/resources/org/onosproject/ui/lion/core/view/Flow.properties b/web/gui/src/main/resources/org/onosproject/ui/lion/core/view/Flow.properties
new file mode 100644
index 0000000..92871c3
--- /dev/null
+++ b/web/gui/src/main/resources/org/onosproject/ui/lion/core/view/Flow.properties
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+#
+
+# Text that appears in the navigation panel
+nav_item_flow=Flows
+
+# View title
+title_flows= Flows for Device 
+
+flowId=Flow ID
+
+
+bytes=Bytes
+packets=Packets
+duration=Duration 
+priority=Flow Priority 
+tableName=Table Name 
+selector=Selector
+treatment=Treatment
+appName=App Name
+appId=App ID
+groupId=Group ID
+idleTimeout=Idle Timeout
+hardTimeout=Hard Timeout
+permanent=Permanent
+
+tt_ctl_show_device=Show device table
+tt_ctl_show_port=Show port view for this device
+tt_ctl_show_group=Show group view for this device
+tt_ctl_show_meter=Show meter view for selected device
+tt_ctl_show_pipeconf=Show pipeconf view for selected device
+tt_ctl_switcth_brief=Switch to brief view
+tt_ctl_switcth_detailed=Switch to detailed view
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.html b/web/gui/src/main/webapp/app/view/flow/flow.html
index a6fed1a..1d89d12 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.html
+++ b/web/gui/src/main/webapp/app/view/flow/flow.html
@@ -2,8 +2,8 @@
 <div id="ov-flow">
     <div class="tabular-header">
         <h2>
-            Flows for Device {{devId || "(No device selected)"}}
-            ({{tableData.length}} total)
+           {{lion('title_flows')}}{{devId || "(No device selected)"}}
+            ({{tableData.length}} {{lion('total')}})
         </h2>
 
         <div class="ctrl-btns">
@@ -81,15 +81,15 @@
             <table>
                 <tr>
                     <!--<td colId="id" col-width="180px" sortable>Flow ID </td>-->
-                    <td colId="state" col-width="100px" sortable>State </td>
+                    <td colId="state" col-width="100px" sortable>{{lion('state')}}</td>
                     <!--<td class="right" colId="bytes" col-width="90px" sortable> Bytes </td>-->
-                    <td class="right" colId="packets" col-width="90px" sortable> Packets </td>
-                    <td class="right" colId="duration" col-width="90px" sortable> Duration </td>
-                    <td colId="priority" col-width="80px" sortable> Priority </td>
-                    <td colId="tableName" col-width="120px" sortable> Table Name </td>
-                    <td colId="selector" sortable> Selector </td>
-                    <td colId="treatment" sortable> Treatment </td>
-                    <td colId="appName" sortable> App Name </td>
+                    <td class="right" colId="packets" col-width="90px" sortable>{{lion('packets')}}</td>
+                    <td class="right" colId="duration" col-width="90px" sortable>{{lion('duration')}}</td>
+                    <td colId="priority" col-width="80px" sortable>{{lion('priority')}}</td>
+                    <td colId="tableName" col-width="120px" sortable>{{lion('tableName')}}</td>
+                    <td colId="selector" sortable>{{lion('selector')}}  </td>
+                    <td colId="treatment" sortable>{{lion('treatment')}}  </td>
+                    <td colId="appName" sortable>{{lion('appName')}}  </td>
                 </tr>
             </table>
         </div>
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.js b/web/gui/src/main/webapp/app/view/flow/flow.js
index 4392d42..0f41b14 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.js
+++ b/web/gui/src/main/webapp/app/view/flow/flow.js
@@ -22,7 +22,7 @@
     'use strict';
 
     // injected references
-    var $log, $scope, $location, fs, tbs, ns, mast, ps, wss, is;
+    var $log, $scope, $location, fs, tbs, ns, mast, ps, wss, is, ls;
 
     // internal state
     var detailsPanel,
@@ -60,26 +60,28 @@
             'idleTimeout',
             'hardTimeout',
             'permanent',
-        ],
-        friendlyProps = [
-            'Flow ID',
-            'State',
-
-            'Bytes',
-            'Packets',
-            'Duration',
-
-            'Flow Priority',
-            'Table Name',
-            'App Name',
-            'App ID',
-
-            'Group ID',
-            'Idle Timeout',
-            'Hard Timeout',
-            'Permanent',
         ];
 
+// deferred localization strings
+    var warnDeactivate,
+        warnOwnRisk,
+        friendlyProps,
+        lion;
+
+    function doLion() {
+        lion = ls.bundle('core.view.Flow');
+
+        warnDeactivate = lion('dlg_warn_deactivate');
+        warnOwnRisk = lion('dlg_warn_own_risk');
+
+        friendlyProps = [
+            lion('flowId'), lion('state'), lion('bytes'), lion('packets'),
+            lion('duration'), lion('priority'),lion('tableName'),lion('appName'),lion('appId'),
+            lion('groupId'),lion('idleTimeout'),lion('hardTimeout'),lion('permanent')
+        ];
+    }
+
+
     function closePanel() {
         if (detailsPanel.isVisible()) {
             $scope.selId = null;
@@ -130,16 +132,6 @@
         addCell('value', value);
     }
 
-    // deferred fetching of user-visible strings, so that lion context is set
-    function getLionProps() {
-        // TODO: Localization... (see cluster.js for the pattern)
-        // var l = $scope.lion;
-        // return [
-        //     l('flow_id'),
-        //     ...
-        // ];
-        return friendlyProps;
-    }
 
     function getLionClearDeferred() {
         // TODO: Localization...
@@ -221,10 +213,10 @@
             ['$log', '$scope', '$location',
                 'FnService', 'TableBuilderService', 'NavService',
                 'MastService', 'PanelService', 'KeyService', 'IconService',
-                'WebSocketService',
+                'WebSocketService','LionService',
 
                 function (_$log_, _$scope_, _$location_, _fs_, _tbs_, _ns_,
-                          _mast_, _ps_, _ks_, _is_, _wss_) {
+                          _mast_, _ps_, _ks_, _is_, _wss_, _ls_) {
                     var params,
                         handlers = {};
 
@@ -238,13 +230,19 @@
                     wss = _wss_;
                     mast = _mast_;
                     ps = _ps_;
-                    $scope.deviceTip = 'Show device table';
-                    $scope.portTip = 'Show port view for this device';
-                    $scope.groupTip = 'Show group view for this device';
-                    $scope.meterTip = 'Show meter view for selected device';
-                    $scope.pipeconfTip = 'Show pipeconf view for selected device';
-                    $scope.briefTip = 'Switch to brief view';
-                    $scope.detailTip = 'Switch to detailed view';
+                    ls = _ls_;
+
+                    doLion();
+
+                    $scope.lion = lion;
+
+                    $scope.deviceTip = lion('tt_ctl_show_device');
+                    $scope.portTip = lion('tt_ctl_show_port');
+                    $scope.groupTip = lion('tt_ctl_show_group');
+                    $scope.meterTip = lion('tt_ctl_show_meter');
+                    $scope.pipeconfTip = lion('tt_ctl_show_pipeconf');
+                    $scope.briefTip = lion('tt_ctl_switcth_brief');
+                    $scope.detailTip = lion('tt_ctl_switcth_detailed');
 
                     $scope.brief = true;
                     params = $location.search();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2.js b/web/gui/src/main/webapp/app/view/topo2/topo2.js
index 8559811..94a704f 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2.js
@@ -25,7 +25,7 @@
 
     // references to injected services
     var $scope, $log, fs, mast, ks, wss,
-        gs, sus, t2es, t2fs, t2is, t2bcs, t2kcs, t2ms, t2zs;
+        gs, sus, t2es, t2fs, t2is, t2bcs, t2kcs, t2ms, t2zs, t2ts;
 
     // DOM elements
     var ovtopo2, svg, defs, zoomLayer, forceG;
@@ -100,7 +100,7 @@
         'Topo2BreadcrumbService', 'Topo2KeyCommandService', 'Topo2MapService',
         'Topo2ZoomService', 'Topo2SpriteLayerService',
         'Topo2SummaryPanelService', 'Topo2DeviceDetailsPanel', 'Topo2ToolbarService',
-        'Topo2NoDevicesConnectedService', 'Topo2OverlayService',
+        'Topo2NoDevicesConnectedService', 'Topo2OverlayService', 'Topo2TrafficService',
 
         function (
             _$scope_, _$log_, _$loc_,
@@ -109,7 +109,8 @@
             _t2es_, _t2fs_, _t2is_,
             _t2bcs_, _t2kcs_, _t2ms_,
             _t2zs_, t2sls,
-            summaryPanel, detailsPanel, t2tbs, t2ndcs, t2os
+            summaryPanel, detailsPanel, t2tbs, t2ndcs, t2os,
+            _t2ts_
         ) {
             var params = _$loc_.search(),
                 dim,
@@ -136,6 +137,7 @@
             t2kcs = _t2kcs_;
             t2ms = _t2ms_;
             t2zs = _t2zs_;
+            t2ts = _t2ts_;
 
             // capture selected intent parameters (if they are set in the
             //  query string) so that the traffic overlay can highlight
@@ -186,7 +188,7 @@
             t2es.bindHandlers();
 
             t2bcs.init();
-            t2kcs.init(t2fs, t2tbs);
+            t2kcs.init(t2fs, t2tbs, svg);
             t2is.initInst({ showMastership: t2fs.showMastership });
             t2fs.init(svg, forceG, uplink, dim, zoomer);
 
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Host.js b/web/gui/src/main/webapp/app/view/topo2/topo2Host.js
index 4247f64..c56b400 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Host.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Host.js
@@ -78,6 +78,10 @@
                     var type = this.get('type');
                     return remappedDeviceTypes[type] || type || 'm_endstation';
                 },
+                title: function () {
+                    var props = this.get('props');
+                    return props.name || this.get('ips')[0] || 'unknown';
+                },
                 labelIndex: function () {
                     return t2ps.get('hlbls');
                 },
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2HostsPanel.js b/web/gui/src/main/webapp/app/view/topo2/topo2HostsPanel.js
index 4ba1f60..73a2325 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2HostsPanel.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2HostsPanel.js
@@ -35,13 +35,20 @@
 
     function formatHostData(data) {
         var format = {
-            title: data.get('id'),
-            propOrder: ['MAC', 'IP', 'VLAN'],
-            props: {
+            title: data.title(),
+            propOrder: ['MAC', 'IP', 'VLAN', 'Configured'],
+            propLabels: {
+                'MAC': 'MAC',
+                'Configured': 'Configured',
+                'IP': 'IP',
+                'VLAN': 'VLAN',
+            },
+            propValues: {
                 '-': '',
                 'MAC': data.get('id'),
                 'IP': data.get('ips')[0],
                 'VLAN': 'None', // TODO: VLAN is not currently in the data received from backend
+                'Configured': data.get('configured'),
             },
         };
 
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
index 5fd9018..25cea72 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
@@ -18,7 +18,7 @@
 
     // Injected Services
     var $log, fs, ks, flash, wss, t2ps, t2bgs, ps, t2is, t2sp, t2vs, t2rs,
-        t2fs, t2tbs, t2dp;
+        t2fs, t2tbs, t2dp, svg, sus;
 
     // Commmands
     function actionMap() {
@@ -38,8 +38,18 @@
             dot: [toggleToolbar, 'Toggle Toolbar'],
             'shift-L': [cycleHostLabels, 'Cycle host labels'],
 
+            // -- instance color palette debug
+            9: function () { sus.cat7().testCard(svg); },
+
             esc: handleEscape,
 
+            // topology overlay selections
+            F1: function () { t2tbs.fnKey(0); },
+            F2: function () { t2tbs.fnKey(1); },
+            F3: function () { t2tbs.fnKey(2); },
+            F4: function () { t2tbs.fnKey(3); },
+            F5: function () { t2tbs.fnKey(4); },
+
             _keyListener: t2tbs.keyListener.bind(t2tbs),
 
             _helpFormat: [
@@ -50,9 +60,10 @@
         };
     }
 
-    function init(_t2fs_, _t2tbs_) {
+    function init(_t2fs_, _t2tbs_, _svg_) {
         t2fs = _t2fs_;
         t2tbs = _t2tbs_;
+        svg = _svg_;
         bindCommands();
     }
 
@@ -234,10 +245,10 @@
         '$log', 'FnService', 'KeyService', 'FlashService', 'WebSocketService',
         'Topo2PrefsService', 'Topo2BackgroundService', 'PrefsService',
         'Topo2InstanceService', 'Topo2SummaryPanelService', 'Topo2ViewService',
-        'Topo2RegionService', 'Topo2DetailsPanelService',
+        'Topo2RegionService', 'Topo2DetailsPanelService', 'SvgUtilService',
 
         function (_$log_, _fs_, _ks_, _flash_, _wss_, _t2ps_, _t2bgs_, _ps_,
-                  _t2is_, _t2sp_, _t2vs_, _t2rs_, _t2dp_) {
+                  _t2is_, _t2sp_, _t2vs_, _t2rs_, _t2dp_, _t2tbs_, _sus_) {
 
             $log = _$log_;
             fs = _fs_;
@@ -252,6 +263,7 @@
             t2vs = _t2vs_;
             t2rs = _t2rs_;
             t2dp = _t2dp_;
+            sus = _sus_;
 
             return {
                 init: init,
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Overlay.js b/web/gui/src/main/webapp/app/view/topo2/topo2Overlay.js
index 49f76ea..1f26220 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Overlay.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Overlay.js
@@ -26,7 +26,8 @@
 
     // internal state
     var overlays = {},
-        current = null;
+        current = null,
+        reset = true;
 
     function error(fn, msg) {
         $log.error(t2os + fn + '(): ' + msg);
@@ -36,6 +37,39 @@
         $log.warn(t2os + fn + '(): ' + msg);
     }
 
+    function mkGlyphId(oid, gid) {
+        return (gid[0] === '*') ? oid + '-' + gid.slice(1) : gid;
+    }
+
+    function handleGlyphs(o) {
+        var gdata = fs.isO(o.glyphs),
+            oid = o.overlayId,
+            gid = o.glyphId || 'unknown',
+            data = {},
+            note = [];
+
+        o._glyphId = mkGlyphId(oid, gid);
+
+        o.mkGid = function (g) {
+            return mkGlyphId(oid, g);
+        };
+        o.mkId = function (s) {
+            return oid + '-' + s;
+        };
+
+        // process glyphs if defined
+        if (gdata) {
+            angular.forEach(gdata, function (value, key) {
+                var fullkey = oid + '-' + key;
+                data['_' + fullkey] = value.vb;
+                data[fullkey] = value.d;
+                note.push('*' + key);
+            });
+            gs.registerGlyphs(data);
+            $log.debug('registered overlay glyphs:', oid, note);
+        }
+    }
+
     function register(overlay) {
         var r = 'register',
             over = fs.isO(overlay),
@@ -49,7 +83,7 @@
             return warn(r, 'already registered: "' + id + '"');
         }
         overlays[id] = overlay;
-        // TODO handleGlyphs(overlay) ... see topoOverlay.js
+        handleGlyphs(overlay);
 
         if (kb) {
             if (!fs.isA(kb._keyOrder)) {
@@ -66,6 +100,48 @@
         $log.debug(t2os + 'registered overlay: ' + id, overlay);
     }
 
+    // add a radio button for each registered overlay
+    // return an overlay id to index map
+    function augmentRbset(rset, switchFn) {
+        var map = {},
+            idx = 1;
+
+        angular.forEach(overlays, function (ov) {
+            rset.push({
+                gid: ov._glyphId,
+                tooltip: (ov.tooltip || ''),
+                cb: function () {
+                    tbSelection(ov.overlayId, switchFn);
+                },
+            });
+            map[ov.overlayId] = idx++;
+        });
+        return map;
+    }
+
+    // an overlay was selected via toolbar radio button press from user
+    function tbSelection(id, switchFn) {
+        var same = current && current.overlayId === id,
+            payload = {},
+            actions;
+
+        function doop(op) {
+            var oid = current.overlayId;
+            $log.debug('Overlay:', op, oid);
+            current[op]();
+            payload[op] = oid;
+        }
+
+        if (reset || !same) {
+            current && doop('deactivate');
+            current = overlays[id];
+            current && doop('activate');
+            actions = current && fs.isO(current.keyBindings);
+            switchFn(id, actions);
+            // TODO: Update Summary Panel
+        }
+    }
+
     // TODO: check topoOverlay.js for more code
     // TODO: medium term -- factor out common code
     // TODO: longer term -- deprecate classic topology view
@@ -163,6 +239,9 @@
             return {
                 register: register,
                 setOverlay: setOverlay,
+                augmentRbset: augmentRbset,
+                tbSelection: tbSelection,
+                mkGlyphId: mkGlyphId,
 
                 hooks: {
                     escape: escapeHook,
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Toolbar.js b/web/gui/src/main/webapp/app/view/topo2/topo2Toolbar.js
index ae1cc90..c9e5285 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Toolbar.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Toolbar.js
@@ -26,13 +26,12 @@
     var k2b = {
         O: { id: 'topo2-summary-tog', gid: 'm_summary', isel: true },
         I: { id: 'topo2-instance-tog', gid: 'm_uiAttached', isel: true },
-        // D: { id: 'details-tog', gid: 'm_details', isel: true },
-        // H: { id: 'hosts-tog', gid: 'm_endstation', isel: false },
-        // M: { id: 'offline-tog', gid: 'm_switch', isel: true },
+        D: { id: 'details-tog', gid: 'm_details', isel: true },
+        H: { id: 'hosts-tog', gid: 'm_endstation', isel: false },
+        M: { id: 'offline-tog', gid: 'm_switch', isel: true },
         P: { id: 'topo2-ports-tog', gid: 'm_ports', isel: true },
         B: { id: 'topo2-bkgrnd-tog', gid: 'm_map', isel: true },
 
-        // Z: { id: 'oblique-tog', gid: 'm_oblique', isel: false },
         // N: { id: 'filters-btn', gid: 'm_filters' },
         L: { id: 'topo2-cycleLabels-btn', gid: 'm_cycleLabels' },
         R: { id: 'topo2-resetZoom-btn', gid: 'm_resetZoom' },
@@ -43,7 +42,8 @@
     angular.module('ovTopo2')
         .factory('Topo2ToolbarService', [
             'FnService', 'ToolbarService', 'Topo2KeyCommandService',
-            function (fs, tbs, t2kcs) {
+            'Topo2OverlayService',
+            function (fs, tbs, t2kcs, t2ov) {
 
                 var Toolbar = function () {
                     instance = this;
@@ -55,11 +55,14 @@
 
                     init: function () {
                         this.el = tbs.createToolbar(this.className);
+                        this.radioSet;
+                        this.ovIndex;
+
                         this.initKeyData();
                         this.addFirstRow();
                         this.el.addRow();
                         this.addSecondRow();
-
+                        this.addOverlays();
                         this.el.hide();
                     },
                     initKeyData: function () {
@@ -97,20 +100,34 @@
                         this.el.toggle();
                     },
 
+                    selectOverlay: function (ovid) {
+                        var index = this.ovIndex[defaultOverlay] || 0,
+                            pidx = (ovid === null) ? 0 : this.ovIndex[ovid] || -1;
+                        if (pidx >= 0 && pidx < this.radioSet.size()) {
+                            index = pidx;
+                        }
+
+                        this.radioSet.selectedIndex(index);
+                    },
+
+                    fnKey: function (index) {
+                        if (index < this.radioSet.size() && index !== this.radioSet.selectedIndex()) {
+                            this.radioSet.selectedIndex(index);
+                        }
+                    },
+
                     addFirstRow: function () {
                         this.addToggle('I');
                         this.addToggle('O');
-                        // this.addToggle('D');
+                        this.addToggle('D');
                         this.el.addSeparator();
 
-                        // this.addToggle('H');
-                        // this.addToggle('M');
+                        this.addToggle('H');
+                        this.addToggle('M');
                         this.addToggle('P', true);
                         this.addToggle('B');
                     },
                     addSecondRow: function () {
-                        // addToggle('X');
-                        // this.addToggle('Z');
                         // this.addButton('N');
                         this.addButton('L');
                         this.addButton('R');
@@ -118,6 +135,28 @@
                         this.addButton('E');
                     },
 
+                    switchOverlayActions: function () {
+                        // TODO: see TopoToolbar.js
+                        // NOTE: Should add overlay buttons on the third row
+                    },
+
+                    addOverlays: function () {
+                        var _this = this; // Keep context in callback
+                        this.el.addSeparator();
+
+                        // generate radio button set for overlays; start with 'none'
+                        var rset = [{
+                            gid: 'm_unknown',
+                            tooltip: 'ov_tt_none',
+                            cb: function () {
+                                t2ov.tbSelection(null, _this.switchOverlayActions);
+                            },
+                        }];
+
+                        t2ov.augmentRbset(rset, this.switchOverlayActions);
+                        this.radioSet = this.el.addRadioSet('topo-overlays', rset);
+                    },
+
                     destroy: function () {
                         // TODO: Should the tbs remove button id's in the destroyToolbar method?
                         // If you go topo2 -> topo -> topo2 there's a button id conflict