Merge branch 'master' into dev-karaf-4.2.1

Change-Id: Iec1b8947c898b0bf10db8caece0c3a064d1c63ae
diff --git a/README.md b/README.md
index 287a375..65f63d2 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@
 3. Build ONOS with Buck
 ```bash
 $ cd $ONOS_ROOT
-$ bazel build onos
+$ onos-buck build onos [--show-output]
 ```
 
 ONOS currently uses a modified version of Buck (`onos-buck`), which has been packaged with ONOS. Please use this version until our changes have been upstreamed and released as part of an official Buck release. 
@@ -79,10 +79,10 @@
 To run ONOS locally on the development machine, simply run the following command:
 
 ```bash
-$ bazel run onos-local [-- [clean] [debug]]
+$ onos-buck run onos-local [-- [clean] [debug]]
 ```
 
-or simpler one:
+or simplier one:
 
 ```bash
 $ ok [clean] [debug]
@@ -107,16 +107,16 @@
 
 ### Unit Tests
 
-To run ONOS unit tests, run the following command:
+To run ONOS unit tests, including code Checkstyle validation, run the following command:
 
 ```bash
-$ bazel query '\''tests(//...)'\'' | xargs bazel test
+$ onos-buck test
 ```
 
-Or better yet, to run code Checkstyle and all unit tests use the following convenience alias:
+Or more specific tests:
 
 ```bash
-$ ot
+$ onos-buck test [buck-test-rule]
 ```
 
 ## Contributing
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java
index e17ddf6..249ad53 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java
@@ -220,18 +220,20 @@
 
         for (CharSequence node : nodes) {
             Document ldoc = toDocument(CharSource.wrap(node));
-            Element cfgRoot = ldoc.getDocumentElement();
+            if (ldoc != null) {
+                Element cfgRoot = ldoc.getDocumentElement();
 
-            // is everything as merge, ok?
-            cfgRoot.setAttribute("xc:operation", "merge");
+                // is everything as merge, ok?
+                cfgRoot.setAttribute("xc:operation", "merge");
 
-            // move (or copy) node to another Document
-            config.appendChild(Optional.ofNullable(doc.adoptNode(cfgRoot))
-                                  .orElseGet(() -> doc.importNode(cfgRoot, true)));
+                // move (or copy) node to another Document
+                config.appendChild(Optional.ofNullable(doc.adoptNode(cfgRoot))
+                                           .orElseGet(() -> doc.importNode(cfgRoot, true)));
 
-            // don't have good use for JSON for now
-            //JsonNode json = toJsonNode(toJsonCompositeStream(toCompositeData(toResourceData(resourceId, node))));
-            //printlog("JSON:\n{}", toCharSequence(json));
+                // don't have good use for JSON for now
+                //JsonNode json = toJsonNode(toJsonCompositeStream(toCompositeData(toResourceData(resourceId, node))));
+                //printlog("JSON:\n{}", toCharSequence(json));
+            }
         }
 
         printlog("XML:\n{}", XmlString.prettifyXml(toCharSequence(doc)));
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiResolver.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiResolver.java
index 81098b4..abdabf5 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiResolver.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DefaultTapiResolver.java
@@ -96,7 +96,7 @@
     public boolean hasNepRef(String sipId) {
         updateCache();
         return tapiNepRefList.stream()
-                .anyMatch(nep -> nep.getSipId().equals(sipId));
+                .anyMatch(nep -> nep.getSipId() != null && nep.getSipId().equals(sipId));
     }
 
     @Override
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortService.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortService.java
index d9890db..b6c99fb 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortService.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortService.java
@@ -64,6 +64,14 @@
     InstancePort instancePort(DeviceId deviceId, PortNumber portNumber);
 
     /**
+     * Returns instance ports with the given device identifier.
+     *
+     * @param deviceId device identifier
+     * @return set of instance ports; empty list if no port exists
+     */
+    Set<InstancePort> instancePort(DeviceId deviceId);
+
+    /**
      * Returns all instance ports.
      *
      * @return set of instance ports; empty list if no port exists
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java
index 2d5c675..8263f63 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java
@@ -224,6 +224,15 @@
     }
 
     @Override
+    public Set<InstancePort> instancePort(DeviceId deviceId) {
+        Set<InstancePort> ports = instancePortStore.instancePorts().stream()
+                .filter(port -> port.deviceId().equals(deviceId))
+                .collect(Collectors.toSet());
+
+        return ImmutableSet.copyOf(ports);
+    }
+
+    @Override
     public Set<InstancePort> instancePorts() {
         Set<InstancePort> ports = instancePortStore.instancePorts();
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index 731933f..7f34ad7 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -44,6 +44,7 @@
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.InstancePortAdminService;
 import org.onosproject.openstacknetworking.api.InstancePortEvent;
@@ -53,10 +54,11 @@
 import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
+import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
 import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
-import org.onosproject.openstacknetworking.api.OpenstackRouterService;
 import org.onosproject.openstacknetworking.api.PreCommitPortService;
+import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
@@ -64,6 +66,7 @@
 import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.IP;
 import org.openstack4j.model.network.NetFloatingIP;
+import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Router;
 import org.osgi.service.component.ComponentContext;
@@ -97,7 +100,9 @@
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -123,7 +128,7 @@
     protected OpenstackNetworkAdminService osNetworkAdminService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected OpenstackRouterService osRouterService;
+    protected OpenstackRouterAdminService osRouterAdminService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected OpenstackNodeService osNodeService;
@@ -173,7 +178,7 @@
         appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
         configService.registerProperties(getClass());
         localNodeId = clusterService.getLocalNode().id();
-        osRouterService.addListener(osRouterListener);
+        osRouterAdminService.addListener(osRouterListener);
         osNodeService.addListener(osNodeListener);
         osNetworkService.addListener(osNetworkListener);
         instancePortService.addListener(instPortListener);
@@ -186,7 +191,7 @@
     protected void deactivate() {
         packetService.removeProcessor(packetProcessor);
         instancePortService.removeListener(instPortListener);
-        osRouterService.removeListener(osRouterListener);
+        osRouterAdminService.removeListener(osRouterListener);
         osNodeService.removeListener(osNodeListener);
         osNetworkService.removeListener(osNetworkListener);
         instancePortService.removeListener(instPortListener);
@@ -220,7 +225,7 @@
 
             MacAddress targetMac = null;
 
-            NetFloatingIP floatingIP = osRouterService.floatingIps().stream()
+            NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
                     .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
                     .findAny().orElse(null);
 
@@ -358,14 +363,14 @@
                 if (completedGws.contains(gateway)) {
                     if (completedGws.size() > 1) {
                         finalGws.remove(gateway);
-                        osRouterService.floatingIps().forEach(fip -> {
+                        osRouterAdminService.floatingIps().forEach(fip -> {
                             if (fip.getPortId() != null) {
                                 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
                                 finalGws.add(gateway);
                             }
                         });
                     }
-                    osRouterService.floatingIps().forEach(fip -> {
+                    osRouterAdminService.floatingIps().forEach(fip -> {
                         if (fip.getPortId() != null) {
                             setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
                         }
@@ -376,14 +381,14 @@
             } else {
                 if (!completedGws.contains(gateway)) {
                     finalGws.add(gateway);
-                    osRouterService.floatingIps().forEach(fip -> {
+                    osRouterAdminService.floatingIps().forEach(fip -> {
                         if (fip.getPortId() != null) {
                             setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
                         }
                     });
                     finalGws.remove(gateway);
                     if (completedGws.size() >= 1) {
-                        osRouterService.floatingIps().forEach(fip -> {
+                        osRouterAdminService.floatingIps().forEach(fip -> {
                             if (fip.getPortId() != null) {
                                 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
                             }
@@ -729,14 +734,14 @@
         public void event(InstancePortEvent event) {
             InstancePort instPort = event.subject();
 
-            Set<NetFloatingIP> ips = osRouterService.floatingIps();
+            Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
             NetFloatingIP fip = associatedFloatingIp(instPort, ips);
             Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
 
             switch (event.type()) {
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
 
-                    osRouterService.floatingIps().stream()
+                    osRouterAdminService.floatingIps().stream()
                             .filter(f -> f.getPortId() != null)
                             .filter(f -> f.getPortId().equals(instPort.portId()))
                             .forEach(f -> setFloatingIpArpRule(f, instPort.portId(), gateways, true));
@@ -802,16 +807,68 @@
                 case OPENSTACK_NODE_COMPLETE:
                     setDefaultArpRule(osNode, true);
                     setFloatingIpArpRuleForGateway(osNode, true);
+                    sendGratuitousArpToSwitch(event.subject(), true);
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
                     setDefaultArpRule(osNode, false);
                     setFloatingIpArpRuleForGateway(osNode, false);
+                    sendGratuitousArpToSwitch(event.subject(), false);
                     break;
+                case OPENSTACK_NODE_REMOVED:
+                    sendGratuitousArpToSwitch(event.subject(), false);
+                    break;
+
                 default:
                     break;
             }
         }
 
+        private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode, boolean isCompleteCase) {
+            Set<OpenstackNode> completeGws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
+
+            if (isCompleteCase) {
+                osNodeService.completeNodes(COMPUTE)
+                        .stream()
+                        .filter(node -> isGwSelectedByComputeNode(completeGws, node, gatewayNode))
+                        .forEach(node -> processGratuitousArpPacketForComputeNode(node, gatewayNode));
+
+            } else {
+                Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
+                oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
+                oldCompleteGws.add(gatewayNode);
+
+                osNodeService.completeNodes(COMPUTE)
+                        .stream()
+                        .filter(node -> isGwSelectedByComputeNode(oldCompleteGws, node, gatewayNode))
+                        .forEach(node -> {
+                            OpenstackNode newSelectedGatewayNode = getGwByComputeDevId(completeGws, node.intgBridge());
+                            processGratuitousArpPacketForComputeNode(node, newSelectedGatewayNode);
+                        });
+            }
+        }
+
+        private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
+                                                  OpenstackNode computeNode,
+                                                  OpenstackNode gwNode) {
+            return OpenstackNetworkingUtil
+                    .getGwByComputeDevId(gws, computeNode.intgBridge())
+                    .intgBridge().equals(gwNode.intgBridge());
+        }
+
+        private void processGratuitousArpPacketForComputeNode(OpenstackNode computeNode, OpenstackNode gatewayNode) {
+            instancePortService.instancePort(computeNode.intgBridge()).forEach(instancePort -> {
+                NetFloatingIP floatingIP = OpenstackNetworkingUtil.floatingIpByInstancePort(instancePort,
+                        osRouterAdminService);
+                Network network = osNetworkService.network(instancePort.networkId());
+                ExternalPeerRouter externalPeerRouter = OpenstackNetworkingUtil.externalPeerRouterForNetwork(network,
+                        osNetworkService, osRouterAdminService);
+                if (floatingIP != null && externalPeerRouter != null) {
+                    processGratuitousArpPacketForFloatingIp(
+                            floatingIP, instancePort, externalPeerRouter.vlanId(), gatewayNode, packetService);
+                }
+            });
+        }
+
         private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
             switch (getArpMode()) {
                 case ARP_PROXY_MODE:
@@ -870,7 +927,7 @@
                     install
             );
 
-            osRouterService.routers().stream()
+            osRouterAdminService.routers().stream()
                     .filter(router -> router.getExternalGatewayInfo() != null)
                     .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
         }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index bf3285f..f1f1370 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -27,7 +27,6 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
-import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.LeadershipService;
 import org.onosproject.cluster.NodeId;
@@ -39,6 +38,7 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
@@ -57,14 +57,10 @@
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
-import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
-import org.openstack4j.model.network.Router;
-import org.openstack4j.model.network.RouterInterface;
-import org.openstack4j.model.network.Subnet;
 import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -85,9 +81,11 @@
 import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
 import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
-import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
@@ -103,8 +101,6 @@
     private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
     private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
 
-    private static final String USE_SECURITY_GROUP = "useSecurityGroup";
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected CoreService coreService;
 
@@ -118,9 +114,6 @@
     protected ClusterService clusterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected ComponentConfigService componentConfigService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected OpenstackNodeService osNodeService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
@@ -138,6 +131,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected PreCommitPortService preCommitPortService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected PacketService packetService;
+
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
     private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
@@ -187,15 +183,8 @@
 
         Network osNet = osNetworkService.network(instPort.networkId());
 
-        if (osNet == null) {
-            final String errorFormat = ERR_FLOW + "no network(%s) exists";
-            final String error = String.format(errorFormat,
-                    floatingIp.getFloatingIpAddress(),
-                    instPort.networkId());
-            throw new IllegalStateException(error);
-        }
-
-        ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
+        ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
+                osNetworkService, osRouterAdminService);
         if (externalPeerRouter == null) {
             final String errorFormat = ERR_FLOW + "no external peer router found";
             throw new IllegalStateException(errorFormat);
@@ -498,36 +487,6 @@
         log.trace("Succeeded to set flow rules for upstream on gateway nodes");
     }
 
-    private ExternalPeerRouter externalPeerRouter(Network network) {
-        if (network == null) {
-            return null;
-        }
-
-        Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
-
-        if (subnet == null) {
-            return null;
-        }
-
-        RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
-                .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
-                .findAny().orElse(null);
-        if (osRouterIface == null) {
-            return null;
-        }
-
-        Router osRouter = osRouterAdminService.router(osRouterIface.getId());
-        if (osRouter == null) {
-            return null;
-        }
-        if (osRouter.getExternalGatewayInfo() == null) {
-            return null;
-        }
-
-        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
-        return osNetworkService.externalPeerRouter(exGatewayInfo);
-    }
-
     private void associateFloatingIp(NetFloatingIP osFip) {
         InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
 
@@ -540,9 +499,31 @@
         // set floating IP rules only if the port is associated to a VM
         if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
             setFloatingIpRules(osFip, instPort, null, true);
+            processGratuitousArpPacket(osFip, instPort);
+
         }
     }
 
+    private void processGratuitousArpPacket(NetFloatingIP floatingIP,
+                                            InstancePort instancePort) {
+        Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
+
+        Network osNet = osNetworkService.network(instancePort.networkId());
+
+
+        OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
+        ExternalPeerRouter externalPeerRouter =
+                externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
+        if (externalPeerRouter == null) {
+            log.error("Failed to process GARP packet for floating ip {} because no external peer router found");
+            return;
+        }
+
+        processGratuitousArpPacketForFloatingIp(floatingIP, instancePort, externalPeerRouter.vlanId(),
+                selectedGw, packetService);
+
+    }
+
     private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
         InstancePort instPort = instancePortService.instancePort(portId);
 
@@ -708,7 +689,8 @@
                                 throw new IllegalStateException(error);
                             }
 
-                            ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
+                            ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
+                                    osNetworkService, osRouterAdminService);
                             if (externalPeerRouter == null) {
                                 final String errorFormat = ERR_FLOW + "no external peer router found";
                                 throw new IllegalStateException(errorFormat);
@@ -783,7 +765,7 @@
 
                     osPort = osNetworkService.port(fip.getPortId());
                     osNet = osNetworkService.network(osPort.getNetworkId());
-                    externalPeerRouter = externalPeerRouter(osNet);
+                    externalPeerRouter = externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
 
                     if (externalPeerRouter == null) {
                         final String errorFormat = ERR_FLOW + "no external peer router found";
@@ -816,7 +798,7 @@
 
                     osPort = osNetworkService.port(fip.getPortId());
                     osNet = osNetworkService.network(osPort.getNetworkId());
-                    externalPeerRouter = externalPeerRouter(osNet);
+                    externalPeerRouter = externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
 
                     if (externalPeerRouter == null) {
                         final String errorFormat = ERR_FLOW + "no external peer router found";
@@ -886,21 +868,12 @@
                     NetFloatingIP fip =
                             associatedFloatingIp(instPort, osRouterAdminService.floatingIps());
 
-                    boolean sgFlag = getPropertyValueAsBoolean(
-                            componentConfigService.getProperties(
-                                    OpenstackSecurityGroupHandler.class.getName()),
-                            USE_SECURITY_GROUP);
-
                     if (fip != null) {
                         instancePortService.updateInstancePort(
                                             instPort.updateState(REMOVE_PENDING));
                         eventExecutor.execute(() -> updateFipStore(event.port().getId()));
                     } else {
-                        // FIXME: we have dependency with security group, need to
-                        // find a better way to remove this dependency
-                        if (!sgFlag) {
-                            instancePortService.removeInstancePort(instPort.portId());
-                        }
+                        instancePortService.removeInstancePort(instPort.portId());
                     }
                     break;
                 default:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
index b759bff..4701d9c 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
@@ -26,6 +26,7 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
+import org.onlab.util.KryoNamespace;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cluster.ClusterService;
@@ -52,15 +53,23 @@
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupEvent;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
-import org.onosproject.openstacknetworking.api.PreCommitPortService;
 import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.SecurityGroup;
 import org.openstack4j.model.network.SecurityGroupRule;
+import org.openstack4j.model.network.State;
+import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
+import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
+import org.openstack4j.openstack.networking.domain.NeutronIP;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
 import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
@@ -73,6 +82,8 @@
 
 import java.util.Collections;
 import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -90,8 +101,7 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_RULE;
-import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVE_PENDING;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtMaskFlag;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtStateFlag;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
@@ -146,7 +156,18 @@
     protected ClusterService clusterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected PreCommitPortService preCommitPortService;
+    protected StorageService storageService;
+
+    private static final KryoNamespace SERIALIZER_PORT = KryoNamespace.newBuilder()
+            .register(KryoNamespaces.API)
+            .register(Port.class)
+            .register(NeutronPort.class)
+            .register(NeutronIP.class)
+            .register(State.class)
+            .register(NeutronAllowedAddressPair.class)
+            .register(NeutronExtraDhcpOptCreate.class)
+            .register(LinkedHashMap.class)
+            .build();
 
     private final InstancePortListener instancePortListener =
                                         new InternalInstancePortListener();
@@ -157,6 +178,9 @@
     private final OpenstackSecurityGroupListener securityGroupListener =
                                         new InternalSecurityGroupListener();
     private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
+
+    private ConsistentMap<String, Port> removedOsPortStore;
+
     private ApplicationId appId;
     private NodeId localNodeId;
 
@@ -196,6 +220,12 @@
         configService.registerProperties(getClass());
         osNodeService.addListener(osNodeListener);
 
+        removedOsPortStore = storageService.<String, Port>consistentMapBuilder()
+                .withSerializer(Serializer.using(SERIALIZER_PORT))
+                .withName("openstack-removed-portstore")
+                .withApplicationId(appId)
+                .build();
+
         log.info("Started");
     }
 
@@ -254,6 +284,20 @@
 
     private void setSecurityGroupRules(InstancePort instPort,
                                        Port port, boolean install) {
+
+        if (!install) {
+            Port rmvPort = removedOsPortStore.asJavaMap().get(instPort.portId());
+            if (port == null && rmvPort == null) {
+                return;
+            }
+
+            if (port == null) {
+                port = rmvPort;
+            }
+        }
+
+        final Port finalPort = port;
+
         port.getSecurityGroups().forEach(sgId -> {
             SecurityGroup sg = securityGroupService.securityGroup(sgId);
             if (sg == null) {
@@ -261,20 +305,10 @@
                 return;
             }
             sg.getRules().forEach(sgRule ->
-                    updateSecurityGroupRule(instPort, port, sgRule, install));
+                    updateSecurityGroupRule(instPort, finalPort, sgRule, install));
             final String action = install ? "Installed " : "Removed ";
             log.debug(action + "security group rule ID : " + sgId);
         });
-
-        if (install) {
-            preCommitPortService.subscribePreCommit(instPort.portId(),
-                    OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
-            log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
-        } else {
-            preCommitPortService.unsubscribePreCommit(instPort.portId(),
-                    OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
-            log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
-        }
     }
 
     private void updateSecurityGroupRule(InstancePort instPort, Port port,
@@ -285,7 +319,7 @@
         }
 
         if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
-            getRemoteInstPorts(port.getTenantId(), sgRule.getRemoteGroupId())
+            getRemoteInstPorts(port.getTenantId(), sgRule.getRemoteGroupId(), install)
                     .forEach(rInstPort -> {
                         populateSecurityGroupRule(sgRule, instPort, port,
                                 rInstPort.ipAddress().toIpPrefix(), install);
@@ -408,10 +442,16 @@
      * @param sgId security group id
      * @return set of ip addresses
      */
-    private Set<InstancePort> getRemoteInstPorts(String tenantId, String sgId) {
+    private Set<InstancePort> getRemoteInstPorts(String tenantId, String sgId, boolean install) {
         Set<InstancePort> remoteInstPorts;
 
-        remoteInstPorts = osNetService.ports().stream()
+        Set<Port> removedPorts = Sets.newConcurrentHashSet();
+
+        if (!install) {
+            removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
+        }
+
+        remoteInstPorts = Sets.union(osNetService.ports(), removedPorts).stream()
                 .filter(port -> port.getTenantId().equals(tenantId))
                 .filter(port -> port.getSecurityGroups().contains(sgId))
                 .map(port -> instancePortService.instancePort(port.getId()))
@@ -601,7 +641,9 @@
     }
 
     private void securityGroupRuleRemoved(SecurityGroupRule sgRule) {
-        osNetService.ports().stream()
+        Set<Port> removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
+
+        Sets.union(osNetService.ports(), removedPorts).stream()
                 .filter(port -> port.getSecurityGroups()
                                     .contains(sgRule.getSecurityGroupId()))
                 .forEach(port -> {
@@ -709,23 +751,38 @@
             InstancePort instPort = event.subject();
             switch (event.type()) {
                 case OPENSTACK_INSTANCE_PORT_UPDATED:
-                    if (instPort.state() == REMOVE_PENDING) {
-                        break;
-                    }
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
-                    log.debug("Instance port detected MAC:{} IP:{}",
-                            instPort.macAddress(),
-                            instPort.ipAddress());
-                    eventExecutor.execute(() -> {
-                        setSecurityGroupRules(instPort,
-                                osNetService.port(event.subject().portId()),
-                                true);
-                    });
+                case OPENSTACK_INSTANCE_MIGRATION_STARTED:
+                    installSecurityGroupRules(event, instPort);
+                    break;
+                case OPENSTACK_INSTANCE_PORT_VANISHED:
+                    Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
+                    eventExecutor.execute(() ->
+                            setSecurityGroupRules(instPort, osPort, false)
+                    );
+                    removedOsPortStore.remove(instPort.portId());
+                    break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+                    InstancePort revisedInstPort = swapStaleLocation(instPort);
+                    Port port = osNetService.port(instPort.portId());
+                    eventExecutor.execute(() ->
+                            setSecurityGroupRules(revisedInstPort, port, false));
                     break;
                 default:
                     break;
             }
         }
+
+        private void installSecurityGroupRules(InstancePortEvent event,
+                                               InstancePort instPort) {
+            log.debug("Instance port detected/updated MAC:{} IP:{}",
+                    instPort.macAddress(),
+                    instPort.ipAddress());
+            eventExecutor.execute(() -> {
+                setSecurityGroupRules(instPort,
+                        osNetService.port(event.subject().portId()), true);
+            });
+        }
     }
 
     private class InternalOpenstackPortListener implements OpenstackNetworkListener {
@@ -749,15 +806,10 @@
         public void event(OpenstackNetworkEvent event) {
             log.debug("openstack port event received {}", event);
             Port osPort = event.port();
-            InstancePort instPort = instancePortService.instancePort(osPort.getId());
 
             switch (event.type()) {
                 case OPENSTACK_PORT_PRE_REMOVE:
-                    instancePortService.updateInstancePort(
-                                        instPort.updateState(REMOVE_PENDING));
-                    eventExecutor.execute(() ->
-                        setSecurityGroupRules(instPort, osPort, false)
-                    );
+                    removedOsPortStore.put(osPort.getId(), osPort);
                     break;
                 default:
                     // do nothing for the other events
@@ -820,6 +872,11 @@
 
         @Override
         public boolean isRelevant(OpenstackSecurityGroupEvent event) {
+            // do not allow to proceed without leadership
+            NodeId leader = leadershipService.getLeader(appId.name());
+            if (!Objects.equals(localNodeId, leader)) {
+                return false;
+            }
             return useSecurityGroup;
         }
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index 6d1e038..c1ea3cd 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -219,7 +219,7 @@
 
         IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
 
-        MacAddress replyMac = gatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
+        MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
                 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
         if (replyMac == MacAddress.NONE) {
             log.trace("Failed to find MAC address for {}", targetIp);
@@ -241,8 +241,16 @@
                 ByteBuffer.wrap(ethReply.serialize())));
     }
 
-    private boolean gatewayIp(IpAddress targetIp) {
+    /**
+     * Denotes whether the given target IP is gateway IP.
+     *
+     * @param targetIp target IP address
+     * @return true if the given targetIP is gateway IP, false otherwise.
+     */
+    private boolean isGatewayIp(IpAddress targetIp) {
         return osNetworkService.subnets().stream()
+                .filter(Objects::nonNull)
+                .filter(subnet -> subnet.getGateway() != null)
                 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
     }
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index b755017..db15e15 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -42,11 +42,21 @@
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.cfg.ConfigProperty;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants.VnicType;
+import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
@@ -63,10 +73,13 @@
 import org.openstack4j.core.transport.ObjectMapperSingleton;
 import org.openstack4j.model.ModelEntity;
 import org.openstack4j.model.common.Identifier;
+import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Router;
 import org.openstack4j.model.network.RouterInterface;
+import org.openstack4j.model.network.Subnet;
 import org.openstack4j.openstack.OSFactory;
 import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
 import org.slf4j.Logger;
@@ -84,6 +97,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.ByteBuffer;
 import java.security.cert.X509Certificate;
 import java.util.Collection;
 import java.util.HashMap;
@@ -846,11 +860,126 @@
         return traceResult;
     }
 
+    /**
+     * Returns the floating ip with supplied instance port.
+     *
+     * @param instancePort instance port
+     * @param osRouterAdminService openstack router admin service
+     * @return floating ip
+     */
+    public static NetFloatingIP floatingIpByInstancePort(InstancePort instancePort,
+                                                         OpenstackRouterAdminService osRouterAdminService) {
+        return osRouterAdminService.floatingIps().stream()
+                .filter(netFloatingIP -> netFloatingIP.getPortId() != null)
+                .filter(netFloatingIP -> netFloatingIP.getPortId().equals(instancePort.portId()))
+                .findAny().orElse(null);
+    }
+
+    /**
+     * Sends GARP packet with supplied floating ip information.
+     *
+     * @param floatingIP floating ip
+     * @param instancePort instance port
+     * @param vlanId vlain id
+     * @param gatewayNode gateway node
+     * @param packetService packet service
+     */
+    public static void processGratuitousArpPacketForFloatingIp(NetFloatingIP floatingIP,
+                                                               InstancePort instancePort,
+                                                               VlanId vlanId,
+                                                               OpenstackNode gatewayNode,
+                                                               PacketService packetService) {
+        Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(gatewayNode.uplinkPortNum()).build();
+
+        packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
+                ByteBuffer.wrap(ethernet.serialize())));
+    }
+
+    /**
+     * Returns the external peer router with supplied network information.
+     *
+     * @param network network
+     * @param osNetworkService openstack network service
+     * @param osRouterAdminService openstack router admin service
+     * @return external peer router
+     */
+    public static ExternalPeerRouter externalPeerRouterForNetwork(Network network,
+                                                                  OpenstackNetworkService osNetworkService,
+                                                                  OpenstackRouterAdminService osRouterAdminService) {
+        if (network == null) {
+            return null;
+        }
+
+        Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
+
+        if (subnet == null) {
+            return null;
+        }
+
+        RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
+                .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
+                .findAny().orElse(null);
+        if (osRouterIface == null) {
+            return null;
+        }
+
+        Router osRouter = osRouterAdminService.router(osRouterIface.getId());
+        if (osRouter == null) {
+            return null;
+        }
+        if (osRouter.getExternalGatewayInfo() == null) {
+            return null;
+        }
+
+        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
+        return osNetworkService.externalPeerRouter(exGatewayInfo);
+
+    }
+
     private static boolean isDirectPort(String portName) {
         return portNamePrefixMap().values().stream().anyMatch(p -> portName.startsWith(p));
     }
 
     /**
+     * Returns GARP packet with supplied floating ip and instance port information.
+     *
+     * @param floatingIP floating ip
+     * @param instancePort instance port
+     * @param vlanId vlan id
+     * @return GARP packet
+     */
+    private static Ethernet buildGratuitousArpPacket(NetFloatingIP floatingIP,
+                                                     InstancePort instancePort,
+                                                     VlanId vlanId) {
+        Ethernet ethernet = new Ethernet();
+        ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
+        ethernet.setSourceMACAddress(instancePort.macAddress());
+        ethernet.setEtherType(Ethernet.TYPE_ARP);
+        ethernet.setVlanID(vlanId.id());
+
+        ARP arp = new ARP();
+        arp.setOpCode(ARP.OP_REPLY);
+        arp.setProtocolType(ARP.PROTO_TYPE_IP);
+        arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
+
+        arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
+        arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
+
+        arp.setSenderHardwareAddress(instancePort.macAddress().toBytes());
+        arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
+
+        arp.setSenderProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
+        arp.setTargetProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
+
+        ethernet.setPayload(arp);
+
+        return ethernet;
+    }
+
+    /**
      * Builds up and a complete endpoint URL from gateway node.
      *
      * @param node gateway node
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/InstancePortServiceAdapter.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/InstancePortServiceAdapter.java
index d4f1d3f..7d9b75a 100644
--- a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/InstancePortServiceAdapter.java
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/InstancePortServiceAdapter.java
@@ -51,6 +51,11 @@
     }
 
     @Override
+    public Set<InstancePort> instancePort(DeviceId deviceId) {
+        return ImmutableSet.of();
+    }
+
+    @Override
     public Set<InstancePort> instancePorts() {
         return ImmutableSet.of();
     }
diff --git a/apps/openstacktelemetry/BUILD b/apps/openstacktelemetry/BUILD
index 61481ae..00ba1b6 100644
--- a/apps/openstacktelemetry/BUILD
+++ b/apps/openstacktelemetry/BUILD
@@ -10,6 +10,19 @@
     "@okio//jar",
     "@moshi//jar",
     "@converter_moshi//jar",
+    # prometheus deps
+    "@simpleclient//jar",
+    "@simpleclient_common//jar",
+    "@simpleclient_hotspot//jar",
+    "@simpleclient_servlet//jar",
+    "@jetty_servlet//jar",
+    "@jetty_http//jar",
+    "@jetty_server//jar",
+    "@jetty_util//jar",
+    "@jetty_security//jar",
+    "@jetty_io//jar",
+    "@jetty_websocket//jar",
+    "@servlet_api//jar",
     # gRPC dependencies (with patched core)
     ":grpc-core-repkg",
     "@runtime_grpc_stub//jar",
diff --git a/apps/openstackvtap/BUCK b/apps/openstackvtap/BUCK
index e8ee83b..e124259 100644
--- a/apps/openstackvtap/BUCK
+++ b/apps/openstackvtap/BUCK
@@ -4,12 +4,12 @@
 ]
 
 onos_app (
-    title = 'OpenStack vTap Application',
+    title = 'Openstack Vtap Application',
     category = 'Integration',
     url = 'https://wiki.onosproject.org/display/ONOS/SONA%3A+DC+Network+Virtualization',
     included_bundles = BUNDLES,
-    description = 'SONA Openstack vTap Application.',
+    description = 'SONA Openstack Vtap Application.',
     required_apps = [
-        'org.onosproject.openstacknetworking'
+        'org.onosproject.openstacknetworking',
     ]
 )
diff --git a/apps/openstackvtap/BUILD b/apps/openstackvtap/BUILD
index fad480d..35db3b9 100644
--- a/apps/openstackvtap/BUILD
+++ b/apps/openstackvtap/BUILD
@@ -4,12 +4,13 @@
 ]
 
 onos_app(
+    app_name = "org.onosproject.openstackvtap",
     category = "Integration",
-    description = "SONA Openstack vTap Application.",
+    description = "Openstack Vtap Application.",
     included_bundles = BUNDLES,
     required_apps = [
         "org.onosproject.openstacknetworking",
     ],
-    title = "OpenStack vTap Application",
+    title = "Openstack Vtap Application",
     url = "https://wiki.onosproject.org/display/ONOS/SONA%3A+DC+Network+Virtualization",
 )
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtap.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtap.java
index 6f74e81..ad189e2 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtap.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtap.java
@@ -22,15 +22,14 @@
 import java.util.Set;
 
 /**
- * Abstraction of an OpenstackVtap.
+ * Abstraction of an openstack vtap.
  */
 public interface OpenstackVtap extends Annotated {
 
     /**
-     * Openstack vTap type.
+     * List of openstack vtap types.
      */
     enum Type {
-
         /**
          * Indicates mirroring both TX and RX traffic.
          */
@@ -47,9 +46,9 @@
         VTAP_TX(0x1),
 
         /**
-         * Indicates do not mirroring any traffic.
+         * Indicates selection of mirroring any traffic.
          */
-        VTAP_NONE(0);
+        VTAP_ANY(0x0);
 
         private final int type;
 
@@ -63,97 +62,96 @@
     }
 
     /**
-     * OpenstackVtap identifier.
+     * Returns the openstack vtap identifier.
      *
-     * @return OpenstackVtap id
+     * @return vtap ID
      */
     OpenstackVtapId id();
 
     /**
-     * Returns OpenstackVtap type.
+     * Returns the openstack vtap type.
      *
-     * @return type
+     * @return type of vtap
      */
     Type type();
 
     /**
-     * Returns the vTap criterion.
+     * Returns the openstack vtap criterion.
      *
-     * @return vTap criterion
+     * @return criterion of vtap
      */
-    OpenstackVtapCriterion vTapCriterion();
+    OpenstackVtapCriterion vtapCriterion();
 
     /**
-     * Returns a collection of TX device identifiers.
+     * Returns a collection of device identifiers for tx.
      *
-     * @return device identifiers
+     * @return device identifiers for tx
      */
     Set<DeviceId> txDeviceIds();
 
     /**
-     * Returns a collection of RX device identifiers.
+     * Returns a collection of device identifiers for rx.
      *
-     * @return device identifiers
+     * @return device identifiers for rx
      */
     Set<DeviceId> rxDeviceIds();
 
     /**
-     * Builder of new openstack vTap instance.
+     * Builder of new openstack vtap instance.
      */
     interface Builder {
-
         /**
-         * Returns openstack vTap builder with supplied vTap identifier.
+         * Returns openstack vtap builder with supplied id.
          *
-         * @param id vTap identifier
-         * @return openstack vTap builder
+         * @param id openstack vtap id
+         * @return openstack vtap builder
          */
         Builder id(OpenstackVtapId id);
 
         /**
-         * Returns openstack vTap builder with supplied vTap type.
+         * Returns openstack vtap builder with supplied type.
          *
-         * @param type vTap type
-         * @return openstack vTap builder
+         * @param type of the vtap
+         * @return openstack vtap builder
          */
         Builder type(OpenstackVtap.Type type);
 
         /**
-         * Returns openstack vTap builder with supplied vTap criterion.
+         * Returns openstack vtap builder with supplied criterion.
          *
-         * @param vTapCriterion vTap criterion
-         * @return openstack vTap builder
+         * @param vtapCriterion for the vtap
+         * @return openstack vtap builder
          */
-        Builder vTapCriterion(OpenstackVtapCriterion vTapCriterion);
+        Builder vtapCriterion(OpenstackVtapCriterion vtapCriterion);
 
         /**
-         * Returns openstack vTap builder with supplied TX device identifiers.
+         * Returns openstack vtap builder with supplied tx deviceId set.
          *
-         * @param txDeviceIds TX device identifiers
-         * @return openstack vTap builder
+         * @param txDeviceIds deviceId set for tx
+         * @return openstack vtap builder
          */
         Builder txDeviceIds(Set<DeviceId> txDeviceIds);
 
         /**
-         * Returns openstack vTap builder with supplied RX device identifiers.
+         * Returns openstack vtap builder with supplied rx deviceId set.
          *
-         * @param rxDeviceIds RX device identifiers
-         * @return openstack vTap builder
+         * @param rxDeviceIds deviceId set for rx
+         * @return openstack vtap builder
          */
         Builder rxDeviceIds(Set<DeviceId> rxDeviceIds);
 
         /**
-         * Returns openstack vTap builder with supplied annotations.
+         * Returns openstack vtap builder with supplied annotations.
          *
          * @param annotations a set of annotations
-         * @return openstack vTap builder
+         * @return openstack vtap builder
          */
-        Builder annotations(SparseAnnotations... annotations);
+        Builder annotations(SparseAnnotations annotations);
 
         /**
-         * Builds an immutable openstack vTap instance.
+         * Builds an immutable OpenstackVtap instance.
          *
-         * @return openstack vTap instance
+         * @return openstack vtap instance
          */
         OpenstackVtap build();
     }
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapAdminService.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapAdminService.java
index da9fd24..1828bee 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapAdminService.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapAdminService.java
@@ -15,60 +15,24 @@
  */
 package org.onosproject.openstackvtap.api;
 
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-
 /**
- * Service for administering the inventory of vTap.
+ * Service for administering the inventory of openstack vtap.
  */
 public interface OpenstackVtapAdminService extends OpenstackVtapService {
 
     /**
-     * Creates a new vTap based on the specified description.
-     *
-     * @param type                  vTap type
-     * @param vTapCriterion         criterion of a vTap
-     * @return created vTap object or null if error occurred
+     * Initializes the flow rules and group tables, tunneling interface for all completed compute nodes.
      */
-    OpenstackVtap createVtap(OpenstackVtap.Type type, OpenstackVtapCriterion vTapCriterion);
+    void initVtap();
 
     /**
-     * Updates the existing vTap based on the given vTap instance.
-     *
-     * @param vTapId             vTap identifier
-     * @param vTap               vTap instance to be modified
-     * @return updated vTap object or null if error occurred
+     * Clears the flow rules and group tables, tunneling interfaces for all compute nodes.
      */
-    OpenstackVtap updateVtap(OpenstackVtapId vTapId, OpenstackVtap vTap);
+    void clearVtap();
 
     /**
-     * Removes the specified vTap with given vTap identifier.
-     *
-     * @param vTapId             vTap identifier
-     * @return removed vTap object or null if error occurred
+     * Purges all flow rules and group tables, tunneling interface for openstack vtap.
      */
-    OpenstackVtap removeVtap(OpenstackVtapId vTapId);
+    void purgeVtap();
 
-    /**
-     * Sets output port and VLAN tag for vTap.
-     *
-     * @param deviceId           device identifier
-     * @param type               vTap type
-     * @param portNumber         port number
-     * @param vlanId             VLAN tag
-     */
-    void setVtapOutput(DeviceId deviceId, OpenstackVtap.Type type,
-                       PortNumber portNumber, VlanId vlanId);
-
-    /**
-     * Sets output port and VNI for vTap.
-     *
-     * @param deviceId          device identifier
-     * @param type              vTap type
-     * @param portNumber        port number
-     * @param vni               virtual network index (VNI) of VxLAN
-     */
-    void setVtapOutput(DeviceId deviceId, OpenstackVtap.Type type,
-                       PortNumber portNumber, int vni);
 }
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapCriterion.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapCriterion.java
index eb21b0c..088f12d 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapCriterion.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapCriterion.java
@@ -19,35 +19,35 @@
 import org.onlab.packet.TpPort;
 
 /**
- * A vTAP criterion used for mirroring traffic.
+ * A vtap criterion used for mirroring traffic.
  */
 public interface OpenstackVtapCriterion {
 
     /**
-     * Returns IP Prefix of Source VM.
+     * Returns IP prefix of source.
      *
-     * @return source IP prefix
+     * @return source IP prefix of vtap criterion
      */
     IpPrefix srcIpPrefix();
 
     /**
-     * Returns IP Prefix of Destination VM.
+     * Returns IP prefix of destination.
      *
-     * @return destination IP prefix
+     * @return destination IP prefix of vtap criterion
      */
     IpPrefix dstIpPrefix();
 
     /**
      * Returns IP protocol.
      *
-     * @return IP protocol
+     * @return IP protocol of vtap criterion
      */
     byte ipProtocol();
 
     /**
      * Returns source transport port.
      *
-     * @return source transport port number
+     * @return source transport port of vtap criterion
      */
 
     TpPort srcTpPort();
@@ -55,60 +55,59 @@
     /**
      * Returns destination transport port.
      *
-     * @return destination transport port number
+     * @return destination transport port of vtap criterion
      */
     TpPort dstTpPort();
 
     /**
-     * Builder of new openstack vTap criteria.
+     * Builder of new OpenstackVtapCriterion instance.
      */
     interface Builder {
-
         /**
-         * Builds an immutable openstack vTap criterion instance.
+         * Returns openstack vtap criterion builder with supplied source IP prefix.
          *
-         * @return openstack vTap criterion
-         */
-        OpenstackVtapCriterion build();
-
-        /**
-         * Returns openstack vTap criterion builder with supplied srcIpPrefix.
-         *
-         * @param srcIpPrefix Source IP address
-         * @return openstack vTap criterion builder
+         * @param srcIpPrefix Source IP prefix
+         * @return openstack vtap criterion builder
          */
         Builder srcIpPrefix(IpPrefix srcIpPrefix);
 
         /**
-         * Returns openstack vTap criterion builder with supplied srcIpPrefix.
+         * Returns openstack vtap criterion builder with supplied destination IP prefix.
          *
-         * @param dstIpPrefix Destination IP Prefix
-         * @return openstack vTap criterion builder
+         * @param dstIpPrefix Destination IP prefix
+         * @return openstack vtap criterion builder
          */
         Builder dstIpPrefix(IpPrefix dstIpPrefix);
 
         /**
-         * Returns openstack vTap criterion builder with supplied ipProtocol.
+         * Returns openstack vtap criterion builder with supplied ipProtocol.
          *
-         * @param ipProtocol IP protocol number
-         * @return openstack vTap criterion builder
+         * @param ipProtocol IP protocol
+         * @return openstack vtap criterion builder
          */
         Builder ipProtocol(byte ipProtocol);
 
         /**
-         * Returns openstack vTap criterion builder with supplied srcTpPort.
+         * Returns openstack vtap criterion builder with supplied source port.
          *
-         * @param srcTpPort Source transport port number
-         * @return openstack vTap criterion builder
+         * @param srcTpPort Source transport port
+         * @return openstack vtap criterion builder
          */
         Builder srcTpPort(TpPort srcTpPort);
 
         /**
-         * Returns openstack vTap criterion builder with supplied dstTpPort.
+         * Returns openstack vtap criterion builder with supplied destination port.
          *
-         * @param dstTpPort Destination transport port number
-         * @return openstack vTap criterion builder
+         * @param dstTpPort Destination transport port
+         * @return openstack vtap criterion builder
          */
         Builder dstTpPort(TpPort dstTpPort);
+
+        /**
+         * Builds an immutable OpenstackVtapCriterion instance.
+         *
+         * @return OpenstackVtapCriterion criterion
+         */
+        OpenstackVtapCriterion build();
     }
 }
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapEvent.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapEvent.java
index 70c1e11..d44c9f9 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapEvent.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapEvent.java
@@ -19,81 +19,166 @@
 import org.onosproject.event.AbstractEvent;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkState;
 
 /**
- * Describes vTap event.
+ * Describes openstack vtap event.
  */
-public class OpenstackVtapEvent extends AbstractEvent<OpenstackVtapEvent.Type, OpenstackVtap> {
+public class OpenstackVtapEvent extends AbstractEvent<OpenstackVtapEvent.Type, Object> {
+
+    private static final String INVALID_OBJ_TYPE = "Invalid OpenstackVtapEvent object type of %";
 
     /**
-     * Type of vTap events.
+     * Type of openstack vtap events.
      */
     public enum Type {
 
         /**
-         * Signifies that a new vTap has been added.
+         * Signifies that a new openstack vtap network has been added.
+         */
+        VTAP_NETWORK_ADDED,
+
+        /**
+         * Signifies that a openstack vtap network has been changed.
+         */
+        VTAP_NETWORK_UPDATED,
+
+        /**
+         * Signifies that a openstack vtap network has been removed.
+         */
+        VTAP_NETWORK_REMOVED,
+
+        /**
+         * Signifies that a new openstack vtap has been added.
          */
         VTAP_ADDED,
 
         /**
-         * Signifies that a vTap has been removed.
-         */
-        VTAP_REMOVED,
-
-        /**
-         * Signifies that a vTap data changed.
+         * Signifies that a openstack vtap has been changed.
          */
         VTAP_UPDATED,
+
+        /**
+         * Signifies that a openstack vtap has been removed.
+         */
+        VTAP_REMOVED,
     }
 
-    private OpenstackVtap prevSubject;
+    private final Object prevSubject;
 
     /**
-     * Creates an event of a given type and for the specified vTap and the
-     * current time.
+     * Creates an event with previous openstack vtap network subject.
      *
-     * @param type vTap event type
-     * @param vTap event vTap subject
+     * The openstack vtap network subject is null if the type is removed
+     * The previous openstack vtap network subject is null if the type is added
+     *
+     * @param type            openstack vtap event type
+     * @param vtapNetwork     event openstack vtap network subject
+     * @param prevVtapNetwork previous openstack vtap network subject
      */
-    public OpenstackVtapEvent(Type type, OpenstackVtap vTap) {
-        super(type, vTap);
+    public OpenstackVtapEvent(Type type,
+                              OpenstackVtapNetwork vtapNetwork,
+                              OpenstackVtapNetwork prevVtapNetwork) {
+        super(type, vtapNetwork);
+        prevSubject = prevVtapNetwork;
     }
 
     /**
-     * Creates an event of a given type and for the specified vTap and time.
+     * Creates an event of a given type and for the specified openstack vtap network and time.
      *
-     * @param type vTap event type
-     * @param vTap event vTap subject
-     * @param time occurrence time
+     * @param type            openstack vtap event type
+     * @param vtapNetwork     event openstack vtap network subject
+     * @param prevVtapNetwork previous openstack vtap network subject
+     * @param time            occurrence time
      */
-    public OpenstackVtapEvent(Type type, OpenstackVtap vTap, long time) {
-        super(type, vTap, time);
+    public OpenstackVtapEvent(Type type,
+                              OpenstackVtapNetwork vtapNetwork,
+                              OpenstackVtapNetwork prevVtapNetwork,
+                              long time) {
+        super(type, vtapNetwork, time);
+        prevSubject = prevVtapNetwork;
     }
 
     /**
-     * Creates an event with previous subject.
+     * Creates an event with previous openstack vtap subject.
      *
-     * The previous subject is ignored if the type is not moved or updated
+     * The openstack vtap subject is null if the type is removed
+     * The previous openstack vtap subject is null if the type is added
      *
-     * @param type vTap event type
-     * @param vTap event vTap subject
-     * @param prevSubject previous vTap subject
+     * @param type     openstack vtap event type
+     * @param vtap     event openstack vtap subject
+     * @param prevVtap previous openstack vtap subject
      */
-    public OpenstackVtapEvent(Type type, OpenstackVtap vTap, OpenstackVtap prevSubject) {
-        super(type, vTap);
-        if (type == Type.VTAP_UPDATED) {
-            this.prevSubject = prevSubject;
-        }
+    public OpenstackVtapEvent(Type type, OpenstackVtap vtap, OpenstackVtap prevVtap) {
+        super(type, vtap);
+        prevSubject = prevVtap;
     }
 
     /**
-     * Gets the previous subject in this vTap event.
+     * Creates an event of a given type and for the specified openstack vtap and time.
+     *
+     * @param type     openstack vtap event type
+     * @param vtap     event openstack vtap subject
+     * @param prevVtap previous openstack vtap subject
+     * @param time     occurrence time
+     */
+    public OpenstackVtapEvent(Type type, OpenstackVtap vtap, OpenstackVtap prevVtap, long time) {
+        super(type, vtap, time);
+        prevSubject = prevVtap;
+    }
+
+    /**
+     * Gets the previous subject in this openstack vtap event.
      *
      * @return the previous subject, or null if previous subject is not
      *         specified.
      */
-    public OpenstackVtap prevSubject() {
-        return this.prevSubject;
+    public Object prevSubject() {
+        return prevSubject;
+    }
+
+    /**
+     * Gets the openstack vtap network in this openstack vtap event.
+     *
+     * @return the subject, or null if the type is removed
+     */
+    public OpenstackVtapNetwork openstackVtapNetwork() {
+        Object obj = subject();
+        checkState(obj == null || obj instanceof OpenstackVtapNetwork, INVALID_OBJ_TYPE, obj);
+        return (OpenstackVtapNetwork) obj;
+    }
+
+    /**
+     * Gets the previous openstack vtap network in this openstack vtap event.
+     *
+     * @return the previous subject, or null if type is added
+     */
+    public OpenstackVtapNetwork prevOpenstackVtapNetwork() {
+        Object obj = prevSubject;
+        checkState(obj == null || obj instanceof OpenstackVtapNetwork, INVALID_OBJ_TYPE, obj);
+        return (OpenstackVtapNetwork) obj;
+    }
+
+    /**
+     * Gets the openstack vtap in this openstack vtap event.
+     *
+     * @return the subject, or null if the type is removed
+     */
+    public OpenstackVtap openstackVtap() {
+        Object obj = subject();
+        checkState(obj == null || obj instanceof OpenstackVtap, INVALID_OBJ_TYPE, obj);
+        return (OpenstackVtap) obj;
+    }
+
+    /**
+     * Gets the previous openstack vtap in this openstack vtap event.
+     *
+     * @return the previous subject, or null if type is added
+     */
+    public OpenstackVtap prevOpenstackVtap() {
+        Object obj = prevSubject;
+        checkState(obj == null || obj instanceof OpenstackVtap, INVALID_OBJ_TYPE, obj);
+        return (OpenstackVtap) obj;
     }
 
     @Override
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapId.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapId.java
index ce8945d..c70fb03 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapId.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapId.java
@@ -19,12 +19,12 @@
 import java.util.UUID;
 
 /**
- * Immutable representation of an openstack vTap identifier.
+ * Immutable representation of an openstack vtap identifier.
  */
 public final class OpenstackVtapId {
 
     /**
-     * Represents either no vTap, or an unspecified vTap.
+     * Represents either no vtap, or an unspecified vtap.
      */
     public static final OpenstackVtapId NONE = new OpenstackVtapId(null);
 
@@ -50,35 +50,35 @@
     }
 
     /**
-     * Creates a vTap identifier using the supplied UUID.
+     * Creates a vtap identifier using the supplied UUID.
      *
-     * @param uuid vTap UUID
-     * @return vTap identifier
+     * @param uuid vtap UUID
+     * @return vtap identifier
      */
-    public static OpenstackVtapId vTapId(UUID uuid) {
+    public static OpenstackVtapId vtapId(UUID uuid) {
         return new OpenstackVtapId(uuid);
     }
 
     /**
-     * Creates a vTap identifier using the supplied string format of UUID.
+     * Creates a vtap identifier using the supplied string format of UUID.
      *
-     * @param uuidString vTap UUID
-     * @return vTap identifier
+     * @param uuidString vtap UUID
+     * @return vtap identifier
      */
-    public static OpenstackVtapId vTapId(String uuidString) {
+    public static OpenstackVtapId vtapId(String uuidString) {
         try {
-            return vTapId(UUID.fromString(uuidString));
+            return vtapId(UUID.fromString(uuidString));
         } catch (Exception e) {
             throw new IllegalArgumentException("Invalid UUID string: " + uuidString);
         }
     }
 
     /**
-     * Creates a OpenstackVtap id using random uuid.
+     * Creates a openstack vtap id using random uuid.
      *
-     * @return OpenstackVtap identifier
+     * @return openstack vtap identifier
      */
-    public static OpenstackVtapId vTapId() {
+    public static OpenstackVtapId vtapId() {
         return new OpenstackVtapId(UUID.randomUUID());
     }
 
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapListener.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapListener.java
index ebea5ed..9df7384 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapListener.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapListener.java
@@ -18,7 +18,7 @@
 import org.onosproject.event.EventListener;
 
 /**
- * Entity capable of receiving user related events.
+ * Entity capable of receiving openstack vtap related events.
  */
 public interface OpenstackVtapListener extends EventListener<OpenstackVtapEvent> {
 }
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapNetwork.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapNetwork.java
new file mode 100644
index 0000000..daa95a8
--- /dev/null
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapNetwork.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.openstackvtap.api;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.Annotated;
+import org.onosproject.net.SparseAnnotations;
+
+/**
+ * Abstraction of an openstack vtap network.
+ */
+public interface OpenstackVtapNetwork extends Annotated {
+
+    /**
+     * List of valid openstack vtap tunneling modes.
+     */
+    enum Mode {
+        /**
+         * Indicates GRE tunneling.
+         */
+        GRE,
+
+        /**
+         * Indicates VXLAN tunneling.
+         */
+        VXLAN
+    }
+
+    /**
+     * Returns the OpenstackVtapNetwork mode.
+     *
+     * @return mode of vtap tunneling
+     */
+    Mode mode();
+
+    /**
+     * Returns the network id of the vtap tunneling.
+     *
+     * @return networkId (e.g., gre key, vxlan vni)
+     */
+    Integer networkId();
+
+    /**
+     * Returns the vtap server IP address used for tunneling.
+     *
+     * @return ip address for vtap server
+     */
+    IpAddress serverIp();
+
+    /**
+     * Builder of new OpenstackVtapNetwork instance.
+     */
+    interface Builder {
+        /**
+         * Returns openstack vtap network builder with supplied OpenstackVtapNetwork mode.
+         *
+         * @param mode mode of vtap tunneling
+         * @return openstack vtap network builder
+         */
+        Builder mode(Mode mode);
+
+        /**
+         * Returns openstack vtap network builder with supplied networkId for tunneling.
+         *
+         * @param networkId (e.g., gre key, vxlan vni)
+         * @return openstack vtap network builder
+         */
+        Builder networkId(Integer networkId);
+
+        /**
+         * Returns openstack vtap network builder with supplied server IP address.
+         *
+         * @param serverIp ip address for vtap server
+         * @return openstack vtap network builder
+         */
+        Builder serverIp(IpAddress serverIp);
+
+        /**
+         * Returns openstack vtap network builder with supplied annotations.
+         *
+         * @param annotations a set of annotations
+         * @return openstack vtap network builder
+         */
+        Builder annotations(SparseAnnotations annotations);
+
+        /**
+         * Builds an immutable OpenstackVtapNetwork instance.
+         *
+         * @return OpenstackVtapNetwork instance
+         */
+        OpenstackVtapNetwork build();
+    }
+}
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapService.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapService.java
index 5041aaf..bfb63a0 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapService.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapService.java
@@ -15,47 +15,111 @@
  */
 package org.onosproject.openstackvtap.api;
 
+import org.onlab.packet.IpAddress;
 import org.onosproject.event.ListenerService;
 import org.onosproject.net.DeviceId;
 
 import java.util.Set;
 
 /**
- * Service for interacting with the inventory of vTap.
+ * Service for interacting with the inventory of openstack vtap.
  */
 public interface OpenstackVtapService
         extends ListenerService<OpenstackVtapEvent, OpenstackVtapListener> {
 
     /**
-     * Returns the number of vTaps in the store.
+     * Creates a new openstack vtap network based on the specified description.
      *
-     * @param type               vTap type
-     * @return vTap count
+     * @param mode      mode of vtap network
+     * @param networkId network id of the vtap tunneling network
+     * @param serverIp  server IP address used for tunneling
+     * @return created openstack vtap network object or null if error occurred
+     */
+    OpenstackVtapNetwork createVtapNetwork(OpenstackVtapNetwork.Mode mode, Integer networkId, IpAddress serverIp);
+
+    /**
+     * Updates the openstack vtap network based on the specified description.
+     *
+     * @param description description of vtap network
+     * @return updated openstack vtap network object or null if error occurred
+     */
+    OpenstackVtapNetwork updateVtapNetwork(OpenstackVtapNetwork description);
+
+    /**
+     * Removes the specified openstack vtap network.
+     *
+     * @return removed openstack vtap network object or null if error occurred
+     */
+    OpenstackVtapNetwork removeVtapNetwork();
+
+    /**
+     * Returns the openstack vtap network.
+     *
+     * @return openstack vtap network or null if not exists
+     */
+    OpenstackVtapNetwork getVtapNetwork();
+
+    /**
+     * Returns a set of devices which are associated with the openstack vtap network.
+     *
+     * @return set of devices
+     */
+    Set<DeviceId> getVtapNetworkDevices();
+
+    /**
+     * Creates a new openstack vtap based on the specified type and criterion.
+     *
+     * @param type          type of vtap (all,rx,tx)
+     * @param vtapCriterion criterion of vtap
+     * @return created openstack vtap object or null if error occurred
+     */
+    OpenstackVtap createVtap(OpenstackVtap.Type type, OpenstackVtapCriterion vtapCriterion);
+
+    /**
+     * Updates the openstack vtap with specified description.
+     *
+     * @param description description of vtap
+     * @return updated openstack vtap object or null if error occurred
+     */
+    OpenstackVtap updateVtap(OpenstackVtap description);
+
+    /**
+     * Removes the specified openstack vtap with given vtap identifier.
+     *
+     * @param vtapId vtap identifier
+     * @return removed openstack vtap object or null if error occurred
+     */
+    OpenstackVtap removeVtap(OpenstackVtapId vtapId);
+
+    /**
+     * Returns the number of openstack vtaps for the given type.
+     *
+     * @param type type of vtap (any,rx,tx,all)
+     * @return number of openstack vtaps
      */
     int getVtapCount(OpenstackVtap.Type type);
 
     /**
-     * Returns a collection of selected vTaps in the store.
+     * Returns a set of openstack vtaps for the given type.
      *
-     * @param type               vTap type
-     * @return iterable collection of selected vTaps
+     * @param type type of vtap (any,rx,tx,all)
+     * @return set of openstack vtaps
      */
     Set<OpenstackVtap> getVtaps(OpenstackVtap.Type type);
 
     /**
-     * Returns the vTap with the specified identifier.
+     * Returns the openstack vtap with the specified identifier.
      *
-     * @param vTapId             vTap identifier
-     * @return vTap or null if not exist
+     * @param vtapId vtap identifier
+     * @return openstack vtap or null if one with the given identifier is not known
      */
-    OpenstackVtap getVtap(OpenstackVtapId vTapId);
+    OpenstackVtap getVtap(OpenstackVtapId vtapId);
 
     /**
-     * Returns a collection of vTaps which are associated with the given device.
+     * Returns a set of openstack vtaps which are associated with the given device.
      *
-     * @param type               vTap type
-     * @param deviceId           device identifier
-     * @return a set of vTaps
+     * @param deviceId device identifier
+     * @return set of openstack vtaps
      */
-    Set<OpenstackVtap> getVtapsByDeviceId(OpenstackVtap.Type type, DeviceId deviceId);
+    Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId);
 }
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapStore.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapStore.java
index 15c945e..da9364d 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapStore.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/OpenstackVtapStore.java
@@ -21,92 +21,162 @@
 import java.util.Set;
 
 /**
- * Manages inventory of OpenstackVtap states; not intended for direct use.
+ * Manages inventory of openstack vtap datum; not intended for direct use.
  */
 public interface OpenstackVtapStore
         extends Store<OpenstackVtapEvent, OpenstackVtapStoreDelegate> {
 
     /**
-     * Creates a new vTap or updates the existing one based on the specified
-     * description.
+     * Creates a new openstack vtap network based on the specified description.
      *
-     * @param vTapId             vTap identifier
-     * @param description        vTap description data
-     * @param replaceFlag        replace device set if true, merge device set otherwise
-     * @return created or updated vTap object or null if error occurred
+     * @param key         vtap network identifier
+     * @param description description of vtap network
+     * @return created openstack vtap network object or null if error occurred
      */
-    OpenstackVtap createOrUpdateVtap(OpenstackVtapId vTapId, OpenstackVtap description, boolean replaceFlag);
+    OpenstackVtapNetwork createVtapNetwork(Integer key, OpenstackVtapNetwork description);
 
     /**
-     * Removes the specified vTap from the inventory by the given vTap identifier.
+     * Updates the openstack vtap network based on the specified description.
      *
-     * @param vTapId             vTap identifier
-     * @return removed vTap object or null if error occurred
+     * @param key         vtap network identifier
+     * @param description description of vtap network
+     * @return updated openstack vtap network object or null if error occurred
      */
-    OpenstackVtap removeVtapById(OpenstackVtapId vTapId);
+    OpenstackVtapNetwork updateVtapNetwork(Integer key, OpenstackVtapNetwork description);
 
     /**
-     * Adds the specified device id from the vTap entry.
+     * Removes the specified openstack vtap network with the specified identifier.
      *
-     * @param vTapId             vTap identification
-     * @param type               vTap type
-     * @param deviceId           device identifier to be added
+     * @param key vtap network identifier
+     * @return removed openstack vtap network object or null if error occurred
+     */
+    OpenstackVtapNetwork removeVtapNetwork(Integer key);
+
+    /**
+     * Removes all openstack vtap networks.
+     */
+    void clearVtapNetworks();
+
+    /**
+     * Returns the number of openstack vtap networks.
+     *
+     * @return number of openstack vtap networks
+     */
+    int getVtapNetworkCount();
+
+    /**
+     * Returns the openstack vtap network with the specified identifier.
+     *
+     * @param key vtap network identifier
+     * @return openstack vtap or null if one with the given identifier is not known
+     */
+    OpenstackVtapNetwork getVtapNetwork(Integer key);
+
+    /**
+     * Adds the specified device id to the specified vtap network entry.
+     *
+     * @param key      vtap network identifier
+     * @param deviceId device identifier to be added
      * @return true on success, false otherwise
      */
-    boolean addDeviceToVtap(OpenstackVtapId vTapId, OpenstackVtap.Type type, DeviceId deviceId);
+    boolean addDeviceToVtapNetwork(Integer key, DeviceId deviceId);
 
     /**
-     * Removes the specified device id from the vTap entry.
+     * Removes the specified device id from the specified vtap network entry.
      *
-     * @param vTapId             vTap identification
-     * @param type               vTap type
-     * @param deviceId           device identifier to be removed
+     * @param key      vtap network identifier
+     * @param deviceId device identifier to be removed
      * @return true on success, false otherwise
      */
-    boolean removeDeviceFromVtap(OpenstackVtapId vTapId, OpenstackVtap.Type type, DeviceId deviceId);
+    boolean removeDeviceFromVtapNetwork(Integer key, DeviceId deviceId);
 
     /**
-     * Adds the specified device id from the vTap entry.
+     * Returns a set of device identifiers from the specified vtap network entry.
      *
-     * @param vTapId             vTap identification
-     * @param txDeviceIds        TX device identifiers to be updated
-     * @param rxDeviceIds        RX device identifiers to be updated
-     * @param replaceFlag        replace device set if true, merge device set otherwise
-     * @return true on success, false otherwise
+     * @param key vtap network identifier
+     * @return set of device identifier
      */
-    boolean updateDeviceForVtap(OpenstackVtapId vTapId, Set<DeviceId> txDeviceIds,
-                                Set<DeviceId> rxDeviceIds, boolean replaceFlag);
+    Set<DeviceId> getVtapNetworkDevices(Integer key);
 
     /**
-     * Returns the number of vTaps in the store.
+     * Creates a new openstack vtap based on the specified description.
      *
-     * @param type               vTap type
-     * @return vTap count
+     * @param description description of vtap
+     * @return created openstack vtap object or null if error occurred
+     */
+    OpenstackVtap createVtap(OpenstackVtap description);
+
+    /**
+     * Updates the openstack vtap with specified description.
+     *
+     * @param description    description of vtap
+     * @param replaceDevices replace device set if true, merge device set otherwise
+     * @return updated openstack vtap object or null if error occurred
+     */
+    OpenstackVtap updateVtap(OpenstackVtap description, boolean replaceDevices);
+
+    /**
+     * Removes the specified openstack vtap with given vtap identifier.
+     *
+     * @param vtapId vtap identifier
+     * @return removed openstack vtap object or null if error occurred
+     */
+    OpenstackVtap removeVtap(OpenstackVtapId vtapId);
+
+    /**
+     * Removes all openstack vtaps.
+     */
+    void clearVtaps();
+
+    /**
+     * Returns the number of openstack vtaps for the given type.
+     *
+     * @param type type of vtap (any,rx,tx,all)
+     * @return number of openstack vtaps
      */
     int getVtapCount(OpenstackVtap.Type type);
 
     /**
-     * Returns a collection of selected vTaps in the store.
+     * Returns a set of openstack vtaps for the given type.
      *
-     * @param type               vTap type
-     * @return iterable collection of selected vTaps
+     * @param type type of vtap (any,rx,tx,all)
+     * @return set of openstack vtaps
      */
     Set<OpenstackVtap> getVtaps(OpenstackVtap.Type type);
 
     /**
-     * Returns the vTap with the specified identifier.
+     * Returns the openstack vtap with the specified identifier.
      *
-     * @param vTapId             vTap identifier
-     * @return vtap or null if not found
+     * @param vtapId vtap identifier
+     * @return openstack vtap or null if one with the given identifier is not known
      */
-    OpenstackVtap getVtap(OpenstackVtapId vTapId);
+    OpenstackVtap getVtap(OpenstackVtapId vtapId);
 
     /**
-     * Returns the set of vTaps whose included on device.
+     * Adds the specified device id to the specified vtap entry.
      *
-     * @param type               vTap type
-     * @param deviceId           device identifier
-     * @return set of vTaps
+     * @param vtapId   vtap identifier
+     * @param type     type of vtap (any,rx,tx,all)
+     * @param deviceId device identifier to be added
+     * @return true on success, false otherwise
      */
-    Set<OpenstackVtap> getVtapsByDeviceId(OpenstackVtap.Type type, DeviceId deviceId);
+    boolean addDeviceToVtap(OpenstackVtapId vtapId, OpenstackVtap.Type type, DeviceId deviceId);
+
+    /**
+     * Removes the specified device id from the vtap entry.
+     *
+     * @param vtapId   vtap identifier
+     * @param type     type of vtap (any,rx,tx,all)
+     * @param deviceId device identifier to be removed
+     * @return true on success, false otherwise
+     */
+    boolean removeDeviceFromVtap(OpenstackVtapId vtapId, OpenstackVtap.Type type, DeviceId deviceId);
+
+    /**
+     * Returns a set of openstack vtaps which are associated with the given device.
+     *
+     * @param deviceId device identifier
+     * @return set of openstack vtaps
+     */
+    Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId);
 }
diff --git a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/package-info.java b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/package-info.java
index 77ad58c..fe00c7c 100644
--- a/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/package-info.java
+++ b/apps/openstackvtap/api/src/main/java/org/onosproject/openstackvtap/api/package-info.java
@@ -15,6 +15,6 @@
  */
 
 /**
- * Application API for Openstack vTap.
+ * Application API for openstack vtap.
  */
 package org.onosproject.openstackvtap.api;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/BUCK b/apps/openstackvtap/app/BUCK
index dc3f55c..3656f6c 100644
--- a/apps/openstackvtap/app/BUCK
+++ b/apps/openstackvtap/app/BUCK
@@ -25,8 +25,8 @@
     deps = COMPILE_DEPS,
     test_deps = TEST_DEPS,
     web_context = '/onos/openstackvtap',
-    api_title = 'OpenStack Network vTap REST API',
+    api_title = 'OpenStack Vtap REST API',
     api_version = '1.0',
-    api_description = 'OpenStack Network vTap REST API',
+    api_description = 'OpenStack Vtap REST API',
     api_package = 'org.onosproject.openstackvtap.web',
 )
diff --git a/apps/openstackvtap/app/BUILD b/apps/openstackvtap/app/BUILD
index 078ed2b..7d2ceba 100644
--- a/apps/openstackvtap/app/BUILD
+++ b/apps/openstackvtap/app/BUILD
@@ -12,9 +12,9 @@
 ]
 
 osgi_jar_with_tests(
-    api_description = "OpenStack Network vTap REST API",
+    api_description = "Openstack Vtap REST API",
     api_package = "org.onosproject.openstackvtap.web",
-    api_title = "OpenStack Network vTap REST API",
+    api_title = "Openstack Vtap REST API",
     api_version = "1.0",
     test_deps = TEST_DEPS,
     web_context = "/onos/openstackvtap",
diff --git a/apps/openstackvtap/app/app.xml b/apps/openstackvtap/app/app.xml
index 45024d9..b077858 100644
--- a/apps/openstackvtap/app/app.xml
+++ b/apps/openstackvtap/app/app.xml
@@ -15,7 +15,7 @@
   ~ limitations under the License.
   -->
 <app name="org.onosproject.openstackvtap" origin="Open Networking Foundation"
-     version="${project.version}" category="Utility" title="OpenStack vTap App"
+     version="${project.version}" category="Utility" title="Openstack Vtap App"
      features="${project.artifactId}" apps="org.onosproject.openstacknetworking"
      featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features">
     <description>${project.description}</description>
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapAddCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapAddCommand.java
index 61049ae..9480346 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapAddCommand.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapAddCommand.java
@@ -29,14 +29,14 @@
 import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
 
 /**
- * Command line interface for adding openstack vTap rule.
+ * Adds a openstack vtap rule.
  */
 @Service
 @Command(scope = "onos", name = "openstack-vtap-add",
         description = "OpenstackVtap activate")
 public class OpenstackVtapAddCommand extends AbstractShellCommand {
 
-    private final OpenstackVtapAdminService vTapService =
+    private final OpenstackVtapAdminService vtapService =
                                             get(OpenstackVtapAdminService.class);
 
     @Argument(index = 0, name = "srcIp",
@@ -50,9 +50,9 @@
     String dstIp = "";
 
     @Argument(index = 2, name = "ipProto",
-            description = "IP protocol [tcp|udp|icmp|none]",
+            description = "IP protocol [any|tcp|udp|icmp]",
             required = false, multiValued = false)
-    String ipProto = "";
+    String ipProto = "any";
 
     @Argument(index = 3, name = "srcTpPort",
             description = "source transport layer port (0 is skip)",
@@ -65,43 +65,43 @@
     int dstTpPort = 0;
 
     @Argument(index = 5, name = "type",
-            description = "vTap type [all|tx|rx]",
+            description = "vtap type [all|rx|tx]",
             required = false, multiValued = false)
-    String vTapTypeStr = "all";
+    String vtapTypeStr = "all";
 
     @Override
     protected void doExecute() {
-        DefaultOpenstackVtapCriterion.Builder
-                    defaultVtapCriterionBuilder = DefaultOpenstackVtapCriterion.builder();
-        if (makeCriterion(defaultVtapCriterionBuilder)) {
-            OpenstackVtap.Type type = getVtapTypeFromString(vTapTypeStr);
+        DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder = DefaultOpenstackVtapCriterion.builder();
+        if (makeCriterion(vtapCriterionBuilder)) {
+            OpenstackVtap.Type type = getVtapTypeFromString(vtapTypeStr);
+
             if (type == null) {
-                print("Invalid vTap type");
+                print("Invalid vtap type");
                 return;
             }
 
-            OpenstackVtap vTap = vTapService.createVtap(type, defaultVtapCriterionBuilder.build());
-            if (vTap != null) {
-                print("Created OpenstackVtap with id { %s }", vTap.id().toString());
+            OpenstackVtap vtap = vtapService.createVtap(type, vtapCriterionBuilder.build());
+            if (vtap != null) {
+                print("Created OpenstackVtap with id { %s }", vtap.id().toString());
             } else {
                 print("Failed to create OpenstackVtap");
             }
         }
     }
 
-    private boolean makeCriterion(DefaultOpenstackVtapCriterion.Builder vTapCriterionBuilder) {
+    private boolean makeCriterion(DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder) {
         try {
-            vTapCriterionBuilder.srcIpPrefix(IpPrefix.valueOf(srcIp));
-            vTapCriterionBuilder.dstIpPrefix(IpPrefix.valueOf(dstIp));
+            vtapCriterionBuilder.srcIpPrefix(IpPrefix.valueOf(srcIp));
+            vtapCriterionBuilder.dstIpPrefix(IpPrefix.valueOf(dstIp));
         } catch (Exception e) {
             print("Inputted valid source IP & destination IP in CIDR (e.g., \"10.1.0.4/32\")");
             return false;
         }
 
-        vTapCriterionBuilder.ipProtocol(getProtocolTypeFromString(ipProto.toLowerCase()));
+        vtapCriterionBuilder.ipProtocol(getProtocolTypeFromString(ipProto.toLowerCase()));
 
-        vTapCriterionBuilder.srcTpPort(TpPort.tpPort(srcTpPort));
-        vTapCriterionBuilder.dstTpPort(TpPort.tpPort(dstTpPort));
+        vtapCriterionBuilder.srcTpPort(TpPort.tpPort(srcTpPort));
+        vtapCriterionBuilder.dstTpPort(TpPort.tpPort(dstTpPort));
 
         return true;
     }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapDeleteCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapDeleteCommand.java
index a5f06ee..e2d37f7 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapDeleteCommand.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapDeleteCommand.java
@@ -23,26 +23,26 @@
 import org.onosproject.openstackvtap.api.OpenstackVtapId;
 
 /**
- * Command line interface for removing openstack vTap rule.
+ * Delete a openstack vtap rule from the existing vtaps.
  */
 @Service
 @Command(scope = "onos", name = "openstack-vtap-del",
         description = "OpenstackVtap deactivate")
 public class OpenstackVtapDeleteCommand extends AbstractShellCommand {
 
-    private final OpenstackVtapAdminService vTapService = get(OpenstackVtapAdminService.class);
+    private final OpenstackVtapAdminService vtapService = get(OpenstackVtapAdminService.class);
 
-    @Argument(index = 0, name = "id", description = "vTap ID",
+    @Argument(index = 0, name = "id", description = "vtap ID",
             required = true, multiValued = false)
-    String vTapId = "";
+    String vtapId = "";
 
     @Override
     protected void doExecute() {
-        OpenstackVtap vTap = vTapService.removeVtap(OpenstackVtapId.vTapId(vTapId));
-        if (vTap != null) {
-            print("Removed OpenstackVtap with id { %s }", vTap.id().toString());
+        OpenstackVtap vtap = vtapService.removeVtap(OpenstackVtapId.vtapId(vtapId));
+        if (vtap != null) {
+            print("Removed OpenstackVtap with id { %s }", vtap.id().toString());
         } else {
-            print("Failed to remove OpenstackVtap with id { %s }", vTapId);
+            print("Failed to remove OpenstackVtap with id { %s }", vtapId);
         }
     }
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapListCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapListCommand.java
index 5ffc265..089f850 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapListCommand.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapListCommand.java
@@ -15,48 +15,68 @@
  */
 package org.onosproject.openstackvtap.cli;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.onosproject.openstackvtap.api.OpenstackVtap;
 import org.onosproject.openstackvtap.api.OpenstackVtapService;
 
+import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
 
 /**
- * Command line interface for listing openstack vTap rules.
+ * Lists openstack vtap rules.
  */
 @Service
 @Command(scope = "onos", name = "openstack-vtap-list",
         description = "OpenstackVtap list")
 public class OpenstackVtapListCommand extends AbstractShellCommand {
 
-    private final OpenstackVtapService vTapService = get(OpenstackVtapService.class);
+    private final OpenstackVtapService vtapService = get(OpenstackVtapService.class);
+    private final OpenstackNodeService osNodeService = get(OpenstackNodeService.class);
 
     @Argument(index = 0, name = "type",
-            description = "vTap type [all|tx|rx]",
+            description = "vtap type [any|all|rx|tx]",
             required = false, multiValued = false)
-    String vTapType = "none";
+    String vtapType = "any";
 
     private static final String FORMAT = "ID { %s }: type [%s], srcIP [%s], dstIP [%s]";
-    private static final String FORMAT_TX_DEVICES  = "   tx devices: %s";
-    private static final String FORMAT_RX_DEVICES  = "   rx devices: %s";
+    private static final String FORMAT_TX_NODES = "   tx openstack nodes: %s";
+    private static final String FORMAT_RX_NODES = "   rx openstack nodes: %s";
 
     @Override
     protected void doExecute() {
-        OpenstackVtap.Type type = getVtapTypeFromString(vTapType);
-        Set<OpenstackVtap> openstackVtaps = vTapService.getVtaps(type);
-        for (OpenstackVtap vTap : openstackVtaps) {
+        OpenstackVtap.Type type = getVtapTypeFromString(vtapType);
+        Set<OpenstackVtap> openstackVtaps = vtapService.getVtaps(type);
+        for (OpenstackVtap vtap : openstackVtaps) {
             print(FORMAT,
-                    vTap.id().toString(),
-                    vTap.type().toString(),
-                    vTap.vTapCriterion().srcIpPrefix().toString(),
-                    vTap.vTapCriterion().dstIpPrefix().toString());
-            print(FORMAT_TX_DEVICES, vTap.txDeviceIds());
-            print(FORMAT_RX_DEVICES, vTap.rxDeviceIds());
+                    vtap.id().toString(),
+                    vtap.type().toString(),
+                    vtap.vtapCriterion().srcIpPrefix().toString(),
+                    vtap.vtapCriterion().dstIpPrefix().toString());
+            print(FORMAT_TX_NODES, osNodeNames(vtap.txDeviceIds()));
+            print(FORMAT_RX_NODES, osNodeNames(vtap.rxDeviceIds()));
         }
     }
+
+    private Set<String> osNodeNames(Set<DeviceId> deviceIds) {
+        if (deviceIds == null) {
+            return ImmutableSet.of();
+        } else {
+            return deviceIds.parallelStream()
+                    .map(osNodeService::node)
+                    .filter(Objects::nonNull)
+                    .map(OpenstackNode::hostname)
+                    .collect(Collectors.toSet());
+        }
+    }
+
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapNetworkListCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapNetworkListCommand.java
new file mode 100644
index 0000000..225582b
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapNetworkListCommand.java
@@ -0,0 +1,70 @@
+/*
+ * 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.openstackvtap.cli;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Lists openstack vtap networks.
+ */
+@Service
+@Command(scope = "onos", name = "openstack-vtap-network-list",
+        description = "OpenstackVtap network list")
+public class OpenstackVtapNetworkListCommand extends AbstractShellCommand {
+
+    private final OpenstackVtapAdminService osVtapAdminService = get(OpenstackVtapAdminService.class);
+    private final OpenstackNodeService osNodeService = get(OpenstackNodeService.class);
+
+    private static final String FORMAT = "mode [%s], networkId [%d], serverIp [%s]";
+    private static final String FORMAT_NODES = "   openstack nodes: %s";
+
+    @Override
+    protected void doExecute() {
+        OpenstackVtapNetwork vtapNetwork = osVtapAdminService.getVtapNetwork();
+        if (vtapNetwork != null) {
+            print(FORMAT,
+                    vtapNetwork.mode().toString(),
+                    vtapNetwork.networkId() != null ? vtapNetwork.networkId() : "N/A",
+                    vtapNetwork.serverIp().toString());
+            print(FORMAT_NODES, osNodeNames(osVtapAdminService.getVtapNetworkDevices()));
+        }
+    }
+
+    private Set<String> osNodeNames(Set<DeviceId> deviceIds) {
+        if (deviceIds == null) {
+            return ImmutableSet.of();
+        } else {
+            return deviceIds.parallelStream()
+                    .map(osNodeService::node)
+                    .filter(Objects::nonNull)
+                    .map(OpenstackNode::hostname)
+                    .collect(Collectors.toSet());
+        }
+    }
+
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapOutputCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapOutputCommand.java
deleted file mode 100644
index 1a04f84..0000000
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapOutputCommand.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.openstackvtap.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.VlanId;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.openstackvtap.api.OpenstackVtap;
-import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
-
-import static org.onlab.packet.VlanId.UNTAGGED;
-import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
-
-/**
- * Command line interface for set openstack vTap output.
- */
-@Service
-@Command(scope = "onos", name = "openstack-vtap-output",
-        description = "OpenstackVtap output setup")
-public class OpenstackVtapOutputCommand extends AbstractShellCommand {
-
-    private final DeviceService deviceService = get(DeviceService.class);
-    private final OpenstackVtapAdminService vTapAdminService =
-                                            get(OpenstackVtapAdminService.class);
-
-    @Argument(index = 0, name = "deviceId", description = "device id",
-            required = true, multiValued = false)
-    String id = "";
-
-    @Argument(index = 1, name = "port", description = "output port number",
-            required = true, multiValued = false)
-    int port = 0;
-
-    @Argument(index = 2, name = "vlan", description = "vlan id",
-            required = false, multiValued = false)
-    int vlan = UNTAGGED;
-
-    @Argument(index = 3, name = "type", description = "vTap type [all|tx|rx]",
-            required = false, multiValued = false)
-    String vTapTypeStr = "all";
-
-    @Override
-    protected void doExecute() {
-        try {
-            Device device = deviceService.getDevice(DeviceId.deviceId(id));
-            if (device != null) {
-                OpenstackVtap.Type type = getVtapTypeFromString(vTapTypeStr);
-
-                vTapAdminService.setVtapOutput(device.id(), type,
-                        PortNumber.portNumber(port), VlanId.vlanId((short) vlan));
-                print("Set OpenstackVtap output deviceId { %s }, port=%s, vlan=%s",
-                        device.id().toString(),
-                        PortNumber.portNumber(port).toString(),
-                        VlanId.vlanId((short) vlan).toString());
-            } else {
-                print("Invalid device id");
-            }
-        } catch (Exception e) {
-            print("Invalid parameter: %s", e.toString());
-        }
-    }
-}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java
index feb6830..49c676d 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java
@@ -30,10 +30,10 @@
     @Override
     protected List<String> choices() {
         List<String> strings = Lists.newArrayList();
+        strings.add("any");
         strings.add("tcp");
         strings.add("udp");
         strings.add("icmp");
-        strings.add("none");
         return strings;
     }
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java
index 811b63d..ba834e7 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java
@@ -30,12 +30,12 @@
 import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
 
 /**
- * vTap ID completer.
+ * Vtap ID completer.
  */
 @Service
 public class VtapIdCompleter implements Completer {
 
-    private static final String VTAP_TYPE = "none";
+    private static final String VTAP_TYPE = "any";
 
     @Override
     public int complete(Session session, CommandLine commandLine, List<String> candidates) {
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java
index 83c227e..50ab3d9 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java
@@ -22,7 +22,7 @@
 import java.util.List;
 
 /**
- * vTap type completer.
+ * Vtap type completer.
  */
 @Service
 public class VtapTypeCompleter extends AbstractChoicesCompleter {
@@ -30,9 +30,10 @@
     @Override
     protected List<String> choices() {
         List<String> strings = Lists.newArrayList();
-        strings.add("tx");
-        strings.add("rx");
         strings.add("all");
+        strings.add("rx");
+        strings.add("tx");
+        strings.add("any");
         return strings;
     }
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java
index 772bbc8..3b3dec1 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java
@@ -15,6 +15,6 @@
  */
 
 /**
- * Console commands for OpenStack vtap.
+ * Console commands for openstack vtap.
  */
 package org.onosproject.openstackvtap.cli;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/OpenstackVtapNetworkCodec.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/OpenstackVtapNetworkCodec.java
new file mode 100644
index 0000000..6dd6b5c
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/OpenstackVtapNetworkCodec.java
@@ -0,0 +1,73 @@
+/*
+ * 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.openstackvtap.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.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.openstackvtap.impl.DefaultOpenstackVtapNetwork;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Openstack vtap network codec used for serializing and de-serializing JSON string.
+ */
+public final class OpenstackVtapNetworkCodec extends JsonCodec<OpenstackVtapNetwork> {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String MODE = "mode";
+    private static final String NETWORK_ID = "networkId";
+    private static final String SERVER_IP = "serverIp";
+    private static final String NODES = "nodes";
+
+    private static final String JSON_NULL_MESSAGE = "% cannot be null";
+    private static final String JSON_MISSING_MESSAGE = "% is required";
+    private static final String JSON_TYPE_MESSAGE = "% is not json object type";
+
+    @Override
+    public ObjectNode encode(OpenstackVtapNetwork network, CodecContext context) {
+        checkNotNull(network, JSON_NULL_MESSAGE, "OpenstackVtapNetwork object");
+
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(MODE, network.mode().toString())
+                .put(NETWORK_ID, network.networkId())
+                .put(SERVER_IP, network.serverIp().toString());
+
+        return result;
+    }
+
+    @Override
+    public OpenstackVtapNetwork decode(ObjectNode json, CodecContext context) {
+        checkNotNull(json, JSON_NULL_MESSAGE, "OpenstackVtapNetwork json");
+        checkState(json.isObject(), JSON_TYPE_MESSAGE, "OpenstackVtapNetwork json");
+
+        DefaultOpenstackVtapNetwork.Builder builder = DefaultOpenstackVtapNetwork.builder()
+                .mode(OpenstackVtapNetwork.Mode.valueOf(checkNotNull(json.get(MODE).asText(null),
+                        JSON_MISSING_MESSAGE, MODE)))
+                .networkId(json.get(NETWORK_ID).asInt(0))
+                .serverIp(IpAddress.valueOf(checkNotNull(json.get(SERVER_IP).asText(null),
+                        JSON_MISSING_MESSAGE, SERVER_IP)));
+
+        log.debug("OpenstackVtapNetwork is {}", builder.build().toString());
+        return builder.build();
+    }
+}
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/package-info.java
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/package-info.java
index 5307028..f76f7a9 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/package-info.java
@@ -13,21 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../app/log.service';
 
 /**
- * ONOS GUI -- Log Service - Unit Tests
+ * Implementations of the codec broker and openstack vtap entity JSON codecs.
  */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
-
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+package org.onosproject.openstackvtap.codec;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUI.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUI.java
new file mode 100644
index 0000000..e2ebf3a
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUI.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.openstackvtap.gui;
+
+import com.google.common.collect.ImmutableList;
+import org.onosproject.ui.UiExtensionService;
+import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiTopoOverlayFactory;
+import org.onosproject.ui.UiView;
+import org.onosproject.ui.UiViewHidden;
+import org.onosproject.ui.UiExtension;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Mechanism to stream data to the GUI.
+ */
+@Component(immediate = true, service = {OpenstackVtapUI.class})
+public class OpenstackVtapUI {
+    private static final String OPENSTACK_VTAP_ID = "openstackvtap";
+    private static final String RESOURCE_PATH = "gui";
+    private static final ClassLoader CL = OpenstackVtapUI.class.getClassLoader();
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected UiExtensionService uiExtensionService;
+
+    // Factory for UI message handlers
+    private final UiMessageHandlerFactory messageHandlerFactory =
+            () -> ImmutableList.of(new OpenstackVtapViewMessageHandler());
+
+    // List of application views
+    private final List<UiView> views = ImmutableList.of(
+            new UiViewHidden(OPENSTACK_VTAP_ID)
+    );
+
+    // Factory for UI topology overlays
+    private final UiTopoOverlayFactory topoOverlayFactory =
+            () -> ImmutableList.of(
+                    new OpenstackVtapUiTopovOverlay()
+            );
+
+    // Application UI extension
+    private final UiExtension uiExtension =
+            new UiExtension.Builder(CL, views)
+                    .messageHandlerFactory(messageHandlerFactory)
+                    .resourcePath(RESOURCE_PATH)
+                    .topoOverlayFactory(topoOverlayFactory)
+                    .build();
+
+    @Activate
+    protected void activate() {
+        uiExtensionService.register(uiExtension);
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        uiExtensionService.unregister(uiExtension);
+        log.info("Stopped");
+    }
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUiTopovOverlay.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUiTopovOverlay.java
new file mode 100644
index 0000000..287aa99
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUiTopovOverlay.java
@@ -0,0 +1,40 @@
+/*
+ * 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.openstackvtap.gui;
+
+import org.onosproject.ui.UiTopoOverlay;
+
+public class OpenstackVtapUiTopovOverlay extends UiTopoOverlay {
+    private static final String OVERLAY_ID = "vtap-overlay";
+
+    public OpenstackVtapUiTopovOverlay() {
+        super(OVERLAY_ID);
+    }
+
+    @Override
+    public void activate() {
+        super.activate();
+        log.debug("Openstack VtapOverlay Activated");
+    }
+
+    @Override
+    public void deactivate() {
+        super.deactivate();
+        log.debug("Openstack VtapOverlay Deactivated");
+    }
+
+}
+
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapViewMessageHandler.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapViewMessageHandler.java
new file mode 100644
index 0000000..f95bbc4
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapViewMessageHandler.java
@@ -0,0 +1,230 @@
+/*
+ * 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.openstackvtap.gui;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.ui.RequestHandler;
+import org.onosproject.ui.UiConnection;
+import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Collection;
+import java.util.Set;
+import java.util.Iterator;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.TpPort;
+import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.impl.DefaultOpenstackVtapCriterion;
+
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getProtocolTypeFromString;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
+
+
+import static org.onosproject.net.HostId.hostId;
+
+/**
+ * Message handler for Openstack Vtap related messages.
+ */
+public class OpenstackVtapViewMessageHandler extends UiMessageHandler {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final String OSV_IS_ACTIVATED_REQ = "openstackVtapIsActivatedRequest";
+    private static final String OSV_IS_ACTIVATED_RESP = "openstackVtapIsActivatedResponse";
+    private static final String OSV_CREATE_REQ = "openstackVtapCreateRequest";
+    private static final String OSV_CREATE_RESP = "openstackVtapCreateResponse";
+
+    private static final String SOURCE = "src";
+    private static final String DESTINATION = "dst";
+    private static final String SOURCE_IP = "srcIp";
+    private static final String DESTINATION_IP = "dstIp";
+    private static final String SOURCE_TRANSPORT_PORT = "srcPort";
+    private static final String DESTINATION_TRANSPORT_PORT = "dstPort";
+    private static final String SOURCE_HOST_NAME = "srcName";
+    private static final String DESTINATION_HOST_NAME = "dstName";
+    private static final String IP_PROTOCOL = "ipProto";
+    private static final String VTAP_TYPE = "vtapType";
+    private static final String IP_PROTOCOL_LIST = "ipProtoList";
+    private static final String VTAP_TYPE_LIST = "vtapTypeList";
+
+    private static final String RESULT = "result";
+    private static final String VALUE = "value";
+    private static final String SUCCESS = "Success";
+    private static final String FAILED = "Failed";
+    private static final String INVALID_VTAP_TYPE = "Invalid vtap type";
+    private static final String FAILED_TO_CREATE_VTAP = "Failed to create OpenstackVtap";
+    private static final String WRONG_IP_ADDRESS =
+            "Inputted valid source & destination IP in CIDR (e.g., \"10.1.0.4/32\")";
+    private static final String INVALID_TRANSPORT_PORT =
+            "Invalid source & destination transport port has been entered";
+
+    private static final String[] IP_PROTOCOL_ARRAY = {"Any", "TCP", "UDP", "ICMP"};
+    private static final String[] VTAP_TYPE_ARRAY = {"All", "RX", "TX"};
+
+    private HostService hostService;
+    private OpenstackVtapAdminService vtapService;
+
+    @Override
+    public void init(UiConnection connection, ServiceDirectory directory) {
+        super.init(connection, directory);
+
+        hostService = directory.get(HostService.class);
+        vtapService = directory.get(OpenstackVtapAdminService.class);
+    }
+
+    @Override
+    protected Collection<RequestHandler> createRequestHandlers() {
+        return ImmutableSet.of(
+                new VtapIsActivatedRequestHandler(),
+                new VtapCreateRequestHandler()
+        );
+
+    }
+
+    private final class VtapIsActivatedRequestHandler extends RequestHandler {
+
+        private VtapIsActivatedRequestHandler() {
+            super(OSV_IS_ACTIVATED_REQ);
+        }
+
+        @Override
+        public void process(ObjectNode payload) {
+            String srcId = string(payload, SOURCE, null);
+            String dstId = string(payload, DESTINATION, null);
+
+            if (srcId != null && dstId != null) {
+                HostId sHostId = hostId(srcId);
+                HostId dHostId = hostId(dstId);
+
+                Host sHost = hostService.getHost(sHostId);
+                Host dHost = hostService.getHost(dHostId);
+
+                if (sHost != null && dHost != null) {
+                    ArrayNode ipProtos = arrayNode();
+                    ArrayNode types = arrayNode();
+                    String sHostName = ipForHost(sHost);
+                    String dHostName = ipForHost(dHost);
+
+                    for (String proto : IP_PROTOCOL_ARRAY) {
+                        ipProtos.add(proto);
+                    }
+
+                    for (String type : VTAP_TYPE_ARRAY) {
+                        types.add(type);
+                    }
+
+                    payload.put(SOURCE_HOST_NAME, sHostName);
+                    payload.put(DESTINATION_HOST_NAME, dHostName);
+                    payload.put(IP_PROTOCOL_LIST, ipProtos);
+                    payload.put(VTAP_TYPE_LIST, types);
+
+                    sendMessage(OSV_IS_ACTIVATED_RESP, payload);
+                }
+            }
+        }
+
+        // Returns the first of the given host's set of IP addresses as a string.
+        private String ipForHost(Host host) {
+            Set<IpAddress> ipAddresses = host.ipAddresses();
+            Iterator<IpAddress> it = ipAddresses.iterator();
+            return it.hasNext() ? it.next().toString() + "/32" : "unknown";
+        }
+    }
+
+    private final class VtapCreateRequestHandler extends RequestHandler {
+        private String srcIp;
+        private String dstIp;
+        private String ipProto;
+        private String srcTpPort;
+        private String dstTpPort;
+        private String vtapTypeStr;
+        private ObjectNode result = objectNode();
+
+        private VtapCreateRequestHandler() {
+            super(OSV_CREATE_REQ);
+        }
+
+        @Override
+        public void process(ObjectNode payload) {
+            srcIp = string(payload, SOURCE_IP, null);
+            dstIp = string(payload, DESTINATION_IP, null);
+            ipProto = string(payload, IP_PROTOCOL, null);
+            srcTpPort = string(payload, SOURCE_TRANSPORT_PORT, null);
+            dstTpPort = string(payload, DESTINATION_TRANSPORT_PORT, null);
+            vtapTypeStr = string(payload, VTAP_TYPE, null);
+            log.trace("VtapCreateRequestHandler payload srcIp:{}, dstIp:{}, ipPro:{}, " +
+                            "srcTpPort:{}, dstTpPort:{}, vtapType:{}", srcIp, dstIp, ipProto,
+                    srcTpPort, dstTpPort, vtapTypeStr);
+
+            DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder = DefaultOpenstackVtapCriterion.builder();
+            if (makeCriterion(vtapCriterionBuilder)) {
+                OpenstackVtap.Type type = getVtapTypeFromString(vtapTypeStr.toLowerCase());
+                if (type == null) {
+                    log.warn(INVALID_VTAP_TYPE);
+                    result.put(RESULT, FAILED);
+                    result.put(VALUE, INVALID_VTAP_TYPE);
+                    sendMessage(OSV_CREATE_RESP, result);
+                    return;
+                }
+
+                OpenstackVtap vtap = vtapService.createVtap(type, vtapCriterionBuilder.build());
+                if (vtap != null) {
+                    log.info("Created OpenstackVtap with id {}", vtap.id().toString());
+                    result.put(RESULT, SUCCESS);
+                    result.put(VALUE, "vtap id: " + vtap.id().toString());
+                } else {
+                    log.warn(FAILED_TO_CREATE_VTAP);
+                    result.put(RESULT, FAILED);
+                    result.put(VALUE, FAILED_TO_CREATE_VTAP);
+                }
+            }
+            sendMessage(OSV_CREATE_RESP, result);
+        }
+
+        private boolean makeCriterion(DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder) {
+            try {
+                vtapCriterionBuilder.srcIpPrefix(IpPrefix.valueOf(srcIp));
+                vtapCriterionBuilder.dstIpPrefix(IpPrefix.valueOf(dstIp));
+            } catch (Exception e) {
+                log.warn(WRONG_IP_ADDRESS);
+                result.put(RESULT, FAILED);
+                result.put(VALUE, WRONG_IP_ADDRESS);
+                return false;
+            }
+
+            vtapCriterionBuilder.ipProtocol(getProtocolTypeFromString(ipProto.toLowerCase()));
+
+            try {
+                vtapCriterionBuilder.srcTpPort(TpPort.tpPort(Integer.valueOf(srcTpPort)));
+                vtapCriterionBuilder.dstTpPort(TpPort.tpPort(Integer.valueOf(dstTpPort)));
+            } catch (Exception e) {
+                log.warn(INVALID_TRANSPORT_PORT);
+                result.put(RESULT, FAILED);
+                result.put(VALUE, INVALID_TRANSPORT_PORT);
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/package-info.java
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/package-info.java
index 5307028..7521561 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/package-info.java
@@ -13,21 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../app/log.service';
 
 /**
- * ONOS GUI -- Log Service - Unit Tests
+ * Web GUI for the control plane manager.
  */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
-
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+package org.onosproject.openstackvtap.gui;
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java
index d5c842f..cc258c0 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java
@@ -15,9 +15,7 @@
  */
 package org.onosproject.openstackvtap.impl;
 
-import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 import org.onosproject.net.AbstractDescription;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DeviceId;
@@ -26,33 +24,47 @@
 import org.onosproject.openstackvtap.api.OpenstackVtapCriterion;
 import org.onosproject.openstackvtap.api.OpenstackVtapId;
 
+import java.util.Objects;
 import java.util.Set;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Default implementation of an immutable openstack vTap.
+ * Default implementation of an immutable OpenstackVtap.
  */
 public final class DefaultOpenstackVtap extends AbstractDescription implements OpenstackVtap {
 
     private final OpenstackVtapId id;
     private final Type type;
-    private final OpenstackVtapCriterion vTapCriterion;
+    private final OpenstackVtapCriterion vtapCriterion;
     private final Set<DeviceId> txDeviceIds;
     private final Set<DeviceId> rxDeviceIds;
 
-    // private constructor not intended to use from external
-    private DefaultOpenstackVtap(OpenstackVtapId id, Type type,
-                                 OpenstackVtapCriterion vTapCriterion,
-                                 Set<DeviceId> txDeviceIds, Set<DeviceId> rxDeviceIds,
+    /**
+     * Creates an DefaultOpenstackVtap using the supplied information.
+     *
+     * @param id            vtap identifier
+     * @param type          type of vtap (all,rx,tx)
+     * @param vtapCriterion criterion of vtap
+     * @param txDeviceIds   device identifiers applied by vtap tx
+     * @param rxDeviceIds   device identifiers applied by vtap rx
+     * @param annotations   optional key/value annotations
+     */
+    private DefaultOpenstackVtap(OpenstackVtapId id,
+                                 Type type,
+                                 OpenstackVtapCriterion vtapCriterion,
+                                 Set<DeviceId> txDeviceIds,
+                                 Set<DeviceId> rxDeviceIds,
                                  SparseAnnotations... annotations) {
         super(annotations);
-        this.id = id;
-        this.type = type;
-        this.vTapCriterion = vTapCriterion;
-        this.txDeviceIds = txDeviceIds;
-        this.rxDeviceIds = rxDeviceIds;
+        this.id = checkNotNull(id);
+        this.type = checkNotNull(type);
+        this.vtapCriterion = checkNotNull(vtapCriterion);
+        this.txDeviceIds = Objects.nonNull(txDeviceIds) ?
+                ImmutableSet.copyOf(txDeviceIds) : ImmutableSet.of();
+        this.rxDeviceIds = Objects.nonNull(rxDeviceIds) ?
+                ImmutableSet.copyOf(rxDeviceIds) : ImmutableSet.of();
     }
 
     @Override
@@ -66,129 +78,184 @@
     }
 
     @Override
-    public OpenstackVtapCriterion vTapCriterion() {
-        return vTapCriterion;
+    public OpenstackVtapCriterion vtapCriterion() {
+        return vtapCriterion;
     }
 
     @Override
     public Set<DeviceId> txDeviceIds() {
-        return ImmutableSet.copyOf(txDeviceIds);
+        return txDeviceIds;
     }
 
     @Override
     public Set<DeviceId> rxDeviceIds() {
-        return ImmutableSet.copyOf(rxDeviceIds);
+        return rxDeviceIds;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, type, vtapCriterion, txDeviceIds, rxDeviceIds);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultOpenstackVtap) {
+            final DefaultOpenstackVtap other = (DefaultOpenstackVtap) obj;
+            return Objects.equals(this.id, other.id) &&
+                    Objects.equals(this.type, other.type) &&
+                    Objects.equals(this.vtapCriterion, other.vtapCriterion) &&
+                    Objects.equals(this.txDeviceIds(), other.txDeviceIds()) &&
+                    Objects.equals(this.rxDeviceIds(), other.rxDeviceIds()) &&
+                    Objects.equals(this.annotations(), other.annotations());
+        }
+        return false;
     }
 
     @Override
     public String toString() {
         return toStringHelper(this)
-                .add("id", id)
-                .add("type", type)
-                .add("vTapCriterion", vTapCriterion)
-                .add("txDeviceIds", txDeviceIds)
-                .add("rxDeviceIds", rxDeviceIds)
+                .add("id", id())
+                .add("type", type())
+                .add("vtapCriterion", vtapCriterion())
+                .add("txDeviceIds", txDeviceIds())
+                .add("rxDeviceIds", rxDeviceIds())
+                .add("annotations", annotations())
                 .toString();
     }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id, type, vTapCriterion, txDeviceIds, rxDeviceIds);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        DefaultOpenstackVtap that = (DefaultOpenstackVtap) o;
-        return Objects.equal(this.id, that.id)
-                    && Objects.equal(this.type, that.type)
-                    && Objects.equal(this.vTapCriterion, that.vTapCriterion)
-                    && Objects.equal(this.txDeviceIds, that.txDeviceIds)
-                    && Objects.equal(this.rxDeviceIds, that.rxDeviceIds);
-    }
-
     /**
-     * Creates a new default openstack vTap builder.
+     * Creates OpenstackVtap builder with default parameters.
      *
-     * @return default openstack vTap builder
+     * @return builder
      */
     public static Builder builder() {
         return new Builder();
     }
 
     /**
+     * Creates OpenstackVtap builder inheriting with default parameters,
+     * from specified OpenstackVtap.
+     *
+     * @param vtap to inherit default from
+     * @return builder
+     */
+    public static Builder builder(OpenstackVtap vtap) {
+        return new Builder(vtap);
+    }
+
+    /**
      * Builder for DefaultOpenstackVtap object.
      */
     public static class Builder implements OpenstackVtap.Builder {
-        private static final SparseAnnotations EMPTY = DefaultAnnotations.builder().build();
-
         private OpenstackVtapId id;
-        private Type type;
-        private OpenstackVtapCriterion vTapCriterion;
+        private Type type = Type.VTAP_ALL;
+        private OpenstackVtapCriterion vtapCriterion;
         private Set<DeviceId> txDeviceIds;
         private Set<DeviceId> rxDeviceIds;
-        private SparseAnnotations annotations = EMPTY;
+        private SparseAnnotations annotations = DefaultAnnotations.EMPTY;
 
-        // private constructor not intended to use from external
+        // Private constructor not intended to use from external
         Builder() {
         }
 
+        Builder(OpenstackVtap description) {
+            this.id = description.id();
+            this.type = description.type();
+            this.vtapCriterion = description.vtapCriterion();
+            this.type = description.type();
+            this.txDeviceIds = description.txDeviceIds();
+            this.rxDeviceIds = description.rxDeviceIds();
+            this.annotations  = (SparseAnnotations) description.annotations();
+        }
+
+        /**
+         * Sets mandatory field id.
+         *
+         * @param id to set
+         * @return self
+         */
         @Override
         public Builder id(OpenstackVtapId id) {
             this.id = id;
             return this;
         }
 
+        /**
+         * Sets mandatory field type.
+         *
+         * @param type of the vtap
+         * @return self
+         */
         @Override
         public Builder type(Type type) {
             this.type = type;
             return this;
         }
 
+        /**
+         * Sets mandatory field criterion.
+         *
+         * @param vtapCriterion for the vtap
+         * @return self
+         */
         @Override
-        public Builder vTapCriterion(OpenstackVtapCriterion vTapCriterion) {
-            this.vTapCriterion = vTapCriterion;
+        public Builder vtapCriterion(OpenstackVtapCriterion vtapCriterion) {
+            this.vtapCriterion = vtapCriterion;
             return this;
         }
 
+        /**
+         * Sets a tx deviceId set.
+         *
+         * @param txDeviceIds deviceId set for tx
+         * @return builder
+         */
         @Override
         public Builder txDeviceIds(Set<DeviceId> txDeviceIds) {
-            if (txDeviceIds != null) {
-                this.txDeviceIds = ImmutableSet.copyOf(txDeviceIds);
-            } else {
-                this.txDeviceIds = Sets.newHashSet();
-            }
+            this.txDeviceIds = txDeviceIds;
             return this;
         }
 
+        /**
+         * Sets a rx deviceId set.
+         *
+         * @param rxDeviceIds deviceId set for rx
+         * @return builder
+         */
         @Override
         public Builder rxDeviceIds(Set<DeviceId> rxDeviceIds) {
-            if (rxDeviceIds != null) {
-                this.rxDeviceIds = ImmutableSet.copyOf(rxDeviceIds);
-            } else {
-                this.rxDeviceIds = Sets.newHashSet();
-            }
+            this.rxDeviceIds = rxDeviceIds;
             return this;
         }
 
+        /**
+         * Sets annotations.
+         *
+         * @param annotations of the vtap
+         * @return self
+         */
         @Override
-        public Builder annotations(SparseAnnotations... annotations) {
-            checkArgument(annotations.length <= 1,
-                    "Only one set of annotations is expected");
-            this.annotations = annotations.length == 1 ? annotations[0] : EMPTY;
+        public Builder annotations(SparseAnnotations annotations) {
+            this.annotations = annotations;
             return this;
         }
 
+        /**
+         * Builds a DefaultOpenstackVtap instance.
+         *
+         * @return DefaultOpenstackVtap
+         */
         @Override
         public DefaultOpenstackVtap build() {
-            return new DefaultOpenstackVtap(id, type, vTapCriterion,
-                                            txDeviceIds, rxDeviceIds, annotations);
+            return new DefaultOpenstackVtap(checkNotNull(id),
+                    checkNotNull(type),
+                    checkNotNull(vtapCriterion),
+                    txDeviceIds,
+                    rxDeviceIds,
+                    checkNotNull(annotations));
         }
     }
 
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java
index d53bf25..287f763 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java
@@ -24,16 +24,15 @@
 import static com.google.common.base.Preconditions.checkArgument;
 
 /**
- * Default implementation of an immutable openstack vTap criterion.
+ * Default implementation of an immutable openstack vtap criterion.
  */
 public final class DefaultOpenstackVtapCriterion implements OpenstackVtapCriterion {
+
     private final IpPrefix srcIpPrefix;
     private final IpPrefix dstIpPrefix;
-    private final byte     ipProtocol;
+    private final byte ipProtocol;
     private final TpPort srcTpPort;
-    private final TpPort   dstTpPort;
-
-    private static final String NOT_NULL_MSG = "Element % cannot be null";
+    private final TpPort dstTpPort;
 
     // private constructor not intended to use from external
     private DefaultOpenstackVtapCriterion(IpPrefix srcIpPrefix,
@@ -107,18 +106,20 @@
     }
 
     /**
-     * Creates a new default openstack vTap criterion builder.
+     * Creates a new default openstack vtap criterion builder.
      *
-     * @return default openstack vTap criterion builder
+     * @return default openstack vtap criterion builder
      */
     public static Builder builder() {
         return new Builder();
     }
 
     /**
-     * A builder class for openstack vTap criterion builder.
+     * A builder class for openstack vtap criterion builder.
      */
     public static final class Builder implements OpenstackVtapCriterion.Builder {
+        private static final String NOT_NULL_MSG = "OpenstackVtapCriterion % cannot be null";
+
         private IpPrefix srcIpPrefix;
         private IpPrefix dstIpPrefix;
         private byte     ipProtocol;
@@ -168,4 +169,5 @@
             return this;
         }
     }
+
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapNetwork.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapNetwork.java
new file mode 100644
index 0000000..af086a2
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapNetwork.java
@@ -0,0 +1,203 @@
+/*
+ * 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.openstackvtap.impl;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.AbstractDescription;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default implementation of an immutable OpenstackVtapNetwork.
+ */
+public class DefaultOpenstackVtapNetwork extends AbstractDescription implements OpenstackVtapNetwork {
+
+    private final Mode mode;
+    private final Integer networkId;
+    private final IpAddress serverIp;
+
+    /**
+     * Creates an DefaultOpenstackVtapNetwork using the supplied information.
+     *
+     * @param mode        mode of vtap network
+     * @param networkId   network id of the vtap tunneling network
+     * @param serverIp    server IP address used for tunneling
+     * @param annotations optional key/value annotations
+     */
+    protected DefaultOpenstackVtapNetwork(Mode mode,
+                                          Integer networkId,
+                                          IpAddress serverIp,
+                                          SparseAnnotations... annotations) {
+        super(annotations);
+        this.mode = checkNotNull(mode);
+        this.networkId = networkId;
+        this.serverIp = checkNotNull(serverIp);
+    }
+
+    @Override
+    public Mode mode() {
+        return mode;
+    }
+
+    @Override
+    public Integer networkId() {
+        return networkId;
+    }
+
+    @Override
+    public IpAddress serverIp() {
+        return serverIp;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mode, networkId, serverIp);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultOpenstackVtapNetwork) {
+            final DefaultOpenstackVtapNetwork other = (DefaultOpenstackVtapNetwork) obj;
+            return Objects.equals(this.mode, other.mode) &&
+                    Objects.equals(this.networkId, other.networkId) &&
+                    Objects.equals(this.serverIp, other.serverIp) &&
+                    Objects.equals(this.annotations(), other.annotations());
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("mode", mode())
+                .add("networkId", networkId())
+                .add("serverIp", serverIp())
+                .add("annotations", annotations())
+                .toString();
+    }
+
+    /**
+     * Creates OpenstackVtapNetwork builder with default parameters.
+     *
+     * @return builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Creates OpenstackVtapNetwork builder inheriting with default parameters,
+     * from specified OpenstackVtapNetwork.
+     *
+     * @param vtapNetwork to inherit default from
+     * @return builder
+     */
+    public static Builder builder(OpenstackVtapNetwork vtapNetwork) {
+        return new Builder(vtapNetwork);
+    }
+
+    /**
+     * Builder for DefaultOpenstackVtapNetwork object.
+     */
+    public static class Builder implements OpenstackVtapNetwork.Builder {
+        private Mode mode;
+        private Integer networkId;
+        private IpAddress serverIp;
+        private SparseAnnotations annotations = DefaultAnnotations.EMPTY;
+
+        // private constructor not intended to use from external
+        private Builder() {
+        }
+
+        Builder(OpenstackVtapNetwork description) {
+            this.mode = description.mode();
+            this.networkId = description.networkId();
+            this.serverIp = description.serverIp();
+            this.annotations  = (SparseAnnotations) description.annotations();
+        }
+
+        /**
+         * Sets mandatory field mode.
+         *
+         * @param mode of vtap network
+         * @return self
+         */
+        @Override
+        public Builder mode(Mode mode) {
+            this.mode = mode;
+            return this;
+        }
+
+        /**
+         * Sets mandatory field networkId.
+         *
+         * @param networkId of the vtap tunneling network
+         * @return self
+         */
+        @Override
+        public Builder networkId(Integer networkId) {
+            this.networkId = networkId;
+            return this;
+        }
+
+        /**
+         * Sets mandatory field serverIp.
+         *
+         * @param serverIp address used for tunneling
+         * @return self
+         */
+        @Override
+        public Builder serverIp(IpAddress serverIp) {
+            this.serverIp = serverIp;
+            return this;
+        }
+
+        /**
+         * Sets annotations.
+         *
+         * @param annotations of the vtap network
+         * @return self
+         */
+        @Override
+        public Builder annotations(SparseAnnotations annotations) {
+            this.annotations = annotations;
+            return this;
+        }
+
+        /**
+         * Builds a DefaultOpenstackVtapNetwork instance.
+         *
+         * @return DefaultOpenstackVtapNetwork
+         */
+        @Override
+        public DefaultOpenstackVtapNetwork build() {
+            return new DefaultOpenstackVtapNetwork(checkNotNull(mode),
+                    networkId,
+                    checkNotNull(serverIp),
+                    checkNotNull(annotations));
+        }
+    }
+
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java
index f8897e8..0f955e5 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java
@@ -23,9 +23,10 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.SparseAnnotations;
 import org.onosproject.openstackvtap.api.OpenstackVtap;
-import org.onosproject.openstackvtap.api.OpenstackVtapCriterion;
+import org.onosproject.openstackvtap.api.OpenstackVtap.Type;
 import org.onosproject.openstackvtap.api.OpenstackVtapEvent;
 import org.onosproject.openstackvtap.api.OpenstackVtapId;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
 import org.onosproject.openstackvtap.api.OpenstackVtapStore;
 import org.onosproject.openstackvtap.api.OpenstackVtapStoreDelegate;
 import org.onosproject.store.AbstractStore;
@@ -36,6 +37,7 @@
 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.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
@@ -52,464 +54,569 @@
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.DefaultAnnotations.merge;
+import static org.onosproject.store.service.Versioned.valueOrNull;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Manages the inventory of users using a {@code ConsistentMap}.
+ * Manages the inventory of openstack vtap and openstack vtap network using a {@code ConsistentMap}.
  */
 @Component(immediate = true, service = OpenstackVtapStore.class)
 public class DistributedOpenstackVtapStore
         extends AbstractStore<OpenstackVtapEvent, OpenstackVtapStoreDelegate>
         implements OpenstackVtapStore {
+
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected StorageService storageService;
 
-    private ConsistentMap<OpenstackVtapId, DefaultOpenstackVtap> vTapConsistentMap;
-    private MapEventListener<OpenstackVtapId, DefaultOpenstackVtap>
-                                            vTapListener = new VtapEventListener();
-    private Map<OpenstackVtapId, DefaultOpenstackVtap> vTapMap;
+    private ConsistentMap<OpenstackVtapId, DefaultOpenstackVtap> vtapConsistentMap;
+    private MapEventListener<OpenstackVtapId, DefaultOpenstackVtap> vtapListener =
+            new VtapEventListener();
+    private Map<OpenstackVtapId, DefaultOpenstackVtap> vtapMap;
+
+    private ConsistentMap<Integer, DefaultOpenstackVtapNetwork> vtapNetworkConsistentMap;
+    private MapEventListener<Integer, DefaultOpenstackVtapNetwork> vtapNetworkListener =
+            new VtapNetworkEventListener();
+    private Map<Integer, DefaultOpenstackVtapNetwork> vtapNetworkMap;
+
+    private ConsistentMap<Integer, Set<DeviceId>> vtapNetworkDevicesConsistentMap;
 
     private static final Serializer SERIALIZER = Serializer
             .using(new KryoNamespace.Builder().register(KryoNamespaces.API)
                     .register(OpenstackVtapId.class)
                     .register(UUID.class)
                     .register(DefaultOpenstackVtap.class)
-                    .register(OpenstackVtap.Type.class)
+                    .register(Type.class)
                     .register(DefaultOpenstackVtapCriterion.class)
+                    .register(DefaultOpenstackVtapNetwork.class)
+                    .register(OpenstackVtapNetwork.Mode.class)
                     .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
                     .build());
 
     private Map<DeviceId, Set<OpenstackVtapId>>
-                                    vTapIdsByTxDeviceId = Maps.newConcurrentMap();
+                                    vtapIdsByTxDeviceId = Maps.newConcurrentMap();
     private Map<DeviceId, Set<OpenstackVtapId>>
-                                    vTapIdsByRxDeviceId = Maps.newConcurrentMap();
+                                    vtapIdsByRxDeviceId = Maps.newConcurrentMap();
 
     private ScheduledExecutorService eventExecutor;
+    private Consumer<Status> vtapStatusListener;
 
-    private Consumer<Status> vTapStatusListener;
-
-    public static final String INVALID_DESCRIPTION = "Invalid create/update parameter";
+    private static final String ERR_NOT_FOUND = "ID {} does not exist";
+    private static final String ERR_DUPLICATE = "ID {} already exists";
 
     @Activate
     public void activate() {
         eventExecutor = newSingleThreadScheduledExecutor(
                 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
 
-        vTapConsistentMap = storageService.<OpenstackVtapId, DefaultOpenstackVtap>
+        // vtap network data
+        vtapNetworkConsistentMap = storageService.<Integer, DefaultOpenstackVtapNetwork>
                 consistentMapBuilder()
-                .withName("vTapMap")
+                .withName("vtapNetworkMap")
+                .withSerializer(SERIALIZER)
+                .build();
+        vtapNetworkMap = vtapNetworkConsistentMap.asJavaMap();
+        vtapNetworkConsistentMap.addListener(vtapNetworkListener);
+
+        // vtap network devices data
+        vtapNetworkDevicesConsistentMap = storageService.<Integer, Set<DeviceId>>
+                consistentMapBuilder()
+                .withName("vtapNetworkDevicesMap")
                 .withSerializer(SERIALIZER)
                 .build();
 
-        vTapMap = vTapConsistentMap.asJavaMap();
-        vTapConsistentMap.addListener(vTapListener);
+        // vtap data
+        vtapConsistentMap = storageService.<OpenstackVtapId, DefaultOpenstackVtap>
+                consistentMapBuilder()
+                .withName("vtapMap")
+                .withSerializer(SERIALIZER)
+                .build();
+        vtapMap = vtapConsistentMap.asJavaMap();
+        vtapConsistentMap.addListener(vtapListener);
 
-        vTapStatusListener = status -> {
+        // initialize vtap data
+        vtapStatusListener = status -> {
             if (status == Status.ACTIVE) {
                 eventExecutor.execute(this::loadVtapIds);
             }
         };
-        vTapConsistentMap.addStatusChangeListener(vTapStatusListener);
+        vtapConsistentMap.addStatusChangeListener(vtapStatusListener);
 
-        log.info("Started {} - {}", this.getClass().getSimpleName());
+        log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
-        vTapConsistentMap.removeStatusChangeListener(vTapStatusListener);
-        vTapConsistentMap.removeListener(vTapListener);
+        vtapConsistentMap.removeStatusChangeListener(vtapStatusListener);
+        vtapConsistentMap.removeListener(vtapListener);
+        vtapNetworkConsistentMap.removeListener(vtapNetworkListener);
+
         eventExecutor.shutdown();
 
-        log.info("Stopped {} - {}", this.getClass().getSimpleName());
+        log.info("Stopped");
     }
 
-    @Override
-    public OpenstackVtap createOrUpdateVtap(OpenstackVtapId vTapId,
-                                            OpenstackVtap description,
-                                            boolean replaceFlag) {
-
-        return vTapMap.compute(vTapId, (id, existing) -> {
-            if (existing == null &&
-                    (description.type() == null ||
-                     description.vTapCriterion() == null ||
-                     description.txDeviceIds() == null ||
-                     description.rxDeviceIds() == null)) {
-                checkState(false, INVALID_DESCRIPTION);
-                return null;
-            }
-
-            if (shouldUpdate(existing, description, replaceFlag)) {
-                // Replace items
-                OpenstackVtap.Type type =
-                        (description.type() == null ? existing.type() : description.type());
-                OpenstackVtapCriterion vTapCriterion =
-                        (description.vTapCriterion() == null ?
-                        existing.vTapCriterion() : description.vTapCriterion());
-
-                // Replace or add devices
-                Set<DeviceId> txDeviceIds;
-                if (description.txDeviceIds() == null) {
-                    txDeviceIds = existing.txDeviceIds();
-                } else {
-                    if (existing == null || replaceFlag) {
-                        txDeviceIds = ImmutableSet.copyOf(description.txDeviceIds());
-                    } else {
-                        txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
-                        txDeviceIds.addAll(description.txDeviceIds());
-                    }
-                }
-
-                Set<DeviceId> rxDeviceIds;
-                if (description.rxDeviceIds() == null) {
-                    rxDeviceIds = existing.rxDeviceIds();
-                } else {
-                    if (existing == null || replaceFlag) {
-                        rxDeviceIds = ImmutableSet.copyOf(description.rxDeviceIds());
-                    } else {
-                        rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
-                        rxDeviceIds.addAll(description.rxDeviceIds());
-                    }
-                }
-
-                // Replace or add annotations
-                SparseAnnotations annotations;
-                if (existing != null) {
-                    annotations = merge((DefaultAnnotations) existing.annotations(),
-                            (SparseAnnotations) description.annotations());
-                } else {
-                    annotations = (SparseAnnotations) description.annotations();
-                }
-
-                // Make new changed vTap and return
-                return DefaultOpenstackVtap.builder()
-                        .id(vTapId)
-                        .type(type)
-                        .vTapCriterion(vTapCriterion)
-                        .txDeviceIds(txDeviceIds)
-                        .rxDeviceIds(rxDeviceIds)
-                        .annotations(annotations)
-                        .build();
-            }
-            return existing;
-        });
-    }
-
-    @Override
-    public OpenstackVtap removeVtapById(OpenstackVtapId vTapId) {
-        return vTapMap.remove(vTapId);
-    }
-
-    @Override
-    public boolean addDeviceToVtap(OpenstackVtapId vTapId,
-                                   OpenstackVtap.Type type,
-                                   DeviceId deviceId) {
-        checkNotNull(vTapId);
-        checkNotNull(deviceId);
-
-        OpenstackVtap vTap = vTapMap.compute(vTapId, (id, existing) -> {
-            if (existing == null) {
-                return null;
-            }
-            if (!existing.type().isValid(type)) {
-                log.error("Not valid OpenstackVtap type {} for requested type {}",
-                        existing.type(), type);
-                return existing;
-            }
-
-            Set<DeviceId> txDeviceIds = null;
-            if (type.isValid(OpenstackVtap.Type.VTAP_TX) &&
-                    !existing.txDeviceIds().contains(deviceId)) {
-                txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
-                txDeviceIds.add(deviceId);
-            }
-
-            Set<DeviceId> rxDeviceIds = null;
-            if (type.isValid(OpenstackVtap.Type.VTAP_RX) &&
-                    !existing.rxDeviceIds().contains(deviceId)) {
-                rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
-                rxDeviceIds.add(deviceId);
-            }
-
-            if (txDeviceIds != null || rxDeviceIds != null) {
-                //updateVTapIdFromDeviceId(existing.id(), deviceId);    // execute from event listener
-
-                return DefaultOpenstackVtap.builder()
-                        .id(vTapId)
-                        .type(existing.type())
-                        .vTapCriterion(existing.vTapCriterion())
-                        .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
-                        .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
-                        .annotations(existing.annotations())
-                        .build();
-            }
-            return existing;
-        });
-        return (vTap != null);
-    }
-
-    @Override
-    public boolean removeDeviceFromVtap(OpenstackVtapId vTapId,
-                                        OpenstackVtap.Type type,
-                                        DeviceId deviceId) {
-        checkNotNull(vTapId);
-        checkNotNull(deviceId);
-
-        OpenstackVtap vTap = vTapMap.compute(vTapId, (id, existing) -> {
-            if (existing == null) {
-                return null;
-            }
-            if (!existing.type().isValid(type)) {
-                log.error("Not valid OpenstackVtap type {} for requested type {}",
-                        existing.type(), type);
-                return existing;
-            }
-
-            Set<DeviceId> txDeviceIds = null;
-            if (type.isValid(OpenstackVtap.Type.VTAP_TX) &&
-                    existing.txDeviceIds().contains(deviceId)) {
-                txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
-                txDeviceIds.remove(deviceId);
-            }
-
-            Set<DeviceId> rxDeviceIds = null;
-            if (type.isValid(OpenstackVtap.Type.VTAP_RX) &&
-                    existing.rxDeviceIds().contains(deviceId)) {
-                rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
-                rxDeviceIds.remove(deviceId);
-            }
-
-            if (txDeviceIds != null || rxDeviceIds != null) {
-                //removeVTapIdFromDeviceId(existing.id(), deviceId);    // execute from event listener
-
-                return DefaultOpenstackVtap.builder()
-                        .id(vTapId)
-                        .type(existing.type())
-                        .vTapCriterion(existing.vTapCriterion())
-                        .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
-                        .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
-                        .annotations(existing.annotations())
-                        .build();
-            }
-            return existing;
-        });
-        return (vTap != null);
-    }
-
-    @Override
-    public boolean updateDeviceForVtap(OpenstackVtapId vTapId,
-                                       Set<DeviceId> txDeviceIds, Set<DeviceId> rxDeviceIds,
-                                       boolean replaceDevices) {
-        checkNotNull(vTapId);
-        checkNotNull(txDeviceIds);
-        checkNotNull(rxDeviceIds);
-
-        OpenstackVtap vTap = vTapMap.compute(vTapId, (id, existing) -> {
-            if (existing == null) {
-                return null;
-            }
-
-            // Replace or add devices
-            Set<DeviceId> txDS = null;
-            if (replaceDevices) {
-                if (!existing.txDeviceIds().equals(txDeviceIds)) {
-                    txDS = ImmutableSet.copyOf(txDeviceIds);
-                }
-            } else {
-                if (!existing.txDeviceIds().containsAll(txDeviceIds)) {
-                    txDS = Sets.newHashSet(existing.txDeviceIds());
-                    txDS.addAll(txDeviceIds);
-                }
-            }
-
-            Set<DeviceId> rxDS = null;
-            if (replaceDevices) {
-                if (!existing.rxDeviceIds().equals(rxDeviceIds)) {
-                    rxDS = ImmutableSet.copyOf(rxDeviceIds);
-                }
-            } else {
-                if (!existing.rxDeviceIds().containsAll(rxDeviceIds)) {
-                    rxDS = Sets.newHashSet(existing.rxDeviceIds());
-                    rxDS.addAll(rxDeviceIds);
-                }
-            }
-
-            if (txDS != null || rxDS != null) {
-
-                return DefaultOpenstackVtap.builder()
-                        .id(vTapId)
-                        .type(existing.type())
-                        .vTapCriterion(existing.vTapCriterion())
-                        .txDeviceIds(txDS != null ? txDS : existing.txDeviceIds())
-                        .rxDeviceIds(rxDS != null ? rxDS : existing.rxDeviceIds())
-                        .annotations(existing.annotations())
-                        .build();
-            }
-            return existing;
-        });
-        return (vTap != null);
-    }
-
-    @Override
-    public int getVtapCount(OpenstackVtap.Type type) {
-        return (int) vTapMap.values().parallelStream()
-                .filter(vTap -> vTap.type().isValid(type))
-                .count();
-    }
-
-    @Override
-    public Set<OpenstackVtap> getVtaps(OpenstackVtap.Type type) {
-        return ImmutableSet.copyOf(
-                vTapMap.values().parallelStream()
-                        .filter(vTap -> vTap.type().isValid(type))
-                        .collect(Collectors.toSet()));
-    }
-
-    @Override
-    public OpenstackVtap getVtap(OpenstackVtapId vTapId) {
-        return vTapMap.get(vTapId);
-    }
-
-    @Override
-    public Set<OpenstackVtap> getVtapsByDeviceId(OpenstackVtap.Type type,
-                                                 DeviceId deviceId) {
-        Set<OpenstackVtapId> vtapIds = Sets.newHashSet();
-        if (type.isValid(OpenstackVtap.Type.VTAP_TX)) {
-            if (vTapIdsByTxDeviceId.get(deviceId) != null) {
-                vtapIds.addAll(vTapIdsByTxDeviceId.get(deviceId));
-            }
-        }
-        if (type.isValid(OpenstackVtap.Type.VTAP_RX)) {
-            if (vTapIdsByRxDeviceId.get(deviceId) != null) {
-                vtapIds.addAll(vTapIdsByRxDeviceId.get(deviceId));
-            }
-        }
-
-        return ImmutableSet.copyOf(
-                vtapIds.parallelStream()
-                        .map(vTapId -> vTapMap.get(vTapId))
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toSet()));
-    }
-
-    private void loadVtapIds() {
-        vTapIdsByTxDeviceId.clear();
-        vTapIdsByRxDeviceId.clear();
-        vTapMap.values().forEach(vTap -> refreshDeviceIdsByVtap(null, vTap));
-    }
-
-    private boolean shouldUpdate(DefaultOpenstackVtap existing,
-                                 OpenstackVtap description,
-                                 boolean replaceDevices) {
+    private boolean shouldUpdateVtapNetwork(DefaultOpenstackVtapNetwork existing,
+                                            OpenstackVtapNetwork description) {
         if (existing == null) {
             return true;
         }
 
-        if ((description.type() != null && !description.type().equals(existing.type()))
-                || (description.vTapCriterion() != null &&
-                !description.vTapCriterion().equals(existing.vTapCriterion()))) {
+        if (!Objects.equals(existing.mode(), description.mode()) ||
+                !Objects.equals(existing.networkId(), description.networkId()) ||
+                !Objects.equals(existing.serverIp(), description.serverIp())) {
             return true;
         }
 
-        if (description.txDeviceIds() != null) {
-            if (replaceDevices) {
-                if (!existing.txDeviceIds().equals(description.txDeviceIds())) {
-                    return true;
-                }
-            } else {
-                if (!existing.txDeviceIds().containsAll(description.txDeviceIds())) {
-                    return true;
-                }
-            }
-        }
-
-        if (description.rxDeviceIds() != null) {
-            if (replaceDevices) {
-                if (!existing.rxDeviceIds().equals(description.rxDeviceIds())) {
-                    return true;
-                }
-            } else {
-                if (!existing.rxDeviceIds().containsAll(description.rxDeviceIds())) {
-                    return true;
-                }
-            }
-        }
-
-        // check to see if any of the annotations provided by vTap
-        // differ from those in the existing vTap
+        // check to see if any of the annotations provided by description
+        // differ from those in the existing vtap network
         return description.annotations().keys().stream()
                 .anyMatch(k -> !Objects.equals(description.annotations().value(k),
                         existing.annotations().value(k)));
     }
 
+    private OpenstackVtapNetwork createOrUpdateVtapNetwork(boolean update,
+                                                           Integer key,
+                                                           OpenstackVtapNetwork description) {
+        DefaultOpenstackVtapNetwork result =
+                vtapNetworkMap.compute(key, (id, existing) -> {
+                    // Check create or update validity
+                    if (update && existing == null) {
+                        return null;
+                    } else if (!update && existing != null) {
+                        return existing;
+                    }
+
+                    if (shouldUpdateVtapNetwork(existing, description)) {
+                        // Replace or add annotations
+                        final SparseAnnotations annotations;
+                        if (existing != null) {
+                            annotations = merge((DefaultAnnotations) existing.annotations(),
+                                    (SparseAnnotations) description.annotations());
+                        } else {
+                            annotations = (SparseAnnotations) description.annotations();
+                        }
+
+                        return DefaultOpenstackVtapNetwork.builder(description)
+                                .annotations(annotations)
+                                .build();
+                    }
+                    return existing;
+                });
+        return result;
+    }
+
+    @Override
+    public OpenstackVtapNetwork createVtapNetwork(Integer key, OpenstackVtapNetwork description) {
+        if (getVtapNetwork(key) == null) {
+            OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(false, key, description);
+            if (Objects.equals(vtapNetwork, description)) {
+                return vtapNetwork;
+            }
+        }
+        log.error(ERR_DUPLICATE, key);
+        return null;
+    }
+
+    @Override
+    public OpenstackVtapNetwork updateVtapNetwork(Integer key, OpenstackVtapNetwork description) {
+        OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(true, key, description);
+        if (vtapNetwork == null) {
+            log.error(ERR_NOT_FOUND, key);
+        }
+        return vtapNetwork;
+    }
+
+    @Override
+    public OpenstackVtapNetwork removeVtapNetwork(Integer key) {
+        return vtapNetworkMap.remove(key);
+    }
+
+    @Override
+    public void clearVtapNetworks() {
+        vtapNetworkMap.clear();
+    }
+
+    @Override
+    public int getVtapNetworkCount() {
+        return vtapNetworkMap.size();
+    }
+
+    @Override
+    public OpenstackVtapNetwork getVtapNetwork(Integer key) {
+        return vtapNetworkMap.get(key);
+    }
+
+    @Override
+    public boolean addDeviceToVtapNetwork(Integer key, DeviceId deviceId) {
+        Versioned<Set<DeviceId>> result =
+                vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
+                    // Add deviceId to deviceIds
+                    if (existing == null) {
+                        return Sets.newHashSet(deviceId);
+                    } else if (!existing.contains(deviceId)) {
+                        Set<DeviceId> deviceIds = Sets.newHashSet(existing);
+                        deviceIds.add(deviceId);
+                        return deviceIds;
+                    } else {
+                        return existing;
+                    }
+                });
+        return Objects.nonNull(valueOrNull(result));
+    }
+
+    @Override
+    public boolean removeDeviceFromVtapNetwork(Integer key, DeviceId deviceId) {
+        Versioned<Set<DeviceId>> result =
+                vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
+                    // Remove deviceId from deviceIds
+                    if (existing != null && existing.contains(deviceId)) {
+                        Set<DeviceId> deviceIds = Sets.newHashSet(existing);
+                        deviceIds.remove(deviceId);
+                        return deviceIds;
+                    } else {
+                        return existing;
+                    }
+                });
+        return Objects.nonNull(valueOrNull(result));
+    }
+
+    @Override
+    public Set<DeviceId> getVtapNetworkDevices(Integer key) {
+        return valueOrNull(vtapNetworkDevicesConsistentMap.get(key));
+    }
+
+    private boolean shouldUpdateVtap(DefaultOpenstackVtap existing,
+                                     OpenstackVtap description,
+                                     boolean replaceDevices) {
+        if (existing == null) {
+            return true;
+        }
+
+        if (!Objects.equals(existing.type(), description.type()) ||
+                !Objects.equals(existing.vtapCriterion(), description.vtapCriterion())) {
+            return true;
+        }
+
+        if (replaceDevices) {
+            if (!Objects.equals(description.txDeviceIds(), existing.txDeviceIds()) ||
+                    !Objects.equals(description.rxDeviceIds(), existing.rxDeviceIds())) {
+                return true;
+            }
+        } else {
+            if (!existing.txDeviceIds().containsAll(description.txDeviceIds()) ||
+                    !existing.rxDeviceIds().containsAll(description.rxDeviceIds())) {
+                return true;
+            }
+        }
+
+        // check to see if any of the annotations provided by description
+        // differ from those in the existing vtap
+        return description.annotations().keys().stream()
+                .anyMatch(k -> !Objects.equals(description.annotations().value(k),
+                        existing.annotations().value(k)));
+    }
+
+    private OpenstackVtap createOrUpdateVtap(boolean update,
+                                             OpenstackVtap description,
+                                             boolean replaceDevices) {
+        DefaultOpenstackVtap result =
+                vtapMap.compute(description.id(), (id, existing) -> {
+                    // Check create or update validity
+                    if (update && existing == null) {
+                        return null;
+                    } else if (!update && existing != null) {
+                        return existing;
+                    }
+
+                    if (shouldUpdateVtap(existing, description, replaceDevices)) {
+                        // Replace or add devices
+                        final Set<DeviceId> txDeviceIds;
+                        if (existing == null || replaceDevices) {
+                            txDeviceIds = description.txDeviceIds();
+                        } else {
+                            txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
+                            txDeviceIds.addAll(description.txDeviceIds());
+                        }
+
+                        final Set<DeviceId> rxDeviceIds;
+                        if (existing == null || replaceDevices) {
+                            rxDeviceIds = description.rxDeviceIds();
+                        } else {
+                            rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
+                            rxDeviceIds.addAll(description.rxDeviceIds());
+                        }
+
+                        // Replace or add annotations
+                        final SparseAnnotations annotations;
+                        if (existing != null) {
+                            annotations = merge((DefaultAnnotations) existing.annotations(),
+                                    (SparseAnnotations) description.annotations());
+                        } else {
+                            annotations = (SparseAnnotations) description.annotations();
+                        }
+
+                        return DefaultOpenstackVtap.builder(description)
+                                .txDeviceIds(txDeviceIds)
+                                .rxDeviceIds(rxDeviceIds)
+                                .annotations(annotations)
+                                .build();
+                    }
+                    return existing;
+                });
+        return result;
+    }
+
+    @Override
+    public OpenstackVtap createVtap(OpenstackVtap description) {
+        if (getVtap(description.id()) == null) {
+            OpenstackVtap vtap = createOrUpdateVtap(false, description, true);
+            if (Objects.equals(vtap, description)) {
+                return vtap;
+            }
+        }
+        log.error(ERR_DUPLICATE, description.id());
+        return null;
+    }
+
+    @Override
+    public OpenstackVtap updateVtap(OpenstackVtap description, boolean replaceDevices) {
+        OpenstackVtap vtap = createOrUpdateVtap(true, description, replaceDevices);
+        if (vtap == null) {
+            log.error(ERR_NOT_FOUND, description.id());
+        }
+        return vtap;
+    }
+
+    @Override
+    public OpenstackVtap removeVtap(OpenstackVtapId vtapId) {
+        return vtapMap.remove(vtapId);
+    }
+
+    @Override
+    public void clearVtaps() {
+        vtapMap.clear();
+    }
+
+    @Override
+    public int getVtapCount(Type type) {
+        return (int) vtapMap.values().parallelStream()
+                .filter(vtap -> vtap.type().isValid(type))
+                .count();
+    }
+
+    @Override
+    public Set<OpenstackVtap> getVtaps(Type type) {
+        return ImmutableSet.copyOf(
+                vtapMap.values().parallelStream()
+                        .filter(vtap -> vtap.type().isValid(type))
+                        .collect(Collectors.toSet()));
+    }
+
+    @Override
+    public OpenstackVtap getVtap(OpenstackVtapId vtapId) {
+        return vtapMap.get(vtapId);
+    }
+
+    @Override
+    public boolean addDeviceToVtap(OpenstackVtapId vtapId, Type type, DeviceId deviceId) {
+        OpenstackVtap result =
+                vtapMap.compute(vtapId, (id, existing) -> {
+                    if (existing == null) {
+                        return null;
+                    }
+
+                    // Check type validate
+                    if (!existing.type().isValid(type)) {
+                        log.error("Not valid OpenstackVtap type {} for requested type {}", existing.type(), type);
+                        return existing;
+                    }
+
+                    // Add deviceId to txDeviceIds
+                    final Set<DeviceId> txDeviceIds;
+                    if (existing.type().isValid(Type.VTAP_TX) &&
+                            (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
+                            !existing.txDeviceIds().contains(deviceId)) {
+                        txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
+                        txDeviceIds.add(deviceId);
+                    } else {
+                        txDeviceIds = null;
+                    }
+
+                    // Add deviceId to rxDeviceIds
+                    final Set<DeviceId> rxDeviceIds;
+                    if (existing.type().isValid(Type.VTAP_RX) &&
+                            (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
+                            !existing.rxDeviceIds().contains(deviceId)) {
+                        rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
+                        rxDeviceIds.add(deviceId);
+                    } else {
+                        rxDeviceIds = null;
+                    }
+
+                    if (txDeviceIds != null || rxDeviceIds != null) {
+                        return DefaultOpenstackVtap.builder()
+                                .id(id)
+                                .type(existing.type())
+                                .vtapCriterion(existing.vtapCriterion())
+                                .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
+                                .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
+                                .annotations(existing.annotations())
+                                .build();
+                    } else {
+                        return existing;
+                    }
+                });
+        return Objects.nonNull(result);
+    }
+
+    @Override
+    public boolean removeDeviceFromVtap(OpenstackVtapId vtapId, OpenstackVtap.Type type, DeviceId deviceId) {
+        OpenstackVtap result =
+                vtapMap.compute(vtapId, (id, existing) -> {
+                    if (existing == null) {
+                        return null;
+                    }
+
+                    // Check type validate
+                    if (!existing.type().isValid(type)) {
+                        log.error("Not valid OpenstackVtap type {} for requested type {}",
+                                existing.type(), type);
+                        return existing;
+                    }
+
+                    // Remove deviceId from txDeviceIds
+                    final Set<DeviceId> txDeviceIds;
+                    if (existing.type().isValid(Type.VTAP_TX) &&
+                            (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
+                            existing.txDeviceIds().contains(deviceId)) {
+                        txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
+                        txDeviceIds.remove(deviceId);
+                    } else {
+                        txDeviceIds = null;
+                    }
+
+                    // Remove deviceId from rxDeviceIds
+                    final Set<DeviceId> rxDeviceIds;
+                    if (existing.type().isValid(Type.VTAP_RX) &&
+                            (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
+                            existing.rxDeviceIds().contains(deviceId)) {
+                        rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
+                        rxDeviceIds.remove(deviceId);
+                    } else {
+                        rxDeviceIds = null;
+                    }
+
+                    if (txDeviceIds != null || rxDeviceIds != null) {
+                        return DefaultOpenstackVtap.builder()
+                                .id(id)
+                                .type(existing.type())
+                                .vtapCriterion(existing.vtapCriterion())
+                                .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
+                                .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
+                                .annotations(existing.annotations())
+                                .build();
+                    } else {
+                        return existing;
+                    }
+                });
+        return Objects.nonNull(result);
+    }
+
+    @Override
+    public Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId) {
+        Set<OpenstackVtapId> vtapIds = Sets.newHashSet();
+        Set<OpenstackVtapId> txIds = vtapIdsByTxDeviceId.get(deviceId);
+        if (txIds != null) {
+            vtapIds.addAll(txIds);
+        }
+        Set<OpenstackVtapId> rxIds = vtapIdsByRxDeviceId.get(deviceId);
+        if (rxIds != null) {
+            vtapIds.addAll(rxIds);
+        }
+        return ImmutableSet.copyOf(
+                vtapIds.parallelStream()
+                        .map(vtapId -> vtapMap.get(vtapId))
+                        .filter(Objects::nonNull)
+                        .collect(Collectors.toSet()));
+    }
+
     private class VtapComparator implements Comparator<OpenstackVtap> {
         @Override
         public int compare(OpenstackVtap v1, OpenstackVtap v2) {
             int diff = (v2.type().compareTo(v1.type()));
             if (diff == 0) {
-                return (v2.vTapCriterion().ipProtocol() - v1.vTapCriterion().ipProtocol());
+                return (v2.vtapCriterion().ipProtocol() - v1.vtapCriterion().ipProtocol());
             }
             return diff;
         }
     }
 
-    private static Set<OpenstackVtapId> addVTapIds(OpenstackVtapId vTapId) {
+    private void loadVtapIds() {
+        vtapIdsByTxDeviceId.clear();
+        vtapIdsByRxDeviceId.clear();
+        vtapMap.values().forEach(vtap -> refreshDeviceIdsByVtap(null, vtap));
+    }
+
+    private static Set<OpenstackVtapId> addVTapIds(OpenstackVtapId vtapId) {
         Set<OpenstackVtapId> vtapIds = Sets.newConcurrentHashSet();
-        vtapIds.add(vTapId);
+        vtapIds.add(vtapId);
         return vtapIds;
     }
 
     private static Set<OpenstackVtapId> updateVTapIds(Set<OpenstackVtapId> existingVtapIds,
-                                                      OpenstackVtapId vTapId) {
-        existingVtapIds.add(vTapId);
+                                                      OpenstackVtapId vtapId) {
+        existingVtapIds.add(vtapId);
         return existingVtapIds;
     }
 
     private static Set<OpenstackVtapId> removeVTapIds(Set<OpenstackVtapId> existingVtapIds,
-                                                      OpenstackVtapId vTapId) {
-        existingVtapIds.remove(vTapId);
+                                                      OpenstackVtapId vtapId) {
+        existingVtapIds.remove(vtapId);
         if (existingVtapIds.isEmpty()) {
             return null;
         }
         return existingVtapIds;
     }
 
-    private void updateVTapIdFromTxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
-        vTapIdsByTxDeviceId.compute(deviceId, (k, v) -> v == null ?
-                addVTapIds(vTapId) : updateVTapIds(v, vTapId));
+    private void updateVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+        vtapIdsByTxDeviceId.compute(deviceId, (k, v) -> v == null ?
+                addVTapIds(vtapId) : updateVTapIds(v, vtapId));
     }
 
-    private void removeVTapIdFromTxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
-        vTapIdsByTxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vTapId));
+    private void removeVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+        vtapIdsByTxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
     }
 
-    private void updateVTapIdFromRxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
-        vTapIdsByRxDeviceId.compute(deviceId, (k, v) -> v == null ?
-                addVTapIds(vTapId) : updateVTapIds(v, vTapId));
+    private void updateVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+        vtapIdsByRxDeviceId.compute(deviceId, (k, v) -> v == null ?
+                addVTapIds(vtapId) : updateVTapIds(v, vtapId));
     }
 
-    private void removeVTapIdFromRxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
-        vTapIdsByRxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vTapId));
+    private void removeVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+        vtapIdsByRxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
     }
 
-    private void refreshDeviceIdsByVtap(OpenstackVtap oldOpenstackVtap,
-                                        OpenstackVtap newOpenstackVtap) {
+    private void refreshDeviceIdsByVtap(OpenstackVtap newOpenstackVtap,
+                                        OpenstackVtap oldOpenstackVtap) {
+        if (Objects.equals(newOpenstackVtap, oldOpenstackVtap)) {
+            return;
+        }
+
         if (oldOpenstackVtap != null) {
             Set<DeviceId> removeDeviceIds;
 
-            // Remove TX vTap
+            // Remove TX vtap
             removeDeviceIds = (newOpenstackVtap != null) ?
                     Sets.difference(oldOpenstackVtap.txDeviceIds(),
                             newOpenstackVtap.txDeviceIds()) : oldOpenstackVtap.txDeviceIds();
             removeDeviceIds.forEach(id -> removeVTapIdFromTxDeviceId(oldOpenstackVtap.id(), id));
 
-            // Remove RX vTap
+            // Remove RX vtap
             removeDeviceIds = (newOpenstackVtap != null) ?
                     Sets.difference(oldOpenstackVtap.rxDeviceIds(),
                             newOpenstackVtap.rxDeviceIds()) : oldOpenstackVtap.rxDeviceIds();
@@ -519,13 +626,13 @@
         if (newOpenstackVtap != null) {
             Set<DeviceId> addDeviceIds;
 
-            // Add TX vTap
+            // Add TX vtap
             addDeviceIds = (oldOpenstackVtap != null) ?
                     Sets.difference(newOpenstackVtap.txDeviceIds(),
                             oldOpenstackVtap.txDeviceIds()) : newOpenstackVtap.txDeviceIds();
             addDeviceIds.forEach(id -> updateVTapIdFromTxDeviceId(newOpenstackVtap.id(), id));
 
-            // Add RX vTap
+            // Add RX vtap
             addDeviceIds = (oldOpenstackVtap != null) ?
                     Sets.difference(newOpenstackVtap.rxDeviceIds(),
                             oldOpenstackVtap.rxDeviceIds()) : newOpenstackVtap.rxDeviceIds();
@@ -542,26 +649,24 @@
             DefaultOpenstackVtap oldValue =
                     event.oldValue() != null ? event.oldValue().value() : null;
 
-            log.debug("VtapEventListener {} -> {}, {}", event.type(), oldValue, newValue);
+            log.trace("VtapEventListener {}: {} -> {}", event.type(), oldValue, newValue);
             switch (event.type()) {
                 case INSERT:
-                    refreshDeviceIdsByVtap(oldValue, newValue);
+                    refreshDeviceIdsByVtap(newValue, oldValue);
                     notifyDelegate(new OpenstackVtapEvent(
-                            OpenstackVtapEvent.Type.VTAP_ADDED, newValue));
+                            OpenstackVtapEvent.Type.VTAP_ADDED, newValue, null));
                     break;
 
                 case UPDATE:
-                    if (!Objects.equals(newValue, oldValue)) {
-                        refreshDeviceIdsByVtap(oldValue, newValue);
-                        notifyDelegate(new OpenstackVtapEvent(
-                                OpenstackVtapEvent.Type.VTAP_UPDATED, newValue, oldValue));
-                    }
+                    refreshDeviceIdsByVtap(newValue, oldValue);
+                    notifyDelegate(new OpenstackVtapEvent(
+                            OpenstackVtapEvent.Type.VTAP_UPDATED, newValue, oldValue));
                     break;
 
                 case REMOVE:
-                    refreshDeviceIdsByVtap(oldValue, newValue);
+                    refreshDeviceIdsByVtap(newValue, oldValue);
                     notifyDelegate(new OpenstackVtapEvent(
-                            OpenstackVtapEvent.Type.VTAP_REMOVED, oldValue));
+                            OpenstackVtapEvent.Type.VTAP_REMOVED, null, oldValue));
                     break;
 
                 default:
@@ -569,4 +674,37 @@
             }
         }
     }
+
+    private class VtapNetworkEventListener
+            implements MapEventListener<Integer, DefaultOpenstackVtapNetwork> {
+        @Override
+        public void event(MapEvent<Integer, DefaultOpenstackVtapNetwork> event) {
+            DefaultOpenstackVtapNetwork newValue =
+                    event.newValue() != null ? event.newValue().value() : null;
+            DefaultOpenstackVtapNetwork oldValue =
+                    event.oldValue() != null ? event.oldValue().value() : null;
+
+            log.trace("VtapNetworkEventListener {}: {} -> {}", event.type(), oldValue, newValue);
+            switch (event.type()) {
+                case INSERT:
+                    notifyDelegate(new OpenstackVtapEvent(
+                            OpenstackVtapEvent.Type.VTAP_NETWORK_ADDED, newValue, null));
+                    break;
+
+                case UPDATE:
+                    notifyDelegate(new OpenstackVtapEvent(
+                            OpenstackVtapEvent.Type.VTAP_NETWORK_UPDATED, newValue, oldValue));
+                    break;
+
+                case REMOVE:
+                    notifyDelegate(new OpenstackVtapEvent(
+                            OpenstackVtapEvent.Type.VTAP_NETWORK_REMOVED, null, oldValue));
+                    break;
+
+                default:
+                    log.warn("Unknown map event type: {}", event.type());
+            }
+        }
+    }
+
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java
index 426e4cb..d9a2ae3 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java
@@ -21,7 +21,8 @@
 import com.google.common.collect.Sets;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
-import org.onlab.packet.VlanId;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.LeadershipService;
 import org.onosproject.cluster.NodeId;
@@ -29,21 +30,21 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.core.GroupId;
 import org.onosproject.event.AbstractListenerManager;
-import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.HostLocation;
+import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.DefaultTunnelDescription;
 import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
+import org.onosproject.net.behaviour.InterfaceConfig;
+import org.onosproject.net.behaviour.TunnelDescription;
+import org.onosproject.net.behaviour.TunnelEndPoints;
+import org.onosproject.net.behaviour.TunnelKey;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DefaultDriverData;
-import org.onosproject.net.driver.DefaultDriverHandler;
-import org.onosproject.net.driver.Driver;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -53,6 +54,7 @@
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficSelector;
 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.DefaultGroupBucket;
 import org.onosproject.net.group.DefaultGroupDescription;
@@ -63,6 +65,7 @@
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.HostListener;
 import org.onosproject.net.host.HostService;
+import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
@@ -73,6 +76,8 @@
 import org.onosproject.openstackvtap.api.OpenstackVtapEvent;
 import org.onosproject.openstackvtap.api.OpenstackVtapId;
 import org.onosproject.openstackvtap.api.OpenstackVtapListener;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork.Mode;
 import org.onosproject.openstackvtap.api.OpenstackVtapService;
 import org.onosproject.openstackvtap.api.OpenstackVtapStore;
 import org.onosproject.openstackvtap.api.OpenstackVtapStoreDelegate;
@@ -80,15 +85,16 @@
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.slf4j.Logger;
 
+import java.util.Dictionary;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ScheduledExecutorService;
-import java.util.function.BiFunction;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
@@ -98,9 +104,10 @@
 import static org.onlab.packet.IPv4.PROTOCOL_ICMP;
 import static org.onlab.packet.IPv4.PROTOCOL_TCP;
 import static org.onlab.packet.IPv4.PROTOCOL_UDP;
-import static org.onlab.packet.VlanId.UNTAGGED;
 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_RESUBMIT_TABLE;
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
 import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
@@ -113,12 +120,20 @@
 import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_GROUP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_MIRROR_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_TABLE;
+import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
+import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.containsIp;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.dumpStackTrace;
 import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getGroupKey;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getTunnelName;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getTunnelType;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.hostCompareIp;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.isValidHost;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Provides basic implementation of the user APIs.
+ * Provides implementation of the openstack vtap and openstack vtap network APIs.
  */
 @Component(immediate = true, service = { OpenstackVtapService.class, OpenstackVtapAdminService.class })
 public class OpenstackVtapManager
@@ -137,12 +152,6 @@
     protected LeadershipService leadershipService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected MastershipService mastershipService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected DriverService driverService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected FlowRuleService flowRuleService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
@@ -152,36 +161,60 @@
     protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected OpenstackNodeService osNodeService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+
     protected HostService hostService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected OpenstackVtapStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected OpenstackNodeService osNodeService;
+    protected ComponentConfigService componentConfigService;
+
+    private static final boolean DEFAULT_TUNNEL_NICRA = false;
+    //@Property(name = TUNNEL_NICIRA, boolValue = DEFAULT_TUNNEL_NICRA,
+    //        label = "Use nicra extension for tunneling")
+    private boolean tunnelNicira = DEFAULT_TUNNEL_NICRA;
 
     public static final String APP_ID = "org.onosproject.openstackvtap";
-
-    public static final String VTAP_ID_NULL = "OpenstackVtap ID cannot be null";
-    public static final String VTAP_DESC_NULL = "OpenstackVtap fields cannot be null";
-    public static final String DEVICE_ID_NULL = "Device ID cannot be null";
+    public static final String VTAP_DESC_NULL = "vtap field %s cannot be null";
 
     private static final int PRIORITY_VTAP_RULE = 50000;
-    private static final int PRIORITY_VTAP_OUTPORT_RULE = 1000;
-    private static final int PRIORITY_VTAP_DROP = 0;
+    private static final int PRIORITY_VTAP_OUTPUT_RULE = 1000;
+    private static final int PRIORITY_VTAP_OUTPUT_DROP = 0;
 
-    private static final int NONE_TABLE = -1;
     private static final int INBOUND_NEXT_TABLE = DHCP_ARP_TABLE;
     private static final int FLAT_OUTBOUND_NEXT_TABLE = FLAT_TABLE;
     private static final int OUTBOUND_NEXT_TABLE = FORWARDING_TABLE;
 
+    private static final int[][] VTAP_TABLES = {
+            {VTAP_INBOUND_TABLE, VTAP_INBOUND_GROUP_TABLE,
+                    INBOUND_NEXT_TABLE, VTAP_INBOUND_MIRROR_TABLE},
+            {VTAP_FLAT_OUTBOUND_TABLE, VTAP_FLAT_OUTBOUND_GROUP_TABLE,
+                    FLAT_OUTBOUND_NEXT_TABLE, VTAP_FLAT_OUTBOUND_MIRROR_TABLE},
+            {VTAP_OUTBOUND_TABLE, VTAP_OUTBOUND_GROUP_TABLE,
+                    OUTBOUND_NEXT_TABLE, VTAP_OUTBOUND_MIRROR_TABLE}};
+    private static final int VTAP_TABLE_INBOUND_IDX = 0;
+    private static final int VTAP_TABLE_FLAT_OUTBOUND_IDX = 1;
+    private static final int VTAP_TABLE_OUTBOUND_IDX = 2;
+    private static final int VTAP_TABLE_INPUT_IDX = 0;
+    private static final int VTAP_TABLE_GROUP_IDX = 1;
+    private static final int VTAP_TABLE_NEXT_IDX = 2;
+    private static final int VTAP_TABLE_OUTPUT_IDX = 3;
+
     private static final IpPrefix ARBITRARY_IP_PREFIX =
                     IpPrefix.valueOf(IpAddress.valueOf("0.0.0.0"), 0);
-    private static final String TABLE_PROPERTY_KEY = "table";
+    private static final String TABLE_EXTENSION = "table";
+    private static final String TUNNEL_DST_EXTENSION = "tunnelDst";
+    private static final String TUNNEL_NICIRA = "tunnelNicira";
+
+    private static final int VTAP_NETWORK_KEY = 0;
 
     private final DeviceListener deviceListener = new InternalDeviceListener();
-    private final HostListener hostListener = new InternalHostListener();
     private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
+    private final HostListener hostListener = new InternalHostListener();
 
     private OpenstackVtapStoreDelegate delegate = new InternalStoreDelegate();
 
@@ -189,12 +222,16 @@
     private NodeId localNodeId;
     private ScheduledExecutorService eventExecutor;
 
+    private final Object syncInterface = new Object();              // notification of tunnel interface
+    private static final int INTERFACE_MANIPULATION_TIMEOUT = 1000; // 1000msec
+    private static final int INTERFACE_MANIPULATION_RETRY = 10;     // 10 times (totally 10sec)
 
     @Activate
     public void activate(ComponentContext context) {
         appId = coreService.registerApplication(APP_ID);
         localNodeId = clusterService.getLocalNode().id();
         leadershipService.runForLeadership(appId.name());
+        componentConfigService.registerProperties(getClass());
 
         eventExecutor = newSingleThreadScheduledExecutor(
                 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
@@ -203,29 +240,200 @@
         eventDispatcher.addSink(OpenstackVtapEvent.class, listenerRegistry);
 
         deviceService.addListener(deviceListener);
-        hostService.addListener(hostListener);
         osNodeService.addListener(osNodeListener);
+        hostService.addListener(hostListener);
 
-        initFlowAndGroupForCompNodes();
+        initVtap();
 
-        log.info("Started {} - {}", appId.name(), this.getClass().getSimpleName());
+        log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
-        clearFlowAndGroupForCompNodes();
+        clearVtap();
 
-        osNodeService.removeListener(osNodeListener);
         hostService.removeListener(hostListener);
+        osNodeService.removeListener(osNodeListener);
         deviceService.removeListener(deviceListener);
 
         eventDispatcher.removeSink(OpenstackVtapEvent.class);
         store.unsetDelegate(delegate);
 
         eventExecutor.shutdown();
+
+        componentConfigService.unregisterProperties(getClass(), false);
         leadershipService.withdraw(appId.name());
 
-        log.info("Stopped {} - {}", appId.name(), this.getClass().getSimpleName());
+        log.info("Stopped");
+    }
+
+    @Modified
+    protected void modified(ComponentContext context) {
+        Dictionary<?, ?> properties = context.getProperties();
+
+        boolean updatedTunnelNicira = Tools.isPropertyEnabled(properties, TUNNEL_NICIRA);
+        if (tunnelNicira != updatedTunnelNicira) {
+            if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+                // Update the tunnel flow rule by reflecting the change.
+                osNodeService.completeNodes(COMPUTE)
+                        .forEach(osNode -> applyVtapNetwork(getVtapNetwork(), osNode, false));
+                tunnelNicira = updatedTunnelNicira;
+                osNodeService.completeNodes(COMPUTE).stream()
+                        .filter(osNode -> osNode.state() == COMPLETE)
+                        .forEach(osNode -> applyVtapNetwork(getVtapNetwork(), osNode, true));
+                log.debug("Apply {} nicira extension for tunneling", tunnelNicira ? "enable" : "disable");
+            } else {
+                tunnelNicira = updatedTunnelNicira;
+            }
+        }
+
+        log.info("Modified");
+    }
+
+    /**
+     * Initializes the flow rules and group tables, tunneling interface for all completed compute nodes.
+     */
+    @Override
+    public void initVtap() {
+        if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+            osNodeService.completeNodes(COMPUTE).stream()
+                    .filter(osNode -> osNode.state() == COMPLETE)
+                    .forEach(osNode -> initVtapForNode(osNode));
+            log.trace("{} flow rules, groups, tunnel interface are initialized", appId.name());
+        }
+    }
+
+    /**
+     * Clears the flow rules and group tables, tunneling interface for all compute nodes.
+     */
+    @Override
+    public void clearVtap() {
+        if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+            osNodeService.completeNodes(COMPUTE).stream()
+                    .forEach(osNode -> clearVtapForNode(osNode));
+            log.trace("{} flow rules, groups, tunnel interface are cleared", appId.name());
+        }
+    }
+
+    /**
+     * Purges all flow rules and group tables, tunneling interface for openstack vtap.
+     */
+    @Override
+    public void purgeVtap() {
+        // Remove all flow rules
+        flowRuleService.removeFlowRulesById(appId);
+
+        // Remove all groups and tunnel interfaces
+        osNodeService.completeNodes(COMPUTE).stream()
+                .filter(osNode -> osNode.state() == COMPLETE)
+                .forEach(osNode -> {
+                    groupService.getGroups(osNode.intgBridge(), appId)
+                            .forEach(group ->
+                                    groupService.removeGroup(osNode.intgBridge(), group.appCookie(), appId));
+
+                    OpenstackVtapNetwork vtapNetwork = getVtapNetwork();
+                    setTunnelInterface(osNode, vtapNetwork, false);
+                });
+
+        log.trace("{} all flow rules, groups, tunnel interface are purged", appId.name());
+    }
+
+    private void initVtapForNode(OpenstackNode osNode) {
+        // Make base vtap network
+        initVtapNetwork(osNode);
+
+        // Make vtap connections by OpenstackVtap config
+        getVtapsByDeviceId(osNode.intgBridge())
+                .forEach(vtap -> applyVtap(vtap, osNode, true));
+
+        // Make vtap networks by OpenstackVtapNetwork config
+        applyVtapNetwork(getVtapNetwork(), osNode, true);
+    }
+
+    private void clearVtapForNode(OpenstackNode osNode) {
+        // Clear vtap networks by OpenstackVtapNetwork config
+        applyVtapNetwork(getVtapNetwork(), osNode, false);
+
+        // Clear vtap connections by OpenstackVtap config
+        getVtapsByDeviceId(osNode.intgBridge())
+                .forEach(vtap -> applyVtap(vtap, osNode, false));
+
+        // Clear base vtap network
+        clearVtapNetwork(osNode);
+    }
+
+    /**
+     * Initializes vtap pipeline of the given device.
+     *
+     * @param osNode device identifier
+     */
+    private void initVtapNetwork(OpenstackNode osNode) {
+        // Create default output tables
+        for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+            setOutputTableForDrop(osNode.intgBridge(),
+                    VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX], true);
+        }
+
+        // Create group tables
+        for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+            createGroupTable(osNode.intgBridge(),
+                    VTAP_TABLES[idx][VTAP_TABLE_GROUP_IDX],
+                    ImmutableList.of(VTAP_TABLES[idx][VTAP_TABLE_NEXT_IDX],
+                            VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX]),
+                    null);
+        }
+    }
+
+    /**
+     * Clear vtap pipeline of the given device.
+     *
+     * @param osNode device identifier
+     */
+    private void clearVtapNetwork(OpenstackNode osNode) {
+        // Clear group tables
+        for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+            removeGroupTable(osNode.intgBridge(),
+                    VTAP_TABLES[idx][VTAP_TABLE_GROUP_IDX]);
+        }
+
+        // Clear default output tables
+        for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+            setOutputTableForDrop(osNode.intgBridge(),
+                    VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX], false);
+        }
+    }
+
+    @Override
+    public OpenstackVtapNetwork getVtapNetwork() {
+        return store.getVtapNetwork(VTAP_NETWORK_KEY);
+    }
+
+    @Override
+    public OpenstackVtapNetwork createVtapNetwork(Mode mode, Integer networkId, IpAddress serverIp) {
+        checkNotNull(mode, VTAP_DESC_NULL, "mode");
+        checkNotNull(serverIp, VTAP_DESC_NULL, "serverIp");
+        DefaultOpenstackVtapNetwork vtapNetwork = DefaultOpenstackVtapNetwork.builder()
+                .mode(mode)
+                .networkId(networkId)
+                .serverIp(serverIp)
+                .build();
+        return store.createVtapNetwork(VTAP_NETWORK_KEY, vtapNetwork);
+    }
+
+    @Override
+    public OpenstackVtapNetwork updateVtapNetwork(OpenstackVtapNetwork description) {
+        checkNotNull(description, VTAP_DESC_NULL, "vtapNetwork");
+        return store.updateVtapNetwork(VTAP_NETWORK_KEY, description);
+    }
+
+    @Override
+    public OpenstackVtapNetwork removeVtapNetwork() {
+        return store.removeVtapNetwork(VTAP_NETWORK_KEY);
+    }
+
+    @Override
+    public Set<DeviceId> getVtapNetworkDevices() {
+        return store.getVtapNetworkDevices(VTAP_NETWORK_KEY);
     }
 
     @Override
@@ -239,87 +447,54 @@
     }
 
     @Override
-    public OpenstackVtap getVtap(OpenstackVtapId vTapId) {
-        checkNotNull(vTapId, VTAP_ID_NULL);
-        return store.getVtap(vTapId);
+    public OpenstackVtap getVtap(OpenstackVtapId vtapId) {
+        return store.getVtap(vtapId);
     }
 
     @Override
-    public Set<OpenstackVtap> getVtapsByDeviceId(OpenstackVtap.Type type,
-                                                 DeviceId deviceId) {
-        checkNotNull(deviceId, DEVICE_ID_NULL);
-        return store.getVtapsByDeviceId(type, deviceId);
+    public Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId) {
+        return store.getVtapsByDeviceId(deviceId);
     }
 
     @Override
-    public OpenstackVtap createVtap(Type type, OpenstackVtapCriterion vTapCriterion) {
-        checkNotNull(vTapCriterion, VTAP_DESC_NULL);
+    public OpenstackVtap createVtap(Type type, OpenstackVtapCriterion vtapCriterion) {
+        checkNotNull(type, VTAP_DESC_NULL, "type");
+        checkNotNull(vtapCriterion, VTAP_DESC_NULL, "vtapCriterion");
 
         Set<DeviceId> txDevices = type.isValid(Type.VTAP_TX) ?
-                getEdgeDevice(type, vTapCriterion) : ImmutableSet.of();
+                getEdgeDevice(Type.VTAP_TX, vtapCriterion) : ImmutableSet.of();
         Set<DeviceId> rxDevices = type.isValid(Type.VTAP_RX) ?
-                getEdgeDevice(type, vTapCriterion) : ImmutableSet.of();
+                getEdgeDevice(Type.VTAP_RX, vtapCriterion) : ImmutableSet.of();
 
-        OpenstackVtap description =
-                            DefaultOpenstackVtap.builder()
-                                                .id(OpenstackVtapId.vTapId())
-                                                .type(type)
-                                                .vTapCriterion(vTapCriterion)
-                                                .txDeviceIds(txDevices)
-                                                .rxDeviceIds(rxDevices)
-                                                .build();
-        return store.createOrUpdateVtap(description.id(), description, true);
+        DefaultOpenstackVtap description = DefaultOpenstackVtap.builder()
+                .id(OpenstackVtapId.vtapId())
+                .type(type)
+                .vtapCriterion(vtapCriterion)
+                .txDeviceIds(txDevices)
+                .rxDeviceIds(rxDevices)
+                .build();
+        return store.createVtap(description);
     }
 
     @Override
-    public OpenstackVtap updateVtap(OpenstackVtapId vTapId, OpenstackVtap vTap) {
-        checkNotNull(vTapId, VTAP_ID_NULL);
-        checkNotNull(vTap, VTAP_DESC_NULL);
+    public OpenstackVtap updateVtap(OpenstackVtap description) {
+        checkNotNull(description, VTAP_DESC_NULL, "vtap");
 
-        if (store.getVtap(vTapId) == null) {
-            return null;
-        }
+        Set<DeviceId> txDevices = description.type().isValid(Type.VTAP_TX) ?
+                getEdgeDevice(Type.VTAP_TX, description.vtapCriterion()) : ImmutableSet.of();
+        Set<DeviceId> rxDevices = description.type().isValid(Type.VTAP_RX) ?
+                getEdgeDevice(Type.VTAP_RX, description.vtapCriterion()) : ImmutableSet.of();
 
-        Set<DeviceId> txDevices = vTap.type().isValid(Type.VTAP_TX) ?
-                getEdgeDevice(vTap.type(), vTap.vTapCriterion()) : ImmutableSet.of();
-        Set<DeviceId> rxDevices = vTap.type().isValid(Type.VTAP_RX) ?
-                getEdgeDevice(vTap.type(), vTap.vTapCriterion()) : ImmutableSet.of();
-
-        DefaultOpenstackVtap description =
-                            DefaultOpenstackVtap.builder()
-                                                .id(vTapId)
-                                                .type(vTap.type())
-                                                .vTapCriterion(vTap.vTapCriterion())
-                                                .txDeviceIds(txDevices)
-                                                .rxDeviceIds(rxDevices)
-                                                .build();
-        return store.createOrUpdateVtap(vTapId, description, true);
+        DefaultOpenstackVtap vtap = DefaultOpenstackVtap.builder(description)
+                .txDeviceIds(txDevices)
+                .rxDeviceIds(rxDevices)
+                .build();
+        return store.updateVtap(vtap, true);
     }
 
     @Override
-    public OpenstackVtap removeVtap(OpenstackVtapId vTapId) {
-        checkNotNull(vTapId, VTAP_ID_NULL);
-        return store.removeVtapById(vTapId);
-    }
-
-    @Override
-    public void setVtapOutput(DeviceId deviceId, OpenstackVtap.Type type,
-                              PortNumber portNumber, VlanId vlanId) {
-
-        // Make output table
-        if (type.isValid(Type.VTAP_TX)) {
-            createOutputTable(deviceId, VTAP_INBOUND_MIRROR_TABLE, portNumber, vlanId);
-        }
-
-        if (type.isValid(Type.VTAP_RX)) {
-            createOutputTable(deviceId, VTAP_FLAT_OUTBOUND_MIRROR_TABLE, portNumber, vlanId);
-            createOutputTable(deviceId, VTAP_OUTBOUND_MIRROR_TABLE, portNumber, vlanId);
-        }
-    }
-
-    @Override
-    public void setVtapOutput(DeviceId deviceId, Type type, PortNumber portNumber, int vni) {
-        // TODO: need to provide implementation
+    public OpenstackVtap removeVtap(OpenstackVtapId vtapId) {
+        return store.removeVtap(vtapId);
     }
 
     /**
@@ -327,274 +502,138 @@
      * Note that, in most of cases target host is attached to one device,
      * however, in some cases, the host can be attached to multiple devices.
      *
-     * @param type          vTap type
-     * @param criterion     vTap criterion
+     * @param type          vtap type
+     * @param criterion     vtap criterion
      * @return a collection of device identifiers
      */
     private Set<DeviceId> getEdgeDevice(Type type, OpenstackVtapCriterion criterion) {
         Set<DeviceId> deviceIds = Sets.newConcurrentHashSet();
         StreamSupport.stream(hostService.getHosts().spliterator(), true)
-            .forEach(host -> {
-                if (host.ipAddresses().stream()
-                        .anyMatch(ip -> containsIp(type, criterion, ip))) {
-                    deviceIds.addAll(host.locations().stream()
-                                         .map(HostLocation::deviceId)
-                                         .collect(Collectors.toSet()));
-                }
-            });
+                .filter(host -> isValidHost(host) &&
+                        host.ipAddresses().stream().anyMatch(ip -> containsIp(type, criterion, ip)))
+                .forEach(host -> {
+                    Set<DeviceId> hostDeviceIds =
+                            host.locations().stream()
+                                    .map(HostLocation::deviceId)
+                                    .filter(deviceId -> Objects.nonNull(osNodeService.node(deviceId)))
+                                    .collect(Collectors.toSet());
+                    deviceIds.addAll(hostDeviceIds);
+                });
         return deviceIds;
     }
 
     /**
-     * Checks whether the given IP address is included in vTap criterion.
-     * We both check the TX and RX directions.
-     *
-     * @param type          vTap type
-     * @param criterion     vTap criterion
-     * @param ip            IP address
-     * @return boolean value indicates the check result
-     */
-    private boolean containsIp(Type type, OpenstackVtapCriterion criterion, IpAddress ip) {
-        boolean isTxEdge = type.isValid(Type.VTAP_TX) &&
-                                             criterion.srcIpPrefix().contains(ip);
-        boolean isRxEdge = type.isValid(Type.VTAP_RX) &&
-                                             criterion.dstIpPrefix().contains(ip);
-
-        return isTxEdge || isRxEdge;
-    }
-
-    /**
-     * Updates device list of vTaps with respect to the host changes.
+     * Updates device list of vtaps with respect to the host changes.
      *
      * @param newHost   new host instance
      * @param oldHost   old host instance
      */
+    private void updateHostbyType(Type type, Host newHost, Host oldHost) {
+        getVtaps(type).forEach(vtap -> {
+            IpPrefix prefix = (type == Type.VTAP_TX) ?
+                    vtap.vtapCriterion().srcIpPrefix() :
+                    vtap.vtapCriterion().dstIpPrefix();
+
+            int hostDiff = hostCompareIp(newHost, oldHost, prefix);
+            if (hostDiff < 0) {
+                oldHost.locations().stream()
+                        .map(HostLocation::deviceId)
+                        .forEach(deviceId ->
+                                store.removeDeviceFromVtap(vtap.id(), type, deviceId));
+            } else if (hostDiff > 0) {
+                newHost.locations().stream()
+                        .map(HostLocation::deviceId)
+                        .filter(deviceId -> Objects.nonNull(osNodeService.node(deviceId)))
+                        .forEach(deviceId ->
+                                store.addDeviceToVtap(vtap.id(), type, deviceId));
+            }
+        });
+    }
+
     private void updateHost(Host newHost, Host oldHost) {
-        // update devices for vTap tx
-        getVtaps(Type.VTAP_TX).parallelStream().forEach(vTap -> {
+        // update devices for vtap tx
+        updateHostbyType(Type.VTAP_TX, newHost, oldHost);
 
-            if (hostDiff(oldHost, newHost, vTap.vTapCriterion().srcIpPrefix())) {
-                oldHost.locations().stream().map(HostLocation::deviceId)
-                        .forEach(deviceId ->
-                                store.removeDeviceFromVtap(vTap.id(), Type.VTAP_TX,
-                                        oldHost.location().deviceId()));
-            }
-
-            if (hostDiff(newHost, oldHost, vTap.vTapCriterion().srcIpPrefix())) {
-                newHost.locations().stream().map(HostLocation::deviceId)
-                        .forEach(deviceId ->
-                                store.addDeviceToVtap(vTap.id(), Type.VTAP_TX,
-                                        newHost.location().deviceId()));
-            }
-        });
-
-        // update devices for vTap rx
-        getVtaps(Type.VTAP_RX).parallelStream().forEach(vTap -> {
-
-            if (hostDiff(oldHost, newHost, vTap.vTapCriterion().dstIpPrefix())) {
-                oldHost.locations().stream().map(HostLocation::deviceId)
-                        .forEach(deviceId ->
-                                store.removeDeviceFromVtap(vTap.id(), Type.VTAP_RX,
-                                        oldHost.location().deviceId()));
-            }
-
-            if (hostDiff(newHost, oldHost, vTap.vTapCriterion().dstIpPrefix())) {
-                newHost.locations().stream().map(HostLocation::deviceId)
-                        .forEach(deviceId ->
-                                store.addDeviceToVtap(vTap.id(), Type.VTAP_RX,
-                                        newHost.location().deviceId()));
-            }
-        });
+        // update devices for vtap rx
+        updateHostbyType(Type.VTAP_RX, newHost, oldHost);
     }
 
-    /**
-     * Checks whether the given IP prefix is contained in the first host rather
-     * than in the second host.
-     *
-     * @param host1     first host instance
-     * @param host2     second host instance
-     * @param ipPrefix  IP prefix to be looked up
-     * @return boolean value
-     */
-    private boolean hostDiff(Host host1, Host host2, IpPrefix ipPrefix) {
-        return ((host1 != null && host1.ipAddresses().stream().anyMatch(ipPrefix::contains)) &&
-                (host2 == null || host2.ipAddresses().stream().noneMatch(ipPrefix::contains)));
-    }
+    private void applyFlowRule(FlowRule flowRule, boolean install) {
+        FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
 
-    /**
-     * Initializes the flow rules and group tables for all completed compute nodes.
-     */
-    private void initFlowAndGroupForCompNodes() {
-        osNodeService.completeNodes(COMPUTE).forEach(node ->
-                                initFlowAndGroupByDeviceId(node.intgBridge()));
-    }
-
-    /**
-     * Initializes the flow rules and group table of the given device identifier.
-     *
-     * @param deviceId device identifier
-     */
-    private void initFlowAndGroupByDeviceId(DeviceId deviceId) {
-        // Make vTap pipeline
-        // TODO: need to selective creation by store device consistentMap
-        initVtapPipeline(deviceId);
-
-        // Install tx filter
-        getVtapsByDeviceId(Type.VTAP_TX, deviceId).forEach(vTap -> {
-            connectTables(deviceId,
-                    VTAP_INBOUND_TABLE, NONE_TABLE, VTAP_INBOUND_GROUP_TABLE,
-                    vTap.vTapCriterion(), PRIORITY_VTAP_RULE, true);
-        });
-
-        // Install rx filter
-        getVtapsByDeviceId(Type.VTAP_RX, deviceId).forEach(vTap -> {
-            connectTables(deviceId,
-                    VTAP_FLAT_OUTBOUND_TABLE, NONE_TABLE, VTAP_FLAT_OUTBOUND_GROUP_TABLE,
-                    vTap.vTapCriterion(), PRIORITY_VTAP_RULE, true);
-            connectTables(deviceId,
-                    VTAP_OUTBOUND_TABLE, NONE_TABLE, VTAP_OUTBOUND_GROUP_TABLE,
-                    vTap.vTapCriterion(), PRIORITY_VTAP_RULE, true);
-        });
-    }
-
-    /**
-     * Initializes vTap pipeline of the given device.
-     *
-     * @param deviceId device identifier
-     */
-    private void initVtapPipeline(DeviceId deviceId) {
-        // Make output table
-        createOutputTable(deviceId, VTAP_INBOUND_MIRROR_TABLE, null, null);
-        createOutputTable(deviceId, VTAP_FLAT_OUTBOUND_MIRROR_TABLE, null, null);
-        createOutputTable(deviceId, VTAP_OUTBOUND_MIRROR_TABLE, null, null);
-
-        // Make tx group table
-        createGroupTable(deviceId, VTAP_INBOUND_GROUP_TABLE,
-                ImmutableList.of(INBOUND_NEXT_TABLE, VTAP_INBOUND_MIRROR_TABLE),
-                ImmutableList.of());
-
-        // Make rx group table
-        createGroupTable(deviceId, VTAP_FLAT_OUTBOUND_GROUP_TABLE,
-                ImmutableList.of(FLAT_OUTBOUND_NEXT_TABLE, VTAP_FLAT_OUTBOUND_MIRROR_TABLE),
-                ImmutableList.of());
-        createGroupTable(deviceId, VTAP_OUTBOUND_GROUP_TABLE,
-                ImmutableList.of(OUTBOUND_NEXT_TABLE, VTAP_OUTBOUND_MIRROR_TABLE),
-                ImmutableList.of());
-    }
-
-    /**
-     * Purges all flow rules and group tables for completed compute nodes.
-     */
-    private void clearFlowAndGroupForCompNodes() {
-        osNodeService.completeNodes(COMPUTE).forEach(node ->
-                clearFlowAndGroupByDeviceId(node.intgBridge()));
-    }
-
-    /**
-     * Purges all flow rules and group tables using the given device identifier.
-     *
-     * @param deviceId  device identifier
-     */
-    private void clearFlowAndGroupByDeviceId(DeviceId deviceId) {
-        Set<FlowRule> purgedRules = Sets.newConcurrentHashSet();
-        for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
-            if (flowRule.deviceId().equals(deviceId)) {
-                purgedRules.add(flowRule);
-            }
+        if (install) {
+            flowOpsBuilder.add(flowRule);
+        } else {
+            flowOpsBuilder.remove(flowRule);
         }
 
-        flowRuleService.removeFlowRules(purgedRules.toArray(new FlowRule[0]));
+        flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.debug("Installed flow rules for vtap");
+            }
 
-        groupService.getGroups(deviceId, appId).forEach(group -> {
-            groupService.removeGroup(deviceId, group.appCookie(), appId);
-        });
-        log.info("OpenstackVtap flow rules and groups are purged");
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.warn("Failed to install flow rules for vtap");
+            }
+        }));
     }
 
-    private void installFilterRule(Set<DeviceId> txDeviceIds, Set<DeviceId> rxDeviceIds,
-                                   OpenstackVtapCriterion vTapCriterion, boolean install) {
-        final int inbound = 0;
-        final int flatOutbound = 1;
-        final int outbound = 2;
-
-        BiFunction<Set<DeviceId>, Integer, Void> installFlow = (deviceIds, table) -> {
-            int inTable = (table == inbound ? VTAP_INBOUND_TABLE :
-                    (table == flatOutbound ? VTAP_FLAT_OUTBOUND_TABLE :
-                                             VTAP_OUTBOUND_TABLE));
-
-            int outGroup = (table == inbound ? VTAP_INBOUND_GROUP_TABLE :
-                    (table == flatOutbound ? VTAP_FLAT_OUTBOUND_GROUP_TABLE :
-                                             VTAP_OUTBOUND_GROUP_TABLE));
-
-            deviceIds.stream()
-                    .filter(deviceId -> mastershipService.isLocalMaster(deviceId))
-                    .forEach(deviceId -> {
-                        connectTables(deviceId, inTable, NONE_TABLE, outGroup,
-                                vTapCriterion, PRIORITY_VTAP_RULE, install);
-                    });
-            return null;
-        };
-
-        installFlow.apply(txDeviceIds, inbound);
-        installFlow.apply(rxDeviceIds, flatOutbound);
-        installFlow.apply(rxDeviceIds, outbound);
-    }
-
-    private void connectTables(DeviceId deviceId, int fromTable, int toTable, int toGroup,
-                               OpenstackVtapCriterion vTapCriterion, int rulePriority,
-                               boolean install) {
-        log.trace("Table Transition: table[{}] -> table[{}] or group[{}]", fromTable, toTable, toGroup);
+    private void connectTables(DeviceId deviceId,
+                               int fromTable,
+                               int toTableOrGroup, boolean isGroup,
+                               OpenstackVtapCriterion vtapCriterion,
+                               int rulePriority, boolean install) {
+        log.debug("Table Transition: table[{}] -> table/group[{}]", fromTable, toTableOrGroup);
 
         TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
                 .matchEthType(TYPE_IPV4);
 
         // if the IpPrefix is "0.0.0.0/0", we do not include such a match into the flow rule
-        if (!vTapCriterion.srcIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
-            selectorBuilder.matchIPSrc(vTapCriterion.srcIpPrefix());
+        if (!vtapCriterion.srcIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
+            selectorBuilder.matchIPSrc(vtapCriterion.srcIpPrefix());
         }
 
-        if (!vTapCriterion.dstIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
-            selectorBuilder.matchIPDst(vTapCriterion.dstIpPrefix());
+        if (!vtapCriterion.dstIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
+            selectorBuilder.matchIPDst(vtapCriterion.dstIpPrefix());
         }
 
-        switch (vTapCriterion.ipProtocol()) {
+        switch (vtapCriterion.ipProtocol()) {
             case PROTOCOL_TCP:
-                selectorBuilder.matchIPProtocol(vTapCriterion.ipProtocol());
+                selectorBuilder.matchIPProtocol(vtapCriterion.ipProtocol());
 
                 // Add port match only if the port number is greater than zero
-                if (vTapCriterion.srcTpPort().toInt() > 0) {
-                    selectorBuilder.matchTcpSrc(vTapCriterion.srcTpPort());
+                if (vtapCriterion.srcTpPort().toInt() > 0) {
+                    selectorBuilder.matchTcpSrc(vtapCriterion.srcTpPort());
                 }
-                if (vTapCriterion.dstTpPort().toInt() > 0) {
-                    selectorBuilder.matchTcpDst(vTapCriterion.dstTpPort());
+                if (vtapCriterion.dstTpPort().toInt() > 0) {
+                    selectorBuilder.matchTcpDst(vtapCriterion.dstTpPort());
                 }
                 break;
             case PROTOCOL_UDP:
-                selectorBuilder.matchIPProtocol(vTapCriterion.ipProtocol());
+                selectorBuilder.matchIPProtocol(vtapCriterion.ipProtocol());
 
                 // Add port match only if the port number is greater than zero
-                if (vTapCriterion.srcTpPort().toInt() > 0) {
-                    selectorBuilder.matchUdpSrc(vTapCriterion.srcTpPort());
+                if (vtapCriterion.srcTpPort().toInt() > 0) {
+                    selectorBuilder.matchUdpSrc(vtapCriterion.srcTpPort());
                 }
-                if (vTapCriterion.dstTpPort().toInt() > 0) {
-                    selectorBuilder.matchUdpDst(vTapCriterion.dstTpPort());
+                if (vtapCriterion.dstTpPort().toInt() > 0) {
+                    selectorBuilder.matchUdpDst(vtapCriterion.dstTpPort());
                 }
                 break;
             case PROTOCOL_ICMP:
-                selectorBuilder.matchIPProtocol(vTapCriterion.ipProtocol());
+                selectorBuilder.matchIPProtocol(vtapCriterion.ipProtocol());
                 break;
             default:
                 break;
         }
 
         TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
-        if (toTable != NONE_TABLE) {
-            treatmentBuilder.transition(toTable);
-        } else if (toGroup != NONE_TABLE) {
-            treatmentBuilder.group(GroupId.valueOf(toGroup));
+        if (isGroup) {
+            treatmentBuilder.group(GroupId.valueOf(toTableOrGroup));
         } else {
-            log.warn("Not specified toTable or toGroup value");
-            return;
+            treatmentBuilder.transition(toTableOrGroup);
         }
 
         FlowRule flowRule = DefaultFlowRule.builder()
@@ -610,69 +649,246 @@
         applyFlowRule(flowRule, install);
     }
 
-    private void createOutputTable(DeviceId deviceId, int tableId,
-                                   PortNumber outPort, VlanId vlanId) {
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-
-        // Set output port & vlan
-        int priority = PRIORITY_VTAP_DROP;
-        if (vlanId != null && vlanId.toShort() != UNTAGGED) {
-            treatment.pushVlan().setVlanId(vlanId);
+    /**
+     * Creates/Removes a tunnel interface in a given openstack node by vtap network information.
+     *
+     * @param osNode openstack node
+     * @param vtapNetwork openstack vtap network for making
+     *
+     */
+    private boolean setTunnelInterface(OpenstackNode osNode,
+                                       OpenstackVtapNetwork vtapNetwork,
+                                       boolean install) {
+        String tunnelName = getTunnelName(vtapNetwork.mode());
+        if (tunnelName == null) {
+            return false;
         }
-        if (outPort != null) {
-            treatment.setOutput(outPort);
-            priority = PRIORITY_VTAP_OUTPORT_RULE;
+
+        if (!deviceService.isAvailable(osNode.ovsdb())) {
+            log.warn("Not available osNode {} ovs {}", osNode.hostname(), osNode.ovsdb());
+            return false;
+        }
+
+        if (install == isInterfaceEnabled(osNode.intgBridge(), tunnelName)) {
+            log.warn("Already {} {} interface on osNode ovs {}, bridge {}",
+                    install ? "add" : "remove",
+                    tunnelName, osNode.ovsdb(), osNode.intgBridge());
+            return true;
+        }
+
+        Device device = deviceService.getDevice(osNode.ovsdb());
+        if (device == null || !device.is(InterfaceConfig.class)) {
+            log.warn("Not able to get InterfaceConfig on osNode ovs {}", osNode.ovsdb());
+            return false;
+        }
+
+        InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
+        if (install) {
+            TunnelDescription.Builder tunnelDesc = DefaultTunnelDescription.builder()
+                    .deviceId(INTEGRATION_BRIDGE)
+                    .ifaceName(tunnelName)
+                    .type(getTunnelType(vtapNetwork.mode()))
+                    .key((vtapNetwork.networkId() == 0) ? null : new TunnelKey<>(vtapNetwork.networkId()))
+                    .remote(TunnelEndPoints.ipTunnelEndpoint(vtapNetwork.serverIp()));
+            if (!ifaceConfig.addTunnelMode(tunnelName, tunnelDesc.build())) {
+                log.error("Fail to create {} interface on osNode ovs {}", tunnelName, osNode.ovsdb());
+                return false;
+            }
+        } else {
+            if (!ifaceConfig.removeTunnelMode(tunnelName)) {
+                log.error("Fail to remove {} interface on osNode ovs {}", tunnelName, osNode.ovsdb());
+                return false;
+            }
+        }
+
+        // Wait for tunnel interface create/remove complete
+        synchronized (syncInterface) {
+            for (int i = 0; i < INTERFACE_MANIPULATION_RETRY; i++) {
+                try {
+                    syncInterface.wait(INTERFACE_MANIPULATION_TIMEOUT);
+                    if (install == isInterfaceEnabled(osNode.intgBridge(), tunnelName)) {
+                        log.debug("Success to {} {} interface on osNode ovs {}, bridge {}",
+                                install ? "add" : "remove",
+                                tunnelName, osNode.ovsdb(), osNode.intgBridge());
+                        return true;
+                    }
+                } catch (InterruptedException e) {
+                    break;
+                }
+            }
+        }
+        log.warn("Fail to {} {} interface on osNode ovs {}, bridge {}",
+                install ? "add" : "remove",
+                tunnelName, osNode.ovsdb(), osNode.intgBridge());
+        return false;
+    }
+
+    /**
+     * Checks whether a given network interface in a given openstack node is enabled or not.
+     *
+     * @param deviceId openstack node
+     * @param interfaceName network interface name
+     * @return true if the given interface is enabled, false otherwise
+     */
+    private boolean isInterfaceEnabled(DeviceId deviceId, String interfaceName) {
+        return deviceService.isAvailable(deviceId) &&
+                deviceService.getPorts(deviceId).parallelStream().anyMatch(port ->
+                        Objects.equals(port.annotations().value(PORT_NAME), interfaceName) && port.isEnabled());
+    }
+
+    private PortNumber portNumber(DeviceId deviceId, String interfaceName) {
+        Port port = deviceService.getPorts(deviceId).stream()
+                .filter(p -> p.isEnabled() &&
+                        Objects.equals(p.annotations().value(PORT_NAME), interfaceName))
+                .findAny().orElse(null);
+        return port != null ? port.number() : null;
+    }
+
+    private void setOutputTableForTunnel(DeviceId deviceId, int tableId,
+                                         PortNumber outPort, IpAddress serverIp,
+                                         boolean install) {
+        log.debug("setOutputTableForTunnel[{}]: deviceId={}, tableId={}, outPort={}, serverIp={}",
+                install ? "add" : "remove", deviceId, tableId, outPort, serverIp);
+
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+                .setOutput(outPort);
+
+        if (tunnelNicira) {
+            ExtensionTreatment extensionTreatment = buildTunnelExtension(deviceId, serverIp);
+            if (extensionTreatment == null) {
+                return;
+            }
+            treatment.extension(extensionTreatment, deviceId);
         }
 
         FlowRule flowRule = DefaultFlowRule.builder()
                 .forDevice(deviceId)
                 .withSelector(selector.build())
                 .withTreatment(treatment.build())
-                .withPriority(priority)
+                .withPriority(PRIORITY_VTAP_OUTPUT_RULE)
                 .makePermanent()
                 .forTable(tableId)
                 .fromApp(appId)
                 .build();
-        applyFlowRule(flowRule, true);
+
+        log.debug("setOutputTableForTunnel flowRule={}, install={}", flowRule, install);
+        applyFlowRule(flowRule, install);
     }
 
-    private ExtensionTreatment buildNiciraExtension(DeviceId id, int tableId) {
-        Driver driver = driverService.getDriver(id);
-        DriverHandler driverHandler =
-                    new DefaultDriverHandler(new DefaultDriverData(driver, id));
-        ExtensionTreatmentResolver resolver =
-                    driverHandler.behaviour(ExtensionTreatmentResolver.class);
+    private void setOutputTableForDrop(DeviceId deviceId, int tableId,
+                                       boolean install) {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
 
-        ExtensionTreatment extensionInstruction =
-                    resolver.getExtensionInstruction(NICIRA_RESUBMIT_TABLE.type());
+        FlowRule flowRule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(PRIORITY_VTAP_OUTPUT_DROP)
+                .makePermanent()
+                .forTable(tableId)
+                .fromApp(appId)
+                .build();
+        applyFlowRule(flowRule, install);
+    }
 
-        try {
-            extensionInstruction.setPropertyValue(TABLE_PROPERTY_KEY, ((short) tableId));
-        } catch (Exception e) {
-            log.error("Failed to set extension treatment for resubmit table {}", id);
+    private void setOutputTable(DeviceId deviceId, Mode mode,
+                                IpAddress serverIp, boolean install) {
+        log.debug("setOutputTable[{}]: deviceId={}, mode={}, serverIp={}",
+                install ? "add" : "remove", deviceId, mode, serverIp);
+
+        if (deviceId == null) {
+            return;
         }
 
-        return extensionInstruction;
+        switch (mode) {
+            case GRE:
+            case VXLAN:
+                String tunnelName = getTunnelName(mode);
+                PortNumber vtapPort = portNumber(deviceId, tunnelName);
+                if (vtapPort != null) {
+                    for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+                        setOutputTableForTunnel(deviceId, VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX],
+                                vtapPort, serverIp, install);
+                    }
+                } else {
+                    log.warn("Vtap tunnel port {} doesn't exist", tunnelName);
+                }
+                break;
+            default:
+                log.warn("Invalid vtap network mode {}", mode);
+                break;
+        }
+    }
+
+    /**
+     * Returns tunnel destination extension treatment object.
+     *
+     * @param deviceId device id to apply this treatment
+     * @param remoteIp tunnel destination ip address
+     * @return extension treatment
+     */
+    private ExtensionTreatment buildTunnelExtension(DeviceId deviceId, IpAddress remoteIp) {
+        Device device = deviceService.getDevice(deviceId);
+        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
+            log.warn("Nicira extension treatment is not supported");
+            return null;
+        }
+
+        ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+        ExtensionTreatment treatment =
+                resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
+        try {
+            treatment.setPropertyValue(TUNNEL_DST_EXTENSION, remoteIp.getIp4Address());
+            return treatment;
+        } catch (ExtensionPropertyException e) {
+            log.error("Failed to set nicira tunnelDst extension treatment for {}", deviceId);
+            return null;
+        }
+    }
+
+    private ExtensionTreatment buildResubmitExtension(DeviceId deviceId, int tableId) {
+        Device device = deviceService.getDevice(deviceId);
+        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
+            log.warn("Nicira extension treatment is not supported");
+            return null;
+        }
+
+        ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+        ExtensionTreatment treatment =
+                resolver.getExtensionInstruction(NICIRA_RESUBMIT_TABLE.type());
+
+        try {
+            treatment.setPropertyValue(TABLE_EXTENSION, ((short) tableId));
+            return treatment;
+        } catch (ExtensionPropertyException e) {
+            log.error("Failed to set nicira resubmit extension treatment for {}", deviceId);
+            return null;
+        }
     }
 
     private void createGroupTable(DeviceId deviceId, int groupId,
                                   List<Integer> tableIds, List<PortNumber> ports) {
         List<GroupBucket> buckets = Lists.newArrayList();
-        tableIds.forEach(tableId -> {
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
-                    .extension(buildNiciraExtension(deviceId, tableId), deviceId);
-            GroupBucket bucket = DefaultGroupBucket
-                    .createAllGroupBucket(treatment.build());
-            buckets.add(bucket);
-        });
-        ports.forEach(port -> {
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
-                    .setOutput(port);
-            GroupBucket bucket = DefaultGroupBucket
-                    .createAllGroupBucket(treatment.build());
-            buckets.add(bucket);
-        });
+        if (tableIds != null) {
+            tableIds.forEach(tableId -> {
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+                        .extension(buildResubmitExtension(deviceId, tableId), deviceId);
+                GroupBucket bucket = DefaultGroupBucket
+                        .createAllGroupBucket(treatment.build());
+                buckets.add(bucket);
+            });
+        }
+        if (ports != null) {
+            ports.forEach(port -> {
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+                        .setOutput(port);
+                GroupBucket bucket = DefaultGroupBucket
+                        .createAllGroupBucket(treatment.build());
+                buckets.add(bucket);
+            });
+        }
 
         GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
                 GroupDescription.Type.ALL,
@@ -683,42 +899,36 @@
         groupService.addGroup(groupDescription);
     }
 
-    private void applyFlowRule(FlowRule flowRule, boolean install) {
-        FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
-
-        flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
-
-        flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
-            @Override
-            public void onSuccess(FlowRuleOperations ops) {
-                log.debug("Installed flow rules for tapping");
-            }
-
-            @Override
-            public void onError(FlowRuleOperations ops) {
-                log.debug("Failed to install flow rules for tapping");
-            }
-        }));
+    private void removeGroupTable(DeviceId deviceId, int groupId) {
+        groupService.removeGroup(deviceId, getGroupKey(groupId), appId);
     }
 
+    /**
+     * Internal listener for device events.
+     */
     private class InternalDeviceListener implements DeviceListener {
-        @Override
-        public boolean isRelevant(DeviceEvent event) {
-            // do not allow to proceed without Mastership
-            DeviceId deviceId = event.subject().id();
-            return mastershipService.isLocalMaster(deviceId) &&
-                    event.subject().type() == Device.Type.SWITCH;
-        }
 
         @Override
         public void event(DeviceEvent event) {
             DeviceEvent.Type type = event.type();
-            DeviceId deviceId = event.subject().id();
-            log.trace("InternalDeviceListener deviceId={}, type={}", deviceId, type);
+            Device device = event.subject();
 
             switch (type) {
-                case DEVICE_ADDED:
-                    eventExecutor.execute(() -> initFlowAndGroupByDeviceId(deviceId));
+                case PORT_ADDED:
+                case PORT_UPDATED:
+                case PORT_REMOVED:
+                    String portName = event.port().annotations().value(PORT_NAME);
+                    if (portName.equals(getTunnelName(Mode.GRE)) ||
+                            portName.equals(getTunnelName(Mode.VXLAN))) {
+                        log.trace("InternalDeviceListener type={}, host={}", type, device);
+                        synchronized (syncInterface) {
+                            try {
+                                syncInterface.notifyAll();
+                            } catch (IllegalMonitorStateException e) {
+                                log.warn("Already syncInterface exited");
+                            }
+                        }
+                    }
                     break;
                 default:
                     break;
@@ -726,9 +936,60 @@
         }
     }
 
+    /**
+     * Internal listener for openstack node events.
+     */
+    private class InternalOpenstackNodeListener implements OpenstackNodeListener {
+
+        @Override
+        public boolean isRelevant(OpenstackNodeEvent event) {
+            // do not allow to proceed without leadership and compute node
+            NodeId leader = leadershipService.getLeader(appId.name());
+            OpenstackNode osNode = event.subject();
+
+            return Objects.equals(localNodeId, leader) && osNode.type() == COMPUTE;
+        }
+
+        @Override
+        public void event(OpenstackNodeEvent event) {
+            OpenstackNodeEvent.Type type = event.type();
+            OpenstackNode osNode = event.subject();
+            log.trace("InternalOpenstackNodeListener type={}, osNode={}", type, osNode);
+
+            eventExecutor.execute(() -> {
+                try {
+                    switch (type) {
+                        case OPENSTACK_NODE_COMPLETE:
+                            initVtapForNode(osNode);
+                            break;
+
+                        case OPENSTACK_NODE_REMOVED:
+                            clearVtapForNode(osNode);
+                            break;
+
+                        default:
+                            break;
+                    }
+                } catch (Exception e) {
+                    dumpStackTrace(log, e);
+                }
+            });
+        }
+    }
+
+    /**
+     * Internal listener for host events.
+     */
     private class InternalHostListener implements HostListener {
+
         @Override
         public boolean isRelevant(HostEvent event) {
+            Host host = event.subject();
+            if (!isValidHost(host)) {
+                log.debug("Invalid host detected, ignore it {}", host);
+                return false;
+            }
+
             // do not allow to proceed without leadership
             NodeId leader = leadershipService.getLeader(appId.name());
             return Objects.equals(localNodeId, leader);
@@ -738,102 +999,173 @@
         public void event(HostEvent event) {
             HostEvent.Type type = event.type();
             Host host = event.subject();
-            log.trace("InternalHostListener hostId={}, type={}", host.id(), type);
+            Host prevHost = event.prevSubject();
+            log.trace("InternalHostListener {}: {} -> {}", type, prevHost, host);
 
-            switch (type) {
-                case HOST_ADDED:
-                    eventExecutor.execute(() -> updateHost(host, null));
-                    break;
+            eventExecutor.execute(() -> {
+                try {
+                    switch (event.type()) {
+                        case HOST_ADDED:
+                            updateHost(host, null);
+                            break;
 
-                case HOST_REMOVED:
-                    eventExecutor.execute(() -> updateHost(null, host));
-                    break;
+                        case HOST_REMOVED:
+                            updateHost(null, host);
+                            break;
 
-                case HOST_UPDATED:
-                case HOST_MOVED:
-                    eventExecutor.execute(() -> updateHost(host, event.prevSubject()));
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
+                        case HOST_MOVED:
+                        case HOST_UPDATED:
+                            updateHost(host, prevHost);
+                            break;
 
-    private class InternalOpenstackNodeListener implements OpenstackNodeListener {
-
-        @Override
-        public boolean isRelevant(OpenstackNodeEvent event) {
-            // do not allow to proceed without leadership
-            NodeId leader = leadershipService.getLeader(appId.name());
-            return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
-        }
-
-        @Override
-        public void event(OpenstackNodeEvent event) {
-            DeviceId deviceId = event.subject().intgBridge();
-            switch (event.type()) {
-                case OPENSTACK_NODE_CREATED:
-                case OPENSTACK_NODE_UPDATED:
-                    eventExecutor.execute(() -> initFlowAndGroupByDeviceId(deviceId));
-                    break;
-                case OPENSTACK_NODE_REMOVED:
-                    eventExecutor.execute(() -> clearFlowAndGroupByDeviceId(deviceId));
-                    break;
-                default:
-                    break;
-            }
+                        default:
+                            break;
+                    }
+                } catch (Exception e) {
+                    dumpStackTrace(log, e);
+                }
+            });
         }
     }
 
     // Store delegate to re-post events emitted from the store.
     private class InternalStoreDelegate implements OpenstackVtapStoreDelegate {
+
         @Override
         public void notify(OpenstackVtapEvent event) {
             OpenstackVtapEvent.Type type = event.type();
-            OpenstackVtap vTap = event.subject();
-            log.trace("vTapStoreDelegate vTap={}, type={}", vTap, type);
+            log.trace("InternalStoreDelegate {}: {} -> {}", type, event.prevSubject(), event.subject());
 
-            switch (type) {
-                case VTAP_ADDED:
-                    eventExecutor.execute(() -> {
-                        // Add new devices
-                        installFilterRule(vTap.txDeviceIds(), vTap.rxDeviceIds(),
-                                vTap.vTapCriterion(), true);
-                    });
-                    break;
+            if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+                eventExecutor.execute(() -> {
+                    try {
+                        switch (type) {
+                            case VTAP_NETWORK_ADDED:
+                            case VTAP_NETWORK_UPDATED:
+                            case VTAP_NETWORK_REMOVED:
+                                // Update network
+                                updateVtapNetwork(event.openstackVtapNetwork(),
+                                        event.prevOpenstackVtapNetwork());
+                                break;
 
-                case VTAP_UPDATED:
-                    OpenstackVtap oldOpenstackVtap = event.prevSubject();
-                    eventExecutor.execute(() -> {
-                        // Remove excluded devices
-                        installFilterRule(
-                                Sets.difference(oldOpenstackVtap.txDeviceIds(),
-                                                            vTap.txDeviceIds()),
-                                Sets.difference(oldOpenstackVtap.rxDeviceIds(),
-                                                            vTap.rxDeviceIds()),
-                                oldOpenstackVtap.vTapCriterion(), false);
+                            case VTAP_ADDED:
+                            case VTAP_UPDATED:
+                            case VTAP_REMOVED:
+                                // Update vtap rule
+                                updateVtap(event.openstackVtap(),
+                                        event.prevOpenstackVtap());
+                                break;
 
-                        // Add new devices
-                        installFilterRule(
-                                Sets.difference(vTap.txDeviceIds(),
-                                                oldOpenstackVtap.txDeviceIds()),
-                                Sets.difference(vTap.rxDeviceIds(),
-                                                oldOpenstackVtap.rxDeviceIds()),
-                                vTap.vTapCriterion(), true);
-                    });
-                    break;
-
-                case VTAP_REMOVED:
-                    eventExecutor.execute(() -> {
-                        // Remove excluded devices
-                        installFilterRule(vTap.txDeviceIds(), vTap.rxDeviceIds(),
-                                vTap.vTapCriterion(), false);
-                    });
-                    break;
-                default:
-                    break;
+                            default:
+                                break;
+                        }
+                    } catch (Exception e) {
+                        dumpStackTrace(log, e);
+                    }
+                });
             }
             post(event);
         }
     }
+
+    private void applyVtap(OpenstackVtap vtap,
+                           OpenstackNode osNode,
+                           boolean install) {
+        if (vtap == null || osNode == null) {
+            return;
+        }
+
+        log.debug("applyVtap vtap={}, osNode={}, install={}", vtap, osNode, install);
+
+        DeviceId deviceId = osNode.intgBridge();
+        for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+            if ((idx == VTAP_TABLE_INBOUND_IDX &&
+                        vtap.type().isValid(Type.VTAP_TX) &&
+                        vtap.txDeviceIds().contains(deviceId)) ||
+                (idx != VTAP_TABLE_INBOUND_IDX &&
+                        vtap.type().isValid(Type.VTAP_RX) &&
+                        vtap.rxDeviceIds().contains(deviceId))) {
+                connectTables(deviceId,
+                        VTAP_TABLES[idx][VTAP_TABLE_INPUT_IDX],
+                        VTAP_TABLES[idx][VTAP_TABLE_GROUP_IDX],
+                        true,
+                        vtap.vtapCriterion(), PRIORITY_VTAP_RULE, install);
+            }
+        }
+    }
+
+    private void updateVtap(OpenstackVtap vtap,
+                            OpenstackVtap prevVtap) {
+        if (Objects.equals(vtap, prevVtap)) {
+            return;
+        }
+
+        Set<DeviceId> prevTxDeviceIds = (prevVtap != null ? prevVtap.txDeviceIds() : ImmutableSet.of());
+        Set<DeviceId> txDeviceIds = (vtap != null ? vtap.txDeviceIds() : ImmutableSet.of());
+        Set<DeviceId> prevRxDeviceIds = (prevVtap != null ? prevVtap.rxDeviceIds() : ImmutableSet.of());
+        Set<DeviceId> rxDeviceIds = (vtap != null ? vtap.rxDeviceIds() : ImmutableSet.of());
+
+        // Remake all vtap rule
+        if (prevVtap != null) {
+            Set<DeviceId> deviceIds = Sets.newHashSet();
+            deviceIds.addAll(Sets.difference(prevTxDeviceIds, txDeviceIds));
+            deviceIds.addAll(Sets.difference(prevRxDeviceIds, rxDeviceIds));
+            deviceIds.stream()
+                    .map(deviceId -> osNodeService.node(deviceId))
+                    .filter(osNode -> Objects.nonNull(osNode) &&
+                            osNode.type() == COMPUTE)
+                    .forEach(osNode -> applyVtap(prevVtap, osNode, false));
+        }
+        if (vtap != null) {
+            Set<DeviceId> deviceIds = Sets.newHashSet();
+            deviceIds.addAll(Sets.difference(txDeviceIds, prevTxDeviceIds));
+            deviceIds.addAll(Sets.difference(rxDeviceIds, prevRxDeviceIds));
+            deviceIds.stream()
+                    .map(deviceId -> osNodeService.node(deviceId))
+                    .filter(osNode -> Objects.nonNull(osNode) &&
+                            osNode.type() == COMPUTE && osNode.state() == COMPLETE)
+                    .forEach(osNode -> applyVtap(vtap, osNode, true));
+        }
+    }
+
+    // create/remove tunnel interface and output table
+    private boolean applyVtapNetwork(OpenstackVtapNetwork vtapNetwork,
+                                     OpenstackNode osNode,
+                                     boolean install) {
+        if (vtapNetwork == null || osNode == null) {
+            return false;
+        }
+
+        if (install) {
+            if (setTunnelInterface(osNode, vtapNetwork, true)) {
+                setOutputTable(osNode.intgBridge(), vtapNetwork.mode(), vtapNetwork.serverIp(), true);
+                store.addDeviceToVtapNetwork(VTAP_NETWORK_KEY, osNode.intgBridge());
+                return true;
+            }
+        } else {
+            Set<DeviceId> deviceIds = getVtapNetworkDevices();
+            if (deviceIds != null && deviceIds.contains(osNode.intgBridge())) {
+                store.removeDeviceFromVtapNetwork(VTAP_NETWORK_KEY, osNode.intgBridge());
+                setOutputTable(osNode.intgBridge(), vtapNetwork.mode(), vtapNetwork.serverIp(), false);
+                setTunnelInterface(osNode, vtapNetwork, false);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void updateVtapNetwork(OpenstackVtapNetwork network,
+                                   OpenstackVtapNetwork prevNetwork) {
+        // Remake all output tables
+        if (prevNetwork != null) {
+            osNodeService.completeNodes(COMPUTE)
+                    .forEach(osNode -> applyVtapNetwork(prevNetwork, osNode, false));
+        }
+        if (network != null) {
+            osNodeService.completeNodes(COMPUTE).stream()
+                    .filter(osNode -> osNode.state() == COMPLETE)
+                    .forEach(osNode -> applyVtapNetwork(network, osNode, true));
+        }
+    }
+
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java
index cc5feb7..7790c8a 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java
@@ -15,6 +15,6 @@
  */
 
 /**
- * Implementation for Openstack vtap.
+ * Implementation for openstack vtap.
  */
 package org.onosproject.openstackvtap.impl;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java
index 1e67693..69919be 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java
@@ -16,15 +16,31 @@
 package org.onosproject.openstackvtap.util;
 
 import org.onlab.packet.IPv4;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.Host;
+import org.onosproject.net.behaviour.TunnelDescription;
 import org.onosproject.net.group.DefaultGroupKey;
 import org.onosproject.net.group.GroupKey;
 import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapCriterion;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.slf4j.Logger;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+
+import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_NETWORK_ID;
+import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_PORT_ID;
 
 /**
- * An utility that used in openstack vTap app.
+ * An utilities that used in openstack vtap app.
  */
 public final class OpenstackVtapUtil {
 
+    private static final String VTAP_TUNNEL_GRE = "vtap_gre";
+    private static final String VTAP_TUNNEL_VXLAN = "vtap_vxlan";
     private static final String VTAP_GROUP_KEY = "VTAP_GROUP_KEY";
 
     /**
@@ -34,31 +50,10 @@
     }
 
     /**
-     * Obtains vTap type from the given string.
-     *
-     * @param str string
-     * @return vTap type
-     */
-    public static OpenstackVtap.Type getVtapTypeFromString(String str) {
-        switch (str) {
-            case "all":
-                return OpenstackVtap.Type.VTAP_ALL;
-            case "tx":
-                return OpenstackVtap.Type.VTAP_TX;
-            case "rx":
-                return OpenstackVtap.Type.VTAP_RX;
-            case "none":
-                return OpenstackVtap.Type.VTAP_NONE;
-            default:
-                throw new IllegalArgumentException("Invalid vTap type string");
-        }
-    }
-
-    /**
      * Obtains IP protocol type from the given string.
      *
-     * @param str string
-     * @return vTap type
+     * @param str protocol string
+     * @return IP protocol number
      */
     public static byte getProtocolTypeFromString(String str) {
         switch (str) {
@@ -68,12 +63,132 @@
                 return IPv4.PROTOCOL_UDP;
             case "icmp":
                 return IPv4.PROTOCOL_ICMP;
-            default:
+            case "any":
                 return 0;
+            default:
+                throw new IllegalArgumentException("Invalid vtap protocol string");
         }
     }
 
+    /**
+     * Obtains openstack vtap type from the given string.
+     *
+     * @param str vtap type string
+     * @return vtap type
+     */
+    public static OpenstackVtap.Type getVtapTypeFromString(String str) {
+        switch (str) {
+            case "all":
+                return OpenstackVtap.Type.VTAP_ALL;
+            case "rx":
+                return OpenstackVtap.Type.VTAP_RX;
+            case "tx":
+                return OpenstackVtap.Type.VTAP_TX;
+            case "any":
+                return OpenstackVtap.Type.VTAP_ANY;
+            default:
+                throw new IllegalArgumentException("Invalid vtap type string");
+        }
+    }
+
+    /**
+     * Checks whether the given IP address is included in vtap criterion with
+     * TX and RX directions by given vtap type.
+     *
+     * @param type      vtap type
+     * @param criterion vtap criterion
+     * @param ip        IP address to check
+     * @return true on match address, false otherwise
+     */
+    public static boolean containsIp(OpenstackVtap.Type type, OpenstackVtapCriterion criterion, IpAddress ip) {
+        boolean isTxEdge = type.isValid(OpenstackVtap.Type.VTAP_TX) &&
+                criterion.srcIpPrefix().contains(ip);
+        boolean isRxEdge = type.isValid(OpenstackVtap.Type.VTAP_RX) &&
+                criterion.dstIpPrefix().contains(ip);
+        return isTxEdge || isRxEdge;
+    }
+
+    /**
+     * Checks the host validation from annotation information.
+     *
+     * @param host host to check
+     * @return true on validate, false otherwise
+     */
+    public static boolean isValidHost(Host host) {
+        return !host.ipAddresses().isEmpty() &&
+                host.annotations().value(ANNOTATION_NETWORK_ID) != null &&
+                host.annotations().value(ANNOTATION_PORT_ID) != null;
+    }
+
+    /**
+     * Checks whether the given IP prefix is contained in the first host rather
+     * than in the second host.
+     *
+     * @param host1     first host instance
+     * @param host2     second host instance
+     * @param ipPrefix  IP prefix to be looked up
+     * @return a negative integer, zero, or a positive integer as the
+     *         first argument is less than, equal to, or greater than the
+     *         second.
+     */
+    public static int hostCompareIp(Host host1, Host host2, IpPrefix ipPrefix) {
+        if ((host1 == null || host1.ipAddresses().stream().noneMatch(ipPrefix::contains)) &&
+                (host2 != null || host2.ipAddresses().stream().anyMatch(ipPrefix::contains))) {
+            return -1;
+        } else if ((host1 != null && host1.ipAddresses().stream().anyMatch(ipPrefix::contains)) &&
+                (host2 == null || host2.ipAddresses().stream().noneMatch(ipPrefix::contains))) {
+            return 1;
+        }
+        return 0;
+    }
+
+    /**
+     * Obtains flow group key from the given id.
+     *
+     * @param groupId flow group identifier
+     * @return flow group key
+     */
     public static GroupKey getGroupKey(int groupId) {
         return new DefaultGroupKey((VTAP_GROUP_KEY + Integer.toString(groupId)).getBytes());
     }
+
+    /**
+     * Obtains tunnel interface name from the given openstack vtap network mode.
+     *
+     * @param mode vtap network mode
+     * @return tunnel interface name
+     */
+    public static String getTunnelName(OpenstackVtapNetwork.Mode mode) {
+        switch (mode) {
+            case GRE:
+                return VTAP_TUNNEL_GRE;
+            case VXLAN:
+                return VTAP_TUNNEL_VXLAN;
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Obtains tunnel description type from the given openstack vtap network mode.
+     *
+     * @param mode vtap network mode
+     * @return tunnel description type
+     */
+    public static TunnelDescription.Type getTunnelType(OpenstackVtapNetwork.Mode mode) {
+        return TunnelDescription.Type.valueOf(mode.toString());
+    }
+
+    /**
+     * Print stack trace of given exception.
+     *
+     * @param log logger for using print
+     * @param e   exception to print
+     */
+    public static void dumpStackTrace(Logger log, Exception e) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        e.printStackTrace(new PrintStream(outputStream));
+        log.error("\n{}", new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
+    }
+
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java
index 905d1c4..b9a3906 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java
@@ -15,6 +15,6 @@
  */
 
 /**
- * Openstack vTap utility package.
+ * Utility package that used in openstack vtap app.
  */
 package org.onosproject.openstackvtap.util;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkCodecRegister.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkCodecRegister.java
new file mode 100644
index 0000000..509a286
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkCodecRegister.java
@@ -0,0 +1,57 @@
+/*
+ * 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.openstackvtap.web;
+
+
+
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.codec.CodecService;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.openstackvtap.codec.OpenstackVtapNetworkCodec;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the JSON codec brokering service for openstack vtap network.
+ */
+@Service
+@Component(immediate = true)
+public class OpenstackVtapNetworkCodecRegister {
+
+    private final org.slf4j.Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected CodecService codecService;
+
+    @Activate
+    protected void activate() {
+        codecService.registerCodec(OpenstackVtapNetwork.class, new OpenstackVtapNetworkCodec());
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        codecService.unregisterCodec(OpenstackVtapNetwork.class);
+
+        log.info("Stopped");
+    }
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkWebResource.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkWebResource.java
new file mode 100644
index 0000000..3900bbd
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkWebResource.java
@@ -0,0 +1,165 @@
+/*
+ * 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.openstackvtap.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+import static org.onlab.util.Tools.readTreeFromStream;
+
+/**
+ * Handles REST API call of openstack vtap network.
+ */
+@Path("vtap-network")
+public class OpenstackVtapNetworkWebResource extends AbstractWebResource {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final String MESSAGE_NETWORK = "Received openstackVtapNetwork {} request";
+    private static final String ERROR_DUPLICATE = "Already has data {}";
+    private static final String ERROR_NOTFOUND = "No data to update {}";
+    private static final String CREATE = "CREATE";
+    private static final String READ = "READ";
+    private static final String UPDATE = "UPDATE";
+    private static final String DELETE = "DELETE";
+
+    private static final String NETWORK = "network";
+
+    private final OpenstackVtapAdminService vtapAdminService = get(OpenstackVtapAdminService.class);
+
+    /**
+     * Creates a openstack vtap network from the JSON input stream.
+     *
+     * @param input openstack vtap network JSON input stream
+     * @return 200 OK if the JSON is correct
+     *         400 BAD_REQUEST if the JSON is malformed
+     *         409 CONFLICT if already the vtap network exists
+     * @onos.rsModel OpenstackVtapNetwork
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createNetwork(InputStream input) {
+        log.info(MESSAGE_NETWORK, CREATE);
+
+        OpenstackVtapNetwork vtapNetwork = readNetworkConfiguration(input);
+        if (vtapNetwork == null) {
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
+
+        if (vtapAdminService.createVtapNetwork(vtapNetwork.mode(),
+                vtapNetwork.networkId(), vtapNetwork.serverIp()) == null) {
+            log.warn(ERROR_DUPLICATE, vtapNetwork);
+            return Response.status(Response.Status.CONFLICT).build();
+        }
+        return Response.ok().build();
+    }
+
+    /**
+     * Updates openstack vtap network from the JSON input stream.
+     *
+     * @param input openstack vtap network JSON input stream
+     * @return 200 OK if the JSON is correct
+     *         400 BAD_REQUEST if the JSON is malformed
+     *         404 NOT_FOUND if vtap network is not exists
+     * @onos.rsModel OpenstackVtapNetwork
+     */
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateNetwork(InputStream input) {
+        log.info(MESSAGE_NETWORK, UPDATE);
+
+        OpenstackVtapNetwork vtapNetwork = readNetworkConfiguration(input);
+        if (vtapNetwork == null) {
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
+
+        if (vtapAdminService.updateVtapNetwork(vtapNetwork) == null) {
+            log.warn(ERROR_NOTFOUND, vtapNetwork);
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+        return Response.ok().build();
+    }
+
+    /**
+     * Get openstack vtap network.
+     *
+     * @return 200 OK with openstack vtap network
+     *         404 NOT_FOUND if openstackvtap network is not exists
+     * @onos.rsModel OpenstackVtapNetwork
+     */
+    @GET
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getNetwork() {
+        log.info(MESSAGE_NETWORK, READ);
+
+        OpenstackVtapNetwork vtapNetwork = vtapAdminService.getVtapNetwork();
+        if (vtapNetwork == null) {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        JsonNode jsonNode = codec(OpenstackVtapNetwork.class).encode(vtapNetwork, this);
+        return Response.ok(jsonNode, MediaType.APPLICATION_JSON_TYPE).build();
+    }
+
+    /**
+     * Removes openstack network.
+     *
+     * @return 200 OK on removing success
+     *         404 NOT_FOUND if openstackvtap network is not exists
+     * @onos.rsModel OpenstackVtapNetwork
+     */
+    @DELETE
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response deleteNetwork() {
+        log.info(MESSAGE_NETWORK, DELETE);
+
+        if (vtapAdminService.removeVtapNetwork() == null) {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        return Response.ok().build();
+    }
+
+    private OpenstackVtapNetwork readNetworkConfiguration(InputStream input) {
+        try {
+            JsonNode jsonTree = readTreeFromStream(mapper().enable(INDENT_OUTPUT), input);
+            ObjectNode vtap = (ObjectNode) jsonTree.get(NETWORK);
+            return codec(OpenstackVtapNetwork.class).decode(vtap, this);
+        } catch (Exception e) {
+            log.error(e.toString());
+            return null;
+        }
+    }
+
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java
index 5d0caf2..96aa9a7 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java
@@ -20,11 +20,12 @@
 import java.util.Set;
 
 /**
- * Openstack vTap REST APIs web application.
+ * Openstack vtap REST APIs web application.
  */
 public class OpenstackVtapWebApplication extends AbstractWebApplication {
     @Override
     public Set<Class<?>> getClasses() {
-        return getClasses(OpenstackVtapWebResource.class);
+        return getClasses(OpenstackVtapWebResource.class,
+                OpenstackVtapNetworkWebResource.class);
     }
 }
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java
index 89468ac..f4c3084 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java
@@ -36,8 +36,6 @@
      * OpenstackVtapServiceImpl method.
      *
      * @return 200 OK
-     *
-     * @onos.rsModel dummy
      */
     @GET
     @Produces(MediaType.APPLICATION_JSON)
diff --git a/apps/openstackvtap/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/openstackvtap/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index c3fa886..7fd8ccf 100644
--- a/apps/openstackvtap/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/openstackvtap/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -42,7 +42,7 @@
         </command>
 
         <command>
-            <action class="org.onosproject.openstackvtap.cli.OpenstackVtapOutputCommand" />
+            <action class="org.onosproject.openstackvtap.cli.OpenstackVtapNetworkListCommand" />
         </command>
     </command-bundle>
 
diff --git a/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.css b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.css
new file mode 100644
index 0000000..2595410
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.css
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- OpenstackVtap -- CSS file
+ */
+
+/* --- Topo Vtap Panel --- */
+#topo-p-vtap {
+    padding: 16px;
+    top: 190px;
+    left: 20px;
+}
+
+.topo-p td input.number-input {
+    width: 50px;
+}
+
+.topo-p div.footer tbody {
+    float: right;
+}
+
+.topo-p div.footer tbody input.button-input {
+    background-color: #5b99d2;
+    border: 0;
+    border-radius: 3px;
+    color: #fff;
+    height: 25px;
+    width: 60px;
+    padding: 1px 0 0 0;
+}
+
+#vtap-dialog {
+    padding: 16px;
+    top: 190px;
+    left: 20px;
+}
diff --git a/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.html b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.html
new file mode 100644
index 0000000..f1a1b72
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.html
@@ -0,0 +1,4 @@
+<!-- partial HTML -->
+<div id="ov-openstackvtap">
+    <p>This is a hidden view .. just a placeholder to house the javascript</p>
+</div>
diff --git a/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.js b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.js
new file mode 100644
index 0000000..9b20eb0
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.js
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Openstack Vtap View Module
+ */
+(function () {
+    'use strict';
+
+    // injected refs
+    var $log, tov, ovts, fs, wss, tts, api, gs, ps, ds;
+
+    // constants
+    var pCls = 'topo-p',
+        idVta = 'topo-p-vtap',
+        idVDi = 'vtap-dialog',
+        vtapPanelOpts = {
+            edge: 'left',
+            width: 330, // vtap panel width
+        }
+
+    // panels
+    var vtap;
+
+    // selected info
+    var selectedItem;
+
+    // constants
+    var osvIsActReq = 'openstackVtapIsActivatedRequest',
+        osvIsActResp =  'openstackVtapIsActivatedResponse',
+        osvCreateReq = 'openstackVtapCreateRequest',
+        osvCreateResp = 'openstackVtapCreateResponse';
+
+    // function to be replaced by the localization bundle function
+    var topoLion = function (x) {
+        return '#ttrafov#' + x + '#';
+    };
+
+    var overlay = {
+        overlayId: 'vtap-overlay',
+        glyphId: 'm_details',
+        tooltip: 'Openstack Vtap Overlay',
+
+        activate: function () {
+            $log.debug("Openstack Vtap topology overlay ACTIVATED");
+        },
+        deactivate: function () {
+            destroyVtapPanel();
+            $log.debug("Openstack Vtap topology overlay DEACTIVATED");
+        },
+
+        // detail panel button definitions
+        buttons: {
+            createHostVtapBtn: {
+                gid: 'm_details',
+                tt: 'Create Host-to-Host Vtap',
+                cb: displayVtap
+            },
+            showRelatedTraffic: {
+                gid: 'm_relatedIntents',
+                tt: function () { return topoLion('tr_btn_show_related_traffic'); },
+                cb: function (data) { tts.showRelatedIntents(); },
+            },
+        },
+
+        hooks: {
+            multi: function (selectOrder) {
+                var selectedHost = new Object();
+                for (var index in selectOrder) {
+                    if (index == 0) {
+                        selectedHost.src = selectOrder[index];
+                    } else if (index == 1) {
+                        selectedHost.dst = selectOrder[index];
+                    }
+                }
+
+                selectedItem = selectedHost;
+
+                tov.addDetailButton('showRelatedTraffic');
+                if(selectOrder.length == 2) {
+                    tov.addDetailButton('createHostVtapBtn');
+                }
+            }
+        }
+    };
+
+    // Panel API
+    function createTopoPanel(id, opts) {
+        var p = ps.createPanel(id, opts),
+            pid = id,
+            header, body, footer;
+        p.classed(pCls, true);
+
+        function panel() {
+            return p;
+        }
+
+        function hAppend(x) {
+            return header.append(x);
+        }
+
+        function bAppend(x) {
+            return body.append(x);
+        }
+
+        function fAppend(x) {
+            return footer.append(x);
+        }
+
+        function setup() {
+            p.empty();
+
+            p.append('div').classed('header', true);
+            p.append('div').classed('body', true);
+            p.append('div').classed('footer', true);
+
+            header = p.el().select('.header');
+            body = p.el().select('.body');
+            footer = p.el().select('.footer');
+        }
+
+        function destroy() {
+            ps.destroyPanel(pid);
+        }
+
+        return {
+            panel: panel,
+            setup: setup,
+            destroy: destroy,
+            appendHeader: hAppend,
+            appendBody: bAppend,
+            appendFooter: fAppend,
+        };
+    }
+
+    function hideVtapPanel() {
+        vtap.panel().hide();
+    }
+
+    function destroyVtapPanel() {
+        if(vtap != null) {
+            vtap.destroy();
+        }
+        vtap = null;
+    }
+
+    function addInput(tbody, type, id, label, value) {
+        var tr = tbody.append('tr'),
+            lab;
+        if (typeof label === 'string') {
+            lab = label.replace(/_/g, ' ');
+        } else {
+            lab = label;
+        }
+
+        tr.append('td').attr('class', 'label').text(lab + ' :');
+
+        if (type == 'radio') {
+            var td = tr.append('td');
+            for(var index in value) {
+                if(index == 0) {
+                    td.append('input').classed( type + '-input', true)
+                                          .attr('type', type)
+                                          .attr('value', value[index])
+                                          .attr('name', label)
+                                          .attr('id', id)
+                                          .attr('checked', 'true');
+                } else {
+                    td.append('input').classed( type + '-input', true)
+                                          .attr('type', type)
+                                          .attr('name', label)
+                                          .attr('id', id)
+                                          .attr('value', value[index]);
+                }
+                td.append('span').text(value[index]);
+            }
+        } else {
+            tr.append('td').append('input').classed(type + '-input', true).attr('type', type)
+                .attr('id', id).attr('value', value);
+        }
+    }
+
+    function addButton(tr, callback, value) {
+        tr.append('td').append('input').classed('button-input', true).attr('type', 'button')
+                        .attr('value', value).on('click', callback);
+    }
+
+    function makeButton(callback, text, keyName) {
+        var cb = fs.isF(callback),
+            key = fs.isS(keyName);
+
+        function invoke() {
+            cb && cb();
+        }
+
+        return createDiv('vtap-button')
+            .text(text)
+            .on('click', invoke);
+    }
+
+    function createDiv(cls) {
+        var div = d3.select(document.createElement('div'));
+        if (cls) {
+            div.classed(cls, true);
+        }
+        return div;
+    }
+
+    function addInput(tbody, type, id, label, value) {
+        var tr = tbody.append('tr'),
+            lab;
+        if (typeof label === 'string') {
+            lab = label.replace(/_/g, ' ');
+        } else {
+            lab = label;
+        }
+
+        tr.append('td').attr('class', 'label').text(lab + ' :');
+
+        if (type == 'radio') {
+            var td = tr.append('td');
+            for(var index in value) {
+                if(index == 0) {
+                    td.append('input').classed( type + '-input', true)
+                                          .attr('type', type)
+                                          .attr('value', value[index])
+                                          .attr('name', label)
+                                          .attr('id', id)
+                                          .attr('checked', 'true');
+                } else {
+                    td.append('input').classed( type + '-input', true)
+                                          .attr('type', type)
+                                          .attr('name', label)
+                                          .attr('id', id)
+                                          .attr('value', value[index]);
+                }
+                td.append('span').text(value[index]);
+            }
+        } else {
+            tr.append('td').append('input').classed(type + '-input', true).attr('type', type)
+                .attr('id', id).attr('value', value);
+        }
+    }
+
+    function addButton(tr, callback, value) {
+        tr.append('td').append('input').classed('button-input', true).attr('type', 'button')
+                        .attr('value', value).on('click', callback);
+    }
+
+    function makeButton(callback, text, keyName) {
+        var cb = fs.isF(callback),
+            key = fs.isS(keyName);
+
+        function invoke() {
+            cb && cb();
+        }
+
+        return createDiv('vtap-button')
+            .text(text)
+            .on('click', invoke);
+    }
+
+    function createDiv(cls) {
+        var div = d3.select(document.createElement('div'));
+        if (cls) {
+            div.classed(cls, true);
+        }
+        return div;
+    }
+
+    function displayVtap() {
+        $log.debug("sendEvent openstackVtapIsActivatedRequest: ", selectedItem);
+        wss.sendEvent(osvIsActReq, selectedItem);
+    }
+
+    function respIsActCb(selected) {
+        $log.debug("openstackVtapIsActivatedResponse: ", selected);
+        if(vtap == null) {
+            vtap = createTopoPanel(idVta, vtapPanelOpts);
+        }
+        vtap.setup();
+
+        var svg = vtap.appendHeader('div')
+                     .classed('icon', true)
+                     .append('svg'),
+            title = vtap.appendHeader('h2'),
+            table = vtap.appendBody('table'),
+            tbody = table.append('tbody'),
+            glyphId = 'm_details';
+
+        gs.addGlyph(svg, glyphId, 30, 0, [1, 1]);
+
+        title.text('Create OpenstackVtap');
+
+        addInput(tbody, 'text', 'srcIp', 'Source IP', selected.srcName);
+        addInput(tbody, 'text', 'dstIp', 'Destination IP', selected.dstName);
+        addInput(tbody, 'radio', 'ipProto', 'Protocol', selected.ipProtoList);
+        addInput(tbody, 'number', 'srcPort', 'Source Port', "");
+        addInput(tbody, 'number', 'dstPort', 'Destination Port', "");
+        addInput(tbody, 'radio', 'vtapType', 'Type', selected.vtapTypeList);
+
+        vtap.appendFooter('hr');
+        var footTr = vtap.appendFooter('table').append('tbody').append('tr');
+
+        addButton(footTr, createVtap, 'Create');
+        addButton(footTr, hideVtapPanel, 'Cancel');
+
+        vtap.panel().show();
+    }
+
+    function createVtap() {
+        var vtapInfo = {};
+
+        vtapInfo.srcIp = document.getElementById('srcIp').value;
+        vtapInfo.dstIp = document.getElementById('dstIp').value;
+        vtapInfo.ipProto = document.querySelector('input[name="Protocol"]:checked').value;
+        vtapInfo.srcPort = document.getElementById('srcPort').value;
+        vtapInfo.dstPort = document.getElementById('dstPort').value;
+        vtapInfo.vtapType = document.querySelector('input[name="Type"]:checked').value;
+
+        if(vtapInfo.srcPort == ""){
+            vtapInfo.srcPort = 0;
+        }
+        if(vtapInfo.dstPort == ""){
+            vtapInfo.dstPort = 0;
+        }
+
+        $log.debug("sendEvent openstackVtapCreateRequest: ", vtapInfo);
+        wss.sendEvent(osvCreateReq, vtapInfo);
+        hideVtapPanel();
+
+    }
+
+    function respCreateCb(result) {
+        $log.debug("respCreateCb: ", result);
+
+        function dOK() {
+            if(result.result == "Failed"){
+                displayVtap(selectedItem);
+            } else {
+                destroyVtapPanel();
+            }
+        }
+
+        function createContent(value) {
+            var content = ds.createDiv();
+            content.append('p').text(value);
+            return content;
+        }
+
+        ds.openDialog(idVDi, vtapPanelOpts)
+            .setTitle("Create Vtap " + result.result)
+            .addContent(createContent(result.value))
+            .addOk(dOK);
+    }
+
+    // invoke code to register with the overlay service
+    angular.module('ovOpenstackvtap', [])
+        .factory('OpenstackVtapTopovService',
+        ['$log', 'FnService', 'WebSocketService', 'GlyphService', 'PanelService', 'DialogService',
+
+        function (_$log_, _fs_, _wss_, _gs_, _ps_, _ds_) {
+            $log = _$log_;
+            fs = _fs_;
+            wss = _wss_;
+            gs = _gs_;
+            ps = _ps_;
+            ds = _ds_;
+
+            var handlers = {},
+                vtapOverlay = 'vtap-overlay',
+                defaultOverlay = 'traffic';
+
+            handlers[osvIsActResp] = respIsActCb;
+            handlers[osvCreateResp] = respCreateCb;
+
+            wss.bindHandlers(handlers);
+
+            return {
+                displayVtap: displayVtap
+            };
+        }])
+        .run(['$log', 'TopoOverlayService', 'OpenstackVtapTopovService', 'TopoTrafficService',
+
+            function (_$log_, _tov_, _ovts_, _tts_) {
+                $log = _$log_;
+                tov = _tov_;
+                ovts = _ovts_;
+                tts = _tts_;
+                tov.register(overlay);
+            }]
+        );
+}());
diff --git a/apps/openstackvtap/app/src/main/resources/definitions/OpenstackVtapNetwork.json b/apps/openstackvtap/app/src/main/resources/definitions/OpenstackVtapNetwork.json
new file mode 100644
index 0000000..32fa001
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/definitions/OpenstackVtapNetwork.json
@@ -0,0 +1,30 @@
+{
+  "type": "object",
+  "required": [
+    "network"
+  ],
+  "properties": {
+    "network": {
+      "type": "object",
+      "required": [
+        "mode",
+        "networkId",
+        "serverIp"
+      ],
+      "properties": {
+        "mode": {
+          "type": "string",
+          "example": "GRE"
+        },
+        "networkId": {
+          "type": "int",
+          "example": 1000
+        },
+        "serverIp": {
+          "type": "string",
+          "example": "10.20.0.1"
+        }
+      }
+    }
+  }
+}
diff --git a/apps/openstackvtap/app/src/main/resources/definitions/dummy.json b/apps/openstackvtap/app/src/main/resources/definitions/dummy.json
deleted file mode 100644
index 7a73a41..0000000
--- a/apps/openstackvtap/app/src/main/resources/definitions/dummy.json
+++ /dev/null
@@ -1,2 +0,0 @@
-{
-}
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/resources/gui/css.html b/apps/openstackvtap/app/src/main/resources/gui/css.html
new file mode 100644
index 0000000..9c1889b
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/gui/css.html
@@ -0,0 +1 @@
+<link rel="stylesheet" href="app/view/openstackvtap/openstackvtap.css">
diff --git a/apps/openstackvtap/app/src/main/resources/gui/js.html b/apps/openstackvtap/app/src/main/resources/gui/js.html
new file mode 100644
index 0000000..46a4bb4
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/gui/js.html
@@ -0,0 +1 @@
+<script src="app/view/openstackvtap/openstackvtap.js"></script>
diff --git a/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml b/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
index 8b44537..109fbe7 100644
--- a/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
@@ -18,7 +18,7 @@
          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 vTap REST API v1.0</display-name>
+    <display-name>Openstack Vtap REST API v1.0</display-name>
 
     <security-constraint>
         <web-resource-collection>
diff --git a/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java b/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java
index fd9fbf5..412d1d6 100644
--- a/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java
+++ b/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java
@@ -34,8 +34,8 @@
  */
 public class DefaultOpenstackVtapTest {
 
-    private static final OpenstackVtapId VTAP_ID_1 = OpenstackVtapId.vTapId();
-    private static final OpenstackVtapId VTAP_ID_2 = OpenstackVtapId.vTapId();
+    private static final OpenstackVtapId VTAP_ID_1 = OpenstackVtapId.vtapId();
+    private static final OpenstackVtapId VTAP_ID_2 = OpenstackVtapId.vtapId();
 
     private static final OpenstackVtap.Type VTAP_TYPE_1 = OpenstackVtap.Type.VTAP_TX;
     private static final OpenstackVtap.Type VTAP_TYPE_2 = OpenstackVtap.Type.VTAP_RX;
@@ -74,10 +74,9 @@
         vtap1 = builder1
                     .id(VTAP_ID_1)
                     .type(VTAP_TYPE_1)
-                    .vTapCriterion(CRITERION_1)
+                    .vtapCriterion(CRITERION_1)
                     .txDeviceIds(Sets.newHashSet())
                     .rxDeviceIds(Sets.newHashSet())
-                    .annotations()
                     .build();
 
         OpenstackVtap.Builder builder2 = DefaultOpenstackVtap.builder();
@@ -85,10 +84,9 @@
         sameAsVtap1 = builder2
                         .id(VTAP_ID_1)
                         .type(VTAP_TYPE_1)
-                        .vTapCriterion(CRITERION_1)
+                        .vtapCriterion(CRITERION_1)
                         .txDeviceIds(Sets.newHashSet())
                         .rxDeviceIds(Sets.newHashSet())
-                        .annotations()
                         .build();
 
         OpenstackVtap.Builder builder3 = DefaultOpenstackVtap.builder();
@@ -96,10 +94,9 @@
         vtap2 = builder3
                     .id(VTAP_ID_2)
                     .type(VTAP_TYPE_2)
-                    .vTapCriterion(CRITERION_2)
+                    .vtapCriterion(CRITERION_2)
                     .txDeviceIds(Sets.newHashSet())
                     .rxDeviceIds(Sets.newHashSet())
-                    .annotations()
                     .build();
 
     }
@@ -116,7 +113,7 @@
         DefaultOpenstackVtap vtap = (DefaultOpenstackVtap) vtap1;
 
         assertThat(vtap.id(), is(VTAP_ID_1));
-        assertThat(vtap.vTapCriterion(), is(CRITERION_1));
+        assertThat(vtap.vtapCriterion(), is(CRITERION_1));
         assertThat(vtap.type(), is(VTAP_TYPE_1));
     }
 
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json
index 4c60e76..913e72e 100644
--- a/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json
+++ b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json
@@ -35,6 +35,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding", 5, false]
       ]
     },
@@ -146,7 +147,14 @@
   "header_unions" : [],
   "header_union_stacks" : [],
   "field_lists" : [],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -345,7 +353,13 @@
       "name" : "c_ingress.l2_fwd_counter",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "c_ingress.t_l2_fwd"
+      "binding" : "c_ingress.t_l2_fwd",
+      "source_info" : {
+        "filename" : "mytunnel.p4",
+        "line" : 189,
+        "column" : 50,
+        "source_fragment" : "l2_fwd_counter"
+      }
     }
   ],
   "register_arrays" : [],
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 d37b466..f672e0b 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
@@ -138,6 +138,10 @@
         ResourceData receivedData = convertJsonToDataNode(rl.uriForYangRuntime(), rootNode);
         ResourceId rid = receivedData.resourceId();
         List<DataNode> dataNodeList = receivedData.dataNodes();
+        if (dataNodeList == null || dataNodeList.isEmpty()) {
+            log.warn("There is no one Data Node can be proceed.");
+            return;
+        }
         if (dataNodeList.size() > 1) {
             log.warn("There are more than one Data Node can be proceed: {}", dataNodeList.size());
         }
@@ -173,6 +177,10 @@
         DataResourceLocator rl = DataResourceLocator.newInstance(uri);
         ResourceData receivedData = convertJsonToDataNode(rmLastPathSegment(rl.uriForYangRuntime()), rootNode);
         List<DataNode> dataNodeList = receivedData.dataNodes();
+        if (dataNodeList == null || dataNodeList.isEmpty()) {
+            log.warn("There is no one Data Node can be proceed.");
+            return;
+        }
         if (dataNodeList.size() > 1) {
             log.warn("There are more than one Data Node can be proceed: {}", dataNodeList.size());
         }
@@ -220,6 +228,10 @@
         ResourceData receivedData = convertJsonToDataNode(rmLastPathSegment(rl.uriForYangRuntime()), rootNode);
         ResourceId rid = receivedData.resourceId();
         List<DataNode> dataNodeList = receivedData.dataNodes();
+        if (dataNodeList == null || dataNodeList.isEmpty()) {
+            log.warn("There is no one Data Node can be proceed.");
+            return;
+        }
         if (dataNodeList.size() > 1) {
             log.warn("There are more than one Data Node can be proceed: {}", dataNodeList.size());
         }
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
index fe65e6e..99ff091 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
@@ -495,7 +495,7 @@
             // get path here, need to use the same for fwd and rev direction
             List<Link> path = getPath(pw.l2TunnelPolicy().cP1(),
                                       pw.l2TunnelPolicy().cP2());
-            if (path == null) {
+            if (path == null || path.isEmpty()) {
                 log.error("Deploying process : No path between the connection points for pseudowire {}", l2TunnelId);
                 return PATH_NOT_FOUND.appendError("No path between the connection points for pseudowire!");
             }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java
index 5f68e40..6a848ac 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java
@@ -34,10 +34,10 @@
 @Beta
 public final class PiMulticastGroupEntry implements PiPreEntry {
 
-    private final long groupId;
+    private final int groupId;
     private final Set<PiPreReplica> replicas;
 
-    private PiMulticastGroupEntry(long groupId, Set<PiPreReplica> replicas) {
+    private PiMulticastGroupEntry(int groupId, Set<PiPreReplica> replicas) {
         this.groupId = groupId;
         this.replicas = replicas;
     }
@@ -48,7 +48,7 @@
      *
      * @return group entry ID
      */
-    public long groupId() {
+    public int groupId() {
         return groupId;
     }
 
@@ -111,7 +111,7 @@
      */
     public static final class Builder {
 
-        private Long groupId;
+        private Integer groupId;
         private ImmutableSet.Builder<PiPreReplica> replicaSetBuilder = ImmutableSet.builder();
 
         private Builder() {
@@ -124,7 +124,7 @@
          * @param groupId group ID
          * @return this
          */
-        public Builder withGroupId(long groupId) {
+        public Builder withGroupId(int groupId) {
             this.groupId = groupId;
             return this;
         }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java
index ea7003d..b661d27 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java
@@ -32,7 +32,7 @@
 public class PiPreReplica {
 
     private final PortNumber egressPort;
-    private final long instanceId;
+    private final int instanceId;
 
     /**
      * Returns a new PRE packet replica for the given egress port and instance
@@ -41,7 +41,7 @@
      * @param egressPort egress port
      * @param instanceId instance ID
      */
-    public PiPreReplica(PortNumber egressPort, long instanceId) {
+    public PiPreReplica(PortNumber egressPort, int instanceId) {
         this.egressPort = checkNotNull(egressPort);
         this.instanceId = instanceId;
     }
@@ -60,7 +60,7 @@
      *
      * @return instance ID
      */
-    public long instanceId() {
+    public int instanceId() {
         return instanceId;
     }
 
diff --git a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryTest.java b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryTest.java
index 7c060ef..049a902 100644
--- a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryTest.java
+++ b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryTest.java
@@ -28,10 +28,10 @@
  * Tests for {@link PiMulticastGroupEntry}.
  */
 public class PiMulticastGroupEntryTest {
-    private final long groupId1 = 1;
-    private final long groupId2 = 2;
+    private final int groupId1 = 1;
+    private final int groupId2 = 2;
 
-    private final long instanceId1 = 1;
+    private final int instanceId1 = 1;
 
     private final PortNumber port1 = PortNumber.portNumber(1);
     private final PortNumber port2 = PortNumber.portNumber(2);
diff --git a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiPreReplicaTest.java b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiPreReplicaTest.java
index 85ea36e..ef6e7d8 100644
--- a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiPreReplicaTest.java
+++ b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiPreReplicaTest.java
@@ -28,8 +28,8 @@
  */
 public class PiPreReplicaTest {
 
-    private final long instanceId1 = 1;
-    private final long instanceId2 = 2;
+    private final int instanceId1 = 1;
+    private final int instanceId2 = 2;
     private final PortNumber port1 = PortNumber.portNumber(1);
     private final PortNumber port2 = PortNumber.portNumber(2);
 
diff --git a/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java b/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
index 13cc403..c0b3beb 100644
--- a/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
+++ b/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
@@ -560,7 +560,9 @@
                 // assume that we can always fallback to default icon
                 iconStream = ApplicationArchive.class.getResourceAsStream("/" + APP_PNG);
             }
-            return ByteStreams.toByteArray(iconStream);
+            byte[] icon = ByteStreams.toByteArray(iconStream);
+            iconStream.close();
+            return icon;
         } catch (IOException e) {
             log.warn("Unable to read app icon for app {}", appName, e);
         }
diff --git a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
index 0f6a5ac..ed01c24 100644
--- a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
+++ b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
@@ -446,9 +446,9 @@
                 case DEVICE_AVAILABILITY_CHANGED:
                     DeviceId deviceId = event.subject().id();
                     if (!deviceService.isAvailable(deviceId)) {
-                        log.debug("Device {} became unavailable; clearing initial audit status",
-                                event.type(), event.subject().id());
-                        store.deviceInitialAuditCompleted(event.subject().id(), false);
+                        log.debug("Device {} became unavailable for {}; clearing initial audit status",
+                                deviceId, event.type());
+                        store.deviceInitialAuditCompleted(deviceId, false);
 
                         if (purgeOnDisconnection) {
                             store.purgeGroupEntry(deviceId);
diff --git a/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java b/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java
index ffe5a56..716795b 100644
--- a/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java
+++ b/core/net/src/main/java/org/onosproject/net/meter/impl/MeterManager.java
@@ -199,7 +199,7 @@
 
     @Override
     public Meter submit(MeterRequest request) {
-
+        checkNotNull(request, "request cannot be null.");
         MeterId id = allocateMeterId(request.deviceId());
 
         Meter.Builder mBuilder = DefaultMeter.builder()
@@ -221,6 +221,7 @@
 
     @Override
     public void withdraw(MeterRequest request, MeterId meterId) {
+        checkNotNull(request, "request cannot be null.");
         Meter.Builder mBuilder = DefaultMeter.builder()
                 .forDevice(request.deviceId())
                 .fromApp(request.appId())
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/atomix/cluster/impl/AtomixClusterStore.java b/core/store/primitives/src/main/java/org/onosproject/store/atomix/cluster/impl/AtomixClusterStore.java
index ec4e8b4..ca82891 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/atomix/cluster/impl/AtomixClusterStore.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/atomix/cluster/impl/AtomixClusterStore.java
@@ -211,7 +211,6 @@
     @Override
     public void markFullyStarted(boolean started) {
         ControllerNode.State state = started ? ControllerNode.State.READY : ControllerNode.State.ACTIVE;
-        states.put(localNode.id(), state);
         membershipService.getLocalMember().properties().setProperty(STATE_KEY, state.name());
     }
 
diff --git a/lib/BUCK b/lib/BUCK
index d799e21..7c56626 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -1,5 +1,6 @@
 <<<<<<< HEAD
 <<<<<<< HEAD
+<<<<<<< HEAD
 # ***** This file was auto-generated at Tue, 18 Sep 2018 20:31:36 GMT. Do not edit this file manually. *****
 =======
 # ***** This file was auto-generated at Thu, 27 Sep 2018 15:25:26 GMT. Do not edit this file manually. *****
@@ -7,6 +8,9 @@
 =======
 # ***** This file was auto-generated at Fri, 5 Oct 2018 20:40:12 GMT. Do not edit this file manually. *****
 >>>>>>> master
+=======
+# ***** This file was auto-generated at Fri, 12 Oct 2018 17:49:41 GMT. Do not edit this file manually. *****
+>>>>>>> f4f54a1be000d2aaae7299ed6d26468c7e0e0763
 # ***** Use onos-lib-gen *****
 
 pass_thru_pom(
@@ -250,73 +254,73 @@
 
 remote_jar (
   name = 'atomix',
-  out = 'atomix-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix:jar:3.0.6',
-  sha1 = 'a8c1401b9f5d3757c8cfa2b7905d928825507cf8',
-  maven_coords = 'io.atomix:atomix:3.0.6',
+  out = 'atomix-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix:jar:3.0.7',
+  sha1 = 'd2c0cdbdc4e7c242d1fe476892fdbc31a1468d43',
+  maven_coords = 'io.atomix:atomix:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'atomix-cluster',
-  out = 'atomix-cluster-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix-cluster:jar:3.0.6',
-  sha1 = '8d91e0caf5c2739476826b32bdcf21afc32bf433',
-  maven_coords = 'io.atomix:atomix-cluster:3.0.6',
+  out = 'atomix-cluster-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix-cluster:jar:3.0.7',
+  sha1 = '1bf4ca3d10f8be0c87588b531a200d982ef6f1a3',
+  maven_coords = 'io.atomix:atomix-cluster:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'atomix-gossip',
-  out = 'atomix-gossip-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix-gossip:jar:3.0.6',
-  sha1 = '5db475ea2702fabfb8eb19079bc07979bc706c17',
-  maven_coords = 'io.atomix:atomix-gossip:3.0.6',
+  out = 'atomix-gossip-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix-gossip:jar:3.0.7',
+  sha1 = 'c702172c4d77cea0fb95ad953ee36c2bae73db34',
+  maven_coords = 'io.atomix:atomix-gossip:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'atomix-primary-backup',
-  out = 'atomix-primary-backup-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix-primary-backup:jar:3.0.6',
-  sha1 = 'af3a4475a54a83fe8eafd58925c04db608eec150',
-  maven_coords = 'io.atomix:atomix-primary-backup:3.0.6',
+  out = 'atomix-primary-backup-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix-primary-backup:jar:3.0.7',
+  sha1 = 'b5269c7bc1172966928ec14af098f02c65c78c97',
+  maven_coords = 'io.atomix:atomix-primary-backup:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'atomix-primitive',
-  out = 'atomix-primitive-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix-primitive:jar:3.0.6',
-  sha1 = 'bb65acf0dd5e805ffc27f0f768e2fe5310d83a71',
-  maven_coords = 'io.atomix:atomix-primitive:3.0.6',
+  out = 'atomix-primitive-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix-primitive:jar:3.0.7',
+  sha1 = '41c55b48913ceffecaa846395e19dbe2e959d145',
+  maven_coords = 'io.atomix:atomix-primitive:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'atomix-raft',
-  out = 'atomix-raft-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix-raft:jar:3.0.6',
-  sha1 = 'f3497269b021f8794ba26296f6779977fd213f0e',
-  maven_coords = 'io.atomix:atomix-raft:3.0.6',
+  out = 'atomix-raft-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix-raft:jar:3.0.7',
+  sha1 = '9b294e0568df35d1a58971b2748426da7d13e849',
+  maven_coords = 'io.atomix:atomix-raft:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'atomix-storage',
-  out = 'atomix-storage-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix-storage:jar:3.0.6',
-  sha1 = '0cebbfd8932c7ed27d173d9f3487687317905f5d',
-  maven_coords = 'io.atomix:atomix-storage:3.0.6',
+  out = 'atomix-storage-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix-storage:jar:3.0.7',
+  sha1 = '451575082ad5bd0257372bd34c29ac0bf1120133',
+  maven_coords = 'io.atomix:atomix-storage:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'atomix-utils',
-  out = 'atomix-utils-3.0.6.jar',
-  url = 'mvn:io.atomix:atomix-utils:jar:3.0.6',
-  sha1 = 'd99e63b9df25b59baea5c2fedbd6ad9dab6de59f',
-  maven_coords = 'io.atomix:atomix-utils:3.0.6',
+  out = 'atomix-utils-3.0.7.jar',
+  url = 'mvn:io.atomix:atomix-utils:jar:3.0.7',
+  sha1 = '647aee1cab71c3b816c8a205d0d55bdae9047434',
+  maven_coords = 'io.atomix:atomix-utils:3.0.7',
   visibility = [ 'PUBLIC' ],
 )
 
diff --git a/lib/deps.json b/lib/deps.json
index 8a70512..f08a6cf 100644
--- a/lib/deps.json
+++ b/lib/deps.json
@@ -146,14 +146,14 @@
     "aopalliance-repackaged": "mvn:org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b42",
     "amqp-client": "mvn:com.rabbitmq:amqp-client:jar:3.6.1",
     "asm": "mvn:org.ow2.asm:asm:5.2",
-    "atomix": "mvn:io.atomix:atomix:3.0.5",
-    "atomix-cluster": "mvn:io.atomix:atomix-cluster:3.0.5",
-    "atomix-gossip": "mvn:io.atomix:atomix-gossip:3.0.5",
-    "atomix-primary-backup": "mvn:io.atomix:atomix-primary-backup:3.0.5",
-    "atomix-primitive": "mvn:io.atomix:atomix-primitive:3.0.5",
-    "atomix-raft": "mvn:io.atomix:atomix-raft:3.0.5",
-    "atomix-storage": "mvn:io.atomix:atomix-storage:3.0.5",
-    "atomix-utils": "mvn:io.atomix:atomix-utils:3.0.5",
+    "atomix": "mvn:io.atomix:atomix:3.0.7",
+    "atomix-cluster": "mvn:io.atomix:atomix-cluster:3.0.7",
+    "atomix-gossip": "mvn:io.atomix:atomix-gossip:3.0.7",
+    "atomix-primary-backup": "mvn:io.atomix:atomix-primary-backup:3.0.7",
+    "atomix-primitive": "mvn:io.atomix:atomix-primitive:3.0.7",
+    "atomix-raft": "mvn:io.atomix:atomix-raft:3.0.7",
+    "atomix-storage": "mvn:io.atomix:atomix-storage:3.0.7",
+    "atomix-utils": "mvn:io.atomix:atomix-utils:3.0.7",
     "classgraph": "mvn:io.github.classgraph:classgraph:4.2.3",
     "commons-codec": "mvn:commons-codec:commons-codec:1.10",
     "commons-cli": "mvn:commons-cli:commons-cli:1.3",
diff --git a/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json b/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json
index 5769494..2e428be 100644
--- a/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json
+++ b/pipelines/basic/src/main/resources/p4c-out/bmv2/basic.json
@@ -40,6 +40,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding_0", 5, false]
       ]
     },
@@ -178,7 +179,14 @@
   "header_unions" : [],
   "header_union_stacks" : [],
   "field_lists" : [],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -485,13 +493,25 @@
       "name" : "ingress.table0_control.table0_counter",
       "id" : 1,
       "is_direct" : true,
-      "binding" : "ingress.table0_control.table0"
+      "binding" : "ingress.table0_control.table0",
+      "source_info" : {
+        "filename" : "include/table0.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "table0_counter"
+      }
     },
     {
       "name" : "ingress.wcmp_control.wcmp_table_counter",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "ingress.wcmp_control.wcmp_table"
+      "binding" : "ingress.wcmp_control.wcmp_table",
+      "source_info" : {
+        "filename" : "include/wcmp.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "wcmp_table_counter"
+      }
     },
     {
       "name" : "egress.port_counters_egress.egress_port_counter",
@@ -1338,6 +1358,12 @@
         {
           "name" : "ingress.wcmp_control.wcmp_selector",
           "id" : 0,
+          "source_info" : {
+            "filename" : "include/wcmp.p4",
+            "line" : 28,
+            "column" : 55,
+            "source_fragment" : "wcmp_selector"
+          },
           "max_size" : 64,
           "selector" : {
             "algo" : "crc16",
diff --git a/pipelines/basic/src/main/resources/p4c-out/bmv2/int.json b/pipelines/basic/src/main/resources/p4c-out/bmv2/int.json
index 13a1d41..f83c2ea 100644
--- a/pipelines/basic/src/main/resources/p4c-out/bmv2/int.json
+++ b/pipelines/basic/src/main/resources/p4c-out/bmv2/int.json
@@ -40,6 +40,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding_0", 5, false]
       ]
     },
@@ -388,7 +389,14 @@
   "header_unions" : [],
   "header_union_stacks" : [],
   "field_lists" : [],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -970,43 +978,85 @@
       "name" : "ingress.table0_control.table0_counter",
       "id" : 1,
       "is_direct" : true,
-      "binding" : "ingress.table0_control.table0"
+      "binding" : "ingress.table0_control.table0",
+      "source_info" : {
+        "filename" : "include/table0.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "table0_counter"
+      }
     },
     {
       "name" : "egress.process_set_source_sink.counter_set_source",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "egress.process_set_source_sink.tb_set_source"
+      "binding" : "egress.process_set_source_sink.tb_set_source",
+      "source_info" : {
+        "filename" : "include/int_source.p4",
+        "line" : 90,
+        "column" : 50,
+        "source_fragment" : "counter_set_source"
+      }
     },
     {
       "name" : "egress.process_set_source_sink.counter_set_sink",
       "id" : 3,
       "is_direct" : true,
-      "binding" : "egress.process_set_source_sink.tb_set_sink"
+      "binding" : "egress.process_set_source_sink.tb_set_sink",
+      "source_info" : {
+        "filename" : "include/int_source.p4",
+        "line" : 91,
+        "column" : 50,
+        "source_fragment" : "counter_set_sink"
+      }
     },
     {
       "name" : "egress.process_int_source.counter_int_source",
       "id" : 4,
       "is_direct" : true,
-      "binding" : "egress.process_int_source.tb_int_source"
+      "binding" : "egress.process_int_source.tb_int_source",
+      "source_info" : {
+        "filename" : "include/int_source.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "counter_int_source"
+      }
     },
     {
       "name" : "egress.process_int_transit.counter_int_insert",
       "id" : 5,
       "is_direct" : true,
-      "binding" : "egress.process_int_transit.tb_int_insert"
+      "binding" : "egress.process_int_transit.tb_int_insert",
+      "source_info" : {
+        "filename" : "include/int_transit.p4",
+        "line" : 25,
+        "column" : 50,
+        "source_fragment" : "counter_int_insert"
+      }
     },
     {
       "name" : "egress.process_int_transit.counter_int_inst_0003",
       "id" : 6,
       "is_direct" : true,
-      "binding" : "egress.process_int_transit.tb_int_inst_0003"
+      "binding" : "egress.process_int_transit.tb_int_inst_0003",
+      "source_info" : {
+        "filename" : "include/int_transit.p4",
+        "line" : 26,
+        "column" : 50,
+        "source_fragment" : "counter_int_inst_0003"
+      }
     },
     {
       "name" : "egress.process_int_transit.counter_int_inst_0407",
       "id" : 7,
       "is_direct" : true,
-      "binding" : "egress.process_int_transit.tb_int_inst_0407"
+      "binding" : "egress.process_int_transit.tb_int_inst_0407",
+      "source_info" : {
+        "filename" : "include/int_transit.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "counter_int_inst_0407"
+      }
     },
     {
       "name" : "egress.port_counters_egress.egress_port_counter",
diff --git a/pipelines/fabric/src/main/resources/p4c-out/fabric-full/bmv2/default/bmv2.json b/pipelines/fabric/src/main/resources/p4c-out/fabric-full/bmv2/default/bmv2.json
index c7d78e8..b20a1ff 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/fabric-full/bmv2/default/bmv2.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/fabric-full/bmv2/default/bmv2.json
@@ -56,6 +56,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding", 5, false]
       ]
     },
@@ -345,6 +346,8 @@
         ["switch_id", 32, false],
         ["new_words", 8, false],
         ["new_bytes", 16, false],
+        ["ig_tstamp", 32, false],
+        ["eg_tstamp", 32, false],
         ["_padding_1", 5, false]
       ]
     }
@@ -614,7 +617,14 @@
       "elements" : []
     }
   ],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -1529,85 +1539,169 @@
       "name" : "FabricIngress.spgw_ingress.ue_counter",
       "id" : 0,
       "is_direct" : true,
-      "binding" : "FabricIngress.spgw_ingress.dl_sess_lookup"
+      "binding" : "FabricIngress.spgw_ingress.dl_sess_lookup",
+      "source_info" : {
+        "filename" : "include/spgw.p4",
+        "line" : 51,
+        "column" : 50,
+        "source_fragment" : "ue_counter"
+      }
     },
     {
       "name" : "FabricIngress.process_set_source_sink.counter_set_source",
       "id" : 1,
       "is_direct" : true,
-      "binding" : "FabricIngress.process_set_source_sink.tb_set_source"
+      "binding" : "FabricIngress.process_set_source_sink.tb_set_source",
+      "source_info" : {
+        "filename" : "include/int/int_main.p4",
+        "line" : 39,
+        "column" : 50,
+        "source_fragment" : "counter_set_source"
+      }
     },
     {
       "name" : "FabricIngress.process_set_source_sink.counter_set_sink",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "FabricIngress.process_set_source_sink.tb_set_sink"
+      "binding" : "FabricIngress.process_set_source_sink.tb_set_sink",
+      "source_info" : {
+        "filename" : "include/int/int_main.p4",
+        "line" : 58,
+        "column" : 50,
+        "source_fragment" : "counter_set_sink"
+      }
     },
     {
       "name" : "FabricIngress.filtering.ingress_port_vlan_counter",
       "id" : 3,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.ingress_port_vlan"
+      "binding" : "FabricIngress.filtering.ingress_port_vlan",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "ingress_port_vlan_counter"
+      }
     },
     {
       "name" : "FabricIngress.filtering.fwd_classifier_counter",
       "id" : 4,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.fwd_classifier"
+      "binding" : "FabricIngress.filtering.fwd_classifier",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 96,
+        "column" : 50,
+        "source_fragment" : "fwd_classifier_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.bridging_counter",
       "id" : 5,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.bridging"
+      "binding" : "FabricIngress.forwarding.bridging",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "bridging_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.mpls_counter",
       "id" : 6,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.mpls"
+      "binding" : "FabricIngress.forwarding.mpls",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 57,
+        "column" : 50,
+        "source_fragment" : "mpls_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.routing_v4_counter",
       "id" : 7,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.routing_v4"
+      "binding" : "FabricIngress.forwarding.routing_v4",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 80,
+        "column" : 50,
+        "source_fragment" : "routing_v4_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.acl_counter",
       "id" : 8,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.acl"
+      "binding" : "FabricIngress.forwarding.acl",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 107,
+        "column" : 50,
+        "source_fragment" : "acl_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.routing_v6_counter",
       "id" : 9,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.routing_v6"
+      "binding" : "FabricIngress.forwarding.routing_v6",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 171,
+        "column" : 50,
+        "source_fragment" : "routing_v6_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.vlan_meta_counter",
       "id" : 10,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.vlan_meta"
+      "binding" : "FabricIngress.next.vlan_meta",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 58,
+        "column" : 50,
+        "source_fragment" : "vlan_meta_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.simple_counter",
       "id" : 11,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.simple"
+      "binding" : "FabricIngress.next.simple",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 82,
+        "column" : 50,
+        "source_fragment" : "simple_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.hashed_counter",
       "id" : 12,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.hashed"
+      "binding" : "FabricIngress.next.hashed",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 146,
+        "column" : 50,
+        "source_fragment" : "hashed_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.multicast_counter",
       "id" : 13,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.multicast"
+      "binding" : "FabricIngress.next.multicast",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 199,
+        "column" : 50,
+        "source_fragment" : "multicast_counter"
+      }
     },
     {
       "name" : "FabricIngress.port_counters_control.egress_port_counter",
@@ -1637,13 +1731,25 @@
       "name" : "FabricEgress.process_int_main.process_int_source.counter_int_source",
       "id" : 16,
       "is_direct" : true,
-      "binding" : "FabricEgress.process_int_main.process_int_source.tb_int_source"
+      "binding" : "FabricEgress.process_int_main.process_int_source.tb_int_source",
+      "source_info" : {
+        "filename" : "include/int/int_source.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "counter_int_source"
+      }
     },
     {
       "name" : "FabricEgress.egress_next.egress_vlan_counter",
       "id" : 17,
       "is_direct" : true,
-      "binding" : "FabricEgress.egress_next.egress_vlan"
+      "binding" : "FabricEgress.egress_next.egress_vlan",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 250,
+        "column" : 50,
+        "source_fragment" : "egress_vlan_counter"
+      }
     }
   ],
   "register_arrays" : [],
@@ -2278,7 +2384,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 91,
+            "line" : 99,
             "column" : 31,
             "source_fragment" : "0x8100; ..."
           }
@@ -2942,7 +3048,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -3018,7 +3124,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3133,7 +3239,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -3209,7 +3315,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3501,7 +3607,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -3577,7 +3683,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3692,7 +3798,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -3768,7 +3874,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3886,7 +3992,7 @@
           ],
           "source_info" : {
             "filename" : "fabric.p4",
-            "line" : 54,
+            "line" : 55,
             "column" : 50,
             "source_fragment" : "hdr.gtpu_ipv4"
           }
@@ -3901,7 +4007,7 @@
           ],
           "source_info" : {
             "filename" : "fabric.p4",
-            "line" : 54,
+            "line" : 55,
             "column" : 65,
             "source_fragment" : "hdr.gtpu_udp"
           }
@@ -4192,7 +4298,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 121,
+            "line" : 129,
             "column" : 36,
             "source_fragment" : "2w1; ..."
           }
@@ -4278,7 +4384,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 122,
+            "line" : 130,
             "column" : 38,
             "source_fragment" : "2w2; ..."
           }
@@ -4304,7 +4410,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 120,
+            "line" : 128,
             "column" : 37,
             "source_fragment" : "2w0; ..."
           }
@@ -4475,7 +4581,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 111,
+            "line" : 119,
             "column" : 31,
             "source_fragment" : "7; ..."
           }
@@ -4501,7 +4607,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 94,
+            "line" : 102,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
           }
@@ -4984,7 +5090,13 @@
               "type" : "hexstr",
               "value" : "0x1"
             }
-          ]
+          ],
+          "source_info" : {
+            "filename" : "include/int/int_main.p4",
+            "line" : 85,
+            "column" : 12,
+            "source_fragment" : "clone(CloneType.I2E, REPORT_MIRROR_SESSION_ID)"
+          }
         }
       ]
     },
@@ -5131,7 +5243,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 103,
+            "line" : 111,
             "column" : 28,
             "source_fragment" : "5; ..."
           }
@@ -5287,7 +5399,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 116,
+            "line" : 124,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -5306,7 +5418,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 100,
+            "line" : 108,
             "column" : 25,
             "source_fragment" : "17; ..."
           }
@@ -5740,7 +5852,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 131,
+            "line" : 139,
             "column" : 36,
             "source_fragment" : "4; ..."
           }
@@ -6158,7 +6270,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 127,
+            "line" : 135,
             "column" : 24,
             "source_fragment" : "0x1; ..."
           }
@@ -12188,7 +12300,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 94,
+            "line" : 102,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
           }
@@ -12416,7 +12528,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 100,
+            "line" : 108,
             "column" : 25,
             "source_fragment" : "17; ..."
           }
@@ -12602,7 +12714,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 137,
+            "line" : 145,
             "column" : 31,
             "source_fragment" : "0; ..."
           }
@@ -12697,7 +12809,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 141,
+            "line" : 149,
             "column" : 21,
             "source_fragment" : "1; ..."
           }
@@ -13300,7 +13412,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 374,
+            "line" : 376,
             "column" : 12,
             "source_fragment" : "return"
           }
@@ -13349,7 +13461,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 382,
+            "line" : 384,
             "column" : 12,
             "source_fragment" : "hdr.ipv4.total_len = hdr.ipv4.total_len + fmeta.int_meta.new_bytes"
           }
@@ -13398,7 +13510,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 379,
+            "line" : 381,
             "column" : 8,
             "source_fragment" : "hdr.int_header.total_hop_cnt = hdr.int_header.total_hop_cnt + 1"
           }
@@ -13447,7 +13559,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 385,
+            "line" : 387,
             "column" : 12,
             "source_fragment" : "hdr.udp.len = hdr.udp.len + fmeta.int_meta.new_bytes"
           }
@@ -13496,7 +13608,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 388,
+            "line" : 390,
             "column" : 12,
             "source_fragment" : "hdr.intl4_shim.len_words = hdr.intl4_shim.len_words + fmeta.int_meta.new_words"
           }
@@ -14952,6 +15064,12 @@
         {
           "name" : "FabricIngress.next.ecmp_selector",
           "id" : 0,
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 145,
+            "column" : 55,
+            "source_fragment" : "ecmp_selector"
+          },
           "max_size" : 64,
           "selector" : {
             "algo" : "crc16",
@@ -15578,7 +15696,7 @@
       "id" : 1,
       "source_info" : {
         "filename" : "fabric.p4",
-        "line" : 79,
+        "line" : 80,
         "column" : 8,
         "source_fragment" : "FabricEgress"
       },
@@ -15885,7 +16003,7 @@
           "id" : 59,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 284,
+            "line" : 286,
             "column" : 10,
             "source_fragment" : "tb_int_inst_0003"
           },
@@ -15899,7 +16017,7 @@
           ],
           "match_type" : "exact",
           "type" : "simple",
-          "max_size" : 16,
+          "max_size" : 1024,
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
@@ -15933,6 +16051,12 @@
           },
           "entries" : [
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 310,
+                "column" : 12,
+                "source_fragment" : "(0x0) : int_set_header_0003_i0()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -15946,6 +16070,12 @@
               "priority" : 1
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 311,
+                "column" : 12,
+                "source_fragment" : "(0x1) : int_set_header_0003_i1()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -15959,6 +16089,12 @@
               "priority" : 2
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 312,
+                "column" : 12,
+                "source_fragment" : "(0x2) : int_set_header_0003_i2()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -15972,6 +16108,12 @@
               "priority" : 3
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 313,
+                "column" : 12,
+                "source_fragment" : "(0x3) : int_set_header_0003_i3()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -15985,6 +16127,12 @@
               "priority" : 4
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 314,
+                "column" : 12,
+                "source_fragment" : "(0x4) : int_set_header_0003_i4()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -15998,6 +16146,12 @@
               "priority" : 5
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 315,
+                "column" : 12,
+                "source_fragment" : "(0x5) : int_set_header_0003_i5()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16011,6 +16165,12 @@
               "priority" : 6
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 316,
+                "column" : 12,
+                "source_fragment" : "(0x6) : int_set_header_0003_i6()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16024,6 +16184,12 @@
               "priority" : 7
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 317,
+                "column" : 12,
+                "source_fragment" : "(0x7) : int_set_header_0003_i7()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16037,6 +16203,12 @@
               "priority" : 8
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 318,
+                "column" : 12,
+                "source_fragment" : "(0x8) : int_set_header_0003_i8()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16050,6 +16222,12 @@
               "priority" : 9
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 319,
+                "column" : 12,
+                "source_fragment" : "(0x9) : int_set_header_0003_i9()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16063,6 +16241,12 @@
               "priority" : 10
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 320,
+                "column" : 12,
+                "source_fragment" : "(0xA) : int_set_header_0003_i10()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16076,6 +16260,12 @@
               "priority" : 11
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 321,
+                "column" : 12,
+                "source_fragment" : "(0xB) : int_set_header_0003_i11()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16089,6 +16279,12 @@
               "priority" : 12
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 322,
+                "column" : 12,
+                "source_fragment" : "(0xC) : int_set_header_0003_i12()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16102,6 +16298,12 @@
               "priority" : 13
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 323,
+                "column" : 12,
+                "source_fragment" : "(0xD) : int_set_header_0003_i13()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16115,6 +16317,12 @@
               "priority" : 14
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 324,
+                "column" : 12,
+                "source_fragment" : "(0xE) : int_set_header_0003_i14()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16128,6 +16336,12 @@
               "priority" : 15
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 325,
+                "column" : 12,
+                "source_fragment" : "(0xF) : int_set_header_0003_i15()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16147,7 +16361,7 @@
           "id" : 60,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 328,
+            "line" : 330,
             "column" : 10,
             "source_fragment" : "tb_int_inst_0407"
           },
@@ -16161,7 +16375,7 @@
           ],
           "match_type" : "exact",
           "type" : "simple",
-          "max_size" : 16,
+          "max_size" : 1024,
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
@@ -16195,6 +16409,12 @@
           },
           "entries" : [
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 354,
+                "column" : 12,
+                "source_fragment" : "(0x0) : int_set_header_0407_i0()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16208,6 +16428,12 @@
               "priority" : 1
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 355,
+                "column" : 12,
+                "source_fragment" : "(0x1) : int_set_header_0407_i1()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16221,6 +16447,12 @@
               "priority" : 2
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 356,
+                "column" : 12,
+                "source_fragment" : "(0x2) : int_set_header_0407_i2()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16234,6 +16466,12 @@
               "priority" : 3
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 357,
+                "column" : 12,
+                "source_fragment" : "(0x3) : int_set_header_0407_i3()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16247,6 +16485,12 @@
               "priority" : 4
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 358,
+                "column" : 12,
+                "source_fragment" : "(0x4) : int_set_header_0407_i4()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16260,6 +16504,12 @@
               "priority" : 5
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 359,
+                "column" : 12,
+                "source_fragment" : "(0x5) : int_set_header_0407_i5()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16273,6 +16523,12 @@
               "priority" : 6
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 360,
+                "column" : 12,
+                "source_fragment" : "(0x6) : int_set_header_0407_i6()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16286,6 +16542,12 @@
               "priority" : 7
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 361,
+                "column" : 12,
+                "source_fragment" : "(0x7) : int_set_header_0407_i7()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16299,6 +16561,12 @@
               "priority" : 8
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 362,
+                "column" : 12,
+                "source_fragment" : "(0x8) : int_set_header_0407_i8()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16312,6 +16580,12 @@
               "priority" : 9
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 363,
+                "column" : 12,
+                "source_fragment" : "(0x9) : int_set_header_0407_i9()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16325,6 +16599,12 @@
               "priority" : 10
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 364,
+                "column" : 12,
+                "source_fragment" : "(0xA) : int_set_header_0407_i10()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16338,6 +16618,12 @@
               "priority" : 11
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 365,
+                "column" : 12,
+                "source_fragment" : "(0xB) : int_set_header_0407_i11()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16351,6 +16637,12 @@
               "priority" : 12
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 366,
+                "column" : 12,
+                "source_fragment" : "(0xC) : int_set_header_0407_i12()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16364,6 +16656,12 @@
               "priority" : 13
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 367,
+                "column" : 12,
+                "source_fragment" : "(0xD) : int_set_header_0407_i13()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16377,6 +16675,12 @@
               "priority" : 14
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 368,
+                "column" : 12,
+                "source_fragment" : "(0xE) : int_set_header_0407_i14()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16390,6 +16694,12 @@
               "priority" : 15
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 369,
+                "column" : 12,
+                "source_fragment" : "(0xF) : int_set_header_0407_i15()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -16964,7 +17274,7 @@
           "id" : 32,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 373,
+            "line" : 375,
             "column" : 12,
             "source_fragment" : "fmeta.int_meta.transit == false"
           },
@@ -17021,7 +17331,7 @@
           "id" : 34,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 381,
+            "line" : 383,
             "column" : 12,
             "source_fragment" : "hdr.ipv4.isValid()"
           },
@@ -17044,7 +17354,7 @@
           "id" : 35,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 384,
+            "line" : 386,
             "column" : 12,
             "source_fragment" : "hdr.udp.isValid()"
           },
@@ -17067,7 +17377,7 @@
           "id" : 36,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 387,
+            "line" : 389,
             "column" : 12,
             "source_fragment" : "hdr.intl4_shim.isValid()"
           },
@@ -17151,6 +17461,12 @@
     {
       "name" : "cksum",
       "id" : 0,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 28,
+        "column" : 8,
+        "source_fragment" : "update_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc",
@@ -17169,6 +17485,12 @@
     {
       "name" : "cksum_0",
       "id" : 1,
+      "source_info" : {
+        "filename" : "include/spgw.p4",
+        "line" : 237,
+        "column" : 8,
+        "source_fragment" : "update_checksum(gtpu_ipv4.isValid(), ..."
+      },
       "target" : ["gtpu_ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_0",
@@ -17187,6 +17509,12 @@
     {
       "name" : "cksum_1",
       "id" : 2,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 57,
+        "column" : 8,
+        "source_fragment" : "verify_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_1",
diff --git a/pipelines/fabric/src/main/resources/p4c-out/fabric-int/bmv2/default/bmv2.json b/pipelines/fabric/src/main/resources/p4c-out/fabric-int/bmv2/default/bmv2.json
index 293212f..4f390ee 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/fabric-int/bmv2/default/bmv2.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/fabric-int/bmv2/default/bmv2.json
@@ -50,6 +50,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding", 5, false]
       ]
     },
@@ -283,6 +284,8 @@
         ["switch_id", 32, false],
         ["new_words", 8, false],
         ["new_bytes", 16, false],
+        ["ig_tstamp", 32, false],
+        ["eg_tstamp", 32, false],
         ["_padding_0", 5, false]
       ]
     }
@@ -469,7 +472,14 @@
   "header_unions" : [],
   "header_union_stacks" : [],
   "field_lists" : [],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -1016,67 +1026,133 @@
       "name" : "FabricIngress.process_set_source_sink.counter_set_source",
       "id" : 0,
       "is_direct" : true,
-      "binding" : "FabricIngress.process_set_source_sink.tb_set_source"
+      "binding" : "FabricIngress.process_set_source_sink.tb_set_source",
+      "source_info" : {
+        "filename" : "include/int/int_main.p4",
+        "line" : 39,
+        "column" : 50,
+        "source_fragment" : "counter_set_source"
+      }
     },
     {
       "name" : "FabricIngress.filtering.ingress_port_vlan_counter",
       "id" : 1,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.ingress_port_vlan"
+      "binding" : "FabricIngress.filtering.ingress_port_vlan",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "ingress_port_vlan_counter"
+      }
     },
     {
       "name" : "FabricIngress.filtering.fwd_classifier_counter",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.fwd_classifier"
+      "binding" : "FabricIngress.filtering.fwd_classifier",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 96,
+        "column" : 50,
+        "source_fragment" : "fwd_classifier_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.bridging_counter",
       "id" : 3,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.bridging"
+      "binding" : "FabricIngress.forwarding.bridging",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "bridging_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.mpls_counter",
       "id" : 4,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.mpls"
+      "binding" : "FabricIngress.forwarding.mpls",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 57,
+        "column" : 50,
+        "source_fragment" : "mpls_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.routing_v4_counter",
       "id" : 5,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.routing_v4"
+      "binding" : "FabricIngress.forwarding.routing_v4",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 80,
+        "column" : 50,
+        "source_fragment" : "routing_v4_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.acl_counter",
       "id" : 6,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.acl"
+      "binding" : "FabricIngress.forwarding.acl",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 107,
+        "column" : 50,
+        "source_fragment" : "acl_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.vlan_meta_counter",
       "id" : 7,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.vlan_meta"
+      "binding" : "FabricIngress.next.vlan_meta",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 58,
+        "column" : 50,
+        "source_fragment" : "vlan_meta_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.simple_counter",
       "id" : 8,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.simple"
+      "binding" : "FabricIngress.next.simple",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 82,
+        "column" : 50,
+        "source_fragment" : "simple_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.hashed_counter",
       "id" : 9,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.hashed"
+      "binding" : "FabricIngress.next.hashed",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 146,
+        "column" : 50,
+        "source_fragment" : "hashed_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.multicast_counter",
       "id" : 10,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.multicast"
+      "binding" : "FabricIngress.next.multicast",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 199,
+        "column" : 50,
+        "source_fragment" : "multicast_counter"
+      }
     },
     {
       "name" : "FabricIngress.port_counters_control.egress_port_counter",
@@ -1106,13 +1182,25 @@
       "name" : "FabricEgress.process_int_main.process_int_source.counter_int_source",
       "id" : 13,
       "is_direct" : true,
-      "binding" : "FabricEgress.process_int_main.process_int_source.tb_int_source"
+      "binding" : "FabricEgress.process_int_main.process_int_source.tb_int_source",
+      "source_info" : {
+        "filename" : "include/int/int_source.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "counter_int_source"
+      }
     },
     {
       "name" : "FabricEgress.egress_next.egress_vlan_counter",
       "id" : 14,
       "is_direct" : true,
-      "binding" : "FabricEgress.egress_next.egress_vlan"
+      "binding" : "FabricEgress.egress_next.egress_vlan",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 250,
+        "column" : 50,
+        "source_fragment" : "egress_vlan_counter"
+      }
     }
   ],
   "register_arrays" : [],
@@ -1470,7 +1558,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 91,
+            "line" : 99,
             "column" : 31,
             "source_fragment" : "0x8100; ..."
           }
@@ -2103,7 +2191,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2179,7 +2267,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2294,7 +2382,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2370,7 +2458,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2662,7 +2750,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2738,7 +2826,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2853,7 +2941,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2929,7 +3017,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3145,7 +3233,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 111,
+            "line" : 119,
             "column" : 31,
             "source_fragment" : "7; ..."
           }
@@ -3171,7 +3259,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 94,
+            "line" : 102,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
           }
@@ -3743,7 +3831,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 131,
+            "line" : 139,
             "column" : 36,
             "source_fragment" : "4; ..."
           }
@@ -4161,7 +4249,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 127,
+            "line" : 135,
             "column" : 24,
             "source_fragment" : "0x1; ..."
           }
@@ -10280,7 +10368,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 374,
+            "line" : 376,
             "column" : 12,
             "source_fragment" : "return"
           }
@@ -10329,7 +10417,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 382,
+            "line" : 384,
             "column" : 12,
             "source_fragment" : "hdr.ipv4.total_len = hdr.ipv4.total_len + fmeta.int_meta.new_bytes"
           }
@@ -10378,7 +10466,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 379,
+            "line" : 381,
             "column" : 8,
             "source_fragment" : "hdr.int_header.total_hop_cnt = hdr.int_header.total_hop_cnt + 1"
           }
@@ -10427,7 +10515,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 385,
+            "line" : 387,
             "column" : 12,
             "source_fragment" : "hdr.udp.len = hdr.udp.len + fmeta.int_meta.new_bytes"
           }
@@ -10476,7 +10564,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 388,
+            "line" : 390,
             "column" : 12,
             "source_fragment" : "hdr.intl4_shim.len_words = hdr.intl4_shim.len_words + fmeta.int_meta.new_words"
           }
@@ -11370,6 +11458,12 @@
         {
           "name" : "FabricIngress.next.ecmp_selector",
           "id" : 0,
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 145,
+            "column" : 55,
+            "source_fragment" : "ecmp_selector"
+          },
           "max_size" : 64,
           "selector" : {
             "algo" : "crc16",
@@ -11743,7 +11837,7 @@
       "id" : 1,
       "source_info" : {
         "filename" : "fabric.p4",
-        "line" : 79,
+        "line" : 80,
         "column" : 8,
         "source_fragment" : "FabricEgress"
       },
@@ -12027,7 +12121,7 @@
           "id" : 36,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 284,
+            "line" : 286,
             "column" : 10,
             "source_fragment" : "tb_int_inst_0003"
           },
@@ -12041,7 +12135,7 @@
           ],
           "match_type" : "exact",
           "type" : "simple",
-          "max_size" : 16,
+          "max_size" : 1024,
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
@@ -12075,6 +12169,12 @@
           },
           "entries" : [
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 310,
+                "column" : 12,
+                "source_fragment" : "(0x0) : int_set_header_0003_i0()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12088,6 +12188,12 @@
               "priority" : 1
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 311,
+                "column" : 12,
+                "source_fragment" : "(0x1) : int_set_header_0003_i1()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12101,6 +12207,12 @@
               "priority" : 2
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 312,
+                "column" : 12,
+                "source_fragment" : "(0x2) : int_set_header_0003_i2()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12114,6 +12226,12 @@
               "priority" : 3
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 313,
+                "column" : 12,
+                "source_fragment" : "(0x3) : int_set_header_0003_i3()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12127,6 +12245,12 @@
               "priority" : 4
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 314,
+                "column" : 12,
+                "source_fragment" : "(0x4) : int_set_header_0003_i4()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12140,6 +12264,12 @@
               "priority" : 5
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 315,
+                "column" : 12,
+                "source_fragment" : "(0x5) : int_set_header_0003_i5()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12153,6 +12283,12 @@
               "priority" : 6
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 316,
+                "column" : 12,
+                "source_fragment" : "(0x6) : int_set_header_0003_i6()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12166,6 +12302,12 @@
               "priority" : 7
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 317,
+                "column" : 12,
+                "source_fragment" : "(0x7) : int_set_header_0003_i7()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12179,6 +12321,12 @@
               "priority" : 8
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 318,
+                "column" : 12,
+                "source_fragment" : "(0x8) : int_set_header_0003_i8()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12192,6 +12340,12 @@
               "priority" : 9
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 319,
+                "column" : 12,
+                "source_fragment" : "(0x9) : int_set_header_0003_i9()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12205,6 +12359,12 @@
               "priority" : 10
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 320,
+                "column" : 12,
+                "source_fragment" : "(0xA) : int_set_header_0003_i10()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12218,6 +12378,12 @@
               "priority" : 11
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 321,
+                "column" : 12,
+                "source_fragment" : "(0xB) : int_set_header_0003_i11()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12231,6 +12397,12 @@
               "priority" : 12
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 322,
+                "column" : 12,
+                "source_fragment" : "(0xC) : int_set_header_0003_i12()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12244,6 +12416,12 @@
               "priority" : 13
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 323,
+                "column" : 12,
+                "source_fragment" : "(0xD) : int_set_header_0003_i13()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12257,6 +12435,12 @@
               "priority" : 14
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 324,
+                "column" : 12,
+                "source_fragment" : "(0xE) : int_set_header_0003_i14()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12270,6 +12454,12 @@
               "priority" : 15
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 325,
+                "column" : 12,
+                "source_fragment" : "(0xF) : int_set_header_0003_i15()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12289,7 +12479,7 @@
           "id" : 37,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 328,
+            "line" : 330,
             "column" : 10,
             "source_fragment" : "tb_int_inst_0407"
           },
@@ -12303,7 +12493,7 @@
           ],
           "match_type" : "exact",
           "type" : "simple",
-          "max_size" : 16,
+          "max_size" : 1024,
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
@@ -12337,6 +12527,12 @@
           },
           "entries" : [
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 354,
+                "column" : 12,
+                "source_fragment" : "(0x0) : int_set_header_0407_i0()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12350,6 +12546,12 @@
               "priority" : 1
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 355,
+                "column" : 12,
+                "source_fragment" : "(0x1) : int_set_header_0407_i1()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12363,6 +12565,12 @@
               "priority" : 2
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 356,
+                "column" : 12,
+                "source_fragment" : "(0x2) : int_set_header_0407_i2()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12376,6 +12584,12 @@
               "priority" : 3
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 357,
+                "column" : 12,
+                "source_fragment" : "(0x3) : int_set_header_0407_i3()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12389,6 +12603,12 @@
               "priority" : 4
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 358,
+                "column" : 12,
+                "source_fragment" : "(0x4) : int_set_header_0407_i4()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12402,6 +12622,12 @@
               "priority" : 5
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 359,
+                "column" : 12,
+                "source_fragment" : "(0x5) : int_set_header_0407_i5()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12415,6 +12641,12 @@
               "priority" : 6
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 360,
+                "column" : 12,
+                "source_fragment" : "(0x6) : int_set_header_0407_i6()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12428,6 +12660,12 @@
               "priority" : 7
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 361,
+                "column" : 12,
+                "source_fragment" : "(0x7) : int_set_header_0407_i7()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12441,6 +12679,12 @@
               "priority" : 8
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 362,
+                "column" : 12,
+                "source_fragment" : "(0x8) : int_set_header_0407_i8()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12454,6 +12698,12 @@
               "priority" : 9
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 363,
+                "column" : 12,
+                "source_fragment" : "(0x9) : int_set_header_0407_i9()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12467,6 +12717,12 @@
               "priority" : 10
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 364,
+                "column" : 12,
+                "source_fragment" : "(0xA) : int_set_header_0407_i10()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12480,6 +12736,12 @@
               "priority" : 11
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 365,
+                "column" : 12,
+                "source_fragment" : "(0xB) : int_set_header_0407_i11()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12493,6 +12755,12 @@
               "priority" : 12
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 366,
+                "column" : 12,
+                "source_fragment" : "(0xC) : int_set_header_0407_i12()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12506,6 +12774,12 @@
               "priority" : 13
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 367,
+                "column" : 12,
+                "source_fragment" : "(0xD) : int_set_header_0407_i13()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12519,6 +12793,12 @@
               "priority" : 14
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 368,
+                "column" : 12,
+                "source_fragment" : "(0xE) : int_set_header_0407_i14()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -12532,6 +12812,12 @@
               "priority" : 15
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 369,
+                "column" : 12,
+                "source_fragment" : "(0xF) : int_set_header_0407_i15()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -13004,7 +13290,7 @@
           "id" : 21,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 373,
+            "line" : 375,
             "column" : 12,
             "source_fragment" : "fmeta.int_meta.transit == false"
           },
@@ -13061,7 +13347,7 @@
           "id" : 23,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 381,
+            "line" : 383,
             "column" : 12,
             "source_fragment" : "hdr.ipv4.isValid()"
           },
@@ -13084,7 +13370,7 @@
           "id" : 24,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 384,
+            "line" : 386,
             "column" : 12,
             "source_fragment" : "hdr.udp.isValid()"
           },
@@ -13107,7 +13393,7 @@
           "id" : 25,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 387,
+            "line" : 389,
             "column" : 12,
             "source_fragment" : "hdr.intl4_shim.isValid()"
           },
@@ -13132,6 +13418,12 @@
     {
       "name" : "cksum",
       "id" : 0,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 28,
+        "column" : 8,
+        "source_fragment" : "update_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc",
@@ -13150,6 +13442,12 @@
     {
       "name" : "cksum_0",
       "id" : 1,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 57,
+        "column" : 8,
+        "source_fragment" : "verify_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_0",
diff --git a/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw-int/bmv2/default/bmv2.json b/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw-int/bmv2/default/bmv2.json
index 97da4eb..a4cce10 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw-int/bmv2/default/bmv2.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw-int/bmv2/default/bmv2.json
@@ -55,6 +55,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding", 5, false]
       ]
     },
@@ -315,6 +316,8 @@
         ["switch_id", 32, false],
         ["new_words", 8, false],
         ["new_bytes", 16, false],
+        ["ig_tstamp", 32, false],
+        ["eg_tstamp", 32, false],
         ["_padding_1", 5, false]
       ]
     }
@@ -543,7 +546,14 @@
   "header_unions" : [],
   "header_union_stacks" : [],
   "field_lists" : [],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -1284,73 +1294,145 @@
       "name" : "FabricIngress.spgw_ingress.ue_counter",
       "id" : 0,
       "is_direct" : true,
-      "binding" : "FabricIngress.spgw_ingress.dl_sess_lookup"
+      "binding" : "FabricIngress.spgw_ingress.dl_sess_lookup",
+      "source_info" : {
+        "filename" : "include/spgw.p4",
+        "line" : 51,
+        "column" : 50,
+        "source_fragment" : "ue_counter"
+      }
     },
     {
       "name" : "FabricIngress.process_set_source_sink.counter_set_source",
       "id" : 1,
       "is_direct" : true,
-      "binding" : "FabricIngress.process_set_source_sink.tb_set_source"
+      "binding" : "FabricIngress.process_set_source_sink.tb_set_source",
+      "source_info" : {
+        "filename" : "include/int/int_main.p4",
+        "line" : 39,
+        "column" : 50,
+        "source_fragment" : "counter_set_source"
+      }
     },
     {
       "name" : "FabricIngress.filtering.ingress_port_vlan_counter",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.ingress_port_vlan"
+      "binding" : "FabricIngress.filtering.ingress_port_vlan",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "ingress_port_vlan_counter"
+      }
     },
     {
       "name" : "FabricIngress.filtering.fwd_classifier_counter",
       "id" : 3,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.fwd_classifier"
+      "binding" : "FabricIngress.filtering.fwd_classifier",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 96,
+        "column" : 50,
+        "source_fragment" : "fwd_classifier_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.bridging_counter",
       "id" : 4,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.bridging"
+      "binding" : "FabricIngress.forwarding.bridging",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "bridging_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.mpls_counter",
       "id" : 5,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.mpls"
+      "binding" : "FabricIngress.forwarding.mpls",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 57,
+        "column" : 50,
+        "source_fragment" : "mpls_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.routing_v4_counter",
       "id" : 6,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.routing_v4"
+      "binding" : "FabricIngress.forwarding.routing_v4",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 80,
+        "column" : 50,
+        "source_fragment" : "routing_v4_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.acl_counter",
       "id" : 7,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.acl"
+      "binding" : "FabricIngress.forwarding.acl",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 107,
+        "column" : 50,
+        "source_fragment" : "acl_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.vlan_meta_counter",
       "id" : 8,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.vlan_meta"
+      "binding" : "FabricIngress.next.vlan_meta",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 58,
+        "column" : 50,
+        "source_fragment" : "vlan_meta_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.simple_counter",
       "id" : 9,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.simple"
+      "binding" : "FabricIngress.next.simple",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 82,
+        "column" : 50,
+        "source_fragment" : "simple_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.hashed_counter",
       "id" : 10,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.hashed"
+      "binding" : "FabricIngress.next.hashed",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 146,
+        "column" : 50,
+        "source_fragment" : "hashed_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.multicast_counter",
       "id" : 11,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.multicast"
+      "binding" : "FabricIngress.next.multicast",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 199,
+        "column" : 50,
+        "source_fragment" : "multicast_counter"
+      }
     },
     {
       "name" : "FabricIngress.port_counters_control.egress_port_counter",
@@ -1380,13 +1462,25 @@
       "name" : "FabricEgress.process_int_main.process_int_source.counter_int_source",
       "id" : 14,
       "is_direct" : true,
-      "binding" : "FabricEgress.process_int_main.process_int_source.tb_int_source"
+      "binding" : "FabricEgress.process_int_main.process_int_source.tb_int_source",
+      "source_info" : {
+        "filename" : "include/int/int_source.p4",
+        "line" : 27,
+        "column" : 50,
+        "source_fragment" : "counter_int_source"
+      }
     },
     {
       "name" : "FabricEgress.egress_next.egress_vlan_counter",
       "id" : 15,
       "is_direct" : true,
-      "binding" : "FabricEgress.egress_next.egress_vlan"
+      "binding" : "FabricEgress.egress_next.egress_vlan",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 250,
+        "column" : 50,
+        "source_fragment" : "egress_vlan_counter"
+      }
     }
   ],
   "register_arrays" : [],
@@ -1973,7 +2067,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 91,
+            "line" : 99,
             "column" : 31,
             "source_fragment" : "0x8100; ..."
           }
@@ -2606,7 +2700,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2682,7 +2776,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2797,7 +2891,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2873,7 +2967,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3165,7 +3259,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -3241,7 +3335,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3356,7 +3450,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -3432,7 +3526,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3550,7 +3644,7 @@
           ],
           "source_info" : {
             "filename" : "fabric.p4",
-            "line" : 54,
+            "line" : 55,
             "column" : 50,
             "source_fragment" : "hdr.gtpu_ipv4"
           }
@@ -3565,7 +3659,7 @@
           ],
           "source_info" : {
             "filename" : "fabric.p4",
-            "line" : 54,
+            "line" : 55,
             "column" : 65,
             "source_fragment" : "hdr.gtpu_udp"
           }
@@ -3856,7 +3950,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 121,
+            "line" : 129,
             "column" : 36,
             "source_fragment" : "2w1; ..."
           }
@@ -3942,7 +4036,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 122,
+            "line" : 130,
             "column" : 38,
             "source_fragment" : "2w2; ..."
           }
@@ -3968,7 +4062,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 120,
+            "line" : 128,
             "column" : 37,
             "source_fragment" : "2w0; ..."
           }
@@ -4139,7 +4233,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 111,
+            "line" : 119,
             "column" : 31,
             "source_fragment" : "7; ..."
           }
@@ -4165,7 +4259,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 94,
+            "line" : 102,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
           }
@@ -4720,7 +4814,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 103,
+            "line" : 111,
             "column" : 28,
             "source_fragment" : "5; ..."
           }
@@ -4876,7 +4970,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 116,
+            "line" : 124,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -4895,7 +4989,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 100,
+            "line" : 108,
             "column" : 25,
             "source_fragment" : "17; ..."
           }
@@ -5329,7 +5423,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 131,
+            "line" : 139,
             "column" : 36,
             "source_fragment" : "4; ..."
           }
@@ -5747,7 +5841,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 127,
+            "line" : 135,
             "column" : 24,
             "source_fragment" : "0x1; ..."
           }
@@ -11866,7 +11960,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 374,
+            "line" : 376,
             "column" : 12,
             "source_fragment" : "return"
           }
@@ -11915,7 +12009,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 382,
+            "line" : 384,
             "column" : 12,
             "source_fragment" : "hdr.ipv4.total_len = hdr.ipv4.total_len + fmeta.int_meta.new_bytes"
           }
@@ -11964,7 +12058,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 379,
+            "line" : 381,
             "column" : 8,
             "source_fragment" : "hdr.int_header.total_hop_cnt = hdr.int_header.total_hop_cnt + 1"
           }
@@ -12013,7 +12107,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 385,
+            "line" : 387,
             "column" : 12,
             "source_fragment" : "hdr.udp.len = hdr.udp.len + fmeta.int_meta.new_bytes"
           }
@@ -12062,7 +12156,7 @@
           ],
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 388,
+            "line" : 390,
             "column" : 12,
             "source_fragment" : "hdr.intl4_shim.len_words = hdr.intl4_shim.len_words + fmeta.int_meta.new_words"
           }
@@ -13398,6 +13492,12 @@
         {
           "name" : "FabricIngress.next.ecmp_selector",
           "id" : 0,
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 145,
+            "column" : 55,
+            "source_fragment" : "ecmp_selector"
+          },
           "max_size" : 64,
           "selector" : {
             "algo" : "crc16",
@@ -13942,7 +14042,7 @@
       "id" : 1,
       "source_info" : {
         "filename" : "fabric.p4",
-        "line" : 79,
+        "line" : 80,
         "column" : 8,
         "source_fragment" : "FabricEgress"
       },
@@ -14249,7 +14349,7 @@
           "id" : 55,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 284,
+            "line" : 286,
             "column" : 10,
             "source_fragment" : "tb_int_inst_0003"
           },
@@ -14263,7 +14363,7 @@
           ],
           "match_type" : "exact",
           "type" : "simple",
-          "max_size" : 16,
+          "max_size" : 1024,
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
@@ -14297,6 +14397,12 @@
           },
           "entries" : [
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 310,
+                "column" : 12,
+                "source_fragment" : "(0x0) : int_set_header_0003_i0()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14310,6 +14416,12 @@
               "priority" : 1
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 311,
+                "column" : 12,
+                "source_fragment" : "(0x1) : int_set_header_0003_i1()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14323,6 +14435,12 @@
               "priority" : 2
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 312,
+                "column" : 12,
+                "source_fragment" : "(0x2) : int_set_header_0003_i2()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14336,6 +14454,12 @@
               "priority" : 3
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 313,
+                "column" : 12,
+                "source_fragment" : "(0x3) : int_set_header_0003_i3()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14349,6 +14473,12 @@
               "priority" : 4
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 314,
+                "column" : 12,
+                "source_fragment" : "(0x4) : int_set_header_0003_i4()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14362,6 +14492,12 @@
               "priority" : 5
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 315,
+                "column" : 12,
+                "source_fragment" : "(0x5) : int_set_header_0003_i5()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14375,6 +14511,12 @@
               "priority" : 6
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 316,
+                "column" : 12,
+                "source_fragment" : "(0x6) : int_set_header_0003_i6()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14388,6 +14530,12 @@
               "priority" : 7
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 317,
+                "column" : 12,
+                "source_fragment" : "(0x7) : int_set_header_0003_i7()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14401,6 +14549,12 @@
               "priority" : 8
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 318,
+                "column" : 12,
+                "source_fragment" : "(0x8) : int_set_header_0003_i8()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14414,6 +14568,12 @@
               "priority" : 9
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 319,
+                "column" : 12,
+                "source_fragment" : "(0x9) : int_set_header_0003_i9()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14427,6 +14587,12 @@
               "priority" : 10
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 320,
+                "column" : 12,
+                "source_fragment" : "(0xA) : int_set_header_0003_i10()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14440,6 +14606,12 @@
               "priority" : 11
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 321,
+                "column" : 12,
+                "source_fragment" : "(0xB) : int_set_header_0003_i11()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14453,6 +14625,12 @@
               "priority" : 12
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 322,
+                "column" : 12,
+                "source_fragment" : "(0xC) : int_set_header_0003_i12()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14466,6 +14644,12 @@
               "priority" : 13
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 323,
+                "column" : 12,
+                "source_fragment" : "(0xD) : int_set_header_0003_i13()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14479,6 +14663,12 @@
               "priority" : 14
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 324,
+                "column" : 12,
+                "source_fragment" : "(0xE) : int_set_header_0003_i14()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14492,6 +14682,12 @@
               "priority" : 15
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 325,
+                "column" : 12,
+                "source_fragment" : "(0xF) : int_set_header_0003_i15()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14511,7 +14707,7 @@
           "id" : 56,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 328,
+            "line" : 330,
             "column" : 10,
             "source_fragment" : "tb_int_inst_0407"
           },
@@ -14525,7 +14721,7 @@
           ],
           "match_type" : "exact",
           "type" : "simple",
-          "max_size" : 16,
+          "max_size" : 1024,
           "with_counters" : false,
           "support_timeout" : false,
           "direct_meters" : null,
@@ -14559,6 +14755,12 @@
           },
           "entries" : [
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 354,
+                "column" : 12,
+                "source_fragment" : "(0x0) : int_set_header_0407_i0()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14572,6 +14774,12 @@
               "priority" : 1
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 355,
+                "column" : 12,
+                "source_fragment" : "(0x1) : int_set_header_0407_i1()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14585,6 +14793,12 @@
               "priority" : 2
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 356,
+                "column" : 12,
+                "source_fragment" : "(0x2) : int_set_header_0407_i2()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14598,6 +14812,12 @@
               "priority" : 3
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 357,
+                "column" : 12,
+                "source_fragment" : "(0x3) : int_set_header_0407_i3()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14611,6 +14831,12 @@
               "priority" : 4
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 358,
+                "column" : 12,
+                "source_fragment" : "(0x4) : int_set_header_0407_i4()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14624,6 +14850,12 @@
               "priority" : 5
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 359,
+                "column" : 12,
+                "source_fragment" : "(0x5) : int_set_header_0407_i5()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14637,6 +14869,12 @@
               "priority" : 6
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 360,
+                "column" : 12,
+                "source_fragment" : "(0x6) : int_set_header_0407_i6()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14650,6 +14888,12 @@
               "priority" : 7
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 361,
+                "column" : 12,
+                "source_fragment" : "(0x7) : int_set_header_0407_i7()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14663,6 +14907,12 @@
               "priority" : 8
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 362,
+                "column" : 12,
+                "source_fragment" : "(0x8) : int_set_header_0407_i8()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14676,6 +14926,12 @@
               "priority" : 9
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 363,
+                "column" : 12,
+                "source_fragment" : "(0x9) : int_set_header_0407_i9()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14689,6 +14945,12 @@
               "priority" : 10
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 364,
+                "column" : 12,
+                "source_fragment" : "(0xA) : int_set_header_0407_i10()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14702,6 +14964,12 @@
               "priority" : 11
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 365,
+                "column" : 12,
+                "source_fragment" : "(0xB) : int_set_header_0407_i11()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14715,6 +14983,12 @@
               "priority" : 12
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 366,
+                "column" : 12,
+                "source_fragment" : "(0xC) : int_set_header_0407_i12()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14728,6 +15002,12 @@
               "priority" : 13
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 367,
+                "column" : 12,
+                "source_fragment" : "(0xD) : int_set_header_0407_i13()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14741,6 +15021,12 @@
               "priority" : 14
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 368,
+                "column" : 12,
+                "source_fragment" : "(0xE) : int_set_header_0407_i14()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -14754,6 +15040,12 @@
               "priority" : 15
             },
             {
+              "source_info" : {
+                "filename" : "include/int/int_transit.p4",
+                "line" : 369,
+                "column" : 12,
+                "source_fragment" : "(0xF) : int_set_header_0407_i15()"
+              },
               "match_key" : [
                 {
                   "match_type" : "exact",
@@ -15252,7 +15544,7 @@
           "id" : 29,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 373,
+            "line" : 375,
             "column" : 12,
             "source_fragment" : "fmeta.int_meta.transit == false"
           },
@@ -15309,7 +15601,7 @@
           "id" : 31,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 381,
+            "line" : 383,
             "column" : 12,
             "source_fragment" : "hdr.ipv4.isValid()"
           },
@@ -15332,7 +15624,7 @@
           "id" : 32,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 384,
+            "line" : 386,
             "column" : 12,
             "source_fragment" : "hdr.udp.isValid()"
           },
@@ -15355,7 +15647,7 @@
           "id" : 33,
           "source_info" : {
             "filename" : "include/int/int_transit.p4",
-            "line" : 387,
+            "line" : 389,
             "column" : 12,
             "source_fragment" : "hdr.intl4_shim.isValid()"
           },
@@ -15380,6 +15672,12 @@
     {
       "name" : "cksum",
       "id" : 0,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 28,
+        "column" : 8,
+        "source_fragment" : "update_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc",
@@ -15398,6 +15696,12 @@
     {
       "name" : "cksum_0",
       "id" : 1,
+      "source_info" : {
+        "filename" : "include/spgw.p4",
+        "line" : 237,
+        "column" : 8,
+        "source_fragment" : "update_checksum(gtpu_ipv4.isValid(), ..."
+      },
       "target" : ["gtpu_ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_0",
@@ -15416,6 +15720,12 @@
     {
       "name" : "cksum_1",
       "id" : 2,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 57,
+        "column" : 8,
+        "source_fragment" : "verify_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_1",
diff --git a/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw/bmv2/default/bmv2.json b/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw/bmv2/default/bmv2.json
index 2d97498..a3db0a8 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw/bmv2/default/bmv2.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/fabric-spgw/bmv2/default/bmv2.json
@@ -53,6 +53,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding", 5, false]
       ]
     },
@@ -331,7 +332,14 @@
   "header_unions" : [],
   "header_union_stacks" : [],
   "field_lists" : [],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -943,67 +951,133 @@
       "name" : "FabricIngress.spgw_ingress.ue_counter",
       "id" : 0,
       "is_direct" : true,
-      "binding" : "FabricIngress.spgw_ingress.dl_sess_lookup"
+      "binding" : "FabricIngress.spgw_ingress.dl_sess_lookup",
+      "source_info" : {
+        "filename" : "include/spgw.p4",
+        "line" : 51,
+        "column" : 50,
+        "source_fragment" : "ue_counter"
+      }
     },
     {
       "name" : "FabricIngress.filtering.ingress_port_vlan_counter",
       "id" : 1,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.ingress_port_vlan"
+      "binding" : "FabricIngress.filtering.ingress_port_vlan",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "ingress_port_vlan_counter"
+      }
     },
     {
       "name" : "FabricIngress.filtering.fwd_classifier_counter",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.fwd_classifier"
+      "binding" : "FabricIngress.filtering.fwd_classifier",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 96,
+        "column" : 50,
+        "source_fragment" : "fwd_classifier_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.bridging_counter",
       "id" : 3,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.bridging"
+      "binding" : "FabricIngress.forwarding.bridging",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "bridging_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.mpls_counter",
       "id" : 4,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.mpls"
+      "binding" : "FabricIngress.forwarding.mpls",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 57,
+        "column" : 50,
+        "source_fragment" : "mpls_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.routing_v4_counter",
       "id" : 5,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.routing_v4"
+      "binding" : "FabricIngress.forwarding.routing_v4",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 80,
+        "column" : 50,
+        "source_fragment" : "routing_v4_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.acl_counter",
       "id" : 6,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.acl"
+      "binding" : "FabricIngress.forwarding.acl",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 107,
+        "column" : 50,
+        "source_fragment" : "acl_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.vlan_meta_counter",
       "id" : 7,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.vlan_meta"
+      "binding" : "FabricIngress.next.vlan_meta",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 58,
+        "column" : 50,
+        "source_fragment" : "vlan_meta_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.simple_counter",
       "id" : 8,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.simple"
+      "binding" : "FabricIngress.next.simple",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 82,
+        "column" : 50,
+        "source_fragment" : "simple_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.hashed_counter",
       "id" : 9,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.hashed"
+      "binding" : "FabricIngress.next.hashed",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 146,
+        "column" : 50,
+        "source_fragment" : "hashed_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.multicast_counter",
       "id" : 10,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.multicast"
+      "binding" : "FabricIngress.next.multicast",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 199,
+        "column" : 50,
+        "source_fragment" : "multicast_counter"
+      }
     },
     {
       "name" : "FabricIngress.port_counters_control.egress_port_counter",
@@ -1033,7 +1107,13 @@
       "name" : "FabricEgress.egress_next.egress_vlan_counter",
       "id" : 13,
       "is_direct" : true,
-      "binding" : "FabricEgress.egress_next.egress_vlan"
+      "binding" : "FabricEgress.egress_next.egress_vlan",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 250,
+        "column" : 50,
+        "source_fragment" : "egress_vlan_counter"
+      }
     }
   ],
   "register_arrays" : [],
@@ -1578,7 +1658,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 91,
+            "line" : 99,
             "column" : 31,
             "source_fragment" : "0x8100; ..."
           }
@@ -2211,7 +2291,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2287,7 +2367,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2402,7 +2482,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2478,7 +2558,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2770,7 +2850,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2846,7 +2926,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2961,7 +3041,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -3037,7 +3117,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -3155,7 +3235,7 @@
           ],
           "source_info" : {
             "filename" : "fabric.p4",
-            "line" : 54,
+            "line" : 55,
             "column" : 50,
             "source_fragment" : "hdr.gtpu_ipv4"
           }
@@ -3170,7 +3250,7 @@
           ],
           "source_info" : {
             "filename" : "fabric.p4",
-            "line" : 54,
+            "line" : 55,
             "column" : 65,
             "source_fragment" : "hdr.gtpu_udp"
           }
@@ -3461,7 +3541,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 121,
+            "line" : 129,
             "column" : 36,
             "source_fragment" : "2w1; ..."
           }
@@ -3547,7 +3627,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 122,
+            "line" : 130,
             "column" : 38,
             "source_fragment" : "2w2; ..."
           }
@@ -3573,7 +3653,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 120,
+            "line" : 128,
             "column" : 37,
             "source_fragment" : "2w0; ..."
           }
@@ -3744,7 +3824,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 111,
+            "line" : 119,
             "column" : 31,
             "source_fragment" : "7; ..."
           }
@@ -3770,7 +3850,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 94,
+            "line" : 102,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
           }
@@ -4301,7 +4381,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 103,
+            "line" : 111,
             "column" : 28,
             "source_fragment" : "5; ..."
           }
@@ -4457,7 +4537,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 116,
+            "line" : 124,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -4476,7 +4556,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 100,
+            "line" : 108,
             "column" : 25,
             "source_fragment" : "17; ..."
           }
@@ -6255,6 +6335,12 @@
         {
           "name" : "FabricIngress.next.ecmp_selector",
           "id" : 0,
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 145,
+            "column" : 55,
+            "source_fragment" : "ecmp_selector"
+          },
           "max_size" : 64,
           "selector" : {
             "algo" : "crc16",
@@ -6799,7 +6885,7 @@
       "id" : 1,
       "source_info" : {
         "filename" : "fabric.p4",
-        "line" : 79,
+        "line" : 80,
         "column" : 8,
         "source_fragment" : "FabricEgress"
       },
@@ -7221,6 +7307,12 @@
     {
       "name" : "cksum",
       "id" : 0,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 28,
+        "column" : 8,
+        "source_fragment" : "update_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc",
@@ -7239,6 +7331,12 @@
     {
       "name" : "cksum_0",
       "id" : 1,
+      "source_info" : {
+        "filename" : "include/spgw.p4",
+        "line" : 237,
+        "column" : 8,
+        "source_fragment" : "update_checksum(gtpu_ipv4.isValid(), ..."
+      },
       "target" : ["gtpu_ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_0",
@@ -7257,6 +7355,12 @@
     {
       "name" : "cksum_1",
       "id" : 2,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 57,
+        "column" : 8,
+        "source_fragment" : "verify_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_1",
diff --git a/pipelines/fabric/src/main/resources/p4c-out/fabric/bmv2/default/bmv2.json b/pipelines/fabric/src/main/resources/p4c-out/fabric/bmv2/default/bmv2.json
index 0623d6c..6a4bdb1 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/fabric/bmv2/default/bmv2.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/fabric/bmv2/default/bmv2.json
@@ -47,6 +47,7 @@
         ["egress_rid", 16, false],
         ["checksum_error", 1, false],
         ["recirculate_flag", 32, false],
+        ["parser_error", 32, false],
         ["_padding", 5, false]
       ]
     },
@@ -256,7 +257,14 @@
   "header_unions" : [],
   "header_union_stacks" : [],
   "field_lists" : [],
-  "errors" : [],
+  "errors" : [
+    ["NoError", 1],
+    ["PacketTooShort", 2],
+    ["NoMatch", 3],
+    ["StackOutOfBounds", 4],
+    ["HeaderTooShort", 5],
+    ["ParserTimeout", 6]
+  ],
   "enums" : [],
   "parsers" : [
     {
@@ -687,61 +695,121 @@
       "name" : "FabricIngress.filtering.ingress_port_vlan_counter",
       "id" : 0,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.ingress_port_vlan"
+      "binding" : "FabricIngress.filtering.ingress_port_vlan",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "ingress_port_vlan_counter"
+      }
     },
     {
       "name" : "FabricIngress.filtering.fwd_classifier_counter",
       "id" : 1,
       "is_direct" : true,
-      "binding" : "FabricIngress.filtering.fwd_classifier"
+      "binding" : "FabricIngress.filtering.fwd_classifier",
+      "source_info" : {
+        "filename" : "include/control/filtering.p4",
+        "line" : 96,
+        "column" : 50,
+        "source_fragment" : "fwd_classifier_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.bridging_counter",
       "id" : 2,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.bridging"
+      "binding" : "FabricIngress.forwarding.bridging",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 34,
+        "column" : 50,
+        "source_fragment" : "bridging_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.mpls_counter",
       "id" : 3,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.mpls"
+      "binding" : "FabricIngress.forwarding.mpls",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 57,
+        "column" : 50,
+        "source_fragment" : "mpls_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.routing_v4_counter",
       "id" : 4,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.routing_v4"
+      "binding" : "FabricIngress.forwarding.routing_v4",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 80,
+        "column" : 50,
+        "source_fragment" : "routing_v4_counter"
+      }
     },
     {
       "name" : "FabricIngress.forwarding.acl_counter",
       "id" : 5,
       "is_direct" : true,
-      "binding" : "FabricIngress.forwarding.acl"
+      "binding" : "FabricIngress.forwarding.acl",
+      "source_info" : {
+        "filename" : "include/control/forwarding.p4",
+        "line" : 107,
+        "column" : 50,
+        "source_fragment" : "acl_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.vlan_meta_counter",
       "id" : 6,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.vlan_meta"
+      "binding" : "FabricIngress.next.vlan_meta",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 58,
+        "column" : 50,
+        "source_fragment" : "vlan_meta_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.simple_counter",
       "id" : 7,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.simple"
+      "binding" : "FabricIngress.next.simple",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 82,
+        "column" : 50,
+        "source_fragment" : "simple_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.hashed_counter",
       "id" : 8,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.hashed"
+      "binding" : "FabricIngress.next.hashed",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 146,
+        "column" : 50,
+        "source_fragment" : "hashed_counter"
+      }
     },
     {
       "name" : "FabricIngress.next.multicast_counter",
       "id" : 9,
       "is_direct" : true,
-      "binding" : "FabricIngress.next.multicast"
+      "binding" : "FabricIngress.next.multicast",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 199,
+        "column" : 50,
+        "source_fragment" : "multicast_counter"
+      }
     },
     {
       "name" : "FabricIngress.port_counters_control.egress_port_counter",
@@ -771,7 +839,13 @@
       "name" : "FabricEgress.egress_next.egress_vlan_counter",
       "id" : 12,
       "is_direct" : true,
-      "binding" : "FabricEgress.egress_next.egress_vlan"
+      "binding" : "FabricEgress.egress_next.egress_vlan",
+      "source_info" : {
+        "filename" : "include/control/next.p4",
+        "line" : 250,
+        "column" : 50,
+        "source_fragment" : "egress_vlan_counter"
+      }
     }
   ],
   "register_arrays" : [],
@@ -1087,7 +1161,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 91,
+            "line" : 99,
             "column" : 31,
             "source_fragment" : "0x8100; ..."
           }
@@ -1720,7 +1794,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -1796,7 +1870,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -1911,7 +1985,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -1987,7 +2061,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2279,7 +2353,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2355,7 +2429,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2470,7 +2544,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 92,
+            "line" : 100,
             "column" : 31,
             "source_fragment" : "0x8847; ..."
           }
@@ -2546,7 +2620,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 115,
+            "line" : 123,
             "column" : 32,
             "source_fragment" : "64; ..."
           }
@@ -2762,7 +2836,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 111,
+            "line" : 119,
             "column" : 31,
             "source_fragment" : "7; ..."
           }
@@ -2788,7 +2862,7 @@
           ],
           "source_info" : {
             "filename" : "include/control/../define.p4",
-            "line" : 94,
+            "line" : 102,
             "column" : 31,
             "source_fragment" : "0x0800; ..."
           }
@@ -4239,6 +4313,12 @@
         {
           "name" : "FabricIngress.next.ecmp_selector",
           "id" : 0,
+          "source_info" : {
+            "filename" : "include/control/next.p4",
+            "line" : 145,
+            "column" : 55,
+            "source_fragment" : "ecmp_selector"
+          },
           "max_size" : 64,
           "selector" : {
             "algo" : "crc16",
@@ -4612,7 +4692,7 @@
       "id" : 1,
       "source_info" : {
         "filename" : "fabric.p4",
-        "line" : 79,
+        "line" : 80,
         "column" : 8,
         "source_fragment" : "FabricEgress"
       },
@@ -4985,6 +5065,12 @@
     {
       "name" : "cksum",
       "id" : 0,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 28,
+        "column" : 8,
+        "source_fragment" : "update_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc",
@@ -5003,6 +5089,12 @@
     {
       "name" : "cksum_0",
       "id" : 1,
+      "source_info" : {
+        "filename" : "include/checksum.p4",
+        "line" : 57,
+        "column" : 8,
+        "source_fragment" : "verify_checksum(hdr.ipv4.isValid(), ..."
+      },
       "target" : ["ipv4", "hdr_checksum"],
       "type" : "generic",
       "calculation" : "calc_0",
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 cb6df8d4..6cf1ddc 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
@@ -321,7 +321,8 @@
                 while (dis.read(buffer) > 0) {
                     // nothing to do :)
                 }
-                dis.getMessageDigest().digest();
+                is.close();
+                return dis.getMessageDigest().digest();
             } catch (NoSuchAlgorithmException ignored) {
             } catch (IOException e) {
                 log.info("Error reading file file: {}", filepath);
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ClientKey.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ClientKey.java
index ee5e2a4..cc4bed0 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ClientKey.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ClientKey.java
@@ -22,7 +22,7 @@
 import java.util.Objects;
 
 /**
- * Key the uniquely identifies a P4Runtime client.
+ * Key that uniquely identifies a P4Runtime client.
  */
 final class ClientKey {
 
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DistributedElectionIdGenerator.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DistributedElectionIdGenerator.java
index ecfe35d..75c068e 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DistributedElectionIdGenerator.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/DistributedElectionIdGenerator.java
@@ -38,6 +38,7 @@
 
     private final Logger log = getLogger(this.getClass());
 
+    // FIXME: counter map use long, but P4Runtime accepts 128bit election IDs
     private AtomicCounterMap<DeviceId> electionIds;
 
     /**
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java
index 0be1ae8..f2ececb 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java
@@ -22,6 +22,8 @@
 import p4.v1.P4RuntimeOuterClass.MulticastGroupEntry;
 import p4.v1.P4RuntimeOuterClass.Replica;
 
+import static java.lang.String.format;
+
 /**
  * A coded of {@link PiMulticastGroupEntry} to P4Runtime MulticastGroupEntry
  * messages, and vice versa.
@@ -38,16 +40,26 @@
      *
      * @param piEntry PiMulticastGroupEntry
      * @return P4Runtime MulticastGroupEntry message
+     * @throws EncodeException if the PiMulticastGroupEntry cannot be encoded.
      */
-    static MulticastGroupEntry encode(PiMulticastGroupEntry piEntry) {
+    static MulticastGroupEntry encode(PiMulticastGroupEntry piEntry) throws EncodeException {
         final MulticastGroupEntry.Builder msgBuilder = MulticastGroupEntry.newBuilder();
         msgBuilder.setMulticastGroupId(piEntry.groupId());
-        piEntry.replicas().stream()
-                .map(r -> Replica.newBuilder()
-                        .setEgressPort(r.egressPort().toLong())
-                        .setInstance(r.instanceId())
-                        .build())
-                .forEach(msgBuilder::addReplicas);
+        for (PiPreReplica replica : piEntry.replicas()) {
+            final int p4PortId;
+            try {
+                p4PortId = Math.toIntExact(replica.egressPort().toLong());
+            } catch (ArithmeticException e) {
+                throw new EncodeException(format(
+                        "Cannot cast 64bit port value '%s' to 32bit",
+                        replica.egressPort()));
+            }
+            msgBuilder.addReplicas(
+                    Replica.newBuilder()
+                            .setEgressPort(p4PortId)
+                            .setInstance(replica.instanceId())
+                            .build());
+        }
         return msgBuilder.build();
     }
 
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 54d284d..c291db4 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
@@ -1053,7 +1053,15 @@
             WriteOperationType opType) {
 
         final List<Update> updateMsgs = entries.stream()
-                .map(MulticastGroupEntryCodec::encode)
+                .map(piEntry -> {
+                    try {
+                        return MulticastGroupEntryCodec.encode(piEntry);
+                    } catch (EncodeException e) {
+                        log.warn("Unable to encode PiMulticastGroupEntry: {}", e.getMessage());
+                        return null;
+                    }
+                })
+                .filter(Objects::nonNull)
                 .map(mcMsg -> PacketReplicationEngineEntry.newBuilder()
                         .setMulticastGroupEntry(mcMsg)
                         .build())
@@ -1117,13 +1125,22 @@
                               WriteOperationType opType,
                               String entryType) {
         // True if all entities were successfully written.
-        return writeAndReturnSuccessEntities(updates, writeEntities, opType,
-                                             entryType).size() == writeEntities.size();
+        return writeAndReturnSuccessEntities(updates, writeEntities, opType, entryType)
+                .size() == writeEntities.size();
     }
 
     private <T> List<T> writeAndReturnSuccessEntities(
             List<Update> updates, List<T> writeEntities,
             WriteOperationType opType, String entryType) {
+        if (updates.isEmpty()) {
+            return Collections.emptyList();
+        }
+        if (updates.size() != writeEntities.size()) {
+            log.error("Cannot perform {} operation, provided {} " +
+                              "update messages for {} {} - BUG?",
+                      opType, updates.size(), writeEntities.size(), entryType);
+            return Collections.emptyList();
+        }
         try {
             //noinspection ResultOfMethodCallIgnored
             blockingStub.write(writeRequest(updates));
diff --git a/protocols/restconf/server/rpp/src/main/webapp/WEB-INF/web.xml b/protocols/restconf/server/rpp/src/main/webapp/WEB-INF/web.xml
index 604057b..16a07b5 100644
--- a/protocols/restconf/server/rpp/src/main/webapp/WEB-INF/web.xml
+++ b/protocols/restconf/server/rpp/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,27 @@
          id="ONOS" version="2.5">
     <display-name>ONOS RESTCONF Protocol Proxy</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>
+            <role-name>viewer</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+        <role-name>viewer</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
     <servlet>
         <servlet-name>RESTCONF Protocol Proxy</servlet-name>
         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
diff --git a/tools/build/bazel/generate_workspace.bzl b/tools/build/bazel/generate_workspace.bzl
index 73e9fa5..8be53fe 100644
--- a/tools/build/bazel/generate_workspace.bzl
+++ b/tools/build/bazel/generate_workspace.bzl
@@ -1,4 +1,4 @@
-# ***** This file was auto-generated at Mon, 22 Oct 2018 16:26:22 GMT. Do not edit this file manually. *****
+# ***** This file was auto-generated at Tue, 23 Oct 2018 17:46:21 GMT. Do not edit this file manually. *****
 # ***** Use onos-lib-gen *****
 
 load("//tools/build/bazel:variables.bzl", "ONOS_GROUP_ID", "ONOS_VERSION")
@@ -163,51 +163,51 @@
     if "atomix" not in native.existing_rules():
         java_import_external(
             name = "atomix",
-            jar_sha256 = "72dad2fa314a8fdc3f10ef0a7e73a667c370cd576863e483fa3f4bb6c82bbb2c",
+            jar_sha256 = "4d6c72efa8e42908dbb3e6594fde5f5aef7a7c5c981da67a624ba2cbf2959b71",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix/3.0.5/atomix-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix/3.0.7/atomix-3.0.7.jar"],        )
     if "atomix_cluster" not in native.existing_rules():
         java_import_external(
             name = "atomix_cluster",
-            jar_sha256 = "139a70b2b733c2fc5cd03d9e82e3075dc73ca54ed317ad7594d4c818f3b70506",
+            jar_sha256 = "2415ca61a697593eaacf7afb5884b999fdd77600ba21b5edda5a3af50a8fcb10",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-cluster/3.0.5/atomix-cluster-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-cluster/3.0.7/atomix-cluster-3.0.7.jar"],        )
     if "atomix_gossip" not in native.existing_rules():
         java_import_external(
             name = "atomix_gossip",
-            jar_sha256 = "34b92866b57d63636871a5d68e84acbad727237541bcbda572167990505f3e7a",
+            jar_sha256 = "ebc82fe9dc396ab03c7dd8e8db1507b90238d1d426c585390ea5fcc0696675fd",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-gossip/3.0.5/atomix-gossip-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-gossip/3.0.7/atomix-gossip-3.0.7.jar"],        )
     if "atomix_primary_backup" not in native.existing_rules():
         java_import_external(
             name = "atomix_primary_backup",
-            jar_sha256 = "1da0a4eff24cd259b75e7c8c39a7f6396bd3aec5d4b06d6740412dc9237f8aa3",
+            jar_sha256 = "0205ffef779bcb55144355679a34f1adeba6644f8949bed0cd8f80ffb48aa014",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-primary-backup/3.0.5/atomix-primary-backup-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-primary-backup/3.0.7/atomix-primary-backup-3.0.7.jar"],        )
     if "atomix_primitive" not in native.existing_rules():
         java_import_external(
             name = "atomix_primitive",
-            jar_sha256 = "80a7b4e0e2aee6ccbeab7a0f66485cd29affbf3f10abfd7740961223a0c76002",
+            jar_sha256 = "8f37e8e73c168e48b7fd45c40514b447eb319a78bdb0a3af5520d0546b9551f1",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-primitive/3.0.5/atomix-primitive-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-primitive/3.0.7/atomix-primitive-3.0.7.jar"],        )
     if "atomix_raft" not in native.existing_rules():
         java_import_external(
             name = "atomix_raft",
-            jar_sha256 = "7f27c11d3f5948190b53714d3a9a12d7a3c967fbe4d4bf0c8cbeb5a75715a78f",
+            jar_sha256 = "76c3d624e4f384cb9bc43430f5a57fca4eb7b9ec1394a67020b5a5bb7c0f1988",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-raft/3.0.5/atomix-raft-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-raft/3.0.7/atomix-raft-3.0.7.jar"],        )
     if "atomix_storage" not in native.existing_rules():
         java_import_external(
             name = "atomix_storage",
-            jar_sha256 = "038a939d2bfc12488bc584c7144a9aeed4c91e0fe30ef514c522bdda352026f1",
+            jar_sha256 = "f190f17969c4c31fee50af99034c6a569505a7d7afd3b034661373d455377dd6",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-storage/3.0.5/atomix-storage-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-storage/3.0.7/atomix-storage-3.0.7.jar"],        )
     if "atomix_utils" not in native.existing_rules():
         java_import_external(
             name = "atomix_utils",
-            jar_sha256 = "e928e252861f8689e450829eaf671c08f5e5afe3f95389866a8ae494ab165987",
+            jar_sha256 = "d13840f8bc55385167ca18637b955fd554d6b3ee0fe1c20c8ba1c87f0cc68cde",
             licenses = ["notice"],
-            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-utils/3.0.5/atomix-utils-3.0.5.jar"],        )
+            jar_urls = ["http://repo1.maven.org/maven2/io/atomix/atomix-utils/3.0.7/atomix-utils-3.0.7.jar"],        )
     if "classgraph" not in native.existing_rules():
         java_import_external(
             name = "classgraph",
@@ -1424,14 +1424,14 @@
 artifact_map["@aopalliance_repackaged//:aopalliance_repackaged"] = "mvn:org.glassfish.hk2.external:aopalliance-repackaged:jar:2.5.0-b42"
 artifact_map["@amqp_client//:amqp_client"] = "mvn:com.rabbitmq:amqp-client:jar:3.6.1"
 artifact_map["@asm//:asm"] = "mvn:org.ow2.asm:asm:jar:5.2"
-artifact_map["@atomix//:atomix"] = "mvn:io.atomix:atomix:jar:3.0.5"
-artifact_map["@atomix_cluster//:atomix_cluster"] = "mvn:io.atomix:atomix-cluster:jar:3.0.5"
-artifact_map["@atomix_gossip//:atomix_gossip"] = "mvn:io.atomix:atomix-gossip:jar:3.0.5"
-artifact_map["@atomix_primary_backup//:atomix_primary_backup"] = "mvn:io.atomix:atomix-primary-backup:jar:3.0.5"
-artifact_map["@atomix_primitive//:atomix_primitive"] = "mvn:io.atomix:atomix-primitive:jar:3.0.5"
-artifact_map["@atomix_raft//:atomix_raft"] = "mvn:io.atomix:atomix-raft:jar:3.0.5"
-artifact_map["@atomix_storage//:atomix_storage"] = "mvn:io.atomix:atomix-storage:jar:3.0.5"
-artifact_map["@atomix_utils//:atomix_utils"] = "mvn:io.atomix:atomix-utils:jar:3.0.5"
+artifact_map["@atomix//:atomix"] = "mvn:io.atomix:atomix:jar:3.0.7"
+artifact_map["@atomix_cluster//:atomix_cluster"] = "mvn:io.atomix:atomix-cluster:jar:3.0.7"
+artifact_map["@atomix_gossip//:atomix_gossip"] = "mvn:io.atomix:atomix-gossip:jar:3.0.7"
+artifact_map["@atomix_primary_backup//:atomix_primary_backup"] = "mvn:io.atomix:atomix-primary-backup:jar:3.0.7"
+artifact_map["@atomix_primitive//:atomix_primitive"] = "mvn:io.atomix:atomix-primitive:jar:3.0.7"
+artifact_map["@atomix_raft//:atomix_raft"] = "mvn:io.atomix:atomix-raft:jar:3.0.7"
+artifact_map["@atomix_storage//:atomix_storage"] = "mvn:io.atomix:atomix-storage:jar:3.0.7"
+artifact_map["@atomix_utils//:atomix_utils"] = "mvn:io.atomix:atomix-utils:jar:3.0.7"
 artifact_map["@classgraph//:classgraph"] = "mvn:io.github.classgraph:classgraph:jar:4.2.3"
 artifact_map["@commons_codec//:commons_codec"] = "mvn:commons-codec:commons-codec:jar:1.10"
 artifact_map["@commons_cli//:commons_cli"] = "mvn:commons-cli:commons-cli:jar:1.3"
diff --git a/tools/build/bazel/p4lang_workspace.bzl b/tools/build/bazel/p4lang_workspace.bzl
index d4d966c..bc054fe 100644
--- a/tools/build/bazel/p4lang_workspace.bzl
+++ b/tools/build/bazel/p4lang_workspace.bzl
@@ -1,10 +1,10 @@
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 
-P4RUNTIME_COMMIT = "028552d98b774301c51be0fe5bc97c9e95716759"
-PI_COMMIT = "36ca74fae69c8d0a142f8bfd2487bee72505cf48"
+P4RUNTIME_COMMIT = "a6f81ac53c6b56d75a9603690794196d67c5dc07"
+PI_COMMIT = "539e4624f16aac39f8890a6dfb11c65040e735ad"
 
-P4RUNTIME_SHA = "f335573ea971c21a1a298954039a27881b7337a03f4523321b6458eb0558644a"
-PI_SHA = "767476cf9232dc39f0115d1ffc38f9b81acec74da078c048f278804f325bf77e"
+P4RUNTIME_SHA = "28b79868bcfd61058cdd3f77a7a021a1add19154fa6717bf921a64cece32caf3"
+PI_SHA = "a16024972c15e6d35466996bbb748e4b7bef819c1c93f05a0f2228062736c35a"
 
 def generate_p4lang():
     http_archive(
diff --git a/tools/dev/mininet/bmv2.py b/tools/dev/mininet/bmv2.py
index 296d672..eafb482 100644
--- a/tools/dev/mininet/bmv2.py
+++ b/tools/dev/mininet/bmv2.py
@@ -17,7 +17,7 @@
 VALGRIND_PREFIX = 'valgrind --leak-check=yes'
 SWITCH_START_TIMEOUT = 5  # seconds
 BMV2_LOG_LINES = 5
-BMV2_DEFAULT_DEVICE_ID = 0
+BMV2_DEFAULT_DEVICE_ID = 1
 
 
 def parseBoolean(value):
diff --git a/tools/dev/p4vm/install-p4-tools.sh b/tools/dev/p4vm/install-p4-tools.sh
index 4f9582a..e3ccdcd 100755
--- a/tools/dev/p4vm/install-p4-tools.sh
+++ b/tools/dev/p4vm/install-p4-tools.sh
@@ -21,9 +21,9 @@
 BUILD_DIR=~/p4tools
 # in case BMV2_COMMIT value is updated, the same variable in
 # protocols/bmv2/thrift-api/BUCK file should also be updated
-BMV2_COMMIT="13370aaf9329fcb369a3ea3989722eb5f61c07f3"
-PI_COMMIT="7e94b025bac6db63bc8534e5dd21a008984e38bc"
-P4C_COMMIT="2d089af757212a057c6690998861ef67439305f4"
+BMV2_COMMIT="ae87b4d4523488ac935133b4aef437796ad1bbd1"
+PI_COMMIT="539e4624f16aac39f8890a6dfb11c65040e735ad"
+P4C_COMMIT="380830f6c26135d1d65e1312e3ba2da628c18145"
 PROTOBUF_COMMIT="tags/v3.2.0"
 GRPC_COMMIT="tags/v1.3.2"
 LIBYANG_COMMIT="v0.14-r1"
@@ -32,7 +32,7 @@
 NUM_CORES=`grep -c ^processor /proc/cpuinfo`
 
 # If false, build tools without debug features to improve throughput of BMv2 and
-# reduce CPU/memory footprint.
+# reduce CPU/memory footprint. Default is true.
 DEBUG_FLAGS=${DEBUG_FLAGS:-true}
 
 # Execute up to the given step (first argument), or all if not defined.
@@ -274,12 +274,8 @@
 
     ./autogen.sh
     # FIXME: re-enable --with-sysrepo when gNMI support becomes more stable
-    # ./configure --with-proto --with-sysrepo 'CXXFLAGS=-O0 -g'
-    if [ "${DEBUG_FLAGS}" = true ] ; then
-        ./configure --with-proto "CXXFLAGS=-O0 -g"
-    else
-        ./configure --with-proto
-    fi
+    # ./configure --with-proto --with-sysrepo
+    ./configure --with-proto --without-internal-rpc --without-cli
     make -j${NUM_CORES}
     sudo make install
     sudo ldconfig
@@ -293,9 +289,9 @@
 
     ./autogen.sh
     if [ "${DEBUG_FLAGS}" = true ] ; then
-        ./configure --with-pi --disable-elogger --without-nanomsg "CXXFLAGS=-O0 -g"
+        ./configure --with-pi --disable-elogger --without-nanomsg
     else
-        ./configure --with-pi --disable-logging-macros --disable-elogger --without-nanomsg
+        ./configure --with-pi --disable-elogger --without-nanomsg --disable-logging-macros
     fi
     make -j${NUM_CORES}
     sudo make install
@@ -304,14 +300,9 @@
     # Simple_switch_grpc target
     cd targets/simple_switch_grpc
     ./autogen.sh
-
-    if [ "${DEBUG_FLAGS}" = true ] ; then
-        ./configure --with-thrift "CXXFLAGS=-O0 -g"
-    else
-        ./configure --with-thrift
-    fi
+    ./configure --with-thrift
     # FIXME: re-enable --with-sysrepo when gNMI support becomes more stable
-    # ./configure --with-sysrepo --with-thrift 'CXXFLAGS=-O0 -g'
+    # ./configure --with-sysrepo --with-thrift
     make -j${NUM_CORES}
     sudo make install
     sudo ldconfig
@@ -329,7 +320,7 @@
 
     mkdir -p build
     cd build
-    cmake ..
+    cmake .. -DENABLE_EBPF=OFF
     make -j${NUM_CORES}
     sudo make install
     sudo ldconfig
diff --git a/tools/dev/p4vm/root-bootstrap.sh b/tools/dev/p4vm/root-bootstrap.sh
index cac34b7..cf90ea2 100755
--- a/tools/dev/p4vm/root-bootstrap.sh
+++ b/tools/dev/p4vm/root-bootstrap.sh
@@ -4,7 +4,7 @@
 VM_TYPE=${1:-dev}
 
 BAZEL_VER="0.15.2"
-BAZEL_DEB="bazel_${BAZEL_VER}-linux-x86_64.deb"
+BAZEL_SH="bazel-${BAZEL_VER}-installer-linux-x86_64.sh"
 # Create user sdn
 useradd -m -d /home/sdn -s /bin/bash sdn
 echo "sdn:rocks" | chpasswd
@@ -28,10 +28,8 @@
 
 DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade
 
-wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/${BAZEL_DEB}
 echo "oracle-java8-installer shared/accepted-oracle-license-v1-1 select true" | debconf-set-selections
 apt-get -y --no-install-recommends install \
-    ./${BAZEL_DEB} \
     avahi-daemon \
     bridge-utils \
     git \
@@ -59,12 +57,16 @@
 
 DEBIAN_FRONTEND=noninteractive apt-get -yq install wireshark
 
-rm -f ${BAZEL_DEB}
+# Install Bazel
+wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/${BAZEL_SH}
+chmod +x ${BAZEL_SH}
+./${BAZEL_SH}
+rm -f ${BAZEL_SH}
 
+# Install pip and some python deps (others are defined in install-p4-tools.sh)
 curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
 python2.7 get-pip.py --force-reinstall
 rm -f get-pip.py
-
 pip install ipaddress
 
 tee -a /etc/ssh/sshd_config <<EOF
diff --git a/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java b/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
index d97c89a..3bff799 100644
--- a/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
+++ b/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
@@ -269,6 +269,7 @@
                     .map(cfg -> expand(cfg.getRootNode().getValue().toString()))
                     .collect(Collectors.toList());
 
+            stream.close();
         } catch (ConfigurationException e) {
             throw new MojoExecutionException("Unable to parse app.xml file", e);
         } catch (FileNotFoundException e) {
diff --git a/tools/test/bin/atomix-install b/tools/test/bin/atomix-install
index 5a10413..af210ae 100755
--- a/tools/test/bin/atomix-install
+++ b/tools/test/bin/atomix-install
@@ -47,7 +47,7 @@
     [ -f $ATOMIX_INSTALL_DIR/bin/atomix-agent ] && echo \"Atomix is already installed\" && exit 1
 
     sudo mkdir -p $ATOMIX_INSTALL_DIR && sudo chown ${ONOS_USER}:${ONOS_GROUP} $ATOMIX_INSTALL_DIR
-    sudo wget -O $ATOMIX_INSTALL_DIR/atomix-dist.tar.gz https://oss.sonatype.org/content/repositories/releases/io/atomix/atomix-dist/3.0.6/atomix-dist-3.0.6.tar.gz
+    sudo wget -O $ATOMIX_INSTALL_DIR/atomix-dist.tar.gz https://oss.sonatype.org/content/repositories/releases/io/atomix/atomix-dist/3.0.7/atomix-dist-3.0.7.tar.gz
     tar -xvf $ATOMIX_INSTALL_DIR/atomix-dist.tar.gz -C $ATOMIX_INSTALL_DIR
 "
 
diff --git a/web/gui2/src/main/webapp/tests/app/consolelogger.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/consolelogger.service.spec.ts
similarity index 93%
rename from web/gui2/src/main/webapp/tests/app/consolelogger.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/consolelogger.service.spec.ts
index 1b01809..bbb8974 100644
--- a/web/gui2/src/main/webapp/tests/app/consolelogger.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/consolelogger.service.spec.ts
@@ -15,7 +15,7 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { ConsoleLoggerService } from '../../app/consolelogger.service';
+import { ConsoleLoggerService } from './consolelogger.service';
 
 /**
  * ONOS GUI -- Console Logger Service - Unit Tests
diff --git a/web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/detectbrowser.directive.spec.ts
similarity index 87%
rename from web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/detectbrowser.directive.spec.ts
index 37f4a8e..3faa7f1 100644
--- a/web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/detectbrowser.directive.spec.ts
@@ -15,12 +15,12 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../app/log.service';
-import { ConsoleLoggerService } from '../../app/consolelogger.service';
-import { DetectBrowserDirective } from '../../app/detectbrowser.directive';
+import { LogService } from './log.service';
+import { ConsoleLoggerService } from './consolelogger.service';
+import { DetectBrowserDirective } from './detectbrowser.directive';
 import { ActivatedRoute, Params } from '@angular/router';
-import { FnService } from '../../app/fw/util/fn.service';
-import { OnosService } from '../../app/onos.service';
+import { FnService } from './util/fn.service';
+import { OnosService } from './onos.service';
 import { of } from 'rxjs';
 
 class MockFnService extends FnService {
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/loading.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/loading.service.spec.ts
similarity index 74%
rename from web/gui2/src/main/webapp/tests/app/fw/layer/loading.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/loading.service.spec.ts
index 92655fa..404439f 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/layer/loading.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/loading.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2015-present Open Networking Foundation
+ *  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.
@@ -15,12 +15,12 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { LoadingService } from '../../../../app/fw/layer/loading.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { ThemeService } from '../../../../app/fw/util/theme.service';
-import { WebSocketService } from '../../../../app/fw/remote/websocket.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { LoadingService } from './loading.service';
+import { FnService } from '../util/fn.service';
+import { ThemeService } from '../util/theme.service';
+import { WebSocketService } from '../remote/websocket.service';
 
 class MockFnService {
     debug() {
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/log.service.spec.ts
similarity index 94%
rename from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/log.service.spec.ts
index 5307028..e2998f8 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/log.service.spec.ts
@@ -15,7 +15,7 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../app/log.service';
+import { LogService } from './log.service';
 
 /**
  * ONOS GUI -- Log Service - Unit Tests
diff --git a/web/gui2/src/main/webapp/tests/app/fw/mast/mast.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast.service.spec.ts
similarity index 78%
rename from web/gui2/src/main/webapp/tests/app/fw/mast/mast.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast.service.spec.ts
index 5c00e67..ca99af8 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/mast/mast.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
@@ -15,10 +15,10 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { MastService } from '../../../../app/fw/mast/mast.service';
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
+import { MastService } from './mast.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { FnService } from '../util/fn.service';
 
 class MockFnService {
     isMobile() {}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.css b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.css
index 5b2d464..a767b2e 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.css
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.css
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.html b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.html
index 2d4e606..437f96d 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.html
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.html
@@ -1,5 +1,5 @@
 <!--
-~ Copyright 2014-present Open Networking Foundation
+~ 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.
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.spec.ts
index fe424e7..fca2dd9 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.ts
index e8e5fec..41e2f3e 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.component.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.theme.css b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.theme.css
index 6b92beb..968aefa 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.theme.css
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/mast/mast/mast.theme.css
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/tests/app/fw/nav/nav.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.spec.ts
similarity index 73%
rename from web/gui2/src/main/webapp/tests/app/fw/nav/nav.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.spec.ts
index 44920df..88ab5fa 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/nav/nav.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
@@ -14,14 +14,18 @@
  * limitations under the License.
  */
 import { TestBed, inject } from '@angular/core/testing';
+import { HttpClient, HttpErrorResponse } from '@angular/common/http';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { NavService } from '../../../../app/fw/nav/nav.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { NavService } from './nav.service';
+import { FnService } from '../util/fn.service';
 
 class MockFnService {}
 
+class MockHttpClient {}
+
+
 /**
  * ONOS GUI -- Util -- Navigation Service - Unit Tests
  */
@@ -33,6 +37,7 @@
 
         TestBed.configureTestingModule({
             providers: [NavService,
+                { provide: HttpClient, useClass: MockHttpClient },
                 { provide: FnService, useClass: MockFnService },
                 { provide: LogService, useValue: log },
             ]
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts
index a24f242..6e96309 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/glyph.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyph.service.spec.ts
similarity index 78%
rename from web/gui2/src/main/webapp/tests/app/fw/svg/glyph.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyph.service.spec.ts
index 538cd9f..5b4669d 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/glyph.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyph.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
@@ -15,10 +15,10 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { GlyphService } from '../../../../app/fw/svg/glyph.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { GlyphService } from './glyph.service';
+import { FnService } from '../util/fn.service';
 
 class MockFnService {}
 
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/glyphdata.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyphdata.service.spec.ts
similarity index 80%
rename from web/gui2/src/main/webapp/tests/app/fw/svg/glyphdata.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyphdata.service.spec.ts
index 5fbf137..ab770d5 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/glyphdata.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyphdata.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2016-present Open Networking Foundation
+ *  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.
@@ -15,9 +15,9 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { GlyphDataService } from '../../../../app/fw/svg/glyphdata.service';
+import { LogService } from '..//log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { GlyphDataService } from './glyphdata.service';
 
 /**
  * ONOS GUI -- SVG -- Glyph Data Service - Unit Tests
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/icon.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.spec.ts
similarity index 76%
rename from web/gui2/src/main/webapp/tests/app/fw/svg/icon.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.spec.ts
index e6e54dc..094baef 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/icon.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2016-present Open Networking Foundation
+ *  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.
@@ -15,11 +15,11 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { IconService } from '../../../../app/fw/svg/icon.service';
-import { GlyphService } from '../../../../app/fw/svg/glyph.service';
-import { SvgUtilService } from '../../../../app/fw/svg/svgutil.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { IconService } from './icon.service';
+import { GlyphService } from './glyph.service';
+import { SvgUtilService } from './svgutil.service';
 
 class MockGlyphService {}
 
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts
index 6ced162..73480ed 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts
@@ -43,6 +43,7 @@
     ['m_ports', 'm_ports'],
 
     ['topo', 'topo'],
+    ['bird', 'bird'],
 
     ['refresh', 'refresh'],
     ['query', 'query'],
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/icon/icon.component.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/icon.component.spec.ts
similarity index 70%
rename from web/gui2/src/main/webapp/tests/app/fw/svg/icon/icon.component.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/icon.component.spec.ts
index 3ca58e3..8234551 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/icon/icon.component.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/icon.component.spec.ts
@@ -1,9 +1,9 @@
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { LogService } from '../../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../../app/consolelogger.service';
-import { IconComponent } from '../../../../../app/fw/svg/icon/icon.component';
-import { IconService } from '../../../../../app/fw/svg/icon.service';
+import { LogService } from '../../log.service';
+import { ConsoleLoggerService } from '../../consolelogger.service';
+import { IconComponent } from './icon.component';
+import { IconService } from '../icon.service';
 
 class MockIconService {}
 
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/svgutil.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.spec.ts
similarity index 78%
rename from web/gui2/src/main/webapp/tests/app/fw/svg/svgutil.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.spec.ts
index 593f5ad..7165b33 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/svgutil.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
@@ -15,10 +15,10 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { SvgUtilService } from '../../../../app/fw/svg/svgutil.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { SvgUtilService } from './svgutil.service';
+import { FnService } from '../util/fn.service';
 
 class MockFnService {}
 
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts
index 13327fe..6107d16 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts
@@ -16,6 +16,7 @@
 import { Injectable } from '@angular/core';
 import { FnService } from '../util/fn.service';
 import { LogService } from '../log.service';
+import * as d3 from 'd3';
 
 /**
  * ONOS GUI -- SVG -- Util Service
@@ -26,11 +27,45 @@
     providedIn: 'root',
 })
 export class SvgUtilService {
+    lightNorm: string[];
+    lightMute: string[];
+    darkNorm: string[];
+    darkMute: string[];
+    colors: any;
 
     constructor(
         private fs: FnService,
         private log: LogService
     ) {
+
+        // --- Ordinal scales for 7 values.
+        // TODO: migrate these colors to the theme service.
+
+        // Colors per Mojo-Design's color palette.. (version one)
+        //               blue       red        dk grey    steel      lt blue    lt red     lt grey
+        // var lightNorm = ['#5b99d2', '#d05a55', '#716b6b', '#7e9aa8', '#66cef6', '#db7773', '#aeada8' ],
+        //     lightMute = ['#a8cceb', '#f1a7a7', '#b9b5b5', '#bdcdd5', '#a8e9fd', '#f8c9c9', '#d7d6d4' ],
+
+        // Colors per Mojo-Design's color palette.. (version two)
+        //               blue       lt blue    red        green      brown      teal       lime
+        this.lightNorm = ['#5b99d2', '#66cef6', '#d05a55', '#0f9d58', '#ba7941', '#3dc0bf', '#56af00'];
+        this.lightMute = ['#9ebedf', '#abdef5', '#d79a96', '#7cbe99', '#cdab8d', '#96d5d5', '#a0c96d'];
+
+        this.darkNorm = ['#5b99d2', '#66cef6', '#d05a55', '#0f9d58', '#ba7941', '#3dc0bf', '#56af00'];
+        this.darkMute = ['#9ebedf', '#abdef5', '#d79a96', '#7cbe99', '#cdab8d', '#96d5d5', '#a0c96d'];
+
+
+        this.colors = {
+            light: {
+                norm: d3.scaleOrdinal().range(this.lightNorm),
+                mute: d3.scaleOrdinal().range(this.lightMute),
+            },
+            dark: {
+                norm: d3.scaleOrdinal().range(this.darkNorm),
+                mute: d3.scaleOrdinal().range(this.darkMute),
+            },
+        };
+
         this.log.debug('SvgUtilService constructed');
     }
 
@@ -40,4 +75,91 @@
         }
         return 'translate(' + x + ',' + y + ')';
     }
+
+    scale(x, y) {
+        return 'scale(' + x + ',' + y + ')';
+    }
+
+    skewX(x) {
+        return 'skewX(' + x + ')';
+    }
+
+    rotate(deg) {
+        return 'rotate(' + deg + ')';
+    }
+
+    cat7() {
+        const tcid = 'd3utilTestCard';
+
+        function getColor(id, muted, theme) {
+            // NOTE: since we are lazily assigning domain ids, we need to
+            //       get the color from all 4 scales, to keep the domains
+            //       in sync.
+            const ln = this.colors.light.norm(id);
+            const lm = this.colors.light.mute(id);
+            const dn = this.colors.dark.norm(id);
+            const dm = this.colors.dark.mute(id);
+            if (theme === 'dark') {
+                return muted ? dm : dn;
+            } else {
+                return muted ? lm : ln;
+            }
+        }
+
+        function testCard(svg) {
+            let g = svg.select('g#' + tcid);
+            const dom = d3.range(7);
+            let k;
+            let muted;
+            let theme;
+            let what;
+
+            if (!g.empty()) {
+                g.remove();
+
+            } else {
+                g = svg.append('g')
+                    .attr('id', tcid)
+                    .attr('transform', 'scale(4)translate(20,20)');
+
+                for (k = 0; k < 4; k++) {
+                    muted = k % 2;
+                    what = muted ? ' muted' : ' normal';
+                    theme = k < 2 ? 'light' : 'dark';
+                    dom.forEach(function (id, i) {
+                        const x = i * 20;
+                        const y = k * 20;
+                        const f = getColor(id, muted, theme);
+                        g.append('circle').attr({
+                            cx: x,
+                            cy: y,
+                            r: 5,
+                            fill: f,
+                        });
+                    });
+                    g.append('rect').attr({
+                        x: 140,
+                        y: k * 20 - 5,
+                        width: 32,
+                        height: 10,
+                        rx: 2,
+                        fill: '#888',
+                    });
+                    g.append('text').text(theme + what)
+                        .attr({
+                            x: 142,
+                            y: k * 20 + 2,
+                            fill: 'white',
+                        })
+                        .style('font-size', '4pt');
+                }
+            }
+        }
+
+        return {
+            testCard: testCard,
+            getColor: getColor,
+        };
+    }
+
 }
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.spec.ts
new file mode 100644
index 0000000..fe25860
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.spec.ts
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { of } from 'rxjs';
+import * as d3 from 'd3';
+
+import { LogService } from '../log.service';
+import { FnService } from '../util/fn.service';
+
+import { ZoomService, CZ, D3S, ZoomOpts, Zoomer } from './zoom.service';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+
+/**
+ * ONOS GUI -- SVG -- Zoom Service - Unit Tests
+ */
+describe('ZoomService', () => {
+    let zs: ZoomService;
+    let ar: ActivatedRoute;
+    let fs: FnService;
+    let mockWindow: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+
+    const svg = d3.select('body').append('svg').attr('id', 'mySvg');
+    const zoomLayer = svg.append('g').attr('id', 'myZoomlayer');
+
+    beforeEach(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({'debug': 'TestService'});
+        mockWindow = <any>{
+            innerWidth: 400,
+            innerHeight: 200,
+            navigator: {
+                userAgent: 'defaultUA'
+            }
+        };
+        fs = new FnService(ar, logSpy, mockWindow);
+
+        TestBed.configureTestingModule({
+            providers: [ ZoomService,
+                { provide: FnService, useValue: fs },
+                { provide: LogService, useValue: logSpy },
+                { provide: ActivatedRoute, useValue: ar },
+                { provide: 'Window', useFactory: (() => mockWindow ) }
+            ]
+        });
+
+        zs = TestBed.get(ZoomService);
+        logServiceSpy = TestBed.get(LogService);
+    });
+
+    it('should be created', () => {
+        expect(zs).toBeTruthy();
+    });
+
+    it('should define ZoomService', function () {
+        expect(zs).toBeDefined();
+    });
+
+    it('should define api functions', function () {
+        expect(fs.areFunctions(zs, [
+            'createZoomer',
+            'zoomed',
+            'adjustZoomLayer'
+        ])).toBeTruthy();
+    });
+
+    function verifyZoomerApi() {
+        expect(fs.areFunctions(zs.zoomer, [
+            'panZoom', 'reset', 'translate', 'scale', 'scaleExtent'
+        ])).toBeTruthy();
+    }
+
+    it('should fail gracefully with no option object', function () {
+        expect(() => zs.createZoomer(<ZoomOpts>{}))
+            .toThrow(new Error(CZ + 'No "svg" (svg tag)' + D3S));
+        expect(logServiceSpy.error)
+            .toHaveBeenCalledWith(CZ + 'No "svg" (svg tag)' + D3S);
+    });
+
+    it('should complain if we miss required options', function () {
+        expect(() => zs.createZoomer(<ZoomOpts>{svg: svg}))
+            .toThrow(new Error(CZ + 'No "zoomLayer" (g tag)' + D3S));
+        expect(logServiceSpy.error).toHaveBeenCalledWith(CZ + 'No "zoomLayer" (g tag)' + D3S);
+    });
+
+    it('should work with minimal parameters', function () {
+        const zoomer = zs.createZoomer(<ZoomOpts>{
+            svg: svg,
+            zoomLayer: zoomLayer
+        });
+        expect(logServiceSpy.error).not.toHaveBeenCalled();
+        verifyZoomerApi();
+    });
+
+    it('should start at scale 1 and translate 0,0', function () {
+        const zoomer = zs.createZoomer(<ZoomOpts>{
+            svg: svg,
+            zoomLayer: zoomLayer
+        });
+        verifyZoomerApi();
+        expect(zoomer.translate()).toEqual([0, 0]);
+        expect(zoomer.scale()).toEqual(1);
+    });
+
+    it('should allow programmatic pan/zoom', function () {
+        const zoomer: Zoomer = zs.createZoomer(<ZoomOpts>{
+            svg: svg,
+            zoomLayer: zoomLayer
+        });
+        verifyZoomerApi();
+
+        expect(zoomer.translate()).toEqual([0, 0]);
+        expect(zoomer.scale()).toEqual(1);
+
+        zoomer.panZoom([20, 30], 1);
+        expect(zoomer.translate()).toEqual([20, 30]);
+        expect(zoomer.scale()).toEqual(1);
+
+        zoomer.reset();
+        expect(zoomer.translate()).toEqual([0, 0]);
+        expect(zoomer.scale()).toEqual(1);
+
+
+    });
+
+    it('should provide default scale extent', function () {
+        const zoomer = zs.createZoomer(<ZoomOpts>{
+            svg: svg,
+            zoomLayer: zoomLayer
+        });
+        expect(zoomer.scaleExtent()).toEqual([0.05, 50]);
+    });
+
+    it('should allow us to override the minimum zoom', function () {
+        const zoomer = zs.createZoomer(<ZoomOpts>{
+            svg: svg,
+            zoomLayer: zoomLayer,
+            zoomMin: 1.23
+        });
+        expect(zoomer.scaleExtent()).toEqual([1.23, 50]);
+    });
+
+    it('should allow us to override the maximum zoom', function () {
+        const zoomer = zs.createZoomer(<ZoomOpts>{
+            svg: svg,
+            zoomLayer: zoomLayer,
+            zoomMax: 13
+        });
+        expect(zoomer.scaleExtent()).toEqual([0.05, 13]);
+    });
+
+    // TODO: test zoomed() where we fake out the d3.event.sourceEvent etc...
+    //  need to check default enabled (true) and custom enabled predicate
+    //  need to check that the callback is invoked also
+
+    it('should invoke the callback on programmatic pan/zoom', function () {
+        const foo = { cb() { return; } };
+        spyOn(foo, 'cb');
+
+        const zoomer = zs.createZoomer(<ZoomOpts>{
+            svg: svg,
+            zoomMin: 0.25,
+            zoomMax: 10,
+            zoomLayer: zoomLayer,
+            zoomEnabled: (ev) => true,
+            zoomCallback: foo.cb,
+        });
+
+        zoomer.panZoom([0, 0], 2);
+        expect(foo.cb).toHaveBeenCalled();
+    });
+});
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.ts
new file mode 100644
index 0000000..fdf08f9
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.ts
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+import { Injectable } from '@angular/core';
+import * as d3 from 'd3';
+import { LogService } from '../log.service';
+
+export interface ZoomOpts {
+    svg: any;                         // D3 selection of <svg> element
+    zoomLayer: any;                   // D3 selection of <g> element
+    zoomMin: number;                  // Min zoom level - usually 0.25
+    zoomMax: number;                  // Max zoom level - usually 10
+    zoomEnabled(ev: any): boolean;   // Function that takes event and returns boolean
+    zoomCallback(translate: number[], scale: number): void; // Function that is called on zoom
+}
+
+export interface Zoomer {
+    panZoom(translate: number[], scale: number, transition?: number): void;
+    reset(): void;
+    translate(): number[];
+    scale(): number;
+    scaleExtent(): number[];
+}
+
+export const CZ: string = 'ZoomService.createZoomer(): ';
+export const D3S: string = ' (D3 selection) property defined';
+
+/**
+ * ONOS GUI -- Topology Zoom Service Module.
+ */
+@Injectable({
+    providedIn: 'root',
+})
+export class ZoomService {
+    defaultSettings: ZoomOpts;
+
+    zoom: any;
+    public zoomer: Zoomer;
+    settings: ZoomOpts;
+
+    constructor(
+        protected log: LogService,
+    ) {
+        this.defaultSettings = <ZoomOpts>{
+            zoomMin: 0.05,
+            zoomMax: 50,
+            zoomEnabled: (ev) => true,
+            zoomCallback: (t, s) => { return; }
+        };
+
+        this.log.debug('ZoomService constructed');
+    }
+
+    createZoomer(opts: ZoomOpts): Zoomer {
+        this.settings = Object.assign(this.defaultSettings, opts);
+
+        if (!this.settings.svg) {
+            this.log.error(CZ + 'No "svg" (svg tag)' + D3S);
+            throw new Error(CZ + 'No "svg" (svg tag)' + D3S);
+        }
+        if (!this.settings.zoomLayer) {
+            this.log.error(CZ + 'No "zoomLayer" (g tag)' + D3S);
+            throw new Error(CZ + 'No "zoomLayer" (g tag)' + D3S);
+        }
+
+        this.zoom = d3.zoom()
+            .scaleExtent([this.settings.zoomMin, this.settings.zoomMax])
+            .extent([[0, 0], [1000, 1000]])
+            .on('zoom', () => this.zoomed);
+
+
+        this.zoomer = <Zoomer>{
+            panZoom: (translate: number[], scale: number, transition?: number) => {
+                this.settings.svg.call(this.zoom.translateBy, translate[0], translate[1]);
+                this.settings.svg.call(this.zoom.scaleTo, scale);
+                this.adjustZoomLayer(translate, scale, transition);
+            },
+
+            reset: () => {
+                this.settings.svg.call(this.zoom.translateTo, 500, 500);
+                this.settings.svg.call(this.zoom.scaleTo, 1);
+                this.adjustZoomLayer([0, 0], 1, 0);
+            },
+
+            translate: () => {
+                const trans = d3.zoomTransform(this.settings.svg.node());
+                return [trans.x, trans.y];
+            },
+
+            scale: () => {
+                const trans = d3.zoomTransform(this.settings.svg.node());
+                return trans.k;
+            },
+
+            scaleExtent: () => {
+                return this.zoom.scaleExtent();
+            },
+        };
+
+        // apply the zoom behavior to the SVG element
+/*
+        if (this.settings.svg ) {
+            this.settings.svg.call(this.zoom);
+        }
+*/
+        // Remove zoom on double click (prevents a
+        // false zoom navigating regions)
+        this.settings.svg.on('dblclick.zoom', null);
+
+        return this.zoomer;
+    }
+
+    /**
+     * zoom events from mouse gestures...
+     */
+    zoomed() {
+        const ev = d3.event.sourceEvent;
+        if (this.settings.zoomEnabled(ev)) {
+            this.adjustZoomLayer(d3.event.translate, d3.event.scale);
+        }
+    }
+
+    /**
+     * Adjust the zoom layer
+     */
+    adjustZoomLayer(translate: number[], scale: number, transition?: any): void {
+
+        this.settings.zoomLayer.transition()
+            .duration(transition || 0)
+            .attr('transform',
+                'translate(' + translate + ') scale(' + scale + ')');
+
+        this.settings.zoomCallback(translate, scale);
+    }
+
+}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.spec.ts
index 5b86d56..e9b7c2a 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.spec.ts
@@ -235,7 +235,8 @@
             'isFirefox', 'parseDebugFlags',
             'debugOn', 'debug', 'find', 'inArray', 'removeFromArray',
             'isEmptyObject', 'cap', 'noPx', 'noPxStyle', 'endsWith',
-            'inEvilList', 'analyze', 'sanitize', 'sameObjProps', 'containsObj'
+            'inEvilList', 'analyze', 'sanitize', 'sameObjProps', 'containsObj',
+            'addToTrie', 'removeFromTrie', 'trieLookup'
 //            'find', 'inArray', 'removeFromArray', 'isEmptyObject', 'sameObjProps', 'containsObj', 'cap',
 //            'eecode', 'noPx', 'noPxStyle', 'endsWith', 'addToTrie', 'removeFromTrie', 'trieLookup',
 //            'classNames', 'extend', 'sanitize'
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.ts
index 506ce74..60d4950 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/fn.service.ts
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { Injectable, Inject } from '@angular/core';
-import { ActivatedRoute, Router} from '@angular/router';
-import { LogService } from '../log.service';
+import {Inject, Injectable} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import {LogService} from '../log.service';
+import {Trie, TrieOp} from './trie';
 
 // Angular>=2 workaround for missing definition
 declare const InstallTrigger: any;
@@ -40,112 +41,6 @@
     name: string;
 }
 
-// TODO Move all this trie stuff to its own class
-// Angular>=2 Tightened up on types to avoid compiler errors
-interface TrieC {
-    p: any;
-    s: string[];
-}
-// trie operation
-function _trieOp(op: string, trie, word: string, data) {
-    const p = trie;
-    const w: string = word.toUpperCase();
-    const s: Array<string> = w.split('');
-    let c: TrieC = { p: p, s: s };
-    let t = [];
-    let  x = 0;
-    const f1 = op === '+' ? add : probe;
-    const f2 = op === '+' ? insert : remove;
-
-    function add(cAdded): TrieC {
-        const q = cAdded.s.shift();
-        let np = cAdded.p[q];
-
-        if (!np) {
-            cAdded.p[q] = {};
-            np = cAdded.p[q];
-            x = 1;
-        }
-        return { p: np, s: cAdded.s };
-    }
-
-    function probe(cProbed): TrieC {
-        const q = cProbed.s.shift();
-        const k: number = Object.keys(cProbed.p).length;
-        const np = cProbed.p[q];
-
-        t.push({ q: q, k: k, p: cProbed.p });
-        if (!np) {
-            t = [];
-            return { p: [], s: [] };
-        }
-        return { p: np, s: cProbed.s };
-    }
-
-    function insert() {
-        c.p._data = data;
-        return x ? 'added' : 'updated';
-    }
-
-    function remove() {
-        if (t.length) {
-            t = t.reverse();
-            while (t.length) {
-                const d = t.shift();
-                delete d.p[d.q];
-                if (d.k > 1) {
-                    t = [];
-                }
-            }
-            return 'removed';
-        }
-        return 'absent';
-    }
-
-    while (c.s.length) {
-        c = f1(c);
-    }
-    return f2();
-}
-
-// add word to trie (word will be converted to uppercase)
-// data associated with the word
-// returns 'added' or 'updated'
-function addToTrie(trie, word, data) {
-    return _trieOp('+', trie, word, data);
-}
-
-// remove word from trie (word will be converted to uppercase)
-// returns 'removed' or 'absent'
-// Angular>=2 added in quotes for data. error TS2554: Expected 4 arguments, but got 3.
-function removeFromTrie(trie, word) {
-    return _trieOp('-', trie, word, '');
-}
-
-// lookup word (converted to uppercase) in trie
-// returns:
-//    undefined if the word is not in the trie
-//    -1 for a partial match (word is a prefix to an existing word)
-//    data for the word for an exact match
-function trieLookup(trie, word) {
-    const s = word.toUpperCase().split('');
-    let p = trie;
-    let n;
-
-    while (s.length) {
-        n = s.shift();
-        p = p[n];
-        if (!p) {
-            return undefined;
-        }
-    }
-    if (p._data) {
-        return p._data;
-    }
-    return -1;
-}
-
-
 /**
  * ONOS GUI -- Util -- General Purpose Functions
  */
@@ -561,4 +456,46 @@
         return html;
     }
 
+    /**
+     * add word to trie (word will be converted to uppercase)
+     * data associated with the word
+     * returns 'added' or 'updated'
+     */
+    addToTrie(trie, word, data) {
+        return new Trie(TrieOp.PLUS, trie, word, data);
+    }
+
+    /**
+     * remove word from trie (word will be converted to uppercase)
+     * returns 'removed' or 'absent'
+     */
+    removeFromTrie(trie, word) {
+        return new Trie(TrieOp.MINUS, trie, word);
+    }
+
+    /**
+     * lookup word (converted to uppercase) in trie
+     * returns:
+     *    undefined if the word is not in the trie
+     *    -1 for a partial match (word is a prefix to an existing word)
+     *    data for the word for an exact match
+     */
+    trieLookup(trie, word) {
+        const s = word.toUpperCase().split('');
+        let p = trie;
+        let n;
+
+        while (s.length) {
+            n = s.shift();
+            p = p[n];
+            if (!p) {
+                return undefined;
+            }
+        }
+        if (p._data) {
+            return p._data;
+        }
+        return -1;
+    }
+
 }
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.spec.ts
new file mode 100644
index 0000000..5f4b349
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.spec.ts
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+import {ActivatedRoute, Params} from '@angular/router';
+
+import { KeysService, KeysToken } from './keys.service';
+import { FnService } from './fn.service';
+import { LogService } from '../log.service';
+import { NavService } from '../nav/nav.service';
+
+import {of} from 'rxjs';
+import * as d3 from 'd3';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+class MockNavService {}
+
+/*
+ ONOS GUI -- Key Handler Service - Unit Tests
+ */
+describe('KeysService', () => {
+    let ar: ActivatedRoute;
+    let fs: FnService;
+    let ks: KeysService;
+    let mockWindow: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+
+    const qhs: any = {};
+    let d3Elem: any;
+    let elem: any;
+    let last: any;
+
+    beforeEach(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['debug', 'warn', 'info']);
+        ar = new MockActivatedRoute({'debug': 'TestService'});
+        mockWindow = <any>{
+            innerWidth: 400,
+            innerHeight: 200,
+            navigator: {
+                userAgent: 'defaultUA'
+            },
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, mockWindow);
+
+        d3Elem = d3.select('body').append('p').attr('id', 'ptest');
+        elem = d3Elem.node();
+        last = {
+            view: null,
+            key: null,
+            code: null,
+            ev: null
+        };
+
+        TestBed.configureTestingModule({
+            providers: [KeysService,
+                { provide: FnService, useValue: fs},
+                { provide: LogService, useValue: logSpy },
+                { provide: ActivatedRoute, useValue: ar },
+                { provide: NavService, useClass: MockNavService},
+                { provide: 'Window', useFactory: (() => mockWindow ) }
+            ]
+        });
+        ks = TestBed.get(KeysService);
+        ks.installOn(d3Elem);
+        ks.bindQhs(qhs);
+        logServiceSpy = TestBed.get(LogService);
+    });
+
+    afterEach(() => {
+        d3.select('#ptest').remove();
+    });
+
+    it('should be created', () => {
+        expect(ks).toBeTruthy();
+    });
+
+    it('should define api functions', () => {
+        expect(fs.areFunctions(ks, [
+            'bindQhs', 'installOn', 'keyBindings', 'unbindKeys', 'dialogKeys',
+            'addSeq', 'remSeq', 'gestureNotes', 'enableKeys', 'enableGlobalKeys',
+            'checkNotGlobal', 'getKeyBindings',
+            'matchSeq', 'whatKey', 'textFieldInput', 'keyIn', 'qhlion', 'qhlionShowHide',
+            'qhlionHintEsc', 'qhlionHintT', 'setupGlobalKeys', 'quickHelp',
+            'escapeKey', 'toggleTheme', 'filterMaskedKeys', 'unexParam',
+            'setKeyBindings', 'bindDialogKeys', 'unbindDialogKeys'
+        ])).toBeTruthy();
+    });
+
+    function jsKeyDown(element, code: string, keyName: string) {
+        const ev = new KeyboardEvent('keydown',
+            { code: code, key: keyName });
+
+        // Chromium Hack
+        // if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
+        //     Object.defineProperty(ev, 'keyCode', {
+        //         get: () => { return this.keyCodeVal; }
+        //     });
+        //     Object.defineProperty(ev, 'which', {
+        //         get: () => { return this.keyCodeVal; }
+        //     });
+        // }
+
+        if (ev.code !== code.toString()) {
+            console.warn('keyCode mismatch ' + ev.code +
+                '(' + ev.which + ') -> ' + code);
+        }
+        element.dispatchEvent(ev);
+    }
+
+    // === Key binding related tests
+    it('should start with default key bindings', () => {
+        const state = ks.getKeyBindings();
+        const gk = state.globalKeys;
+        const mk = state.maskedKeys;
+        const vk = state.viewKeys;
+        const vf = state.viewFunction;
+
+        expect(gk.length).toEqual(4);
+        ['backSlash', 'slash', 'esc', 'T'].forEach((k) => {
+            expect(fs.contains(gk, k)).toBeTruthy();
+        });
+
+        expect(mk.length).toEqual(3);
+        ['backSlash', 'slash', 'T'].forEach((k) => {
+            expect(fs.contains(mk, k)).toBeTruthy();
+        });
+
+        expect(vk.length).toEqual(0);
+        expect(vf).toBeFalsy();
+    });
+
+    function bindTestKeys(withDescs?) {
+        const keys = ['A', '1', 'F5', 'equals'];
+        const kb = {};
+
+        function cb(view, key, code, ev) {
+            last.view = view;
+            last.key = key;
+            last.code = code;
+            last.ev = ev;
+        }
+
+        function bind(k) {
+            return withDescs ?
+                [(view, key, code, ev) => {cb(view, key, code, ev); }, 'desc for key ' + k] :
+                (view, key, code, ev) => {cb(view, key, code, ev); };
+        }
+
+        keys.forEach((k) => {
+            kb[k] = bind(k);
+        });
+
+        ks.keyBindings(kb);
+    }
+
+    function verifyCall(key, code) {
+        // TODO: update expectation, when view tokens are implemented
+        expect(last.view).toEqual(KeysToken.KEYEV);
+        last.view = null;
+
+        expect(last.key).toEqual(key);
+        last.key = null;
+
+        expect(last.code).toEqual(code);
+        last.code = null;
+
+        expect(last.ev).toBeTruthy();
+        last.ev = null;
+    }
+
+    function verifyNoCall() {
+        expect(last.view).toBeNull();
+        expect(last.key).toBeNull();
+        expect(last.code).toBeNull();
+        expect(last.ev).toBeNull();
+    }
+
+    function verifyTestKeys() {
+        jsKeyDown(elem, '65', 'A'); // 'A'
+        verifyCall('A', '65');
+        jsKeyDown(elem, '66', 'B'); // 'B'
+        verifyNoCall();
+
+        jsKeyDown(elem, '49', '1'); // '1'
+        verifyCall('1', '49');
+        jsKeyDown(elem, '50', '2'); // '2'
+        verifyNoCall();
+
+        jsKeyDown(elem, '116', 'F5'); // 'F5'
+        verifyCall('F5', '116');
+        jsKeyDown(elem, '117', 'F6'); // 'F6'
+        verifyNoCall();
+
+        jsKeyDown(elem, '187', '='); // 'equals'
+        verifyCall('equals', '187');
+        jsKeyDown(elem, '189', '-'); // 'dash'
+        verifyNoCall();
+
+        const vk = ks.getKeyBindings().viewKeys;
+
+        expect(vk.length).toEqual(4);
+        ['A', '1', 'F5', 'equals'].forEach((k) => {
+            expect(fs.contains(vk, k)).toBeTruthy();
+        });
+
+        expect(ks.getKeyBindings().viewFunction).toBeFalsy();
+    }
+
+    it('should allow specific key bindings', () => {
+        bindTestKeys();
+        verifyTestKeys();
+    });
+
+    it('should allow specific key bindings with descriptions', () => {
+        bindTestKeys(true);
+        verifyTestKeys();
+    });
+
+    it('should warn about masked keys', () => {
+        const k = {
+            'space': (token, key, code, ev) => cb(token, key, code, ev),
+            'T': (token, key, code, ev) => cb(token, key, code, ev)
+        };
+        let count = 0;
+
+        function cb(token, key, code, ev) {
+            count++;
+            // console.debug('count = ' + count, token, key, code);
+        }
+
+        ks.keyBindings(k);
+
+        expect(logServiceSpy.warn).toHaveBeenCalledWith('setKeyBindings()\n: Key "T" is reserved');
+
+        // the 'T' key should NOT invoke our callback
+        expect(count).toEqual(0);
+        jsKeyDown(elem, '84', 'T'); // 'T'
+        expect(count).toEqual(0);
+
+        // but the 'space' key SHOULD invoke our callback
+        jsKeyDown(elem, '32', ' '); // 'space'
+        expect(count).toEqual(1);
+    });
+
+    it('should block keys when disabled', () => {
+        let cbCount = 0;
+
+        function cb() { cbCount++; }
+
+        function pressA() { jsKeyDown(elem, '65', 'A'); }  // 65 == 'A' keycode
+
+        ks.keyBindings({ A: () => cb() });
+
+        expect(cbCount).toBe(0);
+
+        pressA();
+        expect(cbCount).toBe(1);
+
+        ks.enableKeys(false);
+        pressA();
+        expect(cbCount).toBe(1);
+
+        ks.enableKeys(true);
+        pressA();
+        expect(cbCount).toBe(2);
+    });
+
+    // === Gesture notes related tests
+    it('should start with no notes', () => {
+        expect(ks.gestureNotes()).toEqual([]);
+    });
+
+    it('should allow us to add nodes', () => {
+        const notes = [
+            ['one', 'something about one'],
+            ['two', 'description of two']
+        ];
+        ks.gestureNotes(notes);
+
+        expect(ks.gestureNotes()).toEqual(notes);
+    });
+
+    it('should ignore non-arrays', () => {
+        ks.gestureNotes({foo: 4});
+        expect(ks.gestureNotes()).toEqual([]);
+    });
+
+    // Consider adding test to ensure array contains 2-tuples of strings
+});
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.ts
new file mode 100644
index 0000000..ac68c1a
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.ts
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ */
+import { Injectable } from '@angular/core';
+import * as d3 from 'd3';
+import { LogService } from '../log.service';
+import { FnService } from '../util/fn.service';
+import { LionService } from './lion.service';
+import { NavService } from '../nav/nav.service';
+
+export interface KeyHandler {
+    globalKeys: Object;
+    maskedKeys: Object;
+    dialogKeys: Object;
+    viewKeys: any;
+    viewFn: any;
+    viewGestures: string[][];
+}
+
+export enum KeysToken {
+    KEYEV = 'keyev'
+}
+
+/**
+ * ONOS GUI -- Keys Service Module.
+ */
+@Injectable({
+    providedIn: 'root',
+})
+export class KeysService {
+    enabled: boolean = true;
+    globalEnabled: boolean = true;
+    keyHandler: KeyHandler = <KeyHandler>{
+        globalKeys: {},
+        maskedKeys: {},
+        dialogKeys: {},
+        viewKeys: {},
+        viewFn: null,
+        viewGestures: [],
+    };
+
+    seq: any = {};
+    matching: boolean = false;
+    matched: string = '';
+    lookup: any;
+    textFieldDoesNotBlock: any = {
+        enter: 1,
+        esc: 1,
+    };
+    qhs: any; // Quick Help Service ??
+
+    constructor(
+        protected log: LogService,
+        protected fs: FnService,
+        protected ls: LionService,
+        protected ns: NavService
+    ) {
+        this.log.debug('KeyService constructed');
+    }
+
+    bindQhs(_qhs_) {
+        this.qhs = _qhs_;
+    }
+
+    installOn(elem) {
+        this.log.debug('Installing keys handler');
+        elem.on('keydown', () => { this.keyIn(); });
+        this.setupGlobalKeys();
+    }
+
+    keyBindings(x) {
+        if (x === undefined) {
+            return this.getKeyBindings();
+        } else {
+            this.setKeyBindings(x);
+        }
+    }
+
+    unbindKeys() {
+        this.keyHandler.viewKeys = {};
+        this.keyHandler.viewFn = null;
+        this.keyHandler.viewGestures = [];
+    }
+
+    dialogKeys(x) {
+        if (x === undefined) {
+            this.unbindDialogKeys();
+        } else {
+            this.bindDialogKeys(x);
+        }
+    }
+
+    addSeq(word, data) {
+        this.fs.addToTrie(this.seq, word, data);
+    }
+
+    remSeq(word) {
+        this.fs.removeFromTrie(this.seq, word);
+    }
+
+    gestureNotes(g?) {
+        if (g === undefined) {
+            return this.keyHandler.viewGestures;
+        } else {
+            this.keyHandler.viewGestures = this.fs.isA(g) || [];
+        }
+    }
+
+    enableKeys(b) {
+        this.enabled = b;
+    }
+
+    enableGlobalKeys(b) {
+        this.globalEnabled = b;
+    }
+
+    checkNotGlobal(o) {
+        const oops = [];
+        if (this.fs.isO(o)) {
+            o.forEach((val, key) => {
+                if (this.keyHandler.globalKeys[key]) {
+                    oops.push(key);
+                }
+            });
+            if (oops.length) {
+                this.log.warn('Ignoring reserved global key(s):', oops.join(','));
+                oops.forEach((key) => {
+                    delete o[key];
+                });
+            }
+        }
+    }
+
+    protected matchSeq(key) {
+        if (!this.matching && key === 'shift-shift') {
+            this.matching = true;
+            return true;
+        }
+        if (this.matching) {
+            this.matched += key;
+            this.lookup = this.fs.trieLookup(this.seq, this.matched);
+            if (this.lookup === -1) {
+                return true;
+            }
+            this.matching = false;
+            this.matched = '';
+            if (!this.lookup) {
+                return;
+            }
+            // ee.cluck(lookup);
+            return true;
+        }
+    }
+
+    protected whatKey(code: number): string {
+        switch (code) {
+            case 8: return 'delete';
+            case 9: return 'tab';
+            case 13: return 'enter';
+            case 16: return 'shift';
+            case 27: return 'esc';
+            case 32: return 'space';
+            case 37: return 'leftArrow';
+            case 38: return 'upArrow';
+            case 39: return 'rightArrow';
+            case 40: return 'downArrow';
+            case 186: return 'semicolon';
+            case 187: return 'equals';
+            case 188: return 'comma';
+            case 189: return 'dash';
+            case 190: return 'dot';
+            case 191: return 'slash';
+            case 192: return 'backQuote';
+            case 219: return 'openBracket';
+            case 220: return 'backSlash';
+            case 221: return 'closeBracket';
+            case 222: return 'quote';
+            default:
+                if ((code >= 48 && code <= 57) ||
+                    (code >= 65 && code <= 90)) {
+                    return String.fromCharCode(code);
+                } else if (code >= 112 && code <= 123) {
+                    return 'F' + (code - 111);
+                }
+                return null;
+        }
+    }
+
+    protected textFieldInput() {
+        const t = d3.event.target.tagName.toLowerCase();
+        return t === 'input' || t === 'textarea';
+    }
+
+    protected keyIn() {
+        const event = d3.event;
+        // d3.events can set the keyCode, but unit tests based on KeyboardEvent
+        // cannot set keyCode since the attribute has been deprecated
+        const code = event.keyCode ? event.keyCode : event.code;
+        let key = this.whatKey(Number.parseInt(code));
+        this.log.debug('Key detected', event, key, event.code, event.keyCode);
+        const textBlockable = !this.textFieldDoesNotBlock[key];
+        const modifiers = [];
+
+        if (event.metaKey) {
+            modifiers.push('cmd');
+        }
+        if (event.altKey) {
+            modifiers.push('alt');
+        }
+        if (event.shiftKey) {
+            modifiers.push('shift');
+        }
+
+        if (!key) {
+            return;
+        }
+
+        modifiers.push(key);
+        key = modifiers.join('-');
+
+        if (textBlockable && this.textFieldInput()) {
+            return;
+        }
+
+        const kh: KeyHandler = this.keyHandler;
+        const gk = kh.globalKeys[key];
+        const gcb = this.fs.isF(gk) || (this.fs.isA(gk) && this.fs.isF(gk[0]));
+        const dk = kh.dialogKeys[key];
+        const dcb = this.fs.isF(dk);
+        const vk = kh.viewKeys[key];
+        const kl = this.fs.isF(kh.viewKeys._keyListener);
+        const vcb = this.fs.isF(vk) || (this.fs.isA(vk) && this.fs.isF(vk[0])) || this.fs.isF(kh.viewFn);
+        const token: KeysToken = KeysToken.KEYEV; // indicate this was a key-pressed event
+
+        event.stopPropagation();
+
+        if (this.enabled) {
+            if (this.matchSeq(key)) {
+                return;
+            }
+
+            // global callback?
+            if (gcb && gcb(token, key, code, event)) {
+                // if the event was 'handled', we are done
+                return;
+            }
+            // dialog callback?
+            if (dcb) {
+                dcb(token, key, code, event);
+                // assume dialog handled the event
+                return;
+            }
+            // otherwise, let the view callback have a shot
+            if (vcb) {
+                this.log.debug('Letting view callback have a shot', vcb, token, key, code, event );
+                vcb(token, key, code, event);
+            }
+            if (kl) {
+                kl(key);
+            }
+        }
+    }
+
+    // functions to obtain localized strings deferred from the setup of the
+    //  global key data structures.
+    protected qhlion() {
+        return this.ls.bundle('core.fw.QuickHelp');
+    }
+    protected qhlionShowHide() {
+        return this.qhlion()('qh_hint_show_hide_qh');
+    }
+
+    protected qhlionHintEsc() {
+        return this.qhlion()('qh_hint_esc');
+    }
+
+    protected qhlionHintT() {
+        return this.qhlion()('qh_hint_t');
+    }
+
+    protected setupGlobalKeys() {
+        Object.assign(this.keyHandler, {
+            globalKeys: {
+                backSlash: [(view, key, code, ev) => this.quickHelp(view, key, code, ev), this.qhlionShowHide],
+                slash: [(view, key, code, ev) => this.quickHelp(view, key, code, ev), this.qhlionShowHide],
+                esc: [(view, key, code, ev) => this.escapeKey(view, key, code, ev), this.qhlionHintEsc],
+                T: [(view, key, code, ev) => this.toggleTheme(view, key, code, ev), this.qhlionHintT],
+            },
+            globalFormat: ['backSlash', 'slash', 'esc', 'T'],
+
+            // Masked keys are global key handlers that always return true.
+            // That is, the view will never see the event for that key.
+            maskedKeys: {
+                slash: 1,
+                backSlash: 1,
+                T: 1,
+            },
+        });
+    }
+
+    protected quickHelp(view, key, code, ev) {
+        if (!this.globalEnabled) {
+            return false;
+        }
+        this.qhs.showQuickHelp(this.keyHandler);
+        return true;
+    }
+
+    // returns true if we 'consumed' the ESC keypress, false otherwise
+    protected escapeKey(view, key, code, ev) {
+        return this.ns.hideNav() || this.qhs.hideQuickHelp();
+    }
+
+    protected toggleTheme(view, key, code, ev) {
+        if (!this.globalEnabled) {
+            return false;
+        }
+        // ts.toggleTheme();
+        return true;
+    }
+
+    protected filterMaskedKeys(map: any, caller: any, remove: boolean): any[] {
+        const masked = [];
+        const msgs = [];
+
+        d3.map(map).keys().forEach((key) => {
+            if (this.keyHandler.maskedKeys[key]) {
+                masked.push(key);
+                msgs.push(caller, ': Key "' + key + '" is reserved');
+            }
+        });
+
+        if (msgs.length) {
+            this.log.warn(msgs.join('\n'));
+        }
+
+        if (remove) {
+            masked.forEach((k) => {
+                delete map[k];
+            });
+        }
+        return masked;
+    }
+
+    protected unexParam(fname, x) {
+        this.log.warn(fname, ': unexpected parameter-- ', x);
+    }
+
+    protected setKeyBindings(keyArg) {
+        const fname = 'setKeyBindings()';
+        const kFunc = this.fs.isF(keyArg);
+        const kMap = this.fs.isO(keyArg);
+
+        if (kFunc) {
+            // set general key handler callback
+            this.keyHandler.viewFn = kFunc;
+        } else if (kMap) {
+            this.filterMaskedKeys(kMap, fname, true);
+            this.keyHandler.viewKeys = kMap;
+        } else {
+            this.unexParam(fname, keyArg);
+        }
+    }
+
+    getKeyBindings() {
+        const gkeys = d3.map(this.keyHandler.globalKeys).keys();
+        const masked = d3.map(this.keyHandler.maskedKeys).keys();
+        const vkeys = d3.map(this.keyHandler.viewKeys).keys();
+        const vfn = !!this.fs.isF(this.keyHandler.viewFn);
+
+        return {
+            globalKeys: gkeys,
+            maskedKeys: masked,
+            viewKeys: vkeys,
+            viewFunction: vfn,
+        };
+    }
+
+    protected bindDialogKeys(map) {
+        const fname = 'bindDialogKeys()';
+        const kMap = this.fs.isO(map);
+
+        if (kMap) {
+            this.filterMaskedKeys(map, fname, true);
+            this.keyHandler.dialogKeys = kMap;
+        } else {
+            this.unexParam(fname, map);
+        }
+    }
+
+    protected unbindDialogKeys() {
+        this.keyHandler.dialogKeys = {};
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/lion.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/lion.service.spec.ts
similarity index 78%
rename from web/gui2/src/main/webapp/tests/app/fw/util/lion.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/lion.service.spec.ts
index 0b661c6..b0c252c 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/util/lion.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/lion.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-present Open Networking Foundation
+ * 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.
@@ -17,15 +17,15 @@
 import { TestBed, inject } from '@angular/core/testing';
 import { of } from 'rxjs';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
 import { ActivatedRoute, Params } from '@angular/router';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { GlyphService } from '../../../../app/fw/svg/glyph.service';
-import { LionService } from '../../../../app/fw/util/lion.service';
-import { UrlFnService } from '../../../../app/fw/remote/urlfn.service';
-import { WSock } from '../../../../app/fw/remote/wsock.service';
-import { WebSocketService, WsOptions } from '../../../../app/fw/remote/websocket.service';
+import { FnService } from '../util/fn.service';
+import { GlyphService } from '../svg/glyph.service';
+import { LionService } from './lion.service';
+import { UrlFnService } from '../remote/urlfn.service';
+import { WSock } from '../remote/wsock.service';
+import { WebSocketService, WsOptions } from '../remote/websocket.service';
 
 class MockActivatedRoute extends ActivatedRoute {
     constructor(params: Params) {
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/prefs.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.spec.ts
similarity index 73%
rename from web/gui2/src/main/webapp/tests/app/fw/util/prefs.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.spec.ts
index 0aeed99..d925ecf 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/util/prefs.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
@@ -15,15 +15,20 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { PrefsService } from '../../../../app/fw/util/prefs.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { WebSocketService } from '../../../../app/fw/remote/websocket.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { PrefsService } from '../util/prefs.service';
+import { FnService } from '../util/fn.service';
+import { WebSocketService } from '../remote/websocket.service';
 
 class MockFnService {}
 
-class MockWebSocketService {}
+class MockWebSocketService {
+    createWebSocket() {}
+    isConnected() { return false; }
+    unbindHandlers() {}
+    bindHandlers() {}
+}
 
 /**
  * ONOS GUI -- Util -- User Preference Service - Unit Tests
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/theme.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/theme.service.spec.ts
similarity index 80%
rename from web/gui2/src/main/webapp/tests/app/fw/util/theme.service.spec.ts
rename to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/theme.service.spec.ts
index f69cc5b..16d38e3 100644
--- a/web/gui2/src/main/webapp/tests/app/fw/util/theme.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/theme.service.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-present Open Networking Foundation
+ * 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.
@@ -15,9 +15,9 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { ThemeService } from '../../../../app/fw/util/theme.service';
+import { LogService } from '../log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { ThemeService } from './theme.service';
 
 /**
  * ONOS GUI -- Util -- Theme Service - Unit Tests
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/trie.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/trie.ts
new file mode 100644
index 0000000..5e08061
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/trie.ts
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+export interface TrieC {
+    p: any;
+    s: string[];
+}
+
+export interface TrieT {
+    k: any;
+    p: any;
+    q: any;
+}
+
+export enum TrieRemoved {
+    REMOVED = 'removed',
+    ABSENT = 'absent'
+}
+
+export enum TrieInsert {
+    ADDED = 'added',
+    UPDATED = 'updated'
+}
+
+/**
+ * Combine TrieRemoved and TrieInsert in to a union type
+ */
+export type TrieActions = TrieRemoved | TrieInsert;
+
+export enum TrieOp {
+    PLUS = '+',
+    MINUS = '-'
+}
+
+
+export class Trie {
+    p: any;
+    w: string;
+    s: string[];
+    c: TrieC;
+    t: TrieT[];
+    x: number;
+    f1: (TrieC) => TrieC;
+    f2: () => TrieActions;
+    data: any;
+
+
+    constructor(
+        op: TrieOp,
+        trie: any,
+        word: string,
+        data?: any
+    ) {
+        this.p = trie;
+        this.w = word.toUpperCase();
+        this.s = this.w.split('');
+        this.c = { p: this.p, s: this.s },
+        this.t = [];
+        this.x = 0;
+        this.f1 = op === TrieOp.PLUS ? this.add : this.probe;
+        this.f2 = op === TrieOp.PLUS ? this.insert : this.remove;
+        this.data = data;
+        while (this.c.s.length) {
+            this.c = this.f1(this.c);
+        }
+    }
+
+    add(cAdded: TrieC): TrieC {
+        const q = cAdded.s.shift();
+        let np = cAdded.p[q];
+
+        if (!np) {
+            cAdded.p[q] = {};
+            np = cAdded.p[q];
+            this.x = 1;
+        }
+        return { p: np, s: cAdded.s };
+    }
+
+    probe(cProbed: TrieC): TrieC {
+        const q = cProbed.s.shift();
+        const k: number = Object.keys(cProbed.p).length;
+        const np = cProbed.p[q];
+
+        this.t.push({ q: q, k: k, p: cProbed.p });
+        if (!np) {
+            this.t = [];
+            return { p: [], s: [] };
+        }
+        return { p: np, s: cProbed.s };
+    }
+
+    insert(): TrieInsert {
+        this.c.p._data = this.data;
+        return this.x ? TrieInsert.ADDED : TrieInsert.UPDATED;
+    }
+
+    remove(): TrieRemoved {
+        if (this.t.length) {
+            this.t = this.t.reverse();
+            while (this.t.length) {
+                const d = this.t.shift();
+                delete d.p[d.q];
+                if (d.k > 1) {
+                    this.t = [];
+                }
+            }
+            return TrieRemoved.REMOVED;
+        }
+        return TrieRemoved.ABSENT;
+    }
+}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/detailspanel.base.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/detailspanel.base.ts
index 11dc8c9..03c681b 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/detailspanel.base.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/detailspanel.base.ts
@@ -55,7 +55,7 @@
         protected wss: WebSocketService,
         protected tag: string,
     ) {
-        super(fs, ls, log, wss, {});
+        super(fs, ls, log);
         this.root = tag + 's';
         this.req = tag + 'DetailsRequest';
         this.resp = tag + 'DetailsResponse';
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts
index 90cdfd5..0377c47 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts
@@ -16,41 +16,6 @@
 import { FnService } from '../util/fn.service';
 import { LoadingService } from '../layer/loading.service';
 import { LogService } from '../log.service';
-import { WebSocketService } from '../remote/websocket.service';
-
-
-const noop = (): any => undefined;
-
-/**
- ********* Static functions *********
- */
-function margin(p) {
-    return p.settings.margin;
-}
-
-function hideMargin(p) {
-    return p.settings.hideMargin;
-}
-
-function noPx(p, what) {
-    return Number(p.el.style(what).replace(/px$/, ''));
-}
-
-function widthVal(p) {
-    return noPx(p, 'width');
-}
-
-function heightVal(p) {
-    return noPx(p, 'height');
-}
-
-function pxShow(p) {
-    return margin(p) + 'px';
-}
-
-function pxHide(p) {
-    return (-hideMargin(p) - widthVal(p) - (noPx(p, 'padding') * 2)) + 'px';
-}
 
 
 /**
@@ -60,14 +25,7 @@
     showPanel(cb: any): void;
     hidePanel(cb: any): void;
     togglePanel(cb: any): void;
-    emptyPanel(): void;
-    appendPanel(what: any): void;
-    panelWidth(w: number): number;
-    panelHeight(h: number): number;
-    panelBBox(): string;
     panelIsVisible(): boolean;
-    classed(cls: any, bool: boolean): boolean;
-    panelEl(): any;
 }
 
 /**
@@ -77,36 +35,22 @@
  */
 export abstract class PanelBaseImpl implements PanelBase {
 
-    protected on: boolean;
-    protected el: any;
+    on: boolean;
 
     constructor(
         protected fs: FnService,
         protected ls: LoadingService,
         protected log: LogService,
-        protected wss: WebSocketService,
-        protected settings: any
     ) {
 //        this.log.debug('Panel base class constructed');
     }
 
     showPanel(cb) {
-        const endCb = this.fs.isF(cb) || noop;
         this.on = true;
-        this.el.transition().duration(this.settings.xtnTime)
-            .each('end', endCb)
-            .style(this.settings.edge, pxShow(this))
-            .style('opacity', 1);
     }
 
     hidePanel(cb) {
-        const endCb = this.fs.isF(cb) || noop;
-        const endOpacity = this.settings.fade ? 0 : 1;
         this.on = false;
-        this.el.transition().duration(this.settings.xtnTime)
-            .each('end', endCb)
-            .style(this.settings.edge, pxHide(this))
-            .style('opacity', endOpacity);
     }
 
     togglePanel(cb): boolean {
@@ -118,45 +62,10 @@
         return this.on;
     }
 
-    emptyPanel(): string {
-        return this.el.text('');
-    }
-
-    appendPanel(what) {
-        return this.el.append(what);
-    }
-
-    panelWidth(w: number): number {
-        if (w === undefined) {
-            return widthVal(this);
-        }
-        this.el.style('width', w + 'px');
-    }
-
-    panelHeight(h: number): number {
-        if (h === undefined) {
-            return heightVal(this);
-        }
-        this.el.style('height', h + 'px');
-    }
-
-    panelBBox(): string {
-        return this.el.node().getBoundingClientRect();
-    }
-
     panelIsVisible(): boolean {
         return this.on;
     }
 
-    classed(cls, bool): boolean {
-        return this.el.classed(cls, bool);
-    }
-
-    panelEl() {
-        return this.el;
-    }
-
-
     /**
      * A dummy implementation of the lionFn until the response is received and the LION
      * bundle is received from the WebSocket
diff --git a/web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/tableresize.directive.spec.ts
similarity index 71%
copy from web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts
copy to web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/tableresize.directive.spec.ts
index 37f4a8e..b1e87e6 100644
--- a/web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/tableresize.directive.spec.ts
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../app/log.service';
-import { ConsoleLoggerService } from '../../app/consolelogger.service';
-import { DetectBrowserDirective } from '../../app/detectbrowser.directive';
 import { ActivatedRoute, Params } from '@angular/router';
-import { FnService } from '../../app/fw/util/fn.service';
-import { OnosService } from '../../app/onos.service';
 import { of } from 'rxjs';
+import { TableResizeDirective } from './tableresize.directive';
+import { LogService } from '..//log.service';
+import { ConsoleLoggerService } from '../consolelogger.service';
+import { MastService } from '../mast/mast.service';
+import { FnService } from '../util/fn.service';
+
+class MockMastService {}
 
 class MockFnService extends FnService {
     constructor(ar: ActivatedRoute, log: LogService, w: Window) {
@@ -29,8 +30,6 @@
     }
 }
 
-class MockOnosService {}
-
 class MockActivatedRoute extends ActivatedRoute {
     constructor(params: Params) {
         super();
@@ -39,12 +38,12 @@
 }
 
 /**
- * ONOS GUI -- Detect Browser Directive - Unit Tests
+ * ONOS GUI -- Widget -- Table Resize Directive - Unit Tests
  */
-describe('DetectBrowserDirective', () => {
+describe('TableResizeDirective', () => {
     let log: LogService;
-    let ar: ActivatedRoute;
     let mockWindow: Window;
+    let ar: ActivatedRoute;
 
     beforeEach(() => {
         log = new ConsoleLoggerService();
@@ -55,14 +54,12 @@
                 vendor: 'Google Inc.'
             }
         };
-
         TestBed.configureTestingModule({
-            providers: [ DetectBrowserDirective,
+            providers: [ TableResizeDirective,
                 { provide: FnService, useValue: new MockFnService(ar, log, mockWindow) },
                 { provide: LogService, useValue: log },
-                { provide: OnosService, useClass: MockOnosService },
-                { provide: Document, useValue: document },
-                { provide: 'Window', useFactory: (() => mockWindow ) }
+                { provide: MastService, useClass: MockMastService },
+                { provide: 'Window', useFactory: (() => mockWindow ) },
             ]
         });
     });
@@ -71,7 +68,7 @@
         log = null;
     });
 
-    it('should create an instance', inject([DetectBrowserDirective], (directive: DetectBrowserDirective) => {
+    it('should create an instance', inject([TableResizeDirective], (directive: TableResizeDirective) => {
         expect(directive).toBeTruthy();
     }));
 });
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/tableresize.directive.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/tableresize.directive.ts
index 0678583..5d3a9eb 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/tableresize.directive.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/tableresize.directive.ts
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { AfterContentChecked, Directive, ElementRef, Inject } from '@angular/core';
+import { AfterContentChecked, Directive, Inject } from '@angular/core';
 import { FnService } from '../util/fn.service';
 import { LogService } from '../log.service';
 import { MastService } from '../mast/mast.service';
@@ -34,7 +34,6 @@
     constructor(protected fs: FnService,
         protected log: LogService,
         protected mast: MastService,
-        protected el: ElementRef,
         @Inject('Window') private w: any) {
 
         log.info('TableResizeDirective constructed');
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts
index 51cf201..5f162d5 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts
@@ -36,10 +36,14 @@
 export * from './lib/svg/svgutil.service';
 export * from './lib/svg/glyphdata.service';
 export * from './lib/svg/glyph.service';
+export * from './lib/svg/zoom.service';
+
 export * from './lib/util/prefs.service';
 export * from './lib/util/fn.service';
 export * from './lib/util/lion.service';
 export * from './lib/util/theme.service';
+export * from './lib/util/keys.service';
+export * from './lib/util/trie';
 
 export * from './lib/mast/mast/mast.component';
 export * from './lib/layer/veil/veil.component';
diff --git a/web/gui2-fw-lib/src/app/app.module.ts b/web/gui2-fw-lib/src/app/app.module.ts
index dc92383..d2d4a5d 100644
--- a/web/gui2-fw-lib/src/app/app.module.ts
+++ b/web/gui2-fw-lib/src/app/app.module.ts
@@ -16,13 +16,13 @@
 
 import { BrowserModule } from '@angular/platform-browser';
 import { NgModule } from '@angular/core';
-import { RouterModule, Routes }  from '@angular/router';
+import { RouterModule, Routes } from '@angular/router';
 import { AppComponent } from './app.component';
 import { Gui2FwLibModule, ConsoleLoggerService, LogService } from 'gui2-fw-lib';
 
 const appRoutes: Routes = [
   { path: '**', component: AppComponent }
-]
+];
 
 @NgModule({
   declarations: [
diff --git a/web/gui2/README.md b/web/gui2/README.md
index 3064b76..c3cbed3 100644
--- a/web/gui2/README.md
+++ b/web/gui2/README.md
@@ -5,7 +5,7 @@
 as an alternative to the 1.0.0 GUI which was based 
 off __[AngularJS 1.3.5](https://angularjs.org/)__
 
-Building, testing and running lint are all handled by BUCK. See web/gui2/BUCK file.
+Building, testing and running lint are all handled by Bazel. See web/gui2/BUILD file.
 
 To use this new GUI you simply have to start the GUI in a running ONOS at the __onos>__ cli:
 ```
@@ -16,52 +16,125 @@
 As usual with ONOS if you want to run it in a different language set the __ONOS_LOCALE__ environment variable
 to the locale you want before starting onos. e.g.
 ```
-ONOS_LOCALE=fr_FR onos-buck run onos-local
+ONOS_LOCALE=fr_FR SHLVL=1 bazel run onos-local
 ```
 
 # Development
 There are 2 ways to go about development - 
-1. rebuild the code and rerun through BUCK (much like can be done with any ordinary ONOS app) 
- (this is not recommended though since in this mode the browser side code is built in '--prod' mode
+1. rebuild the code and rerun through Bazel (much like can be done with any ordinary ONOS app) 
+ (this is not optimal though since in this mode the browser side code is built in '--prod' mode
  and all debug symbols are stripped and debug statements are not logged and the code is uglified and minimized.
- It is useful for testing "prod" mode works though) OR
+ It is useful for testing "prod" mode works though and saves having to set up direct development) OR
 2. use Angular 6 CLI (__ng__ command) to rebuild on the fly (must faster for development) 
 
-For 1) if you change the code you can redeploy the application without restarting ONOS with (requires you to be in ~/onos directory):
+For 1) (this needs to be updated for Bazel commands) if you change the code you can redeploy the application without restarting ONOS with (requires you to be in ~/onos directory):
 ```
 onos-buck build //web/gui2:onos-web-gui2-oar --show-output|grep /app.oar | cut -d\  -f2 | xargs onos-app localhost reinstall!
 ```
 
 For 2) it's well worth becoming familiar with Angular CLI.
 The project is created with [Angular CLI](https://github.com/angular/angular-cli) v6 to simplify development of the browser side code.
-
+It is complicated to set up, but is worth the effort if you have more than a day's worth of development to do.
 This allows you to develop the Angular 6 TypeScript code independent of ONOS in a separate container. 
-Since WebSockets have been implemented (Jun 18) there is a requirement to run ONOS in the background.
+Since WebSockets have been implemented - there is a requirement to run ONOS in the background.
 
 There is no need to install node, npm or ng again on your system, and indeed if they are already installed, it's best
-to use the versions of these that's used by BUCK. To do this add to the __start__ of your PATH environment variable. 
+to use the versions of these that's used by Bazel. To do this add the following 2 entries to the __start__ of your PATH environment variable. 
 ```
-~/onos/buck-out/gen/web/gui2/node-bin-v8.11.1/node-binaries/bin
+~/.cache/bazel/_bazel_scondon/8beba376f58d295cf3282443fe02c21a/external/nodejs/bin/nodejs/bin
+```
+(where ~/.cache/bazel/_bazel_scondon/8beba376f58d295cf3282443fe02c21a should be replaced by an equivalent folder on your system)
+```text
+~/onos/web/gui2-fw-lib/node_modules/@angular/cli/bin/
+```
 
+The first time you run this you will have to go to the framework folder and run "npm install"
+```text
+cd ~/onos/web/gui2-fw-lib && \
+npm install
 ```
-On Linux:
-```
-export PATH=~/onos/buck-out/gen/web/gui2/node-bin-v8.11.1/node-binaries/bin:$PATH
-``` 
 
-After this you should be able to run 'ng -v' and see:
+This will install all the vendor Javascript implementations that are listed in package.json
+ (including 'ng' - the Angular CLI command) in to ~/onos/web/gui2-fw-lib/node_modules
+
+After this you should be able to cd in to ~/onos/web/gui2-fw-lib and run 'ng -v' and see:
 ```
 Angular CLI: 6.0.0
 Node: 8.11.1
 OS: linux x64
 ```
 
-To use Angular CLI for development on your system, you need to: 
+## GUI FW Lib
+The GUI2 __framework__ is in __~/onos/web/gui2-fw-lib__ and the GUI __application__ is in __~/onos/web/gui2__ (and depends on the framework).
+
+The GUI2 framework is a library inside its own mini application (unrelated to the main GUI application) - every thing of importance 
+is in projects/gui2-fw-lib. The own application is just a wrapper around the framework
+library - it has to be there for Angular CLI to work. 
+
+If you make any changes here or are using it for the first time it will need to be built
+```text
+cd ~/onos/web/gui2-fw-lib && \
+ng build gui2-fw-lib && \
+pushd dist/gui2-fw-lib && \
+npm pack && \
+popd
+```
+
+To test and lint it use
+```text
+ng lint gui2-fw-lib && \
+ng test gui2-fw-lib
+```
+
+This packages the Framework up in to __onos/web/gui2-fw-lib/dist/gui2-fw-lib/gui2-fw-lib-0.14.0.tgz__
+
+## GUI2 Application
+The application contains the ONOS index.html and all of the tabular views and the topology view.
+It references the gui2-fw-lib, as just another dependency. 
+
+To use this application in Angular CLI for development on your system, you need to: 
 1. Change directory in to onos/web/gui2 - this is where you will run the `ng` command from.
 2. Run `npm install` once from this folder to add dependencies
 3. Then run 'ng -v' from onos/web/gui2 and an additional version should be shown __Angular: 6.0.0__
+4. Temporarily make a change to disable authentication in UIWebSocket.java
+5. Temporarily make a change to disable external routes in onos-routing.module.ts
+6. Create symbolic links for some CSS files
+
+### Disable authentication and external routes
+Before the server can be run a couple of small adjustments need to be temporarily made
+1. The file __~/onos/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java__ 
+needs to be adjusted to remove authentication
+2. The file __~/onos/web/gui2/src/main/webapp/app/onos-routing.module.ts__ needs 
+to be adjusted to remove references to routes in external applications 
+
+These changes are given in Appendix A at the end of this document - these changes should not be 
+checked in though - as they are not required (and will break) the GUI2 embedded in ONOS.
+
+### Create symbolic links for CSS files
+Also some files need to be symbolically linked - these should no be checked in
+```text
+cd ~/onos/web/gui2/src/main/webapp/app && \
+mkdir -p fw/widget && mkdir -p fw/layer && \
+cd fw/layer && ln -s ~/onos/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/loading.service.css && \
+cd ../widget && \
+ln -s ~/onos/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.css && \
+ln -s ~/onos/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel-theme.css && \
+ln -s ~/onos/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/table.css && \
+ln -s ~/onos/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/table.theme.css
+```
+
+After this it will be possible to build/test/lint/run the application inside the Angular CLI without errors.
+```text
+ng build --prod && \
+ng lint && \
+ng test --watch=false
+```
 
 ## Development server
+Finally the application can be run, and will be available at http://localhost:4200
+```text
+ng serve --aot
+``` 
 
 Run `ng serve --aot` for a dev server (because we are using ES6, we [must use AOT](https://github.com/angular/angular-cli/wiki/build)). 
 Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
@@ -75,24 +148,29 @@
 source the image, and this path is not available in this 'ng serve' mode. The icons work fine in the
 mode where it's run inside ONOS. 
 
-## Code scaffolding
+### Navigating
+In this development mode navigation is not available, and to to jump to other view, 
+replace the 'device' at the end of the URL with the route you want to follow
+e.g. 'app' for the Applications view or 'topo' for the Topology view
 
+## Code scaffolding
+Change directory in to '~onos/web/gui2/src/main/webapp/app/view'
 Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
 
 ## Build
-The build is handled through the web/gui2/BUCK file. This downloads Node, NPM and Angular CLI
+The build is handled through the web/gui2/BUILD file. This downloads Node, NPM and Angular CLI
 It runs ```ng build --prod --extract-css``` and copies everything over in to WEB-INF/classes/dist
 
 To run it manually in Angular CLI run `ng build` (and add on --prod --extract-css --watch as necessary to alter its behaviour)
 
 ## Running unit tests
-This is automatically done when using "onos-buck test" - see the web/gui2/BUCK file for more details.
+This is automatically done when using "bazel test " - see the web/gui2/BUILD file for more details.
 
 To run it manually in Angular CLI run `ng test --watch` to execute the unit tests via [Karma](https://karma-runner.github.io).
 Running it directly like this will test with both Firefox and Chrome. To use only one use the __--browsers__ argument
 
-## Running checkstyle
-This is automatically done when using "onos-buck test" - see the web/gui2/BUCK file for more details.
+## Running checkstyle (lint)
+This is automatically done when using "bazel test" - see the web/gui2/BUILD file for more details.
 
 To run it manually in Angular CLI run `ng lint` to run codelyzer on your code, according to the rules in __tslint.json__
 
@@ -101,10 +179,56 @@
 To run it manually in Angular CLI run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
 
 ## Generating documentation
-This is automatically done when using "onos-buck onos build" - see the web/gui2/BUCK file for more details.
+This is automatically done when using "ob" - see the web/gui2/BUILD file for more details.
 
 To run it manually in Angular CLI run `npm run compodoc` to generate documentation via [Compodoc](https://github.com/compodoc/compodoc)
 
 ## Further help
 
 To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
+
+
+# Appendix A - changes needed to run GUI2 application locally
+
+```text
+diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
+index e53a00756b..63e538a4db 100644
+--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
++++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
+@@ -251,9 +251,7 @@ public class UiWebSocket
+             ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
+             String type = message.path(EVENT).asText(UNKNOWN);
+ 
+-            if (sessionToken == null) {
+-                authenticate(type, message);
+-            } else {
++
+                 UiMessageHandler handler = handlers.get(type);
+                 if (handler != null) {
+                     log.debug("RX message: {}", message);
+@@ -261,7 +259,6 @@ public class UiWebSocket
+                 } else {
+                     log.warn("No GUI message handler for type {}", type);
+                 }
+-            }
+ 
+         } catch (Exception e) {
+             log.warn("Unable to parse GUI message {} due to {}", data, e);
+diff --git a/web/gui2/src/main/webapp/app/onos-routing.module.ts b/web/gui2/src/main/webapp/app/onos-routing.module.ts
+index 60ec9d7da6..3abb62376a 100644
+--- a/web/gui2/src/main/webapp/app/onos-routing.module.ts
++++ b/web/gui2/src/main/webapp/app/onos-routing.module.ts
+@@ -83,10 +83,10 @@ const onosRoutes: Routes = [
+         loadChildren: 'app/view/topology/topology.module#TopologyModule'
+     },
+ /*  Comment out below section for running locally with 'ng serve' when developing */
+-    {
++/*    {
+         path: 'alarmTable',
+         loadChildren: 'fm-gui2-lib#FmGui2LibModule'
+-    },
++    },*/
+     {
+         path: '',
+         redirectTo: 'device', // Default to devices view - change to topo in future
+```  
\ No newline at end of file
diff --git a/web/gui2/package-lock.json b/web/gui2/package-lock.json
index da2444c..0fec8ad 100644
--- a/web/gui2/package-lock.json
+++ b/web/gui2/package-lock.json
@@ -70,7 +70,7 @@
         "webpack-dev-server": "3.1.9",
         "webpack-merge": "4.1.4",
         "webpack-sources": "1.3.0",
-        "webpack-subresource-integrity": "1.1.0-rc.6"
+        "webpack-subresource-integrity": "1.1.0-rc.7"
       }
     },
     "@angular-devkit/build-optimizer": {
@@ -662,18 +662,18 @@
       }
     },
     "@types/jasmine": {
-      "version": "2.8.8",
-      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.8.tgz",
-      "integrity": "sha512-OJSUxLaxXsjjhob2DBzqzgrkLmukM3+JMpRp0r0E4HTdT1nwDCWhaswjYxazPij6uOdzHCJfNbDjmQ1/rnNbCg==",
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.9.tgz",
+      "integrity": "sha512-8dPZwjosElZOGGYw1nwTvOEMof4gjwAWNFS93nBI091BoEfd5drnHOLRMiRF/LOPuMTn5LgEdv0bTUO8QFVuHQ==",
       "dev": true
     },
     "@types/jasminewd2": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.4.tgz",
-      "integrity": "sha512-G83fHoholqR7pmsY7ojHJqMAl4zD6ylKNaKCx7zH+GisCBQpnI5a7aUTFWVzv2wppIuWd+mJxyRqTASPfqcQ2w==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.5.tgz",
+      "integrity": "sha512-1awkm/O4pQCR9hI2F80HmIOda/L+ogkSL8Arj1k00eue5VLY5ooewhSOyF/cUJE0S+/34uD5EYY3zmd6fu2OCA==",
       "dev": true,
       "requires": {
-        "@types/jasmine": "2.8.8"
+        "@types/jasmine": "2.8.9"
       }
     },
     "@types/node": {
@@ -1337,7 +1337,7 @@
       "dev": true,
       "requires": {
         "browserslist": "3.2.8",
-        "caniuse-lite": "1.0.30000888",
+        "caniuse-lite": "1.0.30000890",
         "normalize-range": "0.1.2",
         "num2fraction": "1.2.2",
         "postcss": "6.0.23",
@@ -1827,8 +1827,8 @@
       "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==",
       "dev": true,
       "requires": {
-        "caniuse-lite": "1.0.30000888",
-        "electron-to-chromium": "1.3.73"
+        "caniuse-lite": "1.0.30000890",
+        "electron-to-chromium": "1.3.75"
       }
     },
     "buffer": {
@@ -1997,9 +1997,9 @@
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30000888",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000888.tgz",
-      "integrity": "sha512-vftg+5p/lPsQGpnhSo/yBuYL36ai/cyjLvU3dOPJY1kkKrekLWIy8SLm+wzjX0hpCUdFTasC4/ZT7uqw4rKOnQ==",
+      "version": "1.0.30000890",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000890.tgz",
+      "integrity": "sha512-4NI3s4Y6ROm+SgZN5sLUG4k7nVWQnedis3c/RWkynV5G6cHSY7+a8fwFyn2yoBDE3E6VswhTNNwR3PvzGqlTkg==",
       "dev": true
     },
     "caseless": {
@@ -2233,9 +2233,9 @@
       "dev": true
     },
     "codelyzer": {
-      "version": "4.4.4",
-      "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.4.4.tgz",
-      "integrity": "sha512-JgFMudx0n50IuE/ydAfnkksCwQkWSVWgYvhDPHZgDUbmsiYC22VuEXKu5l8Hhx9UJsLgjWDLjTAFGj2WaW5DUA==",
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.5.0.tgz",
+      "integrity": "sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ==",
       "dev": true,
       "requires": {
         "app-root-path": "2.1.0",
@@ -2415,7 +2415,7 @@
         },
         "ms": {
           "version": "0.7.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+          "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
           "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
           "dev": true
         },
@@ -2586,7 +2586,7 @@
       "requires": {
         "cipher-base": "1.0.4",
         "inherits": "2.0.3",
-        "md5.js": "1.3.4",
+        "md5.js": "1.3.5",
         "ripemd160": "2.0.2",
         "sha.js": "2.4.11"
       }
@@ -3378,9 +3378,9 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.73",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.73.tgz",
-      "integrity": "sha512-6PIg7v9zRoVGh6EheRF8h6Plti+3Yo/qtHobS4/Htyt53DNHmKKGFqSae1AIk0k1S4gCQvt7I2WgpbuZNcDY+g==",
+      "version": "1.3.75",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.75.tgz",
+      "integrity": "sha512-nLo03Qpw++8R6BxDZL/B1c8SQvUe/htdgc5LWYHe5YotV2jVvRUMP5AlOmxOsyeOzgMiXrNln2mC05Ixz6vuUQ==",
       "dev": true
     },
     "elliptic": {
@@ -3454,7 +3454,7 @@
         },
         "ms": {
           "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+          "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
           "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
           "dev": true
         }
@@ -3491,7 +3491,7 @@
         },
         "ms": {
           "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+          "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
           "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
           "dev": true
         }
@@ -3738,7 +3738,7 @@
       "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
       "dev": true,
       "requires": {
-        "md5.js": "1.3.4",
+        "md5.js": "1.3.5",
         "safe-buffer": "5.1.2"
       }
     },
@@ -4109,9 +4109,9 @@
       "dev": true
     },
     "fast-glob": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.2.tgz",
-      "integrity": "sha512-TR6zxCKftDQnUAPvkrCWdBgDq/gbqx8A3ApnBrR5rMvpp6+KMJI0Igw7fkWPgeVK0uhRXTXdvO3O+YP0CaUX2g==",
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.3.tgz",
+      "integrity": "sha512-NiX+JXjnx43RzvVFwRWfPKo4U+1BrK5pJPsHQdKMlLoFHrrGktXglQhHliSihWAq+m1z6fHk3uwGHrtRbS9vLA==",
       "dev": true,
       "requires": {
         "@mrmlnc/readdir-enhanced": "2.2.1",
@@ -4151,7 +4151,7 @@
     },
     "file-loader": {
       "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
+      "resolved": "http://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
       "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==",
       "dev": true,
       "requires": {
@@ -4251,7 +4251,7 @@
     },
     "fm-gui2-lib": {
       "version": "file:../../apps/faultmanagement/fm-gui2-lib/dist/fm-gui2-lib/fm-gui2-lib-1.15.0.tgz",
-      "integrity": "sha512-5qRtSAZDtFeafTTaJ9UHwyP+E7Sj6nx5RrAORCzt1DswqI4YFZqW1nSLa9co0hWqi9lem5sKspp+BH787TiXwQ==",
+      "integrity": "sha512-x2tby0vrDdC087L3bY9lB6eQtI90td1XmDFa45+BBHmfEiyFsNEtJcDon4jIXG42SJQRpp4xZUJpJ9jbiCqEfg==",
       "requires": {
         "tslib": "1.9.3"
       }
@@ -4981,7 +4981,7 @@
     },
     "get-stream": {
       "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+      "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
       "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
       "dev": true
     },
@@ -5117,7 +5117,7 @@
     },
     "gui2-fw-lib": {
       "version": "file:../gui2-fw-lib/dist/gui2-fw-lib/gui2-fw-lib-0.14.0.tgz",
-      "integrity": "sha512-8TJ45BxzQw8UEx9/zmwuz9prZmItcpVSbyF5LifAO8iPLQa34VLyTWI39YWWV7Pd3jc+ez270WTEfCzvafvz8w==",
+      "integrity": "sha512-b3u3DZ6GTtp5sqPpDk7XcGsjc1GCpQhDQxaDxkF65GAtlivYWPUS8jSiu2oIVWsYoOnhMW5ck/A33RraVsfhKQ==",
       "requires": {
         "tslib": "1.9.3"
       }
@@ -7254,13 +7254,14 @@
       "dev": true
     },
     "md5.js": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
-      "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=",
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
       "dev": true,
       "requires": {
         "hash-base": "3.0.4",
-        "inherits": "2.0.3"
+        "inherits": "2.0.3",
+        "safe-buffer": "5.1.2"
       }
     },
     "media-typer": {
@@ -8630,7 +8631,7 @@
       "integrity": "sha512-pw4uwwiy5lHZjIguxNpkEwJJa7hVz+bJsvaTI+IbXlfn2qXwzbF8eghW/RmrZwE2sGx82I8etb8lVjQ+JrjejA==",
       "dev": true,
       "requires": {
-        "@types/node": "6.0.117",
+        "@types/node": "6.0.118",
         "@types/q": "0.0.32",
         "@types/selenium-webdriver": "2.53.43",
         "blocking-proxy": "1.0.1",
@@ -8648,9 +8649,9 @@
       },
       "dependencies": {
         "@types/node": {
-          "version": "6.0.117",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.117.tgz",
-          "integrity": "sha512-sihk0SnN8PpiS5ihu5xJQ5ddnURNq4P+XPmW+nORlKkHy21CoZO/IVHK/Wq/l3G8fFW06Fkltgnqx229uPlnRg==",
+          "version": "6.0.118",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.118.tgz",
+          "integrity": "sha512-N33cKXGSqhOYaPiT4xUGsYlPPDwFtQM/6QxJxuMXA/7BcySW+lkn2yigWP7vfs4daiL/7NJNU6DMCqg5N4B+xQ==",
           "dev": true
         },
         "adm-zip": {
@@ -9843,7 +9844,7 @@
         },
         "ms": {
           "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+          "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
           "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
           "dev": true
         },
@@ -9876,7 +9877,7 @@
         },
         "ms": {
           "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+          "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
           "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
           "dev": true
         }
@@ -9912,7 +9913,7 @@
         },
         "ms": {
           "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+          "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
           "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
           "dev": true
         }
@@ -9953,7 +9954,7 @@
         },
         "ms": {
           "version": "0.7.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+          "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
           "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
           "dev": true
         }
@@ -10044,9 +10045,9 @@
       "dev": true
     },
     "spdx-correct": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.1.tgz",
-      "integrity": "sha512-hxSPZbRZvSDuOvADntOElzJpenIR7wXJkuoUcUtS0erbgt2fgeaoPIYretfKpslMhfFDY4k0MZ2F5CUzhBsSvQ==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz",
+      "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==",
       "dev": true,
       "requires": {
         "spdx-expression-parse": "3.0.0",
@@ -10670,7 +10671,7 @@
           "requires": {
             "array-union": "1.0.2",
             "dir-glob": "2.0.0",
-            "fast-glob": "2.2.2",
+            "fast-glob": "2.2.3",
             "glob": "7.1.3",
             "ignore": "3.3.10",
             "pify": "3.0.0",
@@ -11186,7 +11187,7 @@
       "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
       "dev": true,
       "requires": {
-        "spdx-correct": "3.0.1",
+        "spdx-correct": "3.0.2",
         "spdx-expression-parse": "3.0.0"
       }
     },
@@ -11686,9 +11687,9 @@
       }
     },
     "webpack-subresource-integrity": {
-      "version": "1.1.0-rc.6",
-      "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz",
-      "integrity": "sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w==",
+      "version": "1.1.0-rc.7",
+      "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.7.tgz",
+      "integrity": "sha512-oWhoXGeA+F6lNJajh6pIBTTTa1qKJ4bpN3nRUKBrs3wJ6wId5HeKUxB8JUWY2gq6NsUFZ5Xi79HI2QEot6ZuhA==",
       "dev": true,
       "requires": {
         "webpack-core": "0.6.9"
diff --git a/web/gui2/src/main/tslint.json b/web/gui2/src/main/tslint.json
index c040afa..c07f1d2 100644
--- a/web/gui2/src/main/tslint.json
+++ b/web/gui2/src/main/tslint.json
@@ -124,7 +124,7 @@
     ],
     "component-selector": [
       true,
-      "element",
+      ["element", "attribute"],
       "onos",
       "kebab-case"
     ],
diff --git a/web/gui2/src/main/webapp/app/nav/nav.component.css b/web/gui2/src/main/webapp/app/nav/nav.component.css
index d7471c4..2386042 100644
--- a/web/gui2/src/main/webapp/app/nav/nav.component.css
+++ b/web/gui2/src/main/webapp/app/nav/nav.component.css
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/app/nav/nav.component.spec.ts b/web/gui2/src/main/webapp/app/nav/nav.component.spec.ts
index acc400f..7b3fbfa 100644
--- a/web/gui2/src/main/webapp/app/nav/nav.component.spec.ts
+++ b/web/gui2/src/main/webapp/app/nav/nav.component.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/app/nav/nav.component.ts b/web/gui2/src/main/webapp/app/nav/nav.component.ts
index 058f514..218285b 100644
--- a/web/gui2/src/main/webapp/app/nav/nav.component.ts
+++ b/web/gui2/src/main/webapp/app/nav/nav.component.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/app/nav/nav.theme.css b/web/gui2/src/main/webapp/app/nav/nav.theme.css
index 1a308ac..ff2e50b 100644
--- a/web/gui2/src/main/webapp/app/nav/nav.theme.css
+++ b/web/gui2/src/main/webapp/app/nav/nav.theme.css
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/app/onos-routing.module.ts b/web/gui2/src/main/webapp/app/onos-routing.module.ts
index 344e6d9..60ec9d7 100644
--- a/web/gui2/src/main/webapp/app/onos-routing.module.ts
+++ b/web/gui2/src/main/webapp/app/onos-routing.module.ts
@@ -78,6 +78,10 @@
         path: 'meter',
         loadChildren: 'app/view/meter/meter.module#MeterModule'
     },
+    {
+        path: 'topo',
+        loadChildren: 'app/view/topology/topology.module#TopologyModule'
+    },
 /*  Comment out below section for running locally with 'ng serve' when developing */
     {
         path: 'alarmTable',
diff --git a/web/gui2/src/main/webapp/app/onos.common.css b/web/gui2/src/main/webapp/app/onos.common.css
index 9a3f5a6..fa6d502 100644
--- a/web/gui2/src/main/webapp/app/onos.common.css
+++ b/web/gui2/src/main/webapp/app/onos.common.css
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/app/onos.component.css b/web/gui2/src/main/webapp/app/onos.component.css
index 7e5af04..1fd060c 100644
--- a/web/gui2/src/main/webapp/app/onos.component.css
+++ b/web/gui2/src/main/webapp/app/onos.component.css
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/app/onos.component.spec.ts b/web/gui2/src/main/webapp/app/onos.component.spec.ts
new file mode 100644
index 0000000..0801494
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/onos.component.spec.ts
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+import { ComponentFixture, TestBed, async } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import { BrowserModule } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { FormsModule } from '@angular/forms';
+import { of } from 'rxjs';
+
+import { NavComponent } from './nav/nav.component';
+import { OnosComponent } from './onos.component';
+
+import {
+    LogService, ConsoleLoggerService,
+    ConfirmComponent,
+    IconComponent,
+    MastComponent,
+    VeilComponent,
+    FnService,
+    GlyphService,
+    IconService,
+    LionService,
+    NavService, UiView,
+    OnosService,
+    SvgUtilService,
+    ThemeService,
+    WebSocketService,
+    WsOptions
+} from 'gui2-fw-lib';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+class MockDialogService {}
+
+class MockGlyphService {}
+
+class MockIconService {}
+
+class MockLionService {}
+
+class MockNavService {
+    uiPlatformViews = new Array<UiView>();
+    uiNetworkViews = new Array<UiView>();
+    uiOtherViews = new Array<UiView>();
+    uiHiddenViews = new Array<UiView>();
+}
+
+class MockOnosService {}
+
+class MockThemeService {}
+
+class MockVeilComponent {}
+
+class MockWebSocketService {
+    createWebSocket() { }
+    isConnected() { return false; }
+    unbindHandlers() { }
+    bindHandlers() { }
+}
+
+/**
+ * ONOS GUI -- Onos Component - Unit Tests
+ */
+describe('OnosComponent', () => {
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let component: OnosComponent;
+    let fixture: ComponentFixture<OnosComponent>;
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({'debug': 'TestService'});
+
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            },
+            innerHeight: 240,
+            innerWidth: 320
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
+        TestBed.configureTestingModule({
+            imports: [
+                RouterTestingModule,
+                BrowserModule,
+                BrowserAnimationsModule,
+                FormsModule
+            ],
+            declarations: [
+                ConfirmComponent,
+                IconComponent,
+                MastComponent,
+                NavComponent,
+                OnosComponent,
+                VeilComponent,
+            ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: GlyphService, useClass: MockGlyphService },
+                { provide: IconService, useClass: MockIconService },
+                { provide: LionService, useClass: MockLionService },
+                { provide: LogService, useValue: logSpy },
+                { provide: NavService, useClass: MockNavService },
+                { provide: OnosService, useClass: MockOnosService },
+                { provide: ThemeService, useClass: MockThemeService },
+                { provide: WebSocketService, useClass: MockWebSocketService },
+                { provide: Window, useFactory: (() => windowMock ) },
+            ]
+        }).compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(OnosComponent);
+        component = fixture.debugElement.componentInstance;
+        fixture.detectChanges();
+    });
+
+// TODO: Reimplemt this - it's compaining about "no provider for Window"
+//    it('should create the component', () => {
+//        expect(component).toBeTruthy();
+//    });
+
+//    it(`should have as title 'onos'`, async(() => {
+//        const fixture = TestBed.createComponent(OnosComponent);
+//        const app = fixture.componentInstance;
+//        expect(app.title).toEqual('onos');
+//    }));
+});
diff --git a/web/gui2/src/main/webapp/app/onos.component.ts b/web/gui2/src/main/webapp/app/onos.component.ts
index c5f5b3a..0fe1346 100644
--- a/web/gui2/src/main/webapp/app/onos.component.ts
+++ b/web/gui2/src/main/webapp/app/onos.component.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-present Open Networking Foundation
+ * 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.
@@ -15,15 +15,15 @@
  */
 import { Component, OnInit, AfterViewInit, OnDestroy } from '@angular/core';
 import { Observable, Subscription, fromEvent } from 'rxjs';
-import { map, filter } from 'rxjs/operators';
-
+import * as d3 from 'd3';
 import {
     LionService,
     LogService,
     ThemeService,
     GlyphService,
     WebSocketService,
-    WsOptions
+    WsOptions,
+    KeysService
 } from 'gui2-fw-lib';
 import { OnosService, View } from './onos.service';
 
@@ -81,6 +81,7 @@
         private lion: LionService,
         private ts: ThemeService,
         private gs: GlyphService,
+        private ks: KeysService,
         public wss: WebSocketService,
         private log: LogService,
         private onos: OnosService
@@ -121,36 +122,38 @@
      * quick help feature
      */
     ngAfterViewInit() {
-        const keyStrokeHandler =
-            fromEvent(document, 'keyup').pipe(map((x: KeyboardEvent) => x.keyCode));
-        this.quickHelpHandler = keyStrokeHandler.pipe(
-            filter(x => {
-                return [27, 191, 220].includes(x);
-            })
-        ).pipe(
-            map(x => {
-                let direction;
-                switch (x) {
-                    case 27:
-                        direction = 'esc';
-                        break;
-                    case 191:
-                        direction = 'fwdslash';
-                        break;
-                    case 220:
-                        direction = 'backslash';
-                        break;
-                    default:
-                        direction = 'esc';
-                }
-                return direction;
-            })
-        );
-
-        // TODO: Make a Quick Help component popup
-        this.quickHelpSub = this.quickHelpHandler.subscribe((keyname) => {
-            this.log.debug('Keystroke', keyname);
-        });
+        // const keyStrokeHandler =
+        //     fromEvent(document, 'keyup').pipe(map((x: KeyboardEvent) => x.keyCode));
+        // this.quickHelpHandler = keyStrokeHandler.pipe(
+        //     filter(x => {
+        //         return [27, 191, 220].includes(x);
+        //     })
+        // ).pipe(
+        //     map(x => {
+        //         let direction;
+        //         switch (x) {
+        //             case 27:
+        //                 direction = 'esc';
+        //                 break;
+        //             case 191:
+        //                 direction = 'fwdslash';
+        //                 break;
+        //             case 220:
+        //                 direction = 'backslash';
+        //                 break;
+        //             default:
+        //                 direction = 'esc';
+        //         }
+        //         return direction;
+        //     })
+        // );
+        //
+        // // TODO: Make a Quick Help component popup
+        // this.quickHelpSub = this.quickHelpHandler.subscribe((keyname) => {
+        //     this.log.debug('Keystroke', keyname);
+        // });
+        this.ks.installOn(d3.select('body'));
+        this.log.debug('OnosComponent after view initialized');
     }
 
     ngOnDestroy() {
diff --git a/web/gui2/src/main/webapp/app/onos.module.ts b/web/gui2/src/main/webapp/app/onos.module.ts
index 576d0f1..f9bbd15 100644
--- a/web/gui2/src/main/webapp/app/onos.module.ts
+++ b/web/gui2/src/main/webapp/app/onos.module.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/tests/app/onos.service.spec.ts b/web/gui2/src/main/webapp/app/onos.service.spec.ts
similarity index 86%
rename from web/gui2/src/main/webapp/tests/app/onos.service.spec.ts
rename to web/gui2/src/main/webapp/app/onos.service.spec.ts
index 01d5aef..073dfa7 100644
--- a/web/gui2/src/main/webapp/tests/app/onos.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/onos.service.spec.ts
@@ -15,9 +15,8 @@
  */
 import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../app/log.service';
-import { ConsoleLoggerService } from '../../app/consolelogger.service';
-import { OnosService } from '../../app/onos.service';
+import { LogService, ConsoleLoggerService } from 'gui2-fw-lib';
+import { OnosService } from './onos.service';
 
 /**
  * ONOS GUI -- Onos Service - Unit Tests
diff --git a/web/gui2/src/main/webapp/app/view/apps/apps/apps.component.spec.ts b/web/gui2/src/main/webapp/app/view/apps/apps/apps.component.spec.ts
index f1dfe0d..5864743 100644
--- a/web/gui2/src/main/webapp/app/view/apps/apps/apps.component.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/apps/apps/apps.component.spec.ts
@@ -140,8 +140,7 @@
                 { provide: WebSocketService, useClass: MockWebSocketService },
                 { provide: 'Window', useValue: windowMock },
             ]
-        })
-            .compileComponents();
+        }).compileComponents();
         logServiceSpy = TestBed.get(LogService);
     }));
 
diff --git a/web/gui2/src/main/webapp/app/view/cluster/cluster-details.directive.ts b/web/gui2/src/main/webapp/app/view/cluster/cluster-details.directive.ts
index c796962..17e5842 100644
--- a/web/gui2/src/main/webapp/app/view/cluster/cluster-details.directive.ts
+++ b/web/gui2/src/main/webapp/app/view/cluster/cluster-details.directive.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
@@ -72,10 +72,14 @@
     });
 }
 
+
+/**
+ * This should not be a directive - this should be a component, like all of the other details views
+ * Change it when time allows
+ */
 @Directive({
     selector: '[onosClusterDetails]',
 })
-
 export class ClusterDetailsDirective extends DetailsPanelBaseImpl implements OnInit, OnDestroy, OnChanges {
     @Input() id: string;
     @Output() closeEvent = new EventEmitter<string>();
diff --git a/web/gui2/src/main/webapp/app/view/meter/meter/meter.theme.css b/web/gui2/src/main/webapp/app/view/meter/meter/meter.theme.css
index 9f4dea4..4a24785 100644
--- a/web/gui2/src/main/webapp/app/view/meter/meter/meter.theme.css
+++ b/web/gui2/src/main/webapp/app/view/meter/meter/meter.theme.css
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
diff --git a/web/gui2/src/main/webapp/app/view/port/portdetails/portdetails.component.html b/web/gui2/src/main/webapp/app/view/port/portdetails/portdetails.component.html
index 36fa847..d4b59be 100644
--- a/web/gui2/src/main/webapp/app/view/port/portdetails/portdetails.component.html
+++ b/web/gui2/src/main/webapp/app/view/port/portdetails/portdetails.component.html
@@ -1,5 +1,5 @@
 <!--
-~ Copyright 2015-present Open Networking Foundation
+~ 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.
diff --git a/web/gui2/src/main/webapp/app/view/topology/README.md b/web/gui2/src/main/webapp/app/view/topology/README.md
new file mode 100644
index 0000000..3f3e647
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/README.md
@@ -0,0 +1,8 @@
+# Topology
+
+This is the GUI2 version of the combined Topo and Topo2 views of the older version.
+
+It uses Angular 6 components extensively.
+
+This should all be moved to its own separate library once all debugging is done
+(it is slightly more difficult to debug the code when in a separate library)
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.css b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.css
new file mode 100644
index 0000000..642c1c4
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.css
@@ -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.
+ */
+
+
+/*
+ ONOS GUI -- Topology View (background) -- CSS file
+ */
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.html
new file mode 100644
index 0000000..3f78ebb
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.html
@@ -0,0 +1,16 @@
+<!--
+~ 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.
+-->
+<svg:g onos-mapsvg />
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.spec.ts
new file mode 100644
index 0000000..f1e1e69
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.spec.ts
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BackgroundSvgComponent } from './backgroundsvg.component';
+
+describe('BackgroundSvgComponent', () => {
+    let component: BackgroundSvgComponent;
+    let fixture: ComponentFixture<BackgroundSvgComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            declarations: [ BackgroundSvgComponent ]
+        })
+        .compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(BackgroundSvgComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.ts
new file mode 100644
index 0000000..6a010d1
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/backgroundsvg/backgroundsvg.component.ts
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+import { Component, OnInit } from '@angular/core';
+
+/**
+ * ONOS GUI -- Topology Background Layer View.
+ */
+@Component({
+    selector: '[onos-backgroundsvg]',
+    templateUrl: './backgroundsvg.component.html',
+    styleUrls: ['./backgroundsvg.component.css']
+})
+export class BackgroundSvgComponent implements OnInit {
+
+    constructor() { }
+
+    ngOnInit() {
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.css
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.css
index 5307028..addd41c 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.css
@@ -13,21 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../app/log.service';
 
-/**
- * ONOS GUI -- Log Service - Unit Tests
- */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
-
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+/*
+ ONOS GUI -- Topology View (forces) -- CSS file
+ */
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
new file mode 100644
index 0000000..0c2f0aa
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
@@ -0,0 +1,22 @@
+<!--
+~ 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.
+-->
+<svg:g class="topo2-force">
+    <svg:g class="topo2-links" />
+    <svg:g class="topo2-linkLabels" />
+    <svg:g class="topo2-numLinkLabels" />
+    <svg:g class="topo2-nodes" />
+    <svg:g class="topo2-portLabels" />
+</svg:g>
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.spec.ts
new file mode 100644
index 0000000..505c528
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.spec.ts
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ForceSvgComponent } from './forcesvg.component';
+
+describe('ForceSvgComponent', () => {
+    let component: ForceSvgComponent;
+    let fixture: ComponentFixture<ForceSvgComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+          declarations: [ ForceSvgComponent ]
+        })
+        .compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(ForceSvgComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
new file mode 100644
index 0000000..45fa000
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+import { Component, OnInit } from '@angular/core';
+
+/**
+ * ONOS GUI -- Topology Forces Graph Layer View.
+ */
+@Component({
+    selector: '[onos-forcesvg]',
+    templateUrl: './forcesvg.component.html',
+    styleUrls: ['./forcesvg.component.css']
+})
+export class ForceSvgComponent implements OnInit {
+
+    constructor() { }
+
+    ngOnInit() {
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.css b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.css
new file mode 100644
index 0000000..beb3725
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.css
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.html
new file mode 100644
index 0000000..8fe566b
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.html
@@ -0,0 +1,18 @@
+<!--
+~ 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.
+-->
+<p>
+  layout works!
+</p>
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.spec.ts
new file mode 100644
index 0000000..1691947
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.spec.ts
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LayoutComponent } from './layout.component';
+
+describe('LayoutComponent', () => {
+  let component: LayoutComponent;
+  let fixture: ComponentFixture<LayoutComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ LayoutComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(LayoutComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.ts
new file mode 100644
index 0000000..477dd15
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.ts
@@ -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.
+ */
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'onos-layout',
+  templateUrl: './layout.component.html',
+  styleUrls: ['./layout.component.css']
+})
+export class LayoutComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.css
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.css
index 5307028..f206973 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.css
@@ -13,21 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../app/log.service';
 
 /**
- * ONOS GUI -- Log Service - Unit Tests
- */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
-
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+ * ONOS GUI -- Topology Map Layer -- CSS file
+ */
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.html
new file mode 100644
index 0000000..4f3b14f
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.html
@@ -0,0 +1,17 @@
+<!--
+~ 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.
+-->
+<svg:text>Map of Croatia</svg:text>
+<svg:path d="m 187.50819,219.30177 -3.14986,-1.57795 z M 45.764161,56.635237 48.914029,55.022914 Z m 62.997349,-32.313055 6.29973,4.85593 6.29974,11.31816 v 11.300949 h 9.4496 l 12.59947,8.061616 6.29973,12.880483 v 8.039036 l 6.29974,14.448536 -3.14987,9.616908 -6.29973,12.80342 v 14.37787 l 3.14986,7.97587 -9.4496,3.18799 3.14987,9.55592 6.29973,4.77344 v 7.94906 l -6.29973,1.58881 3.14987,15.86987 6.29973,6.33869 v 6.33341 l 6.29974,1.58253 v 20.54314 h 6.29973 18.89921 l 3.14986,4.73289 v 1.57699 6.30469 l -3.14986,4.72511 6.29973,6.29564 v 1.57311 l 3.14987,7.8607 -9.4496,17.26536 h -9.44961 l -6.29973,4.70203 v 14.08899 l -6.29974,3.12741 v 15.61816 l -3.14986,6.23849 -22.04907,3.11737 -3.14987,7.78797 h -6.29974 l 9.44961,17.10623 -3.14987,6.21118 -6.29974,-1.55233 v 10.85988 l -6.29973,7.74786 -18.89921,-6.19768 v -20.17635 l -6.299731,-3.10867 v -6.22107 l -6.299735,-10.8988 -9.449602,-3.11675 v -4.67746 l -9.449602,-1.55978 -6.299735,-6.24224 -9.449602,-3.123 -9.449602,-12.5046 -3.149867,-14.09183 12.599469,12.52734 3.149868,-12.52734 -9.449602,-9.40886 6.299734,1.56894 v -7.84788 l -6.299734,1.57021 -6.299735,-9.4261 3.149867,-4.71738 V 228.7627 l 3.149868,-9.46093 6.299734,-3.15624 v -31.63431 l 6.299735,-7.92914 -3.149867,-6.34927 H 52.063896 V 155.9275 l 9.449602,-9.5519 -9.449602,-7.96914 h 12.599469 v -27.15822 l -12.599469,-6.40444 -6.299735,1.60162 V 82.385126 l 3.149868,-3.213886 6.299734,1.607116 3.149868,-8.039036 -12.59947,-9.658277 6.299735,-9.6708 -3.149867,-1.613022 6.299734,-11.300949 6.299735,-4.848528 v -6.469632 l 6.299735,-3.236933 v -8.098523 l 9.449602,-4.863368 3.149867,3.2426 v 14.574161 l 6.299735,3.234816 12.59947,-3.234816 z"></svg:path>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.spec.ts
new file mode 100644
index 0000000..e1000c8
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.spec.ts
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MapSvgComponent } from './mapsvg.component';
+
+describe('MapSvgComponent', () => {
+  let component: MapSvgComponent;
+  let fixture: ComponentFixture<MapSvgComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ MapSvgComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MapSvgComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.ts
new file mode 100644
index 0000000..2de6c12
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/mapsvg/mapsvg.component.ts
@@ -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.
+ */
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+    selector: '[onos-mapsvg]',
+    templateUrl: './mapsvg.component.html',
+    styleUrls: ['./mapsvg.component.css']
+})
+export class MapSvgComponent implements OnInit {
+
+    constructor() { }
+
+    ngOnInit() {
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.css
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.css
index 5307028..7897595 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.css
@@ -13,21 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../app/log.service';
 
-/**
- * ONOS GUI -- Log Service - Unit Tests
+/*
+ ONOS GUI -- Topology View (no devices connected) -- CSS file
  */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
+/* --- "No Devices" Layer --- */
+#topo-noDevsLayer {
+    visibility: hidden;
+}
 
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+#topo-noDevsLayer text {
+    font-size: 60pt;
+    font-style: italic;
+    fill: #7e9aa8;
+}
+
+#topo-noDevsLayer .noDevsBird {
+    fill: #db7773;
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.html
new file mode 100644
index 0000000..d201c8a
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.html
@@ -0,0 +1,21 @@
+<!--
+~ 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.
+-->
+<svg:g id="topo-noDevsLayer" transform="translate(500,500)" style="visibility: visible;">
+    <svg:g id="reposition" #reposition [attr.transform]="centre(reposition.getBBox())">
+        <svg:use width="100" height="100" class="noDevsBird" href="#bird"></svg:use>
+        <svg:text x="120" y="80">No Devices Are Connected</svg:text>
+    </svg:g>
+</svg:g>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.spec.ts
new file mode 100644
index 0000000..a467a3d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.spec.ts
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { NoDeviceConnectedSvgComponent } from './nodeviceconnectedsvg.component';
+import { DebugElement } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import {
+    FnService,
+    IconService,
+    LionService,
+    LogService,
+    UrlFnService,
+    TableFilterPipe,
+    IconComponent,
+    WebSocketService
+} from 'gui2-fw-lib';
+import { of } from 'rxjs';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+class MockIconService {
+    classes = 'active-close';
+    loadIconDef() { }
+}
+
+class MockWebSocketService {
+    createWebSocket() { }
+    isConnected() { return false; }
+    unbindHandlers() { }
+    bindHandlers() { }
+}
+
+/**
+ * ONOS GUI -- Topology NoDevicesConnected -- Unit Tests
+ */
+describe('NoDeviceConnectedSvgComponent', () => {
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let component: NoDeviceConnectedSvgComponent;
+    let fixture: ComponentFixture<NoDeviceConnectedSvgComponent>;
+
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({'debug': 'panel'});
+
+        windowMock = <any>{
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
+        TestBed.configureTestingModule({
+            declarations: [ NoDeviceConnectedSvgComponent ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: IconService, useClass: MockIconService },
+                { provide: LogService, useValue: logSpy },
+                { provide: WebSocketService, useClass: MockWebSocketService },
+                { provide: 'Window', useValue: windowMock },
+            ]
+        }).compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(NoDeviceConnectedSvgComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.ts
new file mode 100644
index 0000000..2ff9ed1
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.ts
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+import { Component, OnInit } from '@angular/core';
+import { ViewControllerImpl } from '../viewcontroller';
+import {
+    FnService,
+    LogService,
+    PrefsService,
+    IconService,
+    SvgUtilService
+} from 'gui2-fw-lib';
+
+/**
+ * ONOS GUI -- Topology No Connected Devices View.
+ * View that contains the 'No Connected Devices' message
+ *
+ * This component is an SVG snippet that expects to be in an SVG element with a view box of 1000x1000
+ *
+ * It should be added to a template with a tag like <svg:g onos-nodeviceconnected />
+ */
+@Component({
+  selector: '[onos-nodeviceconnected]',
+  templateUrl: './nodeviceconnectedsvg.component.html',
+  styleUrls: ['./nodeviceconnectedsvg.component.css']
+})
+export class NoDeviceConnectedSvgComponent extends ViewControllerImpl implements OnInit {
+
+    constructor(
+        protected fs: FnService,
+        protected log: LogService,
+        protected ps: PrefsService,
+        protected is: IconService,
+        protected sus: SvgUtilService
+    ) {
+        super(fs, log, ps);
+        this.is.loadIconDef('bird');
+        this.log.debug('NoDeviceConnectedSvgComponent constructed');
+    }
+
+    ngOnInit() {
+        this.log.debug('NoDeviceConnectedSvgComponent initialized');
+    }
+
+    /*
+     * The whole SVG canvas is based on a 1000 by 1000 box
+     */
+    centre(repositionBox: SVGRect) {
+        const scale: number = Number.parseFloat((1000 / repositionBox.width).toFixed(3));
+        repositionBox.x -= Number.parseFloat((repositionBox.width * scale / 2).toFixed(0));
+        repositionBox.y -= Number.parseFloat((repositionBox.height * scale / 2).toFixed(0));
+        return this.sus.translate([repositionBox.x, repositionBox.y]) + '' + this.sus.scale(scale, scale);
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/viewcontroller.ts b/web/gui2/src/main/webapp/app/view/topology/layer/viewcontroller.ts
new file mode 100644
index 0000000..1b40195
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/viewcontroller.ts
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+import { FnService, LogService, PrefsService } from 'gui2-fw-lib';
+
+export interface ViewControllerPrefs {
+    visible: string;
+}
+
+/*
+ ONOS GUI -- View Controller.
+ A base class for view controllers to extend from
+ */
+export abstract class ViewControllerImpl {
+    id: string;
+    displayName: string = 'View';
+    name: string;
+    prefs: ViewControllerPrefs;
+    visibility: string;
+
+    constructor(
+        protected fs: FnService,
+        protected log: LogService,
+        protected ps: PrefsService
+    ) {
+        this.log.debug('View Controller constructed');
+    }
+
+    initialize() {
+        this.name = this.displayName.toLowerCase().replace(/ /g, '_');
+        this.prefs = {
+            visible: this.name + '_visible',
+        };
+    }
+
+    enabled() {
+        return this.ps.getPrefs('topo2_prefs', null)[this.prefs.visible];
+    }
+
+    isVisible() {
+        return this.visibility;
+    }
+
+    hide() {
+        this.visibility = 'hidden';
+    }
+
+    show() {
+        this.visibility = 'visible';
+    }
+
+    toggle() {
+        if (this.visibility === 'hidden') {
+            this.visibility = 'visible';
+        } else if (this.visibility === 'visible') {
+            this.visibility = 'hidden';
+        }
+    }
+
+    lookupPrefState(key: string): number {
+        // Return 0 if not defined
+        return this.ps.getPrefs('topo2_prefs', null)[key] || 0;
+    }
+
+    updatePrefState(key: string, value: number) {
+        const state = this.ps.getPrefs('topo2_prefs', null);
+        state[key] = value ? 1 : 0;
+        this.ps.setPrefs('topo2_prefs', state);
+    }
+}
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.css
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.css
index 5307028..fca0dc7 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.css
@@ -13,21 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../app/log.service';
 
 /**
- * ONOS GUI -- Log Service - Unit Tests
- */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
-
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+ * ONOS GUI -- Topology Zoom Layer -- CSS file
+ */
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.html
new file mode 100644
index 0000000..6f1bb4b
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.html
@@ -0,0 +1,19 @@
+<!--
+~ 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.
+-->
+<svg:g id="topo-zoomlayer">
+    <svg:g onos-backgroundsvg/>
+    <svg:g onos-forcesvg/>
+</svg:g>
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.spec.ts
new file mode 100644
index 0000000..60a1997
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.spec.ts
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { of } from 'rxjs';
+
+import { ZoomLayerSvgComponent } from './zoomlayersvg.component';
+import {
+    FnService,
+    LogService,
+    ZoomService
+} from 'gui2-fw-lib';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+class MockZoomService {}
+
+/**
+ * ONOS GUI -- Topology View Zoom Layer -- Unit Tests
+ */
+describe('ZoomLayerSvgComponent', () => {
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let component: ZoomLayerSvgComponent;
+    let fixture: ComponentFixture<ZoomLayerSvgComponent>;
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({ 'debug': 'txrx' });
+
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
+        TestBed.configureTestingModule({
+            declarations: [ ZoomLayerSvgComponent ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: LogService, useValue: logSpy },
+                { provide: 'Window', useValue: windowMock },
+                { provide: ZoomService, useClass: MockZoomService }
+            ]
+        })
+        .compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(ZoomLayerSvgComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.ts
new file mode 100644
index 0000000..e0c85ed
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.ts
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+import { Component, OnInit } from '@angular/core';
+import {
+    FnService,
+    LogService,
+    ZoomService, Zoomer, ZoomOpts
+} from 'gui2-fw-lib';
+
+/**
+ * ONOS GUI -- Topology Zoom Layer View.
+ * View that contains the 'Force graph' message
+ *
+ * This component is an SVG snippet that expects to be in an SVG element with a view box of 1000x1000
+ *
+ * It should be added to a template with a tag like <svg:g onos-zoomlayer />
+ */
+@Component({
+  selector: '[onos-zoomlayer]',
+  templateUrl: './zoomlayersvg.component.html',
+  styleUrls: ['./zoomlayersvg.component.css']
+})
+export class ZoomLayerSvgComponent implements OnInit {
+    zoomer: Zoomer;
+    zoomEventListeners: any[];
+
+    constructor(
+        protected fs: FnService,
+        protected log: LogService,
+        protected zs: ZoomService
+    ) {
+        this.log.debug('ZoomLayerSvgComponent constructed');
+    }
+
+    ngOnInit() {
+
+    }
+
+    createZoomer(options: ZoomOpts) {
+        // need to wrap the original zoom callback to extend its behavior
+        const origCallback = this.fs.isF(options.zoomCallback) ? options.zoomCallback : () => {};
+
+        options.zoomCallback = () => {
+            origCallback([0, 0], 1);
+
+            this.zoomEventListeners.forEach((ev) => ev(this.zoomer));
+        };
+
+        this.zoomer = this.zs.createZoomer(options);
+        return this.zoomer;
+    }
+
+    getZoomer() {
+        return this.zoomer;
+    }
+
+    findZoomEventListener(ev) {
+        for (let i = 0, len = this.zoomEventListeners.length; i < len; i++) {
+            if (this.zoomEventListeners[i] === ev) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    addZoomEventListener(callback) {
+        this.zoomEventListeners.push(callback);
+    }
+
+    removeZoomEventListener(callback) {
+        const evIndex = this.findZoomEventListener(callback);
+
+        if (evIndex !== -1) {
+            this.zoomEventListeners.splice(evIndex);
+        }
+    }
+
+    adjustmentScale(min: number, max: number): number {
+        let _scale = 1;
+        const size = (min + max) / 2;
+
+        if (size * this.scale() < max) {
+            _scale = min / (size * this.scale());
+        } else if (size * this.scale() > max) {
+            _scale = min / (size * this.scale());
+        }
+
+        return _scale;
+    }
+
+    scale(): number {
+        return this.zoomer.scale();
+    }
+
+    panAndZoom(translate: number[], scale: number, transition?: number) {
+        this.zoomer.panZoom(translate, scale, transition);
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.css b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.css
new file mode 100644
index 0000000..9a35cb3
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.css
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+/* --- Topo Details Panel --- */
+
+#topo2-p-detail {
+    padding: 16px;
+    top: 370px;
+}
+html[data-platform='iPad'] #topo2-p-detail {
+    top: 386px;
+}
+
+#topo2-p-detail .actionBtns .actionBtn {
+    display: inline-block;
+}
+#topo2-p-detail .actionBtns .actionBtn svg {
+    width: 28px;
+    height: 28px;
+}
+
+#topo2-p-detail  div.actionBtns {
+    padding-top: 6px;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.html
new file mode 100644
index 0000000..1ff43e6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.html
@@ -0,0 +1,128 @@
+<!--
+~ 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.
+-->
+<div id="topo2-p-detail" class="floatpanel topo2-p"
+     style="opacity: 1; right: 20px; width: 260px; top: 350px;" [@detailsPanelState]="!on">
+    <div class="header">
+        <div class="icon clickable">
+            <svg>
+                <use width="26" height="26" class="glyph" xlink:href="#m_switch"></use>
+            </svg>
+        </div>
+        <h2 class="clickable">rest:10.1.2.2:443</h2>
+    </div>
+    <div class="body">
+        <table>
+            <tbody>
+            <tr>
+                <td class="label">URI :</td>
+                <td class="value">null:0000000000000002</td>
+            </tr>
+            <tr>
+                <td class="label">Vendor :</td>
+                <td class="value">ONF</td>
+            </tr>
+            <tr>
+                <td class="label">H/W Version :</td>
+                <td class="value">0.1</td>
+            </tr>
+            <tr>
+                <td class="label">S/W Version :</td>
+                <td class="value">0.1</td>
+            </tr>
+            <tr>
+                <td class="label">Serial # :</td>
+                <td class="value">1234</td>
+            </tr>
+            <tr>
+                <td class="label">Protocol :</td>
+                <td class="value"></td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <hr>
+                </td>
+            </tr>
+            <tr>
+                <td class="label">Ports :</td>
+                <td class="value">4</td>
+            </tr>
+            <tr>
+                <td class="label">Flows :</td>
+                <td class="value">4</td>
+            </tr>
+            <tr>
+                <td class="label">Tunnels :</td>
+                <td class="value">0</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+    <div class="footer">
+        <hr>
+        <div class="actionBtns">
+            <div class="actionBtn">
+                <div class="button" id="topo2-p-detail-core-showDeviceView">
+                    <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                        <g class="icon">
+                            <rect width="50" height="50" rx="5"></rect>
+                            <use width="50" height="50" class="glyph" xlink:href="#switch"></use>
+                        </g>
+                    </svg>
+                </div>
+            </div>
+            <div class="actionBtn">
+                <div class="button" id="topo2-p-detail-core-showFlowView">
+                    <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                        <g class="icon">
+                            <rect width="50" height="50" rx="5"></rect>
+                            <use width="50" height="50" class="glyph" xlink:href="#flowTable"></use>
+                        </g>
+                    </svg>
+                </div>
+            </div>
+            <div class="actionBtn">
+                <div class="button" id="topo2-p-detail-core-showPortView">
+                    <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                        <g class="icon">
+                            <rect width="50" height="50" rx="5"></rect>
+                            <use width="50" height="50" class="glyph" xlink:href="#portTable"></use>
+                        </g>
+                    </svg>
+                </div>
+            </div>
+            <div class="actionBtn">
+                <div class="button" id="topo2-p-detail-core-showGroupView">
+                    <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                        <g class="icon">
+                            <rect width="50" height="50" rx="5"></rect>
+                            <use width="50" height="50" class="glyph" xlink:href="#groupTable"></use>
+                        </g>
+                    </svg>
+                </div>
+            </div>
+            <div class="actionBtn">
+                <div class="button" id="topo2-p-detail-core-showMeterView">
+                    <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                        <g class="icon">
+                            <rect width="50" height="50" rx="5"></rect>
+                            <use width="50" height="50" class="glyph" xlink:href="#meterTable"></use>
+                        </g>
+                    </svg>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.spec.ts
new file mode 100644
index 0000000..0c0c269
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.spec.ts
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { of } from 'rxjs';
+import { DetailsComponent } from './details.component';
+
+import {
+    FnService,
+    LogService
+} from 'gui2-fw-lib';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+/**
+ * ONOS GUI -- Topology View Details Panel-- Unit Tests
+ */
+describe('DetailsComponent', () => {
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let component: DetailsComponent;
+    let fixture: ComponentFixture<DetailsComponent>;
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({ 'debug': 'txrx' });
+
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
+        TestBed.configureTestingModule({
+            imports: [ BrowserAnimationsModule ],
+            declarations: [ DetailsComponent ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: LogService, useValue: logSpy },
+                { provide: 'Window', useValue: windowMock },
+            ]
+        })
+        .compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(DetailsComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.ts
new file mode 100644
index 0000000..c8bf95b
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.ts
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+import { Component, OnInit } from '@angular/core';
+import { animate, state, style, transition, trigger } from '@angular/animations';
+import {
+    LogService,
+    LoadingService,
+    FnService,
+    DetailsPanelBaseImpl,
+    WebSocketService
+} from 'gui2-fw-lib';
+
+/*
+ ONOS GUI -- Topology Details Panel.
+ Displays details of selected device.
+ */
+@Component({
+    selector: 'onos-details',
+    templateUrl: './details.component.html',
+    styleUrls: [
+        './details.component.css', './details.theme.css',
+        '../../topology.common.css',
+        '../../../../fw/widget/panel.css', '../../../../fw/widget/panel-theme.css'
+    ],
+    animations: [
+        trigger('detailsPanelState', [
+            state('true', style({
+                transform: 'translateX(0%)',
+                opacity: '100'
+            })),
+            state('false', style({
+                transform: 'translateX(100%)',
+                opacity: '0'
+            })),
+            transition('0 => 1', animate('100ms ease-in')),
+            transition('1 => 0', animate('100ms ease-out'))
+        ])
+    ]
+})
+export class DetailsComponent extends DetailsPanelBaseImpl implements OnInit {
+
+    constructor(
+        protected fs: FnService,
+        protected log: LogService,
+        protected ls: LoadingService,
+        protected wss: WebSocketService,
+    ) {
+        super(fs, ls, log, wss, 'topo');
+        this.log.debug('InstanceComponent constructed');
+    }
+
+    ngOnInit() {
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.theme.css b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.theme.css
new file mode 100644
index 0000000..7ad72dd
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.theme.css
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+/* --- Topo Details Panel Theme --- */
+
+#topo2-p-detail svg {
+    background: none;
+}
+
+#topo2-p-detail .header svg .glyph {
+    fill: #c0242b;
+}
+
+.dark #topo2-p-detail .header svg .glyph {
+    fill: #91292f;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.css b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.css
new file mode 100644
index 0000000..cb78e8d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.css
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+/* --- Topo Instance Panel --- */
+
+#topo-p-instance {
+    height: 85px;
+    padding: 10px;
+}
+
+#topo-p-instance div.onosInst {
+    display: inline-block;
+    width: 170px;
+    height: 85px;
+    cursor: pointer;
+}
+
+#topo-p-instance svg text.instTitle {
+    font-size: 11pt;
+    font-weight: bold;
+    font-variant: small-caps;
+    text-transform: uppercase;
+}
+#topo-p-instance svg text.instLabel {
+    font-size: 10pt;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.html
new file mode 100644
index 0000000..6a1aba9
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.html
@@ -0,0 +1,29 @@
+<!--
+~ 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.
+-->
+<div id="topo-p-instance" class="floatpanel" style="left: 20px; width: 170px; height: 85px;" [@instancePanelState]="!on">
+    <div class="onosInst online ready mastership affinity">
+        <svg width="170" height="85" viewBox="0 0 170 85">
+            <rect x="5" y="5" width="160" height="30" style="fill: rgb(91, 153, 210);"></rect>
+            <rect x="5" y="35" width="160" height="45"></rect>
+            <use width="20" height="20" class="glyph badgeIcon bird" xlink:href="#bird" transform="translate(15,10)"></use>
+            <use width="16" height="16" class="glyph overlay badgeIcon readyBadge" xlink:href="#checkMark" transform="translate(18,40)"></use>
+            <text class="instTitle" x="48" y="27">127.0.0.1</text>
+            <text class="instLabel ip" x="48" y="55">127.0.0.1</text>
+            <text class="instLabel ns" x="48" y="73">Devices: 0</text>
+            <use width="24" height="24" class="glyph overlay badgeIcon uiBadge" xlink:href="#uiAttached" transform="translate(14,54)"></use>
+        </svg>
+    </div>
+</div>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.spec.ts
new file mode 100644
index 0000000..a03f23e
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.spec.ts
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { of } from 'rxjs';
+import { InstanceComponent } from './instance.component';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import {
+    FnService,
+    LogService
+} from 'gui2-fw-lib';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+/**
+ * ONOS GUI -- Topology View Instance Panel-- Unit Tests
+ */
+describe('InstanceComponent', () => {
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let component: InstanceComponent;
+    let fixture: ComponentFixture<InstanceComponent>;
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({ 'debug': 'txrx' });
+
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
+        TestBed.configureTestingModule({
+            imports: [ BrowserAnimationsModule ],
+            declarations: [ InstanceComponent ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: LogService, useValue: logSpy },
+                { provide: 'Window', useValue: windowMock },
+            ]
+        })
+        .compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(InstanceComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.ts
new file mode 100644
index 0000000..66b2a05
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.ts
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+import { Component, OnInit, Input } from '@angular/core';
+import { animate, state, style, transition, trigger } from '@angular/animations';
+import {
+    LogService,
+    LoadingService,
+    FnService,
+    PanelBaseImpl
+} from 'gui2-fw-lib';
+
+/*
+ ONOS GUI -- Topology Instances Panel.
+ Displays ONOS instances.
+ */
+@Component({
+    selector: 'onos-instance',
+    templateUrl: './instance.component.html',
+    styleUrls: [
+        './instance.component.css', './instance.theme.css',
+        '../../topology.common.css',
+        '../../../../fw/widget/panel.css', '../../../../fw/widget/panel-theme.css'
+    ],
+    animations: [
+        trigger('instancePanelState', [
+            state('true', style({
+                transform: 'translateX(0%)',
+                opacity: '100'
+            })),
+            state('false', style({
+                transform: 'translateX(-100%)',
+                opacity: '0'
+            })),
+            transition('0 => 1', animate('100ms ease-in')),
+            transition('1 => 0', animate('100ms ease-out'))
+        ])
+    ]
+})
+export class InstanceComponent extends PanelBaseImpl implements OnInit {
+
+    constructor(
+        protected fs: FnService,
+        protected log: LogService,
+        protected ls: LoadingService,
+    ) {
+        super(fs, ls, log);
+        this.log.debug('InstanceComponent constructed');
+    }
+
+    ngOnInit() {
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.theme.css b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.theme.css
new file mode 100644
index 0000000..a20711d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.theme.css
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+/* --- Topo Instance Panel --- */
+
+#topo-p-instance svg rect {
+    stroke-width: 0;
+    fill: #fbfbfb;
+}
+
+/* body of an instance */
+#topo-p-instance .online svg rect {
+    opacity: 1;
+    fill: #fbfbfb;
+}
+
+#topo-p-instance svg .glyph {
+    fill: #fff;
+}
+#topo-p-instance .online svg .glyph {
+    fill: #fff;
+}
+.dark #topo-p-instance .online svg .glyph.overlay {
+    fill: #fff;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.css b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.css
new file mode 100644
index 0000000..56f0cc9
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.css
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+
+/*
+ ONOS GUI -- Topology Summary Panel -- CSS file
+ */
+#topo2-p-summary {
+    padding: 16px;
+}
+
+#topo2-p-summary  td.label {
+    width: 50%;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.html
new file mode 100644
index 0000000..e71b58d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.html
@@ -0,0 +1,76 @@
+<!--
+~ 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.
+-->
+<div id="topo2-p-summary" class="floatpanel topo2-p"
+     style="opacity: 1; right: 20px; width: 260px;" [@summaryPanelState]="!on">
+    <div class="header">
+        <div class="icon">
+            <svg>
+                <use width="24" height="24" class="glyph" xlink:href="#bird"
+                     transform="translate(1,1)"></use>
+            </svg>
+        </div>
+        <h2>ONOS Summary</h2>
+    </div>
+    <div class="body">
+        <table>
+            <tbody>
+            <tr>
+                <td class="label">Version :</td>
+                <td class="value">1.15.0.a18e6e1</td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <hr>
+                </td>
+            </tr>
+            <tr>
+                <td class="label">Devices :</td>
+                <td class="value">2</td>
+            </tr>
+            <tr>
+                <td class="label">Links :</td>
+                <td class="value">0</td>
+            </tr>
+            <tr>
+                <td class="label">Hosts :</td>
+                <td class="value">0</td>
+            </tr>
+            <tr>
+                <td class="label">Topology SCCs :</td>
+                <td class="value">2</td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <hr>
+                </td>
+            </tr>
+            <tr>
+                <td class="label">Intents :</td>
+                <td class="value">0</td>
+            </tr>
+            <tr>
+                <td class="label">Tunnels :</td>
+                <td class="value">0</td>
+            </tr>
+            <tr>
+                <td class="label">Flows :</td>
+                <td class="value">8</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+    <div class="footer"></div>
+</div>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.spec.ts
new file mode 100644
index 0000000..5f69c19
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.spec.ts
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { of } from 'rxjs';
+import { SummaryComponent } from './summary.component';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import {
+    FnService,
+    LogService
+} from 'gui2-fw-lib';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+/**
+ * ONOS GUI -- Topology View Summary Panel -- Unit Tests
+ */
+describe('SummaryComponent', () => {
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let component: SummaryComponent;
+    let fixture: ComponentFixture<SummaryComponent>;
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({ 'debug': 'txrx' });
+
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
+        TestBed.configureTestingModule({
+            imports: [ BrowserAnimationsModule ],
+            declarations: [ SummaryComponent ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: LogService, useValue: logSpy },
+                { provide: 'Window', useValue: windowMock },
+            ]
+        })
+        .compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(SummaryComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.ts
new file mode 100644
index 0000000..d314528
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.ts
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+import { Component, OnInit } from '@angular/core';
+import { animate, state, style, transition, trigger } from '@angular/animations';
+import {
+    LogService,
+    LoadingService,
+    FnService,
+    PanelBaseImpl
+} from 'gui2-fw-lib';
+
+/*
+ ONOS GUI -- Topology Summary Module.
+ Defines modeling of ONOS Summary Panel.
+ */
+@Component({
+    selector: 'onos-summary',
+    templateUrl: './summary.component.html',
+    styleUrls: [
+        './summary.component.css',
+        '../../topology.common.css',
+        '../../../../fw/widget/panel.css', '../../../../fw/widget/panel-theme.css'
+    ],
+    animations: [
+        trigger('summaryPanelState', [
+            state('true', style({
+                transform: 'translateX(0%)',
+                opacity: '100'
+            })),
+            state('false', style({
+                transform: 'translateX(100%)',
+                opacity: '0'
+            })),
+            transition('0 => 1', animate('100ms ease-in')),
+            transition('1 => 0', animate('100ms ease-out'))
+        ])
+    ]
+})
+export class SummaryComponent extends PanelBaseImpl implements OnInit {
+
+    constructor(
+        protected fs: FnService,
+        protected log: LogService,
+        protected ls: LoadingService,
+    ) {
+        super(fs, ls, log);
+        this.log.debug('SummaryComponent constructed');
+    }
+
+
+    ngOnInit() {
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.css b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.css
new file mode 100644
index 0000000..9dca44c
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.css
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+
+/*
+ ONOS GUI -- Topology Toolbar Panel -- CSS file
+ */
+#toolbar-topo2-toolbar {
+    padding: 6px;
+}
+
+#toolbar-topo2-toolbar .tbar-row.right {
+    width: 100%;
+}
+
+#toolbar-topo2-toolbar .tbar-row-text {
+    height: 21px;
+    text-align: right;
+    padding: 8px 60px 0 0;
+    font-style: italic;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.html
new file mode 100644
index 0000000..a5e4b96
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.html
@@ -0,0 +1,132 @@
+<!--
+~ 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.
+-->
+<div id="toolbar-topo2-toolbar" class="floatpanel toolbar"
+     style="opacity: 1; left: 0px; width: 261px; top: auto; bottom: 10px;">
+    <div class="tbar-arrow">
+        <svg class="embeddedIcon" width="10" height="10" viewBox="0 0 50 50">
+            <g class="icon" transform="translate(0 50) rotate(-90)">
+                <rect width="50" height="50" rx="5"></rect>
+                <use width="50" height="50" class="glyph" xlink:href="#triangleUp"></use>
+            </g>
+        </svg>
+    </div>
+    <div class="tbar-row">
+        <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-instance-tog">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_uiAttached"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-summary-tog">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_summary"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="toggleButton selected" id="toolbar-topo2-toolbar-details-tog">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_details"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="separator"></div>
+        <div class="toggleButton" id="toolbar-topo2-toolbar-hosts-tog">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_endstation"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="toggleButton selected" id="toolbar-topo2-toolbar-offline-tog">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_switch"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-ports-tog">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_ports"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-bkgrnd-tog">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_map"></use>
+                </g>
+            </svg>
+        </div>
+    </div>
+    <br>
+    <div class="tbar-row">
+        <div class="button" id="toolbar-topo2-toolbar-topo2-cycleLabels-btn">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_cycleLabels"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="button" id="toolbar-topo2-toolbar-topo2-resetZoom-btn">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_resetZoom"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="separator"></div>
+        <div class="button" id="toolbar-topo2-toolbar-topo2-eqMaster-btn">
+            <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                <g class="icon">
+                    <rect width="50" height="50" rx="5"></rect>
+                    <use width="50" height="50" class="glyph" xlink:href="#m_eqMaster"></use>
+                </g>
+            </svg>
+        </div>
+        <div class="separator"></div>
+        <div class="radioSet" id="toolbar-topo2-toolbar-topo-overlays">
+            <div class="radioButton selected" id="toolbar-topo2-toolbar-topo-overlays-0">
+                <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                    <g class="icon">
+                        <rect width="50" height="50" rx="5"></rect>
+                        <use width="50" height="50" class="glyph" xlink:href="#m_unknown"></use>
+                    </g>
+                </svg>
+            </div>
+            <div class="radioButton" id="toolbar-topo2-toolbar-topo-overlays-1">
+                <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
+                    <g class="icon">
+                        <rect width="50" height="50" rx="5"></rect>
+                        <use width="50" height="50" class="glyph" xlink:href="#m_allTraffic"></use>
+                    </g>
+                </svg>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.spec.ts
new file mode 100644
index 0000000..730809c
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.spec.ts
@@ -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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { of } from 'rxjs';
+import { ToolbarComponent } from './toolbar.component';
+
+import {
+    FnService,
+    LogService
+} from 'gui2-fw-lib';
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+/**
+ * ONOS GUI -- Topology View Topology Panel-- Unit Tests
+ */
+describe('ToolbarComponent', () => {
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let component: ToolbarComponent;
+    let fixture: ComponentFixture<ToolbarComponent>;
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({ 'debug': 'txrx' });
+
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+        TestBed.configureTestingModule({
+            declarations: [ ToolbarComponent ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: LogService, useValue: logSpy },
+                { provide: 'Window', useValue: windowMock },
+            ]
+        })
+        .compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(ToolbarComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.ts
new file mode 100644
index 0000000..208cafe
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.ts
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+import { Component, OnInit } from '@angular/core';
+import {
+    LogService,
+    LoadingService,
+    FnService,
+    PanelBaseImpl
+} from 'gui2-fw-lib';
+
+/*
+ ONOS GUI -- Topology Toolbar Module.
+ Defines modeling of ONOS toolbar.
+ */
+@Component({
+    selector: 'onos-toolbar',
+    templateUrl: './toolbar.component.html',
+    styleUrls: [
+        './toolbar.component.css', './toolbar.theme.css',
+        '../../topology.common.css',
+        '../../../../fw/widget/panel.css', '../../../../fw/widget/panel-theme.css'
+    ]
+})
+export class ToolbarComponent extends PanelBaseImpl implements OnInit {
+
+    constructor(
+        protected fs: FnService,
+        protected log: LogService,
+        protected ls: LoadingService,
+    ) {
+        super(fs, ls, log);
+        this.log.debug('ToolbarComponent constructed');
+    }
+
+    ngOnInit() {
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.theme.css b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.theme.css
new file mode 100644
index 0000000..fcd9157
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.theme.css
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+
+/*
+ ONOS GUI -- Topology Toolbar Panel -- Theme CSS file
+ */
+.dark #toolbar-topo2-toolbar .tbar-row.right {
+    color: #666;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology-routing.module.ts b/web/gui2/src/main/webapp/app/view/topology/topology-routing.module.ts
new file mode 100644
index 0000000..66e17b6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/topology-routing.module.ts
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { TopologyComponent } from './topology/topology.component';
+
+const topologyRoutes: Routes = [
+    {
+        path: '',
+        component: TopologyComponent
+    },
+];
+
+/**
+ * ONOS GUI -- Topology Tabular View Feature Routing Module - allows it to be lazy loaded
+ *
+ * See https://angular.io/guide/lazy-loading-ngmodules
+ */
+@NgModule({
+    imports: [RouterModule.forChild(topologyRoutes)],
+    exports: [RouterModule]
+})
+export class TopologyRoutingModule { }
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology.common.css b/web/gui2/src/main/webapp/app/view/topology/topology.common.css
new file mode 100644
index 0000000..41b7851
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.common.css
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/**
+ * ONOS GUI -- Topology Common styles -- CSS file
+ */
+.topo2-p div.header {
+    margin-bottom: 10px;
+}
+
+.topo2-p div.header div.icon {
+    vertical-align: middle;
+    display: inline-block;
+}
+.topo2-p div.body {
+    overflow-y: scroll;
+}
+
+.topo2-p div.body::-webkit-scrollbar {
+    display: none;
+}
+
+.topo2-p svg {
+    display: inline-block;
+    width: 26px;
+    height: 26px;
+}
+
+
+.topo2-p h2 {
+    padding: 0 0 0 10px;
+    margin: 0;
+    font-weight: lighter;
+    word-wrap: break-word;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.topo2-p h3 {
+    padding: 0 4px;
+    margin: 0;
+    word-wrap: break-word;
+    top: 20px;
+    left: 50px;
+}
+
+.topo2-p p,
+.topo2-p table {
+    padding: 0;
+    margin: 0;
+    width: 100%;
+}
+
+.topo2-p td {
+    word-wrap: break-word;
+}
+.topo2-p td.label {
+    font-weight: bold;
+    padding: 0 10px 0 0;
+}
+.topo2-p td.value {
+    padding: 0;
+}
+
+#topo2-p-summary  td.label {
+    width: 50%;
+}
+
+#topo2-p-detail  div.actionBtns {
+    padding-top: 6px;
+}
+
+.topo2-p hr {
+    height: 1px;
+    border: 0;
+    margin: 4px -3px;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology.module.ts b/web/gui2/src/main/webapp/app/view/topology/topology.module.ts
new file mode 100644
index 0000000..cc03053
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.module.ts
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { TopologyRoutingModule } from './topology-routing.module';
+import { TopologyComponent } from './topology/topology.component';
+import { NoDeviceConnectedSvgComponent } from './layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component';
+import { LayoutComponent } from './layer/layout/layout.component';
+import { ZoomLayerSvgComponent } from './layer/zoomlayersvg/zoomlayersvg.component';
+import { InstanceComponent } from './panel/instance/instance.component';
+import { SummaryComponent } from './panel/summary/summary.component';
+import { ToolbarComponent } from './panel/toolbar/toolbar.component';
+import { DetailsComponent } from './panel/details/details.component';
+import { Gui2FwLibModule } from 'gui2-fw-lib';
+import { BackgroundSvgComponent } from './layer/backgroundsvg/backgroundsvg.component';
+import { ForceSvgComponent } from './layer/forcesvg/forcesvg.component';
+import { MapSvgComponent } from './layer/mapsvg/mapsvg.component';
+
+/**
+ * ONOS GUI -- Topology View Module
+ *
+ * Note: This has been updated from onos-gui-1.0.0 where it was called 'topo2'
+ * whereas here it is now called 'topology'. This also merges in the old 'topo'
+ */
+@NgModule({
+    imports: [
+        CommonModule,
+        TopologyRoutingModule,
+        Gui2FwLibModule
+    ],
+    declarations: [
+        TopologyComponent,
+        NoDeviceConnectedSvgComponent,
+        LayoutComponent,
+        ZoomLayerSvgComponent,
+        InstanceComponent,
+        SummaryComponent,
+        ToolbarComponent,
+        DetailsComponent,
+        BackgroundSvgComponent,
+        ForceSvgComponent,
+        MapSvgComponent
+    ]
+})
+export class TopologyModule { }
diff --git a/web/gui2/src/main/webapp/tests/app/onos.service.spec.ts b/web/gui2/src/main/webapp/app/view/topology/topology.service.spec.ts
similarity index 72%
copy from web/gui2/src/main/webapp/tests/app/onos.service.spec.ts
copy to web/gui2/src/main/webapp/app/view/topology/topology.service.spec.ts
index 01d5aef..ca8711a 100644
--- a/web/gui2/src/main/webapp/tests/app/onos.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.service.spec.ts
@@ -14,28 +14,26 @@
  * limitations under the License.
  */
 import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../app/log.service';
-import { ConsoleLoggerService } from '../../app/consolelogger.service';
-import { OnosService } from '../../app/onos.service';
+import { LogService, ConsoleLoggerService } from 'gui2-fw-lib';
+import { TopologyService } from './topology.service';
 
 /**
- * ONOS GUI -- Onos Service - Unit Tests
+ * ONOS GUI -- Topology Service - Unit Tests
  */
-describe('OnosService', () => {
+describe('TopologyService', () => {
     let log: LogService;
 
     beforeEach(() => {
         log = new ConsoleLoggerService();
 
         TestBed.configureTestingModule({
-            providers: [OnosService,
+            providers: [TopologyService,
                 { provide: LogService, useValue: log },
             ]
         });
     });
 
-    it('should be created', inject([OnosService], (service: OnosService) => {
+    it('should be created', inject([TopologyService], (service: TopologyService) => {
         expect(service).toBeTruthy();
     }));
 });
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2/src/main/webapp/app/view/topology/topology.service.ts
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to web/gui2/src/main/webapp/app/view/topology/topology.service.ts
index 5307028..b75ed07 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.service.ts
@@ -13,21 +13,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
+import { Injectable } from '@angular/core';
+import {
+    LogService,
+} from 'gui2-fw-lib';
 
-import { LogService } from '../../app/log.service';
 
 /**
- * ONOS GUI -- Log Service - Unit Tests
+ * ONOS GUI -- Topology Service Module.
  */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
+@Injectable()
+export class TopologyService {
 
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+    constructor(
+        protected log: LogService,
+    ) {
+        this.log.debug('Initialized TopologyService');
+    }
+
+    init() {
+
+
+    }
+
+    destroy() {
+
+
+    }
+}
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.css
similarity index 60%
copy from web/gui2/src/main/webapp/tests/app/log.service.spec.ts
copy to web/gui2/src/main/webapp/app/view/topology/topology/topology.component.css
index 5307028..f1cde38 100644
--- a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.css
@@ -13,21 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TestBed, inject } from '@angular/core/testing';
 
-import { LogService } from '../../app/log.service';
 
-/**
- * ONOS GUI -- Log Service - Unit Tests
+/*
+ ONOS GUI -- Topology View (layout) -- CSS file
  */
-describe('LogService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [LogService]
-    });
-  });
-
-  it('should be created', inject([LogService], (service: LogService) => {
-    expect(service).toBeTruthy();
-  }));
-});
+/* --- Base SVG Layer --- */
+#ov-topo2 svg {
+    /* prevents the little cut/copy/paste square that would appear on iPad */
+    -webkit-user-select: none;
+    background-color: #f4f4f4;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
new file mode 100644
index 0000000..7347cb5
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
@@ -0,0 +1,32 @@
+<!--
+~ 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.
+-->
+<onos-flash id="topoMsgFlash" message="{{ flashMsg }}" (closed)="flashMsg = ''"></onos-flash>
+
+<onos-instance #instance></onos-instance>
+<onos-summary #summary></onos-summary>
+<onos-toolbar #toolbar></onos-toolbar>
+<onos-details #details></onos-details>
+
+<div id="ov-topo2">
+    <svg viewBox="0 0 1000 1000" id="topo2"
+        resize offset-height="56" offset-width="12"
+        notifier="notifyResize()">
+        <svg:g onos-nodeviceconnected />
+        <svg:g onos-zoomlayer />
+    </svg>
+</div>
+
+<div id="breadcrumbs"></div>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.spec.ts
new file mode 100644
index 0000000..5933d37
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.spec.ts
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+import { of } from 'rxjs';
+import { HttpClient } from '@angular/common/http';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { TopologyComponent } from './topology.component';
+import { InstanceComponent } from '../panel/instance/instance.component';
+import { SummaryComponent } from '../panel/summary/summary.component';
+import { ToolbarComponent } from '../panel/toolbar/toolbar.component';
+import { DetailsComponent } from '../panel/details/details.component';
+
+import {
+    FlashComponent,
+    FnService,
+    LogService
+} from 'gui2-fw-lib';
+
+
+class MockActivatedRoute extends ActivatedRoute {
+    constructor(params: Params) {
+        super();
+        this.queryParams = of(params);
+    }
+}
+
+class MockHttpClient {}
+
+/**
+ * ONOS GUI -- Topology View -- Unit Tests
+ */
+describe('TopologyComponent', () => {
+    let fs: FnService;
+    let ar: MockActivatedRoute;
+    let windowMock: Window;
+    let logServiceSpy: jasmine.SpyObj<LogService>;
+    let component: TopologyComponent;
+    let fixture: ComponentFixture<TopologyComponent>;
+
+    beforeEach(async(() => {
+        const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+        ar = new MockActivatedRoute({ 'debug': 'txrx' });
+
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
+        TestBed.configureTestingModule({
+            imports: [ BrowserAnimationsModule ],
+            declarations: [
+                TopologyComponent,
+                InstanceComponent,
+                SummaryComponent,
+                ToolbarComponent,
+                DetailsComponent,
+                FlashComponent
+            ],
+            providers: [
+                { provide: FnService, useValue: fs },
+                { provide: LogService, useValue: logSpy },
+                { provide: 'Window', useValue: windowMock },
+                { provide: HttpClient, useClass: MockHttpClient },
+            ]
+        }).compileComponents();
+        logServiceSpy = TestBed.get(LogService);
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(TopologyComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.ts b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.ts
new file mode 100644
index 0000000..5ed744b
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.ts
@@ -0,0 +1,335 @@
+/*
+ * 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.
+ */
+import { Component, OnInit, ViewChild } from '@angular/core';
+import {
+    FnService,
+    KeysService, KeysToken,
+    LogService, PrefsService,
+    SvgUtilService, WebSocketService
+} from 'gui2-fw-lib';
+import {InstanceComponent} from '../panel/instance/instance.component';
+import {SummaryComponent} from '../panel/summary/summary.component';
+import {DetailsComponent} from '../panel/details/details.component';
+
+/**
+ * ONOS GUI Topology View
+ *
+ * This Topology View component is the top level component in a hierarchy that
+ * comprises the whole Topology View
+ *
+ * There are three main parts (panels, graphical and breadcrumbs)
+ * The panel hierarchy
+ * |-- Instances Panel (shows ONOS instances)
+ * |-- Summary Panel (summary of ONOS)
+ * |-- Toolbar Panel (the toolbar)
+ * |-- Details Panel (when a node is selected in the Force graphical view (see below))
+ *
+ * The graphical hierarchy contains
+ * Topology (this)
+ *  |-- No Devices Connected (only of there are no nodes to show)
+ *  |-- Zoom Layer (everything beneath this can be zoomed and panned)
+ *      |-- Background (container for any backgrounds - can be toggled on and off)
+ *          |-- Map
+ *      |-- Forces (all of the nodes and links laid out by a d3.force simulation)
+ *
+ * The breadcrumbs
+ * |-- Breadcrumb (in region view a way of navigating back up through regions)
+ */
+@Component({
+  selector: 'onos-topology',
+  templateUrl: './topology.component.html',
+  styleUrls: ['./topology.component.css']
+})
+export class TopologyComponent implements OnInit {
+    @ViewChild(InstanceComponent) instance: InstanceComponent;
+    @ViewChild(SummaryComponent) summary: SummaryComponent;
+    @ViewChild(DetailsComponent) details: DetailsComponent;
+
+    flashMsg: string = '';
+    prefsState = {};
+    svg: any;
+    hostLabelIdx: number = 1;
+
+    constructor(
+        protected log: LogService,
+        protected fs: FnService,
+        protected ks: KeysService,
+        protected sus: SvgUtilService,
+        protected ps: PrefsService,
+        protected wss: WebSocketService
+    ) {
+
+        this.log.debug('Topology component constructed');
+    }
+
+    ngOnInit() {
+        this.bindCommands();
+        this.log.debug('Topology component initialized');
+    }
+
+    actionMap() {
+        return {
+            L: [() => {this.cycleDeviceLabels(); }, 'Cycle device labels'],
+            B: [(token) => {this.toggleBackground(token); }, 'Toggle background'],
+            D: [(token) => {this.toggleDetails(token); }, 'Toggle details panel'],
+            I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'],
+            O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'],
+            R: [() => {this.resetZoom(); }, 'Reset pan / zoom'],
+            P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'],
+            E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'],
+            X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'],
+            U: [() => {this.unpinNode(); }, 'Unpin node (mouse over)'],
+            H: [() => {this.toggleHosts(); }, 'Toggle host visibility'],
+            M: [() => {this.toggleOfflineDevices(); }, 'Toggle offline visibility'],
+            dot: [() => {this.toggleToolbar(); }, 'Toggle Toolbar'],
+            'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'],
+
+            // -- instance color palette debug
+            9: function () {
+                this.sus.cat7().testCard(this.svg);
+            },
+
+            esc: this.handleEscape,
+
+            // TODO update after adding in Background Service
+            // 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: [
+                ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B'],
+                ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', 'E', 'dot'],
+                [], // this column reserved for overlay actions
+            ],
+        };
+    }
+
+
+    bindCommands(additional?: any) {
+
+        const am = this.actionMap();
+        const add = this.fs.isO(additional);
+
+        // TODO: Reimplement when we have a use case
+        // if (add) {
+        //     _.each(add, function (value, key) {
+        //         // filter out meta properties (e.g. _keyOrder)
+        //         if (!(_.startsWith(key, '_'))) {
+        //             // don't allow re-definition of existing key bindings
+        //             if (am[key]) {
+        //                 this.log.warn('keybind: ' + key + ' already exists');
+        //             } else {
+        //                 am[key] = [value.cb, value.tt];
+        //             }
+        //         }
+        //     });
+        // }
+
+        this.ks.keyBindings(am);
+
+        this.ks.gestureNotes([
+            ['click', 'Select the item and show details'],
+            ['shift-click', 'Toggle selection state'],
+            ['drag', 'Reposition (and pin) device / host'],
+            ['cmd-scroll', 'Zoom in / out'],
+            ['cmd-drag', 'Pan'],
+        ]);
+    }
+
+    handleEscape() {
+
+        if (false) {
+            // TODO: Cancel show mastership
+            // TODO: Cancel Active overlay
+            // TODO: Reinstate with components
+        } else {
+            this.log.debug('Handling escape');
+            // } else if (t2rs.deselectAllNodes()) {
+            //     // else if we have node selections, deselect them all
+            //     // (work already done)
+            // } else if (t2rs.deselectLink()) {
+            //     // else if we have a link selection, deselect it
+            //     // (work already done)
+            // } else if (t2is.isVisible()) {
+            //     // If the instance panel is visible, close it
+            //     t2is.toggle();
+            // } else if (t2sp.isVisible()) {
+            //     // If the summary panel is visible, close it
+            //     t2sp.toggle();
+        }
+    }
+
+
+
+    updatePrefsState(what, b) {
+        this.prefsState[what] = b ? 1 : 0;
+        this.ps.setPrefs('topo2_prefs', this.prefsState);
+    }
+
+    deviceLabelFlashMessage(index) {
+        switch (index) {
+            case 0: return 'Hide device labels';
+            case 1: return 'Show friendly device labels';
+            case 2: return 'Show device ID labels';
+        }
+    }
+
+    hostLabelFlashMessage(index) {
+        switch (index) {
+            case 0: return 'Hide host labels';
+            case 1: return 'Show friendly host labels';
+            case 2: return 'Show host IP labels';
+            case 3: return 'Show host MAC Address labels';
+        }
+    }
+
+    protected cycleDeviceLabels() {
+        this.log.debug('Cycling device labels');
+        // TODO: Reinstate with components
+        // let deviceLabelIndex = t2ps.get('dlbls') + 1;
+        // let newDeviceLabelIndex = deviceLabelIndex % 3;
+        //
+        // t2ps.set('dlbls', newDeviceLabelIndex);
+        // t2fs.updateNodes();
+        // flash.flash(deviceLabelFlashMessage(newDeviceLabelIndex));
+    }
+
+    protected cycleHostLabels() {
+        const hostLabelIndex = this.hostLabelIdx + 1;
+        this.hostLabelIdx = hostLabelIndex % 4;
+        this.flashMsg = this.hostLabelFlashMessage(this.hostLabelIdx);
+        this.log.debug('Cycling host labels');
+        // TODO: Reinstate with components
+        // t2ps.set('hlbls', newHostLabelIndex);
+        // t2fs.updateNodes();
+    }
+
+    protected toggleBackground(token: KeysToken) {
+        this.flashMsg = 'Toggling background';
+        this.log.debug('Toggling background', token);
+        // TODO: Reinstate with components
+        // t2bgs.toggle(x);
+    }
+
+    protected toggleDetails(token: KeysToken) {
+        this.flashMsg = 'Toggling details';
+        this.details.togglePanel(() => {});
+        this.log.debug('Toggling details', token);
+    }
+
+    protected toggleInstancePanel(token: KeysToken) {
+        this.flashMsg = 'Toggling instances';
+        this.instance.togglePanel(() => {});
+        this.log.debug('Toggling instances', token);
+        // TODO: Reinstate with components
+        // this.updatePrefsState('insts', t2is.toggle(x));
+    }
+
+    protected toggleSummary() {
+        this.flashMsg = 'Toggling summary';
+        this.summary.togglePanel(() => {});
+    }
+
+    protected resetZoom() {
+        this.log.debug('resetting zoom');
+        // TODO: Reinstate with components
+        // t2bgs.resetZoom();
+        // flash.flash('Pan and zoom reset');
+    }
+
+    protected togglePorts(token: KeysToken) {
+        this.log.debug('Toggling ports');
+        // TODO: Reinstate with components
+        // this.updatePrefsState('porthl', t2vs.togglePortHighlights(x));
+        // t2fs.updateLinks();
+    }
+
+    protected equalizeMasters() {
+        this.wss.sendEvent('equalizeMasters', null);
+
+        this.log.debug('equalizing masters');
+        // TODO: Reinstate with components
+        // flash.flash('Equalizing master roles');
+    }
+
+    protected resetNodeLocation() {
+        this.log.debug('resetting node location');
+        // TODO: Reinstate with components
+        // t2fs.resetNodeLocation();
+        // flash.flash('Reset node locations');
+    }
+
+    protected unpinNode() {
+        this.log.debug('unpinning node');
+        // TODO: Reinstate with components
+        // t2fs.unpin();
+        // flash.flash('Unpin node');
+    }
+
+    protected toggleToolbar() {
+        this.log.debug('toggling toolbar');
+        // TODO: Reinstate with components
+        // t2tbs.toggle();
+    }
+
+    protected actionedFlashed(action, message) {
+        this.log.debug('action flashed');
+        // TODO: Reinstate with components
+        // this.flash.flash(action + ' ' + message);
+    }
+
+    protected toggleHosts() {
+        // this.flashMsg = on ? 'Show': 'Hide', 'Hosts';
+        this.log.debug('toggling hosts');
+        // TODO: Reinstate with components
+        // let on = t2rs.toggleHosts();
+        // this.actionedFlashed(on ? 'Show': 'Hide', 'Hosts');
+    }
+
+    protected toggleOfflineDevices() {
+        this.log.debug('toggling offline devices');
+        // TODO: Reinstate with components
+        // let on = t2rs.toggleOfflineDevices();
+        // this.actionedFlashed(on ? 'Show': 'Hide', 'offline devices');
+    }
+
+    protected notValid(what) {
+        this.log.warn('topo.js getActionEntry(): Not a valid ' + what);
+    }
+
+    getActionEntry(key) {
+        let entry;
+
+        if (!key) {
+            this.notValid('key');
+            return null;
+        }
+
+        entry = this.actionMap()[key];
+
+        if (!entry) {
+            this.notValid('actionMap (' + key + ') entry');
+            return null;
+        }
+        return this.fs.isA(entry) || [entry, ''];
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/editabletext.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/editabletext.service.spec.ts
deleted file mode 100644
index 05663c7..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/layer/editabletext.service.spec.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { EditableTextService } from '../../../../app/fw/layer/editabletext.service';
-import { KeyService } from '../../../../app/fw/util/key.service';
-import { WebSocketService } from '../../../../app/fw/remote/websocket.service';
-
-class MockKeyService {}
-
-class MockWebSocketService {}
-
-/**
- * ONOS GUI -- Layer -- Editable Text Service - Unit Tests
- */
-describe('EditableTextService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [EditableTextService,
-                { provide: LogService, useValue: log },
-                { provide: KeyService, useClass: MockKeyService },
-                { provide: WebSocketService, useClass: MockWebSocketService },
-            ]
-        });
-    });
-
-    it('should be created', inject([EditableTextService], (service: EditableTextService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/quickhelp.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/quickhelp.service.spec.ts
deleted file mode 100644
index fa8f8ea..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/layer/quickhelp.service.spec.ts
+++ /dev/null
@@ -1,57 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { QuickHelpService } from '../../../../app/fw/layer/quickhelp.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { LionService } from '../../../../app/fw/util/lion.service';
-import { LoadingService } from '../../../../app/fw/layer/loading.service';
-import { SvgUtilService } from '../../../../app/fw/svg/svgutil.service';
-
-class MockFnService {}
-
-class MockLionService {}
-
-class MockLoadingService {}
-
-class MockSvgUtilService {}
-
-/**
- * ONOS GUI -- Layer -- Quick Help Service - Unit Tests
- */
-describe('QuickHelpService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [QuickHelpService,
-                { provide: LogService, useValue: log },
-                { provide: FnService, useClass: MockFnService },
-                { provide: LionService, useClass: MockLionService },
-                { provide: LoadingService, useClass: MockLoadingService },
-                { provide: SvgUtilService, useClass: MockSvgUtilService },
-            ]
-        });
-    });
-
-    it('should be created', inject([QuickHelpService], (service: QuickHelpService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/remote/rest.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/remote/rest.service.spec.ts
deleted file mode 100644
index 45576f6..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/remote/rest.service.spec.ts
+++ /dev/null
@@ -1,49 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { RestService } from '../../../../app/fw/remote/rest.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { UrlFnService } from '../../../../app/fw/remote/urlfn.service';
-
-class MockFnService {}
-
-class MockUrlFnService {}
-
-/**
- * ONOS GUI -- Remote -- REST Service - Unit Tests
- */
-describe('RestService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [RestService,
-                { provide: FnService, useClass: MockFnService },
-                { provide: LogService, useValue: log },
-                { provide: UrlFnService, useClass: MockUrlFnService },
-            ]
-        });
-    });
-
-    it('should be created', inject([RestService], (service: RestService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/geodata.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/geodata.service.spec.ts
deleted file mode 100644
index 3057897..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/geodata.service.spec.ts
+++ /dev/null
@@ -1,45 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { GeoDataService } from '../../../../app/fw/svg/geodata.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-
-class MockFnService {}
-
-/**
- * ONOS GUI -- SVG -- GeoData Service - Unit Tests
- */
-describe('GeoDataService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [GeoDataService,
-                { provide: FnService, useClass: MockFnService },
-                { provide: LogService, useValue: log },
-            ]
-        });
-    });
-
-    it('should be created', inject([GeoDataService], (service: GeoDataService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/map.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/map.service.spec.ts
deleted file mode 100644
index 347db99..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/map.service.spec.ts
+++ /dev/null
@@ -1,45 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { MapService } from '../../../../app/fw/svg/map.service';
-import { GlyphDataService } from '../../../../app/fw/svg/glyphdata.service';
-
-class MockGlyphDataService {}
-
-/**
- * ONOS GUI -- SVG -- Map Service - Unit Tests
- */
-describe('MapService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [MapService,
-                { provide: LogService, useValue: log },
-                { provide: GlyphDataService, useClass: MockGlyphDataService },
-            ]
-        });
-    });
-
-    it('should be created', inject([MapService], (service: MapService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/sprite.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/sprite.service.spec.ts
deleted file mode 100644
index 9c352c9..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/sprite.service.spec.ts
+++ /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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { SpriteService } from '../../../../app/fw/svg/sprite.service';
-
-/**
- * ONOS GUI -- SVG -- Sprite Service - Unit Tests
- */
-describe('SpriteService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [SpriteService,
-                { provide: LogService, useValue: log },
-            ]
-        });
-    });
-
-    it('should be created', inject([SpriteService], (service: SpriteService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/spritedata.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/spritedata.service.spec.ts
deleted file mode 100644
index 0e20c85..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/spritedata.service.spec.ts
+++ /dev/null
@@ -1,41 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { SpriteDataService } from '../../../../app/fw/svg/spritedata.service';
-
-/**
- * ONOS GUI -- SVG -- Sprite Data Service - Unit Tests
- */
-describe('SpriteDataService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [SpriteDataService,
-                { provide: LogService, useValue: log },
-            ]
-        });
-    });
-
-    it('should be created', inject([SpriteDataService], (service: SpriteDataService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/zoom.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/zoom.service.spec.ts
deleted file mode 100644
index 360ff41..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/svg/zoom.service.spec.ts
+++ /dev/null
@@ -1,41 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { ZoomService } from '../../../../app/fw/svg/zoom.service';
-
-/**
- * ONOS GUI -- SVG -- Zoom Service - Unit Tests
- */
-describe('ZoomService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [ZoomService,
-                { provide: LogService, useValue: log },
-            ]
-        });
-    });
-
-    it('should be created', inject([ZoomService], (service: ZoomService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/ee.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/ee.service.spec.ts
deleted file mode 100644
index 90c00d0..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/util/ee.service.spec.ts
+++ /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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { EeService } from '../../../../app/fw/util/ee.service';
-
-/**
- * ONOS GUI -- Util -- EE functions - Unit Tests
- */
-describe('EeService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [EeService,
-                { provide: LogService, useValue: log },
-            ]
-        });
-    });
-
-    it('should be created', inject([EeService], (service: EeService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/key.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/key.service.spec.ts
deleted file mode 100644
index 7ceadb8..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/util/key.service.spec.ts
+++ /dev/null
@@ -1,45 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { KeyService } from '../../../../app/fw/util/key.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-
-class MockFnService {}
-
-/**
- * ONOS GUI -- Key Handler Service - Unit Tests
- */
-describe('KeyService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [KeyService,
-                { provide: LogService, useValue: log },
-                { provide: FnService, useClass: MockFnService },
-            ]
-        });
-    });
-
-    it('should be created', inject([KeyService], (service: KeyService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/random.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/random.service.spec.ts
deleted file mode 100644
index 726fc92..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/util/random.service.spec.ts
+++ /dev/null
@@ -1,45 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { RandomService } from '../../../../app/fw/util/random.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-
-class MockFnService {}
-
-/**
- * ONOS GUI -- Random -- Encapsulated randomness - Unit Tests
- */
-describe('RandomService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [RandomService,
-                { provide: LogService, useValue: log },
-                { provide: FnService, useClass: MockFnService },
-            ]
-        });
-    });
-
-    it('should be created', inject([RandomService], (service: RandomService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/button.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/button.service.spec.ts
deleted file mode 100644
index c3e501d..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/widget/button.service.spec.ts
+++ /dev/null
@@ -1,49 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { ButtonService } from '../../../../app/fw/widget/button.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { IconService } from '../../../../app/fw/svg/icon.service';
-
-class MockIconService {}
-
-class MockFnService {}
-
-/**
- * ONOS GUI -- Widget -- Button Service - Unit Tests
- */
-describe('ButtonService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [ButtonService,
-                { provide: LogService, useValue: log },
-                { provide: IconService, useClass: MockIconService },
-                { provide: FnService, useClass: MockFnService },
-            ]
-        });
-    });
-
-    it('should be created', inject([ButtonService], (service: ButtonService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/chartbuilder.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/chartbuilder.service.spec.ts
deleted file mode 100644
index dbb806d..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/widget/chartbuilder.service.spec.ts
+++ /dev/null
@@ -1,53 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { ChartBuilderService } from '../../../../app/fw/widget/chartbuilder.service';
-import { LoadingService } from '../../../../app/fw/layer/loading.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { WebSocketService } from '../../../../app/fw/remote/websocket.service';
-
-class MockFnService {}
-
-class MockLoadingService {}
-
-class MockWebSocketService {}
-
-/**
- * ONOS GUI -- Widget -- Chart Builder Service - Unit Tests
- */
-describe('ChartBuilderService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [ChartBuilderService,
-                { provide: LogService, useValue: log },
-                { provide: FnService, useClass: MockFnService },
-                { provide: LoadingService, useClass: MockLoadingService },
-                { provide: WebSocketService, useClass: MockWebSocketService },
-            ]
-        });
-    });
-
-    it('should be created', inject([ChartBuilderService], (service: ChartBuilderService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/list.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/list.service.spec.ts
deleted file mode 100644
index 7380270..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/widget/list.service.spec.ts
+++ /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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { ListService } from '../../../../app/fw/widget/list.service';
-
-/**
- * ONOS GUI -- Widget -- List Service - Unit Tests
- */
-describe('ListService', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [ListService,
-                { provide: LogService, useValue: log },
-            ]
-        });
-    });
-
-    it('should be created', inject([ListService], (service: ListService) => {
-        expect(service).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/sortableheader.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/sortableheader.directive.spec.ts
deleted file mode 100644
index 993430b..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/widget/sortableheader.directive.spec.ts
+++ /dev/null
@@ -1,57 +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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { SortableHeaderDirective } from '../../../../app/fw/widget/sortableheader.directive';
-import { IconService } from '../../../../app/fw/svg/icon.service';
-import { GlyphService } from '../../../../app/fw/svg/glyph.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-
-class MockFnService {}
-
-class MockGlyphService {}
-
-class MockIconService {}
-
-/**
- * ONOS GUI -- Widget -- Table Sortable Header Directive - Unit Tests
- */
-describe('SortableHeaderDirective', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [ SortableHeaderDirective,
-                { provide: FnService, useClass: MockFnService },
-                { provide: LogService, useValue: log },
-                { provide: GlyphService, useClass: MockGlyphService },
-                { provide: IconService, useClass: MockIconService },
-            ]
-        });
-    });
-
-    afterEach(() => {
-        log = null;
-    });
-
-    it('should create an instance', inject([SortableHeaderDirective], (directive: SortableHeaderDirective) => {
-        expect(directive).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/tableresize.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/tableresize.directive.spec.ts
deleted file mode 100644
index 3fa6fe0..0000000
--- a/web/gui2/src/main/webapp/tests/app/fw/widget/tableresize.directive.spec.ts
+++ /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.
- */
-import { TestBed, inject } from '@angular/core/testing';
-
-import { TableResizeDirective } from '../../../../app/fw/widget/tableresize.directive';
-import { LogService } from '../../../../app/log.service';
-import { ConsoleLoggerService } from '../../../../app/consolelogger.service';
-import { FnService } from '../../../../app/fw/util/fn.service';
-import { MastService } from '../../../../app/fw/mast/mast.service';
-
-class MockFnService {}
-
-class MockMastService {}
-
-/**
- * ONOS GUI -- Widget -- Table Resize Directive - Unit Tests
- */
-describe('TableResizeDirective', () => {
-    let log: LogService;
-
-    beforeEach(() => {
-        log = new ConsoleLoggerService();
-
-        TestBed.configureTestingModule({
-            providers: [ TableResizeDirective,
-                { provide: FnService, useClass: MockFnService },
-                { provide: LogService, useValue: log },
-                { provide: MastService, useClass: MockMastService },
-            ]
-        });
-    });
-
-    afterEach(() => {
-        log = null;
-    });
-
-    it('should create an instance', inject([TableResizeDirective], (directive: TableResizeDirective) => {
-        expect(directive).toBeTruthy();
-    }));
-});
diff --git a/web/gui2/src/main/webapp/tests/app/onos.component.spec.ts b/web/gui2/src/main/webapp/tests/app/onos.component.spec.ts
deleted file mode 100644
index c03f680..0000000
--- a/web/gui2/src/main/webapp/tests/app/onos.component.spec.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.
- */
-import { TestBed, async } from '@angular/core/testing';
-import { RouterModule, RouterOutlet, ChildrenOutletContexts, ActivatedRoute, Params } from '@angular/router';
-import { of } from 'rxjs';
-
-import { LogService } from '../../app/log.service';
-import { ConsoleLoggerService } from '../../app/consolelogger.service';
-
-import { IconComponent } from '../../app/fw/svg/icon/icon.component';
-import { MastComponent } from '../../app/fw/mast/mast/mast.component';
-import { NavComponent } from '../../app/fw/nav/nav/nav.component';
-import { OnosComponent } from '../../app/onos.component';
-import { VeilComponent } from '../../app/fw/layer/veil/veil.component';
-
-import { DialogService } from '../../app/fw/layer/dialog.service';
-import { EeService } from '../../app/fw/util/ee.service';
-import { FnService } from '../../app/fw/util/fn.service';
-import { GlyphService } from '../../app/fw/svg/glyph.service';
-import { IconService } from '../../app/fw/svg/icon.service';
-import { KeyService } from '../../app/fw/util/key.service';
-import { LionService } from '../../app/fw/util/lion.service';
-import { NavService } from '../../app/fw/nav/nav.service';
-import { OnosService } from '../../app/onos.service';
-import { QuickHelpService } from '../../app/fw/layer/quickhelp.service';
-import { SvgUtilService } from '../../app/fw/svg/svgutil.service';
-import { ThemeService } from '../../app/fw/util/theme.service';
-import { SpriteService } from '../../app/fw/svg/sprite.service';
-import { WebSocketService, WsOptions } from '../../app/fw/remote/websocket.service';
-
-class MockActivatedRoute extends ActivatedRoute {
-    constructor(params: Params) {
-        super();
-        this.queryParams = of(params);
-    }
-}
-
-class MockDialogService {}
-
-class MockEeService {}
-
-class MockGlyphService {}
-
-class MockIconService {}
-
-class MockKeyService {}
-
-class MockLionService {}
-
-class MockNavService {}
-
-class MockOnosService {}
-
-class MockQuickHelpService {}
-
-class MockSpriteService {}
-
-class MockThemeService {}
-
-class MockVeilComponent {}
-
-class MockWebSocketService {
-    createWebSocket() {}
-    isConnected() { return false; }
-}
-
-/**
- * ONOS GUI -- Onos Component - Unit Tests
- */
-describe('OnosComponent', () => {
-    let log: LogService;
-    let fs: FnService;
-    let ar: MockActivatedRoute;
-    let windowMock: Window;
-    let fixture;
-    let app;
-
-    beforeEach(async(() => {
-        log = new ConsoleLoggerService();
-        ar = new MockActivatedRoute({'debug': 'TestService'});
-
-        windowMock = <any>{
-            location: <any> {
-                hostname: '',
-                host: '',
-                port: '',
-                protocol: '',
-                search: { debug: 'true'},
-                href: ''
-            },
-            innerHeight: 240,
-            innerWidth: 320
-        };
-        fs = new FnService(ar, log, windowMock);
-
-        TestBed.configureTestingModule({
-            declarations: [
-                IconComponent,
-                MastComponent,
-                NavComponent,
-                OnosComponent,
-                VeilComponent,
-                RouterOutlet
-            ],
-            providers: [
-                { provide: ChildrenOutletContexts, useClass: ChildrenOutletContexts },
-                { provide: DialogService, useClass: MockDialogService },
-                { provide: EeService, useClass: MockEeService },
-                { provide: FnService, useValue: fs },
-                { provide: GlyphService, useClass: MockGlyphService },
-                { provide: IconService, useClass: MockIconService },
-                { provide: KeyService, useClass: MockKeyService },
-                { provide: LionService, useClass: MockLionService },
-                { provide: LogService, useValue: log },
-                { provide: NavService, useClass: MockNavService },
-                { provide: OnosService, useClass: MockOnosService },
-                { provide: QuickHelpService, useClass: MockQuickHelpService },
-                { provide: SpriteService, useClass: MockSpriteService },
-                { provide: ThemeService, useClass: MockThemeService },
-                { provide: WebSocketService, useClass: MockWebSocketService },
-                { provide: Window, useFactory: (() => windowMock ) },
-            ]
-        }).compileComponents();
-
-        fixture = TestBed.createComponent(OnosComponent);
-        app = fixture.componentInstance;
-    }));
-
-    it('should create the app', async(() => {
-        expect(app).toBeTruthy();
-    }));
-
-//    it(`should have as title 'onos'`, async(() => {
-//        const fixture = TestBed.createComponent(OnosComponent);
-//        const app = fixture.componentInstance;
-//        expect(app.title).toEqual('onos');
-//    }));
-});