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