[ONOS-7684] Support VM Live Migration (VxLAN + VLAN)

Change-Id: I4717f0af6731b41eaf3114994f2087af74c3e3f5
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortEvent.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortEvent.java
index 00f15ed..4276cf2 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortEvent.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/InstancePortEvent.java
@@ -40,7 +40,17 @@
         /**
          * Signifies that the instance port is disabled.
          */
-        OPENSTACK_INSTANCE_PORT_VANISHED
+        OPENSTACK_INSTANCE_PORT_VANISHED,
+
+        /**
+         * Signifies that the instance migration is started.
+         */
+        OPENSTACK_INSTANCE_MIGRATION_STARTED,
+
+        /**
+         * Signifies that the instance is migration is ended.
+         */
+        OPENSTACK_INSTANCE_MIGRATION_ENDED
     }
 
     /**
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 f5ebe11..d462e1b 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
@@ -66,4 +66,18 @@
      * @return set of instance ports; empty list if no port exists
      */
     Set<InstancePort> instancePorts(String osNetId);
+
+    /**
+     * Processes instance port addition event caused by VM migration.
+     *
+     * @param port instance port
+     */
+    void migrationPortAdded(InstancePort port);
+
+    /**
+     * Processes instance port removal event caused by VM migration.
+     *
+     * @param port instance port
+     */
+    void migrationPortRemoved(InstancePort port);
 }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/HostBasedInstancePortManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/HostBasedInstancePortManager.java
index d5d1aac..3378b82 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/HostBasedInstancePortManager.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/HostBasedInstancePortManager.java
@@ -43,6 +43,8 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
+import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
 import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_PORT_DETECTED;
 import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_PORT_UPDATED;
 import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_PORT_VANISHED;
@@ -65,7 +67,7 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostService hostService;
 
-    private final HostListener hostListener = new InternalHostListener();
+    private final InternalHostListener hostListener = new InternalHostListener();
 
     @Activate
     protected void activate() {
@@ -124,6 +126,16 @@
         return ImmutableSet.copyOf(instPors);
     }
 
+    @Override
+    public void migrationPortAdded(InstancePort port) {
+        hostListener.processEvent(OPENSTACK_INSTANCE_MIGRATION_STARTED, port);
+    }
+
+    @Override
+    public void migrationPortRemoved(InstancePort port) {
+        hostListener.processEvent(OPENSTACK_INSTANCE_MIGRATION_ENDED, port);
+    }
+
     private boolean isValidHost(Host host) {
         return !host.ipAddresses().isEmpty() &&
                 host.annotations().value(ANNOTATION_NETWORK_ID) != null &&
@@ -171,6 +183,8 @@
             eventMap.put(OPENSTACK_INSTANCE_PORT_UPDATED, "updated");
             eventMap.put(OPENSTACK_INSTANCE_PORT_DETECTED, "detected");
             eventMap.put(OPENSTACK_INSTANCE_PORT_VANISHED, "disabled");
+            eventMap.put(OPENSTACK_INSTANCE_MIGRATION_STARTED, "detected");
+            eventMap.put(OPENSTACK_INSTANCE_MIGRATION_ENDED, "disabled");
 
             InstancePortEvent instPortEvent = new InstancePortEvent(type, port);
             log.debug("Instance port is {}: {}", eventMap.get(type), port);
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 4cadb17..8c3c56d 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
@@ -57,6 +57,8 @@
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.InstancePortEvent;
+import org.onosproject.openstacknetworking.api.InstancePortListener;
 import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
@@ -96,7 +98,10 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_NETWORK_ID;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_PORT_ID;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -159,11 +164,13 @@
     private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
     private final HostListener hostListener = new InternalHostListener();
     private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
+    private final InstancePortListener instPortListener = new InternalInstancePortListener();
 
     private ApplicationId appId;
     private NodeId localNodeId;
     private Map<String, MacAddress> floatingIpMacMap = Maps.newConcurrentMap();
     private Map<MacAddress, InstancePort> removedPorts = Maps.newConcurrentMap();
+    private Map<String, DeviceId> migrationPool = Maps.newConcurrentMap();
 
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
@@ -178,6 +185,7 @@
         hostService.addListener(hostListener);
         osRouterService.addListener(osRouterListener);
         osNodeService.addListener(osNodeListener);
+        instancePortService.addListener(instPortListener);
         leadershipService.runForLeadership(appId.name());
         packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
         log.info("Started");
@@ -189,6 +197,7 @@
         hostService.removeListener(hostListener);
         osRouterService.removeListener(osRouterListener);
         osNodeService.removeListener(osNodeListener);
+        instancePortService.removeListener(instPortListener);
         leadershipService.withdraw(appId.name());
         eventExecutor.shutdown();
         configService.unregisterProperties(getClass(), false);
@@ -410,6 +419,33 @@
     }
 
     /**
+     * Installs/uninstalls ARP flow rules to the corresponding gateway by
+     * looking for compute node's device ID.
+     *
+     * @param fip       floating IP
+     * @param port      instance port
+     * @param gateways  a collection of gateways
+     * @param install   install flag
+     */
+    private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
+                                                   InstancePort port,
+                                                   Set<OpenstackNode> gateways,
+                                                   boolean install) {
+        if (arpMode.equals(ARP_BROADCAST_MODE)) {
+
+            OpenstackNode gw = getGwByInstancePort(gateways, port);
+
+            if (gw == null) {
+                return;
+            }
+
+            String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
+
+            setArpRule(fip, MacAddress.valueOf(macString), gw, install);
+        }
+    }
+
+    /**
      * Installs static ARP rules used in ARP BROAD_CAST mode.
      * Note that, those rules will be only matched ARP_REQUEST packets,
      * used for telling gateway node the mapped MAC address of requested IP,
@@ -460,36 +496,41 @@
                 return;
             }
 
-            TrafficSelector selector = DefaultTrafficSelector.builder()
-                    .matchEthType(EthType.EtherType.ARP.ethType().toShort())
-                    .matchArpOp(ARP.OP_REQUEST)
-                    .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
-                    .build();
+            setArpRule(fip, targetMac, gw, install);
+        }
+    }
 
-            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                    .setArpOp(ARP.OP_REPLY)
-                    .setArpSha(targetMac)
-                    .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
-                    .setOutput(PortNumber.IN_PORT)
-                    .build();
+    private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
+                            OpenstackNode gateway, boolean install) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                .matchArpOp(ARP.OP_REQUEST)
+                .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
+                .build();
 
-            osFlowRuleService.setRule(
-                    appId,
-                    gw.intgBridge(),
-                    selector,
-                    treatment,
-                    PRIORITY_ARP_GATEWAY_RULE,
-                    GW_COMMON_TABLE,
-                    install
-            );
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setArpOp(ARP.OP_REPLY)
+                .setArpSha(targetMac)
+                .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
+                .setOutput(PortNumber.IN_PORT)
+                .build();
 
-            if (install) {
-                log.info("Install ARP Rule for Floating IP {}",
-                        fip.getFloatingIpAddress());
-            } else {
-                log.info("Uninstall ARP Rule for Floating IP {}",
-                        fip.getFloatingIpAddress());
-            }
+        osFlowRuleService.setRule(
+                appId,
+                gateway.intgBridge(),
+                selector,
+                treatment,
+                PRIORITY_ARP_GATEWAY_RULE,
+                GW_COMMON_TABLE,
+                install
+        );
+
+        if (install) {
+            log.info("Install ARP Rule for Floating IP {}",
+                    fip.getFloatingIpAddress());
+        } else {
+            log.info("Uninstall ARP Rule for Floating IP {}",
+                    fip.getFloatingIpAddress());
         }
     }
 
@@ -780,4 +821,58 @@
             );
         }
     }
+
+    private class InternalInstancePortListener implements InstancePortListener {
+
+        @Override
+        public boolean isRelevant(InstancePortEvent event) {
+            Set<NetFloatingIP> ips = osRouterService.floatingIps();
+            NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
+            Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
+
+            if (gateways.size() == 1) {
+                return false;
+            }
+
+            return fip != null && isAssociatedWithVM(osNetworkService, fip);
+        }
+
+        @Override
+        public void event(InstancePortEvent event) {
+            Set<NetFloatingIP> ips = osRouterService.floatingIps();
+            NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
+            Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
+
+            switch (event.type()) {
+                case OPENSTACK_INSTANCE_MIGRATION_STARTED:
+
+                    migrationPool.put(fip.getFloatingIpAddress(), event.subject().deviceId());
+
+                    eventExecutor.execute(() -> {
+                        setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
+                                gateways, true);
+                    });
+                    break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+
+                    DeviceId newDeviceId = migrationPool.get(fip.getFloatingIpAddress());
+                    DeviceId oldDeviceId = event.subject().deviceId();
+                    migrationPool.remove(fip.getFloatingIpAddress());
+
+                    OpenstackNode oldGw = getGwByComputeDevId(gateways, oldDeviceId);
+                    OpenstackNode newGw = getGwByComputeDevId(gateways, newDeviceId);
+
+                    if (oldGw != null && oldGw.equals(newGw)) {
+                        return;
+                    }
+
+                    eventExecutor.execute(() ->
+                        setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
+                                gateways, false));
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
 }
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 3976e5c..4ca4a6a 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
@@ -33,6 +33,7 @@
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
@@ -46,6 +47,8 @@
 import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.InstancePortEvent;
+import org.onosproject.openstacknetworking.api.InstancePortListener;
 import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
@@ -83,7 +86,9 @@
 import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_NETWORK_ID;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_PORT_ID;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 
@@ -130,10 +135,12 @@
 
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
-    private final OpenstackRouterListener floatingIpLisener = new InternalFloatingIpListener();
+    private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
+    private final InstancePortListener instancePortListener = new InternalInstancePortListener();
     private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
     private final HostListener hostListener = new InternalHostListener();
     private Map<MacAddress, InstancePort> removedPorts = Maps.newConcurrentMap();
+    private Map<String, DeviceId> migrationPool = Maps.newConcurrentMap();
 
     private ApplicationId appId;
     private NodeId localNodeId;
@@ -144,17 +151,19 @@
         localNodeId = clusterService.getLocalNode().id();
         leadershipService.runForLeadership(appId.name());
         hostService.addListener(hostListener);
-        osRouterAdminService.addListener(floatingIpLisener);
+        osRouterAdminService.addListener(floatingIpListener);
         osNodeService.addListener(osNodeListener);
+        instancePortService.addListener(instancePortListener);
 
         log.info("Started");
     }
 
     @Deactivate
     protected void deactivate() {
+        instancePortService.removeListener(instancePortListener);
         hostService.removeListener(hostListener);
         osNodeService.removeListener(osNodeListener);
-        osRouterAdminService.removeListener(floatingIpLisener);
+        osRouterAdminService.removeListener(floatingIpListener);
         leadershipService.withdraw(appId.name());
         eventExecutor.shutdown();
 
@@ -584,7 +593,6 @@
         return osNetworkService.externalPeerRouter(exGatewayInfo);
     }
 
-
     private void associateFloatingIp(NetFloatingIP osFip) {
         Port osPort = osNetworkService.port(osFip.getPortId());
         if (osPort == null) {
@@ -809,4 +817,95 @@
                     host.annotations().value(ANNOTATION_PORT_ID) != null;
         }
     }
+
+    private class InternalInstancePortListener implements InstancePortListener {
+
+        @Override
+        public boolean isRelevant(InstancePortEvent event) {
+            Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
+            NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
+
+            return fip != null && isAssociatedWithVM(osNetworkService, fip);
+        }
+
+        @Override
+        public void event(InstancePortEvent event) {
+
+            Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
+            NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
+            Port osPort = osNetworkService.port(fip.getPortId());
+            Network osNet = osNetworkService.network(osPort.getNetworkId());
+            Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
+
+            ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
+            if (externalPeerRouter == null) {
+                final String errorFormat = ERR_FLOW + "no external peer router found";
+                throw new IllegalStateException(errorFormat);
+            }
+
+            switch (event.type()) {
+                case OPENSTACK_INSTANCE_MIGRATION_STARTED:
+                    eventExecutor.execute(() -> {
+
+                        // since downstream internal rules are located in all gateway
+                        // nodes, therefore, we simply update the rules with new compute node info
+                        setDownstreamInternalRules(fip, osNet, event.subject(), true);
+
+                        // since DownstreamExternal rules should only be placed in
+                        // corresponding gateway node, we need to install new rule to
+                        // the corresponding gateway node
+                        setDownstreamExternalRulesHelper(fip, osNet,
+                                event.subject(), externalPeerRouter, gateways, true);
+
+                        // since ComputeNodeToGateway rules should only be placed in
+                        // corresponding compute node, we need to install new rule to
+                        // the target compute node, and remove rules from original node
+                        setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
+
+                        migrationPool.put(fip.getFloatingIpAddress(), event.subject().deviceId());
+
+                    });
+                    break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+
+                    // if we only have one gateway, we simply do not remove any
+                    // flow rules from either gateway or compute node
+                    if (gateways.size() == 1) {
+                        return;
+                    }
+
+                    // checks whether the destination compute node's device id
+                    // has identical gateway hash or not
+                    // if it is true, we simply do not remove the rules, as
+                    // it has been overwritten at port detention event
+                    // if it is false, we will remove the rules
+                    DeviceId newDeviceId = migrationPool.get(fip.getFloatingIpAddress());
+                    DeviceId oldDeviceId = event.subject().deviceId();
+                    migrationPool.remove(fip.getFloatingIpAddress());
+
+                    OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
+                    OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
+
+                    if (oldGateway != null && oldGateway.equals(newGateway)) {
+                        return;
+                    }
+
+                    eventExecutor.execute(() -> {
+
+                        // we need to remove the old ComputeNodeToGateway rules from
+                        // original compute node
+                        setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, false);
+
+                        // since DownstreamExternal rules should only be placed in
+                        // corresponding gateway node, we need to remove old rule from
+                        // the corresponding gateway node
+                        setDownstreamExternalRulesHelper(fip, osNet,
+                                event.subject(), externalPeerRouter, gateways, false);
+                    });
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
 }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
index 142a9f7..e174eef 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
@@ -1060,6 +1060,14 @@
                         instPortRemoved(event.subject());
                     });
                     break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+                    eventExecutor.execute(() -> {
+                        log.info("RoutingHandler: Instance port vanished MAC:{} IP:{} due to VM migration",
+                                instPort.macAddress(),
+                                instPort.ipAddress());
+                        // TODO: need to reconfigure rules to point to update VM
+                    });
+                    break;
                 default:
                     break;
             }
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 f6b8e50..837c891 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
@@ -531,6 +531,9 @@
                     setArpRequestRule(event.subject(), false);
                     setArpReplyRule(event.subject(), false);
                     break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+                    setArpRequestRule(event.subject(), false);
+                    break;
                 default:
                     break;
             }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
index 4869101..aab3780 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
@@ -161,6 +161,27 @@
         }
     }
 
+    /**
+     * Removes virtual port.
+     *
+     * @param instPort instance port
+     */
+    private void removeVportRules(InstancePort instPort) {
+        NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
+
+        switch (type) {
+            case VXLAN:
+                setTunnelTagFlowRules(instPort, false);
+                break;
+            case VLAN:
+                setVlanTagFlowRules(instPort, false);
+                break;
+            default:
+                log.warn("Unsupported network tunnel type {}", type.name());
+                break;
+        }
+    }
+
     private void setFlatJumpRules(InstancePort port, boolean install) {
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         selector.matchInPort(port.portNumber());
@@ -597,6 +618,14 @@
                         instPortRemoved(event.subject());
                     });
                     break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+                    eventExecutor.execute(() -> {
+                        log.info("Instance port vanished MAC:{} IP:{}, due to VM migration",
+                                instPort.macAddress(),
+                                instPort.ipAddress());
+                        removeVportRules(event.subject());
+                    });
+                    break;
                 default:
                     break;
             }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index 62fd2b4..6094e72 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -16,6 +16,8 @@
 package org.onosproject.openstacknetworking.impl;
 
 import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -30,7 +32,9 @@
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultHost;
 import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
@@ -46,6 +50,8 @@
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
@@ -56,6 +62,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -77,7 +84,6 @@
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     private static final String PORT_NAME_PREFIX_VM = "tap";
-    private static final String PORT_NAME_PREFIX_CAVIUM = "enp";
     private static final String ERR_ADD_HOST = "Failed to add host: ";
     private static final String ANNOTATION_SEGMENT_ID = "segId";
     private static final String SONA_HOST_SCHEME = "sona";
@@ -103,6 +109,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackNodeService osNodeService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected InstancePortService instancePortService;
+
     private final ExecutorService deviceEventExecutor =
             Executors.newSingleThreadExecutor(groupedThreads("openstacknetworking", "device-event"));
     private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
@@ -110,6 +119,9 @@
 
     private HostProviderService hostProvider;
 
+    private Map<HostId, Device> hostDeviceMap = Maps.newConcurrentMap();
+    private Set<Host> migratingHosts = Sets.newConcurrentHashSet();
+
     /**
      * Creates OpenStack switching host provider.
      */
@@ -151,7 +163,7 @@
      *
      * @param port port object used in ONOS
      */
-    private void processPortAdded(Port port) {
+    private void processPortAdded(Port port, Device device) {
         // TODO check the node state is COMPLETE
         org.openstack4j.model.network.Port osPort = osNetworkService.port(port);
         if (osPort == null) {
@@ -176,6 +188,24 @@
                 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
                 .collect(Collectors.toSet());
         ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
+        HostId oldHostId = HostId.hostId(macAddr);
+
+        // In VM migration case, a duplicated host port (port created in at new
+        // compute node) will be detected at OVS; in this case, we will store
+        // the old host instance into migration list, and overwrite old host
+        // with new host instance issue host creation event to ONOS core
+        Device oldDevice = hostDeviceMap.get(oldHostId);
+
+        if (device != null && oldDevice != null && !oldDevice.equals(device)) {
+            Host host = hostService.getHost(oldHostId);
+            if (host != null) {
+                migratingHosts.add(host);
+            }
+        }
+
+        if (device != null) {
+            hostDeviceMap.put(oldHostId, device);
+        }
 
         DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
                 .set(ANNOTATION_NETWORK_ID, osPort.getNetworkId())
@@ -187,15 +217,25 @@
 
         }
 
+        long currentTime = System.currentTimeMillis();
+
         HostDescription hostDesc = new DefaultHostDescription(
                 macAddr,
                 VlanId.NONE,
-                new HostLocation(connectPoint, System.currentTimeMillis()),
+                new HostLocation(connectPoint, currentTime),
                 fixedIps,
                 annotations.build());
 
         HostId hostId = HostId.hostId(macAddr);
         hostProvider.hostDetected(hostId, hostDesc, false);
+
+        if (device != null && oldDevice != null && !oldDevice.equals(device)) {
+            Host oldHost = hostService.getHost(oldHostId);
+            Host newHost = new DefaultHost(oldHost.providerId(), hostId, macAddr,
+                    VlanId.NONE, new HostLocation(connectPoint, currentTime),
+                    fixedIps, annotations.build());
+            instancePortService.migrationPortAdded(HostBasedInstancePort.of(newHost));
+        }
     }
 
     /**
@@ -204,12 +244,37 @@
      * instance through host provider by giving connect point information,
      * and vanishes it.
      *
-     * @param port port object used in ONOS
+     * @param event device event
      */
-    private void processPortRemoved(Port port) {
+    private void processPortRemoved(DeviceEvent event) {
+        Port port = event.port();
+        DeviceId deviceId = event.subject().id();
         ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
-        hostService.getConnectedHosts(connectPoint)
-                    .forEach(host -> hostProvider.hostVanished(host.id()));
+
+        Set<Host> hostsToBeRemoved = hostService.getConnectedHosts(connectPoint);
+
+        if (hostsToBeRemoved.size() == 0) {
+
+            for (Host host : migratingHosts) {
+                if (host.location() == null) {
+                    continue;
+                }
+                String hostLocation = host.location().toString();
+                StringBuilder deviceIdWithPort = new StringBuilder();
+                deviceIdWithPort.append(deviceId.toString());
+                deviceIdWithPort.append("/");
+                deviceIdWithPort.append(port.number().toString());
+
+                if (hostLocation.equals(deviceIdWithPort.toString())) {
+                    InstancePort instPort = HostBasedInstancePort.of(host);
+                    instancePortService.migrationPortRemoved(instPort);
+                    migratingHosts.remove(host);
+                }
+            }
+
+        } else {
+            hostsToBeRemoved.forEach(host -> hostProvider.hostVanished(host.id()));
+        }
     }
 
     /**
@@ -274,7 +339,7 @@
             log.debug("Instance port {} is detected from {}",
                     event.port().annotations().value(PORT_NAME),
                     event.subject().id());
-            processPortAdded(event.port());
+            processPortAdded(event.port(), event.subject());
         });
     }
 
@@ -290,7 +355,7 @@
             log.debug("Instance port {} is removed from {}",
                     event.port().annotations().value(PORT_NAME),
                     event.subject().id());
-            processPortRemoved(event.port());
+            processPortRemoved(event);
         });
     }
 
@@ -343,7 +408,8 @@
                         log.debug("Instance port {} is detected from {}",
                                   port.annotations().value(PORT_NAME),
                                   osNode.hostname());
-                        processPortAdded(port);
+                        processPortAdded(port,
+                                deviceService.getDevice(osNode.intgBridge()));
                     });
 
             portNamePrefixMap().values().forEach(portNamePrefix -> {
@@ -355,7 +421,8 @@
                             log.debug("Instance port {} is detected from {}",
                                     port.annotations().value(portNamePrefix),
                                     osNode.hostname());
-                            processPortAdded(port);
+                            processPortAdded(port,
+                                    deviceService.getDevice(osNode.intgBridge()));
                         });
             });
 
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 2ebf9db..9914957 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
@@ -18,9 +18,11 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Strings;
 import org.onosproject.net.DeviceId;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknode.api.OpenstackAuth;
 import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
 import org.onosproject.openstacknode.api.OpenstackNode;
@@ -32,6 +34,8 @@
 import org.openstack4j.core.transport.ObjectMapperSingleton;
 import org.openstack4j.model.ModelEntity;
 import org.openstack4j.model.common.Identifier;
+import org.openstack4j.model.network.NetFloatingIP;
+import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.RouterInterface;
 import org.openstack4j.openstack.OSFactory;
@@ -78,6 +82,8 @@
     private static final String IDENTITY_PATH = "identity/";
     private static final String SSL_TYPE = "SSL";
 
+    private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
+
     /**
      * Prevents object instantiation from external.
      */
@@ -125,6 +131,57 @@
     }
 
     /**
+     * Obtains a floating IP associated with the given instance port.
+     *
+     * @param port instance port
+     * @param fips a collection of floating IPs
+     * @return associated floating IP
+     */
+    public static NetFloatingIP associatedFloatingIp(InstancePort port,
+                                                     Set<NetFloatingIP> fips) {
+        for (NetFloatingIP fip : fips) {
+            if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
+                continue;
+            }
+            if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
+                continue;
+            }
+            if (fip.getFixedIpAddress().equals(port.ipAddress().toString())) {
+                return fip;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Checks whether the given floating IP is associated with a VM.
+     *
+     * @param service openstack network service
+     * @param fip floating IP
+     * @return true if the given floating IP associated with a VM, false otherwise
+     */
+    public static boolean isAssociatedWithVM(OpenstackNetworkService service,
+                                             NetFloatingIP fip) {
+        Port osPort = service.port(fip.getPortId());
+        if (osPort == null) {
+            return false;
+        }
+
+        if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
+            Network osNet = service.network(osPort.getNetworkId());
+            if (osNet == null) {
+                final String errorFormat = ERR_FLOW + "no network(%s) exists";
+                final String error = String.format(errorFormat,
+                        fip.getFloatingIpAddress(), osPort.getNetworkId());
+                throw new IllegalStateException(error);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
      * Obtains the gateway node by instance port.
      *
      * @param gateways      a collection of gateway nodes
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 885c7d8..64c7747 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
@@ -54,6 +54,14 @@
     }
 
     @Override
+    public void migrationPortAdded(InstancePort port) {
+    }
+
+    @Override
+    public void migrationPortRemoved(InstancePort port) {
+    }
+
+    @Override
     public void addListener(InstancePortListener listener) {
 
     }