Learning switch functionality
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 a0b6aa7..e69de29 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
@@ -1,273 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 Open Networking Laboratory.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License v2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- ******************************************************************************/
-
-package net.onrc.onos.apps.segmentrouting;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.api.packet.IPacketListener;
-import net.onrc.onos.api.packet.IPacketService;
-import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
-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.ITopologyService;
-import net.onrc.onos.core.topology.MutableTopology;
-import net.onrc.onos.core.topology.Port;
-import net.onrc.onos.core.topology.Switch;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.U32;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.esotericsoftware.minlog.Log;
-
-/**
- * Handling ARP requests to switches for Segment Routing.
- * <p/>
- * The module is for handling ARP requests to switches. It sends ARP response for any known
- * hosts to the controllers.
- * TODO: need to check the network config file for all hosts and packets
- */
-public class ArpHandler implements IPacketListener  {
-
-    private static final Logger log = LoggerFactory
-            .getLogger(ArpHandler.class);
-
-    private IFloodlightProviderService floodlightProvider;
-    private IPacketService packetService;
-    private IFlowPusherService flowPusher;
-    private ITopologyService topologyService;
-    private MutableTopology mutableTopology;
-    //private List<ArpEntry> arpEntries;
-    private SegmentRoutingManager srManager;
-
-    private static final short IDLE_TIMEOUT = 0;
-    private static final short HARD_TIMEOUT = 0;
-
-    private static final int TABLE_VLAN = 0;
-    private static final int TABLE_TMAC = 1;
-    private static final int TABLE_IPv4_UNICAST = 2;
-    private static final int TABLE_MPLS = 3;
-    private static final int TABLE_META = 4;
-    private static final int TABLE_ACL = 5;
-
-    private static final short MAX_PRIORITY = (short) 0xffff;
-    private static final short SLASH_24_PRIORITY = (short) 0xfff0;
-    private static final short SLASH_16_PRIORITY = (short) 0xff00;
-    private static final short SLASH_8_PRIORITY = (short) 0xf000;
-    private static final short MIN_PRIORITY = 0x0;
-
-
-    /*
-     * Default Constructor
-     */
-    public ArpHandler(FloodlightModuleContext context, SegmentRoutingManager segmentRoutingManager) {
-
-        this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-        this.packetService = context.getServiceImpl(IPacketService.class);
-        this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
-        this.topologyService = context.getServiceImpl(ITopologyService.class);
-        this.srManager = segmentRoutingManager;
-        this.mutableTopology = topologyService.getTopology();
-
-        packetService.registerPacketListener(this);
-        //arpEntries = new ArrayList<ArpEntry>();
-
-        Log.debug("Arp Handler is initialized");
-
-    }
-
-    @Override
-    public void receive(Switch sw, Port inPort, Ethernet payload) {
-        log.debug("Received a packet {} from sw {} ", payload.toString(), sw.getDpid());
-
-        if (payload.getEtherType() == Ethernet.TYPE_ARP) {
-
-            ARP arp = (ARP)payload.getPayload();
-            srManager.updateArpCache(arp);
-
-            if (arp.getOpCode() == ARP.OP_REQUEST) {
-                handleArpRequest(sw, inPort, arp);
-            }
-            else {
-                byte[] senderMacAddressByte = arp.getSenderHardwareAddress();
-                String targetMacAddressStr = MacAddress.of(senderMacAddressByte).toString();
-                if (targetMacAddressStr.equals(sw.getStringAttribute("routerMac"))) {
-                    IPv4Address hostIpAddress = IPv4Address.of(arp.getSenderProtocolAddress());
-                    srManager.addRouteToHost(sw,hostIpAddress.getInt(), senderMacAddressByte);
-                }
-            }
-
-        }
-
-    }
-
-
-    /**
-     * Send an ARP response for the ARP request to the known switches
-     *
-     * @param sw Switch
-     * @param inPort port to send ARP response to
-     * @param arpRequest ARP request packet to handle
-     */
-    private void handleArpRequest(Switch sw, Port inPort, ARP arpRequest) {
-
-        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);
-
-                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());
-            }
-        }
-    }
-
-    /**
-     * Retrieve Gateway IP address of all subnets defined in net config file
-     *
-     * @param sw Switch to retrieve subnet GW IPs for
-     * @return list of GW IP addresses for all subnets
-     */
-    private List<String> getSubnetGatewayIps(Switch sw) {
-
-        List<String> gatewayIps = new ArrayList<String>();
-
-        String subnets = sw.getStringAttribute("subnets");
-        try {
-            JSONArray arry = new JSONArray(subnets);
-            for (int i = 0; i < arry.length(); i++) {
-                String subnetIpSlash = (String) arry.getJSONObject(i).get("subnetIp");
-                if (subnetIpSlash != null) {
-                    String subnetIp = subnetIpSlash.substring(0, subnetIpSlash.indexOf('/'));
-                    gatewayIps.add(subnetIp);
-                }
-            }
-        } catch (JSONException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-
-        return gatewayIps;
-    }
-
-    /**
-     * Send an ARP request
-     *
-     * @param sw Switch
-     * @param targetAddress Target IP address
-     * @param inPort Port to send the ARP request
-     *
-     */
-    public void sendArpRequest(Switch sw, int targetAddressInt, Port inPort) {
-
-        IPv4Address targetAddress = IPv4Address.of(targetAddressInt);
-        String senderMacAddressStr = sw.getStringAttribute("routerMac");
-        String senderIpAddressSlash = sw.getStringAttribute("routerIp");
-        if (senderMacAddressStr == null || senderIpAddressSlash == null)
-            return;
-        String senderIpAddressStr =
-                senderIpAddressSlash.substring(0, senderIpAddressSlash.indexOf('/'));
-        byte[] senderMacAddress = MacAddress.of(senderMacAddressStr).getBytes();
-        byte[] senderIpAddress = IPv4Address.of(senderIpAddressStr).getBytes();
-
-        ARP arpRequest = new ARP();
-        arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
-                .setProtocolType(ARP.PROTO_TYPE_IP)
-                .setHardwareAddressLength(
-                        (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
-                .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
-                .setOpCode(ARP.OP_REQUEST)
-                .setSenderHardwareAddress(senderMacAddress)
-                .setTargetHardwareAddress(MacAddress.NONE.getBytes())
-                .setSenderProtocolAddress(senderIpAddress)
-                .setTargetProtocolAddress(targetAddress.getBytes());
-
-        Ethernet eth = new Ethernet();
-        eth.setDestinationMACAddress(MacAddress.BROADCAST.getBytes())
-                .setSourceMACAddress(senderMacAddress)
-                .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
-
-        sendPacketOut(sw, eth, (short)-1);
-
-    }
-
-    /**
-     * Send PACKET_OUT packet to switch
-     *
-     * @param sw Switch to send the packet to
-     * @param packet Packet to send
-     * @param switchPort port to send (if -1, broadcast)
-     */
-    private void sendPacketOut(Switch sw, Ethernet packet, short port) {
-
-        IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
-        OFFactory factory = ofSwitch.getFactory();
-
-        List<OFAction> actions = new ArrayList<>();
-
-        if (port > 0) {
-            OFAction outport = factory.actions().output(OFPort.of(port), Short.MAX_VALUE);
-            actions.add(outport);
-        }
-        else {
-            Iterator<Port> iter = sw.getPorts().iterator();
-            while (iter.hasNext()) {
-                Port p = iter.next();
-                int pnum = p.getPortNumber().shortValue();
-                if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
-                    OFAction outport = factory.actions().output(OFPort.of(p.getNumber().shortValue()),
-                            Short.MAX_VALUE);
-                    actions.add(outport);
-                }
-            }
-        }
-
-        OFPacketOut po = factory.buildPacketOut()
-                .setData(packet.serialize())
-                .setActions(actions)
-                .build();
-
-        flowPusher.add(sw.getDpid(), po);
-    }
-
-}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java b/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java
index 5fa76ca..a5df74b 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java
@@ -203,10 +203,11 @@
                 ArrayList<ArrayList<Dpid>>>> getAllLearnedSwitchesAndVia() {
 
         HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>>
-            switchViaMap = new HashMap();
+            switchViaMap = new HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>>();
 
         for (Integer itrIndx : distanceSwitchMap.keySet()) {
-            HashMap<Switch, ArrayList<ArrayList<Dpid>>> swMap = new HashMap();
+            HashMap<Switch, ArrayList<ArrayList<Dpid>>> swMap =
+                    new HashMap<Switch, ArrayList<ArrayList<Dpid>>>();
 
             for (Switch sw : distanceSwitchMap.get(itrIndx)) {
                 ArrayList<ArrayList<Dpid>> swViaArray = new ArrayList<>();
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
index 7e6d2ac..e04ae85 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
@@ -76,8 +76,11 @@
     @Override
     public void receive(Switch sw, Port inPort, Ethernet payload) {
         // TODO Auto-generated method stub
-        if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
+        if ((payload.getEtherType() == Ethernet.TYPE_IPV4) &&
+            (((IPv4)payload.getPayload()).getProtocol() != IPv4.PROTOCOL_ICMP)){
 
+            log.debug("GenericIPHandler: Received a IP packet {} from sw {} ",
+                    payload.toString(), sw.getDpid());
             IPv4 ipv4 = (IPv4)payload.getPayload();
             int destinationAddress = ipv4.getDestinationAddress();
 
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
index b548e18..b8bbc99 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
@@ -12,6 +12,7 @@
 import net.onrc.onos.core.packet.Ethernet;
 import net.onrc.onos.core.packet.ICMP;
 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;
@@ -92,6 +93,9 @@
             IPv4 ipv4 = (IPv4)payload.getPayload();
 
             if (ipv4.getProtocol() == IPv4.PROTOCOL_ICMP) {
+
+                log.debug("ICMPHandler: Received a ICMP packet {} from sw {} ",
+                        payload.toString(), sw.getDpid());
                 int destinationAddress = ipv4.getDestinationAddress();
                 String destAddressStr = IPv4Address.of(destinationAddress).toString();
 
@@ -105,10 +109,35 @@
                     if (((ICMP)ipv4.getPayload()).getIcmpType() == ICMP_TYPE_ECHO &&
                             (destinationAddress == switchIpAddress.getInt() ||
                              gatewayIps.contains(destAddressStr))) {
+                        log.debug("ICMPHandler: ICMP packet for sw {} and "
+                                + "sending ICMP response ", sw.getDpid());
                         sendICMPResponse(sw, inPort, payload);
                         return;
                     }
                 }
+
+                /* Check if ICMP is for any switch known host */
+                for (Host host: sw.getHosts()) {
+                    IPv4Address hostIpAddress =
+                            IPv4Address.of(host.getIpAddress());
+                    if (hostIpAddress != null &&
+                            hostIpAddress.equals(destinationAddress)) {
+                        /* TODO: We should not have come here as ARP itself
+                         * would have installed a Route to the host. See if
+                         * we can remove this code
+                         */
+                        log.debug("ICMPHandler: ICMP request for known host {}",
+                                         hostIpAddress);
+                        byte[] destinationMacAddress = host.getMacAddress().toBytes();
+                        srManager.addRouteToHost(sw,
+                                destinationAddress, destinationMacAddress);
+                        return;
+                    }
+                }
+                /* ICMP for an unknown host */
+                log.debug("ICMPHandler: ICMP request for unknown host {}"
+                        + " and sending ARP request", destinationAddress);
+                srManager.sendArpRequest(sw, destinationAddress, inPort);
             }
 
         }