Began implementing IPC with Hazelcast in order to broadcast ARP via other ONOS nodes
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java b/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java
index f3d0da5..b14dc12 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java
@@ -11,9 +11,9 @@
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.topology.ITopologyService;
+import net.onrc.onos.datagrid.IDatagridService;
 import net.onrc.onos.ofcontroller.core.config.DefaultConfiguration;
 import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
 import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
@@ -24,10 +24,10 @@
 public class OnosModuleLoader implements IFloodlightModule {
 	private IFloodlightProviderService floodlightProvider;
 	private ITopologyService topology;
-	private IDeviceService deviceService;
 	private IConfigInfoService config;
 	private IRestApiService restApi;
 	private IFlowService flowService;
+	private IDatagridService datagrid;
 
 	private ProxyArpManager arpManager;
 	private Forwarding forwarding;
@@ -59,10 +59,9 @@
 				new ArrayList<Class<? extends IFloodlightService>>();
 		dependencies.add(IFloodlightProviderService.class);
 		dependencies.add(ITopologyService.class);
-		dependencies.add(IDeviceService.class);
-		//dependencies.add(IConfigInfoService.class);
 		dependencies.add(IRestApiService.class);
 		dependencies.add(IFlowService.class);
+		dependencies.add(IDatagridService.class);
 		return dependencies;
 	}
 
@@ -71,9 +70,9 @@
 			throws FloodlightModuleException {
 		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
 		topology = context.getServiceImpl(ITopologyService.class);
-		deviceService = context.getServiceImpl(IDeviceService.class);
 		restApi = context.getServiceImpl(IRestApiService.class);
 		flowService = context.getServiceImpl(IFlowService.class);
+		datagrid = context.getServiceImpl(IDatagridService.class);
 		
 		//This could be null because it's not mandatory to have an
 		//IConfigInfoService loaded.
@@ -82,7 +81,7 @@
 			config = new DefaultConfiguration();
 		}
 
-		arpManager.init(floodlightProvider, topology, deviceService, config, restApi);
+		arpManager.init(floodlightProvider, topology, datagrid, config, restApi);
 		forwarding.init(floodlightProvider, flowService);
 	}
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IArpEventHandler.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IArpEventHandler.java
new file mode 100644
index 0000000..51d92bd
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IArpEventHandler.java
@@ -0,0 +1,11 @@
+package net.onrc.onos.ofcontroller.proxyarp;
+
+public interface IArpEventHandler {
+
+	/**
+	 * Notify the ARP event handler that an ARP request has been received.
+	 * @param id The string ID of the ARP request
+	 * @param arpRequest The ARP request packet
+	 */
+	public void arpRequestNotification(byte[] arpRequest);
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index a5dabc9..4d261a2 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -17,16 +17,18 @@
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.packet.ARP;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.datagrid.IDatagridService;
 import net.onrc.onos.ofcontroller.bgproute.Interface;
 import net.onrc.onos.ofcontroller.core.IDeviceStorage;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
 import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
 import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
 
@@ -46,7 +48,8 @@
 import com.google.common.collect.SetMultimap;
 import com.google.common.net.InetAddresses;
 
-public class ProxyArpManager implements IProxyArpService, IOFMessageListener {
+public class ProxyArpManager implements IProxyArpService, IOFMessageListener,
+										IArpEventHandler {
 	private final static Logger log = LoggerFactory.getLogger(ProxyArpManager.class);
 	
 	private final long ARP_TIMER_PERIOD = 60000; //ms (== 1 min) 
@@ -55,11 +58,13 @@
 			
 	private IFloodlightProviderService floodlightProvider;
 	private ITopologyService topology;
-	private IDeviceService deviceService;
+	private IDatagridService datagrid;
 	private IConfigInfoService configService;
 	private IRestApiService restApi;
 	
 	private IDeviceStorage deviceStorage;
+	private ITopoSwitchService topoSwitchService;
+	private ITopoLinkService topoLinkService;
 	
 	private short vlan;
 	private static final short NO_VLAN = 0;
@@ -124,11 +129,11 @@
 	*/
 	
 	public void init(IFloodlightProviderService floodlightProvider,
-			ITopologyService topology, IDeviceService deviceService,
+			ITopologyService topology, IDatagridService datagrid,
 			IConfigInfoService config, IRestApiService restApi){
 		this.floodlightProvider = floodlightProvider;
 		this.topology = topology;
-		this.deviceService = deviceService;
+		this.datagrid = datagrid;
 		this.configService = config;
 		this.restApi = restApi;
 		
@@ -145,6 +150,8 @@
 		restApi.addRestletRoutable(new ArpWebRoutable());
 		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
 		
+		datagrid.registerArpEventHandler(this);
+		
 		deviceStorage = new DeviceStorageImpl();
 		deviceStorage.init("");
 		
@@ -232,9 +239,10 @@
 	public Command receive(
 			IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
 		
-		if (msg.getType() != OFType.PACKET_IN){
-			return Command.CONTINUE;
-		}
+		//if (msg.getType() != OFType.PACKET_IN){
+			//return Command.CONTINUE;
+		//}
+		log.debug("received packet");
 		
 		OFPacketIn pi = (OFPacketIn) msg;
 		
@@ -243,13 +251,13 @@
 		
 		if (eth.getEtherType() == Ethernet.TYPE_ARP){
 			ARP arp = (ARP) eth.getPayload();
-			
+			log.debug("etharp {}", arp);	
 			if (arp.getOpCode() == ARP.OP_REQUEST) {
 				//TODO check what the DeviceManager does about propagating
 				//or swallowing ARPs. We want to go after DeviceManager in the
 				//chain but we really need it to CONTINUE ARP packets so we can
 				//get them.
-				handleArpRequest(sw, pi, arp);
+				handleArpRequest(sw, pi, arp, eth);
 			}
 			else if (arp.getOpCode() == ARP.OP_REPLY) {
 				//handleArpReply(sw, pi, arp);
@@ -261,7 +269,7 @@
 		return Command.CONTINUE;
 	}
 	
-	private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp) {
+	private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp, Ethernet eth) {
 		if (log.isTraceEnabled()) {
 			log.trace("ARP request received for {}", 
 					inetAddressToString(arp.getTargetProtocolAddress()));
@@ -302,8 +310,10 @@
 		IDeviceObject targetDevice = 
 				deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
 		
+		log.debug("targetDevice: {}", targetDevice);
+		
 		if (targetDevice != null) {
-			//We have the device in our database, so send a reply
+			// We have the device in our database, so send a reply
 			MACAddress macAddress = MACAddress.valueOf(targetDevice.getMACAddress());
 			
 			if (log.isTraceEnabled()) {
@@ -315,6 +325,16 @@
 			
 			sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
 		}
+		else {
+			// We don't know the device so broadcast the request out
+			// the edge of the network
+			
+			//Record where the request came from so we know where to send the reply
+			arpRequests.put(target, new ArpRequest(
+					new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
+			
+			sendArpRequestToEdge(eth, pi);
+		}
 		
 		/*if (macAddress == null){
 			//MAC address is not in our ARP cache.
@@ -459,6 +479,27 @@
 		}
 	}
 	
+	private void sendArpRequestToEdge(Ethernet arpRequest, OFPacketIn pi) {
+		// Pull the topology from the network map and find edge ports
+		/*for (ISwitchObject swObject : topoSwitchService.getActiveSwitches()) {
+			//List<Link> linksOnSwitch = topoLinkService.getLinksOnSwitch(swObject.getDPID());
+			
+			Set<IPortObject> edgePorts = new HashSet<IPortObject>();
+			
+			for (IPortObject portObject : swObject.getPorts()) {
+				if (!portObject.getLinkedPorts().iterator().hasNext()) {
+					edgePorts.add(portObject);
+				}
+			}
+			
+			
+		}*/
+		//log.debug("Sending ARP request for {} to other ONOS instances",
+				//HexString.toHexString(arpRequest.getTargetProtocolAddress()));
+		//log.debug("Sent request bytes: {}", );
+		datagrid.sendArpRequest(arpRequest.serialize());
+	}
+	
 	private void broadcastArpRequestOutEdge(byte[] arpRequest, long inSwitch, short inPort) {
 		for (IOFSwitch sw : floodlightProvider.getSwitches().values()){
 			Collection<Short> enabledPorts = sw.getEnabledPortNumbers();
@@ -637,4 +678,14 @@
 	public List<String> getMappings() {
 		return arpCache.getMappings();
 	}
+
+	/*
+	 * IArpEventHandler methods
+	 */
+	
+	@Override
+	public void arpRequestNotification(byte[] arpRequest) {
+		log.debug("Received ARP notification from other instances");
+		broadcastArpRequestOutEdge(arpRequest, Long.MAX_VALUE, Short.MAX_VALUE);
+	}
 }