Merged with the latest master
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 486d057..4b6e328 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -14,17 +14,19 @@
 
 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;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.devicemanager.IDeviceService;
-import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.topology.ITopologyListener;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.onrc.onos.ofcontroller.util.DataPath;
 import net.onrc.onos.ofcontroller.util.FlowEntry;
 import net.onrc.onos.ofcontroller.util.Port;
@@ -36,7 +38,6 @@
 import org.codehaus.jackson.JsonParseException;
 import org.codehaus.jackson.map.JsonMappingException;
 import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.openflow.protocol.OFFlowMod;
 import org.openflow.protocol.OFMatch;
 import org.openflow.protocol.OFMessage;
@@ -45,12 +46,14 @@
 import org.openflow.protocol.action.OFAction;
 import org.openflow.protocol.action.OFActionDataLayerDestination;
 import org.openflow.protocol.action.OFActionOutput;
+import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.net.InetAddresses;
 
-public class BgpRoute implements IFloodlightModule, IBgpRouteService, ITopologyListener {
+public class BgpRoute implements IFloodlightModule, IBgpRouteService, 
+									ITopologyListener, IOFSwitchListener {
 	
 	protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
 
@@ -79,16 +82,27 @@
 	protected final short SDNIP_PRIORITY = 10;
 	
 	protected Map<String, GatewayRouter> gatewayRouters;
+	protected List<String> switches;
+	
+	//True when all switches have connected
+	protected volatile boolean switchesConnected = false;
+	//True when we have a full mesh of shortest paths between gateways
+	protected volatile boolean topologyReady = false;
 	
 	private void readGatewaysConfiguration(String gatewaysFilename){
 		File gatewaysFile = new File(gatewaysFilename);
 		ObjectMapper mapper = new ObjectMapper();
 		
-		TypeReference<HashMap<String, GatewayRouter>> typeref 
-			= new TypeReference<HashMap<String, GatewayRouter>>() {};
-		
 		try {
-			gatewayRouters = mapper.readValue(gatewaysFile, typeref);
+			Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
+			
+			gatewayRouters = config.getGateways();
+			switches = config.getSwitches();
+			
+			for (String sw : switches){
+				log.debug("Switchjoin {}", sw);
+			}
+			
 		} catch (JsonParseException e) {
 			log.error("Error in JSON file", e);
 			System.exit(1);
@@ -265,6 +279,18 @@
 
 	}
 	
+	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);
@@ -318,6 +344,15 @@
 	}
 	
 	public void prefixAdded(PtreeNode node) {
+		if (!topologyReady){
+			return;
+		}
+		
+		String prefix = getPrefixFromPtree(node);
+		
+		log.debug("New prefix {} added, next hop {}", 
+				prefix, node.rib.nextHop.toString());
+		
 		//Add a flow to rewrite mac for this prefix to all border switches
 		GatewayRouter thisRouter = gatewayRouters
 				.get(InetAddresses.toAddrString(node.rib.nextHop));
@@ -425,15 +460,88 @@
 	}
 	
 	public void prefixDeleted(PtreeNode node) {
-		//Remove MAC rewriting flows from other border switches
+		if (!topologyReady) {
+			return;
+		}
 		
+		String prefix = getPrefixFromPtree(node);
+		
+		log.debug("Prefix {} deleted, next hop {}", 
+				prefix, node.rib.nextHop.toString());
+		
+		//Remove MAC rewriting flows from other border switches
+		GatewayRouter thisRouter = gatewayRouters
+				.get(InetAddresses.toAddrString(node.rib.nextHop));
+		
+		for (GatewayRouter ingressRouter : gatewayRouters.values()){
+			if (ingressRouter == thisRouter) {
+				continue;
+			}
+			
+			//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_DELETE)
+	        //.setMatch(match)
+	        //.setActions(actions)
+	        .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.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
+	        match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
+	        
+	        //match.setDataLayerDestination(ingressRouter.getSdnRouterMac().toBytes());
+	        //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
+
+	        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;
+			}
+	        
+	        match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
+	        fm.setMatch(match);
+	        
+	        //Write to switch
+	        IOFSwitch sw = floodlightProvider.getSwitches()
+	        		.get(ingressRouter.getAttachmentPoint().dpid().value());
+	        
+            if (sw == null){
+            	log.warn("Switch not found when pushing flow mod");
+            	continue;
+            }
+            
+            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);
+			}
+		}
 	}
 	
 	/*
 	 * On startup we need to calculate a full mesh of paths between all gateway
 	 * switches
 	 */
-	private void calculateFullMesh(){
+	private void setupFullMesh(){
 		Map<IOFSwitch, SwitchPort> gatewaySwitches = new HashMap<IOFSwitch, SwitchPort>();
 		
 		//have to account for switches not being there, paths not being found.
@@ -455,7 +563,6 @@
 			}
 			
 		}
-		log.debug("size {}", gatewaySwitches.size());
 		
 		//For each border router, calculate and install a path from every other
 		//border switch to said border router. However, don't install the entry
@@ -544,46 +651,118 @@
 		}
 	}
 	
+	
+	private void beginRouting(){
+		log.debug("Topology is now ready, beginning routing function");
+		
+		//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);
+			}
+		}
+	}
+	
+	private void checkSwitchesConnected(){
+		for (String dpid : switches){
+			if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
+				log.debug("Not all switches are here yet");
+				return;
+			}
+		}
+		switchesConnected = true;
+	}
+	
+	private void checkTopologyReady(){
+		for (GatewayRouter dstRouter : gatewayRouters.values()){
+			SwitchPort dstAttachmentPoint = dstRouter.getAttachmentPoint();
+			for (GatewayRouter srcRouter : gatewayRouters.values()) {
+				
+				if (dstRouter == srcRouter){
+					continue;
+				}
+				
+				SwitchPort srcAttachmentPoint = srcRouter.getAttachmentPoint();
+				
+				DataPath shortestPath = topoRouteService.getShortestPath(
+						srcAttachmentPoint, dstAttachmentPoint);
+				
+				if (shortestPath == null){
+					log.debug("Shortest path between {} and {} not found",
+							srcAttachmentPoint, dstAttachmentPoint);
+					return;
+				}
+			}
+		}
+		topologyReady = true;
+	}
+	
+	private void checkStatus(){
+		log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
+		
+		if (!switchesConnected){
+			checkSwitchesConnected();
+		}
+		boolean oldTopologyReadyStatus = topologyReady;
+		if (switchesConnected && !topologyReady){
+			checkTopologyReady();
+		}
+		if (!oldTopologyReadyStatus && topologyReady){
+			beginRouting();
+		}
+	}
+	
 	@Override
 	public void startUp(FloodlightModuleContext context) {
 		restApi.addRestletRoutable(new BgpRouteWebRoutable());
+		floodlightProvider.addOFSwitchListener(this);
 		topology.addListener(this);
 		
 		//Retrieve the RIB from BGPd during startup
 		retrieveRib();
-		
-		//Don't have to do this as we'll never have switches connected here
-		//calculateFullMesh();
 	}
 
 	@Override
-	public void topologyChanged() {
-		//Probably need to look at all changes, not just port changes
-		/*
-		boolean change = false;
-		String changelog = "";
+	public void topologyChanged() {		
+		//There seems to be more topology events than there should be. Lots of link
+		//updated, port up and switch updated on what should be a fairly static topology
 		
-		for (LDUpdate ldu : topology.getLastLinkUpdates()) {
-			if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.PORT_DOWN)) {
-				change = true;
-				changelog = changelog + " down ";
-			} else if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.PORT_UP)) {
-				change = true;
-				changelog = changelog + " up ";
+		boolean refreshNeeded = false;
+		for (LDUpdate ldu : topology.getLastLinkUpdates()){
+			if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
+				//We don't need to recalculate anything for just link updates
+				//They happen way too frequently (may be a bug in our link discovery)
+				refreshNeeded = true;
+			}
+			log.debug("Topo change {}", ldu.getOperation());
+		}
+		
+		if (refreshNeeded){
+			if (topologyReady){
+				setupFullMesh();
+			}
+			else{
+				checkStatus();
 			}
 		}
-		log.info ("received topo change" + changelog);
+	}
 
-		if (change) {
-			//RestClient.get ("http://localhost:5000/topo_change");
-		}
-		*/
-		
-		for (LDUpdate update : topology.getLastLinkUpdates()){
-			log.debug("{} event causing internal L2 path recalculation",
-					update.getOperation().toString());
-			
-		}
-		calculateFullMesh();
+	//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/BgpRouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
index 34c5c43b..8355308 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
@@ -184,6 +184,16 @@
 			}
 
 			PtreeNode node = ptree.lookup(p.getAddress(), p.masklen);
+			
+			//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){
+				bgpRoute.prefixDeleted(node);
+			}
 
 			Rib r = new Rib(routerId, nextHop, p.masklen);
 
@@ -193,8 +203,6 @@
 					ptree.delReference(node);					
 				}
 			}
-
-			bgpRoute.prefixDeleted(node);
 			
 			reply =reply + "[DELE: " + prefix + "/" + mask + ":" + nextHop + "]";
 		}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
new file mode 100644
index 0000000..5194584
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
@@ -0,0 +1,34 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class Configuration {
+	List<String> switches;
+	Map<String, GatewayRouter> gateways;
+	
+	public Configuration() {
+		// TODO Auto-generated constructor stub
+	}
+
+	public List<String> getSwitches() {
+		return switches;
+	}
+
+	@JsonProperty("switches")
+	public void setSwitches(List<String> switches) {
+		this.switches = switches;
+	}
+
+	public Map<String, GatewayRouter> getGateways() {
+		return gateways;
+	}
+
+	@JsonProperty("gateways")
+	public void setGateways(Map<String, GatewayRouter> gateways) {
+		this.gateways = gateways;
+	}
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/IDeviceStorage.java b/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
similarity index 83%
rename from src/main/java/net/onrc/onos/ofcontroller/devicemanager/IDeviceStorage.java
rename to src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
index d4355c6..7310d8c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/IDeviceStorage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
@@ -1,7 +1,6 @@
-package net.onrc.onos.ofcontroller.devicemanager;
+package net.onrc.onos.ofcontroller.core;
 
 import net.floodlightcontroller.devicemanager.IDevice;
-import net.onrc.onos.ofcontroller.core.INetMapStorage;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
 
 public interface IDeviceStorage extends INetMapStorage {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkStorage.java b/src/main/java/net/onrc/onos/ofcontroller/core/ILinkStorage.java
similarity index 88%
rename from src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkStorage.java
rename to src/main/java/net/onrc/onos/ofcontroller/core/ILinkStorage.java
index 5150668..b56cfef 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkStorage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/ILinkStorage.java
@@ -1,10 +1,9 @@
-package net.onrc.onos.ofcontroller.linkdiscovery;
+package net.onrc.onos.ofcontroller.core;
 
 import java.util.List;
 
-import net.floodlightcontroller.linkdiscovery.LinkInfo;
 import net.floodlightcontroller.routing.Link;
-import net.onrc.onos.ofcontroller.core.INetMapStorage;
+import net.onrc.onos.ofcontroller.linkdiscovery.LinkInfo;
 
 public interface ILinkStorage extends INetMapStorage {
 	
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
index 3cfa190..fc1c32f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -1,7 +1,6 @@
 package net.onrc.onos.ofcontroller.core;
 
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
-import net.onrc.onos.ofcontroller.flowcache.web.DatapathSummarySerializer;
+import net.onrc.onos.ofcontroller.flowmanager.web.DatapathSummarySerializer;
 
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
@@ -49,7 +48,7 @@
 
 // Requires Frames 2.3.0		
 		@JsonIgnore
-		@GremlinGroovy("_().out('on').has('number',port_num)")
+		@GremlinGroovy("it.out('on').has('number',port_num)")
 		public IPortObject getPort(@GremlinParam("port_num") final short port_num);
 		
 		@Adjacency(label="on")
@@ -59,7 +58,7 @@
 		public void removePort(final IPortObject port);
 		
 		@JsonIgnore
-		@GremlinGroovy("_().out('on').out('host')")
+		@GremlinGroovy("it.out('on').out('host')")
 		public Iterable<IDeviceObject> getDevices();
 		
 		@JsonIgnore
@@ -92,6 +91,7 @@
 		public void setPortState(Integer s);
 		
 		@JsonIgnore
+//		@GremlinGroovy("it.in('on')")
 		@Adjacency(label="on",direction = Direction.IN)
 		public ISwitchObject getSwitch();
 				
@@ -155,7 +155,7 @@
 		public void removeHostPort(final IPortObject port);
 		
 		@JsonIgnore
-		@GremlinGroovy("_().in('host').in('on')")
+		@GremlinGroovy("it.in('host').in('on')")
 		public Iterable<ISwitchObject> getSwitch();
 		
 /*		@JsonProperty("dpid")
@@ -268,7 +268,7 @@
 		public void setMatchDstIPv4Net(String matchDstIPv4Net);
 		
 		@JsonIgnore
-		@GremlinGroovy("_().in('flow').out('switch')")
+		@GremlinGroovy("it.in('flow').out('switch')")
 		public Iterable<ISwitchObject> getSwitches();
 		
 		@JsonIgnore
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/IOFSwitchPortListener.java b/src/main/java/net/onrc/onos/ofcontroller/core/IOFSwitchPortListener.java
new file mode 100644
index 0000000..5deae69
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/IOFSwitchPortListener.java
@@ -0,0 +1,26 @@
+/**
+ * 
+ */
+package net.onrc.onos.ofcontroller.core;
+
+import org.openflow.protocol.OFPhysicalPort;
+
+import net.floodlightcontroller.core.IOFSwitchListener;
+
+/**
+ * @author y-higuchi
+ *
+ */
+public interface IOFSwitchPortListener extends IOFSwitchListener {
+
+	/**
+	 * Fired when ports on a switch area added
+	 */
+	public void switchPortAdded(Long switchId, OFPhysicalPort port);
+
+	/**
+	 * Fired when ports on a switch area removed
+	 */
+	public void switchPortRemoved(Long switchId, OFPhysicalPort port);
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/IOnosRemoteSwitch.java b/src/main/java/net/onrc/onos/ofcontroller/core/IOnosRemoteSwitch.java
new file mode 100644
index 0000000..c9b0e2f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/IOnosRemoteSwitch.java
@@ -0,0 +1,20 @@
+/**
+ * 
+ */
+package net.onrc.onos.ofcontroller.core;
+
+import net.floodlightcontroller.core.IOFSwitch;
+
+/**
+ * @author y-higuchi
+ *
+ */
+public interface IOnosRemoteSwitch extends IOFSwitch {
+
+	/**
+	 * Setup an unconnected switch with the info required.
+	 * @param dpid of the switch
+	 */
+	public void setupRemoteSwitch(Long dpid);
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/Main.java b/src/main/java/net/onrc/onos/ofcontroller/core/Main.java
new file mode 100644
index 0000000..a80ac36
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/Main.java
@@ -0,0 +1,50 @@
+package net.onrc.onos.ofcontroller.core;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.internal.CmdLineSettings;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.FloodlightModuleLoader;
+import net.floodlightcontroller.core.module.IFloodlightModuleContext;
+import net.floodlightcontroller.restserver.IRestApiService;
+
+/**
+ * Host for the ONOS main method
+ * @author alexreimers
+ */
+public class Main {
+
+    /**
+     * Main method to load configuration and modules
+     * @param args
+     * @throws FloodlightModuleException 
+     */
+    public static void main(String[] args) throws FloodlightModuleException {
+        // Setup logger
+        System.setProperty("org.restlet.engine.loggerFacadeClass", 
+                "org.restlet.ext.slf4j.Slf4jLoggerFacade");
+        
+        CmdLineSettings settings = new CmdLineSettings();
+        CmdLineParser parser = new CmdLineParser(settings);
+        try {
+            parser.parseArgument(args);
+        } catch (CmdLineException e) {
+            parser.printUsage(System.out);
+            System.exit(1);
+        }
+        
+        // Load modules
+        FloodlightModuleLoader fml = new FloodlightModuleLoader();
+        IFloodlightModuleContext moduleContext = fml.loadModulesFromConfig(settings.getModuleFile());
+        // Run REST server
+        IRestApiService restApi = moduleContext.getServiceImpl(IRestApiService.class);
+        restApi.run();
+        // Run the main floodlight module
+        IFloodlightProviderService controller =
+                moduleContext.getServiceImpl(IFloodlightProviderService.class);
+        // This call blocks, it has to be the last line in the main
+        controller.run();
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/internal/DeviceStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
similarity index 95%
rename from src/main/java/net/onrc/onos/ofcontroller/devicemanager/internal/DeviceStorageImpl.java
rename to src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
index 98b4a88..dcb28ce 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/internal/DeviceStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.ofcontroller.devicemanager.internal;
+package net.onrc.onos.ofcontroller.core.internal;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -11,12 +11,10 @@
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.packet.IPv4;
+import net.onrc.onos.ofcontroller.core.IDeviceStorage;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
-import net.onrc.onos.ofcontroller.devicemanager.IDeviceStorage;
-import net.onrc.onos.util.GraphDBConnection;
-import net.onrc.onos.util.GraphDBConnection.Transaction;
 import net.onrc.onos.util.GraphDBOperation;
 
 /**
@@ -25,7 +23,6 @@
  */
 public class DeviceStorageImpl implements IDeviceStorage {
 	
-	private GraphDBConnection conn;
 	private GraphDBOperation ope;
 	protected static Logger log = LoggerFactory.getLogger(SwitchStorageImpl.class);
 
@@ -36,10 +33,7 @@
 	@Override
 	public void init(String conf) {
 		try{
-			if((conn = GraphDBConnection.getInstance(conf)) != null)
-			{
-				ope = new GraphDBOperation(conn);
-			}
+			ope = new GraphDBOperation(conf);
 		} catch(Exception e) {
 			log.error(e.getMessage());
 		}
@@ -51,7 +45,7 @@
 	 */
 	@Override
 	public void close() {
-		conn.close();
+		ope.close();
 	}
 	
 	/***
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
new file mode 100644
index 0000000..b33591e
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
@@ -0,0 +1,347 @@
+package net.onrc.onos.ofcontroller.core.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.floodlightcontroller.routing.Link;
+import net.onrc.onos.ofcontroller.core.ILinkStorage;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.linkdiscovery.LinkInfo;
+import net.onrc.onos.util.GraphDBOperation;
+
+import org.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.thinkaurelius.titan.core.TitanException;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.PathPipe;
+
+public class LinkStorageImpl implements ILinkStorage {
+	
+	protected static Logger log = LoggerFactory.getLogger(LinkStorageImpl.class);
+	protected GraphDBOperation dbop;
+
+	/**
+	 * Update a record in the LinkStorage in a way provided by op.
+	 * @param link Record of a link to be updated.
+	 * @param op Operation to be done.
+	 */
+	@Override
+	public void update(Link link, DM_OPERATION op) {
+		update(link, (LinkInfo)null, op);
+	}
+
+	/**
+	 * Update multiple records in the LinkStorage in a way provided by op.
+	 * @param links List of records to be updated.
+	 * @param op Operation to be done.
+	 */
+	@Override
+	public void update(List<Link> links, DM_OPERATION op) {
+		for (Link lt: links) {
+			update(lt, (LinkInfo)null, op);
+		}
+	}
+
+	/**
+	 * Update a record of link with meta-information in the LinkStorage in a way provided by op.
+	 * @param link Record of a link to update.
+	 * @param linkinfo Meta-information of a link to be updated.
+	 * @param op Operation to be done.
+	 */
+	@Override
+	public void update(Link link, LinkInfo linkinfo, DM_OPERATION op) {
+		switch (op) {
+		case UPDATE:
+		case CREATE:
+		case INSERT:
+			updateLink(link, linkinfo, op);
+			break;
+		case DELETE:
+			deleteLink(link);
+			break;
+		}
+	}
+	
+	/**
+	 * Perform INSERT/CREATE/UPDATE operation to update the LinkStorage.
+	 * @param lt Record of a link to be updated.
+	 * @param linkinfo Meta-information of a link to be updated.
+	 * @param op Operation to be done. (only INSERT/CREATE/UPDATE is acceptable)
+	 */
+	public void updateLink(Link lt, LinkInfo linkinfo, DM_OPERATION op) {
+		IPortObject vportSrc = null, vportDst = null;
+	
+		log.trace("updateLink(): op {} {} {}", new Object[]{op, lt, linkinfo});
+		
+        try {
+            // get source port vertex
+        	String dpid = HexString.toHexString(lt.getSrc());
+        	short port = lt.getSrcPort();
+        	vportSrc = dbop.searchPort(dpid, port);
+            
+            // get dest port vertex
+            dpid = HexString.toHexString(lt.getDst());
+            port = lt.getDstPort();
+            vportDst = dbop.searchPort(dpid, port);
+                        
+            if (vportSrc != null && vportDst != null) {
+            	// check if the link exists
+            	
+            	Iterable<IPortObject> currPorts = vportSrc.getLinkedPorts();
+            	List<IPortObject> currLinks = new ArrayList<IPortObject>();
+            	for (IPortObject V : currPorts) {
+            		currLinks.add(V);
+            	}
+
+            	if (currLinks.contains(vportDst)) {
+            		// TODO: update linkinfo
+            		if (op.equals(DM_OPERATION.INSERT) || op.equals(DM_OPERATION.CREATE)) {
+            			log.debug("addOrUpdateLink(): failed link exists {} {} src {} dst {}", 
+            					new Object[]{op, lt, vportSrc, vportDst});
+            		}
+            	} else {
+            		vportSrc.setLinkPort(vportDst);
+
+            		dbop.commit();
+            		log.debug("updateLink(): link added {} {} src {} dst {}", new Object[]{op, lt, vportSrc, vportDst});
+            	}
+            } else {
+            	log.error("updateLink(): failed invalid vertices {} {} src {} dst {}", new Object[]{op, lt, vportSrc, vportDst});
+            	dbop.rollback();
+            }
+        } catch (TitanException e) {
+            /*
+             * retry till we succeed?
+             */
+        	e.printStackTrace();
+        	log.error("updateLink(): titan exception {} {} {}", new Object[]{op, lt, e.toString()});
+        }
+	}
+	
+	/**
+	 * Delete multiple records in the LinkStorage.
+	 * @param links List of records to be deleted.
+	 */
+	@Override
+	public void deleteLinks(List<Link> links) {
+
+		for (Link lt : links) {
+			deleteLink(lt);
+		}
+	}
+	
+	/**
+	 * Delete a record in the LinkStorage.
+	 * @param link Record to be deleted.
+	 */
+	@Override
+	public void deleteLink(Link lt) {
+		IPortObject vportSrc = null, vportDst = null;
+		int count = 0;
+		
+		log.debug("deleteLink(): {}", lt);
+		
+        try {
+            // get source port vertex
+         	String dpid = HexString.toHexString(lt.getSrc());
+         	short port = lt.getSrcPort();
+         	vportSrc = dbop.searchPort(dpid, port);
+            
+            // get dst port vertex
+         	dpid = HexString.toHexString(lt.getDst());
+         	port = lt.getDstPort();
+         	vportDst = dbop.searchPort(dpid, port);
+     		// FIXME: This needs to remove all edges
+         	
+         	if (vportSrc != null && vportDst != null) {
+
+   /*      		for (Edge e : vportSrc.asVertex().getEdges(Direction.OUT)) {
+         			log.debug("deleteLink(): {} in {} out {}", 
+         					new Object[]{e.getLabel(), e.getVertex(Direction.IN), e.getVertex(Direction.OUT)});
+         			if (e.getLabel().equals("link") && e.getVertex(Direction.IN).equals(vportDst)) {
+         				graph.removeEdge(e);
+         				count++;
+         			}
+         		}*/
+         		vportSrc.removeLink(vportDst);
+        		dbop.commit();
+            	log.debug("deleteLink(): deleted edges src {} dst {}", new Object[]{
+            			lt, vportSrc, vportDst});
+            	
+            } else {
+            	log.error("deleteLink(): failed invalid vertices {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+            	dbop.rollback();
+            }
+         	
+        } catch (TitanException e) {
+            /*
+             * retry till we succeed?
+             */
+        	log.error("deleteLink(): titan exception {} {}", new Object[]{lt, e.toString()});
+        	dbop.rollback();
+        	e.printStackTrace();
+        }
+	}
+
+	/**
+	 * Get list of all links connected to the port specified by given DPID and port number.
+	 * @param dpid DPID of desired port.
+	 * @param port Port number of desired port.
+	 * @return List of links. Empty list if no port was found.
+	 */
+	// TODO: Fix me
+	@Override
+	public List<Link> getLinks(Long dpid, short port) {
+    	List<Link> links = new ArrayList<Link>();
+    	
+    	IPortObject srcPort = dbop.searchPort(HexString.toHexString(dpid), port);
+    	ISwitchObject srcSw = srcPort.getSwitch();
+    	
+    	if(srcSw != null) {
+        	for(IPortObject dstPort : srcPort.getLinkedPorts()) {
+        		ISwitchObject dstSw = dstPort.getSwitch();
+        		Link link = new Link(HexString.toLong(srcSw.getDPID()),
+        				srcPort.getNumber(),
+        				HexString.toLong(dstSw.getDPID()),
+        				dstPort.getNumber());
+    		
+        		links.add(link);
+        	}
+    	}
+    	
+     	return links;
+	}
+	
+	/**
+	 * Initialize the object. Open LinkStorage using given configuration file.
+	 * @param conf Path (absolute path for now) to configuration file.
+	 */
+	@Override
+	public void init(String conf) {
+		//TODO extract the DB location from properties
+		this.dbop = new GraphDBOperation(conf);
+	}
+
+	/**
+	 * Delete records of the links connected to the port specified by given DPID and port number.
+	 * @param dpid DPID of desired port.
+	 * @param port Port number of desired port.
+	 */
+	// TODO: Fix me
+	@Override
+	public void deleteLinksOnPort(Long dpid, short port) {
+		List<Link> linksToDelete = getLinks(dpid,port);
+		
+		for(Link l : linksToDelete) {
+			deleteLink(l);
+		}
+	}
+
+	/**
+	 * Get list of all links connected to the switch specified by given DPID.
+	 * @param dpid DPID of desired switch.
+	 * @return List of links. Empty list if no port was found.
+	 */
+	// TODO: Fix me
+	@Override
+	public List<Link> getLinks(String dpid) {
+		List<Link> links = new ArrayList<Link>();
+
+		ISwitchObject srcSw = dbop.searchSwitch(dpid);
+		
+		if(srcSw != null) {
+			for(IPortObject srcPort : srcSw.getPorts()) {
+				for(IPortObject dstPort : srcPort.getLinkedPorts()) {
+					ISwitchObject dstSw = dstPort.getSwitch();
+					if(dstSw != null) {
+		        		Link link = new Link(HexString.toLong(srcSw.getDPID()),
+		        				srcPort.getNumber(),
+		        				HexString.toLong(dstSw.getDPID()),
+		        				dstPort.getNumber());
+		        		links.add(link);
+					}
+				}
+			}
+		}
+		
+		return links;
+	}
+
+	/**
+	 * Get list of all links whose state is ACTIVE.
+	 * @return List of active links. Empty list if no port was found.
+	 */
+	public List<Link> getActiveLinks() {
+		Iterable<ISwitchObject> switches = dbop.getActiveSwitches();
+
+		List<Link> links = new ArrayList<Link>(); 
+		
+		for (ISwitchObject srcSw : switches) {
+			for(IPortObject srcPort : srcSw.getPorts()) {
+				for(IPortObject dstPort : srcPort.getLinkedPorts()) {
+					ISwitchObject dstSw = dstPort.getSwitch();
+					
+					if(dstSw != null && dstSw.getState().equals("ACTIVE")) {
+						links.add(new Link(HexString.toLong(srcSw.getDPID()),
+								srcPort.getNumber(),
+								HexString.toLong(dstSw.getDPID()),
+								dstPort.getNumber()));
+					}
+				}
+			}
+		}
+		
+		return links;
+	}
+	
+	static class ExtractLink implements PipeFunction<PathPipe<Vertex>, Link> {
+	
+		@Override
+		public Link compute(PathPipe<Vertex> pipe ) {
+			// TODO Auto-generated method stub
+			long s_dpid = 0;
+			long d_dpid = 0;
+			short s_port = 0;
+			short d_port = 0;
+			List<Vertex> V = new ArrayList<Vertex>();
+			V = pipe.next();
+			Vertex src_sw = V.get(0);
+			Vertex dest_sw = V.get(3);
+			Vertex src_port = V.get(1);
+			Vertex dest_port = V.get(2);
+			s_dpid = HexString.toLong((String) src_sw.getProperty("dpid"));
+			d_dpid = HexString.toLong((String) dest_sw.getProperty("dpid"));
+			s_port = (Short) src_port.getProperty("number");
+			d_port = (Short) dest_port.getProperty("number");
+			
+			Link l = new Link(s_dpid,s_port,d_dpid,d_port);
+			
+			return l;
+		}
+	}
+	
+	/**
+	 * Finalize the object.
+	 */
+	public void finalize() {
+		close();
+	}
+
+	/**
+	 * Close LinkStorage.
+	 */
+	@Override
+	public void close() {
+		// TODO Auto-generated method stub
+//		graph.shutdown();		
+	}
+
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
index ec0c993..b12ccfa 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
@@ -207,4 +207,4 @@
 			log.info("SwitchStorage:deletePort dpid:{} port:{} failed", dpid, port);
 		}	
 	}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/TopoLinkServiceImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
similarity index 83%
rename from src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/TopoLinkServiceImpl.java
rename to src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
index 1fe12c4..1222ff3 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/TopoLinkServiceImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
@@ -1,14 +1,12 @@
-package net.onrc.onos.ofcontroller.linkdiscovery.internal;
+package net.onrc.onos.ofcontroller.core.internal;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import net.floodlightcontroller.linkdiscovery.internal.LinkStorageImpl;
-import net.floodlightcontroller.linkdiscovery.internal.LinkStorageImpl.ExtractLink;
 import net.floodlightcontroller.routing.Link;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
-import net.onrc.onos.util.GraphDBConnection;
+import net.onrc.onos.ofcontroller.core.internal.LinkStorageImpl.ExtractLink;
 import net.onrc.onos.util.GraphDBOperation;
 
 import org.slf4j.Logger;
@@ -34,8 +32,8 @@
 	@Override
 	public List<Link> getActiveLinks() {
 		// TODO Auto-generated method stub
-		op = new GraphDBOperation(GraphDBConnection.getInstance(""));
-		op.close(); //Commit to ensure we see latest data
+		op = new GraphDBOperation("");
+		op.commit(); //Commit to ensure we see latest data
 		Iterable<ISwitchObject> switches = op.getActiveSwitches();
 		List<Link> links = new ArrayList<Link>(); 
 		for (ISwitchObject sw : switches) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java
index e279422..c1659fb 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java
@@ -3,7 +3,6 @@
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
-import net.onrc.onos.util.GraphDBConnection;
 import net.onrc.onos.util.GraphDBOperation;
 
 import org.slf4j.Logger;
@@ -15,7 +14,7 @@
 	protected static Logger log = LoggerFactory.getLogger(TopoSwitchServiceImpl.class);
 
 	public TopoSwitchServiceImpl(String conf) {
-		op = new GraphDBOperation(GraphDBConnection.getInstance(conf));
+		op = new GraphDBOperation(conf);
 	}
 
 	public TopoSwitchServiceImpl() {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/TopoLinksResource.java b/src/main/java/net/onrc/onos/ofcontroller/core/web/TopoLinksResource.java
similarity index 74%
rename from src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/TopoLinksResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/core/web/TopoLinksResource.java
index b692517..327c110 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/TopoLinksResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/web/TopoLinksResource.java
@@ -1,8 +1,8 @@
-package net.onrc.onos.ofcontroller.linkdiscovery.web;
+package net.onrc.onos.ofcontroller.core.web;
 
 import java.util.List;
 import net.floodlightcontroller.routing.Link;
-import net.onrc.onos.ofcontroller.linkdiscovery.internal.TopoLinkServiceImpl;
+import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
 
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/web/TopoDevicesResource.java b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/web/TopoDevicesResource.java
index 1cd6b90..97ecfcc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/web/TopoDevicesResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/web/TopoDevicesResource.java
@@ -3,7 +3,6 @@
 import java.util.Iterator;
 
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
-import net.onrc.onos.util.GraphDBConnection;
 import net.onrc.onos.util.GraphDBOperation;
 
 import org.restlet.resource.Get;
@@ -13,12 +12,8 @@
 	
 	@Get("json")
 	public Iterator<IDeviceObject> retrieve() {
-		
-		GraphDBConnection conn = GraphDBConnection.getInstance("");
-		GraphDBOperation op = new GraphDBOperation(conn);
+		GraphDBOperation op = new GraphDBOperation("");
 		
 		return op.getDevices().iterator();
-		
 	}
-	
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/onoslistener/OnosPublisher.java b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
similarity index 90%
rename from src/main/java/net/onrc/onos/ofcontroller/onoslistener/OnosPublisher.java
rename to src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
index 6a9d433..bb7318f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/onoslistener/OnosPublisher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.ofcontroller.onoslistener;
+package net.onrc.onos.ofcontroller.floodlightlistener;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -22,21 +22,20 @@
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IDeviceListener;
 import net.floodlightcontroller.devicemanager.IDeviceService;
-import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
-import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
-import net.floodlightcontroller.linkdiscovery.internal.LinkStorageImpl;
 import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.onrc.onos.ofcontroller.core.IDeviceStorage;
+import net.onrc.onos.ofcontroller.core.ILinkStorage;
+import net.onrc.onos.ofcontroller.core.IOFSwitchPortListener;
 import net.onrc.onos.ofcontroller.core.ISwitchStorage;
 import net.onrc.onos.ofcontroller.core.INetMapStorage.DM_OPERATION;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
+import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
+import net.onrc.onos.ofcontroller.core.internal.LinkStorageImpl;
 import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
-import net.onrc.onos.ofcontroller.core.internal.TopoSwitchServiceImpl;
-import net.onrc.onos.ofcontroller.devicemanager.IDeviceStorage;
-import net.onrc.onos.ofcontroller.devicemanager.internal.DeviceStorageImpl;
-import net.onrc.onos.ofcontroller.linkdiscovery.ILinkStorage;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryListener;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.registry.controller.IControllerRegistryService;
 import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
 import net.onrc.onos.registry.controller.RegistryException;
@@ -45,7 +44,7 @@
 import net.onrc.onos.util.IDBConnection;
 import net.onrc.onos.util.LocalTopologyEventListener;
 
-public class OnosPublisher implements IDeviceListener, IOFSwitchListener,
+public class NetworkGraphPublisher implements IDeviceListener, IOFSwitchListener, IOFSwitchPortListener,
 		ILinkDiscoveryListener, IFloodlightModule {
 	
 	protected IDeviceStorage devStore;
@@ -189,7 +188,7 @@
 
 	@Override
 	public String getName() {
-		return "OnosPublisher";
+		return "NetworkGraphPublisher";
 	}
 
 	@Override
@@ -253,9 +252,9 @@
 		// TODO Auto-generated method stub
 		Map<String, String> configMap = context.getConfigParams(this);
 		String conf = configMap.get(DBConfigFile);
-		op = new GraphDBOperation(GraphDBConnection.getInstance(conf));
+		op = new GraphDBOperation(conf);
 		
-		log = LoggerFactory.getLogger(OnosPublisher.class);
+		log = LoggerFactory.getLogger(NetworkGraphPublisher.class);
 		floodlightProvider =
 	            context.getServiceImpl(IFloodlightProviderService.class);
 		deviceService = context.getServiceImpl(IDeviceService.class);
@@ -272,7 +271,7 @@
 		linkStore = new LinkStorageImpl();
 		linkStore.init(conf);
 				
-		log.debug("Initializing OnosPublisher module with {}", conf);
+		log.debug("Initializing NetworkGraphPublisher module with {}", conf);
 		
 	}
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/FlowManager.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
similarity index 99%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/FlowManager.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
index 125acf3..2dc230c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.ofcontroller.flowcache;
+package net.onrc.onos.ofcontroller.flowmanager;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -33,7 +33,7 @@
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
-import net.onrc.onos.ofcontroller.flowcache.web.FlowWebRoutable;
+import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
 import net.onrc.onos.ofcontroller.util.CallerId;
 import net.onrc.onos.ofcontroller.util.DataPath;
 import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
@@ -49,7 +49,6 @@
 import net.onrc.onos.ofcontroller.util.IPv4Net;
 import net.onrc.onos.ofcontroller.util.Port;
 import net.onrc.onos.ofcontroller.util.SwitchPort;
-import net.onrc.onos.util.GraphDBConnection;
 import net.onrc.onos.util.GraphDBOperation;
 
 import org.openflow.protocol.OFFlowMod;
@@ -413,7 +412,7 @@
 
     @Override
     public void init(String conf) {
-    	op = new GraphDBOperation(GraphDBConnection.getInstance(conf));
+    	op = new GraphDBOperation(conf);
     }
 
     public void finalize() {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/IFlowService.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
similarity index 98%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/IFlowService.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
index 06566d4..ba9cd1b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.ofcontroller.flowcache;
+package net.onrc.onos.ofcontroller.flowmanager;
 
 import java.util.ArrayList;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/AddFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
similarity index 91%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/AddFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
index 0763b8a..2800305 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/AddFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
@@ -1,15 +1,14 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.io.IOException;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowId;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 
 import org.codehaus.jackson.JsonGenerationException;
 import org.codehaus.jackson.map.ObjectMapper;
 import org.codehaus.jackson.map.JsonMappingException;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.restlet.resource.Post;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/AddShortestPathFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
similarity index 91%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/AddShortestPathFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
index 59a8972..9d2e0c9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/AddShortestPathFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
@@ -1,13 +1,12 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.io.IOException;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowId;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 
 import org.codehaus.jackson.JsonGenerationException;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.codehaus.jackson.map.JsonMappingException;
 import org.codehaus.jackson.map.ObjectMapper;
 import org.restlet.resource.Post;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/ClearFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
similarity index 87%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/ClearFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
index e51bc9d..1daa2ab 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/ClearFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
@@ -1,9 +1,8 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowId;
 
-import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/DatapathSummarySerializer.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DatapathSummarySerializer.java
similarity index 97%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/DatapathSummarySerializer.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DatapathSummarySerializer.java
index 2022966..9133077 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/DatapathSummarySerializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DatapathSummarySerializer.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.io.IOException;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/DeleteFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DeleteFlowResource.java
similarity index 88%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/DeleteFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DeleteFlowResource.java
index fb3d100..393ff44 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/DeleteFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/DeleteFlowResource.java
@@ -1,9 +1,8 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowId;
 
-import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/FlowWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
similarity index 97%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/FlowWebRoutable.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
index a2a3e54..954c84d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/FlowWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import net.floodlightcontroller.restserver.RestletRoutable;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsByEndpointsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
similarity index 94%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsByEndpointsResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
index c284a9c..6142096 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsByEndpointsResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
@@ -1,8 +1,8 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.util.ArrayList;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
 import net.onrc.onos.ofcontroller.util.Dpid;
 import net.onrc.onos.ofcontroller.util.FlowPath;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsByInstallerIdResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
similarity index 94%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsByInstallerIdResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
index 8247422..498108f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsByInstallerIdResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
@@ -1,8 +1,8 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.util.ArrayList;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.CallerId;
 import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
 import net.onrc.onos.ofcontroller.util.Dpid;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsResource.java
similarity index 88%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsResource.java
index 5ffbefa..61eaf27 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetAllFlowsResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsResource.java
@@ -1,8 +1,8 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.util.ArrayList;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 
 import org.restlet.resource.Get;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetFlowByIdResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetFlowByIdResource.java
similarity index 89%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetFlowByIdResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetFlowByIdResource.java
index 2f0f712..48e7369 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetFlowByIdResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetFlowByIdResource.java
@@ -1,6 +1,6 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowId;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetSummaryFlowsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
similarity index 89%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetSummaryFlowsResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
index 54c75f2..4b3c00f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/GetSummaryFlowsResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
@@ -1,11 +1,10 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.util.ArrayList;
 
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowId;
-import net.onrc.onos.ofcontroller.util.FlowPath;
 
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementClearAllPathsFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementClearAllPathsFlowResource.java
similarity index 81%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementClearAllPathsFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementClearAllPathsFlowResource.java
index d0c013e..07d9fb2 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementClearAllPathsFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementClearAllPathsFlowResource.java
@@ -1,9 +1,7 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
-import net.onrc.onos.ofcontroller.util.FlowId;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 
-import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementGetInstallPathsTimeNsecFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
similarity index 81%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
index 2d2fbf6..467afca 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
@@ -1,9 +1,7 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
-import net.onrc.onos.ofcontroller.util.FlowId;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 
-import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementGetPerFlowInstallTimeFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetPerFlowInstallTimeFlowResource.java
similarity index 81%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementGetPerFlowInstallTimeFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetPerFlowInstallTimeFlowResource.java
index 981c12c..92d84ab 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementGetPerFlowInstallTimeFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementGetPerFlowInstallTimeFlowResource.java
@@ -1,9 +1,7 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
-import net.onrc.onos.ofcontroller.util.FlowId;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 
-import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementInstallPathsFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementInstallPathsFlowResource.java
similarity index 83%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementInstallPathsFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementInstallPathsFlowResource.java
index 911de89..074dfb4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementInstallPathsFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementInstallPathsFlowResource.java
@@ -1,9 +1,7 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
-import net.onrc.onos.ofcontroller.util.FlowId;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 
-import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementStorePathFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementStorePathFlowResource.java
similarity index 91%
rename from src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementStorePathFlowResource.java
rename to src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementStorePathFlowResource.java
index 5eb8af0..0f23663 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowcache/web/MeasurementStorePathFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/MeasurementStorePathFlowResource.java
@@ -1,13 +1,12 @@
-package net.onrc.onos.ofcontroller.flowcache.web;
+package net.onrc.onos.ofcontroller.flowmanager.web;
 
 import java.io.IOException;
 
-import net.onrc.onos.ofcontroller.flowcache.IFlowService;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowId;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 
 import org.codehaus.jackson.JsonGenerationException;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.codehaus.jackson.map.JsonMappingException;
 import org.codehaus.jackson.map.ObjectMapper;
 import org.restlet.resource.Post;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
new file mode 100644
index 0000000..6113ea8
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
@@ -0,0 +1,164 @@
+package net.onrc.onos.ofcontroller.linkdiscovery;
+
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.ser.std.ToStringSerializer;
+import org.openflow.util.HexString;
+
+public interface ILinkDiscovery {
+
+    @JsonSerialize(using=ToStringSerializer.class)
+    public enum UpdateOperation {
+    	LINK_ADDED("Link Added"), // Operation Added by ONOS
+        LINK_UPDATED("Link Updated"),
+        LINK_REMOVED("Link Removed"),
+        SWITCH_UPDATED("Switch Updated"),
+        SWITCH_REMOVED("Switch Removed"),
+        PORT_UP("Port Up"),
+        PORT_DOWN("Port Down");
+        
+        private String value;
+        UpdateOperation(String v) {
+            value = v;
+        }
+        
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    public class LDUpdate {
+        protected long src;
+        protected short srcPort;
+        protected long dst;
+        protected short dstPort;
+        protected SwitchType srcType;
+        protected LinkType type;
+        protected UpdateOperation operation;
+
+        public LDUpdate(long src, short srcPort,
+                      long dst, short dstPort,
+                      ILinkDiscovery.LinkType type,
+                      UpdateOperation operation) {
+            this.src = src;
+            this.srcPort = srcPort;
+            this.dst = dst;
+            this.dstPort = dstPort;
+            this.type = type;
+            this.operation = operation;
+        }
+
+        public LDUpdate(LDUpdate old) {
+            this.src = old.src;
+            this.srcPort = old.srcPort;
+            this.dst = old.dst;
+            this.dstPort = old.dstPort;
+            this.srcType = old.srcType;
+            this.type = old.type;
+            this.operation = old.operation;
+        }
+
+        // For updtedSwitch(sw)
+        public LDUpdate(long switchId, SwitchType stype, UpdateOperation oper ){
+            this.operation = oper;
+            this.src = switchId;
+            this.srcType = stype;
+        }
+
+        // For port up or port down.
+        public LDUpdate(long sw, short port, UpdateOperation operation) {
+            this.src = sw;
+            this.srcPort = port;
+            this.operation = operation;
+        }
+
+        public long getSrc() {
+            return src;
+        }
+
+        public short getSrcPort() {
+            return srcPort;
+        }
+
+        public long getDst() {
+            return dst;
+        }
+
+        public short getDstPort() {
+            return dstPort;
+        }
+
+        public SwitchType getSrcType() {
+            return srcType;
+        }
+
+        public LinkType getType() {
+            return type;
+        }
+
+        public UpdateOperation getOperation() {
+            return operation;
+        }
+
+        public void setOperation(UpdateOperation operation) {
+            this.operation = operation;
+        }
+        
+        @Override
+        public String toString() {
+            switch (operation) {
+            case LINK_ADDED:
+            case LINK_REMOVED:
+            case LINK_UPDATED:
+                return "LDUpdate [operation=" + operation +
+                        ", src=" + HexString.toHexString(src)
+                        + ", srcPort=" + srcPort
+                        + ", dst=" + HexString.toHexString(dst) 
+                        + ", dstPort=" + dstPort
+                        + ", type=" + type + "]";
+            case PORT_DOWN:
+            case PORT_UP:
+                return "LDUpdate [operation=" + operation +
+                        ", src=" + HexString.toHexString(src)
+                        + ", srcPort=" + srcPort + "]";
+            case SWITCH_REMOVED:
+            case SWITCH_UPDATED:
+                return "LDUpdate [operation=" + operation +
+                        ", src=" + HexString.toHexString(src) + "]";
+            default:
+                return "LDUpdate: Unknown update.";
+            }
+        }
+    }
+
+    public enum SwitchType {
+        BASIC_SWITCH, CORE_SWITCH
+    };
+
+    public enum LinkType {
+        INVALID_LINK {
+        	@Override
+        	public String toString() {
+        		return "invalid";
+        	}
+        }, 
+        DIRECT_LINK{
+        	@Override
+        	public String toString() {
+        		return "internal";
+        	}
+        }, 
+        MULTIHOP_LINK {
+        	@Override
+        	public String toString() {
+        		return "external";
+        	}
+        }, 
+        TUNNEL {
+        	@Override
+        	public String toString() {
+        		return "tunnel";
+        	}
+        }
+    };
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscoveryListener.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscoveryListener.java
new file mode 100644
index 0000000..9ca114f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscoveryListener.java
@@ -0,0 +1,23 @@
+/**
+ *    Copyright 2011, Big Switch Networks, Inc. 
+ *    Originally created by David Erickson, Stanford University
+ * 
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.onrc.onos.ofcontroller.linkdiscovery;
+
+public interface ILinkDiscoveryListener extends ILinkDiscovery{
+
+    public void linkDiscoveryUpdate(LDUpdate update);
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscoveryService.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscoveryService.java
new file mode 100644
index 0000000..99438ab
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscoveryService.java
@@ -0,0 +1,84 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson, Stanford University
+* 
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package net.onrc.onos.ofcontroller.linkdiscovery;
+
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.topology.NodePortTuple;
+
+
+public interface ILinkDiscoveryService extends IFloodlightService {
+    /**
+     * Retrieves a map of all known link connections between OpenFlow switches
+     * and the associated info (valid time, port states) for the link.
+     */
+    public Map<Link, LinkInfo> getLinks();
+
+    /**
+     * Returns link type of a given link
+     * @param info
+     * @return
+     */
+    public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info);
+
+    /**
+     * Returns an unmodifiable map from switch id to a set of all links with it 
+     * as an endpoint.
+     */
+    public Map<Long, Set<Link>> getSwitchLinks();
+
+    /**
+     * Adds a listener to listen for ILinkDiscoveryService messages
+     * @param listener The listener that wants the notifications
+     */
+    public void addListener(ILinkDiscoveryListener listener);
+
+    /**
+     * Retrieves a set of all switch ports on which lldps are suppressed.
+     */
+    public Set<NodePortTuple> getSuppressLLDPsInfo();
+
+    /**
+     * Adds a switch port to suppress lldp set
+     */
+    public void AddToSuppressLLDPs(long sw, short port);
+
+    /**
+     * Removes a switch port from suppress lldp set
+     */
+    public void RemoveFromSuppressLLDPs(long sw, short port);
+
+    /**
+     * Get the set of quarantined ports on a switch
+     */
+    public Set<Short> getQuarantinedPorts(long sw);
+
+    /**
+     * Get the status of auto port fast feature.
+     */
+    public boolean isAutoPortFastFeature();
+
+    /**
+     * Set the state for auto port fast feature.
+     * @param autoPortFastFeature
+     */
+    public void setAutoPortFastFeature(boolean autoPortFastFeature);
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/LinkInfo.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/LinkInfo.java
new file mode 100644
index 0000000..825b0a2
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/LinkInfo.java
@@ -0,0 +1,182 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc.*    Originally created by David Erickson, Stanford University
+**    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package net.onrc.onos.ofcontroller.linkdiscovery;
+
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LinkType;
+
+import org.openflow.protocol.OFPhysicalPort.OFPortState;
+
+public class LinkInfo {
+
+    public LinkInfo(Long firstSeenTime,
+                    Long lastLldpReceivedTime,
+                    Long lastBddpReceivedTime,
+                    int srcPortState,
+                    int dstPortState) {
+        super();
+        this.srcPortState = srcPortState;
+        this.dstPortState = dstPortState;
+        this.firstSeenTime = firstSeenTime;
+        this.lastLldpReceivedTime = lastLldpReceivedTime;
+        this.lastBddpReceivedTime = lastBddpReceivedTime;
+    }
+
+    protected Integer srcPortState;
+    protected Integer dstPortState;
+    protected Long firstSeenTime;
+    protected Long lastLldpReceivedTime; /* Standard LLLDP received time */
+    protected Long lastBddpReceivedTime; /* Modified LLDP received time  */
+
+    /** The port states stored here are topology's last knowledge of
+     * the state of the port. This mostly mirrors the state
+     * maintained in the port list in IOFSwitch (i.e. the one returned
+     * from getPort), except that during a port status message the
+     * IOFSwitch port state will already have been updated with the
+     * new port state, so topology needs to keep its own copy so that
+     * it can determine if the port state has changed and therefore
+     * requires the new state to be written to storage.
+     */
+
+
+
+    public boolean linkStpBlocked() {
+        return ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue()) ||
+            ((dstPortState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue());
+    }
+
+    public Long getFirstSeenTime() {
+        return firstSeenTime;
+    }
+
+    public void setFirstSeenTime(Long firstSeenTime) {
+        this.firstSeenTime = firstSeenTime;
+    }
+
+    public Long getUnicastValidTime() {
+        return lastLldpReceivedTime;
+    }
+
+    public void setUnicastValidTime(Long unicastValidTime) {
+        this.lastLldpReceivedTime = unicastValidTime;
+    }
+
+    public Long getMulticastValidTime() {
+        return lastBddpReceivedTime;
+    }
+
+    public void setMulticastValidTime(Long multicastValidTime) {
+        this.lastBddpReceivedTime = multicastValidTime;
+    }
+
+    public Integer getSrcPortState() {
+        return srcPortState;
+    }
+
+    public void setSrcPortState(Integer srcPortState) {
+        this.srcPortState = srcPortState;
+    }
+
+    public Integer getDstPortState() {
+        return dstPortState;
+    }
+
+    public void setDstPortState(int dstPortState) {
+        this.dstPortState = dstPortState;
+    }
+
+    public LinkType getLinkType() {
+        if (lastLldpReceivedTime != null) {
+            return LinkType.DIRECT_LINK;
+        } else if (lastBddpReceivedTime != null) {
+            return LinkType.MULTIHOP_LINK;
+        }
+        return LinkType.INVALID_LINK;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 5557;
+        int result = 1;
+        result = prime * result + ((firstSeenTime == null) ? 0 : firstSeenTime.hashCode());
+        result = prime * result + ((lastLldpReceivedTime == null) ? 0 : lastLldpReceivedTime.hashCode());
+        result = prime * result + ((lastBddpReceivedTime == null) ? 0 : lastBddpReceivedTime.hashCode());
+        result = prime * result + ((srcPortState == null) ? 0 : srcPortState.hashCode());
+        result = prime * result + ((dstPortState == null) ? 0 : dstPortState.hashCode());
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (!(obj instanceof LinkInfo))
+            return false;
+        LinkInfo other = (LinkInfo) obj;
+
+        if (firstSeenTime == null) {
+            if (other.firstSeenTime != null)
+                return false;
+        } else if (!firstSeenTime.equals(other.firstSeenTime))
+            return false;
+
+        if (lastLldpReceivedTime == null) {
+            if (other.lastLldpReceivedTime != null)
+                return false;
+        } else if (!lastLldpReceivedTime.equals(other.lastLldpReceivedTime))
+            return false;
+
+        if (lastBddpReceivedTime == null) {
+            if (other.lastBddpReceivedTime != null)
+                return false;
+        } else if (!lastBddpReceivedTime.equals(other.lastBddpReceivedTime))
+            return false;
+
+        if (srcPortState == null) {
+            if (other.srcPortState != null)
+                return false;
+        } else if (!srcPortState.equals(other.srcPortState))
+            return false;
+
+        if (dstPortState == null) {
+            if (other.dstPortState != null)
+                return false;
+        } else if (!dstPortState.equals(other.dstPortState))
+            return false;
+
+        return true;
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "LinkInfo [unicastValidTime=" + ((lastLldpReceivedTime == null) ? "null" : lastLldpReceivedTime)
+                + ", multicastValidTime=" + ((lastBddpReceivedTime == null) ? "null" : lastBddpReceivedTime)
+                + ", srcPortState=" + ((srcPortState == null) ? "null" : srcPortState)
+                + ", dstPortState=" + ((dstPortState == null) ? "null" : srcPortState)
+                + "]";
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/README b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/README
new file mode 100644
index 0000000..3cec58d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/README
@@ -0,0 +1,8 @@
+Note about this directory
+=========================
+
+This directory contains link discovery manager and it's related module derived from Flood Light v0.9.0.
+Many of the code is unmodified from it's original state, but they had to be moved due to package visibility etc.
+
+Compare with floodlight's linkdiscovery directory to see what was modified from it's original code.
+
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologyCluster.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologyCluster.java
new file mode 100644
index 0000000..696c63e
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologyCluster.java
@@ -0,0 +1,43 @@
+package net.onrc.onos.ofcontroller.linkdiscovery.internal;
+
+import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+/***
+ * Topology Cluster merge/split event history related classes and members
+ * @author subrata
+ *
+ */
+public class EventHistoryTopologyCluster {
+    // The following fields are not stored as String to save memory
+    // They should be converted to appropriate human-readable strings by 
+    // the front end (e.g. in cli in Python)
+    public long     dpid;
+    public long     clusterIdOld; // Switch with dpid moved from cluster x to y
+    public long     clusterIdNew;
+    public String   reason;
+    
+    @JsonProperty("Switch")
+    @JsonSerialize(using=DPIDSerializer.class)
+    public long getDpid() {
+        return dpid;
+    }
+    @JsonProperty("OldClusterId")
+    @JsonSerialize(using=DPIDSerializer.class)
+    public long getClusterIdOld() {
+        return clusterIdOld;
+    }
+    @JsonProperty("NewClusterId")
+    @JsonSerialize(using=DPIDSerializer.class)
+    public long getClusterIdNew() {
+        return clusterIdNew;
+    }
+    @JsonProperty("Reason")
+    public String getReason() {
+        return reason;
+    }
+    
+    
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologyLink.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologyLink.java
new file mode 100644
index 0000000..5d2e955
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologyLink.java
@@ -0,0 +1,62 @@
+package net.onrc.onos.ofcontroller.linkdiscovery.internal;
+
+import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+/***
+ * Topology link up/down event history related classes and members
+ * @author subrata
+ *
+ */
+public class EventHistoryTopologyLink {
+    // The following fields are not stored as String to save memory
+    // They should be converted to appropriate human-readable strings by 
+    // the front end (e.g. in cli in Python)
+    public long     srcSwDpid;
+    public long     dstSwDpid;
+    public int      srcPortState;
+    public int      dstPortState;
+    public int      srcSwport;
+    public int      dstSwport;
+    public String   linkType;
+    public String   reason;
+    
+    @JsonProperty("Source-Switch")
+    @JsonSerialize(using=DPIDSerializer.class)
+    public long getSrcSwDpid() {
+        return srcSwDpid;
+    }
+    @JsonProperty("Dest-Switch")
+    @JsonSerialize(using=DPIDSerializer.class)
+    public long getDstSwDpid() {
+        return dstSwDpid;
+    }
+    @JsonProperty("SrcPortState")
+    public int getSrcPortState() {
+        return srcPortState;
+    }
+    @JsonProperty("DstPortState")
+    public int getDstPortState() {
+        return dstPortState;
+    }
+    @JsonProperty("SrcPort")
+    public int getSrcSwport() {
+        return srcSwport;
+    }
+    @JsonProperty("DstPort")
+    public int getDstSwport() {
+        return dstSwport;
+    }
+    @JsonProperty("LinkType")
+    public String getLinkType() {
+        return linkType;
+    }
+    @JsonProperty("Reason")
+    public String getReason() {
+        return reason;
+    }
+    
+    
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologySwitch.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologySwitch.java
new file mode 100644
index 0000000..d6afd7a
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/EventHistoryTopologySwitch.java
@@ -0,0 +1,43 @@
+package net.onrc.onos.ofcontroller.linkdiscovery.internal;
+
+import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+import net.floodlightcontroller.core.web.serializers.IPv4Serializer;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+/***
+ * Topology Switch event history related classes and members
+ * @author subrata
+ *
+ */
+public class EventHistoryTopologySwitch {
+    // The following fields are not stored as String to save memory
+    // They should be converted to appropriate human-readable strings by 
+    // the front end (e.g. in cli in Python)
+    public long     dpid;
+    public int  ipv4Addr;
+    public int    l4Port;
+    public String   reason;
+    
+    @JsonProperty("Switch")
+    @JsonSerialize(using=DPIDSerializer.class)
+    public long getDpid() {
+        return dpid;
+    }
+    @JsonProperty("IpAddr")
+    @JsonSerialize(using=IPv4Serializer.class)
+    public int getIpv4Addr() {
+        return ipv4Addr;
+    }
+    @JsonProperty("Port")
+    public int getL4Port() {
+        return l4Port;
+    }
+    @JsonProperty("Reason")
+    public String getReason() {
+        return reason;
+    }
+    
+    
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
new file mode 100644
index 0000000..f057a29
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -0,0 +1,2122 @@
+/**
+ *    Copyright 2011, Big Switch Networks, Inc.
+ *    Originally created by David Erickson, Stanford University
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.onrc.onos.ofcontroller.linkdiscovery.internal;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.IHAListener;
+import net.floodlightcontroller.core.IInfoProvider;
+import net.floodlightcontroller.core.IOFMessageListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchListener;
+import net.floodlightcontroller.core.annotations.LogMessageCategory;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.internal.OFSwitchImpl;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.core.util.SingletonTask;
+import net.floodlightcontroller.packet.BSN;
+import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.packet.LLDP;
+import net.floodlightcontroller.packet.LLDPTLV;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.storage.IResultSet;
+import net.floodlightcontroller.storage.IStorageSourceListener;
+import net.floodlightcontroller.storage.IStorageSourceService;
+import net.floodlightcontroller.storage.OperatorPredicate;
+import net.floodlightcontroller.storage.StorageException;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.topology.NodePortTuple;
+import net.floodlightcontroller.util.EventHistory;
+import net.floodlightcontroller.util.EventHistory.EvAction;
+import net.onrc.onos.ofcontroller.core.IOnosRemoteSwitch;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryListener;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.onrc.onos.ofcontroller.linkdiscovery.LinkInfo;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LinkType;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.SwitchType;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.UpdateOperation;
+import net.onrc.onos.ofcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable;
+import net.onrc.onos.registry.controller.IControllerRegistryService;
+
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
+import org.openflow.protocol.OFPhysicalPort.OFPortState;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFPortStatus;
+import org.openflow.protocol.OFPortStatus.OFPortReason;
+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;
+
+/**
+ * This class sends out LLDP messages containing the sending switch's datapath
+ * id as well as the outgoing port number.  Received LLrescDP messages that
+ * match a known switch cause a new LinkTuple to be created according to the
+ * invariant rules listed below.  This new LinkTuple is also passed to routing
+ * if it exists to trigger updates.
+ *
+ * This class also handles removing links that are associated to switch ports
+ * that go down, and switches that are disconnected.
+ *
+ * Invariants:
+ *  -portLinks and switchLinks will not contain empty Sets outside of
+ *   critical sections
+ *  -portLinks contains LinkTuples where one of the src or dst
+ *   SwitchPortTuple matches the map key
+ *  -switchLinks contains LinkTuples where one of the src or dst
+ *   SwitchPortTuple's id matches the switch id
+ *  -Each LinkTuple will be indexed into switchLinks for both
+ *   src.id and dst.id, and portLinks for each src and dst
+ *  -The updates queue is only added to from within a held write lock
+ */
+@LogMessageCategory("Network Topology")
+public class LinkDiscoveryManager
+implements IOFMessageListener, IOFSwitchListener, 
+IStorageSourceListener, ILinkDiscoveryService,
+IFloodlightModule, IInfoProvider, IHAListener {
+    protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
+
+    // Names of table/fields for links in the storage API
+    private static final String LINK_TABLE_NAME = "controller_link";
+    private static final String LINK_ID = "id";
+    private static final String LINK_SRC_SWITCH = "src_switch_id";
+    private static final String LINK_SRC_PORT = "src_port";
+    private static final String LINK_SRC_PORT_STATE = "src_port_state";
+    private static final String LINK_DST_SWITCH = "dst_switch_id";
+    private static final String LINK_DST_PORT = "dst_port";
+    private static final String LINK_DST_PORT_STATE = "dst_port_state";
+    private static final String LINK_VALID_TIME = "valid_time";
+    private static final String LINK_TYPE = "link_type";
+    private static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig";
+    private static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch";
+
+    protected IFloodlightProviderService floodlightProvider;
+    protected IStorageSourceService storageSource;
+    protected IThreadPoolService threadPool;
+    protected IRestApiService restApi;
+    // Registry Service for ONOS
+    protected IControllerRegistryService registryService;
+
+
+    // LLDP and BDDP fields
+    private static final byte[] LLDP_STANDARD_DST_MAC_STRING = 
+            HexString.fromHexString("01:80:c2:00:00:0e");
+    private static final long LINK_LOCAL_MASK  = 0xfffffffffff0L;
+    private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
+
+    // BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
+    private static final String LLDP_BSN_DST_MAC_STRING = "5d:16:c7:00:00:01";
+    //private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
+
+
+    // Direction TLVs are used to indicate if the LLDPs were sent 
+    // periodically or in response to a recieved LLDP
+    private static final byte TLV_DIRECTION_TYPE = 0x73;
+    private static final short TLV_DIRECTION_LENGTH = 1;  // 1 byte
+    private static final byte TLV_DIRECTION_VALUE_FORWARD[] = {0x01};
+    private static final byte TLV_DIRECTION_VALUE_REVERSE[] = {0x02};
+    private static final LLDPTLV forwardTLV 
+    = new LLDPTLV().
+    setType((byte)TLV_DIRECTION_TYPE).
+    setLength((short)TLV_DIRECTION_LENGTH).
+    setValue(TLV_DIRECTION_VALUE_FORWARD);
+
+    private static final LLDPTLV reverseTLV 
+    = new LLDPTLV().
+    setType((byte)TLV_DIRECTION_TYPE).
+    setLength((short)TLV_DIRECTION_LENGTH).
+    setValue(TLV_DIRECTION_VALUE_REVERSE);
+
+    // Link discovery task details.
+    protected SingletonTask discoveryTask;
+    protected final int DISCOVERY_TASK_INTERVAL = 1; 
+    protected final int LINK_TIMEOUT = 35; // original 35 secs, aggressive 5 secs
+    protected final int LLDP_TO_ALL_INTERVAL = 15 ; //original 15 seconds, aggressive 2 secs.
+    protected long lldpClock = 0;
+    // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
+    // If we want to identify link failures faster, we could decrease this
+    // value to a small number, say 1 or 2 sec.
+    protected final int LLDP_TO_KNOWN_INTERVAL= 20; // LLDP frequency for known links
+
+    protected LLDPTLV controllerTLV;
+    protected ReentrantReadWriteLock lock;
+    int lldpTimeCount = 0;
+
+    /**
+     * Flag to indicate if automatic port fast is enabled or not.
+     * Default is set to false -- Initialized in the init method as well.
+     */
+    boolean autoPortFastFeature = false;
+
+    /**
+     * Map of remote switches that are not connected to this controller. This
+     * is used to learn remote switches in a distributed controller ONOS.
+     */
+    protected Map<Long, IOnosRemoteSwitch> remoteSwitches;
+
+    /**
+     * Map from link to the most recent time it was verified functioning
+     */
+    protected Map<Link, LinkInfo> links;
+
+    /**
+     * Map from switch id to a set of all links with it as an endpoint
+     */
+    protected Map<Long, Set<Link>> switchLinks;
+
+    /**
+     * Map from a id:port to the set of links containing it as an endpoint
+     */
+    protected Map<NodePortTuple, Set<Link>> portLinks;
+
+    /**
+     * Set of link tuples over which multicast LLDPs are received
+     * and unicast LLDPs are not received.
+     */
+    protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks;
+
+    protected volatile boolean shuttingDown = false;
+
+    /* topology aware components are called in the order they were added to the
+     * the array */
+    protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
+    protected BlockingQueue<LDUpdate> updates;
+    protected Thread updatesThread;
+
+    /**
+     * List of ports through which LLDP/BDDPs are not sent.
+     */
+    protected Set<NodePortTuple> suppressLinkDiscovery;
+
+    /** A list of ports that are quarantined for discovering links through
+     * them.  Data traffic from these ports are not allowed until the ports
+     * are released from quarantine.
+     */
+    protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
+    protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
+    /**
+     * Quarantine task
+     */
+    protected SingletonTask bddpTask;
+    protected final int BDDP_TASK_INTERVAL = 100; // 100 ms.
+    protected final int BDDP_TASK_SIZE = 5;       // # of ports per iteration
+
+    /**
+     * Map of broadcast domain ports and the last time a BDDP was either
+     * sent or received on that port.
+     */
+    protected Map<NodePortTuple, Long> broadcastDomainPortTimeMap;
+
+    /** 
+     * Get the LLDP sending period in seconds.
+     * @return LLDP sending period in seconds.
+     */
+    public int getLldpFrequency() {
+        return LLDP_TO_KNOWN_INTERVAL;
+    }
+
+    /**
+     * Get the LLDP timeout value in seconds
+     * @return LLDP timeout value in seconds
+     */
+    public int getLldpTimeout() {
+        return LINK_TIMEOUT;
+    }
+
+    public Map<NodePortTuple, Set<Link>> getPortLinks() {
+        return portLinks;
+    }
+
+    public Set<NodePortTuple> getSuppressLLDPsInfo() {
+        return suppressLinkDiscovery;
+    }
+
+    /**
+     * Add a switch port to the suppressed LLDP list.
+     * Remove any known links on the switch port.
+     */
+    public void AddToSuppressLLDPs(long sw, short port)
+    {
+        NodePortTuple npt = new NodePortTuple(sw, port);
+        this.suppressLinkDiscovery.add(npt);
+        deleteLinksOnPort(npt, "LLDP suppressed.");
+    }
+
+    /**
+     * Remove a switch port from the suppressed LLDP list.
+     * Discover links on that switchport.
+     */
+    public void RemoveFromSuppressLLDPs(long sw, short port) 
+    {
+        NodePortTuple npt = new NodePortTuple(sw, port);
+        this.suppressLinkDiscovery.remove(npt);
+        discover(npt);
+    }
+
+    public boolean isShuttingDown() {
+        return shuttingDown;
+    }
+
+    public boolean isFastPort(long sw, short port) {
+        return false;
+    }
+
+    public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
+        if (info.getUnicastValidTime() != null) {
+            return ILinkDiscovery.LinkType.DIRECT_LINK;
+        } else if (info.getMulticastValidTime() != null) {
+            return ILinkDiscovery.LinkType.MULTIHOP_LINK;
+        }
+        return ILinkDiscovery.LinkType.INVALID_LINK;
+    }
+
+    @LogMessageDoc(level="ERROR",
+            message="Error in link discovery updates loop",
+            explanation="An unknown error occured while dispatching " +
+            		"link update notifications",
+            recommendation=LogMessageDoc.GENERIC_ACTION)
+    private void doUpdatesThread() throws InterruptedException {
+        do {
+            LDUpdate update = updates.take();
+
+            if (linkDiscoveryAware != null) {
+                if (log.isTraceEnabled()) {
+                    log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
+                              new Object[]{update.getOperation(),
+                                           HexString.toHexString(update.getSrc()), update.getSrcPort(),
+                                           HexString.toHexString(update.getDst()), update.getDstPort(),
+                                           linkDiscoveryAware});
+                }
+                try {
+                    for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
+                        lda.linkDiscoveryUpdate(update);
+                    }
+                }
+                catch (Exception e) {
+                    log.error("Error in link discovery updates loop", e);
+                }
+            }
+        } while (updates.peek() != null);
+    }
+    private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
+        return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
+    }
+
+    protected void discoverLinks() {
+
+        // timeout known links.
+        timeoutLinks();
+
+        //increment LLDP clock
+        lldpClock = (lldpClock + 1)% LLDP_TO_ALL_INTERVAL;
+
+        if (lldpClock == 0) {
+            log.debug("Sending LLDP out on all ports.");
+            discoverOnAllPorts();
+        }
+    }
+
+
+    /**
+     *  Quarantine Ports.
+     */
+    protected class QuarantineWorker implements Runnable {
+        @Override
+        public void run() {
+            try {
+                processBDDPLists();
+            }
+            catch (Exception e) {
+                log.error("Error in quarantine worker thread", e);
+            } finally {
+                    bddpTask.reschedule(BDDP_TASK_INTERVAL,
+                                              TimeUnit.MILLISECONDS);
+            }
+        }
+    }
+
+    /**
+     * Add a switch port to the quarantine queue. Schedule the
+     * quarantine task if the quarantine queue was empty before adding
+     * this switch port.
+     * @param npt
+     */
+    protected void addToQuarantineQueue(NodePortTuple npt) {
+        if (quarantineQueue.contains(npt) == false)
+            quarantineQueue.add(npt);
+    }
+
+    /**
+     * Remove a switch port from the quarantine queue.
+     */
+    protected void removeFromQuarantineQueue(NodePortTuple npt) {
+        // Remove all occurrences of the node port tuple from the list.
+        while (quarantineQueue.remove(npt));
+    }
+
+    /**
+     * Add a switch port to maintenance queue.
+     * @param npt
+     */
+    protected void addToMaintenanceQueue(NodePortTuple npt) {
+        // TODO We are not checking if the switch port tuple is already
+        // in the maintenance list or not.  This will be an issue for
+        // really large number of switch ports in the network.
+        if (maintenanceQueue.contains(npt) == false)
+            maintenanceQueue.add(npt);
+    }
+
+    /**
+     * Remove a switch port from maintenance queue.
+     * @param npt
+     */
+    protected void removeFromMaintenanceQueue(NodePortTuple npt) {
+        // Remove all occurrences of the node port tuple from the queue.
+        while (maintenanceQueue.remove(npt));
+    }
+
+    /**
+    * This method processes the quarantine list in bursts.  The task is
+    * at most once per BDDP_TASK_INTERVAL.
+    * One each call, BDDP_TASK_SIZE number of switch ports are processed.
+    * Once the BDDP packets are sent out through the switch ports, the ports
+    * are removed from the quarantine list.
+    */
+
+    protected void processBDDPLists() {
+        int count = 0;
+        Set<NodePortTuple> nptList = new HashSet<NodePortTuple>();
+
+        while(count < BDDP_TASK_SIZE && quarantineQueue.peek() !=null) {
+            NodePortTuple npt;
+            npt = quarantineQueue.remove();
+            sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
+            nptList.add(npt);
+            count++;
+        }
+
+        count = 0;
+        while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) {
+            NodePortTuple npt;
+            npt = maintenanceQueue.remove();
+            sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
+            count++;
+        }
+
+        for(NodePortTuple npt:nptList) {
+            generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId());
+        }
+    }
+
+    public Set<Short> getQuarantinedPorts(long sw) {
+        Set<Short> qPorts = new HashSet<Short>();
+
+        Iterator<NodePortTuple> iter = quarantineQueue.iterator();
+        while (iter.hasNext()) {
+            NodePortTuple npt = iter.next();
+            if (npt.getNodeId() == sw) {
+                qPorts.add(npt.getPortId());
+            }
+        }
+        return qPorts;
+    }
+
+    private void generateSwitchPortStatusUpdate(long sw, short port) {
+        UpdateOperation operation;
+
+        IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
+        if (iofSwitch == null) return;
+
+        OFPhysicalPort ofp = iofSwitch.getPort(port);
+        if (ofp == null) return;
+
+        int srcPortState = ofp.getState();
+        boolean portUp = ((srcPortState &
+                OFPortState.OFPPS_STP_MASK.getValue()) !=
+                OFPortState.OFPPS_STP_BLOCK.getValue());
+
+        if (portUp) operation = UpdateOperation.PORT_UP;
+        else operation = UpdateOperation.PORT_DOWN;
+
+        updates.add(new LDUpdate(sw, port, operation));
+    }
+
+    /** 
+     * Send LLDP on known ports
+     */
+    protected void discoverOnKnownLinkPorts() {
+        // Copy the port set.
+        Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
+        nptSet.addAll(portLinks.keySet());
+
+        // Send LLDP from each of them.
+        for(NodePortTuple npt: nptSet) {
+            discover(npt);
+        }
+    }
+
+    protected void discover(NodePortTuple npt) {
+        discover(npt.getNodeId(), npt.getPortId());
+    }
+
+    protected void discover(long sw, short port) {
+        sendDiscoveryMessage(sw, port, true, false);
+    }
+
+    /**
+     * Learn remote switches when running as a distributed controller ONOS
+     */
+    protected IOFSwitch addRemoteSwitch(long sw, short port) {
+    	IOnosRemoteSwitch remotesw = null;
+    	
+    	// add a switch if we have not seen it before
+    	remotesw = remoteSwitches.get(sw);
+
+    	if (remotesw == null) {
+        	remotesw = new OFSwitchImpl();
+        	remotesw.setupRemoteSwitch(sw);
+        	remoteSwitches.put(remotesw.getId(), remotesw);
+        	log.debug("addRemoteSwitch(): added fake remote sw {}", remotesw);
+        }
+        
+        // add the port if we have not seen it before
+        if (remotesw.getPort(port) == null) {
+        	OFPhysicalPort remoteport = new OFPhysicalPort();
+        	remoteport.setPortNumber(port);
+        	remoteport.setName("fake_" + port);
+        	remoteport.setConfig(0); 
+        	remoteport.setState(0);
+        	remotesw.setPort(remoteport);
+        	log.debug("addRemoteSwitch(): added fake remote port {} to sw {}", remoteport, remotesw.getId());
+        }
+        
+        return remotesw;
+    }
+    
+    /**
+     * Send link discovery message out of a given switch port.
+     * The discovery message may be a standard LLDP or a modified
+     * LLDP, where the dst mac address is set to :ff.  
+     * 
+     * TODO: The modified LLDP will updated in the future and may
+     * use a different eth-type.
+     * @param sw
+     * @param port
+     * @param isStandard   indicates standard or modified LLDP
+     * @param isReverse    indicates whether the LLDP was sent as a response
+     */
+    @LogMessageDoc(level="ERROR",
+            message="Failure sending LLDP out port {port} on switch {switch}",
+            explanation="An I/O error occured while sending LLDP message " +
+            		"to the switch.",
+            recommendation=LogMessageDoc.CHECK_SWITCH)
+    protected void sendDiscoveryMessage(long sw, short port,
+                             boolean isStandard,
+                             boolean isReverse) {
+
+        IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
+        if (iofSwitch == null) {
+            return;
+        }
+
+        if (port == OFPort.OFPP_LOCAL.getValue())
+            return;
+
+        OFPhysicalPort ofpPort = iofSwitch.getPort(port);
+
+        if (ofpPort == null) {
+            if (log.isTraceEnabled()) {
+                log.trace("Null physical port. sw={}, port={}", sw, port);
+            }
+            return;
+        }
+
+        if (isLinkDiscoverySuppressed(sw, port)) {
+            /* Dont send LLDPs out of this port as suppressLLDPs set
+             * 
+             */
+            return;
+        }
+
+        // For fast ports, do not send forward LLDPs or BDDPs.
+        if (!isReverse && autoPortFastFeature && isFastPort(sw, port))
+            return;
+
+        if (log.isTraceEnabled()) {
+            log.trace("Sending LLDP packet out of swich: {}, port: {}",
+                      sw, port);
+        }
+
+        // using "nearest customer bridge" MAC address for broadest possible propagation
+        // through provider and TPMR bridges (see IEEE 802.1AB-2009 and 802.1Q-2011),
+        // in particular the Linux bridge which behaves mostly like a provider bridge
+        byte[] chassisId = new byte[] {4, 0, 0, 0, 0, 0, 0}; // filled in later
+        byte[] portId = new byte[] {2, 0, 0}; // filled in later
+        byte[] ttlValue = new byte[] {0, 0x78};
+        // OpenFlow OUI - 00-26-E1
+        byte[] dpidTLVValue = new byte[] {0x0, 0x26, (byte) 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+        LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127).setLength((short) dpidTLVValue.length).setValue(dpidTLVValue);
+
+        byte[] dpidArray = new byte[8];
+        ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray);
+        ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2);
+
+        Long dpid = sw;
+        dpidBB.putLong(dpid);
+        // set the ethernet source mac to last 6 bytes of dpid
+        System.arraycopy(dpidArray, 2, ofpPort.getHardwareAddress(), 0, 6);
+        // set the chassis id's value to last 6 bytes of dpid
+        System.arraycopy(dpidArray, 2, chassisId, 1, 6);
+        // set the optional tlv to the full dpid
+        System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8);
+
+
+        // set the portId to the outgoing port
+        portBB.putShort(port);
+        if (log.isTraceEnabled()) {
+            log.trace("Sending LLDP out of interface: {}/{}",
+                      HexString.toHexString(sw), port);
+        }
+
+        LLDP lldp = new LLDP();
+        lldp.setChassisId(new LLDPTLV().setType((byte) 1).setLength((short) chassisId.length).setValue(chassisId));
+        lldp.setPortId(new LLDPTLV().setType((byte) 2).setLength((short) portId.length).setValue(portId));
+        lldp.setTtl(new LLDPTLV().setType((byte) 3).setLength((short) ttlValue.length).setValue(ttlValue));
+        lldp.getOptionalTLVList().add(dpidTLV);
+
+        // Add the controller identifier to the TLV value.
+        lldp.getOptionalTLVList().add(controllerTLV);
+        if (isReverse) {
+            lldp.getOptionalTLVList().add(reverseTLV);
+        }else {
+            lldp.getOptionalTLVList().add(forwardTLV);
+        }
+
+        Ethernet ethernet;
+        if (isStandard) {
+            ethernet = new Ethernet()
+            .setSourceMACAddress(ofpPort.getHardwareAddress())
+            .setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING)
+            .setEtherType(Ethernet.TYPE_LLDP);
+            ethernet.setPayload(lldp);
+        } else {
+            BSN bsn = new BSN(BSN.BSN_TYPE_BDDP);
+            bsn.setPayload(lldp);
+
+            ethernet = new Ethernet()
+            .setSourceMACAddress(ofpPort.getHardwareAddress())
+            .setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING)
+            .setEtherType(Ethernet.TYPE_BSN);
+            ethernet.setPayload(bsn);
+        }
+
+
+        // serialize and wrap in a packet out
+        byte[] data = ethernet.serialize();
+        OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
+        po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+        po.setInPort(OFPort.OFPP_NONE);
+
+        // set actions
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(new OFActionOutput(port, (short) 0));
+        po.setActions(actions);
+        po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
+
+        // set data
+        po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + data.length);
+        po.setPacketData(data);
+
+        // send
+        try {
+            iofSwitch.write(po, null);
+            iofSwitch.flush();
+        } catch (IOException e) {
+            log.error("Failure sending LLDP out port {} on switch {}",
+                      new Object[]{ port, iofSwitch.getStringId() }, e);
+        }
+
+    }
+
+    /**
+     * Send LLDPs to all switch-ports
+     */
+    protected void discoverOnAllPorts() {
+        if (log.isTraceEnabled()) {
+            log.trace("Sending LLDP packets out of all the enabled ports on switch {}");
+        }
+        Set<Long> switches = floodlightProvider.getSwitches().keySet();
+        // Send standard LLDPs
+        for (long sw: switches) {
+            IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
+            if (iofSwitch == null) continue;
+            if (iofSwitch.getEnabledPorts() != null) {
+                for (OFPhysicalPort ofp: iofSwitch.getEnabledPorts()) {
+                    if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber()))
+                        continue;
+                    if (autoPortFastFeature && isFastPort(sw, ofp.getPortNumber()))
+                        continue;
+
+                    // sends forward LLDP only non-fastports.
+                    sendDiscoveryMessage(sw, ofp.getPortNumber(), true, false);
+
+                    // If the switch port is not alreayd in the maintenance
+                    // queue, add it.
+                    NodePortTuple npt = new NodePortTuple(sw, ofp.getPortNumber());
+                    addToMaintenanceQueue(npt);
+                }
+            }
+        }
+    }
+
+    protected void setControllerTLV() {
+        //Setting the controllerTLVValue based on current nano time,
+        //controller's IP address, and the network interface object hash
+        //the corresponding IP address.
+
+        final int prime = 7867;
+        InetAddress localIPAddress = null;
+        NetworkInterface localInterface = null;
+
+        byte[] controllerTLVValue = new byte[] {0, 0, 0, 0, 0, 0, 0, 0};  // 8 byte value.
+        ByteBuffer bb = ByteBuffer.allocate(10);
+
+        try{
+            localIPAddress = java.net.InetAddress.getLocalHost();
+            localInterface = NetworkInterface.getByInetAddress(localIPAddress);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        long result = System.nanoTime();
+        if (localIPAddress != null)
+            result = result * prime + IPv4.toIPv4Address(localIPAddress.getHostAddress());
+        if (localInterface != null)
+            result = result * prime + localInterface.hashCode();
+        // set the first 4 bits to 0.
+        result = result & (0x0fffffffffffffffL);
+
+        bb.putLong(result);
+
+        bb.rewind();
+        bb.get(controllerTLVValue, 0, 8);
+
+        this.controllerTLV = new LLDPTLV().setType((byte) 0x0c).setLength((short) controllerTLVValue.length).setValue(controllerTLVValue);
+    }
+
+    @Override
+    public String getName() {
+        return "linkdiscovery";
+    }
+
+    @Override
+    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+        switch (msg.getType()) {
+            case PACKET_IN:
+                return this.handlePacketIn(sw.getId(), (OFPacketIn) msg, cntx);
+            case PORT_STATUS:
+                return this.handlePortStatus(sw.getId(), (OFPortStatus) msg);
+            default:
+                break;
+        }
+        return Command.CONTINUE;
+    }
+
+    private Command handleLldp(LLDP lldp, long sw, OFPacketIn pi, boolean isStandard, FloodlightContext cntx) {
+        // If LLDP is suppressed on this port, ignore received packet as well
+        IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
+        if (iofSwitch == null) {
+            return Command.STOP;
+        }
+
+        if (isLinkDiscoverySuppressed(sw, pi.getInPort()))
+            return Command.STOP;
+
+        // If this is a malformed LLDP, or not from us, exit
+        if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3)
+            return Command.CONTINUE;
+
+        long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong();
+        long otherId = 0;
+        boolean myLLDP = false;
+        Boolean isReverse = null;
+
+        ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue());
+        portBB.position(1);
+
+        Short remotePort = portBB.getShort();
+        IOFSwitch remoteSwitch = null;
+
+        // Verify this LLDP packet matches what we're looking for
+        for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
+            if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 &&
+                    lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 &&
+                    lldptlv.getValue()[2] == (byte)0xe1 && lldptlv.getValue()[3] == 0x0) {
+                ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
+                remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4));
+                if (remoteSwitch == null) {
+                	// Added by ONOS
+                	// floodlight LLDP coming from a remote switch connected to a different controller
+                	// add it to our cache of unconnected remote switches
+                	remoteSwitch = addRemoteSwitch(dpidBB.getLong(4), remotePort);
+                }
+            } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8){
+                otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
+                if (myId == otherId)
+                    myLLDP = true;
+            } else if (lldptlv.getType() == TLV_DIRECTION_TYPE &&
+                    lldptlv.getLength() == TLV_DIRECTION_LENGTH) {
+                if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0])
+                    isReverse = false;
+                else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0])
+                    isReverse = true;
+            }
+        }
+
+        if (myLLDP == false) {
+            // This is not the LLDP sent by this controller.
+            // If the LLDP message has multicast bit set, then we need to broadcast
+            // the packet as a regular packet.
+            if (isStandard) {
+                if (log.isTraceEnabled()) {
+                    log.trace("Getting standard LLDP from a different controller and quelching it.");
+                }
+                return Command.STOP;
+            }
+            else if (myId < otherId)  {
+                if (log.isTraceEnabled()) {
+                    log.trace("Getting BDDP packets from a different controller" +
+                            "and letting it go through normal processing chain.");
+                }
+                //XXX ONOS: Fix the BDDP broadcast issue
+                //return Command.CONTINUE;
+                return Command.STOP;
+            }
+        }
+
+
+        if (remoteSwitch == null) {
+            // Ignore LLDPs not generated by Floodlight, or from a switch that has recently
+            // disconnected, or from a switch connected to another Floodlight instance
+            if (log.isTraceEnabled()) {
+                log.trace("Received LLDP from remote switch not connected to the controller");
+            }
+            return Command.STOP;
+        }
+
+        if (!remoteSwitch.portEnabled(remotePort)) {
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
+            }
+            return Command.STOP;
+        }
+        if (suppressLinkDiscovery.contains(new NodePortTuple(remoteSwitch.getId(),
+                                                     remotePort))) {
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring link with suppressed src port: switch {} port {}",
+                      remoteSwitch, remotePort);
+            }
+            return Command.STOP;
+        }
+        if (!iofSwitch.portEnabled(pi.getInPort())) {
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
+            }
+            return Command.STOP;
+        }
+
+        OFPhysicalPort physicalPort = remoteSwitch.getPort(remotePort);
+        int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0;
+        physicalPort = iofSwitch.getPort(pi.getInPort());
+        int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0;
+
+        // Store the time of update to this link, and push it out to routingEngine
+        Link lt = new Link(remoteSwitch.getId(), remotePort, iofSwitch.getId(), pi.getInPort());
+
+
+        Long lastLldpTime = null;
+        Long lastBddpTime = null;
+
+        Long firstSeenTime = System.currentTimeMillis();
+
+        if (isStandard)
+            lastLldpTime = System.currentTimeMillis();
+        else
+            lastBddpTime = System.currentTimeMillis();
+
+        LinkInfo newLinkInfo =
+                new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
+                             srcPortState, dstPortState);
+
+        addOrUpdateLink(lt, newLinkInfo);
+
+        // Check if reverse link exists. 
+        // If it doesn't exist and if the forward link was seen 
+        // first seen within a small interval, send probe on the 
+        // reverse link.
+
+        newLinkInfo = links.get(lt);
+        if (newLinkInfo != null && isStandard && isReverse == false) {
+            Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
+                                        lt.getSrc(), lt.getSrcPort());
+            LinkInfo reverseInfo = links.get(reverseLink);
+            if (reverseInfo == null) {
+                // the reverse link does not exist.
+                if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - LINK_TIMEOUT) {
+                    this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), isStandard, true);
+                }
+            }
+        }
+
+        // If the received packet is a BDDP packet, then create a reverse BDDP
+        // link as well.
+        if (!isStandard) {
+            Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
+                                        lt.getSrc(), lt.getSrcPort());
+
+            // srcPortState and dstPort state are reversed.
+            LinkInfo reverseInfo =
+                    new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
+                                 dstPortState, srcPortState);
+
+            addOrUpdateLink(reverseLink, reverseInfo);
+        }
+
+        // Remove the node ports from the quarantine and maintenance queues.
+        NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
+        NodePortTuple nptDst = new NodePortTuple(lt.getDst(), lt.getDstPort());
+        removeFromQuarantineQueue(nptSrc);
+        removeFromMaintenanceQueue(nptSrc);
+        removeFromQuarantineQueue(nptDst);
+        removeFromMaintenanceQueue(nptDst);
+
+        // Consume this message
+        return Command.STOP;
+    }
+
+    protected Command handlePacketIn(long sw, OFPacketIn pi,
+                                     FloodlightContext cntx) {
+        Ethernet eth = 
+                IFloodlightProviderService.bcStore.get(cntx, 
+                                                       IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+
+        if(eth.getEtherType() == Ethernet.TYPE_BSN) {
+            BSN bsn = (BSN) eth.getPayload();
+            if (bsn == null) return Command.STOP;
+            if (bsn.getPayload() == null) return Command.STOP;
+            // It could be a packet other than BSN LLDP, therefore
+            // continue with the regular processing.
+            if (bsn.getPayload() instanceof LLDP == false)
+                return Command.CONTINUE;
+            return handleLldp((LLDP) bsn.getPayload(), sw, pi, false, cntx);
+        } else if (eth.getEtherType() == Ethernet.TYPE_LLDP)  {
+            return handleLldp((LLDP) eth.getPayload(), sw, pi, true, cntx);
+        } else if (eth.getEtherType() < 1500) {
+            long destMac = eth.getDestinationMAC().toLong();
+            if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE){
+                if (log.isTraceEnabled()) {
+                    log.trace("Ignoring packet addressed to 802.1D/Q " +
+                            "reserved address.");
+                }
+                return Command.STOP;
+            }
+        }
+
+        // If packet-in is from a quarantine port, stop processing.
+        NodePortTuple npt = new NodePortTuple(sw, pi.getInPort());
+        if (quarantineQueue.contains(npt)) return Command.STOP;
+
+        return Command.CONTINUE;
+    }
+
+    protected UpdateOperation getUpdateOperation(int srcPortState,
+                                                 int dstPortState) {
+        boolean added =
+                (((srcPortState &
+                   OFPortState.OFPPS_STP_MASK.getValue()) !=
+                   OFPortState.OFPPS_STP_BLOCK.getValue()) &&
+                ((dstPortState &
+                  OFPortState.OFPPS_STP_MASK.getValue()) !=
+                  OFPortState.OFPPS_STP_BLOCK.getValue()));
+
+        if (added) return UpdateOperation.LINK_UPDATED;
+        return UpdateOperation.LINK_REMOVED;
+    }
+
+
+
+    protected UpdateOperation getUpdateOperation(int srcPortState) {
+        boolean portUp = ((srcPortState &
+                OFPortState.OFPPS_STP_MASK.getValue()) !=
+                OFPortState.OFPPS_STP_BLOCK.getValue());
+
+        if (portUp) return UpdateOperation.PORT_UP;
+        else return UpdateOperation.PORT_DOWN;
+    }
+
+    protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
+
+        NodePortTuple srcNpt, dstNpt;
+        boolean linkChanged = false;
+
+        lock.writeLock().lock();
+        try {
+            // put the new info.  if an old info exists, it will be returned.
+            LinkInfo oldInfo = links.put(lt, newInfo);
+            if (oldInfo != null &&
+                    oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime())
+                newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
+
+            if (log.isTraceEnabled()) {
+                log.trace("addOrUpdateLink: {} {}", 
+                          lt, 
+                          (newInfo.getMulticastValidTime()!=null) ? "multicast" : "unicast");
+            }
+
+            UpdateOperation updateOperation = null;
+            linkChanged = false;
+
+            srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
+            dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
+
+            if (oldInfo == null) {
+                // index it by switch source
+                if (!switchLinks.containsKey(lt.getSrc()))
+                    switchLinks.put(lt.getSrc(), new HashSet<Link>());
+                switchLinks.get(lt.getSrc()).add(lt);
+
+                // index it by switch dest
+                if (!switchLinks.containsKey(lt.getDst()))
+                    switchLinks.put(lt.getDst(), new HashSet<Link>());
+                switchLinks.get(lt.getDst()).add(lt);
+
+                // index both ends by switch:port
+                if (!portLinks.containsKey(srcNpt))
+                    portLinks.put(srcNpt, new HashSet<Link>());
+                portLinks.get(srcNpt).add(lt);
+
+                if (!portLinks.containsKey(dstNpt))
+                    portLinks.put(dstNpt, new HashSet<Link>());
+                portLinks.get(dstNpt).add(lt);
+
+                // Add to portNOFLinks if the unicast valid time is null
+                if (newInfo.getUnicastValidTime() == null)
+                    addLinkToBroadcastDomain(lt);
+
+                writeLinkToStorage(lt, newInfo);
+                
+                // ONOS: Distinguish added event separately from updated event
+                updateOperation = UpdateOperation.LINK_ADDED;
+                linkChanged = true;
+
+                // Add to event history
+                evHistTopoLink(lt.getSrc(),
+                               lt.getDst(),
+                               lt.getSrcPort(),
+                               lt.getDstPort(),
+                               newInfo.getSrcPortState(), newInfo.getDstPortState(),
+                               getLinkType(lt, newInfo),
+                               EvAction.LINK_ADDED, "LLDP Recvd");
+            } else {
+                // Since the link info is already there, we need to
+                // update the right fields.
+                if (newInfo.getUnicastValidTime() == null) {
+                    // This is due to a multicast LLDP, so copy the old unicast
+                    // value.
+                    if (oldInfo.getUnicastValidTime() != null) {
+                        newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
+                    }
+                } else if (newInfo.getMulticastValidTime() == null) {
+                    // This is due to a unicast LLDP, so copy the old multicast
+                    // value.
+                    if (oldInfo.getMulticastValidTime() != null) {
+                        newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime());
+                    }
+                }
+
+                Long oldTime = oldInfo.getUnicastValidTime();
+                Long newTime = newInfo.getUnicastValidTime();
+                // the link has changed its state between openflow and non-openflow
+                // if the unicastValidTimes are null or not null
+                if (oldTime != null & newTime == null) {
+                    // openflow -> non-openflow transition
+                    // we need to add the link tuple to the portNOFLinks
+                    addLinkToBroadcastDomain(lt);
+                    linkChanged = true;
+                } else if (oldTime == null & newTime != null) {
+                    // non-openflow -> openflow transition
+                    // we need to remove the link from the portNOFLinks
+                    removeLinkFromBroadcastDomain(lt);
+                    linkChanged = true;
+                }
+
+                // Only update the port states if they've changed
+                if (newInfo.getSrcPortState().intValue() !=
+                        oldInfo.getSrcPortState().intValue() ||
+                        newInfo.getDstPortState().intValue() !=
+                        oldInfo.getDstPortState().intValue())
+                    linkChanged = true;
+
+                // Write changes to storage. This will always write the updated
+                // valid time, plus the port states if they've changed (i.e. if
+                // they weren't set to null in the previous block of code.
+                writeLinkToStorage(lt, newInfo);
+
+                if (linkChanged) {
+                    updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
+                                                         newInfo.getDstPortState());
+                    if (log.isTraceEnabled()) {
+                        log.trace("Updated link {}", lt);
+                    }
+                    // Add to event history
+                    evHistTopoLink(lt.getSrc(),
+                                   lt.getDst(),
+                                   lt.getSrcPort(),
+                                   lt.getDstPort(),
+                                   newInfo.getSrcPortState(), newInfo.getDstPortState(),
+                                   getLinkType(lt, newInfo),
+                                   EvAction.LINK_PORT_STATE_UPDATED,
+                                   "LLDP Recvd");
+                }
+            }
+
+            if (linkChanged) {
+                // find out if the link was added or removed here.
+                updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+                                         lt.getDst(), lt.getDstPort(),
+                                         getLinkType(lt, newInfo),
+                                         updateOperation));
+            }
+        } finally {
+            lock.writeLock().unlock();
+        }
+
+        return linkChanged;
+    }
+
+    public Map<Long, Set<Link>> getSwitchLinks() {
+        return this.switchLinks;
+    }
+
+    /**
+     * Removes links from memory and storage.
+     * @param links The List of @LinkTuple to delete.
+     */
+    protected void deleteLinks(List<Link> links, String reason) {
+        NodePortTuple srcNpt, dstNpt;
+
+        lock.writeLock().lock();
+        try {
+            for (Link lt : links) {
+                srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
+                dstNpt  =new NodePortTuple(lt.getDst(), lt.getDstPort());
+
+                switchLinks.get(lt.getSrc()).remove(lt);
+                switchLinks.get(lt.getDst()).remove(lt);
+                if (switchLinks.containsKey(lt.getSrc()) &&
+                        switchLinks.get(lt.getSrc()).isEmpty())
+                    this.switchLinks.remove(lt.getSrc());
+                if (this.switchLinks.containsKey(lt.getDst()) &&
+                        this.switchLinks.get(lt.getDst()).isEmpty())
+                    this.switchLinks.remove(lt.getDst());
+
+                if (this.portLinks.get(srcNpt) != null) {
+                    this.portLinks.get(srcNpt).remove(lt);
+                    if (this.portLinks.get(srcNpt).isEmpty())
+                        this.portLinks.remove(srcNpt);
+                }
+                if (this.portLinks.get(dstNpt) != null) {
+                    this.portLinks.get(dstNpt).remove(lt);
+                    if (this.portLinks.get(dstNpt).isEmpty())
+                        this.portLinks.remove(dstNpt);
+                }
+
+                LinkInfo info = this.links.remove(lt);
+                updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+                                         lt.getDst(), lt.getDstPort(),
+                                         getLinkType(lt, info),
+                                         UpdateOperation.LINK_REMOVED));
+
+                // Update Event History
+                evHistTopoLink(lt.getSrc(),
+                               lt.getDst(),
+                               lt.getSrcPort(),
+                               lt.getDstPort(),
+                               0, 0, // Port states
+                               ILinkDiscovery.LinkType.INVALID_LINK,
+                               EvAction.LINK_DELETED, reason);
+
+                // remove link from storage.
+                removeLinkFromStorage(lt);
+
+                // TODO  Whenever link is removed, it has to checked if
+                // the switchports must be added to quarantine.
+
+                if (log.isTraceEnabled()) {
+                    log.trace("Deleted link {}", lt);
+                }
+            }
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Handles an OFPortStatus message from a switch. We will add or
+     * delete LinkTupes as well re-compute the topology if needed.
+     * @param sw The IOFSwitch that sent the port status message
+     * @param ps The OFPortStatus message
+     * @return The Command to continue or stop after we process this message
+     */
+    protected Command handlePortStatus(long sw, OFPortStatus ps) {
+
+        IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
+        if (iofSwitch == null) return Command.CONTINUE;
+
+        // ONOS: If we do not control this switch, then we should not process its port status messages
+        if (!registryService.hasControl(iofSwitch.getId())) return Command.CONTINUE;
+        
+        if (log.isTraceEnabled()) {
+            log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
+                    "config is {} state is {}",
+                    new Object[] {iofSwitch.getStringId(),
+                                  ps.getDesc().getPortNumber(),
+                                  ps.getReason(),
+                                  ps.getDesc().getConfig(),
+                                  ps.getDesc().getState()});
+        }
+
+        short port = ps.getDesc().getPortNumber();
+        NodePortTuple npt = new NodePortTuple(sw, port);
+        boolean linkDeleted  = false;
+        boolean linkInfoChanged = false;
+
+        lock.writeLock().lock();
+        try {
+            // if ps is a delete, or a modify where the port is down or
+            // configured down
+            if ((byte)OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() ||
+                    ((byte)OFPortReason.OFPPR_MODIFY.ordinal() ==
+                    ps.getReason() && !portEnabled(ps.getDesc()))) {
+                deleteLinksOnPort(npt, "Port Status Changed");
+                LDUpdate update = new LDUpdate(sw, port, UpdateOperation.PORT_DOWN);
+                updates.add(update);
+                linkDeleted = true;
+                } 
+            else if (ps.getReason() ==
+                    (byte)OFPortReason.OFPPR_MODIFY.ordinal()) {
+                // If ps is a port modification and the port state has changed
+                // that affects links in the topology
+
+                if (this.portLinks.containsKey(npt)) {
+                    for (Link lt: this.portLinks.get(npt)) {
+                        LinkInfo linkInfo = links.get(lt);
+                        assert(linkInfo != null);
+                        Integer updatedSrcPortState = null;
+                        Integer updatedDstPortState = null;
+                        if (lt.getSrc() == npt.getNodeId() && 
+                                lt.getSrcPort() == npt.getPortId() &&
+                                (linkInfo.getSrcPortState() !=
+                                ps.getDesc().getState())) {
+                            updatedSrcPortState = ps.getDesc().getState();
+                            linkInfo.setSrcPortState(updatedSrcPortState);
+                        }
+                        if (lt.getDst() == npt.getNodeId() &&
+                                lt.getDstPort() == npt.getPortId() &&
+                                (linkInfo.getDstPortState() !=
+                                ps.getDesc().getState())) {
+                            updatedDstPortState = ps.getDesc().getState();
+                            linkInfo.setDstPortState(updatedDstPortState);
+                        }
+                        if ((updatedSrcPortState != null) ||
+                                (updatedDstPortState != null)) {
+                            // The link is already known to link discovery
+                            // manager and the status has changed, therefore
+                            // send an LDUpdate.
+                            UpdateOperation operation =
+                                    getUpdateOperation(linkInfo.getSrcPortState(),
+                                                       linkInfo.getDstPortState());
+                            updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+                                                     lt.getDst(), lt.getDstPort(),
+                                                     getLinkType(lt, linkInfo),
+                                                     operation));
+                            writeLinkToStorage(lt, linkInfo);
+                            linkInfoChanged = true;
+                        }
+                    }
+                }
+
+                UpdateOperation operation =
+                        getUpdateOperation(ps.getDesc().getState());
+                updates.add(new LDUpdate(sw, port, operation));
+            }
+
+            if (!linkDeleted && !linkInfoChanged){
+                if (log.isTraceEnabled()) {
+                    log.trace("handlePortStatus: Switch {} port #{} reason {};"+
+                            " no links to update/remove",
+                            new Object[] {HexString.toHexString(sw),
+                                          ps.getDesc().getPortNumber(),
+                                          ps.getReason()});
+                }
+            }
+        } finally {
+            lock.writeLock().unlock();
+        }
+
+        if (!linkDeleted) {
+            // Send LLDP right away when port state is changed for faster
+            // cluster-merge. If it is a link delete then there is not need
+            // to send the LLDPs right away and instead we wait for the LLDPs
+            // to be sent on the timer as it is normally done
+            // do it outside the write-lock
+            // sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
+            processNewPort(npt.getNodeId(), npt.getPortId());
+        }
+        return Command.CONTINUE;
+    }
+
+    /**
+     * Process a new port.
+     * If link discovery is disabled on the port, then do nothing.
+     * If autoportfast feature is enabled and the port is a fast port, then
+     * do nothing.
+     * Otherwise, send LLDP message.  Add the port to quarantine.
+     * @param sw
+     * @param p
+     */
+    private void processNewPort(long sw, short p) {
+        if (isLinkDiscoverySuppressed(sw, p)) {
+            // Do nothing as link discovery is suppressed.
+        }
+        else if (autoPortFastFeature && isFastPort(sw, p)) {
+            // Do nothing as the port is a fast port.
+        }
+        else {
+            NodePortTuple npt = new NodePortTuple(sw, p);
+            discover(sw, p);
+            // if it is not a fast port, add it to quarantine.
+            if (!isFastPort(sw, p)) {
+                addToQuarantineQueue(npt);
+            } else {
+                // Add to maintenance queue to ensure that BDDP packets
+                // are sent out.
+                addToMaintenanceQueue(npt);
+            }
+        }
+    }
+
+    /**
+     * We send out LLDP messages when a switch is added to discover the topology
+     * @param sw The IOFSwitch that connected to the controller
+     */
+    @Override
+    public void addedSwitch(IOFSwitch sw) {
+
+        if (sw.getEnabledPorts() != null) {
+            for (Short p : sw.getEnabledPortNumbers()) {
+                processNewPort(sw.getId(), p);
+            }
+        }
+        // Update event history
+        evHistTopoSwitch(sw, EvAction.SWITCH_CONNECTED, "None");
+        LDUpdate update = new LDUpdate(sw.getId(), null,
+                                       UpdateOperation.SWITCH_UPDATED);
+        updates.add(update);
+    }
+
+    /**
+     * When a switch disconnects we remove any links from our map and notify.
+     * @param The id of the switch
+     */
+    @Override
+    public void removedSwitch(IOFSwitch iofSwitch) {
+        // Update event history
+        long sw = iofSwitch.getId();
+        evHistTopoSwitch(iofSwitch, EvAction.SWITCH_DISCONNECTED, "None");
+        List<Link> eraseList = new ArrayList<Link>();
+        lock.writeLock().lock();
+        try {
+            if (switchLinks.containsKey(sw)) {
+                if (log.isTraceEnabled()) {
+                    log.trace("Handle switchRemoved. Switch {}; removing links {}",
+                              HexString.toHexString(sw), switchLinks.get(sw));
+                }
+                // add all tuples with an endpoint on this switch to erase list
+                eraseList.addAll(switchLinks.get(sw));
+                deleteLinks(eraseList, "Switch Removed");
+
+                // Send a switch removed update
+                LDUpdate update = new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED);
+                updates.add(update);
+            }
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+    
+    /**
+     * We don't react the port changed notifications here. we listen for 
+     * OFPortStatus messages directly. Might consider using this notifier
+     * instead
+     */
+    @Override
+    public void switchPortChanged(Long switchId) {
+        // no-op
+    }
+
+    /** 
+     * Delete links incident on a given switch port.
+     * @param npt
+     * @param reason
+     */
+    protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
+        List<Link> eraseList = new ArrayList<Link>();
+        if (this.portLinks.containsKey(npt)) {
+            if (log.isTraceEnabled()) {
+                log.trace("handlePortStatus: Switch {} port #{} " +
+                        "removing links {}",
+                        new Object[] {HexString.toHexString(npt.getNodeId()),
+                                      npt.getPortId(),
+                                      this.portLinks.get(npt)});
+            }
+            eraseList.addAll(this.portLinks.get(npt));
+            deleteLinks(eraseList, reason);
+        }
+    }
+
+    /** 
+     * Iterates through the list of links and deletes if the
+     * last discovery message reception time exceeds timeout values.
+     */
+    protected void timeoutLinks() {
+        List<Link> eraseList = new ArrayList<Link>();
+        Long curTime = System.currentTimeMillis();
+        boolean linkChanged = false;
+
+        // reentrant required here because deleteLink also write locks
+        lock.writeLock().lock();
+        try {
+            Iterator<Entry<Link, LinkInfo>> it =
+                    this.links.entrySet().iterator();
+            while (it.hasNext()) {
+                Entry<Link, LinkInfo> entry = it.next();
+                Link lt = entry.getKey();
+                LinkInfo info = entry.getValue();
+
+                // Timeout the unicast and multicast LLDP valid times
+                // independently.
+                if ((info.getUnicastValidTime() != null) && 
+                        (info.getUnicastValidTime() + (this.LINK_TIMEOUT * 1000) < curTime)){
+                    info.setUnicastValidTime(null);
+
+                    if (info.getMulticastValidTime() != null)
+                        addLinkToBroadcastDomain(lt);
+                    // Note that even if mTime becomes null later on,
+                    // the link would be deleted, which would trigger updateClusters().
+                    linkChanged = true;
+                }
+                if ((info.getMulticastValidTime()!= null) && 
+                        (info.getMulticastValidTime()+ (this.LINK_TIMEOUT * 1000) < curTime)) {
+                    info.setMulticastValidTime(null);
+                    // if uTime is not null, then link will remain as openflow
+                    // link. If uTime is null, it will be deleted.  So, we
+                    // don't care about linkChanged flag here.
+                    removeLinkFromBroadcastDomain(lt);
+                    linkChanged = true;
+                }
+                // Add to the erase list only if the unicast
+                // time is null.
+                if (info.getUnicastValidTime() == null && 
+                        info.getMulticastValidTime() == null){
+                    eraseList.add(entry.getKey());
+                } else if (linkChanged) {
+                    UpdateOperation operation;
+                    operation = getUpdateOperation(info.getSrcPortState(),
+                                                   info.getDstPortState());
+                    updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+                                             lt.getDst(), lt.getDstPort(),
+                                             getLinkType(lt, info),
+                                             operation));
+                }
+            }
+
+            // if any link was deleted or any link was changed.
+            if ((eraseList.size() > 0) || linkChanged) {
+                deleteLinks(eraseList, "LLDP timeout");
+            }
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+
+    private boolean portEnabled(OFPhysicalPort port) {
+        if (port == null)
+            return false;
+        if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0)
+            return false;
+        if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0)
+            return false;
+        // Port STP state doesn't work with multiple VLANs, so ignore it for now
+        // if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
+        //    return false;
+        return true;
+    }
+
+    public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
+        return portBroadcastDomainLinks;
+    }
+
+    @Override
+    public Map<Link, LinkInfo> getLinks() {
+        lock.readLock().lock();
+        Map<Link, LinkInfo> result;
+        try {
+            result = new HashMap<Link, LinkInfo>(links);
+        } finally {
+            lock.readLock().unlock();
+        }
+        return result;
+    }
+
+    protected void addLinkToBroadcastDomain(Link lt) {
+
+        NodePortTuple srcNpt, dstNpt;
+        srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
+        dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
+
+        if (!portBroadcastDomainLinks.containsKey(lt.getSrc()))
+            portBroadcastDomainLinks.put(srcNpt, new HashSet<Link>());
+        portBroadcastDomainLinks.get(srcNpt).add(lt);
+
+        if (!portBroadcastDomainLinks.containsKey(lt.getDst()))
+            portBroadcastDomainLinks.put(dstNpt, new HashSet<Link>());
+        portBroadcastDomainLinks.get(dstNpt).add(lt);
+    }
+
+    protected void removeLinkFromBroadcastDomain(Link lt) {
+
+        NodePortTuple srcNpt, dstNpt;
+        srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
+        dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
+
+        if (portBroadcastDomainLinks.containsKey(srcNpt)) {
+            portBroadcastDomainLinks.get(srcNpt).remove(lt);
+            if (portBroadcastDomainLinks.get(srcNpt).isEmpty())
+                portBroadcastDomainLinks.remove(srcNpt);
+        }
+
+        if (portBroadcastDomainLinks.containsKey(dstNpt)) {
+            portBroadcastDomainLinks.get(dstNpt).remove(lt);
+            if (portBroadcastDomainLinks.get(dstNpt).isEmpty())
+                portBroadcastDomainLinks.remove(dstNpt);
+        }
+    }
+
+    // STORAGE METHODS
+    /**
+     * Deletes all links from storage
+     */
+    void clearAllLinks() {
+        storageSource.deleteRowsAsync(LINK_TABLE_NAME, null);
+    }
+
+    /**
+     * Gets the storage key for a LinkTuple
+     * @param lt The LinkTuple to get
+     * @return The storage key as a String
+     */
+    private String getLinkId(Link lt) {
+        return HexString.toHexString(lt.getSrc()) +
+                "-" + lt.getSrcPort() + "-" +
+                HexString.toHexString(lt.getDst())+
+                "-" + lt.getDstPort();
+    }
+
+    /**
+     * Writes a LinkTuple and corresponding LinkInfo to storage
+     * @param lt The LinkTuple to write
+     * @param linkInfo The LinkInfo to write
+     */
+    protected void writeLinkToStorage(Link lt, LinkInfo linkInfo) {
+        LinkType type = getLinkType(lt, linkInfo);
+
+        // Write only direct links.  Do not write links to external
+        // L2 network.
+        // if (type != LinkType.DIRECT_LINK && type != LinkType.TUNNEL) {
+        //    return;
+        // }
+
+        Map<String, Object> rowValues = new HashMap<String, Object>();
+        String id = getLinkId(lt);
+        rowValues.put(LINK_ID, id);
+        rowValues.put(LINK_VALID_TIME, linkInfo.getUnicastValidTime());
+        String srcDpid = HexString.toHexString(lt.getSrc());
+        rowValues.put(LINK_SRC_SWITCH, srcDpid);
+        rowValues.put(LINK_SRC_PORT, lt.getSrcPort());
+
+        if (type == LinkType.DIRECT_LINK)
+            rowValues.put(LINK_TYPE, "internal");
+        else if (type == LinkType.MULTIHOP_LINK) 
+            rowValues.put(LINK_TYPE, "external");
+        else if (type == LinkType.TUNNEL) 
+            rowValues.put(LINK_TYPE, "tunnel"); 
+        else rowValues.put(LINK_TYPE, "invalid");
+
+        if (linkInfo.linkStpBlocked()) {
+            if (log.isTraceEnabled()) {
+                log.trace("writeLink, link {}, info {}, srcPortState Blocked",
+                          lt, linkInfo);
+            }
+            rowValues.put(LINK_SRC_PORT_STATE,
+                          OFPhysicalPort.OFPortState.OFPPS_STP_BLOCK.getValue());
+        } else {
+            if (log.isTraceEnabled()) {
+                log.trace("writeLink, link {}, info {}, srcPortState {}",
+                          new Object[]{ lt, linkInfo, linkInfo.getSrcPortState() });
+            }
+            rowValues.put(LINK_SRC_PORT_STATE, linkInfo.getSrcPortState());
+        }
+        String dstDpid = HexString.toHexString(lt.getDst());
+        rowValues.put(LINK_DST_SWITCH, dstDpid);
+        rowValues.put(LINK_DST_PORT, lt.getDstPort());
+        if (linkInfo.linkStpBlocked()) {
+            if (log.isTraceEnabled()) {
+                log.trace("writeLink, link {}, info {}, dstPortState Blocked",
+                          lt, linkInfo);
+            }
+            rowValues.put(LINK_DST_PORT_STATE,
+                          OFPhysicalPort.OFPortState.OFPPS_STP_BLOCK.getValue());
+        } else {
+            if (log.isTraceEnabled()) {
+                log.trace("writeLink, link {}, info {}, dstPortState {}",
+                          new Object[]{ lt, linkInfo, linkInfo.getDstPortState() });
+            }
+            rowValues.put(LINK_DST_PORT_STATE, linkInfo.getDstPortState());
+        }
+        storageSource.updateRowAsync(LINK_TABLE_NAME, rowValues);
+    }
+
+    public Long readLinkValidTime(Link lt) {
+        // FIXME: We're not currently using this right now, but if we start
+        // to use this again, we probably shouldn't use it in its current
+        // form, because it's doing synchronous storage calls. Depending
+        // on the context this may still be OK, but if it's being called
+        // on the packet in processing thread it should be reworked to
+        // use asynchronous storage calls.
+        Long validTime = null;
+        IResultSet resultSet = null;
+        try {
+            String[] columns = { LINK_VALID_TIME };
+            String id = getLinkId(lt);
+            resultSet = storageSource.executeQuery(LINK_TABLE_NAME, columns,
+                                                   new OperatorPredicate(LINK_ID, OperatorPredicate.Operator.EQ, id), null);
+            if (resultSet.next())
+                validTime = resultSet.getLong(LINK_VALID_TIME);
+        }
+        finally {
+            if (resultSet != null)
+                resultSet.close();
+        }
+        return validTime;
+    }
+
+    /**
+     * Removes a link from storage using an asynchronous call.
+     * @param lt The LinkTuple to delete.
+     */
+    protected void removeLinkFromStorage(Link lt) {
+        String id = getLinkId(lt);
+        storageSource.deleteRowAsync(LINK_TABLE_NAME, id);
+    }
+
+    @Override
+    public void addListener(ILinkDiscoveryListener listener) {
+        linkDiscoveryAware.add(listener);
+    }
+
+    /**
+     * Register a link discovery aware component
+     * @param linkDiscoveryAwareComponent
+     */
+    public void addLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
+        // TODO make this a copy on write set or lock it somehow
+        this.linkDiscoveryAware.add(linkDiscoveryAwareComponent);
+    }
+
+    /**
+     * Deregister a link discovery aware component
+     * @param linkDiscoveryAwareComponent
+     */
+    public void removeLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
+        // TODO make this a copy on write set or lock it somehow
+        this.linkDiscoveryAware.remove(linkDiscoveryAwareComponent);
+    }
+
+    /**
+     * Sets the IStorageSource to use for ITology
+     * @param storageSource the storage source to use
+     */
+    public void setStorageSource(IStorageSourceService storageSource) {
+        this.storageSource = storageSource;
+    }
+
+    /**
+     * Gets the storage source for this ITopology
+     * @return The IStorageSource ITopology is writing to
+     */
+    public IStorageSourceService getStorageSource() {
+        return storageSource;
+    }
+
+    @Override
+    public boolean isCallbackOrderingPrereq(OFType type, String name) {
+        return false;
+    }
+
+    @Override
+    public boolean isCallbackOrderingPostreq(OFType type, String name) {
+        return false;
+    }
+
+    @Override
+    public void rowsModified(String tableName, Set<Object> rowKeys) {
+        Map<Long, IOFSwitch> switches = floodlightProvider.getSwitches();
+        ArrayList<IOFSwitch> updated_switches = new ArrayList<IOFSwitch>();
+        for(Object key: rowKeys) {
+            Long swId = new Long(HexString.toLong((String)key));
+            if (switches.containsKey(swId)) {
+                IOFSwitch sw = switches.get(swId);
+                boolean curr_status = sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH);
+                boolean new_status =  false;
+                IResultSet resultSet = null;
+
+                try {
+                    resultSet = storageSource.getRow(tableName, key);
+                    for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
+                        // In case of multiple rows, use the status in last row?
+                        Map<String, Object> row = it.next().getRow();
+                        if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) {
+                            new_status = ((String)row.get(SWITCH_CONFIG_CORE_SWITCH)).equals("true");
+                        }
+                    }
+                }
+                finally {
+                    if (resultSet != null)
+                        resultSet.close();
+                }
+
+                if (curr_status != new_status) {
+                    updated_switches.add(sw);
+                }
+            } else {
+                if (log.isTraceEnabled()) {
+                    log.trace("Update for switch which has no entry in switch " +
+                            "list (dpid={}), a delete action.", (String)key);
+                }
+            }
+        }
+
+        for (IOFSwitch sw : updated_switches) {
+            // Set SWITCH_IS_CORE_SWITCH to it's inverse value
+            if (sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH)) {
+                sw.removeAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH);
+                if (log.isTraceEnabled()) {
+                    log.trace("SWITCH_IS_CORE_SWITCH set to False for {}", sw);
+                }
+                updates.add(new LDUpdate(sw.getId(), SwitchType.BASIC_SWITCH,
+                                         UpdateOperation.SWITCH_UPDATED));
+            }
+            else {
+                sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, new Boolean(true));
+                if (log.isTraceEnabled()) {
+                    log.trace("SWITCH_IS_CORE_SWITCH set to True for {}", sw);
+                }
+                updates.add(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH,
+                                         UpdateOperation.SWITCH_UPDATED));
+            }
+        }
+    }
+
+    @Override
+    public void rowsDeleted(String tableName, Set<Object> rowKeys) {
+        // Ignore delete events, the switch delete will do the right thing on it's own
+    }
+
+    // IFloodlightModule classes
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l = 
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(ILinkDiscoveryService.class);
+        //l.add(ITopologyService.class);
+        return l;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+    getServiceImpls() {
+        Map<Class<? extends IFloodlightService>,
+        IFloodlightService> m = 
+        new HashMap<Class<? extends IFloodlightService>,
+        IFloodlightService>();
+        // We are the class that implements the service
+        m.put(ILinkDiscoveryService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+        Collection<Class<? extends IFloodlightService>> l = 
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(IFloodlightProviderService.class);
+        l.add(IStorageSourceService.class);
+        l.add(IThreadPoolService.class);
+        l.add(IRestApiService.class);
+        // Added by ONOS
+        l.add(IControllerRegistryService.class);
+        return l;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+        storageSource = context.getServiceImpl(IStorageSourceService.class);
+        threadPool = context.getServiceImpl(IThreadPoolService.class);
+        restApi = context.getServiceImpl(IRestApiService.class);
+        // Added by ONOS
+        registryService = context.getServiceImpl(IControllerRegistryService.class);
+
+        // Set the autoportfast feature to false.
+        this.autoPortFastFeature = false;
+
+        // We create this here because there is no ordering guarantee
+        this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
+        this.lock = new ReentrantReadWriteLock();
+        this.updates = new LinkedBlockingQueue<LDUpdate>();
+        this.links = new HashMap<Link, LinkInfo>();
+        this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
+        this.suppressLinkDiscovery =
+                Collections.synchronizedSet(new HashSet<NodePortTuple>());
+        this.portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
+        this.switchLinks = new HashMap<Long, Set<Link>>();
+        this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>();
+        this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>();
+        // Added by ONOS
+        this.remoteSwitches = new HashMap<Long, IOnosRemoteSwitch>();
+
+        this.evHistTopologySwitch =
+                new EventHistory<EventHistoryTopologySwitch>("Topology: Switch");
+        this.evHistTopologyLink =
+                new EventHistory<EventHistoryTopologyLink>("Topology: Link");
+        this.evHistTopologyCluster =
+                new EventHistory<EventHistoryTopologyCluster>("Topology: Cluster");
+    }
+
+    @Override
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+                message="No storage source found.",
+                explanation="Storage source was not initialized; cannot initialize " +
+                "link discovery.",
+                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG),
+        @LogMessageDoc(level="ERROR",
+                message="Error in installing listener for " +
+                        "switch config table {table}",
+                explanation="Failed to install storage notification for the " +
+                		"switch config table",
+                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG),
+        @LogMessageDoc(level="ERROR",
+                message="No storage source found.",
+                explanation="Storage source was not initialized; cannot initialize " +
+                "link discovery.",
+                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG),
+        @LogMessageDoc(level="ERROR",
+                message="Exception in LLDP send timer.",
+                explanation="An unknown error occured while sending LLDP " +
+                		"messages to switches.",
+                recommendation=LogMessageDoc.CHECK_SWITCH)
+    })
+    public void startUp(FloodlightModuleContext context) {
+        // Create our storage tables
+        if (storageSource == null) {
+            log.error("No storage source found.");
+            return;
+        }
+
+        storageSource.createTable(LINK_TABLE_NAME, null);
+        storageSource.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID);
+        storageSource.deleteMatchingRows(LINK_TABLE_NAME, null);
+        // Register for storage updates for the switch table
+        try {
+            storageSource.addListener(SWITCH_CONFIG_TABLE_NAME, this);
+        } catch (StorageException ex) {
+            log.error("Error in installing listener for " +
+            		  "switch table {}", SWITCH_CONFIG_TABLE_NAME);
+        }
+
+        ScheduledExecutorService ses = threadPool.getScheduledExecutor();
+
+        // To be started by the first switch connection
+        discoveryTask = new SingletonTask(ses, new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    discoverLinks();
+                } catch (StorageException e) {
+                    log.error("Storage exception in LLDP send timer; " + 
+                            "terminating process", e);
+                    floodlightProvider.terminate();
+                } catch (Exception e) {
+                    log.error("Exception in LLDP send timer.", e);
+                } finally {
+                    if (!shuttingDown) {
+                        // null role implies HA mode is not enabled.
+                         Role role = floodlightProvider.getRole();
+                         if (role == null || role == Role.MASTER) {
+                             log.trace("Rescheduling discovery task as role = {}", role);
+                             discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
+                                                TimeUnit.SECONDS);
+                         } else {
+                             log.trace("Stopped LLDP rescheduling due to role = {}.", role);
+                         }
+                    }
+                }
+            }
+        });
+
+        // null role implies HA mode is not enabled.
+        Role role = floodlightProvider.getRole();
+        if (role == null || role == Role.MASTER) {
+            log.trace("Setup: Rescheduling discovery task. role = {}", role);
+            discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS);
+        } else {
+                log.trace("Setup: Not scheduling LLDP as role = {}.", role);
+        }
+
+        // Setup the BDDP task.  It is invoked whenever switch port tuples
+        // are added to the quarantine list.
+        bddpTask = new SingletonTask(ses, new QuarantineWorker());
+        bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
+
+        updatesThread = new Thread(new Runnable () {
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        doUpdatesThread();
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }}, "Topology Updates");
+        updatesThread.start();
+
+
+
+        // Register for the OpenFlow messages we want to receive
+        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+        floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
+        // Register for switch updates
+        floodlightProvider.addOFSwitchListener(this);
+        floodlightProvider.addHAListener(this);
+        floodlightProvider.addInfoProvider("summary", this);
+        if (restApi != null)
+            restApi.addRestletRoutable(new LinkDiscoveryWebRoutable());
+        setControllerTLV();
+    }
+
+    // ****************************************************
+    // Topology Manager's Event History members and methods
+    // ****************************************************
+
+    // Topology Manager event history
+    public EventHistory<EventHistoryTopologySwitch>  evHistTopologySwitch;
+    public EventHistory<EventHistoryTopologyLink>    evHistTopologyLink;
+    public EventHistory<EventHistoryTopologyCluster> evHistTopologyCluster;
+    public EventHistoryTopologySwitch  evTopoSwitch;
+    public EventHistoryTopologyLink    evTopoLink;
+    public EventHistoryTopologyCluster evTopoCluster;
+
+    // Switch Added/Deleted
+    private void evHistTopoSwitch(IOFSwitch sw, EvAction actn, String reason) {
+        if (evTopoSwitch == null) {
+            evTopoSwitch = new EventHistoryTopologySwitch();
+        }
+        evTopoSwitch.dpid     = sw.getId();
+        if ((sw.getChannel() != null) &&
+                (SocketAddress.class.isInstance(
+                                                sw.getChannel().getRemoteAddress()))) {
+            evTopoSwitch.ipv4Addr = 
+                    IPv4.toIPv4Address(((InetSocketAddress)(sw.getChannel().
+                            getRemoteAddress())).getAddress().getAddress());
+            evTopoSwitch.l4Port   =
+                    ((InetSocketAddress)(sw.getChannel().
+                            getRemoteAddress())).getPort();
+        } else {
+            evTopoSwitch.ipv4Addr = 0;
+            evTopoSwitch.l4Port = 0;
+        }
+        evTopoSwitch.reason   = reason;
+        evTopoSwitch = evHistTopologySwitch.put(evTopoSwitch, actn);
+    }
+
+    private void evHistTopoLink(long srcDpid, long dstDpid, short srcPort,
+                                short dstPort, int srcPortState, int dstPortState,
+                                ILinkDiscovery.LinkType linkType,
+                                EvAction actn, String reason) {
+        if (evTopoLink == null) {
+            evTopoLink = new EventHistoryTopologyLink();
+        }
+        evTopoLink.srcSwDpid = srcDpid;
+        evTopoLink.dstSwDpid = dstDpid;
+        evTopoLink.srcSwport = srcPort & 0xffff;
+        evTopoLink.dstSwport = dstPort & 0xffff;
+        evTopoLink.srcPortState = srcPortState;
+        evTopoLink.dstPortState = dstPortState;
+        evTopoLink.reason    = reason;
+        switch (linkType) {
+            case DIRECT_LINK:
+                evTopoLink.linkType = "DIRECT_LINK";
+                break;
+            case MULTIHOP_LINK:
+                evTopoLink.linkType = "MULTIHOP_LINK";
+                break;
+            case TUNNEL:
+                evTopoLink.linkType = "TUNNEL";
+                break;
+            case INVALID_LINK:
+            default:
+                evTopoLink.linkType = "Unknown";
+                break;
+        }
+        evTopoLink = evHistTopologyLink.put(evTopoLink, actn);
+    }
+
+    public void evHistTopoCluster(long dpid, long clusterIdOld,
+                                  long clusterIdNew, EvAction action, String reason) {
+        if (evTopoCluster == null) {
+            evTopoCluster = new EventHistoryTopologyCluster();
+        }
+        evTopoCluster.dpid         = dpid;
+        evTopoCluster.clusterIdOld = clusterIdOld;
+        evTopoCluster.clusterIdNew = clusterIdNew;
+        evTopoCluster.reason       = reason;
+        evTopoCluster = evHistTopologyCluster.put(evTopoCluster, action);
+    }
+
+    @Override
+    public Map<String, Object> getInfo(String type) {
+        if (!"summary".equals(type)) return null;
+
+        Map<String, Object> info = new HashMap<String, Object>();
+
+        int num_links = 0;
+        for (Set<Link> links : switchLinks.values())
+            num_links += links.size();
+        info.put("# inter-switch links", num_links / 2);
+
+        return info;
+    }
+
+    // IHARoleListener
+    @Override
+    public void roleChanged(Role oldRole, Role newRole) {
+        switch(newRole) {
+            case MASTER:
+                if (oldRole == Role.SLAVE) {
+                    if (log.isTraceEnabled()) {
+                        log.trace("Sending LLDPs " +
+                                "to HA change from SLAVE->MASTER");
+                    }
+                    clearAllLinks();
+                    log.debug("Role Change to Master: Rescheduling discovery task.");
+                    discoveryTask.reschedule(1, TimeUnit.MICROSECONDS);
+                }
+                break;
+            case SLAVE:
+                if (log.isTraceEnabled()) {
+                    log.trace("Clearing links due to " +
+                            "HA change to SLAVE");
+                }
+                switchLinks.clear();
+                links.clear();
+                portLinks.clear();
+                portBroadcastDomainLinks.clear();
+                discoverOnAllPorts();
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void controllerNodeIPsChanged(
+                                         Map<String, String> curControllerNodeIPs,
+                                         Map<String, String> addedControllerNodeIPs,
+                                         Map<String, String> removedControllerNodeIPs) {
+        // ignore
+    }
+
+    public boolean isAutoPortFastFeature() {
+        return autoPortFastFeature;
+    }
+
+    public void setAutoPortFastFeature(boolean autoPortFastFeature) {
+        this.autoPortFastFeature = autoPortFastFeature;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/AutoPortFast.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/AutoPortFast.java
new file mode 100644
index 0000000..29dc890
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/AutoPortFast.java
@@ -0,0 +1,31 @@
+package net.onrc.onos.ofcontroller.linkdiscovery.web;
+
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
+
+import org.restlet.data.Status;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AutoPortFast extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(AutoPortFast.class);
+
+    @Get("json")
+    public String retrieve() {
+        ILinkDiscoveryService linkDiscovery;
+        linkDiscovery = (ILinkDiscoveryService)getContext().getAttributes().
+                get(ILinkDiscoveryService.class.getCanonicalName());
+
+        String param = ((String)getRequestAttributes().get("state")).toLowerCase();
+        if (param.equals("enable") || param.equals("true")) {
+            linkDiscovery.setAutoPortFastFeature(true);
+        } else if (param.equals("disable") || param.equals("false")) {
+            linkDiscovery.setAutoPortFastFeature(false);
+        }
+        setStatus(Status.SUCCESS_OK, "OK");
+        if (linkDiscovery.isAutoPortFastFeature())
+            return "enabled";
+        else return "disabled";
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java
new file mode 100644
index 0000000..8eae558
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java
@@ -0,0 +1,26 @@
+package net.onrc.onos.ofcontroller.linkdiscovery.web;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+import org.restlet.Context;
+import org.restlet.routing.Router;
+
+public class LinkDiscoveryWebRoutable implements RestletRoutable {
+    /**
+     * Create the Restlet router and bind to the proper resources.
+     */
+    @Override
+    public Router getRestlet(Context context) {
+        Router router = new Router(context);
+        router.attach("/autoportfast/{state}/json", AutoPortFast.class); // enable/true or disable/false
+        return router;
+    }
+
+    /**
+     * Set the base path for the Topology
+     */
+    @Override
+    public String basePath() {
+        return "/wm/linkdiscovery";
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkWithType.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkWithType.java
new file mode 100644
index 0000000..3e5a5e7
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkWithType.java
@@ -0,0 +1,65 @@
+package net.onrc.onos.ofcontroller.linkdiscovery.web;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.openflow.util.HexString;
+
+import net.floodlightcontroller.routing.Link;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LinkType;
+
+/**
+ * This class is both the datastructure and the serializer
+ * for a link with the corresponding type of link.
+ * @author alexreimers
+ */
+@JsonSerialize(using=LinkWithType.class)
+public class LinkWithType extends JsonSerializer<LinkWithType> {
+    public long srcSwDpid;
+    public short srcPort;
+    public int srcPortState;
+    public long dstSwDpid;
+    public short dstPort;
+    public int dstPortState;
+    public LinkType type;
+
+    // Do NOT delete this, it's required for the serializer
+    public LinkWithType() {}
+    
+    public LinkWithType(Link link,
+                        int srcPortState,
+                        int dstPortState,
+                        LinkType type) {
+        this.srcSwDpid = link.getSrc();
+        this.srcPort = link.getSrcPort();
+        this.srcPortState = srcPortState;
+        this.dstSwDpid = link.getDst();
+        this.dstPort = link.getDstPort();
+        this.dstPortState = dstPortState;
+        this.type = type;
+    }
+
+	@Override
+	public void serialize(LinkWithType lwt, JsonGenerator jgen, SerializerProvider arg2) 
+			throws IOException, JsonProcessingException {
+		// You ****MUST*** use lwt for the fields as it's actually a different object.
+		jgen.writeStartObject();
+		jgen.writeStringField("src-switch", HexString.toHexString(lwt.srcSwDpid));
+		jgen.writeNumberField("src-port", lwt.srcPort);
+		jgen.writeNumberField("src-port-state", lwt.srcPortState);
+		jgen.writeStringField("dst-switch", HexString.toHexString(lwt.dstSwDpid));
+		jgen.writeNumberField("dst-port", lwt.dstPort);
+		jgen.writeNumberField("dst-port-state", lwt.dstPortState);
+		jgen.writeStringField("type", lwt.type.toString());
+		jgen.writeEndObject();
+	}
+	
+	@Override
+	public Class<LinkWithType> handledType() {
+		return LinkWithType.class;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinksResource.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinksResource.java
new file mode 100644
index 0000000..c522a05
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinksResource.java
@@ -0,0 +1,37 @@
+package net.onrc.onos.ofcontroller.linkdiscovery.web;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.routing.Link;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.onrc.onos.ofcontroller.linkdiscovery.LinkInfo;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+public class LinksResource extends ServerResource {
+
+    @Get("json")
+    public Set<LinkWithType> retrieve() {
+        ILinkDiscoveryService ld = (ILinkDiscoveryService)getContext().getAttributes().
+                get(ILinkDiscoveryService.class.getCanonicalName());
+        Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>();
+        Set<LinkWithType> returnLinkSet = new HashSet<LinkWithType>();
+
+        if (ld != null) {
+            links.putAll(ld.getLinks());
+            for (Link link: links.keySet()) {
+                LinkInfo info = links.get(link);
+                LinkWithType lwt = new LinkWithType(link,
+                                                    info.getSrcPortState(),
+                                                    info.getDstPortState(),
+                                                    ld.getLinkType(link, info));
+                returnLinkSet.add(lwt);
+            }
+        }
+        return returnLinkSet;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java b/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
index a051d4c..1671412 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/routing/TopoRouteService.java
@@ -23,8 +23,6 @@
 import net.onrc.onos.ofcontroller.util.FlowEntry;
 import net.onrc.onos.ofcontroller.util.Port;
 import net.onrc.onos.ofcontroller.util.SwitchPort;
-import net.onrc.onos.util.GraphDBConnection;
-import net.onrc.onos.util.GraphDBConnection.Transaction;
 import net.onrc.onos.util.GraphDBOperation;
 
 import org.openflow.util.HexString;
@@ -32,7 +30,6 @@
 import org.slf4j.LoggerFactory;
 
 import com.tinkerpop.blueprints.Direction;
-import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
 import com.tinkerpop.blueprints.Vertex;
 import com.tinkerpop.pipes.PipeFunction;
 import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
@@ -135,7 +132,7 @@
     public void init(FloodlightModuleContext context)
 	throws FloodlightModuleException {
 	// TODO: Add the appropriate initialization
-    	op = new GraphDBOperation(GraphDBConnection.getInstance(""));
+    	op = new GraphDBOperation("");
     }
 
     @Override
@@ -266,7 +263,7 @@
      * See the documentation for method @ref prepareShortestPathTopo()
      * for additional information and usage.
      *
-     * @shortestPathTopo the Shortest Path info handler to release.
+     * @param shortestPathTopo the Shortest Path info handler to release.
      */
     public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
 	shortestPathTopo = null;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
new file mode 100644
index 0000000..5ad892b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
@@ -0,0 +1,50 @@
+package net.onrc.onos.ofcontroller.topology.web;
+
+import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
+import net.onrc.onos.ofcontroller.util.DataPath;
+import net.onrc.onos.ofcontroller.util.Dpid;
+import net.onrc.onos.ofcontroller.util.Port;
+import net.onrc.onos.ofcontroller.util.SwitchPort;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RouteResource extends ServerResource {
+
+    protected static Logger log = LoggerFactory.getLogger(RouteResource.class);
+
+    @Get("json")
+    public DataPath retrieve() {
+        ITopoRouteService topoRouteService = 
+                (ITopoRouteService)getContext().getAttributes().
+                    get(ITopoRouteService.class.getCanonicalName());
+	if (topoRouteService == null) {
+	    log.debug("Topology Route Service not found");
+	    return null;
+	}
+        
+        String srcDpidStr = (String) getRequestAttributes().get("src-dpid");
+        String srcPortStr = (String) getRequestAttributes().get("src-port");
+        String dstDpidStr = (String) getRequestAttributes().get("dst-dpid");
+        String dstPortStr = (String) getRequestAttributes().get("dst-port");
+
+        log.debug( srcDpidStr + "--" + srcPortStr + "--" + dstDpidStr + "--" + dstPortStr);
+
+	Dpid srcDpid = new Dpid(srcDpidStr);
+	Port srcPort = new Port(Short.parseShort(srcPortStr));
+	Dpid dstDpid = new Dpid(dstDpidStr);
+	Port dstPort = new Port(Short.parseShort(dstPortStr));
+        
+	DataPath result =
+	    topoRouteService.getShortestPath(new SwitchPort(srcDpid, srcPort),
+					     new SwitchPort(dstDpid, dstPort));
+	if (result != null) {
+	    return result;
+	} else {
+            log.debug("ERROR! no route found");
+            return null;
+        }
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java b/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
index f02552b..5f96414 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
@@ -2,7 +2,6 @@
 
 import java.util.ArrayList;
 
-
 import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/Dpid.java b/src/main/java/net/onrc/onos/ofcontroller/util/Dpid.java
index ce8a4f6..c3cf3aa 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/Dpid.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/Dpid.java
@@ -1,13 +1,11 @@
 package net.onrc.onos.ofcontroller.util;
 
-import org.openflow.util.HexString;
-
 import net.onrc.onos.ofcontroller.util.serializers.DpidDeserializer;
 import net.onrc.onos.ofcontroller.util.serializers.DpidSerializer;
 
-import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.openflow.util.HexString;
 
 /**
  * The class representing a network switch DPID.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
index ac32d0b..7dd0699 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
@@ -2,15 +2,6 @@
 
 import java.util.ArrayList;
 
-
-import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction;
-import net.onrc.onos.ofcontroller.util.FlowEntryErrorState;
-import net.onrc.onos.ofcontroller.util.FlowEntryId;
-import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
-import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
-import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
-
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
index 858272c..22aef98 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
@@ -1,7 +1,6 @@
 package net.onrc.onos.ofcontroller.util;
 
 import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.util.Port.PortValues;
 
 import org.codehaus.jackson.annotate.JsonProperty;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java
index 7a8f67b..c4e75a5 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java
@@ -5,7 +5,6 @@
 import net.onrc.onos.ofcontroller.util.serializers.FlowEntryIdDeserializer;
 import net.onrc.onos.ofcontroller.util.serializers.FlowEntryIdSerializer;
 
-import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
index b9652b8..2310972 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
@@ -5,7 +5,6 @@
 import net.onrc.onos.ofcontroller.util.serializers.FlowIdDeserializer;
 import net.onrc.onos.ofcontroller.util.serializers.FlowIdSerializer;
 
-import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
index 29898e6..f9385e7 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
@@ -5,8 +5,6 @@
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
-import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
-import net.onrc.onos.ofcontroller.util.FlowId;
 
 import org.codehaus.jackson.annotate.JsonProperty;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
index a9d7d85..2081bbe 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4.java
@@ -3,7 +3,6 @@
 import net.onrc.onos.ofcontroller.util.serializers.IPv4Deserializer;
 import net.onrc.onos.ofcontroller.util.serializers.IPv4Serializer;
 
-import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
index fdc6dca..52e6535 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv4Net.java
@@ -1,10 +1,8 @@
 package net.onrc.onos.ofcontroller.util;
 
-import net.onrc.onos.ofcontroller.util.IPv4;
 import net.onrc.onos.ofcontroller.util.serializers.IPv4NetDeserializer;
 import net.onrc.onos.ofcontroller.util.serializers.IPv4NetSerializer;
 
-import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
index 82d1db5..2d28db8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6.java
@@ -1,13 +1,11 @@
 package net.onrc.onos.ofcontroller.util;
 
-import org.openflow.util.HexString;
-
 import net.onrc.onos.ofcontroller.util.serializers.IPv6Deserializer;
 import net.onrc.onos.ofcontroller.util.serializers.IPv6Serializer;
 
-import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.openflow.util.HexString;
 
 /**
  * The class representing an IPv6 address.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
index aacb648..bafff24 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/IPv6Net.java
@@ -1,10 +1,8 @@
 package net.onrc.onos.ofcontroller.util;
 
-import net.onrc.onos.ofcontroller.util.IPv6;
 import net.onrc.onos.ofcontroller.util.serializers.IPv6NetDeserializer;
 import net.onrc.onos.ofcontroller.util.serializers.IPv6NetSerializer;
 
-import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/SwitchPort.java b/src/main/java/net/onrc/onos/ofcontroller/util/SwitchPort.java
index afc2af3..95a934f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/SwitchPort.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/SwitchPort.java
@@ -1,7 +1,5 @@
 package net.onrc.onos.ofcontroller.util;
 
-import net.onrc.onos.ofcontroller.util.Port;
-
 import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidDeserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidDeserializer.java
index f6b1ea0..9075f96 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidDeserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidDeserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.onrc.onos.ofcontroller.util.Dpid;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidSerializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidSerializer.java
index 0da74d4..7ece4d3 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidSerializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/DpidSerializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.onrc.onos.ofcontroller.util.Dpid;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.onrc.onos.ofcontroller.util.Dpid;
-
 /**
  * Serialize a DPID as a string.
  */
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdDeserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdDeserializer.java
index 7a15ddc..72ddfea 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdDeserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdDeserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.onrc.onos.ofcontroller.util.FlowEntryId;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdSerializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdSerializer.java
index 00f4d61..bf73265 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdSerializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowEntryIdSerializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.onrc.onos.ofcontroller.util.FlowEntryId;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.onrc.onos.ofcontroller.util.FlowEntryId;
-
 /**
  * Serialize a Flow Entry ID as a hexadecimal string.
  */
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdDeserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdDeserializer.java
index 6e04108..eb93a23 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdDeserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdDeserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.onrc.onos.ofcontroller.util.FlowId;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdSerializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdSerializer.java
index 575126f..34f6e05 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdSerializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/FlowIdSerializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.onrc.onos.ofcontroller.util.FlowId;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.onrc.onos.ofcontroller.util.FlowId;
-
 /**
  * Serialize a Flow ID as a hexadecimal string.
  */
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Deserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Deserializer.java
index 13ddc0d..daf90af 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Deserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Deserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.onrc.onos.ofcontroller.util.IPv4;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetDeserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetDeserializer.java
index 1f30e91..f67ab38 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetDeserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetDeserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.onrc.onos.ofcontroller.util.IPv4Net;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetSerializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetSerializer.java
index 2580550..0454a58 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetSerializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4NetSerializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.onrc.onos.ofcontroller.util.IPv4Net;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.onrc.onos.ofcontroller.util.IPv4Net;
-
 /**
  * Serialize an IPv4Net address as a string.
  */
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Serializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Serializer.java
index 49dc140..aefc8a0 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Serializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv4Serializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.onrc.onos.ofcontroller.util.IPv4;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.onrc.onos.ofcontroller.util.IPv4;
-
 /**
  * Serialize an IPv4 address as a string.
  */
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Deserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Deserializer.java
index 36109e8..7e3e5f6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Deserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Deserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.onrc.onos.ofcontroller.util.IPv6;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetDeserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetDeserializer.java
index ff3a0ee..d7631b3 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetDeserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetDeserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.onrc.onos.ofcontroller.util.IPv6Net;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetSerializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetSerializer.java
index e0837d5..06dc6cf 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetSerializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6NetSerializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.onrc.onos.ofcontroller.util.IPv6Net;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.onrc.onos.ofcontroller.util.IPv6Net;
-
 /**
  * Serialize an IPv6Net address as a string.
  */
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Serializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Serializer.java
index b4ac122..b6709b8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Serializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/IPv6Serializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.onrc.onos.ofcontroller.util.IPv6;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.onrc.onos.ofcontroller.util.IPv6;
-
 /**
  * Serialize an IPv6 address as a string.
  */
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressDeserializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressDeserializer.java
index 86ed2a7..dc4a0e2 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressDeserializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressDeserializer.java
@@ -2,16 +2,13 @@
 
 import java.io.IOException;
 
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.ObjectCodec;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.DeserializationContext;
-
 import net.floodlightcontroller.util.MACAddress;
 
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressSerializer.java b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressSerializer.java
index 85c8dc4..9c0e225 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressSerializer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/serializers/MACAddressSerializer.java
@@ -2,13 +2,13 @@
 
 import java.io.IOException;
 
+import net.floodlightcontroller.util.MACAddress;
+
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.JsonSerializer;
 import org.codehaus.jackson.map.SerializerProvider;
 
-import net.floodlightcontroller.util.MACAddress;
-
 /**
  * Serialize a MAC address as a string.
  */