Simplified the port handling logic for VM live migration case

Change-Id: Ib28978bb2ee62c4719261c38eebb72a006f81f19
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 831f53b..5be8b87 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
@@ -43,9 +43,9 @@
 import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.InstancePortAdminService;
 import org.onosproject.openstacknetworking.api.InstancePortEvent;
 import org.onosproject.openstacknetworking.api.InstancePortListener;
-import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
@@ -82,11 +82,14 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
 import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
+import static org.onosproject.openstacknetworking.api.InstancePort.State.PENDING_REMOVAL;
+import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVED;
 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.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.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 
@@ -117,7 +120,7 @@
     protected OpenstackNodeService osNodeService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected InstancePortService instancePortService;
+    protected InstancePortAdminService instancePortService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackRouterAdminService osRouterAdminService;
@@ -136,10 +139,7 @@
     private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
     private final InstancePortListener instPortListener = new InternalInstancePortListener();
 
-    private final Map<String, DeviceId> migrationPool = Maps.newConcurrentMap();
     private Map<String, Port> terminatedOsPorts = Maps.newConcurrentMap();
-    private Map<String, InstancePort> terminatedInstPorts = Maps.newConcurrentMap();
-    private Map<String, InstancePort> tobeRemovedInstPorts = Maps.newConcurrentMap();
     private Map<String, NetFloatingIP> pendingInstPortIds = Maps.newConcurrentMap();
 
     private ApplicationId appId;
@@ -189,21 +189,16 @@
         InstancePort instPort = instancePortService.instancePort(srcMac);
 
         if (instPort == null) {
-            instPort = tobeRemovedInstPorts.get(osPort.getId());
-            tobeRemovedInstPorts.remove(osPort.getId());
-        }
-
-        if (instPort == null) {
-            instPort = terminatedInstPorts.get(osPort.getId());
-        }
-
-        if (instPort == null) {
             final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
             final String error = String.format(errorFormat,
                     floatingIp.getFloatingIpAddress(), srcMac);
             throw new IllegalStateException(error);
         }
 
+        if (instPort.state() == PENDING_REMOVAL) {
+            instancePortService.updateInstancePort(instPort.updateState(REMOVED));
+        }
+
         ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
         if (externalPeerRouter == null) {
             final String errorFormat = ERR_FLOW + "no external peer router found";
@@ -638,12 +633,6 @@
         // set floating IP rules only if the port is associated to a VM
         if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
 
-            if (!tobeRemovedInstPorts.containsKey(osPort.getId()) &&
-                    terminatedInstPorts.containsKey(osPort.getId())) {
-                tobeRemovedInstPorts.put(osPort.getId(),
-                                    terminatedInstPorts.get(osPort.getId()));
-            }
-
             if (instancePortService.instancePort(osPort.getId()) == null) {
 
                 // in case there is pending instance port, we simply remove that
@@ -753,15 +742,6 @@
                                 continue;
                             }
 
-                            // This is for handling a VM, which is associated
-                            // with a floating IP, was terminated case
-                            // in this case, we cannot obtain instance port
-                            // information from a terminated VM, we simply
-                            // construct a pending map where key is terminated
-                            // instance port ID while value is floating IP
-                            // address which supposed to be associated with the
-                            // terminated instance port.
-
                             // Note that, at OPENSTACK_INSTANCE_PORT_DETECTED phase,
                             // we will install floating IP related rules by
                             // referring to the key and value stored in pending map
@@ -770,6 +750,7 @@
                                 pendingInstPortIds.put(fip.getPortId(), fip);
                                 continue;
                             }
+
                             setFloatingIpRules(fip, osPort, event.subject(), true);
                         }
                     });
@@ -863,7 +844,6 @@
                     if (instPort != null && instPort.portId() != null) {
                         String portId = instPort.portId();
 
-                        terminatedInstPorts.remove(portId);
                         terminatedOsPorts.remove(portId);
 
                         Port port = osNetworkService.port(portId);
@@ -877,19 +857,6 @@
 
                     break;
 
-                case OPENSTACK_INSTANCE_PORT_VANISHED:
-                    if (instPort != null && instPort.portId() != null) {
-                        String portId = instPort.portId();
-                        Port port = osNetworkService.port(portId);
-
-                        if (port != null) {
-                            terminatedInstPorts.put(portId, instPort);
-                            terminatedOsPorts.put(portId, port);
-                        }
-                    }
-
-                    break;
-
                 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
 
                     fip = associatedFloatingIp(event.subject(), ips);
@@ -923,14 +890,13 @@
                         // 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:
 
-                    fip = associatedFloatingIp(event.subject(), ips);
+                    InstancePort revisedInstPort = swapStaleLocation(event.subject());
+
+                    fip = associatedFloatingIp(revisedInstPort, ips);
 
                     if (fip == null) {
                         return;
@@ -956,9 +922,8 @@
                     // 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());
+                    DeviceId newDeviceId = event.subject().deviceId();
+                    DeviceId oldDeviceId = revisedInstPort.deviceId();
 
                     OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
                     OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
@@ -971,13 +936,13 @@
 
                         // We need to remove the old ComputeNodeToGateway rules from
                         // original compute node
-                        setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, false);
+                        setComputeNodeToGatewayHelper(revisedInstPort, 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);
+                        setDownstreamExternalRulesHelper(fip, osNet, revisedInstPort,
+                                externalPeerRouter, gateways, false);
                     });
                     break;
                 default:
@@ -999,10 +964,23 @@
         public void event(OpenstackNetworkEvent event) {
             switch (event.type()) {
                 case OPENSTACK_PORT_REMOVED:
-                    Port osPort = event.port();
-                    if (terminatedInstPorts.containsKey(osPort.getId())) {
-                        updateFipStore(terminatedInstPorts.get(osPort.getId()));
-                        terminatedInstPorts.remove(osPort.getId());
+                    String portId = event.port().getId();
+                    terminatedOsPorts.put(portId, event.port());
+
+                    InstancePort instPort = instancePortService.instancePort(portId);
+                    InstancePort updated = instPort.updateState(PENDING_REMOVAL);
+                    instancePortService.updateInstancePort(updated);
+
+                    updateFipStore(instPort);
+
+                    // we will hold the instance port in its store, until its
+                    // state is changed to REMOVED
+                    while (true) {
+                        if (instancePortService.instancePort(portId).state() ==
+                                REMOVED) {
+                            instancePortService.removeInstancePort(portId);
+                            break;
+                        }
                     }
                     break;
                 default:
@@ -1029,7 +1007,6 @@
                     // invalidate bound fixed IP and port
                     neutronFip.setFixedIpAddress(null);
                     neutronFip.setPortId(null);
-                    tobeRemovedInstPorts.put(port.portId(), port);
 
                     // Following update will in turn trigger
                     // OPENSTACK_FLOATING_IP_DISASSOCIATED event