- 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/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);
+
+    }
+
+
+}