ONOS-4713, ONOS-4715 issues merge to master

Change-Id: I3e52af949005529cec18a85e49601c47f7e386f8
diff --git a/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/SfcFlowRuleInstallerService.java b/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/SfcFlowRuleInstallerService.java
index caff305..e76a578 100644
--- a/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/SfcFlowRuleInstallerService.java
+++ b/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/SfcFlowRuleInstallerService.java
@@ -64,4 +64,15 @@
      */
     ConnectPoint unInstallLoadBalancedFlowRules(PortChain portChain, FiveTuple fiveTuple,
             NshServicePathId nshSpiId);
+
+    /**
+     * Uninstall load balanced classifier rules.
+     *
+     * @param portChain port-chain
+     * @param fiveTuple five tuple packet information
+     * @param nshSpiId service path index identifier
+     * @return connectPoint the network identifier
+     */
+    ConnectPoint unInstallLoadBalancedClassifierRules(PortChain portChain, FiveTuple fiveTuple,
+            NshServicePathId nshSpiId);
 }
diff --git a/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/impl/SfcFlowRuleInstallerImpl.java b/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/impl/SfcFlowRuleInstallerImpl.java
index 71397a7..59329c4 100644
--- a/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/impl/SfcFlowRuleInstallerImpl.java
+++ b/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/installer/impl/SfcFlowRuleInstallerImpl.java
@@ -218,6 +218,20 @@
         return installSfcFlowRules(portChain, fiveTuple, nshSpiId, Objective.Operation.REMOVE);
     }
 
+    @Override
+    public ConnectPoint unInstallLoadBalancedClassifierRules(PortChain portChain, FiveTuple fiveTuple,
+            NshServicePathId nshSpiId) {
+        checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
+
+        List<PortPairId> portPairs = portChain.getLoadBalancePath(fiveTuple);
+        // Get the first port pair
+        ListIterator<PortPairId> portPairListIterator = portPairs.listIterator();
+        PortPairId portPairId = portPairListIterator.next();
+        PortPair portPair = portPairService.getPortPair(portPairId);
+
+        return installSfcClassifierRules(portChain, portPair, nshSpiId, fiveTuple, Objective.Operation.REMOVE);
+    }
+
     public ConnectPoint installSfcFlowRules(PortChain portChain, FiveTuple fiveTuple, NshServicePathId nshSpiId,
             Objective.Operation type) {
         checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
@@ -634,7 +648,10 @@
                 treatment.extension(tunnelDsttreatment, deviceId);
                 treatment.transition(TUNNEL_SEND_TABLE);
                 sendSfcRule(selector, treatment, deviceId, type, flowClassifier.priority());
-                classifierList.add(deviceIdfromPortPair);
+
+                selector.matchInPort(PortNumber.CONTROLLER);
+                sendSfcRule(selector, treatment, deviceId, type, flowClassifier.priority());
+                classifierList.add(deviceId);
 
                 installSfcTunnelSendRule(deviceId, nshSpiId, type);
                 installSfcTunnelReceiveRule(deviceIdfromPortPair, nshSpiId, type);
@@ -646,6 +663,9 @@
                                                                              nshSpiId, flowClassifier);
                 treatment.transition(ENCAP_OUTPUT_TABLE);
                 sendSfcRule(selector, treatment, deviceIdfromPortPair, type, flowClassifier.priority());
+
+                selector.matchInPort(PortNumber.CONTROLLER);
+                sendSfcRule(selector, treatment, deviceId, type, flowClassifier.priority());
                 classifierList.add(deviceIdfromPortPair);
             }
         }
diff --git a/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/manager/impl/SfcManager.java b/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/manager/impl/SfcManager.java
index 3292e23..171195e 100644
--- a/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/manager/impl/SfcManager.java
+++ b/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/manager/impl/SfcManager.java
@@ -316,13 +316,15 @@
         Set<FiveTuple> fiveTupleSet = portChain.getLoadBalanceIdMapKeys();
         for (FiveTuple fiveTuple : fiveTupleSet) {
             id = portChain.getLoadBalanceId(fiveTuple);
+            nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
             if (processedIdList.contains(id)) {
-                // multiple five tuple can have single path.
+                // Multiple five tuple can have single path. In this case only
+                // the classifier rule need to delete
+                flowRuleInstaller.unInstallLoadBalancedClassifierRules(portChain, fiveTuple, nshSpi);
                 continue;
             } else {
                 processedIdList.add(id);
             }
-            nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
             flowRuleInstaller.unInstallLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
         }
 
@@ -507,6 +509,7 @@
             int portDst = 0;
             byte protocol = 0;
             MacAddress macSrc = packet.getSourceMAC();
+            MacAddress macDst = packet.getDestinationMAC();
             TenantId tenantId = getTenantId(macSrc);
 
             if (ethType == Ethernet.TYPE_IPV4) {
@@ -539,6 +542,8 @@
                     .setPortDst(PortNumber.portNumber(portDst))
                     .setProtocol(protocol)
                     .setTenantId(tenantId)
+                    .setMacSrc(macSrc)
+                    .setMacDst(macDst)
                     .build();
 
             PortChainId portChainId = findPortChainFromFiveTuple(fiveTuple);
@@ -577,13 +582,12 @@
          * Send packet back to classifier.
          *
          * @param context packet context
-         * @param connectPoint connect point of first service function
          */
         private void sendPacket(PacketContext context) {
 
             ConnectPoint sourcePoint = context.inPacket().receivedFrom();
 
-            TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(sourcePoint.port()).build();
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(PortNumber.TABLE).build();
             OutboundPacket packet = new DefaultOutboundPacket(sourcePoint.deviceId(), treatment, context.inPacket()
                     .unparsed());
             packetService.emit(packet);
diff --git a/apps/vtn/sfcmgr/src/test/java/org/onosproject/sfc/util/VirtualPortAdapter.java b/apps/vtn/sfcmgr/src/test/java/org/onosproject/sfc/util/VirtualPortAdapter.java
index cc2c265..e51c699 100644
--- a/apps/vtn/sfcmgr/src/test/java/org/onosproject/sfc/util/VirtualPortAdapter.java
+++ b/apps/vtn/sfcmgr/src/test/java/org/onosproject/sfc/util/VirtualPortAdapter.java
@@ -16,16 +16,17 @@
 package org.onosproject.sfc.util;
 
 import java.util.Collection;
-import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
 import org.onosproject.vtnrsc.FixedIp;
 import org.onosproject.vtnrsc.TenantId;
+import org.onosproject.vtnrsc.TenantNetworkId;
 import org.onosproject.vtnrsc.VirtualPort;
 import org.onosproject.vtnrsc.VirtualPortId;
-import org.onosproject.vtnrsc.TenantNetworkId;
+import org.onosproject.vtnrsc.virtualport.VirtualPortListener;
 import org.onosproject.vtnrsc.virtualport.VirtualPortService;
 
 /**
@@ -95,4 +96,12 @@
     public boolean removePorts(Iterable<VirtualPortId> vPortIds) {
         return true;
     }
+
+    @Override
+    public void addListener(VirtualPortListener listener) {
+    }
+
+    @Override
+    public void removeListener(VirtualPortListener listener) {
+    }
 }
diff --git a/apps/vtn/sfcweb/pom.xml b/apps/vtn/sfcweb/pom.xml
index e89a2e1..79bce92 100755
--- a/apps/vtn/sfcweb/pom.xml
+++ b/apps/vtn/sfcweb/pom.xml
@@ -53,6 +53,11 @@
             <artifactId>onos-app-vtn-rsc</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcLink.java b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcLink.java
new file mode 100644
index 0000000..3936633
--- /dev/null
+++ b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcLink.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.sfcweb;
+
+import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
+import org.onosproject.ui.topo.BiLink;
+import org.onosproject.ui.topo.LinkHighlight;
+import org.onosproject.ui.topo.LinkHighlight.Flavor;
+
+/**
+ * Bi-directional link capable of different highlights.
+ */
+public class SfcLink extends BiLink {
+
+    private boolean primary = false;
+    private boolean secondary = false;
+
+    public SfcLink(LinkKey key, Link link) {
+        super(key, link);
+    }
+
+    @Override
+    public LinkHighlight highlight(Enum<?> anEnum) {
+        Flavor flavor = primary ? Flavor.PRIMARY_HIGHLIGHT :
+            (secondary ? Flavor.SECONDARY_HIGHLIGHT : Flavor.NO_HIGHLIGHT);
+        return new LinkHighlight(this.linkId(), Flavor.PRIMARY_HIGHLIGHT);
+    }
+}
diff --git a/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcLinkMap.java b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcLinkMap.java
new file mode 100644
index 0000000..03c9c3d
--- /dev/null
+++ b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcLinkMap.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.sfcweb;
+
+import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
+import org.onosproject.ui.topo.BiLinkMap;
+
+/**
+ * Sfc concrete link map.
+ */
+public class SfcLinkMap extends BiLinkMap<SfcLink> {
+    @Override
+    protected SfcLink create(LinkKey linkKey, Link link) {
+        return new SfcLink(linkKey, link);
+    }
+}
diff --git a/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovMessageHandler.java b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovMessageHandler.java
index df541b3..8319137 100644
--- a/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovMessageHandler.java
+++ b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovMessageHandler.java
@@ -15,50 +15,53 @@
  */
 package org.onosproject.sfcweb;
 
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.TimerTask;
+
+import jersey.repackaged.com.google.common.collect.Lists;
+
 import org.onlab.osgi.DefaultServiceDirectory;
 import org.onlab.osgi.ServiceDirectory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.google.common.collect.ImmutableSet;
-
 import org.onlab.packet.MacAddress;
-import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.Element;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
 import org.onosproject.net.Link;
-import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.link.LinkService;
-import org.onosproject.ui.topo.HostHighlight;
 import org.onosproject.ui.RequestHandler;
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.topo.DeviceHighlight;
 import org.onosproject.ui.topo.Highlights;
+import org.onosproject.ui.topo.HostHighlight;
 import org.onosproject.ui.topo.NodeBadge;
 import org.onosproject.ui.topo.TopoJson;
-import org.onosproject.ui.topo.DeviceHighlight;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.onosproject.vtnrsc.FiveTuple;
+import org.onosproject.vtnrsc.LoadBalanceId;
 import org.onosproject.vtnrsc.PortChain;
-import org.onosproject.vtnrsc.portchain.PortChainService;
-import org.onosproject.vtnrsc.portpair.PortPairService;
 import org.onosproject.vtnrsc.PortChainId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
 import org.onosproject.vtnrsc.PortPair;
 import org.onosproject.vtnrsc.PortPairId;
+import org.onosproject.vtnrsc.VirtualPort;
 import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.portchain.PortChainService;
+import org.onosproject.vtnrsc.portpair.PortPairService;
+import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
 import org.onosproject.vtnrsc.service.VtnRscService;
 import org.onosproject.vtnrsc.virtualport.VirtualPortService;
-import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
-import org.onosproject.vtnrsc.PortPairGroupId;
-import org.onosproject.vtnrsc.PortPairGroup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import java.util.Collection;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.List;
-import java.util.ListIterator;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * SFC web gui topology-overlay message handler.
@@ -69,32 +72,27 @@
     private static final String SAMPLE_TOPOV_DISPLAY_SFC = "showSfcInfo";
     private static final String SAMPLE_TOPOV_DISPLAY_STOP = "sfcTopovClear";
     private static final String CONFIG_SFP_MSG = "configSfpMessage";
-
+    private static final String SAMPLE_TOPOV_SHOW_SFC_PATH = "showSfcPath";
     private static final String ID = "id";
     private static final String MODE = "mode";
-    private static final String SFC_ID   = "SFC";
-
-    private static final long UPDATE_PERIOD_MS = 1000;
+    private static final String CLASSIFIER = "CLS";
+    private static final String FORWARDER = "SFF";
 
     private static final Link[] EMPTY_LINK_SET = new Link[0];
 
-    private enum Mode { IDLE, MOUSE, LINK }
+    private enum Mode {
+        IDLE, MOUSE, LINK
+    }
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
-    private DeviceService deviceService;
     private HostService hostService;
     private LinkService linkService;
-
-    private final Timer timer = new Timer("sfcweb-overlay");
     private TimerTask demoTask = null;
     private Mode currentMode = Mode.IDLE;
     private Element elementOfNote;
     private Link[] linkSet = EMPTY_LINK_SET;
-    private int linkIndex;
 
-    private long someNumber = 1;
-    private long someIncrement = 1;
     protected PortPairService portPairService;
     protected VtnRscService vtnRscService;
     protected VirtualPortService virtualPortService;
@@ -104,7 +102,6 @@
     @Override
     public void init(UiConnection connection, ServiceDirectory directory) {
         super.init(connection, directory);
-        deviceService = directory.get(DeviceService.class);
         hostService = directory.get(HostService.class);
         linkService = directory.get(LinkService.class);
         portChainService = directory.get(PortChainService.class);
@@ -172,7 +169,10 @@
             vtnRscService = serviceDirectory.get(VtnRscService.class);
             virtualPortService = serviceDirectory.get(VirtualPortService.class);
 
+            List<String> sfcPathList = Lists.newArrayList();
+
             Highlights highlights = new Highlights();
+            SfcLinkMap linkMap = new SfcLinkMap();
 
             PortChainId portChainId = PortChainId.of(id);
             boolean portChainIdExist = portChainService.exists(portChainId);
@@ -183,44 +183,111 @@
 
             PortChain portChain = portChainService.getPortChain(portChainId);
 
-            List<PortPairGroupId> llPortPairGroupIdList = portChain.portPairGroups();
-            ListIterator<PortPairGroupId> portPairGroupIdListIterator = llPortPairGroupIdList.listIterator();
-            while (portPairGroupIdListIterator.hasNext()) {
-                PortPairGroupId portPairGroupId = portPairGroupIdListIterator.next();
-                PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
-                List<PortPairId> llPortPairIdList = portPairGroup.portPairs();
-                ListIterator<PortPairId> portPairListIterator = llPortPairIdList.listIterator();
+            Set<FiveTuple> fiveTupleSet = portChain.getLoadBalanceIdMapKeys();
+            for (FiveTuple fiveTuple : fiveTupleSet) {
+                List<PortPairId> path = portChain.getLoadBalancePath(fiveTuple);
+                LoadBalanceId lbId = portChain.getLoadBalanceId(fiveTuple);
+                ListIterator<PortPairId> pathIterator = path.listIterator();
 
-                while (portPairListIterator.hasNext()) {
-                    PortPairId portPairId = portPairListIterator.next();
+                // Add source
+                Host srcHost = hostService.getHost(HostId.hostId(fiveTuple.macSrc()));
+
+                HostHighlight hSrc = new HostHighlight(srcHost.id().toString());
+                hSrc.setBadge(NodeBadge.text("SRC"));
+                String sfcPath = "SRC -> ";
+                highlights.add(hSrc);
+
+                DeviceId previousDeviceId = null;
+                while (pathIterator.hasNext()) {
+
+                    PortPairId portPairId = pathIterator.next();
                     PortPair portPair = portPairService.getPortPair(portPairId);
                     DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.egress()));
-                    Device device = deviceService.getDevice(deviceId);
-                    DeviceHighlight dh = new DeviceHighlight(device.id().toString());
-                    dh.setBadge(NodeBadge.text(SFC_ID));
-
-                    MacAddress dstMacAddress = virtualPortService.getPort(VirtualPortId
-                                                        .portId(portPair.egress())).macAddress();
+                    VirtualPort vPort = virtualPortService.getPort(VirtualPortId.portId(portPair.egress()));
+                    MacAddress dstMacAddress = vPort.macAddress();
                     Host host = hostService.getHost(HostId.hostId(dstMacAddress));
-                    HostHighlight hhDst = new HostHighlight(host.id().toString());
-                    hhDst.setBadge(NodeBadge.text(SFC_ID));
 
-                    MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId
-                                                        .portId(portPair.ingress())).macAddress();
-                    Host hostSrc = hostService.getHost(HostId.hostId(srcMacAddress));
-                    HostHighlight hhSrc = new HostHighlight(hostSrc.id().toString());
-                    hhSrc.setBadge(NodeBadge.text(SFC_ID));
+                    addEdgeLinks(linkMap, host);
+                    log.info("before check");
+                    if (previousDeviceId != null) {
+                        log.info("pdid not null");
+                        if (!deviceId.equals(previousDeviceId)) {
+                            // Highlight the link between devices.
+
+                            Link link = getLinkBetweenDevices(deviceId, previousDeviceId);
+                            if (link != null) {
+                                linkMap.add(link);
+                            }
+                        }
+                    }
+
+                    DeviceHighlight dh = new DeviceHighlight(deviceId.toString());
+                    if (portChain.getSfcClassifiers(lbId).contains(deviceId)) {
+                        dh.setBadge(NodeBadge.text(CLASSIFIER));
+                    } else {
+                        dh.setBadge(NodeBadge.text(FORWARDER));
+                    }
 
                     highlights.add(dh);
-                    highlights.add(hhSrc);
+
+                    HostHighlight hhDst = new HostHighlight(host.id().toString());
+                    hhDst.setBadge(NodeBadge.text(portPair.name()));
+                    sfcPath = sfcPath + portPair.name() + "(" + vPort.fixedIps().iterator().next().ip() + ") -> ";
+
+                    if (!portPair.ingress().equals(portPair.egress())) {
+                        MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId
+                                .portId(portPair.ingress()))
+                                .macAddress();
+                        Host hostSrc = hostService.getHost(HostId.hostId(srcMacAddress));
+                        HostHighlight hhSrc = new HostHighlight(hostSrc.id().toString());
+                        hhSrc.setBadge(NodeBadge.text(portPair.name()));
+                        highlights.add(hhSrc);
+                    }
                     highlights.add(hhDst);
+                    previousDeviceId = deviceId;
                 }
+
+                // Add destination
+                Host dstHost = hostService.getHost(HostId.hostId(fiveTuple.macDst()));
+
+                HostHighlight hDst = new HostHighlight(dstHost.id().toString());
+                hDst.setBadge(NodeBadge.text("DST"));
+                sfcPath = sfcPath + "DST";
+                highlights.add(hDst);
+                sfcPathList.add(sfcPath);
             }
 
+            for (SfcLink sfcLink : linkMap.biLinks()) {
+                highlights.add(sfcLink.highlight(null));
+            }
             sendHighlights(highlights);
+
+            ObjectNode result = objectNode();
+            ArrayNode arrayNode = arrayNode();
+            for (String path : sfcPathList) {
+                arrayNode.add(path);
+            }
+            result.putArray("sfcPathList").addAll(arrayNode);
+
+            sendMessage(SAMPLE_TOPOV_SHOW_SFC_PATH, sid, result);
         }
     }
 
+    private Link getLinkBetweenDevices(DeviceId deviceId, DeviceId previousDeviceId) {
+        Set<Link> deviceLinks = linkService.getDeviceEgressLinks(deviceId);
+        Set<Link> previousDeviceLinks = linkService.getDeviceIngressLinks(previousDeviceId);
+        for (Link link : deviceLinks) {
+            previousDeviceLinks.contains(link);
+            return link;
+        }
+        return null;
+    }
+
+    private void addEdgeLinks(SfcLinkMap linkMap, Host host1) {
+        linkMap.add(createEdgeLink(host1, true));
+        linkMap.add(createEdgeLink(host1, false));
+    }
+
     private synchronized void cancelTask() {
         if (demoTask != null) {
             demoTask.cancel();
diff --git a/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovOverlay.java b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovOverlay.java
index 6ee1b02..dce4f9c 100644
--- a/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovOverlay.java
+++ b/apps/vtn/sfcweb/src/main/java/org/onosproject/sfcweb/SfcwebUiTopovOverlay.java
@@ -15,11 +15,19 @@
  */
 package org.onosproject.sfcweb;
 
+import org.onlab.packet.MacAddress;
+import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
 import org.onosproject.net.HostId;
+import org.onosproject.net.host.HostService;
 import org.onosproject.ui.UiTopoOverlay;
 import org.onosproject.ui.topo.PropertyPanel;
-
+import org.onosproject.vtnrsc.PortPair;
+import org.onosproject.vtnrsc.VirtualPort;
+import org.onosproject.vtnrsc.VirtualPortId;
+import org.onosproject.vtnrsc.portpair.PortPairService;
+import org.onosproject.vtnrsc.virtualport.VirtualPortService;
 
 /**
  * Our sfcweb topology overlay.
@@ -46,6 +54,19 @@
     public void modifyHostDetails(PropertyPanel pp, HostId hostId) {
         pp.title(MY_HOST_TITLE);
         pp.removeAllProps();
+        PortPairService portPairService = AbstractShellCommand.get(PortPairService.class);
+        VirtualPortService virtualPortService = AbstractShellCommand.get(VirtualPortService.class);
+        HostService hostService = AbstractShellCommand.get(HostService.class);
+        Iterable<PortPair> portPairs = portPairService.getPortPairs();
+        for (PortPair portPair : portPairs) {
+            VirtualPort vPort = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress()));
+            MacAddress dstMacAddress = vPort.macAddress();
+            Host host = hostService.getHost(HostId.hostId(dstMacAddress));
+            if (hostId.toString().equals(host.id().toString())) {
+                pp.addProp("SF Name", portPair.name());
+                pp.addProp("SF Ip", vPort.fixedIps().iterator().next().ip());
+            }
+        }
         pp.addProp("SF host Address", hostId.toString());
     }
 
diff --git a/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovDemo.js b/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovDemo.js
index ebaf482..78488b3 100755
--- a/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovDemo.js
+++ b/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovDemo.js
@@ -28,31 +28,41 @@
     var displayStart     = 'sfcwebTopovDisplayStart',
         showSfcInf       = 'showSfcInfo',
         clearMessage     = 'sfcTopovClear',
-        configSfpMessage = 'configSfpMessage' ;
+        configSfpMessage = 'configSfpMessage',
+        sfcPath          = 'showSfcPath' ;
 
     // internal state
     var currentMode = null;
+    var sfpInfo;
 
     // === Main API functions
 
     function start() {
         handlerMap[showSfcInf] = showSfcInformation;
+        handlerMap[sfcPath] = showSfcPath;
         wss.bindHandlers(handlerMap);
         wss.sendEvent(displayStart);
     }
 
-    function dOk() {
-        var sfcId = null;
-        sfcId = d3.select('#sfp-value').property("value");
+    function dOkSfp() {
+        var tdString;
+        var i = 0;
 
-        if (sfcId) {
-            console.log(sfcId);
+        sfpInfo.a.forEach( function () {
+            var sfpId = d3.select("#sfp-value-id-"+i).property("checked");
+            if (sfpId)
+            {
+                tdString = sfpInfo.a[i];
+            }
+            i++;
+        } );
+
+        if (!tdString) {
+            $log.debug("No SFP ID is selected.");
         }
 
-       $log.debug('Dialog OK button clicked');
-
        wss.sendEvent(configSfpMessage, {
-            id: sfcId
+            id: tdString
         });
 
         flash.flash('SFP ID query:');
@@ -62,68 +72,67 @@
         $log.debug('Dialog Close button clicked (or Esc pressed)');
     }
 
-    function createUserText() {
+    function createUserTextSfp(data) {
+        console.log(data);
+
         var content = ds.createDiv();
         var form = content.append('form');
         var p = form.append('p');
+        var i = 0;
 
-        p.append('input').attr({
-            id: 'sfp-value',
-            type: 'string',
-            name: 'sfp-value-name'
-        });
-        p.append('span').text('ID');
+        p.append('span').text('SFP IDs');
         p.append('br');
+        sfpInfo = data;
+        data.a.forEach( function () {
+
+            p.append('input').attr({
+                id: 'sfp-value-id-'+i,
+                type: 'radio',
+                name: 'sfp-id-name',
+                value: data.a[i]
+            });
+
+            p.append('span').text(data.a[i]);
+            p.append('br');
+            i++;
+        } );
 
         return content;
     }
 
-    function configSfp() {
+    function showSfcInformation(data) {
         tds.openDialog()
-        .setTitle('SFP ID User Input')
-        .addContent(createUserText())
-        .addOk(dOk, 'OK')
-        .addCancel(dClose, 'Close')
-        .bindKeys();
+            .setTitle('List of active service functions')
+            .addContent(createUserTextSfp(data))
+            .addOk(dOkSfp, 'Select SFP ID')
+            .addCancel(dClose, 'Close')
+            .bindKeys();
+
     }
 
-    function showSfcInformation(data) {
-        console.log(data);
-        wss.unbindHandlers(handlerMap);
+    function createSfcPathText(data) {
 
-        // Get the modal
-        var modal = document.getElementById('myModal');
+        var content = ds.createDiv();
+        var form = content.append('form');
+        var p = form.append('p');
+        var i = 0;
 
-        // Get the button that opens the modal
-        var btn = document.getElementById("myBtn");
+        p.append('span').text('SFC Path');
+        p.append('br');
+        data.sfcPathList.forEach( function (val, idx) {
+            p.append('span').text(val);
+            p.append('br')
+        } );
 
-        // Get the <span> element that closes the modal
-        var span = document.getElementsByClassName("close")[0];
+        return content;
+    }
 
-        modal.style.display = "block";
-
-        var tBody = document.getElementById('sfc-info-body');
-
-        var tdString = '' ;
-
-        for (var i = 0; i < data.a.length; i++) {
-            tdString += '<tr> <td>'+ data.a[i] +'</td></tr>';
-        }
-
-        tBody.innerHTML = tdString;
-
-        // When the user clicks on <span> (x), close the modal
-        span.onclick = function() {
-            modal.style.display = "none";
-        }
-
-        // When the user clicks anywhere outside of the modal, close it
-        window.onclick = function(event) {
-            if (event.target == modal) {
-                modal.style.display = "none";
-            }
-        }
-
+    function showSfcPath(data) {
+        tds.openDialog()
+            .setTitle('Service function path')
+            .addContent(createSfcPathText(data))
+            .addCancel(dClose, 'Close')
+            .bindKeys();
     }
 
     function clear() {
@@ -146,8 +155,8 @@
             return {
                 start: start,
                 showSfcInformation: showSfcInformation,
-                clear: clear,
-                configSfp: configSfp
+                showSfcPath : showSfcPath,
+                clear: clear
             };
         }]);
 
diff --git a/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovOverlay.js b/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovOverlay.js
index 75bccb1..5f5c118 100755
--- a/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovOverlay.js
+++ b/apps/vtn/sfcweb/src/main/resources/app/view/sfcwebTopov/sfcwebTopovOverlay.js
@@ -27,11 +27,6 @@
             star4: {
                 vb: '0 0 8 8',
                 d: 'M1,4l2,-1l1,-2l1,2l2,1l-2,1l-1,2l-1,-2z'
-            },
-            jp: {
-                vb: '0 0 110 110',
-                d: 'M84.3,89.3L58.9,64.2l-1.4,1.4L83,90.7L84.3,89.3z M27,7.6H7.4v19.2H27V7.6z' +
-                'M59.3,47.1H39.8v19.2h19.5V47.1z M102.1,79.5H82.6v19.2h19.5V79.5z M41.7,47.6L19,25.1l-1.2,1.2l22.7,22.5L41.7,47.6z'
             }
         },
         activate: function () {
@@ -53,16 +48,9 @@
                 tt: 'Query SFP active list information',
                 gid: 'summary'
             },
-            5: {
-                cb: function () {
-                    pps.configSfp();
-                },
-                tt: 'Highlight SFP active list information',
-                gid: '*jp'
-            },
 
             _keyOrder: [
-                '4' , '5'
+                '4'
             ]
         }
 
diff --git a/apps/vtn/sfcweb/src/main/resources/sfcwebTopov/js.html b/apps/vtn/sfcweb/src/main/resources/sfcwebTopov/js.html
index ea42c70..4a6ab75 100755
--- a/apps/vtn/sfcweb/src/main/resources/sfcwebTopov/js.html
+++ b/apps/vtn/sfcweb/src/main/resources/sfcwebTopov/js.html
@@ -1,61 +1,2 @@
 <script src="app/view/sfcwebTopov/sfcwebTopovDemo.js"></script>
 <script src="app/view/sfcwebTopov/sfcwebTopovOverlay.js"></script>
-
-<style>
-    /* The Modal (background) */
-    .modal {
-        display: none;
-        position: fixed;
-        z-index: 1;
-        padding-top: 0px;
-        left: 0px;
-        top: 0;
-        width: 37%;
-        height: 25%;
-        overflow: auto;
-        background-color: none;
-        margin: 178px 0px 0px -8px;
-    }
-
-    /* Modal Content */
-    .modal-content {
-        background-color: #fefefe;
-        margin: auto;
-        padding: 20px;
-        border: 1px solid #888;
-        width: 80%;
-    }
-
-    /* The Close Button */
-    .close {
-        color: #aaaaaa;
-        float: right;
-        font-size: 28px;
-        font-weight: bold;
-    }
-
-    .close:hover,
-    .close:focus {
-        color: #000;
-        text-decoration: none;
-        cursor: pointer;
-    }
-
-</style>
-
-<!-- The Modal -->
-<div id="myModal" class="modal">
-
-    <!-- Modal content -->
-    <div class="modal-content">
-        <span class="close">×</span>
-            <table id='sfc-info'>
-                <thead>
-                    <td>SFP ID information</td>
-                </thead>
-                    <tbody id='sfc-info-body'>
-
-                    </tbody>
-            </table>
-    </div>
-</div>
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java
index f2971bf..c07e1ab 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java
@@ -62,6 +62,7 @@
 import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
 import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.config.basics.BasicDeviceConfig;
+import org.onosproject.net.config.basics.BasicHostConfig;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
@@ -207,6 +208,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected FlowRuleService flowRuleService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
     private ApplicationId appId;
     private ClassifierService classifierService;
     private L2ForwardService l2ForwardService;
@@ -840,13 +844,16 @@
             VtnRscEventFeedback l3Feedback = event.subject();
             if (VtnRscEvent.Type.ROUTER_INTERFACE_PUT == event.type()) {
                 onRouterInterfaceDetected(l3Feedback);
-            } else
-                if (VtnRscEvent.Type.ROUTER_INTERFACE_DELETE == event.type()) {
+            } else if (VtnRscEvent.Type.ROUTER_INTERFACE_DELETE == event.type()) {
                 onRouterInterfaceVanished(l3Feedback);
             } else if (VtnRscEvent.Type.FLOATINGIP_BIND == event.type()) {
                 onFloatingIpDetected(l3Feedback);
             } else if (VtnRscEvent.Type.FLOATINGIP_UNBIND == event.type()) {
                 onFloatingIpVanished(l3Feedback);
+            } else if (VtnRscEvent.Type.VIRTUAL_PORT_PUT == event.type()) {
+                onVirtualPortCreated(l3Feedback);
+            } else if (VtnRscEvent.Type.VIRTUAL_PORT_DELETE == event.type()) {
+                onVirtualPortDeleted(l3Feedback);
             }
         }
 
@@ -919,6 +926,29 @@
         programFloatingIpEvent(l3Feedback, VtnRscEvent.Type.FLOATINGIP_UNBIND);
     }
 
+    public void onVirtualPortCreated(VtnRscEventFeedback l3Feedback) {
+        VirtualPort vPort = l3Feedback.virtualPort();
+        BasicHostConfig basicHostConfig = networkConfigService.addConfig(HostId.hostId(vPort.macAddress()),
+                                                                         BasicHostConfig.class);
+        Set<IpAddress> ips = new HashSet<>();
+        for (FixedIp fixedIp : vPort.fixedIps()) {
+            ips.add(fixedIp.ip());
+        }
+        basicHostConfig.setIps(ips).apply();
+    }
+
+    public void onVirtualPortDeleted(VtnRscEventFeedback l3Feedback) {
+        VirtualPort vPort = l3Feedback.virtualPort();
+        HostId hostId = HostId.hostId(vPort.macAddress());
+        BasicHostConfig basicHostConfig = networkConfigService.addConfig(hostId,
+                                                                         BasicHostConfig.class);
+        Set<IpAddress> ips = hostService.getHost(hostId).ipAddresses();
+        for (FixedIp fixedIp : vPort.fixedIps()) {
+            ips.remove(fixedIp.ip());
+        }
+        basicHostConfig.setIps(ips).apply();
+    }
+
     private void programInterfacesSet(Set<RouterInterface> interfacesSet,
                                       Objective.Operation operation) {
         int subnetVmNum = 0;
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFiveTuple.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFiveTuple.java
index fc7fd4f..c13e922 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFiveTuple.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFiveTuple.java
@@ -22,6 +22,7 @@
 
 import org.onlab.packet.IPv4;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
 import org.onosproject.net.PortNumber;
 
 /**
@@ -29,6 +30,8 @@
  */
 public final class DefaultFiveTuple implements FiveTuple {
 
+    private final MacAddress macSrc;
+    private final MacAddress macDst;
     private final IpAddress ipSrc;
     private final IpAddress ipDst;
     private final PortNumber portSrc;
@@ -46,7 +49,7 @@
      * @param portDst destination port of the packet
      */
     private DefaultFiveTuple(byte protocol, IpAddress ipSrc, IpAddress ipDst, PortNumber portSrc, PortNumber portDst,
-                             TenantId tenantId) {
+                             TenantId tenantId, MacAddress macSrc, MacAddress macDst) {
 
         this.protocol = protocol;
         this.ipSrc = ipSrc;
@@ -54,6 +57,8 @@
         this.portSrc = portSrc;
         this.portDst = portDst;
         this.tenantId = tenantId;
+        this.macSrc = macSrc;
+        this.macDst = macDst;
     }
 
     @Override
@@ -82,6 +87,16 @@
     }
 
     @Override
+    public MacAddress macSrc() {
+        return macSrc;
+    }
+
+    @Override
+    public MacAddress macDst() {
+        return macDst;
+    }
+
+    @Override
     public TenantId tenantId() {
         return tenantId;
     }
@@ -139,6 +154,8 @@
         private PortNumber portDst;
         private byte protocol;
         private TenantId tenantId;
+        private MacAddress macSrc;
+        private MacAddress macDst;
 
         @Override
         public Builder setIpSrc(IpAddress ipSrc) {
@@ -171,17 +188,29 @@
         }
 
         @Override
-        public org.onosproject.vtnrsc.FiveTuple.Builder setTenantId(TenantId tenantId) {
+        public Builder setTenantId(TenantId tenantId) {
             this.tenantId = tenantId;
             return this;
         }
 
         @Override
+        public Builder setMacSrc(MacAddress macSrc) {
+            this.macSrc = macSrc;
+            return this;
+        }
+
+        @Override
+        public Builder setMacDst(MacAddress macDst) {
+            this.macDst = macDst;
+            return this;
+        }
+
+        @Override
         public FiveTuple build() {
             checkArgument(protocol == IPv4.PROTOCOL_TCP || protocol == IPv4.PROTOCOL_UDP ||
                     protocol == IPv4.PROTOCOL_ICMP, "Unsupported value for protocol while creating five tuple");
 
-            return new DefaultFiveTuple(protocol, ipSrc, ipDst, portSrc, portDst, tenantId);
+            return new DefaultFiveTuple(protocol, ipSrc, ipDst, portSrc, portDst, tenantId, macSrc, macDst);
         }
     }
 }
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FiveTuple.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FiveTuple.java
index 557b79f..8946abf 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FiveTuple.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FiveTuple.java
@@ -16,6 +16,7 @@
 package org.onosproject.vtnrsc;
 
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
 import org.onosproject.net.PortNumber;
 
 /**
@@ -61,6 +62,20 @@
     PortNumber portDst();
 
     /**
+     * Returns source mac.
+     *
+     * @return srcMac
+     */
+    MacAddress macSrc();
+
+    /**
+     * Returns destination mac.
+     *
+     * @return dstMac
+     */
+    MacAddress macDst();
+
+    /**
      * Returns the tenant id.
      *
      * @return tenantId
@@ -105,6 +120,22 @@
         Builder setPortDst(PortNumber portDst);
 
         /**
+         * Assign the source mac address to this object.
+         *
+         * @param macSrc source mac address
+         * @return this the builder object
+         */
+        Builder setMacSrc(MacAddress macSrc);
+
+        /**
+         * Assign the destination mac address to this object.
+         *
+         * @param macDst destination mac address
+         * @return this the builder object
+         */
+        Builder setMacDst(MacAddress macDst);
+
+        /**
          * Assign the protocol to this object.
          *
          * @param protocol packet protocol
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEvent.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEvent.java
index e71dc5d..fb8d0d7 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEvent.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEvent.java
@@ -107,7 +107,15 @@
         /**
          * Signifies that port-chain has update.
          */
-        PORT_CHAIN_UPDATE
+        PORT_CHAIN_UPDATE,
+        /**
+         * Signifies that virtual-port has created.
+         */
+        VIRTUAL_PORT_PUT,
+        /**
+         * Signifies that virtual-port has removed.
+         */
+        VIRTUAL_PORT_DELETE
     }
 
     /**
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEventFeedback.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEventFeedback.java
index 4d610b6..ec5885c 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEventFeedback.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/event/VtnRscEventFeedback.java
@@ -24,6 +24,7 @@
 import org.onosproject.vtnrsc.PortPairGroup;
 import org.onosproject.vtnrsc.FlowClassifier;
 import org.onosproject.vtnrsc.PortChain;
+import org.onosproject.vtnrsc.VirtualPort;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -39,6 +40,7 @@
     private final PortPairGroup portPairGroup;
     private final FlowClassifier flowClassifier;
     private final PortChain portChain;
+    private final VirtualPort virtualPort;
 
     /**
      * Creates VtnRscEventFeedback object.
@@ -53,6 +55,7 @@
         this.portPairGroup = null;
         this.flowClassifier = null;
         this.portChain = null;
+        this.virtualPort = null;
     }
 
     /**
@@ -68,6 +71,7 @@
         this.portPairGroup = null;
         this.flowClassifier = null;
         this.portChain = null;
+        this.virtualPort = null;
     }
 
     /**
@@ -84,6 +88,7 @@
         this.portPairGroup = null;
         this.flowClassifier = null;
         this.portChain = null;
+        this.virtualPort = null;
     }
 
     /**
@@ -100,6 +105,7 @@
         this.portPairGroup = null;
         this.flowClassifier = null;
         this.portChain = null;
+        this.virtualPort = null;
     }
 
     /**
@@ -113,9 +119,10 @@
         this.routerInterface = null;
         this.portPair = null;
         this.portPairGroup = checkNotNull(portPairGroup,
-                                     "Port-Pair-Group cannot be null");
+                "Port-Pair-Group cannot be null");
         this.flowClassifier = null;
         this.portChain = null;
+        this.virtualPort = null;
     }
 
     /**
@@ -130,8 +137,9 @@
         this.portPair = null;
         this.portPairGroup = null;
         this.flowClassifier = checkNotNull(flowClassifier,
-                                     "Flow-Classifier cannot be null");
+                "Flow-Classifier cannot be null");
         this.portChain = null;
+        this.virtualPort = null;
     }
 
     /**
@@ -147,7 +155,25 @@
         this.portPairGroup = null;
         this.flowClassifier = null;
         this.portChain = checkNotNull(portChain,
-                                     "Port-Chain cannot be null");
+                "Port-Chain cannot be null");
+        this.virtualPort = null;
+    }
+
+    /**
+     * Creates VtnRscEventFeedback object.
+     *
+     * @param virtualPort the Virtual-Port
+     */
+    public VtnRscEventFeedback(VirtualPort virtualPort) {
+        this.floaingtIp = null;
+        this.router = null;
+        this.routerInterface = null;
+        this.portPair = null;
+        this.portPairGroup = null;
+        this.flowClassifier = null;
+        this.portChain = null;
+        this.virtualPort = checkNotNull(virtualPort,
+                "Virtual-port cannot be null");
     }
 
     /**
@@ -213,10 +239,19 @@
         return portChain;
     }
 
+    /**
+     * Returns Virtual-Port.
+     *
+     * @return virtualPort the Virtual-Port
+     */
+    public VirtualPort virtualPort() {
+        return virtualPort;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(floaingtIp, router, routerInterface, portPair,
-                            portPairGroup, flowClassifier, portChain);
+                            portPairGroup, flowClassifier, portChain, virtualPort);
     }
 
     @Override
@@ -232,7 +267,8 @@
                     && Objects.equals(this.portPair, that.portPair)
                     && Objects.equals(this.portPairGroup, that.portPairGroup)
                     && Objects.equals(this.flowClassifier, that.flowClassifier)
-                    && Objects.equals(this.portChain, that.portChain);
+                    && Objects.equals(this.portChain, that.portChain)
+                    && Objects.equals(this.virtualPort, that.virtualPort);
         }
         return false;
     }
@@ -247,6 +283,7 @@
                 .add("portPairGroup", portPairGroup)
                 .add("flowClassifier", flowClassifier)
                 .add("portChain", portChain)
+                .add("virtualPort", virtualPort)
                 .toString();
     }
 }
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/impl/PortChainManager.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/impl/PortChainManager.java
index 21a3d2d..6d7fe04 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/impl/PortChainManager.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/impl/PortChainManager.java
@@ -97,6 +97,7 @@
     @Deactivate
     public void deactivate() {
         eventDispatcher.removeSink(PortChainEvent.class);
+        portChainStore.removeListener(portChainListener);
         portChainStore.destroy();
         log.info("Stopped");
     }
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/service/impl/VtnRscManager.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/service/impl/VtnRscManager.java
index b39e82c..f6d54a9 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/service/impl/VtnRscManager.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/service/impl/VtnRscManager.java
@@ -87,6 +87,8 @@
 import org.onosproject.vtnrsc.service.VtnRscService;
 import org.onosproject.vtnrsc.subnet.SubnetService;
 import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+import org.onosproject.vtnrsc.virtualport.VirtualPortEvent;
+import org.onosproject.vtnrsc.virtualport.VirtualPortListener;
 import org.onosproject.vtnrsc.virtualport.VirtualPortService;
 import org.slf4j.Logger;
 
@@ -112,6 +114,7 @@
     private PortPairGroupListener portPairGroupListener = new InnerPortPairGroupListener();
     private FlowClassifierListener flowClassifierListener = new InnerFlowClassifierListener();
     private PortChainListener portChainListener = new InnerPortChainListener();
+    private VirtualPortListener virtualPortListener = new InnerVirtualPortListener();
 
     private EventuallyConsistentMap<TenantId, SegmentationId> l3vniTenantMap;
     private EventuallyConsistentMap<TenantRouter, SegmentationId> l3vniTenantRouterMap;
@@ -165,6 +168,7 @@
         portPairGroupService.addListener(portPairGroupListener);
         flowClassifierService.addListener(flowClassifierListener);
         portChainService.addListener(portChainListener);
+        virtualPortService.addListener(virtualPortListener);
 
         KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
                 .register(KryoNamespaces.API)
@@ -205,6 +209,7 @@
         portPairGroupService.removeListener(portPairGroupListener);
         flowClassifierService.removeListener(flowClassifierListener);
         portChainService.removeListener(portChainListener);
+        virtualPortService.removeListener(virtualPortListener);
 
         l3vniTenantMap.destroy();
         l3vniTenantRouterMap.destroy();
@@ -401,6 +406,22 @@
         }
     }
 
+    private class InnerVirtualPortListener implements VirtualPortListener {
+
+        @Override
+        public void event(VirtualPortEvent event) {
+            checkNotNull(event, EVENT_NOT_NULL);
+            VirtualPort virtualPort = event.subject();
+            if (VirtualPortEvent.Type.VIRTUAL_PORT_PUT == event.type()) {
+                notifyListeners(new VtnRscEvent(VtnRscEvent.Type.VIRTUAL_PORT_PUT,
+                                                new VtnRscEventFeedback(virtualPort)));
+            } else if (VirtualPortEvent.Type.VIRTUAL_PORT_DELETE == event.type()) {
+                notifyListeners(new VtnRscEvent(VtnRscEvent.Type.VIRTUAL_PORT_DELETE,
+                                                new VtnRscEventFeedback(virtualPort)));
+            }
+        }
+    }
+
     @Override
     public Iterator<Device> getClassifierOfTenant(TenantId tenantId) {
         checkNotNull(tenantId, TENANTID_NOT_NULL);
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortEvent.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortEvent.java
new file mode 100644
index 0000000..e0d3aac
--- /dev/null
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortEvent.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.virtualport;
+
+import org.onosproject.event.AbstractEvent;
+import org.onosproject.vtnrsc.VirtualPort;
+
+/**
+ * Describes virtual port event.
+ */
+public class VirtualPortEvent extends AbstractEvent<VirtualPortEvent.Type, VirtualPort> {
+    /**
+     * Type of virtual port events.
+     */
+    public enum Type {
+        /**
+         * Signifies that virtual port has been created.
+         */
+        VIRTUAL_PORT_PUT,
+        /**
+         * Signifies that virtual port has been deleted.
+         */
+        VIRTUAL_PORT_DELETE,
+        /**
+         * Signifies that virtual port has been updated.
+         */
+        VIRTUAL_PORT_UPDATE
+    }
+
+    /**
+     * Creates an event of a given type and for the specified virtual port.
+     *
+     * @param type virtual port event type
+     * @param virtualPort virtual port subject
+     */
+    public VirtualPortEvent(Type type, VirtualPort virtualPort) {
+        super(type, virtualPort);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified virtual port.
+     *
+     * @param type virtual port event type
+     * @param virtualPort virtual port subject
+     * @param time occurrence time
+     */
+    public VirtualPortEvent(Type type, VirtualPort virtualPort, long time) {
+        super(type, virtualPort, time);
+    }
+}
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortListener.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortListener.java
new file mode 100644
index 0000000..c2d848d
--- /dev/null
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortListener.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnrsc.virtualport;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Entity capable of virtual port related events.
+ */
+public interface VirtualPortListener extends EventListener<VirtualPortEvent> {
+
+}
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java
index 25ef028..3808291 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java
@@ -18,6 +18,7 @@
 import java.util.Collection;
 
 import org.onlab.packet.IpAddress;
+import org.onosproject.event.ListenerService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.vtnrsc.FixedIp;
 import org.onosproject.vtnrsc.TenantId;
@@ -28,7 +29,7 @@
 /**
  * Service for interacting with the inventory of virtualPort.
  */
-public interface VirtualPortService {
+public interface VirtualPortService extends ListenerService<VirtualPortEvent, VirtualPortListener> {
     /**
      * Returns if the virtualPort is existed.
      *
diff --git a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java
index 2722123..d352cb3 100644
--- a/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java
+++ b/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java
@@ -18,12 +18,10 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.stream.Collectors;
 
 import org.apache.felix.scr.annotations.Activate;
@@ -33,12 +31,18 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.IpAddress;
+import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.net.DeviceId;
 import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.EventuallyConsistentMapEvent;
+import org.onosproject.store.service.EventuallyConsistentMapListener;
+import org.onosproject.store.service.MultiValuedTimestamp;
 import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
 import org.onosproject.vtnrsc.AllowedAddressPair;
 import org.onosproject.vtnrsc.BindingHostId;
 import org.onosproject.vtnrsc.DefaultVirtualPort;
@@ -50,6 +54,8 @@
 import org.onosproject.vtnrsc.VirtualPort;
 import org.onosproject.vtnrsc.VirtualPortId;
 import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
+import org.onosproject.vtnrsc.virtualport.VirtualPortEvent;
+import org.onosproject.vtnrsc.virtualport.VirtualPortListener;
 import org.onosproject.vtnrsc.virtualport.VirtualPortService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,7 +65,8 @@
  */
 @Component(immediate = true)
 @Service
-public class VirtualPortManager implements VirtualPortService {
+public class VirtualPortManager extends AbstractListenerManager<VirtualPortEvent, VirtualPortListener>
+implements VirtualPortService {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -73,8 +80,9 @@
     private static final String DEVICEID_NOT_NULL = "DeviceId  cannot be null";
     private static final String FIXEDIP_NOT_NULL = "FixedIp  cannot be null";
     private static final String IP_NOT_NULL = "Ip  cannot be null";
+    private static final String EVENT_NOT_NULL = "event cannot be null";
 
-    protected Map<VirtualPortId, VirtualPort> vPortStore;
+    protected EventuallyConsistentMap<VirtualPortId, VirtualPort> vPortStore;
     protected ApplicationId appId;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -86,28 +94,35 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
 
+    private EventuallyConsistentMapListener<VirtualPortId, VirtualPort> virtualPortListener =
+            new InnerVirtualPortStoreListener();
+
     @Activate
     public void activate() {
 
         appId = coreService.registerApplication(VTNRSC_APP);
 
-        vPortStore = storageService.<VirtualPortId, VirtualPort>consistentMapBuilder()
+        eventDispatcher.addSink(VirtualPortEvent.class, listenerRegistry);
+
+        vPortStore = storageService.<VirtualPortId, VirtualPort>eventuallyConsistentMapBuilder()
                 .withName(VIRTUALPORT)
-                .withApplicationId(appId)
-                .withPurgeOnUninstall()
-                .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
-                                                 VirtualPortId.class,
-                                                 TenantNetworkId.class,
-                                                 VirtualPort.State.class,
-                                                 TenantId.class,
-                                                 AllowedAddressPair.class,
-                                                 FixedIp.class,
-                                                 BindingHostId.class,
-                                                 SecurityGroup.class,
-                                                 SubnetId.class,
-                                                 IpAddress.class,
-                                                 DefaultVirtualPort.class))
-                .build().asJavaMap();
+                .withSerializer(KryoNamespace.newBuilder().register(KryoNamespaces.API)
+                                .register(MultiValuedTimestamp.class)
+                        .register(VirtualPortId.class,
+                                  TenantNetworkId.class,
+                                  VirtualPort.State.class,
+                                  TenantId.class,
+                                  AllowedAddressPair.class,
+                                  FixedIp.class,
+                                  BindingHostId.class,
+                                  SecurityGroup.class,
+                                  SubnetId.class,
+                                  IpAddress.class,
+                                  DefaultVirtualPort.class))
+                .withTimestampProvider((k, v) ->new WallClockTimestamp())
+                                          .build();
+
+        vPortStore.addListener(virtualPortListener);
         log.info("Started");
     }
 
@@ -246,4 +261,35 @@
         return true;
     }
 
+    private class InnerVirtualPortStoreListener
+    implements
+    EventuallyConsistentMapListener<VirtualPortId, VirtualPort> {
+
+        @Override
+        public void event(EventuallyConsistentMapEvent<VirtualPortId, VirtualPort> event) {
+            checkNotNull(event, EVENT_NOT_NULL);
+            log.info("virtual port event raised");
+            VirtualPort virtualPort = event.value();
+            if (EventuallyConsistentMapEvent.Type.PUT == event.type()) {
+                notifyListeners(new VirtualPortEvent(
+                                                     VirtualPortEvent.Type.VIRTUAL_PORT_PUT,
+                                                     virtualPort));
+            }
+            if (EventuallyConsistentMapEvent.Type.REMOVE == event.type()) {
+                notifyListeners(new VirtualPortEvent(
+                                                     VirtualPortEvent.Type.VIRTUAL_PORT_DELETE,
+                                                     virtualPort));
+            }
+        }
+    }
+
+    /**
+     * Notifies specify event to all listeners.
+     *
+     * @param event virtual port event
+     */
+    private void notifyListeners(VirtualPortEvent event) {
+        checkNotNull(event, EVENT_NOT_NULL);
+        post(event);
+    }
 }
diff --git a/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/gui/SfcViewMessageHandler.java b/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/gui/SfcViewMessageHandler.java
index 66c84d4..a17ef6c 100644
--- a/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/gui/SfcViewMessageHandler.java
+++ b/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/gui/SfcViewMessageHandler.java
@@ -50,7 +50,7 @@
  */
 public class SfcViewMessageHandler extends UiMessageHandler {
 
-    private static final String SLASH = " ; ";
+    private static final String SLASH = " -> ";
     private static final String NONE = "none";
     private static final String SFCTYPE = "Service Function Chain";
 
@@ -61,13 +61,13 @@
     private static final String ID = "id";
     private static final String STATE = "_iconid_state";
     private static final String PORTCHAINNAME = "portChainName";
-    private static final String HOSTS = "hosts";
+    private static final String SFS = "sfs";
     private static final String TYPE = "type";
     private static final String SRCIP = "srcIp";
     private static final String DSTIP = "dstIp";
 
     private static final String[] COL_IDS = {
-            ID, STATE, PORTCHAINNAME, HOSTS, TYPE, SRCIP, DSTIP
+                                             ID, STATE, PORTCHAINNAME, SFS, TYPE, SRCIP, DSTIP
     };
 
     private static final String ICON_ID_ONLINE = "active";
@@ -116,7 +116,7 @@
             row.cell(ID, pchain.portChainId().value().toString())
                 .cell(STATE, sfcState(vpList))
                 .cell(PORTCHAINNAME, pchain.name())
-                .cell(HOSTS, sfcHosts(vpList))
+                .cell(SFS, sfcHosts(vpList))
                 .cell(TYPE, SFCTYPE)
                 .cell(SRCIP, portChainIpRange.srcip())
                 .cell(DSTIP, portChainIpRange.dstip());
diff --git a/apps/vtn/vtnweb/src/main/resources/app/view/sfc/sfc.html b/apps/vtn/vtnweb/src/main/resources/app/view/sfc/sfc.html
index 21697d5..a17aff1 100644
--- a/apps/vtn/vtnweb/src/main/resources/app/view/sfc/sfc.html
+++ b/apps/vtn/vtnweb/src/main/resources/app/view/sfc/sfc.html
@@ -32,7 +32,7 @@
                 <tr>
                     <td colId="_iconid_state" class="table-icon" sortable></td>
                     <td colId="portChainName" sortable>PortChainName </td>
-                    <td colId="hosts" sortable>Hosts </td>
+                    <td colId="sfs" sortable>Sfs </td>
                     <td colId="type" sortable>Type </td>
                     <td colId="srcIp" sortable>Source IP Prefix </td>
                     <td colId="dstIp" sortable>Destination IP Prefix </td>
@@ -54,7 +54,7 @@
                         <div icon icon-id="{{sfc._iconid_state}}"></div>
                     </td>
                     <td>{{sfc.portChainName}}</td>
-                    <td>{{sfc.hosts}}</td>
+                    <td>{{sfc.sfs}}</td>
                     <td>{{sfc.type}}</td>
                     <td>{{sfc.srcIp}}</td>
                     <td>{{sfc.dstIp}}</td>