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/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: