Sends GARP packet when floating ip is associated and the gateway node is changed.

Change-Id: I1bd9deb2574d97473ef9709321944116904aec8d
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
index 96d111c..f1a5fe0 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
@@ -48,6 +48,8 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.PacketService;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
@@ -55,6 +57,7 @@
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.slf4j.Logger;
 
+import java.nio.ByteBuffer;
 import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 
@@ -70,6 +73,7 @@
 import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
 import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
 import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VXLAN;
+import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.buildGarpPacket;
 import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.externalPatchPortNum;
 import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.gatewayNodeForSpecifiedRouter;
 import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getRouterMacAddress;
@@ -97,6 +101,9 @@
     protected DeviceAdminService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected PacketService packetService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected KubevirtPortService kubevirtPortService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
@@ -148,9 +155,10 @@
         log.info("Stopped");
     }
 
-    private void setFloatingIpRules(KubevirtRouter router,
-                                    KubevirtFloatingIp floatingIp,
-                                    boolean install) {
+    private void setFloatingIpRulesForFip(KubevirtRouter router,
+                                          KubevirtFloatingIp floatingIp,
+                                          KubevirtNode electedGw,
+                                          boolean install) {
 
         KubevirtPort kubevirtPort = getKubevirtPort(floatingIp);
         if (kubevirtPort == null) {
@@ -164,24 +172,16 @@
             setFloatingIpDownstreamRulesToGatewayTunBridge(router, floatingIp, kubevirtNetwork, kubevirtPort, install);
         }
 
-        setFloatingIpArpResponseRules(router, floatingIp, kubevirtPort, install);
-        setFloatingIpUpstreamRules(router, floatingIp, kubevirtPort, install);
-        setFloatingIpDownstreamRules(router, floatingIp, kubevirtPort, install);
+        setFloatingIpArpResponseRules(router, floatingIp, kubevirtPort, electedGw, install);
+        setFloatingIpUpstreamRules(router, floatingIp, kubevirtPort, electedGw, install);
+        setFloatingIpDownstreamRules(router, floatingIp, kubevirtPort, electedGw, install);
     }
 
     private void setFloatingIpArpResponseRules(KubevirtRouter router,
                                                KubevirtFloatingIp floatingIp,
                                                KubevirtPort port,
+                                               KubevirtNode electedGw,
                                                boolean install) {
-
-        KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
-
-        if (electedGw == null) {
-            log.warn("Failed to install floating Ip rules for floating ip {} " +
-                    "because there's no gateway assigned to it", floatingIp.floatingIp());
-            return;
-        }
-
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchInPort(externalPatchPortNum(deviceService, electedGw))
                 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
@@ -222,16 +222,9 @@
     private void setFloatingIpUpstreamRules(KubevirtRouter router,
                                             KubevirtFloatingIp floatingIp,
                                             KubevirtPort port,
+                                            KubevirtNode electedGw,
                                             boolean install) {
 
-        KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
-
-        if (electedGw == null) {
-            log.warn("Failed to install floating Ip rules for floating ip {} " +
-                    "because there's no gateway assigned to it", floatingIp.floatingIp());
-            return;
-        }
-
         MacAddress peerMacAddress = router.peerRouter().macAddress();
 
         if (peerMacAddress == null) {
@@ -271,15 +264,8 @@
     private void setFloatingIpDownstreamRules(KubevirtRouter router,
                                               KubevirtFloatingIp floatingIp,
                                               KubevirtPort port,
+                                              KubevirtNode electedGw,
                                               boolean install) {
-        KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
-
-        if (electedGw == null) {
-            log.warn("Failed to install floating Ip rules for floating ip {} " +
-                    "because there's no gateway assigned to it", floatingIp.floatingIp());
-            return;
-        }
-
         MacAddress routerMacAddress = getRouterMacAddress(router);
 
         TrafficSelector selector = DefaultTrafficSelector.builder()
@@ -355,6 +341,31 @@
                 install);
     }
 
+    private void processGarpPacketForFloatingIp(KubevirtFloatingIp floatingIp, KubevirtNode electedGw) {
+
+        if (floatingIp == null) {
+            return;
+        }
+
+        KubevirtPort kubevirtPort = getKubevirtPort(floatingIp);
+        if (kubevirtPort == null) {
+            log.warn("Failed to install floating Ip rules for floating ip {} " +
+                    "because there's no kubevirt port associated to it", floatingIp.floatingIp());
+            return;
+        }
+
+        Ethernet ethernet = buildGarpPacket(kubevirtPort.macAddress(), floatingIp.floatingIp());
+        if (ethernet == null) {
+            return;
+        }
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(externalPatchPortNum(deviceService, electedGw)).build();
+
+        packetService.emit(new DefaultOutboundPacket(electedGw.intgBridge(), treatment,
+                ByteBuffer.wrap(ethernet.serialize())));
+    }
+
     private class InternalRouterEventListener implements KubevirtRouterListener {
         private boolean isRelevantHelper() {
             return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
@@ -371,25 +382,65 @@
                     eventExecutor.execute(() -> processFloatingIpDisassociation(event.subject(),
                             event.floatingIp()));
                     break;
-
+                case KUBEVIRT_GATEWAY_NODE_CHANGED:
+                    eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
+                            event.gateway()));
+                    break;
                 default:
                     //do nothing
                     break;
             }
         }
 
+        private void processRouterGatewayNodeChanged(KubevirtRouter router, String disAssociatedGateway) {
+
+            kubevirtRouterService.floatingIps()
+                    .stream()
+                    .filter(fip -> fip.routerName().equals(router.name())).forEach(fip -> {
+                        KubevirtNode oldGw = kubevirtNodeService.node(disAssociatedGateway);
+                        if (oldGw == null) {
+                            return;
+                        }
+
+                        KubevirtNode newGw = kubevirtNodeService.node(router.electedGateway());
+                        if (newGw == null) {
+                            return;
+                        }
+
+                        setFloatingIpRulesForFip(router, fip, oldGw, false);
+
+                        setFloatingIpRulesForFip(router, fip, newGw, true);
+                        processGarpPacketForFloatingIp(fip, newGw);
+
+            });
+        }
+
         private void processFloatingIpAssociation(KubevirtRouter router, KubevirtFloatingIp floatingIp) {
-            if (!isRelevantHelper()) {
+            if (!isRelevantHelper() || router.electedGateway() == null) {
                 return;
             }
-            setFloatingIpRules(router, floatingIp, true);
+
+            KubevirtNode electedGw = kubevirtNodeService.node(router.electedGateway());
+
+            if (electedGw == null) {
+                return;
+            }
+
+            processGarpPacketForFloatingIp(floatingIp, electedGw);
+            setFloatingIpRulesForFip(router, floatingIp, electedGw, true);
         }
 
         private void processFloatingIpDisassociation(KubevirtRouter router, KubevirtFloatingIp floatingIp) {
-            if (!isRelevantHelper()) {
+            if (!isRelevantHelper() || router.electedGateway() == null) {
                 return;
             }
-            setFloatingIpRules(router, floatingIp, false);
+
+            KubevirtNode electedGw = kubevirtNodeService.node(router.electedGateway());
+
+            if (electedGw == null) {
+                return;
+            }
+            setFloatingIpRulesForFip(router, floatingIp, electedGw, false);
         }
     }
 
@@ -413,20 +464,21 @@
         }
 
         private void processNodeCompletion(KubevirtNode node) {
-            if (!isRelevantHelper()) {
+            if (!isRelevantHelper() || !node.type().equals(KubevirtNode.Type.GATEWAY)) {
                 return;
             }
 
             kubevirtRouterService.floatingIps().forEach(fip -> {
                 KubevirtRouter router = kubevirtRouterService.router(fip.routerName());
-                if (router != null) {
-                    KubevirtNode electedGw = gatewayNodeForSpecifiedRouter(kubevirtNodeService, router);
+
+                if (router != null && router.electedGateway() != null) {
+                    KubevirtNode electedGw = kubevirtNodeService.node(router.electedGateway());
                     if (electedGw == null) {
                         return;
                     }
 
                     if (electedGw.hostname().equals(node.hostname())) {
-                        setFloatingIpRules(router, fip, true);
+                        setFloatingIpRulesForFip(router, fip, electedGw, true);
                     }
                 }
             });