Cherry-pick from https://gerrit.onos.onlab.us/#/c/335/

Move to FlowManager & Running SDN-IP on multiple onos instances (ONOS-668)

Make DISCARD_FIRST_HOP_ENTRY, KEEP_ONLY_FIRST_HOP_ENTRY accessible

Add a new type of BroadcastPacketOutNotification without inSwitch/inPort

Send Arp Request to all ONOS instances, not just to the local one

Get rid of BgpProxyArpManager.java

Improvements patch (ONOS-668)

change FlowPathFlag from private to public

delete BroadcastPacketOutNotification with no dpid/port

sendPacketOutNotification to specific out-dpid/our-port

Conflicts:

	src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
	src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java

NOTE: The above conflicts have been resolved by hand.

Change-Id: I449717d2289d14c2655af10ae7f628ea62187c63
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java
deleted file mode 100644
index 3dba4f8..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java
+++ /dev/null
@@ -1,637 +0,0 @@
-package net.onrc.onos.ofcontroller.proxyarp;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.core.IOFSwitch;
-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.ofcontroller.bgproute.Interface;
-import net.onrc.onos.ofcontroller.core.IDeviceStorage;
-import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
-import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
-
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionOutput;
-import org.openflow.util.HexString;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-
-public class BgpProxyArpManager implements IProxyArpService, IOFMessageListener {
-	private final static Logger log = LoggerFactory.getLogger(BgpProxyArpManager.class);
-	
-	private final long ARP_TIMER_PERIOD = 60000; //ms (== 1 min) 
-	
-	private static final int ARP_REQUEST_TIMEOUT = 2000; //ms
-			
-	private IFloodlightProviderService floodlightProvider;
-	private ITopologyService topology;
-	//private IDeviceService deviceService;
-	private IConfigInfoService configService;
-	private IRestApiService restApi;
-	
-	private IDeviceStorage deviceStorage;
-	
-	private short vlan;
-	private static final short NO_VLAN = 0;
-	
-	private ArpCache arpCache;
-
-	private SetMultimap<InetAddress, ArpRequest> arpRequests;
-	
-	private static class ArpRequest {
-		private final IArpRequester requester;
-		private final boolean retry;
-		private long requestTime;
-		
-		public ArpRequest(IArpRequester requester, boolean retry){
-			this.requester = requester;
-			this.retry = retry;
-			this.requestTime = System.currentTimeMillis();
-		}
-		
-		public ArpRequest(ArpRequest old) {
-			this.requester = old.requester;
-			this.retry = old.retry;
-			this.requestTime = System.currentTimeMillis();
-		}
-		
-		public boolean isExpired() {
-			return (System.currentTimeMillis() - requestTime) > ARP_REQUEST_TIMEOUT;
-		}
-		
-		public boolean shouldRetry() {
-			return retry;
-		}
-		
-		public void dispatchReply(InetAddress ipAddress, MACAddress replyMacAddress) {
-			requester.arpResponse(ipAddress, replyMacAddress);
-		}
-	}
-	
-	private class HostArpRequester implements IArpRequester {
-		private final ARP arpRequest;
-		private final long dpid;
-		private final short port;
-		
-		public HostArpRequester(ARP arpRequest, long dpid, short port) {
-			this.arpRequest = arpRequest;
-			this.dpid = dpid;
-			this.port = port;
-		}
-
-		@Override
-		public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
-			BgpProxyArpManager.this.sendArpReply(arpRequest, dpid, port, macAddress);
-		}
-	}
-	
-	/*
-	public ProxyArpManager(IFloodlightProviderService floodlightProvider,
-				ITopologyService topology, IConfigInfoService configService,
-				IRestApiService restApi){
-
-	}
-	*/
-	
-	public void init(IFloodlightProviderService floodlightProvider,
-			ITopologyService topology,
-			IConfigInfoService config, IRestApiService restApi){
-		this.floodlightProvider = floodlightProvider;
-		this.topology = topology;
-		//this.deviceService = deviceService;
-		this.configService = config;
-		this.restApi = restApi;
-		
-		arpCache = new ArpCache();
-
-		arpRequests = Multimaps.synchronizedSetMultimap(
-				HashMultimap.<InetAddress, ArpRequest>create());
-	}
-	
-	public void startUp() {
-		this.vlan = configService.getVlan();
-		log.info("vlan set to {}", this.vlan);
-		
-		restApi.addRestletRoutable(new ArpWebRoutable());
-		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-		
-		deviceStorage = new DeviceStorageImpl();
-		deviceStorage.init("","");
-		
-		Timer arpTimer = new Timer("arp-processing");
-		arpTimer.scheduleAtFixedRate(new TimerTask() {
-			@Override
-			public void run() {
-				doPeriodicArpProcessing();
-			}
-		}, 0, ARP_TIMER_PERIOD);
-	}
-	
-	/*
-	 * Function that runs periodically to manage the asynchronous request mechanism.
-	 * It basically cleans up old ARP requests if we don't get a response for them.
-	 * The caller can designate that a request should be retried indefinitely, and
-	 * this task will handle that as well.
-	 */
-	private void doPeriodicArpProcessing() {
-		SetMultimap<InetAddress, ArpRequest> retryList 
-				= HashMultimap.<InetAddress, ArpRequest>create();
-
-		//Have to synchronize externally on the Multimap while using an iterator,
-		//even though it's a synchronizedMultimap
-		synchronized (arpRequests) {
-			log.debug("Current have {} outstanding requests", 
-					arpRequests.size());
-			
-			Iterator<Map.Entry<InetAddress, ArpRequest>> it 
-				= arpRequests.entries().iterator();
-			
-			while (it.hasNext()) {
-				Map.Entry<InetAddress, ArpRequest> entry
-						= it.next();
-				ArpRequest request = entry.getValue();
-				if (request.isExpired()) {
-					log.debug("Cleaning expired ARP request for {}", 
-							entry.getKey().getHostAddress());
-		
-					it.remove();
-					
-					if (request.shouldRetry()) {
-						retryList.put(entry.getKey(), request);
-					}
-				}
-			}
-		}
-		
-		for (Map.Entry<InetAddress, Collection<ArpRequest>> entry 
-				: retryList.asMap().entrySet()) {
-			
-			InetAddress address = entry.getKey();
-			
-			log.debug("Resending ARP request for {}", address.getHostAddress());
-			
-			sendArpRequestForAddress(address);
-			
-			for (ArpRequest request : entry.getValue()) {
-				arpRequests.put(address, new ArpRequest(request));
-			}
-		}
-	}
-	
-	@Override
-	public String getName() {
-		return "proxyarpmanager";
-	}
-
-	@Override
-	public boolean isCallbackOrderingPrereq(OFType type, String name) {
-		if (type == OFType.PACKET_IN) {
-			return "devicemanager".equals(name);
-		}
-		else {
-			return false;
-		}
-	}
-
-	@Override
-	public boolean isCallbackOrderingPostreq(OFType type, String name) {
-		return false;
-	}
-
-	@Override
-	public Command receive(
-			IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-		
-		if (msg.getType() != OFType.PACKET_IN){
-			return Command.CONTINUE;
-		}
-		
-		OFPacketIn pi = (OFPacketIn) msg;
-		
-		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, 
-                IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-		
-		if (eth.getEtherType() == Ethernet.TYPE_ARP){
-			ARP arp = (ARP) eth.getPayload();
-			
-			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);
-			}
-			else if (arp.getOpCode() == ARP.OP_REPLY) {
-				handleArpReply(sw, pi, arp);
-			}
-		}
-		
-		//TODO should we propagate ARP or swallow it?
-		//Always propagate for now so DeviceManager can learn the host location
-		return Command.CONTINUE;
-	}
-	
-	private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp) {
-		if (log.isTraceEnabled()) {
-			log.trace("ARP request received for {}", 
-					inetAddressToString(arp.getTargetProtocolAddress()));
-		}
-
-		InetAddress target;
-		try {
-			 target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
-		} catch (UnknownHostException e) {
-			log.debug("Invalid address in ARP request", e);
-			return;
-		}
-
-		if (configService.fromExternalNetwork(sw.getId(), pi.getInPort())) {
-			//If the request came from outside our network, we only care if
-			//it was a request for one of our interfaces.
-			if (configService.isInterfaceAddress(target)) {
-				log.trace("ARP request for our interface. Sending reply {} => {}",
-						target.getHostAddress(), configService.getRouterMacAddress());
-				
-				sendArpReply(arp, sw.getId(), pi.getInPort(), 
-						configService.getRouterMacAddress());
-			}
-			
-			return;
-		}
-		
-		MACAddress macAddress = arpCache.lookup(target);
-		
-		//IDevice dstDevice = deviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);
-		//Iterator<? extends IDevice> it = deviceService.queryDevices(
-				//null, null, InetAddresses.coerceToInteger(target), null, null);
-		
-		//IDevice targetDevice = null;
-		//if (it.hasNext()) {
-			//targetDevice = it.next();
-		//}
-		/*IDeviceObject targetDevice = 
-				deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
-		
-		if (targetDevice != null) {
-			//We have the device in our database, so send a reply
-			MACAddress macAddress = MACAddress.valueOf(targetDevice.getMACAddress());
-			
-			if (log.isTraceEnabled()) {
-				log.trace("Sending reply: {} => {} to host at {}/{}", new Object [] {
-						inetAddressToString(arp.getTargetProtocolAddress()),
-						macAddress.toString(),
-						HexString.toHexString(sw.getId()), pi.getInPort()});
-			}
-			
-			sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
-		}*/
-		
-		if (macAddress == null){
-			//MAC address is not in our ARP cache.
-			
-			//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));
-						
-			//Flood the request out edge ports
-			sendArpRequestToSwitches(target, pi.getPacketData(), sw.getId(), pi.getInPort());
-		}
-		else {
-			//We know the address, so send a reply
-			if (log.isTraceEnabled()) {
-				log.trace("Sending reply: {} => {} to host at {}/{}", new Object [] {
-						inetAddressToString(arp.getTargetProtocolAddress()),
-						macAddress.toString(),
-						HexString.toHexString(sw.getId()), pi.getInPort()});
-			}
-			
-			sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
-		}
-	}
-	
-	private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
-		if (log.isTraceEnabled()) {
-			log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[] { 
-					inetAddressToString(arp.getSenderProtocolAddress()),
-					HexString.toHexString(arp.getSenderHardwareAddress()),
-					HexString.toHexString(sw.getId()), pi.getInPort()});
-		}
-		
-		InetAddress senderIpAddress;
-		try {
-			senderIpAddress = InetAddress.getByAddress(arp.getSenderProtocolAddress());
-		} catch (UnknownHostException e) {
-			log.debug("Invalid address in ARP reply", e);
-			return;
-		}
-		
-		MACAddress senderMacAddress = MACAddress.valueOf(arp.getSenderHardwareAddress());
-		
-		arpCache.update(senderIpAddress, senderMacAddress);
-		
-		//See if anyone's waiting for this ARP reply
-		Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
-		
-		//Synchronize on the Multimap while using an iterator for one of the sets
-		List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(requests.size());
-		synchronized (arpRequests) {
-			Iterator<ArpRequest> it = requests.iterator();
-			while (it.hasNext()) {
-				ArpRequest request = it.next();
-				it.remove();
-				requestsToSend.add(request);
-			}
-		}
-		
-		//Don't hold an ARP lock while dispatching requests
-		for (ArpRequest request : requestsToSend) {
-			request.dispatchReply(senderIpAddress, senderMacAddress);
-		}
-	}
-	
-	private void sendArpRequestForAddress(InetAddress ipAddress) {
-		//TODO what should the sender IP address and MAC address be if no
-		//IP addresses are configured? Will there ever be a need to send
-		//ARP requests from the controller in that case?
-		//All-zero MAC address doesn't seem to work - hosts don't respond to it
-		
-		byte[] zeroIpv4 = {0x0, 0x0, 0x0, 0x0};
-		byte[] zeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-		byte[] genericNonZeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x01};
-		byte[] broadcastMac = {(byte)0xff, (byte)0xff, (byte)0xff, 
-				(byte)0xff, (byte)0xff, (byte)0xff};
-		
-		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)
-			.setTargetHardwareAddress(zeroMac)
-			.setTargetProtocolAddress(ipAddress.getAddress());
-
-		MACAddress routerMacAddress = configService.getRouterMacAddress();
-		//TODO hack for now as it's unclear what the MAC address should be
-		byte[] senderMacAddress = genericNonZeroMac;
-		if (routerMacAddress != null) {
-			senderMacAddress = routerMacAddress.toBytes();
-		}
-		arpRequest.setSenderHardwareAddress(senderMacAddress);
-		
-		byte[] senderIPAddress = zeroIpv4;
-		Interface intf = configService.getOutgoingInterface(ipAddress);
-		if (intf != null) {
-			senderIPAddress = intf.getIpAddress().getAddress();
-		}
-		
-		arpRequest.setSenderProtocolAddress(senderIPAddress);
-		
-		Ethernet eth = new Ethernet();
-		eth.setSourceMACAddress(senderMacAddress)
-			.setDestinationMACAddress(broadcastMac)
-			.setEtherType(Ethernet.TYPE_ARP)
-			.setPayload(arpRequest);
-		
-		if (vlan != NO_VLAN) {
-			eth.setVlanID(vlan)
-			   .setPriorityCode((byte)0);
-		}
-		
-		sendArpRequestToSwitches(ipAddress, eth.serialize());
-	}
-	
-	private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
-		sendArpRequestToSwitches(dstAddress, arpRequest, 
-				0, OFPort.OFPP_NONE.getValue());
-	}
-	
-	private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest,
-			long inSwitch, short inPort) {
-
-		if (configService.hasLayer3Configuration()) {
-			Interface intf = configService.getOutgoingInterface(dstAddress);
-			if (intf != null) {
-				sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
-			}
-			else {
-				//TODO here it should be broadcast out all non-interface edge ports.
-				//I think we can assume that if it's not a request for an external 
-				//network, it's an ARP for a host in our own network. So we want to 
-				//send it out all edge ports that don't have an interface configured
-				//to ensure it reaches all hosts in our network.
-				log.debug("No interface found to send ARP request for {}",
-						dstAddress.getHostAddress());
-			}
-		}
-		else {
-			broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
-		}
-	}
-	
-	private void broadcastArpRequestOutEdge(byte[] arpRequest, long inSwitch, short inPort) {
-		for (IOFSwitch sw : floodlightProvider.getSwitches().values()){
-			Collection<Short> enabledPorts = sw.getEnabledPortNumbers();
-			Set<Short> linkPorts = topology.getPortsWithLinks(sw.getId());
-			
-			if (linkPorts == null){
-				//I think this means the switch doesn't have any links.
-				//continue;
-				linkPorts = new HashSet<Short>();
-			}
-			
-			
-			OFPacketOut po = new OFPacketOut();
-			po.setInPort(OFPort.OFPP_NONE)
-				.setBufferId(-1)
-				.setPacketData(arpRequest);
-				
-			List<OFAction> actions = new ArrayList<OFAction>();
-			
-			for (short portNum : enabledPorts){
-				if (linkPorts.contains(portNum) || 
-						(sw.getId() == inSwitch && portNum == inPort)){
-					//If this port isn't an edge port or is the ingress port
-					//for the ARP, don't broadcast out it
-					continue;
-				}
-				
-				actions.add(new OFActionOutput(portNum));
-			}
-			
-			po.setActions(actions);
-			short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
-			po.setActionsLength(actionsLength);
-			po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength 
-					+ arpRequest.length);
-			
-			List<OFMessage> msgList = new ArrayList<OFMessage>();
-			msgList.add(po);
-			
-			try {
-				sw.write(msgList, null);
-				sw.flush();
-			} catch (IOException e) {
-				log.error("Failure writing packet out to switch", e);
-			}
-		}
-	}
-	
-	private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
-		if (log.isTraceEnabled()) {
-			log.trace("Sending ARP request out {}/{}", 
-					HexString.toHexString(dpid), port);
-		}
-		
-		OFPacketOut po = new OFPacketOut();
-		po.setInPort(OFPort.OFPP_NONE)
-			.setBufferId(-1)
-			.setPacketData(arpRequest);
-			
-		List<OFAction> actions = new ArrayList<OFAction>();
-		actions.add(new OFActionOutput(port));
-		po.setActions(actions);
-		short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
-		po.setActionsLength(actionsLength);
-		po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength 
-				+ arpRequest.length);
-		
-		IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
-		
-		if (sw == null) {
-			log.warn("Switch not found when sending ARP request");
-			return;
-		}
-		
-		try {
-			sw.write(po, null);
-			sw.flush();
-		} catch (IOException e) {
-			log.error("Failure writing packet out to switch", e);
-		}
-	}
-	
-	private void sendArpReply(ARP arpRequest, long dpid, short port, MACAddress targetMac) {
-		if (log.isTraceEnabled()) {
-			log.trace("Sending reply {} => {} to {}", new Object[] {
-					inetAddressToString(arpRequest.getTargetProtocolAddress()),
-					targetMac,
-					inetAddressToString(arpRequest.getSenderProtocolAddress())});
-		}
-		
-		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);
-		
-		if (vlan != NO_VLAN) {
-			eth.setVlanID(vlan)
-			   .setPriorityCode((byte)0);
-		}
-		
-		List<OFAction> actions = new ArrayList<OFAction>();
-		actions.add(new OFActionOutput(port));
-		
-		OFPacketOut po = new OFPacketOut();
-		po.setInPort(OFPort.OFPP_NONE)
-			.setBufferId(-1)
-			.setPacketData(eth.serialize())
-			.setActions(actions)
-			.setActionsLength((short)OFActionOutput.MINIMUM_LENGTH)
-			.setLengthU(OFPacketOut.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH
-					+ po.getPacketData().length);
-		
-		List<OFMessage> msgList = new ArrayList<OFMessage>();
-		msgList.add(po);
-
-		IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
-		
-		if (sw == null) {
-			log.warn("Switch {} not found when sending ARP reply", 
-					HexString.toHexString(dpid));
-			return;
-		}
-		
-		try {
-			sw.write(msgList, null);
-			sw.flush();
-		} catch (IOException e) {
-			log.error("Failure writing packet out to switch", e);
-		}
-	}
-	
-	private String inetAddressToString(byte[] bytes) {
-		try {
-			return InetAddress.getByAddress(bytes).getHostAddress();
-		} catch (UnknownHostException e) {
-			log.debug("Invalid IP address", e);
-			return "";
-		}
-	}
-	
-	/*
-	 * IProxyArpService methods
-	 */
-
-	@Override
-	public MACAddress getMacAddress(InetAddress ipAddress) {
-		return arpCache.lookup(ipAddress);
-	}
-
-	@Override
-	public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
-			boolean retry) {
-		arpRequests.put(ipAddress, new ArpRequest(requester, retry));
-		
-		//Sanity check to make sure we don't send a request for our own address
-		if (!configService.isInterfaceAddress(ipAddress)) {
-			sendArpRequestForAddress(ipAddress);
-		}
-	}
-	
-	@Override
-	public List<String> getMappings() {
-		return arpCache.getMappings();
-	}
-}
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 f5fee45..c7d495c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -229,7 +229,6 @@
 					// TODO check whether this is OK from this thread
 					IDeviceObject targetDevice = 
 							deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(entry.getKey()));
-					
 					if (targetDevice != null) {
 						deviceStorage.removeDevice(targetDevice);
 						if (log.isDebugEnabled()) {
@@ -253,6 +252,8 @@
 			
 			log.debug("Resending ARP request for {}", address.getHostAddress());
 			
+			// Only ARP requests sent by the controller will have the retry flag
+			// set, so for now we can just send a new ARP request for that address.
 			sendArpRequestForAddress(address);
 			
 			for (ArpRequest request : entry.getValue()) {
@@ -433,8 +434,6 @@
 		
 		MACAddress senderMacAddress = MACAddress.valueOf(arp.getSenderHardwareAddress());
 		
-		//arpCache.update(senderIpAddress, senderMacAddress);
-		
 		//See if anyone's waiting for this ARP reply
 		Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
 		
@@ -504,7 +503,8 @@
 			   .setPriorityCode((byte)0);
 		}
 		
-		sendArpRequestToSwitches(ipAddress, eth.serialize());
+		//sendArpRequestToSwitches(ipAddress, eth.serialize());
+		datagrid.sendPacketOutNotification(new SinglePacketOutNotification(eth.serialize(),intf.getDpid(),intf.getPort()));
 	}
 	
 	private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
@@ -531,7 +531,8 @@
 			}
 		}
 		else {
-			broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+			//broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+			broadcastArpRequestOutMyEdge(arpRequest, inSwitch, inPort);
 		}
 	}