Re-doing Learning switch functionality changes
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
index 20f05e1..9d82fd6 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
@@ -9,6 +9,7 @@
 package net.onrc.onos.apps.segmentrouting;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
@@ -20,6 +21,7 @@
 import net.onrc.onos.core.packet.ARP;
 import net.onrc.onos.core.packet.Ethernet;
 import net.onrc.onos.core.packet.IPv4;
+import net.onrc.onos.core.topology.Host;
 import net.onrc.onos.core.topology.ITopologyService;
 import net.onrc.onos.core.topology.MutableTopology;
 import net.onrc.onos.core.topology.Port;
@@ -116,36 +118,86 @@
     private void handleArpRequest(Switch sw, Port inPort, Ethernet payload) {
 
     	ARP arpRequest = (ARP)payload.getPayload();
-        List<String> subnetGatewayIPs = getSubnetGatewayIps(sw);
-        String switchMacAddressStr = sw.getStringAttribute("routerMac");
-        if (!subnetGatewayIPs.isEmpty()) {
-            IPv4Address targetProtocolAddress = IPv4Address.of(arpRequest.getTargetProtocolAddress());
-            // Do we have to check port also ??
-            if (subnetGatewayIPs.contains(targetProtocolAddress.toString())) {
-                MACAddress targetMac = MACAddress.valueOf(switchMacAddressStr);
+    	MACAddress targetMac = null;
 
-                ARP arpReply = new ARP();
-                arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
-                        .setProtocolType(ARP.PROTO_TYPE_IP)
-                        .setHardwareAddressLength(
-                                (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
-                        .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
-                        .setOpCode(ARP.OP_REPLY)
-                        .setSenderHardwareAddress(targetMac.toBytes())
-                        .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
-                        .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
-                        .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
+    	if (isArpReqForSwitch(sw, arpRequest)) {
+            String switchMacAddressStr = sw.getStringAttribute("routerMac");
+            targetMac = MACAddress.valueOf(switchMacAddressStr);
+        	log.debug("ArpHandler: Received a ARP query for a sw {} ", sw.getDpid());
+    	}
 
-                Ethernet eth = new Ethernet();
-                eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
-                        .setSourceMACAddress(targetMac.toBytes())
-                        .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
+    	Host knownHost = isArpReqForKnownHost(sw, arpRequest);
+    	if (knownHost != null) {
+            targetMac = knownHost.getMacAddress();
+        	log.debug("ArpHandler: Received a ARP query for a known host {} ",
+        						IPv4Address.of(knownHost.getIpAddress()));
+    	}
 
-                sendPacketOut(sw, eth, inPort.getPortNumber().shortValue());
-            }
-        }
+    	if (targetMac != null) {
+    		/* ARP Destination is known. Packet out ARP Reply */
+            ARP arpReply = new ARP();
+            arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
+                    .setProtocolType(ARP.PROTO_TYPE_IP)
+                    .setHardwareAddressLength(
+                            (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
+                    .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
+                    .setOpCode(ARP.OP_REPLY)
+                    .setSenderHardwareAddress(targetMac.toBytes())
+                    .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
+                    .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
+                    .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
+
+            Ethernet eth = new Ethernet();
+            eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
+                    .setSourceMACAddress(targetMac.toBytes())
+                    .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
+
+            sendPacketOut(sw, eth, inPort.getPortNumber().shortValue());
+    	}
+    	else
+    	{
+    		/* Broadcast the received ARP request to all switch ports
+    		 * that subnets are connected to except the port from which
+    		 * ARP request is received
+    		 */
+        	log.debug("ArpHandler: Received a ARP query for unknown host {} ",
+        			IPv4Address.of(arpRequest.getTargetProtocolAddress()));
+    		for (Integer portNo : getSwitchSubnetPorts(sw)) {
+    			if (portNo.shortValue() == inPort.getPortNumber().shortValue())
+    				continue;
+            	log.debug("ArpHandler: Sending ARP request on switch {} port {}",
+            			sw.getDpid(), portNo.shortValue());
+                sendPacketOut(sw, payload, portNo.shortValue());
+    		}
+    	}
     }
 
+    private Host isArpReqForKnownHost(Switch sw, ARP arpRequest) {
+    	Host knownHost = null;
+
+        IPv4Address targetIPAddress = IPv4Address.of(
+        					arpRequest.getTargetProtocolAddress());
+
+        for (Host host:sw.getHosts()) {
+        	if (host.getIpAddress() == targetIPAddress.getInt()) {
+        		knownHost = host;
+        		break;
+        	}
+        }
+        return knownHost;
+
+    }
+    private boolean isArpReqForSwitch(Switch sw, ARP arpRequest) {
+        List<String> subnetGatewayIPs = getSubnetGatewayIps(sw);
+        boolean isArpForSwitch = false;
+        if (!subnetGatewayIPs.isEmpty()) {
+            IPv4Address targetProtocolAddress = IPv4Address.of(arpRequest.getTargetProtocolAddress());
+            if (subnetGatewayIPs.contains(targetProtocolAddress.toString())) {
+            	isArpForSwitch = true;
+            }
+        }
+        return isArpForSwitch;
+    }
     /**
      * Retrieve Gateway IP address of all subnets defined in net config file
      *
@@ -174,6 +226,24 @@
         return gatewayIps;
     }
 
+    private HashSet<Integer> getSwitchSubnetPorts(Switch sw) {
+        HashSet<Integer> switchSubnetPorts = new HashSet<Integer>();
+
+        String subnets = sw.getStringAttribute("subnets");
+        try {
+            JSONArray arry = new JSONArray(subnets);
+            for (int i = 0; i < arry.length(); i++) {
+                Integer subnetPort = (Integer)arry.getJSONObject(i).get("portNo");
+                switchSubnetPorts.add(subnetPort);
+            }
+        } catch (JSONException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        return switchSubnetPorts;
+    }
+
     /**
      * Send an ARP request
      *