Added an L3 mode to ProxyArpModule which limits the ports ARPs are sent out based on IP address. This should prevent leaking ARPs from one network into another
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index 278fb86..d72c52c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -24,7 +24,6 @@
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.SingletonTask;
-import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.restserver.IRestApiService;
@@ -81,7 +80,6 @@
 	protected IFloodlightProviderService floodlightProvider;
 	protected ITopologyService topology;
 	protected ITopoRouteService topoRouteService;
-	protected IDeviceService devices;
 	protected IRestApiService restApi;
 	
 	protected ProxyArpManager proxyArp;
@@ -116,6 +114,7 @@
 	protected Map<String, Interface> interfaces;
 	protected Map<InetAddress, BgpPeer> bgpPeers;
 	protected SwitchPort bgpdAttachmentPoint;
+	protected MACAddress bgpdMacAddress;
 	
 	//True when all switches have connected
 	protected volatile boolean switchesConnected = false;
@@ -193,6 +192,7 @@
 					new Dpid(config.getBgpdAttachmentDpid()),
 					new Port(config.getBgpdAttachmentPort()));
 			
+			bgpdMacAddress = config.getBgpdMacAddress();
 		} catch (JsonParseException e) {
 			log.error("Error in JSON file", e);
 			System.exit(1);
@@ -233,7 +233,6 @@
 			= new ArrayList<Class<? extends IFloodlightService>>();
 		l.add(IFloodlightProviderService.class);
 		l.add(ITopologyService.class);
-		l.add(IDeviceService.class);
 		l.add(IRestApiService.class);
 		return l;
 	}
@@ -250,12 +249,11 @@
 		// Register floodlight provider and REST handler.
 		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
 		topology = context.getServiceImpl(ITopologyService.class);
-		devices = context.getServiceImpl(IDeviceService.class);
 		restApi = context.getServiceImpl(IRestApiService.class);
 		
 		//TODO We'll initialise this here for now, but it should really be done as
 		//part of the controller core
-		proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
+		proxyArp = new ProxyArpManager(floodlightProvider, topology);
 		
 		linkUpdates = new ArrayList<LDUpdate>();
 		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
@@ -300,6 +298,8 @@
 		log.debug("Config file set to {}", configFilename);
 		
 		readGatewaysConfiguration(configFilename);
+		
+		proxyArp.setL3Mode(interfacePtrie, bgpdMacAddress);
 	}
 	
 	@Override
@@ -307,6 +307,8 @@
 		restApi.addRestletRoutable(new BgpRouteWebRoutable());
 		topology.addListener(this);
 		
+		proxyArp.startUp();
+		
 		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
 		
 		//Retrieve the RIB from BGPd during startup
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
index 4b623e4..1d90edc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
@@ -3,12 +3,15 @@
 import java.util.Collections;
 import java.util.List;
 
+import net.floodlightcontroller.util.MACAddress;
+
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.openflow.util.HexString;
 
 public class Configuration {
 	private long bgpdAttachmentDpid;
 	private short bgpdAttachmentPort;
+	private MACAddress bgpdMacAddress;
 	private List<String> switches;
 	private List<Interface> interfaces;
 	private List<BgpPeer> peers;
@@ -34,6 +37,15 @@
 	public void setBgpdAttachmentPort(short bgpdAttachmentPort) {
 		this.bgpdAttachmentPort = bgpdAttachmentPort;
 	}
+	
+	public MACAddress getBgpdMacAddress() {
+		return bgpdMacAddress;
+	}
+
+	@JsonProperty("bgpdMacAddress")
+	public void setBgpdMacAddress(String strMacAddress) {
+		this.bgpdMacAddress = MACAddress.valueOf(strMacAddress);
+	}
 
 	public List<String> getSwitches() {
 		return Collections.unmodifiableList(switches);
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 521ba0f..ca84bc0 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -17,11 +17,14 @@
 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.topology.ITopologyService;
 import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.bgproute.IPatriciaTrie;
+import net.onrc.onos.ofcontroller.bgproute.Interface;
+import net.onrc.onos.ofcontroller.bgproute.Prefix;
+import net.onrc.onos.ofcontroller.util.SwitchPort;
 
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPacketIn;
@@ -48,12 +51,18 @@
 			
 	protected IFloodlightProviderService floodlightProvider;
 	protected ITopologyService topology;
-	protected IDeviceService devices;
 	
 	protected Map<InetAddress, ArpTableEntry> arpTable;
 
 	protected SetMultimap<InetAddress, ArpRequest> arpRequests;
 	
+	public enum Mode {L2_MODE, L3_MODE}
+	
+	private Mode mode;
+	private IPatriciaTrie<Interface> interfacePtrie = null;
+	private MACAddress routerMacAddress = null;
+	//private SwitchPort bgpdAttachmentPoint = null;
+	
 	private class ArpRequest {
 		private IArpRequester requester;
 		private boolean retry;
@@ -88,16 +97,26 @@
 	}
 	
 	public ProxyArpManager(IFloodlightProviderService floodlightProvider,
-				ITopologyService topology, IDeviceService devices){
+				ITopologyService topology){
 		this.floodlightProvider = floodlightProvider;
 		this.topology = topology;
-		this.devices = devices;
 		
 		arpTable = new HashMap<InetAddress, ArpTableEntry>();
 
 		arpRequests = Multimaps.synchronizedSetMultimap(
 				HashMultimap.<InetAddress, ArpRequest>create());
 		
+		mode = Mode.L2_MODE;
+	}
+	
+	public void setL3Mode(IPatriciaTrie<Interface> interfacePtrie, MACAddress routerMacAddress) {
+		this.interfacePtrie = interfacePtrie;
+		this.routerMacAddress = routerMacAddress;
+		//this.bgpdAttachmentPoint = bgpdAttachmentPoint;
+		mode = Mode.L3_MODE;
+	}
+	
+	public void startUp() {
 		Timer arpTimer = new Timer();
 		arpTimer.scheduleAtFixedRate(new TimerTask() {
 			@Override
@@ -205,23 +224,31 @@
 	protected void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp) {
 		log.debug("ARP request received for {}", 
 				bytesToStringAddr(arp.getTargetProtocolAddress()));
+
+		InetAddress target;
+		try {
+			 target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
+		} catch (UnknownHostException e) {
+			log.debug("Invalid address in ARP request", e);
+			return;
+		}
+		
+		if (mode == Mode.L3_MODE) {
+			Interface intf = interfacePtrie.match(new Prefix(target.getAddress(), 32));
+			if (intf != null && target.equals(intf.getIpAddress())) {
+				//ARP request for one of our interfaces, we can reply straight away
+				sendArpReply(arp, sw.getId(), pi.getInPort(), routerMacAddress.toBytes());
+				return;
+			}
+		}
 		
 		byte[] mac = lookupArpTable(arp.getTargetProtocolAddress());
 		
 		if (mac == null){
 			//Mac address is not in our arp table.
 			
-			//TODO check what the DeviceManager thinks
-			
 			//Record where the request came from so we know where to send the reply
-			InetAddress target;
-			try {
-				 target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
-			} catch (UnknownHostException e) {
-				log.debug("Invalid address in ARP request", e);
-				//return Command.CONTINUE; //Continue or stop?
-				return;
-			}
+
 			
 			//Should we just broadcast all received requests here? Or rate limit
 			//if we know we just sent an request?
@@ -229,7 +256,8 @@
 					new HostArpRequester(this, arp, sw.getId(), pi.getInPort()), false));
 						
 			//Flood the request out edge ports
-			broadcastArpRequestOutEdge(pi.getPacketData(), sw.getId(), pi.getInPort());
+			//broadcastArpRequestOutEdge(pi.getPacketData(), sw.getId(), pi.getInPort());
+			sendArpRequestToSwitches(target, pi.getPacketData(), sw.getId(), pi.getInPort());
 		}
 		else {
 			//We know the address, so send a reply
@@ -279,7 +307,7 @@
 		ArpTableEntry arpEntry = arpTable.get(addr);
 		
 		if (arpEntry == null){
-			log.debug("MAC for {} unknown", bytesToStringAddr(ipAddress));
+			//log.debug("MAC for {} unknown", bytesToStringAddr(ipAddress));
 			return null;
 		}
 		
@@ -332,18 +360,46 @@
 			.setProtocolAddressLength((byte)4) //can't find the constant anywhere
 			.setOpCode(ARP.OP_REQUEST)
 			.setSenderHardwareAddress(bgpdMac)
-			.setSenderProtocolAddress(zeroIpv4)
+			//.setSenderProtocolAddress(zeroIpv4)
 			.setTargetHardwareAddress(zeroMac)
 			.setTargetProtocolAddress(ipAddress.getAddress());
-	
+
+		byte[] senderIPAddress = zeroIpv4;
+		if (mode == Mode.L3_MODE) {
+			Interface intf = interfacePtrie.match(new Prefix(ipAddress.getAddress(), 32));
+			if (intf != null) {
+				senderIPAddress = intf.getIpAddress().getAddress();
+			}
+		}
+		
+		arpRequest.setSenderProtocolAddress(senderIPAddress);
+		
 		Ethernet eth = new Ethernet();
-		//eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
 		eth.setSourceMACAddress(bgpdMac)
 			.setDestinationMACAddress(broadcastMac)
 			.setEtherType(Ethernet.TYPE_ARP)
 			.setPayload(arpRequest);
 		
-		broadcastArpRequestOutEdge(eth.serialize(), 0, OFPort.OFPP_NONE.getValue());
+		//broadcastArpRequestOutEdge(eth.serialize(), 0, OFPort.OFPP_NONE.getValue());
+		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 (mode == Mode.L2_MODE) {
+			log.debug("mode is l2");
+			broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+		}
+		else if (mode == Mode.L3_MODE) {
+			log.debug("mode is l3");
+			Interface intf = interfacePtrie.match(new Prefix(dstAddress.getAddress(), 32));
+			if (intf != null) {
+				sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
+			}
+		}
 	}
 	
 	private void broadcastArpRequestOutEdge(byte[] arpRequest, long inSwitch, short inPort) {
@@ -394,6 +450,37 @@
 		}
 	}
 	
+	private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
+		log.debug("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.debug("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);
+		}
+	}
+	
 	public void sendArpReply(ARP arpRequest, long dpid, short port, byte[] targetMac) {
 		ARP arpReply = new ARP();
 		arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)