Cleaned up the refactor of BgpRoute and renamed PathUpdate to Path
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 bbc9f15..278fb86 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -19,7 +19,6 @@
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -75,8 +74,7 @@
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
 public class BgpRoute implements IFloodlightModule, IBgpRouteService, 
-									ITopologyListener, IOFSwitchListener,
-									IArpRequester {
+									ITopologyListener, IArpRequester {
 	
 	protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
 
@@ -88,7 +86,6 @@
 	
 	protected ProxyArpManager proxyArp;
 	
-	//protected static Ptree ptree;
 	protected IPatriciaTrie<RibEntry> ptree;
 	protected IPatriciaTrie<Interface> interfacePtrie;
 	protected BlockingQueue<RibUpdate> ribUpdates;
@@ -130,14 +127,12 @@
 	
 	protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
 	
-	//TODO should this really be a Multimap?
-	//Es kann nur einen geben per IP address?
-	protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
+	protected Map<InetAddress, Path> pathsWaitingOnArp;
 	
 	protected ExecutorService bgpUpdatesExecutor;
 	
-	protected Map<InetAddress, PathUpdate> pushedPaths;
-	protected Map<Prefix, PathUpdate> prefixToPath;
+	protected Map<InetAddress, Path> pushedPaths;
+	protected Map<Prefix, Path> prefixToPath;
 	protected Multimap<Prefix, PushedFlowMod> pushedFlows;
 		
 	protected class TopologyChangeDetector implements Runnable {
@@ -214,16 +209,6 @@
 			Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
 			interfacePtrie.put(prefix, intf);
 		}
-		
-		/*
-		Iterator<IPatriciaTrie.Entry<Interface>> it = interfacePtrie.iterator();
-		while (it.hasNext()) {
-			IPatriciaTrie.Entry<Interface> entry = it.next();
-			Interface intf = entry.getValue();
-			log.debug("Interface at prefix {}, switchport {}/{}",
-					new Object[] {entry.getPrefix(), HexString.toHexString(intf.getDpid()), intf.getPort()});
-		}
-		*/
 	}
 	
 	@Override
@@ -257,7 +242,6 @@
 	public void init(FloodlightModuleContext context)
 			throws FloodlightModuleException {
 	    
-	    //ptree = new Ptree(32);
 		ptree = new PatriciaTrie<RibEntry>(32);
 		interfacePtrie = new PatriciaTrie<Interface>(32);
 	    
@@ -279,13 +263,12 @@
 
 		topoRouteService = new TopoRouteService("");
 		
-		pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
-				HashMultimap.<InetAddress, PathUpdate>create());
+		pathsWaitingOnArp = new HashMap<InetAddress, Path>();
 		prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
 				HashMultimap.<InetAddress, RibUpdate>create());
 		
-		pushedPaths = new HashMap<InetAddress, PathUpdate>();
-		prefixToPath = new HashMap<Prefix, PathUpdate>();
+		pushedPaths = new HashMap<InetAddress, Path>();
+		prefixToPath = new HashMap<Prefix, Path>();
 		pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
 		
 		bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
@@ -317,18 +300,24 @@
 		log.debug("Config file set to {}", configFilename);
 		
 		readGatewaysConfiguration(configFilename);
-		// Test.
-		//test();
+	}
+	
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		restApi.addRestletRoutable(new BgpRouteWebRoutable());
+		topology.addListener(this);
+		
+		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
+		
+		//Retrieve the RIB from BGPd during startup
+		retrieveRib();
 	}
 
-	//public Ptree getPtree() {
 	public IPatriciaTrie<RibEntry> getPtree() {
 		return ptree;
 	}
 	
 	public void clearPtree() {
-		//ptree = null;
-		//ptree = new Ptree(32);
 		ptree = new PatriciaTrie<RibEntry>(32);
 	}
 	
@@ -340,105 +329,6 @@
 		return routerId;
 	}
 	
-	// Return nexthop address as byte array.
-	/*
-	public RibEntry lookupRib(byte[] dest) {
-		if (ptree == null) {
-		    log.debug("lookupRib: ptree null");
-		    return null;
-		}
-		
-		PtreeNode node = ptree.match(dest, 32);
-		if (node == null) {
-            log.debug("lookupRib: ptree node null");
-			return null;
-		}
-		
-		if (node.rib == null) {
-            log.debug("lookupRib: ptree rib null");
-			return null;
-		}
-		
-		ptree.delReference(node);
-		
-		return node.rib;
-	}
-	*/
-	
-	/*
-	//TODO looks like this should be a unit test
-	@SuppressWarnings("unused")
-    private void test() throws UnknownHostException {
-		System.out.println("Here it is");
-		Prefix p = new Prefix("128.0.0.0", 8);
-		Prefix q = new Prefix("8.0.0.0", 8);
-		Prefix r = new Prefix("10.0.0.0", 24);
-		Prefix a = new Prefix("10.0.0.1", 32);
-	
-		ptree.acquire(p.getAddress(), p.getPrefixLength());
-		ptree.acquire(q.getAddress(), q.getPrefixLength());
-		ptree.acquire(r.getAddress(), r.getPrefixLength());
-	
-		System.out.println("Traverse start");
-		for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
-			Prefix p_result = new Prefix(node.key, node.keyBits);
-		}
-	
-		PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
-		if (n != null) {
-			System.out.println("Matched prefix for 10.0.0.1:");
-			Prefix x = new Prefix(n.key, n.keyBits);
-			ptree.delReference(n);
-		}
-		
-		n = ptree.lookup(p.getAddress(), p.getPrefixLength());
-		if (n != null) {
-			ptree.delReference(n);
-			ptree.delReference(n);
-		}
-		System.out.println("Traverse start");
-		for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
-			Prefix p_result = new Prefix(node.key, node.keyBits);
-		}
-		
-		n = ptree.lookup(q.getAddress(), q.getPrefixLength());
-		if (n != null) {
-			ptree.delReference(n);
-			ptree.delReference(n);
-		}
-		System.out.println("Traverse start");
-		for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
-			Prefix p_result = new Prefix(node.key, node.keyBits);
-		}
-		
-		n = ptree.lookup(r.getAddress(), r.getPrefixLength());
-		if (n != null) {
-			ptree.delReference(n);
-			ptree.delReference(n);
-		}
-		System.out.println("Traverse start");
-		for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
-			Prefix p_result = new Prefix(node.key, node.keyBits);
-		}
-
-	}
-	*/
-	
-	//TODO once the Ptree is object oriented this can go
-	/*
-	private String getPrefixFromPtree(PtreeNode node){
-        InetAddress address = null;
-        try {
-			address = InetAddress.getByAddress(node.key);
-		} catch (UnknownHostException e1) {
-			//Should never happen is the reverse conversion has already been done
-			log.error("Malformed IP address");
-			return "";
-		}
-        return address.toString() + "/" + node.rib.masklen;
-	}
-	*/
-	
 	private void retrieveRib(){
 		String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
 		String response = RestClient.get(url);
@@ -477,21 +367,8 @@
 				continue;
 			}
 			
-			//PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
 			RibEntry rib = new RibEntry(router_id, nexthop);
-			
-			/*
-			if (node.rib != null) {
-				node.rib = null;
-				ptree.delReference(node);
-			}
-			
-			node.rib = rib;
-			*/
-			
-			//ptree.put(p, rib);
-			
-			//addPrefixFlows(p, rib);
+
 			try {
 				ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
 			} catch (InterruptedException e) {
@@ -505,8 +382,8 @@
 		try {
 			ribUpdates.put(update);
 		} catch (InterruptedException e) {
-			// TODO Auto-generated catch block
-			log.debug(" ", e);
+			log.debug("Interrupted while putting on ribUpdates queue", e);
+			Thread.currentThread().interrupt();
 		}
 	}
 	
@@ -515,37 +392,24 @@
 		
 		log.debug("Processing prefix add {}", prefix);
 		
-		//PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
 		RibEntry rib = ptree.put(prefix, update.getRibEntry());
 		
-		//if (node.rib != null) {
 		if (rib != null && !rib.equals(update.getRibEntry())) {
 			//There was an existing nexthop for this prefix. This update supersedes that,
 			//so we need to remove the old flows for this prefix from the switches
-			//deletePrefixFlows(prefix);
 			_processDeletePrefix(prefix, rib);
-			
-			//Then remove the old nexthop from the Ptree
-			//node.rib = null;
-			//ptree.delReference(node);
 		}
 		
-		//Put the new nexthop in the Ptree
-		//node.rib = update.getRibEntry();
-		
-		//log.debug("hurro {}", InetAddresses.forString("0.0.0.0").getHostAddress()); 
-				//InetAddresses.forString("0.0.0.0").getHostAddress()});//, rib.getNextHop().equals(InetAddresses.forString("0.0.0.0"))});
-		if (update.getRibEntry().getNextHop().equals(InetAddresses.forString("0.0.0.0"))) {
+		if (update.getRibEntry().getNextHop().equals(
+				InetAddresses.forString("0.0.0.0"))) {
 			//Route originated by SDN domain
 			//We don't handle these at the moment
-			log.debug("Own route {} to {}", prefix, update.getRibEntry().getNextHop().getHostAddress());
+			log.debug("Own route {} to {}", prefix, 
+					update.getRibEntry().getNextHop().getHostAddress());
 			return;
 		}
 		
 		_processRibAdd(update);
-		
-		//Push flows for the new <prefix, nexthop>
-		//addPrefixFlows(prefix, update.getRibEntry());
 	}
 	
 	private void _processRibAdd(RibUpdate update) {
@@ -554,31 +418,19 @@
 		
 		InetAddress dstIpAddress = rib.getNextHop();
 		
+		//See if we know the MAC address of the next hop
 		byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
-		//Interface egressInterface = null;
-		Interface egressInterface = null;//getEgressInterface(prefix, rib.getNextHop());
 		
+		//Find the attachment point (egress interface) of the next hop
+		Interface egressInterface = null;
 		if (bgpPeers.containsKey(dstIpAddress)) {
 			//Route to a peer
 			log.debug("Route to peer {}", dstIpAddress);
 			BgpPeer peer = bgpPeers.get(dstIpAddress);
 			egressInterface = interfaces.get(peer.getInterfaceName());
-			
-			/*
-			if (nextHopMacAddress == null) {
-				//A RibUpdate is still a nice way to package them up
-				prefixesWaitingOnArp.put(rib.getNextHop(), 
-						new RibUpdate(Operation.UPDATE, prefix, rib));
-				proxyArp.sendArpRequest(rib.getNextHop(), this, true);
-				return;
-			}
-			else {
-				addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
-			}
-			*/
 		}
 		else {
-			//Route to someone else
+			//Route to non-peer
 			log.debug("Route to non-peer {}", dstIpAddress);
 			egressInterface = interfacePtrie.match(
 					new Prefix(dstIpAddress.getAddress(), 32));
@@ -586,23 +438,6 @@
 				log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
 				return;
 			}
-			/*
-			if (nextHopMacAddress == null) {
-				//A RibUpdate is still a nice way to package them up
-				prefixesWaitingOnArp.put(rib.getNextHop(), 
-						new RibUpdate(Operation.UPDATE, prefix, rib));
-				//pathsWaitingOnArp.put(rib.getNextHop(), 
-					//	new PathUpdate(egressInterface, rib.getNextHop()));
-				
-				proxyArp.sendArpRequest(rib.getNextHop(), this, true);
-				return;
-			}
-			else {
-				//calculateAndPushPath(egressInterface, new MACAddress(nextHopMacAddress));
-				setUpDataPath(egressInterface, rib.getNextHop(), MACAddress.valueOf(nextHopMacAddress));
-				//installPathToNextHop(egressInterface, rib.getNextHop());
-				addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
-			}*/
 		}
 		
 		if (nextHopMacAddress == null) {
@@ -613,65 +448,107 @@
 		}
 		else {
 			if (!bgpPeers.containsKey(dstIpAddress)) {
-				//setUpDataPath(new PathUpdate(egressInterface, dstIpAddress),
-				//PathUpdate path = new PathUpdate(egressInterface, dstIpAddress);
-				PathUpdate path = pushedPaths.get(dstIpAddress);
+				//If the prefix is for a non-peer we need to ensure there's a path,
+				//and push one if there isn't.
+				Path path = pushedPaths.get(dstIpAddress);
 				if (path == null) {
-					path = new PathUpdate(egressInterface, dstIpAddress);
+					path = new Path(egressInterface, dstIpAddress);
+					setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
 					pushedPaths.put(dstIpAddress, path);
 				}
-				//PathUpdate path = setUpDataPath(egressInterface, dstIpAddress,
-				//		MACAddress.valueOf(nextHopMacAddress));
-				setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
 				
 				path.incrementUsers();
 				prefixToPath.put(prefix, path);
 			}
+			
+			//For all prefixes we need to add the first-hop mac-rewriting flows
 			addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
 		}
 	}
 	
-	/*
-	private Interface getEgressInterface(Prefix prefix, InetAddress nextHop) {
-		if (bgpPeers.containsKey(nextHop)) {
-			//Route to a peer
-			log.debug("Route to peer {}", nextHop);
-			BgpPeer peer = bgpPeers.get(nextHop);
-			return interfaces.get(peer.getInterfaceName());			
-		}
-		else {
-			//Route to someone else
-			log.debug("Route to non-peer {}", nextHop);
-			return interfacePtrie.match(prefix);
+	private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {		
+		log.debug("Adding flows for prefix {} added, next hop mac {}",
+				prefix, HexString.toHexString(nextHopMacAddress));
+
+		//Add a flow to rewrite mac for this prefix to all other border switches
+		for (Interface srcInterface : interfaces.values()) {
+			if (srcInterface == egressInterface) {
+				//Don't push a flow for the switch where this peer is attached
+				continue;
+			}
+						
+			DataPath shortestPath = topoRouteService.getShortestPath(
+					srcInterface.getSwitchPort(),
+					egressInterface.getSwitchPort());
+			
+			if (shortestPath == null){
+				log.debug("Shortest path between {} and {} not found",
+						srcInterface.getSwitchPort(),
+						egressInterface.getSwitchPort());
+				return; // just quit here?
+			}
+			
+			//Set up the flow mod
+			OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
+					.getMessage(OFType.FLOW_MOD);
+			
+	        fm.setIdleTimeout((short)0)
+	        .setHardTimeout((short)0)
+	        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+	        .setCookie(MAC_RW_COOKIE)
+	        .setCommand(OFFlowMod.OFPFC_ADD)
+	        .setPriority(SDNIP_PRIORITY)
+	        .setLengthU(OFFlowMod.MINIMUM_LENGTH
+	        		+ OFActionDataLayerDestination.MINIMUM_LENGTH
+	        		+ OFActionOutput.MINIMUM_LENGTH);
+	        
+	        OFMatch match = new OFMatch();
+	        match.setDataLayerType(Ethernet.TYPE_IPv4);
+	        match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+	        
+	        match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
+	        fm.setMatch(match);
+	        
+	        //Set up MAC rewrite action
+	        OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
+	        macRewriteAction.setDataLayerAddress(nextHopMacAddress);
+	        
+	        //Set up output action
+	        OFActionOutput outputAction = new OFActionOutput();
+	        outputAction.setMaxLength((short)0xffff);
+	        Port outputPort = shortestPath.flowEntries().get(0).outPort();
+	        outputAction.setPort(outputPort.value());
+	        
+	        List<OFAction> actions = new ArrayList<OFAction>();
+	        actions.add(macRewriteAction);
+	        actions.add(outputAction);
+	        fm.setActions(actions);
+	        
+	        //Write to switch
+	        IOFSwitch sw = floodlightProvider.getSwitches()
+	        			.get(srcInterface.getDpid());
+	        
+            if (sw == null){
+            	log.warn("Switch not found when pushing flow mod");
+            	continue;
+            }
+            
+            pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
+            
+            List<OFMessage> msglist = new ArrayList<OFMessage>();
+            msglist.add(fm);
+            try {
+				sw.write(msglist, null);
+				sw.flush();
+			} catch (IOException e) {
+				log.error("Failure writing flow mod", e);
+			}
 		}
 	}
-	*/
 	
 	public synchronized void processRibDelete(RibUpdate update) {
 		Prefix prefix = update.getPrefix();
 		
-		//PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
-		
-		/* 
-		 * Remove the flows from the switches before the rib is lost
-		 * Theory: we could get a delete for a prefix not in the Ptree.
-		 * This would result in a null node being returned. We could get a delete for
-		 * a node that's not actually there, but is a aggregate node. This would result
-		 * in a non-null node with a null rib. Only a non-null node with a non-null
-		 * rib is an actual prefix in the Ptree.
-		 */
-
-		/*
-		if (node != null && node.rib != null) {
-			if (update.getRibEntry().equals(node.rib)) {
-				node.rib = null;
-				ptree.delReference(node);
-				
-				deletePrefixFlows(update.getPrefix());
-			}
-		}
-		*/
-		
 		if (ptree.remove(prefix, update.getRibEntry())) {
 			/*
 			 * Only delete flows if an entry was actually removed from the trie.
@@ -679,8 +556,6 @@
 			 * it's probably already been removed and we don't need to do anything
 			 */
 			_processDeletePrefix(prefix, update.getRibEntry());
-			
-			//TODO may need to delete a path here too
 		}
 	}
 	
@@ -691,7 +566,7 @@
 		log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
 		if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
 			log.debug("Getting path for route with non-peer nexthop");
-			PathUpdate path = prefixToPath.get(prefix);
+			Path path = prefixToPath.get(prefix);
 			
 			if (path == null) {
 				log.error("No path found for non-peer path");
@@ -705,7 +580,23 @@
 		}
 	}
 	
-	private void deletePath(PathUpdate path) {
+	private void deletePrefixFlows(Prefix prefix) {	
+		Collection<PushedFlowMod> pushedFlowMods 
+				= pushedFlows.removeAll(prefix);
+		
+		for (PushedFlowMod pfm : pushedFlowMods) {
+			log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
+					new Object[] {HexString.toHexString(pfm.getDpid()),
+					pfm.getFlowMod().getMatch().getNetworkDestination() + 
+					pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
+					HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
+							.getDataLayerAddress())});
+			
+			sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
+		}
+	}
+	
+	private void deletePath(Path path) {
 		for (PushedFlowMod pfm : path.getFlowMods()) {
 			log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
 					new Object[] {HexString.toHexString(pfm.getDpid()),
@@ -737,204 +628,8 @@
 		}
 	}
 	
-	//TODO compatibility layer, used by beginRouting()
-	/*public void prefixAdded(PtreeNode node) {
-		Prefix prefix = null;
-		try {
-			prefix = new Prefix(node.key, node.rib.masklen);
-		} catch (IllegalArgumentException e) {
-			log.error(" ", e);
-		}
-
-		addPrefixFlows(prefix, node.rib);
-	}*/
-
-	private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
-		//TODO get rid of this
-		/*if (!topologyReady){
-			return;
-		}*/
-		
-		//TODO before we do anything, we have to check that the RIB entry is still in the
-		//Ptree because it could have been removed while we were waiting for ARP.
-		//I think we'll have to make prefixAdded and prefixDelete atomic as well
-		//to protect against the prefix getting deleted while where trying to add it
-
-		log.debug("Adding flows for prefix {} added, next hop mac {}",
-				prefix, HexString.toHexString(nextHopMacAddress));
-				//prefix, rib.getNextHop().getHostAddress());
-		
-
-		
-		//TODO this is wrong, we shouldn't be dealing with BGP peers here.
-		//We need to figure out where the device is attached and what its
-		//mac address is by learning. 
-		//The next hop is not necessarily the peer, and the peer's attachment
-		//point is not necessarily the next hop's attachment point.
-
-		
-		
-		//if (peer == null){
-			//TODO local router isn't in peers list so this will get thrown
-			//Need to work out what to do about local prefixes with next hop 0.0.0.0.
-			
-			//The other scenario is this is a route server route. In that
-			//case the next hop is not in our configuration
-			//log.error("Couldn't find next hop router in router {} in config",
-			//		rib.getNextHop().getHostAddress());
-			//return; //just quit out here? This is probably a configuration error
-		//}
-		
-		//Get MAC address for peer from the ARP module
-		//TODO separate out the 'ask for MAC' bit to another method
-		//byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
-		//byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
-		//if (nextHopMacAddress == null) {
-
-		//}
-		
-		//Interface peerInterface = interfaces.get(peer.getInterfaceName());
-
-		//Add a flow to rewrite mac for this prefix to all border switches
-		for (Interface srcInterface : interfaces.values()) {
-			if (srcInterface == egressInterface) {
-				//Don't push a flow for the switch where this peer is attached
-				continue;
-			}
-						
-			DataPath shortestPath = topoRouteService.getShortestPath(
-					srcInterface.getSwitchPort(),
-					egressInterface.getSwitchPort());
-			
-			if (shortestPath == null){
-				log.debug("Shortest path between {} and {} not found",
-						srcInterface.getSwitchPort(),
-						egressInterface.getSwitchPort());
-				return; // just quit here?
-			}
-			
-			//Set up the flow mod
-			OFFlowMod fm =
-	                (OFFlowMod) floodlightProvider.getOFMessageFactory()
-	                                              .getMessage(OFType.FLOW_MOD);
-			
-	        fm.setIdleTimeout((short)0)
-	        .setHardTimeout((short)0)
-	        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-	        .setCookie(MAC_RW_COOKIE)
-	        .setCommand(OFFlowMod.OFPFC_ADD)
-	        .setPriority(SDNIP_PRIORITY)
-	        .setLengthU(OFFlowMod.MINIMUM_LENGTH
-	        		+ OFActionDataLayerDestination.MINIMUM_LENGTH
-	        		+ OFActionOutput.MINIMUM_LENGTH);
-	        
-	        OFMatch match = new OFMatch();
-	        match.setDataLayerType(Ethernet.TYPE_IPv4);
-	        match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
-	        
-	        /*
-	        InetAddress address = null;
-	        try {
-	        	address = InetAddress.getByAddress(prefix.getAddress());
-			} catch (UnknownHostException e1) {
-				//Should never happen is the reverse conversion has already been done
-				log.error("Malformed IP address");
-				return;
-			}*/
-	        
-	        //match.setFromCIDR(address.getHostAddress() + "/" + 
-	        //		prefix.getPrefixLength(), OFMatch.STR_NW_DST);
-	        match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
-	        fm.setMatch(match);
-	        
-	        //Set up MAC rewrite action
-	        OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
-	        //TODO the peer's mac address is not necessarily the next hop's...
-	        macRewriteAction.setDataLayerAddress(nextHopMacAddress);
-	        
-	        //Set up output action
-	        OFActionOutput outputAction = new OFActionOutput();
-	        outputAction.setMaxLength((short)0xffff);
-	        
-	        Port outputPort = shortestPath.flowEntries().get(0).outPort();
-	        outputAction.setPort(outputPort.value());
-	        
-	        List<OFAction> actions = new ArrayList<OFAction>();
-	        actions.add(macRewriteAction);
-	        actions.add(outputAction);
-	        fm.setActions(actions);
-	        
-	        //Write to switch
-	        IOFSwitch sw = floodlightProvider.getSwitches()
-	        			.get(srcInterface.getDpid());
-	        
-            if (sw == null){
-            	log.warn("Switch not found when pushing flow mod");
-            	continue;
-            }
-            
-            //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
-            pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
-            
-            List<OFMessage> msglist = new ArrayList<OFMessage>();
-            msglist.add(fm);
-            try {
-				sw.write(msglist, null);
-				sw.flush();
-			} catch (IOException e) {
-				log.error("Failure writing flow mod", e);
-			}
-		}
-	}
-	
 	//TODO test next-hop changes
 	//TODO check delete/add synchronization
-		
-	private void deletePrefixFlows(Prefix prefix) {
-		/*if (!topologyReady) {
-			return;
-		}*/
-				
-		/*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
-			log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
-		}*/
-		
-		Collection<PushedFlowMod> pushedFlowMods 
-				= pushedFlows.removeAll(prefix);
-		
-		for (PushedFlowMod pfm : pushedFlowMods) {
-			log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
-					new Object[] {HexString.toHexString(pfm.getDpid()),
-					pfm.getFlowMod().getMatch().getNetworkDestination() + 
-					pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
-					HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
-							.getDataLayerAddress())});
-			
-			sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
-			/*
-			OFFlowMod fm = pfm.getFlowMod();
-			
-			fm.setCommand(OFFlowMod.OFPFC_DELETE)
-			.setOutPort(OFPort.OFPP_NONE)
-			.setLengthU(OFFlowMod.MINIMUM_LENGTH);
-			
-			fm.getActions().clear();
-			
-			IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
-			if (sw == null) {
-            	log.warn("Switch not found when pushing delete flow mod");
-            	continue;
-			}
-			
-			try {
-				sw.write(fm, null);
-				sw.flush();
-			} catch (IOException e) {
-				log.error("Failure writing flow mod", e);
-			}
-			*/
-		}
-	}
 	
 	/*
 	 * On startup we need to calculate a full mesh of paths between all gateway
@@ -952,7 +647,7 @@
 			
 			//We know there's not already a Path here pushed, because this is
 			//called before all other routing
-			PathUpdate path = new PathUpdate(peerInterface, peer.getIpAddress());
+			Path path = new Path(peerInterface, peer.getIpAddress());
 			path.setPermanent();
 			
 			//See if we know the MAC address of the peer. If not we can't
@@ -961,48 +656,22 @@
 			if (mac == null) {
 				log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
 				//Put in the pending paths list first
-				pathsWaitingOnArp.put(peer.getIpAddress(),
-						//new PathUpdate(peerInterface, peer.getIpAddress()));
-						path);
+				pathsWaitingOnArp.put(peer.getIpAddress(), path);
 				
 				proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
 				continue;
 			}
 			
 			//If we know the MAC, lets go ahead and push the paths to this peer
-			//calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
-			//setUpDataPath(peerInterface, peer.getIpAddress(), MACAddress.valueOf(mac));
 			setUpDataPath(path, MACAddress.valueOf(mac));
 		}
 	}
 	
-	//private void setUpDataPath(Interface dstInterface, InetAddress dstInetAddress,
-	//private PathUpdate setUpDataPath(Interface dstInterface, InetAddress dstInetAddress, MACAddress dstMacAddress) {
-	private void setUpDataPath(PathUpdate path, MACAddress dstMacAddress) {
-		//PathUpdate path = pushedPaths.get(dstInterface);
-		
-		
-		//if (!pushedPaths.containsKey(path.getDstIpAddress())) {
-		//if (path == null) {
-			//PathUpdate path = new PathUpdate(dstInterface, dstInetAddress);
-			//path = new PathUpdate(dstInterface, dstInetAddress);
-			calculateAndPushPath(path, dstMacAddress);
-			//pushedPaths.put(path.getDstIpAddress(), path);
-			//calculateAndPushPath(dstInterface, dstMacAddress);
-			//pushedPaths.put(dstInetAddress, new PathUpdate(dstInterface, dstInetAddress));
-		//}
-		
-		//return path;
-		
-		/*
-		else {
-			existingPath.incrementUsers();
-		}
-		*/
+	private void setUpDataPath(Path path, MACAddress dstMacAddress) {
+		calculateAndPushPath(path, dstMacAddress);
 	}
 	
-	//private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
-	private void calculateAndPushPath(PathUpdate path, MACAddress dstMacAddress) {
+	private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
 		Interface dstInterface = path.getDstInterface();
 		
 		List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
@@ -1021,8 +690,6 @@
 				return; // just quit here?
 			}
 			
-			//List<PushedFlowMod> pushedFlows 
-				//	= installPath(shortestPath.flowEntries(), dstMacAddress);
 			pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
 		}
 		
@@ -1132,7 +799,6 @@
 	        
 	        //Common match fields
 	        forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
-	        //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
 	        forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
 	        forwardMatchSrc.setTransportDestination(BGP_PORT);
 	        forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
@@ -1254,38 +920,33 @@
 		 * could get out of sync. 
 		 */
 		synchronized (this) {
-			Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
+			Path path = pathsWaitingOnArp.remove(ipAddress);
 			
-			for (PathUpdate update : pathsToPush) {
+			if (path != null) {
 				log.debug("Pushing path to {} at {} on {}", new Object[] {
-						update.getDstIpAddress().getHostAddress(), 
+						path.getDstIpAddress().getHostAddress(), 
 						MACAddress.valueOf(macAddress),
-						update.getDstInterface().getSwitchPort()});
-				//calculateAndPushPath(update.getDstInterface(), 
-						//MACAddress.valueOf(macAddress));
-				//setUpDataPath(update.getDstInterface(), update.getDstIpAddress(), 
-				if (pushedPaths.containsKey(update.getDstInterface())) {
+						path.getDstInterface().getSwitchPort()});
+				//These paths should always be to BGP peers. Paths to non-peers are
+				//handled once the first prefix is ready to push
+				if (pushedPaths.containsKey(path.getDstInterface())) {
 					//A path already got pushed to this endpoint while we were waiting
 					//for ARP. We'll copy over the permanent attribute if it is set on this path.
-					if (update.isPermanent()) {
-						pushedPaths.get(update.getDstInterface()).setPermanent();
+					if (path.isPermanent()) {
+						pushedPaths.get(path.getDstInterface()).setPermanent();
 					}
 				}
 				else {
-					setUpDataPath(update, MACAddress.valueOf(macAddress));
-					pushedPaths.put(update.getDstIpAddress(), update);
+					setUpDataPath(path, MACAddress.valueOf(macAddress));
+					pushedPaths.put(path.getDstIpAddress(), path);
 				}
 			}
 			
-			
-			
 			Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
 			
 			for (RibUpdate update : prefixesToPush) {
 				//These will always be adds
 				
-				//addPrefixFlows(update.getPrefix(), update.getRibEntry());
-				//processRibAdd(update);
 				RibEntry rib = ptree.lookup(update.getPrefix()); 
 				if (rib != null && rib.equals(update.getRibEntry())) {
 					log.debug("Pushing prefix {} next hop {}", update.getPrefix(), 
@@ -1294,7 +955,6 @@
 					//and the next hop is the same as our update. The prefix could 
 					//have been removed while we were waiting for the ARP, or the 
 					//next hop could have changed.
-					//addPrefixFlows(update.getPrefix(), rib);
 					_processRibAdd(update);
 				} else {
 					log.debug("Received ARP response, but {},{} is no longer in ptree", 
@@ -1309,32 +969,12 @@
 		setupBgpPaths();
 		setupFullMesh();
 		
-		//Traverse ptree and create flows for all routes
-		/*
-		for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
-			if (node.rib != null){
-				prefixAdded(node);
-			}
-		}
-		*/
-		
-		/*
-		synchronized (ptree) {
-			Iterator<IPatriciaTrie.Entry> it = ptree.iterator();
-			while (it.hasNext()) {
-				IPatriciaTrie.Entry entry = it.next();
-				addPrefixFlows(entry.getPrefix(), entry.getRib());
-			}
-		}
-		*/
-		
 		bgpUpdatesExecutor.execute(new Runnable() {
 			@Override
 			public void run() {
 				doUpdatesThread();
 			}
 		});
-		
 	}
 	
 	private void checkSwitchesConnected(){
@@ -1370,8 +1010,6 @@
 	}
 	
 	private void checkStatus(){
-		//log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
-		
 		if (!switchesConnected){
 			checkSwitchesConnected();
 		}
@@ -1383,19 +1021,7 @@
 			beginRouting();
 		}
 	}
-	
-	@Override
-	public void startUp(FloodlightModuleContext context) {
-		restApi.addRestletRoutable(new BgpRouteWebRoutable());
-		floodlightProvider.addOFSwitchListener(this);
-		topology.addListener(this);
-		
-		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
-		
-		//Retrieve the RIB from BGPd during startup
-		retrieveRib();
-	}
-	
+
 	private void doUpdatesThread() {
 		boolean interrupted = false;
 		try {
@@ -1411,7 +1037,7 @@
 						break;
 					}
 				} catch (InterruptedException e) {
-					log.debug("interrupted", e);
+					log.debug("Interrupted while taking from updates queue", e);
 					interrupted = true;
 				} catch (Exception e) {
 					log.debug("exception", e);
@@ -1447,23 +1073,4 @@
 			topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
 		}
 	}
-
-	//TODO determine whether we need to listen for switch joins
-	@Override
-	public void addedSwitch(IOFSwitch sw) {
-		//checkStatus();
-	}
-
-	@Override
-	public void removedSwitch(IOFSwitch sw) {
-		// TODO Auto-generated method stub	
-	}
-
-	@Override
-	public void switchPortChanged(Long switchId) {}
-
-	@Override
-	public String getName() {
-		return "BgpRoute";
-	}
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PathUpdate.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java
similarity index 91%
rename from src/main/java/net/onrc/onos/ofcontroller/bgproute/PathUpdate.java
rename to src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java
index c39b51d..5cf4b09 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PathUpdate.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java
@@ -9,7 +9,7 @@
  * switchports) to the destination interface.
  */
 
-public class PathUpdate {
+public class Path {
 
 	private Interface dstInterface;
 	private InetAddress dstIpAddress;
@@ -18,7 +18,7 @@
 	private List<PushedFlowMod> flowMods = null;
 	private boolean permanent = false;
 	
-	public PathUpdate(Interface dstInterface, InetAddress dstIpAddress) {
+	public Path(Interface dstInterface, InetAddress dstIpAddress) {
 		this.dstInterface = dstInterface;
 		this.dstIpAddress = dstIpAddress;
 	}