[ONOS-5114] Fix to send icmp packet from vm to gateway when floating is assigned

Change-Id: Ia8ba62cfa38ee56a0f8d40545f728e47a902082c
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java
index 1af9dc6..df1d031 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java
@@ -59,6 +59,8 @@
     public static final int TUNNELTAG_RULE_PRIORITY = 30000;
     public static final int ACL_RULE_PRIORITY = 30000;
     public static final int EW_ROUTING_RULE_PRIORITY = 28000;
+
+    public static final int GATEWAY_ICMP_PRIORITY = 43000;
     public static final int ROUTING_RULE_PRIORITY = 25000;
     public static final int FLOATING_RULE_PRIORITY = 42000;
     public static final int PNAT_RULE_PRIORITY = 26000;
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
index add2634..31bb899 100644
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
+++ b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
@@ -23,6 +23,7 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
@@ -157,6 +158,8 @@
             return;
         }
 
+        setGatewayIcmp(Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));
+
         setRoutes(osRouter, Optional.empty());
         if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
             String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
@@ -176,13 +179,66 @@
         OpenstackSubnet osSubnet = openstackService.subnet(routerIface.subnetId());
         OpenstackNetwork osNet = openstackService.network(osSubnet.networkId());
 
+        unsetGatewayIcmp(Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));
+
         unsetRoutes(osRouter, osSubnet);
+
         if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
             unsetExternalConnection(osRouter, osNet.id());
         }
         log.info("Disconnected {} from router {}", osSubnet.cidr(), osRouter.name());
     }
 
+    private void setGatewayIcmp(Ip4Address gatewayIp) {
+        if (gatewayIp == null) {
+            return;
+        }
+        gatewayService.getGatewayDeviceIds().stream().forEach(deviceId -> {
+            populateGatewayIcmpRule(gatewayIp, deviceId);
+        });
+    }
+
+    private void populateGatewayIcmpRule(Ip4Address gatewayIp, DeviceId deviceId) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPProtocol(IPv4.PROTOCOL_ICMP)
+                .matchIPDst(gatewayIp.toIpPrefix());
+
+        tBuilder.setOutput(PortNumber.CONTROLLER);
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(GATEWAY_ICMP_PRIORITY)
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(deviceId, fo);
+    }
+
+    private void unsetGatewayIcmp(Ip4Address gatewayIp) {
+        if (gatewayIp == null) {
+            return;
+        }
+        gatewayService.getGatewayDeviceIds().forEach(deviceId -> {
+            removeGatewayIcmpRule(gatewayIp, deviceId);
+        });
+    }
+
+    private void removeGatewayIcmpRule(Ip4Address gatewayIp, DeviceId deviceId) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPProtocol(IPv4.PROTOCOL_ICMP)
+                .matchIPDst(gatewayIp.toIpPrefix());
+
+        RulePopulatorUtil.removeRule(flowObjectiveService, appId, deviceId, sBuilder.build(),
+                ForwardingObjective.Flag.VERSATILE, GATEWAY_ICMP_PRIORITY);
+
+    }
     private void setExternalConnection(OpenstackRouter osRouter, String osSubNetId) {
         if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
             log.debug("Source NAT is disabled");
@@ -462,6 +518,10 @@
                 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
                 .forEach(osPort -> {
                     OpenstackRouter osRouter = openstackRouter(osPort.deviceId());
+
+                    setGatewayIcmp(Ip4Address.valueOf(openstackService
+                            .subnet(osPort.fixedIps().keySet().stream().findAny().get()).gatewayIp()));
+
                     setRoutes(osRouter, Optional.empty());
                     if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
                         String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();