- Modified IcmpHandler and ArpHandler to check both routerIP and gateway information for all subnets
- Added GenericIpHandler to set a routing rule to any known host for any IPv4 packets
- Modified ArpHandler so that as soon as it receives ARP response, it sets a routing rule to the host
- Use FlowPusher instead of PacketService in ArpHandler

Change-Id: Ie7d72e688a7d19624b5595f344c6f201f58ee9c1
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 fc6c02e..a0b6aa7 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
@@ -8,7 +8,12 @@
 
 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;
@@ -21,9 +26,16 @@
 import net.onrc.onos.core.topology.MutableTopology;
 import net.onrc.onos.core.topology.Port;
 import net.onrc.onos.core.topology.Switch;
-import net.onrc.onos.core.util.SwitchPort;
 
+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;
 
@@ -95,9 +107,16 @@
             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);
+                }
+            }
 
         }
 
@@ -113,14 +132,12 @@
      */
     private void handleArpRequest(Switch sw, Port inPort, ARP arpRequest) {
 
-        String switchIpAddressSlash = sw.getStringAttribute("routerIp");
+        List<String> subnetGatewayIPs = getSubnetGatewayIps(sw);
         String switchMacAddressStr = sw.getStringAttribute("routerMac");
-        if (switchIpAddressSlash != null && switchMacAddressStr != null) {
-
-            String switchIpAddressStr = switchIpAddressSlash.substring(0, switchIpAddressSlash.indexOf('/'));
-            IPv4Address switchIpAddress = IPv4Address.of(switchIpAddressStr);
+        if (!subnetGatewayIPs.isEmpty()) {
             IPv4Address targetProtocolAddress = IPv4Address.of(arpRequest.getTargetProtocolAddress());
-            if (targetProtocolAddress.equals(switchIpAddress)) {
+            // Do we have to check port also ??
+            if (subnetGatewayIPs.contains(targetProtocolAddress.toString())) {
                 MACAddress targetMac = MACAddress.valueOf(switchMacAddressStr);
 
                 ARP arpReply = new ARP();
@@ -140,14 +157,117 @@
                         .setSourceMACAddress(targetMac.toBytes())
                         .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
 
-                packetService.sendPacket(eth, new SwitchPort(sw.getDpid(), inPort.getPortNumber()));
+                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/GenericIpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
new file mode 100644
index 0000000..7e6d2ac
--- /dev/null
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
@@ -0,0 +1,202 @@
+package net.onrc.onos.apps.segmentrouting;
+
+import java.util.ArrayList;
+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.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.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMatchV3;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFOxmList;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GenericIpHandler implements IPacketListener {
+
+    private MutableTopology mutableTopology;
+    private ITopologyService topologyService;
+    private IFloodlightProviderService floodlightProvider;
+    private IFlowPusherService flowPusher;
+    private IPacketService packetService;
+    private SegmentRoutingManager srManager;
+
+    private static final Logger log = LoggerFactory
+            .getLogger(GenericIpHandler.class);
+
+    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;
+
+    public GenericIpHandler(FloodlightModuleContext context, SegmentRoutingManager sr) {
+        this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+        this.topologyService = context.getServiceImpl(ITopologyService.class);
+        this.mutableTopology = topologyService.getTopology();
+        this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
+        this.packetService = context.getServiceImpl(IPacketService.class);
+        this.srManager = sr;
+
+        packetService.registerPacketListener(this);
+
+    }
+
+    @Override
+    public void receive(Switch sw, Port inPort, Ethernet payload) {
+        // TODO Auto-generated method stub
+        if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
+
+            IPv4 ipv4 = (IPv4)payload.getPayload();
+            int destinationAddress = ipv4.getDestinationAddress();
+
+            // Check if the destination is any host known to TopologyService
+            for (net.onrc.onos.core.topology.Host host: mutableTopology.getHosts()) {
+                IPv4Address hostIpAddress = IPv4Address.of(host.getIpAddress());
+                if (hostIpAddress != null && hostIpAddress.getInt() == destinationAddress) {
+                    byte[] destinationMacAddress = host.getMacAddress().toBytes();
+                    addRouteToHost(sw, destinationAddress, destinationMacAddress);
+                    return;
+                }
+            }
+
+            // Check if the destination is within subnets of the swtich
+            if (isWithinSubnets(sw, IPv4Address.of(destinationAddress).toString())) {
+                srManager.sendArpRequest(sw, destinationAddress, inPort);
+            }
+        }
+    }
+
+    private boolean isWithinSubnets(Switch sw, String ipAddress) {
+
+        return true;
+    }
+
+
+    /**
+     * Add routing rules to forward packets to known hosts
+     *
+     * @param sw Switch
+     * @param hostIp Host IP address to forwards packets to
+     */
+    public void addRouteToHost(Switch sw, int destinationAddress, byte[] destinationMacAddress) {
+
+        IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
+        OFFactory factory = ofSwitch.getFactory();
+
+
+        OFOxmEthType ethTypeIp = factory.oxms()
+                .ethType(EthType.IPv4);
+        OFOxmIpv4DstMasked ipPrefix = factory.oxms()
+                .ipv4DstMasked(
+                        IPv4Address.of(destinationAddress),
+                        IPv4Address.NO_MASK); // host addr should be /32
+        OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
+        OFMatchV3 match = factory.buildMatchV3()
+                .setOxmList(oxmListSlash32).build();
+        OFAction setDmac = null;
+        OFOxmEthDst dmac = factory.oxms()
+                .ethDst(MacAddress.of(destinationMacAddress));
+        setDmac = factory.actions().buildSetField()
+                .setField(dmac).build();
+
+        OFAction decTtl = factory.actions().decNwTtl();
+
+        // Set the source MAC address with the switch MAC address
+        String switchMacAddress = sw.getStringAttribute("routerMac");
+        OFOxmEthSrc srcAddr = factory.oxms().ethSrc(MacAddress.of(switchMacAddress));
+        OFAction setSA = factory.actions().buildSetField()
+                .setField(srcAddr).build();
+
+        List<OFAction> actionList = new ArrayList<OFAction>();
+        actionList.add(setDmac);
+        actionList.add(decTtl);
+        actionList.add(setSA);
+
+
+        /* TODO : need to check the config file for all packets
+        String subnets = sw.getStringAttribute("subnets");
+        try {
+            JSONArray arry = new JSONArray(subnets);
+            for (int i = 0; i < arry.length(); i++) {
+                String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
+                int portNo = (int) arry.getJSONObject(i).get("portNo");
+
+                if (netMatch(subnetIp, IPv4Address.of(hostIp.getDestinationAddress()).toString())) {
+                    OFAction out = factory.actions().buildOutput()
+                            .setPort(OFPort.of(portNo)).build();
+                    actionList.add(out);
+                }
+            }
+        } catch (JSONException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        */
+
+        // Set output port
+        net.onrc.onos.core.topology.Host host = mutableTopology.getHostByMac(MACAddress.valueOf(destinationMacAddress));
+        if (host != null) {
+            for (Port port: host.getAttachmentPoints()) {
+                OFAction out = factory.actions().buildOutput()
+                                .setPort(OFPort.of(port.getPortNumber().shortValue())).build();
+                actionList.add(out);
+            }
+        }
+
+        OFInstruction writeInstr = factory.instructions().buildWriteActions()
+                .setActions(actionList).build();
+
+        List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+        instructions.add(writeInstr);
+
+        OFMessage myIpEntry = factory.buildFlowAdd()
+                .setTableId(TableId.of(TABLE_IPv4_UNICAST))
+                .setMatch(match)
+                .setInstructions(instructions)
+                .setPriority(MAX_PRIORITY)
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setIdleTimeout(0)
+                .setHardTimeout(0)
+                //.setXid(getNextTransactionId())
+                .build();
+
+        log.debug("Sending 'Routing information' OF message to the switch {}.", sw.getDpid().toString());
+
+        flowPusher.add(sw.getDpid(), myIpEntry);
+
+    }
+
+
+}
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 8e58eac..b548e18 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
@@ -6,7 +6,6 @@
 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;
@@ -28,16 +27,11 @@
 import org.projectfloodlight.openflow.protocol.OFPacketOut;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
-import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
-import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
-import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
-import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
 import org.projectfloodlight.openflow.types.EthType;
 import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
@@ -99,34 +93,53 @@
 
             if (ipv4.getProtocol() == IPv4.PROTOCOL_ICMP) {
                 int destinationAddress = ipv4.getDestinationAddress();
+                String destAddressStr = IPv4Address.of(destinationAddress).toString();
 
                 // Check if it is ICMP request to the switch
                 String switchIpAddressSlash = sw.getStringAttribute("routerIp");
                 if (switchIpAddressSlash != null) {
-                    String switchIpAddressStr = switchIpAddressSlash.substring(0, switchIpAddressSlash.indexOf('/'));
+                    String switchIpAddressStr
+                        = switchIpAddressSlash.substring(0, switchIpAddressSlash.indexOf('/'));
                     IPv4Address switchIpAddress = IPv4Address.of(switchIpAddressStr);
-
+                    List<String> gatewayIps = getSubnetGatewayIps(sw);
                     if (((ICMP)ipv4.getPayload()).getIcmpType() == ICMP_TYPE_ECHO &&
-                            destinationAddress == switchIpAddress.getInt()) {
+                            (destinationAddress == switchIpAddress.getInt() ||
+                             gatewayIps.contains(destAddressStr))) {
                         sendICMPResponse(sw, inPort, payload);
                         return;
                     }
                 }
-
-
-                // Check if the destination is any host known to TopologyService
-                for (net.onrc.onos.core.topology.Host host: mutableTopology.getHosts()) {
-                    IPv4Address hostIpAddress = IPv4Address.of(host.getIpAddress());
-                    if (hostIpAddress != null && hostIpAddress.getInt() == destinationAddress) {
-                        byte[] destinationMacAddress = host.getMacAddress().toBytes();
-                        addRouteToHost(sw, destinationAddress, destinationMacAddress);
-                        return;
-                    }
-                }
             }
 
         }
+    }
 
+    /**
+     * 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;
     }
 
 
@@ -273,99 +286,7 @@
         return mplsLabel;
     }
 
-    /**
-     * Add routing rules to forward packets to known hosts
-     *
-     * @param sw Switch
-     * @param hostIp Host IP address to forwards packets to
-     */
-    private void addRouteToHost(Switch sw, int destinationAddress, byte[] destinationMacAddress) {
 
-        IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
-        OFFactory factory = ofSwitch.getFactory();
-
-
-        OFOxmEthType ethTypeIp = factory.oxms()
-                .ethType(EthType.IPv4);
-        OFOxmIpv4DstMasked ipPrefix = factory.oxms()
-                .ipv4DstMasked(
-                        IPv4Address.of(destinationAddress),
-                        IPv4Address.NO_MASK); // host addr should be /32
-        OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
-        OFMatchV3 match = factory.buildMatchV3()
-                .setOxmList(oxmListSlash32).build();
-        OFAction setDmac = null;
-        OFOxmEthDst dmac = factory.oxms()
-                .ethDst(MacAddress.of(destinationMacAddress));
-        setDmac = factory.actions().buildSetField()
-                .setField(dmac).build();
-
-        OFAction decTtl = factory.actions().decNwTtl();
-
-        // Set the source MAC address with the switch MAC address
-        String switchMacAddress = sw.getStringAttribute("routerMac");
-        OFOxmEthSrc srcAddr = factory.oxms().ethSrc(MacAddress.of(switchMacAddress));
-        OFAction setSA = factory.actions().buildSetField()
-                .setField(srcAddr).build();
-
-        List<OFAction> actionList = new ArrayList<OFAction>();
-        actionList.add(setDmac);
-        actionList.add(decTtl);
-        actionList.add(setSA);
-
-
-        /* TODO : need to check the config file for all packets
-        String subnets = sw.getStringAttribute("subnets");
-        try {
-            JSONArray arry = new JSONArray(subnets);
-            for (int i = 0; i < arry.length(); i++) {
-                String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
-                int portNo = (int) arry.getJSONObject(i).get("portNo");
-
-                if (netMatch(subnetIp, IPv4Address.of(hostIp.getDestinationAddress()).toString())) {
-                    OFAction out = factory.actions().buildOutput()
-                            .setPort(OFPort.of(portNo)).build();
-                    actionList.add(out);
-                }
-            }
-        } catch (JSONException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-        */
-
-        // Set output port
-        net.onrc.onos.core.topology.Host host = mutableTopology.getHostByMac(MACAddress.valueOf(destinationMacAddress));
-        if (host != null) {
-            for (Port port: host.getAttachmentPoints()) {
-                OFAction out = factory.actions().buildOutput()
-                                .setPort(OFPort.of(port.getPortNumber().shortValue())).build();
-                actionList.add(out);
-            }
-        }
-
-        OFInstruction writeInstr = factory.instructions().buildWriteActions()
-                .setActions(actionList).build();
-
-        List<OFInstruction> instructions = new ArrayList<OFInstruction>();
-        instructions.add(writeInstr);
-
-        OFMessage myIpEntry = factory.buildFlowAdd()
-                .setTableId(TableId.of(TABLE_IPv4_UNICAST))
-                .setMatch(match)
-                .setInstructions(instructions)
-                .setPriority(MAX_PRIORITY)
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setIdleTimeout(0)
-                .setHardTimeout(0)
-                //.setXid(getNextTransactionId())
-                .build();
-
-        log.debug("Sending 'Routing information' OF message to the switch {}.", sw.getDpid().toString());
-
-        flowPusher.add(sw.getDpid(), myIpEntry);
-
-    }
 
     /**
      * Add a new rule to VLAN table to forward packets from any port to the next table
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
index 457a626..eedc1c9 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -24,6 +24,7 @@
 import net.onrc.onos.core.topology.ITopologyService;
 import net.onrc.onos.core.topology.LinkData;
 import net.onrc.onos.core.topology.MutableTopology;
+import net.onrc.onos.core.topology.Port;
 import net.onrc.onos.core.topology.Switch;
 import net.onrc.onos.core.topology.TopologyEvents;
 import net.onrc.onos.core.util.Dpid;
@@ -41,6 +42,8 @@
     private MutableTopology mutableTopology;
 
     private List<ArpEntry> arpEntries;
+    private ArpHandler arpHandler;
+    private GenericIpHandler ipHandler;
 
     @Override
     public Collection<Class<? extends IFloodlightService>> getModuleServices() {
@@ -72,8 +75,9 @@
     @Override
     public void init(FloodlightModuleContext context) throws FloodlightModuleException {
 
-        ArpHandler aprHandler = new ArpHandler(context, this);
+        arpHandler = new ArpHandler(context, this);
         IcmpHandler icmpHandler = new IcmpHandler(context, this);
+        ipHandler = new GenericIpHandler(context, this);
         arpEntries = new ArrayList<ArpEntry>();
         topologyService = context.getServiceImpl(ITopologyService.class);
         mutableTopology = topologyService.getTopology();
@@ -132,6 +136,16 @@
         return null;
     }
 
+    /**
+     * Send an ARP request via ArpHandler
+     * @param destinationAddress
+     * @param sw
+     * @param inPort
+     *
+     */
+    public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
+        arpHandler.sendArpRequest(sw, destinationAddress, inPort);
+    }
 
     /**
      * Temporary class to to keep ARP entry
@@ -146,8 +160,8 @@
             this.targetMacAddress = macAddress;
             this.targetIpAddress = ipAddress;
         }
-
     }
+
     /**
      * Topology events that have been generated.
      *
@@ -230,25 +244,70 @@
      */
     private void setSegmentRoutingRule(Switch sw, ArrayList<Path> paths) {
 
-        log.debug("Set routing infor for {} to .. ", sw.getDpid());
+        log.debug("Set routing info for {} to .. ", sw.getDpid());
         for (Path path: paths) {
 
             for (Object obj : path.toArray()) {
                 LinkData link = (LinkData)obj;
-                log.debug("  ---- Set a rule in {} [Forward to {}] " , link.getSrc(), link.getDst().getDpid());
+                String destMplsLabel = getMplslabel(link.getDst().getDpid());
+                String targetMplsLabel = getMplslabel(sw.getDpid());
+                if (destMplsLabel != null && targetMplsLabel != null)
+                    setTransitRouterRule(targetMplsLabel, destMplsLabel);
+            }
+        }
+    }
+
+    /**
+     * Get MPLS label reading the config file
+     *
+     * @param dipid  DPID of the switch
+     * @return MPLS label for the switch
+     */
+
+    private String getMplslabel(Dpid dpid) {
+
+        String mplsLabel = null;
+        for (Switch sw: mutableTopology.getSwitches()) {
+            String dpidStr = sw.getStringAttribute("nodeDpid");
+            if (dpid.toString().endsWith(dpidStr)) {
+                mplsLabel = sw.getStringAttribute("nodeSid");
+                break;
             }
         }
 
+        return mplsLabel;
     }
 
     /**
+     * Test function
+     *
+     *
+     */
+    private void setTransitRouterRule(String targetMplsLabel, String destMplsLabel) {
+
+        log.debug("Match: MPLS label {}, action: forward to {}", targetMplsLabel, destMplsLabel);
+
+    }
+
+    /**
+     * Test function
+     *
+     */
+    private void setBorderRouterRule() {
+
+
+
+    }
+
+
+
+    /**
      * The function checks if given IP matches to the given subnet mask
      *
      * @param addr - subnet address to match
      * @param addr1 - IP address to check
      * @return true if the IP address matches to the subnet, otherwise false
      */
-
     public boolean netMatch(String addr, String addr1){ //addr is subnet address and addr1 is ip address. Function will return true, if addr1 is within addr(subnet)
 
         String[] parts = addr.split("/");
@@ -289,4 +348,9 @@
             return false;
         }
     }
+
+    public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
+        ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
+
+    }
 }