Original ArpHandler file
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 e69de29..fe4e6e3 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * 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);
+    }
+
+}
+