Merge branch 'master' into dev-karaf-4.2.1

Change-Id: Iec1b8947c898b0bf10db8caece0c3a064d1c63ae
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java
index 2d5c675..8263f63 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/InstancePortManager.java
@@ -224,6 +224,15 @@
     }
 
     @Override
+    public Set<InstancePort> instancePort(DeviceId deviceId) {
+        Set<InstancePort> ports = instancePortStore.instancePorts().stream()
+                .filter(port -> port.deviceId().equals(deviceId))
+                .collect(Collectors.toSet());
+
+        return ImmutableSet.copyOf(ports);
+    }
+
+    @Override
     public Set<InstancePort> instancePorts() {
         Set<InstancePort> ports = instancePortStore.instancePorts();
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index 731933f..7f34ad7 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -44,6 +44,7 @@
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.InstancePortAdminService;
 import org.onosproject.openstacknetworking.api.InstancePortEvent;
@@ -53,10 +54,11 @@
 import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
+import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
 import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
-import org.onosproject.openstacknetworking.api.OpenstackRouterService;
 import org.onosproject.openstacknetworking.api.PreCommitPortService;
+import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
@@ -64,6 +66,7 @@
 import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.IP;
 import org.openstack4j.model.network.NetFloatingIP;
+import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Router;
 import org.osgi.service.component.ComponentContext;
@@ -97,7 +100,9 @@
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -123,7 +128,7 @@
     protected OpenstackNetworkAdminService osNetworkAdminService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected OpenstackRouterService osRouterService;
+    protected OpenstackRouterAdminService osRouterAdminService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected OpenstackNodeService osNodeService;
@@ -173,7 +178,7 @@
         appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
         configService.registerProperties(getClass());
         localNodeId = clusterService.getLocalNode().id();
-        osRouterService.addListener(osRouterListener);
+        osRouterAdminService.addListener(osRouterListener);
         osNodeService.addListener(osNodeListener);
         osNetworkService.addListener(osNetworkListener);
         instancePortService.addListener(instPortListener);
@@ -186,7 +191,7 @@
     protected void deactivate() {
         packetService.removeProcessor(packetProcessor);
         instancePortService.removeListener(instPortListener);
-        osRouterService.removeListener(osRouterListener);
+        osRouterAdminService.removeListener(osRouterListener);
         osNodeService.removeListener(osNodeListener);
         osNetworkService.removeListener(osNetworkListener);
         instancePortService.removeListener(instPortListener);
@@ -220,7 +225,7 @@
 
             MacAddress targetMac = null;
 
-            NetFloatingIP floatingIP = osRouterService.floatingIps().stream()
+            NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
                     .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
                     .findAny().orElse(null);
 
@@ -358,14 +363,14 @@
                 if (completedGws.contains(gateway)) {
                     if (completedGws.size() > 1) {
                         finalGws.remove(gateway);
-                        osRouterService.floatingIps().forEach(fip -> {
+                        osRouterAdminService.floatingIps().forEach(fip -> {
                             if (fip.getPortId() != null) {
                                 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
                                 finalGws.add(gateway);
                             }
                         });
                     }
-                    osRouterService.floatingIps().forEach(fip -> {
+                    osRouterAdminService.floatingIps().forEach(fip -> {
                         if (fip.getPortId() != null) {
                             setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
                         }
@@ -376,14 +381,14 @@
             } else {
                 if (!completedGws.contains(gateway)) {
                     finalGws.add(gateway);
-                    osRouterService.floatingIps().forEach(fip -> {
+                    osRouterAdminService.floatingIps().forEach(fip -> {
                         if (fip.getPortId() != null) {
                             setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
                         }
                     });
                     finalGws.remove(gateway);
                     if (completedGws.size() >= 1) {
-                        osRouterService.floatingIps().forEach(fip -> {
+                        osRouterAdminService.floatingIps().forEach(fip -> {
                             if (fip.getPortId() != null) {
                                 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
                             }
@@ -729,14 +734,14 @@
         public void event(InstancePortEvent event) {
             InstancePort instPort = event.subject();
 
-            Set<NetFloatingIP> ips = osRouterService.floatingIps();
+            Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
             NetFloatingIP fip = associatedFloatingIp(instPort, ips);
             Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
 
             switch (event.type()) {
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
 
-                    osRouterService.floatingIps().stream()
+                    osRouterAdminService.floatingIps().stream()
                             .filter(f -> f.getPortId() != null)
                             .filter(f -> f.getPortId().equals(instPort.portId()))
                             .forEach(f -> setFloatingIpArpRule(f, instPort.portId(), gateways, true));
@@ -802,16 +807,68 @@
                 case OPENSTACK_NODE_COMPLETE:
                     setDefaultArpRule(osNode, true);
                     setFloatingIpArpRuleForGateway(osNode, true);
+                    sendGratuitousArpToSwitch(event.subject(), true);
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
                     setDefaultArpRule(osNode, false);
                     setFloatingIpArpRuleForGateway(osNode, false);
+                    sendGratuitousArpToSwitch(event.subject(), false);
                     break;
+                case OPENSTACK_NODE_REMOVED:
+                    sendGratuitousArpToSwitch(event.subject(), false);
+                    break;
+
                 default:
                     break;
             }
         }
 
+        private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode, boolean isCompleteCase) {
+            Set<OpenstackNode> completeGws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
+
+            if (isCompleteCase) {
+                osNodeService.completeNodes(COMPUTE)
+                        .stream()
+                        .filter(node -> isGwSelectedByComputeNode(completeGws, node, gatewayNode))
+                        .forEach(node -> processGratuitousArpPacketForComputeNode(node, gatewayNode));
+
+            } else {
+                Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
+                oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
+                oldCompleteGws.add(gatewayNode);
+
+                osNodeService.completeNodes(COMPUTE)
+                        .stream()
+                        .filter(node -> isGwSelectedByComputeNode(oldCompleteGws, node, gatewayNode))
+                        .forEach(node -> {
+                            OpenstackNode newSelectedGatewayNode = getGwByComputeDevId(completeGws, node.intgBridge());
+                            processGratuitousArpPacketForComputeNode(node, newSelectedGatewayNode);
+                        });
+            }
+        }
+
+        private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
+                                                  OpenstackNode computeNode,
+                                                  OpenstackNode gwNode) {
+            return OpenstackNetworkingUtil
+                    .getGwByComputeDevId(gws, computeNode.intgBridge())
+                    .intgBridge().equals(gwNode.intgBridge());
+        }
+
+        private void processGratuitousArpPacketForComputeNode(OpenstackNode computeNode, OpenstackNode gatewayNode) {
+            instancePortService.instancePort(computeNode.intgBridge()).forEach(instancePort -> {
+                NetFloatingIP floatingIP = OpenstackNetworkingUtil.floatingIpByInstancePort(instancePort,
+                        osRouterAdminService);
+                Network network = osNetworkService.network(instancePort.networkId());
+                ExternalPeerRouter externalPeerRouter = OpenstackNetworkingUtil.externalPeerRouterForNetwork(network,
+                        osNetworkService, osRouterAdminService);
+                if (floatingIP != null && externalPeerRouter != null) {
+                    processGratuitousArpPacketForFloatingIp(
+                            floatingIP, instancePort, externalPeerRouter.vlanId(), gatewayNode, packetService);
+                }
+            });
+        }
+
         private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
             switch (getArpMode()) {
                 case ARP_PROXY_MODE:
@@ -870,7 +927,7 @@
                     install
             );
 
-            osRouterService.routers().stream()
+            osRouterAdminService.routers().stream()
                     .filter(router -> router.getExternalGatewayInfo() != null)
                     .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
         }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index bf3285f..f1f1370 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -27,7 +27,6 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
-import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.LeadershipService;
 import org.onosproject.cluster.NodeId;
@@ -39,6 +38,7 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
@@ -57,14 +57,10 @@
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
-import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
-import org.openstack4j.model.network.Router;
-import org.openstack4j.model.network.RouterInterface;
-import org.openstack4j.model.network.Subnet;
 import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -85,9 +81,11 @@
 import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
 import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
-import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
@@ -103,8 +101,6 @@
     private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
     private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
 
-    private static final String USE_SECURITY_GROUP = "useSecurityGroup";
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected CoreService coreService;
 
@@ -118,9 +114,6 @@
     protected ClusterService clusterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected ComponentConfigService componentConfigService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected OpenstackNodeService osNodeService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
@@ -138,6 +131,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected PreCommitPortService preCommitPortService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected PacketService packetService;
+
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
     private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
@@ -187,15 +183,8 @@
 
         Network osNet = osNetworkService.network(instPort.networkId());
 
-        if (osNet == null) {
-            final String errorFormat = ERR_FLOW + "no network(%s) exists";
-            final String error = String.format(errorFormat,
-                    floatingIp.getFloatingIpAddress(),
-                    instPort.networkId());
-            throw new IllegalStateException(error);
-        }
-
-        ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
+        ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
+                osNetworkService, osRouterAdminService);
         if (externalPeerRouter == null) {
             final String errorFormat = ERR_FLOW + "no external peer router found";
             throw new IllegalStateException(errorFormat);
@@ -498,36 +487,6 @@
         log.trace("Succeeded to set flow rules for upstream on gateway nodes");
     }
 
-    private ExternalPeerRouter externalPeerRouter(Network network) {
-        if (network == null) {
-            return null;
-        }
-
-        Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
-
-        if (subnet == null) {
-            return null;
-        }
-
-        RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
-                .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
-                .findAny().orElse(null);
-        if (osRouterIface == null) {
-            return null;
-        }
-
-        Router osRouter = osRouterAdminService.router(osRouterIface.getId());
-        if (osRouter == null) {
-            return null;
-        }
-        if (osRouter.getExternalGatewayInfo() == null) {
-            return null;
-        }
-
-        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
-        return osNetworkService.externalPeerRouter(exGatewayInfo);
-    }
-
     private void associateFloatingIp(NetFloatingIP osFip) {
         InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
 
@@ -540,9 +499,31 @@
         // set floating IP rules only if the port is associated to a VM
         if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
             setFloatingIpRules(osFip, instPort, null, true);
+            processGratuitousArpPacket(osFip, instPort);
+
         }
     }
 
+    private void processGratuitousArpPacket(NetFloatingIP floatingIP,
+                                            InstancePort instancePort) {
+        Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
+
+        Network osNet = osNetworkService.network(instancePort.networkId());
+
+
+        OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
+        ExternalPeerRouter externalPeerRouter =
+                externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
+        if (externalPeerRouter == null) {
+            log.error("Failed to process GARP packet for floating ip {} because no external peer router found");
+            return;
+        }
+
+        processGratuitousArpPacketForFloatingIp(floatingIP, instancePort, externalPeerRouter.vlanId(),
+                selectedGw, packetService);
+
+    }
+
     private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
         InstancePort instPort = instancePortService.instancePort(portId);
 
@@ -708,7 +689,8 @@
                                 throw new IllegalStateException(error);
                             }
 
-                            ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
+                            ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
+                                    osNetworkService, osRouterAdminService);
                             if (externalPeerRouter == null) {
                                 final String errorFormat = ERR_FLOW + "no external peer router found";
                                 throw new IllegalStateException(errorFormat);
@@ -783,7 +765,7 @@
 
                     osPort = osNetworkService.port(fip.getPortId());
                     osNet = osNetworkService.network(osPort.getNetworkId());
-                    externalPeerRouter = externalPeerRouter(osNet);
+                    externalPeerRouter = externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
 
                     if (externalPeerRouter == null) {
                         final String errorFormat = ERR_FLOW + "no external peer router found";
@@ -816,7 +798,7 @@
 
                     osPort = osNetworkService.port(fip.getPortId());
                     osNet = osNetworkService.network(osPort.getNetworkId());
-                    externalPeerRouter = externalPeerRouter(osNet);
+                    externalPeerRouter = externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
 
                     if (externalPeerRouter == null) {
                         final String errorFormat = ERR_FLOW + "no external peer router found";
@@ -886,21 +868,12 @@
                     NetFloatingIP fip =
                             associatedFloatingIp(instPort, osRouterAdminService.floatingIps());
 
-                    boolean sgFlag = getPropertyValueAsBoolean(
-                            componentConfigService.getProperties(
-                                    OpenstackSecurityGroupHandler.class.getName()),
-                            USE_SECURITY_GROUP);
-
                     if (fip != null) {
                         instancePortService.updateInstancePort(
                                             instPort.updateState(REMOVE_PENDING));
                         eventExecutor.execute(() -> updateFipStore(event.port().getId()));
                     } else {
-                        // FIXME: we have dependency with security group, need to
-                        // find a better way to remove this dependency
-                        if (!sgFlag) {
-                            instancePortService.removeInstancePort(instPort.portId());
-                        }
+                        instancePortService.removeInstancePort(instPort.portId());
                     }
                     break;
                 default:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
index b759bff..4701d9c 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
@@ -26,6 +26,7 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
+import org.onlab.util.KryoNamespace;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cluster.ClusterService;
@@ -52,15 +53,23 @@
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupEvent;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
-import org.onosproject.openstacknetworking.api.PreCommitPortService;
 import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.SecurityGroup;
 import org.openstack4j.model.network.SecurityGroupRule;
+import org.openstack4j.model.network.State;
+import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
+import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
+import org.openstack4j.openstack.networking.domain.NeutronIP;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
 import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
@@ -73,6 +82,8 @@
 
 import java.util.Collections;
 import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -90,8 +101,7 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_RULE;
-import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVE_PENDING;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtMaskFlag;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtStateFlag;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
@@ -146,7 +156,18 @@
     protected ClusterService clusterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected PreCommitPortService preCommitPortService;
+    protected StorageService storageService;
+
+    private static final KryoNamespace SERIALIZER_PORT = KryoNamespace.newBuilder()
+            .register(KryoNamespaces.API)
+            .register(Port.class)
+            .register(NeutronPort.class)
+            .register(NeutronIP.class)
+            .register(State.class)
+            .register(NeutronAllowedAddressPair.class)
+            .register(NeutronExtraDhcpOptCreate.class)
+            .register(LinkedHashMap.class)
+            .build();
 
     private final InstancePortListener instancePortListener =
                                         new InternalInstancePortListener();
@@ -157,6 +178,9 @@
     private final OpenstackSecurityGroupListener securityGroupListener =
                                         new InternalSecurityGroupListener();
     private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
+
+    private ConsistentMap<String, Port> removedOsPortStore;
+
     private ApplicationId appId;
     private NodeId localNodeId;
 
@@ -196,6 +220,12 @@
         configService.registerProperties(getClass());
         osNodeService.addListener(osNodeListener);
 
+        removedOsPortStore = storageService.<String, Port>consistentMapBuilder()
+                .withSerializer(Serializer.using(SERIALIZER_PORT))
+                .withName("openstack-removed-portstore")
+                .withApplicationId(appId)
+                .build();
+
         log.info("Started");
     }
 
@@ -254,6 +284,20 @@
 
     private void setSecurityGroupRules(InstancePort instPort,
                                        Port port, boolean install) {
+
+        if (!install) {
+            Port rmvPort = removedOsPortStore.asJavaMap().get(instPort.portId());
+            if (port == null && rmvPort == null) {
+                return;
+            }
+
+            if (port == null) {
+                port = rmvPort;
+            }
+        }
+
+        final Port finalPort = port;
+
         port.getSecurityGroups().forEach(sgId -> {
             SecurityGroup sg = securityGroupService.securityGroup(sgId);
             if (sg == null) {
@@ -261,20 +305,10 @@
                 return;
             }
             sg.getRules().forEach(sgRule ->
-                    updateSecurityGroupRule(instPort, port, sgRule, install));
+                    updateSecurityGroupRule(instPort, finalPort, sgRule, install));
             final String action = install ? "Installed " : "Removed ";
             log.debug(action + "security group rule ID : " + sgId);
         });
-
-        if (install) {
-            preCommitPortService.subscribePreCommit(instPort.portId(),
-                    OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
-            log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
-        } else {
-            preCommitPortService.unsubscribePreCommit(instPort.portId(),
-                    OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
-            log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
-        }
     }
 
     private void updateSecurityGroupRule(InstancePort instPort, Port port,
@@ -285,7 +319,7 @@
         }
 
         if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
-            getRemoteInstPorts(port.getTenantId(), sgRule.getRemoteGroupId())
+            getRemoteInstPorts(port.getTenantId(), sgRule.getRemoteGroupId(), install)
                     .forEach(rInstPort -> {
                         populateSecurityGroupRule(sgRule, instPort, port,
                                 rInstPort.ipAddress().toIpPrefix(), install);
@@ -408,10 +442,16 @@
      * @param sgId security group id
      * @return set of ip addresses
      */
-    private Set<InstancePort> getRemoteInstPorts(String tenantId, String sgId) {
+    private Set<InstancePort> getRemoteInstPorts(String tenantId, String sgId, boolean install) {
         Set<InstancePort> remoteInstPorts;
 
-        remoteInstPorts = osNetService.ports().stream()
+        Set<Port> removedPorts = Sets.newConcurrentHashSet();
+
+        if (!install) {
+            removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
+        }
+
+        remoteInstPorts = Sets.union(osNetService.ports(), removedPorts).stream()
                 .filter(port -> port.getTenantId().equals(tenantId))
                 .filter(port -> port.getSecurityGroups().contains(sgId))
                 .map(port -> instancePortService.instancePort(port.getId()))
@@ -601,7 +641,9 @@
     }
 
     private void securityGroupRuleRemoved(SecurityGroupRule sgRule) {
-        osNetService.ports().stream()
+        Set<Port> removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
+
+        Sets.union(osNetService.ports(), removedPorts).stream()
                 .filter(port -> port.getSecurityGroups()
                                     .contains(sgRule.getSecurityGroupId()))
                 .forEach(port -> {
@@ -709,23 +751,38 @@
             InstancePort instPort = event.subject();
             switch (event.type()) {
                 case OPENSTACK_INSTANCE_PORT_UPDATED:
-                    if (instPort.state() == REMOVE_PENDING) {
-                        break;
-                    }
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
-                    log.debug("Instance port detected MAC:{} IP:{}",
-                            instPort.macAddress(),
-                            instPort.ipAddress());
-                    eventExecutor.execute(() -> {
-                        setSecurityGroupRules(instPort,
-                                osNetService.port(event.subject().portId()),
-                                true);
-                    });
+                case OPENSTACK_INSTANCE_MIGRATION_STARTED:
+                    installSecurityGroupRules(event, instPort);
+                    break;
+                case OPENSTACK_INSTANCE_PORT_VANISHED:
+                    Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
+                    eventExecutor.execute(() ->
+                            setSecurityGroupRules(instPort, osPort, false)
+                    );
+                    removedOsPortStore.remove(instPort.portId());
+                    break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+                    InstancePort revisedInstPort = swapStaleLocation(instPort);
+                    Port port = osNetService.port(instPort.portId());
+                    eventExecutor.execute(() ->
+                            setSecurityGroupRules(revisedInstPort, port, false));
                     break;
                 default:
                     break;
             }
         }
+
+        private void installSecurityGroupRules(InstancePortEvent event,
+                                               InstancePort instPort) {
+            log.debug("Instance port detected/updated MAC:{} IP:{}",
+                    instPort.macAddress(),
+                    instPort.ipAddress());
+            eventExecutor.execute(() -> {
+                setSecurityGroupRules(instPort,
+                        osNetService.port(event.subject().portId()), true);
+            });
+        }
     }
 
     private class InternalOpenstackPortListener implements OpenstackNetworkListener {
@@ -749,15 +806,10 @@
         public void event(OpenstackNetworkEvent event) {
             log.debug("openstack port event received {}", event);
             Port osPort = event.port();
-            InstancePort instPort = instancePortService.instancePort(osPort.getId());
 
             switch (event.type()) {
                 case OPENSTACK_PORT_PRE_REMOVE:
-                    instancePortService.updateInstancePort(
-                                        instPort.updateState(REMOVE_PENDING));
-                    eventExecutor.execute(() ->
-                        setSecurityGroupRules(instPort, osPort, false)
-                    );
+                    removedOsPortStore.put(osPort.getId(), osPort);
                     break;
                 default:
                     // do nothing for the other events
@@ -820,6 +872,11 @@
 
         @Override
         public boolean isRelevant(OpenstackSecurityGroupEvent event) {
+            // do not allow to proceed without leadership
+            NodeId leader = leadershipService.getLeader(appId.name());
+            if (!Objects.equals(localNodeId, leader)) {
+                return false;
+            }
             return useSecurityGroup;
         }
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index 6d1e038..c1ea3cd 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -219,7 +219,7 @@
 
         IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
 
-        MacAddress replyMac = gatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
+        MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
                 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
         if (replyMac == MacAddress.NONE) {
             log.trace("Failed to find MAC address for {}", targetIp);
@@ -241,8 +241,16 @@
                 ByteBuffer.wrap(ethReply.serialize())));
     }
 
-    private boolean gatewayIp(IpAddress targetIp) {
+    /**
+     * Denotes whether the given target IP is gateway IP.
+     *
+     * @param targetIp target IP address
+     * @return true if the given targetIP is gateway IP, false otherwise.
+     */
+    private boolean isGatewayIp(IpAddress targetIp) {
         return osNetworkService.subnets().stream()
+                .filter(Objects::nonNull)
+                .filter(subnet -> subnet.getGateway() != null)
                 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
     }
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index b755017..db15e15 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -42,11 +42,21 @@
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.cfg.ConfigProperty;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants.VnicType;
+import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
@@ -63,10 +73,13 @@
 import org.openstack4j.core.transport.ObjectMapperSingleton;
 import org.openstack4j.model.ModelEntity;
 import org.openstack4j.model.common.Identifier;
+import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Router;
 import org.openstack4j.model.network.RouterInterface;
+import org.openstack4j.model.network.Subnet;
 import org.openstack4j.openstack.OSFactory;
 import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
 import org.slf4j.Logger;
@@ -84,6 +97,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.ByteBuffer;
 import java.security.cert.X509Certificate;
 import java.util.Collection;
 import java.util.HashMap;
@@ -846,11 +860,126 @@
         return traceResult;
     }
 
+    /**
+     * Returns the floating ip with supplied instance port.
+     *
+     * @param instancePort instance port
+     * @param osRouterAdminService openstack router admin service
+     * @return floating ip
+     */
+    public static NetFloatingIP floatingIpByInstancePort(InstancePort instancePort,
+                                                         OpenstackRouterAdminService osRouterAdminService) {
+        return osRouterAdminService.floatingIps().stream()
+                .filter(netFloatingIP -> netFloatingIP.getPortId() != null)
+                .filter(netFloatingIP -> netFloatingIP.getPortId().equals(instancePort.portId()))
+                .findAny().orElse(null);
+    }
+
+    /**
+     * Sends GARP packet with supplied floating ip information.
+     *
+     * @param floatingIP floating ip
+     * @param instancePort instance port
+     * @param vlanId vlain id
+     * @param gatewayNode gateway node
+     * @param packetService packet service
+     */
+    public static void processGratuitousArpPacketForFloatingIp(NetFloatingIP floatingIP,
+                                                               InstancePort instancePort,
+                                                               VlanId vlanId,
+                                                               OpenstackNode gatewayNode,
+                                                               PacketService packetService) {
+        Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(gatewayNode.uplinkPortNum()).build();
+
+        packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
+                ByteBuffer.wrap(ethernet.serialize())));
+    }
+
+    /**
+     * Returns the external peer router with supplied network information.
+     *
+     * @param network network
+     * @param osNetworkService openstack network service
+     * @param osRouterAdminService openstack router admin service
+     * @return external peer router
+     */
+    public static ExternalPeerRouter externalPeerRouterForNetwork(Network network,
+                                                                  OpenstackNetworkService osNetworkService,
+                                                                  OpenstackRouterAdminService osRouterAdminService) {
+        if (network == null) {
+            return null;
+        }
+
+        Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
+
+        if (subnet == null) {
+            return null;
+        }
+
+        RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
+                .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
+                .findAny().orElse(null);
+        if (osRouterIface == null) {
+            return null;
+        }
+
+        Router osRouter = osRouterAdminService.router(osRouterIface.getId());
+        if (osRouter == null) {
+            return null;
+        }
+        if (osRouter.getExternalGatewayInfo() == null) {
+            return null;
+        }
+
+        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
+        return osNetworkService.externalPeerRouter(exGatewayInfo);
+
+    }
+
     private static boolean isDirectPort(String portName) {
         return portNamePrefixMap().values().stream().anyMatch(p -> portName.startsWith(p));
     }
 
     /**
+     * Returns GARP packet with supplied floating ip and instance port information.
+     *
+     * @param floatingIP floating ip
+     * @param instancePort instance port
+     * @param vlanId vlan id
+     * @return GARP packet
+     */
+    private static Ethernet buildGratuitousArpPacket(NetFloatingIP floatingIP,
+                                                     InstancePort instancePort,
+                                                     VlanId vlanId) {
+        Ethernet ethernet = new Ethernet();
+        ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
+        ethernet.setSourceMACAddress(instancePort.macAddress());
+        ethernet.setEtherType(Ethernet.TYPE_ARP);
+        ethernet.setVlanID(vlanId.id());
+
+        ARP arp = new ARP();
+        arp.setOpCode(ARP.OP_REPLY);
+        arp.setProtocolType(ARP.PROTO_TYPE_IP);
+        arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
+
+        arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
+        arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
+
+        arp.setSenderHardwareAddress(instancePort.macAddress().toBytes());
+        arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
+
+        arp.setSenderProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
+        arp.setTargetProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
+
+        ethernet.setPayload(arp);
+
+        return ethernet;
+    }
+
+    /**
      * Builds up and a complete endpoint URL from gateway node.
      *
      * @param node gateway node