Fix: specify the correct ARP THA and TPA for ARP reply packet

Change-Id: I3a2a100b50d1ea5875984fc31339df9ad75b53a1
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 0e09b03..6b96dfa 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
@@ -31,6 +31,7 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.Device;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -98,6 +99,9 @@
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
+import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
+import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
+import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 
 /**
@@ -338,24 +342,37 @@
                     .matchArpOp(ARP.OP_REQUEST)
                     .matchArpTpa(Ip4Address.valueOf(gateway));
 
-            tBuilder.setArpOp(ARP.OP_REPLY)
-                    .setArpSha(MacAddress.valueOf(gatewayMac))
-                    .setArpSpa(Ip4Address.valueOf(gateway))
-                    .setOutput(PortNumber.IN_PORT);
-
             if (osNode == null) {
-                osNodeService.completeNodes(COMPUTE).forEach(n ->
-                        osFlowRuleService.setRule(
-                                appId,
-                                n.intgBridge(),
-                                sBuilder.build(),
-                                tBuilder.build(),
-                                PRIORITY_ARP_GATEWAY_RULE,
-                                ARP_TABLE,
-                                install
-                        )
-                );
+                osNodeService.completeNodes(COMPUTE).forEach(n -> {
+                    Device device = deviceService.getDevice(n.intgBridge());
+                    tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
+                            .extension(buildMoveArpShaToThaExtension(device), device.id())
+                            .extension(buildMoveArpSpaToTpaExtension(device), device.id())
+                            .setArpOp(ARP.OP_REPLY)
+                            .setArpSha(MacAddress.valueOf(gatewayMac))
+                            .setArpSpa(Ip4Address.valueOf(gateway))
+                            .setOutput(PortNumber.IN_PORT);
+
+                    osFlowRuleService.setRule(
+                            appId,
+                            n.intgBridge(),
+                            sBuilder.build(),
+                            tBuilder.build(),
+                            PRIORITY_ARP_GATEWAY_RULE,
+                            ARP_TABLE,
+                            install
+                    );
+                });
             } else {
+                Device device = deviceService.getDevice(osNode.intgBridge());
+                tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
+                        .extension(buildMoveArpShaToThaExtension(device), device.id())
+                        .extension(buildMoveArpSpaToTpaExtension(device), device.id())
+                        .setArpOp(ARP.OP_REPLY)
+                        .setArpSha(MacAddress.valueOf(gatewayMac))
+                        .setArpSpa(Ip4Address.valueOf(gateway))
+                        .setOutput(PortNumber.IN_PORT);
+
                 osFlowRuleService.setRule(
                         appId,
                         osNode.intgBridge(),
@@ -366,7 +383,6 @@
                         install
                 );
             }
-
         }
     }
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java
index 77a66ab..bc7ecba 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java
@@ -36,6 +36,8 @@
 import java.util.List;
 
 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_LOAD;
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SHA_TO_THA;
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SPA_TO_TPA;
 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ETH_SRC_TO_DST;
 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_IP_SRC_TO_DST;
 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_POP_NSH;
@@ -140,8 +142,7 @@
                                                     DeviceId deviceId,
                                                     Ip4Address remoteIp) {
         Device device = deviceService.getDevice(deviceId);
-        if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
-            log.error("The extension treatment is not supported");
+        if (!checkTreatmentResolver(device)) {
             return null;
         }
 
@@ -202,8 +203,7 @@
     public static ExtensionTreatment buildLoadExtension(Device device,
                                                         long field,
                                                         long value) {
-        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
-            log.warn("Nicira extension treatment is not supported");
+        if (!checkTreatmentResolver(device)) {
             return null;
         }
 
@@ -232,8 +232,7 @@
      * @return push extension treatment
      */
     public static ExtensionTreatment buildPushExtension(Device device) {
-        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
-            log.warn("Nicira extension treatment is not supported");
+        if (!checkTreatmentResolver(device)) {
             return null;
         }
 
@@ -248,8 +247,7 @@
      * @return pop extension treatment
      */
     public static ExtensionTreatment buildPopExtension(Device device) {
-        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
-            log.warn("Nicira extension treatment is not supported");
+        if (!checkTreatmentResolver(device)) {
             return null;
         }
 
@@ -264,8 +262,7 @@
      * @return move extension treatment
      */
     public static ExtensionTreatment buildMoveEthSrcToDstExtension(Device device) {
-        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
-            log.warn("Nicira extension treatment is not supported");
+        if (!checkTreatmentResolver(device)) {
             return null;
         }
 
@@ -280,8 +277,7 @@
      * @return move extension treatment
      */
     public static ExtensionTreatment buildMoveIpSrcToDstExtension(Device device) {
-        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
-            log.warn("Nicira extension treatment is not supported");
+        if (!checkTreatmentResolver(device)) {
             return null;
         }
 
@@ -290,6 +286,36 @@
     }
 
     /**
+     * Returns the nicira move ARP SHA to THA extension treatment.
+     *
+     * @param device        device instance
+     * @return move extension treatment
+     */
+    public static ExtensionTreatment buildMoveArpShaToThaExtension(Device device) {
+        if (!checkTreatmentResolver(device)) {
+            return null;
+        }
+
+        ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+        return resolver.getExtensionInstruction(NICIRA_MOV_ARP_SHA_TO_THA.type());
+    }
+
+    /**
+     * Returns the nicira move ARP SPA to TPA extension treatment.
+     *
+     * @param device        device instance
+     * @return move extension treatment
+     */
+    public static ExtensionTreatment buildMoveArpSpaToTpaExtension(Device device) {
+        if (!checkTreatmentResolver(device)) {
+            return null;
+        }
+
+        ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+        return resolver.getExtensionInstruction(NICIRA_MOV_ARP_SPA_TO_TPA.type());
+    }
+
+    /**
      * Computes ConnTack State flag values.
      *
      * @param isTracking true for +trk, false for -trk
@@ -349,6 +375,15 @@
         return ctMaskFlag;
     }
 
+    private static boolean checkTreatmentResolver(Device device) {
+        if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
+            log.warn("Nicira extension treatment is not supported");
+            return false;
+        }
+
+        return true;
+    }
+
     /**
      * Builder class for OVS Connection Tracking feature actions.
      */