Merged conflicts
diff --git a/scripts/link.sh b/scripts/link.sh
index d87464b..dc202e7 100755
--- a/scripts/link.sh
+++ b/scripts/link.sh
@@ -1,4 +1,5 @@
 #! /bin/bash
+
 controller=`hostname`
 switches=`ifconfig -a | grep sw |grep -v eth | awk '{print $1}'`
 
@@ -20,21 +21,26 @@
 for s in $switches; do
     dpid=`sudo ovs-ofctl  show  $s |grep dpid | awk '{print $4}'`
     if [  "x$dpid" == "x$src_dpid" ]; then
-        intfs=`sudo ovs-ofctl show $s |grep addr | awk '{print $1}' | sed 's/.*(//g' | sed 's/):$//g'`
-	intf_list=()
-	for i in $intfs; do
-	  intf_list+=($i)
-        done
-	intf=${intf_list[$src_port]}
-        if [ x$cmd == "xup" ]; then
-	    echo "sudo ifconfig ${intf}  up"
-	    sudo ifconfig ${intf}  up
-        elif [ x$cmd == "xdown" ]; then
-	    echo "sudo ifconfig ${intf}  down"
-	    sudo ifconfig ${intf}  down
-        else
-	    echo "sudo ifconfig ${intf}"
-	    sudo ifconfig ${intf} 
+
+#       intf=`sudo ovs-ofctl show $s |grep addr | awk -v p=$src_port 'BEGIN {pat="^ "p"\("}
+#	$0 ~ pat {w=match ($0, /\(.*\)/); if (w) print substr($0, RSTART+1, RLENGTH-2)}'`
+
+        sudo ovs-ofctl show $s |grep addr | sed 's/[\(\)]/,/g'>/tmp/baz.out
+	intf=`cat /tmp/baz.out | awk -v p=$src_port 'BEGIN {pat="^ "p","}
+	$0 ~ pat {w=match($0, /,.*,/); if (w) print substr($0, RSTART+1, RLENGTH-2)}'`
+
+	if [ x$intf != "x" ]; then
+	        if [ x$cmd == "xup" ]; then
+		    echo "sudo ifconfig ${intf}  up"
+		    sudo ifconfig ${intf}  up
+       		elif [ x$cmd == "xdown" ]; then
+		    echo "sudo ifconfig ${intf}  down"
+		    sudo ifconfig ${intf}  down
+	        else
+		    echo "sudo ifconfig ${intf}"
+		    sudo ifconfig ${intf} 
+		fi
+		break
         fi
     fi
 done
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index be56ec2..18da3dd 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -283,26 +283,29 @@
 
 		@Property("actionOutput")
 		public void setActionOutput(Short actionOutput);
-		
+
+		@Adjacency(label="flow")
+		public IFlowPath getFlow();
+
+		@Adjacency(label="flow")
+		public void setFlow(IFlowPath flow);
+
 		@Adjacency(label="switch")
 		public ISwitchObject getSwitch();
-		
+
 		@Adjacency(label="switch")
 		public void setSwitch(ISwitchObject sw);
-		
+
 		@Adjacency(label="inport")
 		public IPortObject getInPort();
-		
+
 		@Adjacency(label="inport")
 		public void setInPort(IPortObject port);
-		
+
 		@Adjacency(label="outport")
 		public IPortObject getOutPort();
-		
-		@Adjacency(label="switch")
+
+		@Adjacency(label="outport")
 		public void setOutPort(IPortObject port);
-		
-		@Adjacency(label="flow")
-		public IFlowPath getFlowPath();
 	}
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 257add8..0e37e17 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -5,6 +5,7 @@
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -695,7 +696,11 @@
 	    flowEntryObj.setType("flow_entry");
 
 	    // 
-	    // Set the Flow Entry attributes:
+	    // Set the Flow Entry Edges and attributes:
+	    // - Switch edge
+	    // - InPort edge
+	    // - OutPort edge
+	    //
 	    // - flowEntry.flowEntryMatch()
 	    // - flowEntry.flowEntryActions()
 	    // - flowEntry.dpid()
@@ -710,13 +715,14 @@
 	    // - flowEntry.matchDstMac()
 	    // - flowEntry.actionOutput()
 	    //
-	    ISwitchObject sw = conn.utils().searchSwitch(conn,flowEntry.dpid().toString());
+	    ISwitchObject sw =
+		conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
 	    flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
-	    
 	    flowEntryObj.setSwitch(sw);
 	    if (flowEntry.flowEntryMatch().matchInPort()) {
-	    	IPortObject inport = conn.utils().searchPort(conn,flowEntry.dpid().toString(),
-	    			flowEntry.flowEntryMatch().inPort().value());
+	    	IPortObject inport =
+		    conn.utils().searchPort(conn, flowEntry.dpid().toString(),
+					    flowEntry.flowEntryMatch().inPort().value());
 	    	flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
 	    	flowEntryObj.setInPort(inport);
 	    }
@@ -738,10 +744,12 @@
 
 	    for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
 	    	if (fa.actionOutput() != null) {
-	    		IPortObject outport = conn.utils().searchPort(conn,flowEntry.dpid().toString(),
-	    									fa.actionOutput().port().value());
-	    		flowEntryObj.setActionOutput(fa.actionOutput().port().value());
-	    		flowEntryObj.setOutPort(outport);
+		    IPortObject outport =
+			conn.utils().searchPort(conn,
+						flowEntry.dpid().toString(),
+						fa.actionOutput().port().value());
+		    flowEntryObj.setActionOutput(fa.actionOutput().port().value());
+		    flowEntryObj.setOutPort(outport);
 	    	}
 	    }
 	    // TODO: Hacks with hard-coded state names!
@@ -751,18 +759,16 @@
 		flowEntryObj.setUserState("FE_USER_ADD");
 	    flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
 	    //
-	    // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
-	    // and FlowEntryErrorState.
+	    // TODO: Take care of the FlowEntryErrorState.
 	    //
 
 	    // Flow Entries edges:
 	    //   Flow
-	    //   NextFE
-	    //   InPort
-	    //   OutPort
-	    //   Switch
-	    if (! found)
+	    //   NextFE (TODO)
+	    if (! found) {
 		flowObj.addFlowEntry(flowEntryObj);
+		flowEntryObj.setFlow(flowObj);
+	    }
 	}
 	conn.endTx(Transaction.COMMIT);
 
@@ -1116,12 +1122,29 @@
 	//
 	// Extract the Flow state
 	//
-	flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
-	flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
-	flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
-	flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
-	flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
-	flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
+	String flowIdStr = flowObj.getFlowId();
+	String installerIdStr = flowObj.getInstallerId();
+	String srcSwitchStr = flowObj.getSrcSwitch();
+	Short srcPortStr = flowObj.getSrcPort();
+	String dstSwitchStr = flowObj.getDstSwitch();
+	Short dstPortStr = flowObj.getDstPort();
+
+	if ((flowIdStr == null) ||
+	    (installerIdStr == null) ||
+	    (srcSwitchStr == null) ||
+	    (srcPortStr == null) ||
+	    (dstSwitchStr == null) ||
+	    (dstPortStr == null)) {
+	    // TODO: A work-around, becauuse of some bogus database objects
+	    return null;
+	}
+
+	flowPath.setFlowId(new FlowId(flowIdStr));
+	flowPath.setInstallerId(new CallerId(installerIdStr));
+	flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
+	flowPath.dataPath().srcPort().setPort(new Port(srcPortStr));
+	flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
+	flowPath.dataPath().dstPort().setPort(new Port(dstPortStr));
 
 	//
 	// Extract all Flow Entries
@@ -1129,8 +1152,20 @@
 	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
 	for (IFlowEntry flowEntryObj : flowEntries) {
 	    FlowEntry flowEntry = new FlowEntry();
-	    flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
-	    flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
+	    String flowEntryIdStr = flowEntryObj.getFlowEntryId();
+	    String switchDpidStr = flowEntryObj.getSwitchDpid();
+	    String userState = flowEntryObj.getUserState();
+	    String switchState = flowEntryObj.getSwitchState();
+
+	    if ((flowEntryIdStr == null) ||
+		(switchDpidStr == null) ||
+		(userState == null) ||
+		(switchState == null)) {
+		// TODO: A work-around, becauuse of some bogus database objects
+		continue;
+	    }
+	    flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
+	    flowEntry.setDpid(new Dpid(switchDpidStr));
 
 	    //
 	    // Extract the match conditions
@@ -1167,10 +1202,7 @@
 		actions.add(action);
 	    }
 	    flowEntry.setFlowEntryActions(actions);
-
-	    String userState = flowEntryObj.getUserState();
 	    flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
-	    String switchState = flowEntryObj.getSwitchState();
 	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
 	    //
 	    // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
@@ -1185,7 +1217,7 @@
     /**
      * Add and maintain a shortest-path flow.
      *
-     * NOTE: The Flow Path does NOT contain all flow entries.
+     * NOTE: The Flow Path argument does NOT contain all flow entries.
      * Instead, it contains a single dummy flow entry that is used to
      * store the matching condition(s).
      * That entry is replaced by the appropriate entries from the
@@ -1193,12 +1225,10 @@
      *
      * @param flowPath the Flow Path with the endpoints and the match
      * conditions to install.
-     * @param flowId the return-by-reference Flow ID as assigned internally.
-     * @return true on success, otherwise false.
+     * @return the added shortest-path flow on success, otherwise null.
      */
     @Override
-    public boolean addAndMaintainShortestPathFlow(FlowPath flowPath,
-						  FlowId flowId) {
+    public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
 	//
 	// Do the shortest path computation
 	//
@@ -1206,7 +1236,7 @@
 	    topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
 					     flowPath.dataPath().dstPort());
 	if (dataPath == null)
-	    return false;
+	    return null;
 
 	FlowEntryMatch userFlowEntryMatch = null;
 	if (! flowPath.dataPath().flowEntries().isEmpty()) {
@@ -1241,16 +1271,18 @@
 	//
 	// Prepare the computed Flow Path
 	//
-	FlowPath resultFlowPath = new FlowPath();
-	resultFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
-	resultFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
-	resultFlowPath.setDataPath(dataPath);
+	FlowPath computedFlowPath = new FlowPath();
+	computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
+	computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
+	computedFlowPath.setDataPath(dataPath);
 
-	boolean returnValue = addFlow(resultFlowPath, flowId);
+	FlowId flowId = new FlowId();
+	if (! addFlow(computedFlowPath, flowId))
+	    return null;
 
 	// TODO: Mark the flow for maintenance purpose
 
-	return (returnValue);
+	return (computedFlowPath);
     }
 
     /**
@@ -1261,6 +1293,7 @@
      * @param src_port the source port.
      * @param dest_port the destination port.
      */
+    @Override
     public void createFlow(IPortObject src_port, IPortObject dest_port) {
 	// TODO: We don't need it for now.
     }
@@ -1274,6 +1307,7 @@
      * @param dest_port the destination port to match.
      * @return all flows matching the source and the destination port.
      */
+    @Override
     public Iterable<FlowPath> getFlows(IPortObject src_port,
 				       IPortObject dest_port) {
 	// TODO: Pankaj might be implementing it later.
@@ -1288,23 +1322,123 @@
      * @param port the port to match.
      * @return the list of flows that are going out from the port.
      */
+    @Override
     public Iterable<FlowPath> getFlows(IPortObject port) {
 	// TODO: We need it now: Pankaj
 	return null;
     }
 
     /**
-     * Reconcile all flows on inactive port (src port of link which might be
-     * broken).
+     * Reconcile all flows on inactive switch port.
      *
-     * TODO: We need it now: Pavlin
-     *
-     * @param src_port the port that has become inactive.
+     * @param portObject the port that has become inactive.
      */
-    public void reconcileFlows(IPortObject src_port) {
-	// TODO: We need it now: Pavlin
+    @Override
+    public void reconcileFlows(IPortObject portObject) {
+	Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
+	Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
 
-	// TODO: It should call installFlowEntry() as appropriate.
+	//
+	// Collect all affected Flow IDs from the affected flow entries
+	//
+	HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
+	for (IFlowEntry flowEntryObj: inFlowEntries) {
+	    IFlowPath flowObj = flowEntryObj.getFlow();
+	    if (flowObj != null)
+		flowObjSet.add(flowObj);
+	}
+	for (IFlowEntry flowEntryObj: outFlowEntries) {
+	    IFlowPath flowObj = flowEntryObj.getFlow();
+	    if (flowObj != null)
+		flowObjSet.add(flowObj);
+	}
+	// conn.endTx(Transaction.COMMIT);
+
+	//
+	// Remove the old Flow Entries, and add the new Flow Entries
+	//
+	Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
+	for (IFlowPath flowObj : flowObjSet) {
+	    FlowPath flowPath = extractFlowPath(flowObj);
+	    if (flowPath == null)
+		continue;
+
+	    //
+	    // Remove my Flow Entries from the Network MAP
+	    //
+	    Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
+	    for (IFlowEntry flowEntryObj : flowEntries) {
+		String dpidStr = flowEntryObj.getSwitchDpid();
+		if (dpidStr == null)
+		    continue;
+		Dpid dpid = new Dpid(dpidStr);
+		IOFSwitch mySwitch = mySwitches.get(dpid.value());
+		if (mySwitch == null)
+		    continue;		// Ignore the entry: not my switch
+		flowObj.removeFlowEntry(flowEntryObj);
+		conn.utils().removeFlowEntry(conn, flowEntryObj);
+	    }
+
+	    //
+	    // Delete the flow entries from the switches
+	    //
+	    for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
+		flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
+		IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
+		if (mySwitch == null) {
+		    // Not my switch
+		    installRemoteFlowEntry(flowEntry);
+		} else {
+		    installFlowEntry(mySwitch, flowEntry);
+		}
+	    }
+
+	    //
+	    // Calculate the new shortest path and install it in the
+	    // Network MAP.
+	    //
+	    FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
+	    if (addedFlowPath == null) {
+		log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
+			  flowPath.dataPath().srcPort().toString(),
+			  flowPath.dataPath().dstPort().toString());
+		continue;
+	    }
+
+	    //
+	    // Add the flow entries to the switches
+	    //
+	    for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
+		flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
+		IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
+		if (mySwitch == null) {
+		    // Not my switch
+		    installRemoteFlowEntry(flowEntry);
+		    continue;
+		}
+
+		IFlowEntry flowEntryObj =
+		    conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
+		if (flowEntryObj == null) {
+		    //
+		    // TODO: Remove the "new Object[] wrapper in the statement
+		    // below after the SLF4J logger is upgraded to
+		    // Version 1.7.5
+		    //
+		    log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
+			      new Object[] {
+				  flowEntry.dpid(),
+				  flowPath.dataPath().srcPort(),
+				  flowPath.dataPath().dstPort()
+			      });
+		    continue;
+		}
+		// Update the Flow Entry Switch State in the Network MAP
+		if (installFlowEntry(mySwitch, flowEntry)) {
+		    flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
+		}
+	    }
+	}
     }
 
     /**
@@ -1315,6 +1449,7 @@
      * @param src_port the source port.
      * @param dest_port the destination port.
      */
+    @Override
     public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
 	// TODO: We don't need it for now.
     }
@@ -1331,6 +1466,7 @@
      * Installer ID, and any additional matching conditions for the
      * flow entries (e.g., source or destination MAC address, etc).
      */
+    @Override
     public FlowPath computeFlowPath(IPortObject src_port,
 				    IPortObject dest_port) {
 	//
@@ -1393,6 +1529,7 @@
      * @param flow the flow whose flow entries should be returned.
      * @return the flow entries of the flow.
      */
+    @Override
     public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
 	return flow.dataPath().flowEntries();
     }
@@ -1400,19 +1537,12 @@
     /**
      * Install a Flow Entry on a switch.
      *
-     * @param mySwitches the DPID-to-Switch mapping for the switches
-     * controlled by this controller.
+     * @param mySwitch the switch to install the Flow Entry into.
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    public boolean installFlowEntry(Map<Long, IOFSwitch> mySwitches,
-				    FlowEntry flowEntry) {
-	IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
-	if (mySwitch == null) {
-	    // Not my switch
-	    return (installRemoteFlowEntry(flowEntry));
-	}
-
+    @Override
+    public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
 	//
 	// Create the OpenFlow Flow Modification Entry to push
 	//
@@ -1528,18 +1658,17 @@
     /**
      * Remove a Flow Entry from a switch.
      *
-     * TODO: We need it now: Pavlin
-     * - Remove only for local switches
-     * - It will call the removeRemoteFlowEntry() for remote switches.
-     * - To be called by reconcileFlow()
-     *
-     * @param entry the flow entry to remove.
+     * @param mySwitch the switch to remove the Flow Entry from.
+     * @param flowEntry the flow entry to remove.
+     * @return true on success, otherwise false.
      */
-    public void removeFlowEntry(FlowEntry entry) {
-	// TODO: We need it now: Pavlin
-	//  - Remove only for local switches
-	//  - It will call the removeRemoteFlowEntry() for remote switches.
-	//  - To be called by reconcileFlow()
+    @Override
+    public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
+	//
+	// The installFlowEntry() method implements both installation
+	// and removal of flow entries.
+	//
+	return (installFlowEntry(mySwitch, flowEntry));
     }
 
     /**
@@ -1549,10 +1678,11 @@
      * - For now it will make a REST call to the remote controller.
      * - Internally, it needs to know the name of the remote controller.
      *
-     * @param entry the flow entry to install.
+     * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    public boolean installRemoteFlowEntry(FlowEntry entry) {
+    @Override
+    public boolean installRemoteFlowEntry(FlowEntry flowEntry) {
 	// TODO: We need it now: Jono
 	//  - For now it will make a REST call to the remote controller.
 	//  - Internally, it needs to know the name of the remote controller.
@@ -1562,15 +1692,15 @@
     /**
      * Remove a flow entry on a remote controller.
      *
-     * TODO: We need it now: Jono
-     * - For now it will make a REST call to the remote controller.
-     * - Internally, it needs to know the name of the remote controller.
-     *
-     * @param entry the flow entry to remove.
+     * @param flowEntry the flow entry to remove.
+     * @return true on success, otherwise false.
      */
-    public void removeRemoteFlowEntry(FlowEntry entry) {
-	// TODO: We need it now: Jono
-	//  - For now it will make a REST call to the remote controller.
-	//  - Internally, it needs to know the name of the remote controller.
+    @Override
+    public boolean removeRemoteFlowEntry(FlowEntry flowEntry) {
+	//
+	// The installRemoteFlowEntry() method implements both installation
+	// and removal of flow entries.
+	//
+	return (installRemoteFlowEntry(flowEntry));
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index 45cdde0..b6df1e2 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -86,7 +86,7 @@
     /**
      * Add and maintain a shortest-path flow.
      *
-     * NOTE: The Flow Path does NOT contain all flow entries.
+     * NOTE: The Flow Path argument does NOT contain all flow entries.
      * Instead, it contains a single dummy flow entry that is used to
      * store the matching condition(s).
      * That entry is replaced by the appropriate entries from the
@@ -94,9 +94,7 @@
      *
      * @param flowPath the Flow Path with the endpoints and the match
      * conditions to install.
-     * @param flowId the return-by-reference Flow ID as assigned internally.
-     * @return true on success, otherwise false.
+     * @return the added shortest-path flow on success, otherwise null.
      */
-    public boolean addAndMaintainShortestPathFlow(FlowPath flowPath,
-						  FlowId flowId);
+    public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath);
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/AddShortestPathFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/AddShortestPathFlowResource.java
index e00a4b5..3c5bcd8 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/AddShortestPathFlowResource.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/AddShortestPathFlowResource.java
@@ -52,10 +52,12 @@
 
 	// Process the request
 	if (flowPath != null) {
-	    if (flowService.addAndMaintainShortestPathFlow(flowPath, result)
-		!= true) {
+	    FlowPath addedFlowPath =
+		flowService.addAndMaintainShortestPathFlow(flowPath);
+	    if (addedFlowPath == null)
 		result = new FlowId();		// Error: Return empty Flow Id
-	    }
+	    else
+		result = addedFlowPath.flowId();
 	}
 
         return result;
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntry.java b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
index 56a1631..2e61636 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowEntry.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
@@ -23,7 +23,7 @@
  * support multiple in-ports and multiple out-ports.
  */
 public class FlowEntry {
-	private FlowId flowId;                  //FlowID of flowEntry
+    private FlowId flowId;			// FlowID of flowEntry
     private FlowEntryId flowEntryId;		// The Flow Entry ID
     private FlowEntryMatch flowEntryMatch;	// The Flow Entry Match
     private ArrayList<FlowEntryAction> flowEntryActions; // The Flow Entry Actions
@@ -127,6 +127,22 @@
     }
 
     /**
+     * Get the Flow ID.
+     * @return the Flow ID.
+     */
+    @JsonIgnore
+    public FlowId getFlowId() { return flowId; }
+
+    /**
+     * Set the Flow ID.
+     *
+     * @param flowId the Flow ID to set.
+     */
+    public void setFlowId(FlowId flowId) {
+	this.flowId = flowId;
+    }
+
+    /**
      * Get the Flow Entry ID.
      *
      * @return the Flow Entry ID.
@@ -329,19 +345,4 @@
 
 	return ret;
     }
-
-	/**
-	 * @return the flowId
-	 */
-    @JsonIgnore
-	public FlowId getFlowId() {
-		return flowId;
-	}
-
-	/**
-	 * @param flowId the flowId to set
-	 */
-	public void setFlowId(FlowId flowId) {
-		this.flowId = flowId;
-	}
 }
diff --git a/src/main/java/net/onrc/onos/flow/IFlowManager.java b/src/main/java/net/onrc/onos/flow/IFlowManager.java
index 1c90e56..d163760 100644
--- a/src/main/java/net/onrc/onos/flow/IFlowManager.java
+++ b/src/main/java/net/onrc/onos/flow/IFlowManager.java
@@ -41,14 +41,11 @@
     public Iterable<FlowPath> getOutFlows(IPortObject port);
 
     /**
-     * Reconcile all flows on inactive port (src port of link which might be
-     * broken).
+     * Reconcile all flows on inactive switch port.
      *
-     * TODO: We need it now: Pavlin
-     *
-     * @param src_port the port that has become inactive.
+     * @param portObject the port that has become inactive.
      */
-    public void reconcileFlows(IPortObject src_port);
+    public void reconcileFlows(IPortObject portObject);
 
     /**
      * Reconcile all flows between a source and a destination port.
@@ -63,12 +60,14 @@
     /**
      * Compute the shortest path between a source and a destination ports.
      *
-     * TODO: We need it now: Pavlin
-     *
      * @param src_port the source port.
      * @param dest_port the destination port.
      * @return the computed shortest path between the source and the
-     * destination ports.
+     * destination ports. The flow entries in the path itself would
+     * contain the incoming port matching and the outgoing port output
+     * actions set. However, the path itself will NOT have the Flow ID,
+     * Installer ID, and any additional matching conditions for the
+     * flow entries (e.g., source or destination MAC address, etc).
      */
     public FlowPath computeFlowPath(IPortObject src_port,
 				    IPortObject dest_port);
@@ -76,8 +75,6 @@
     /**
      * Get all Flow Entries of a Flow.
      *
-     * TODO: We need it now: Pavlin
-     *
      * @param flow the flow whose flow entries should be returned.
      * @return the flow entries of the flow.
      */
@@ -86,30 +83,20 @@
     /**
      * Install a Flow Entry on a switch.
      *
-     * TODO: We need it now: Pavlin
-     * - Install only for local switches
-     * - It will call the installRemoteFlowEntry() for remote switches.
-     * - To be called by reconcileFlow()
-     *
-     * @param mySwitches the DPID-to-Switch mapping for the switches
-     * controlled by this controller.
+     * @param mySwitch the switch to install the Flow Entry into.
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    public boolean installFlowEntry(Map<Long, IOFSwitch> mySwitches,
-				    FlowEntry flowEntry);
+    public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry);
 
     /**
      * Remove a Flow Entry from a switch.
      *
-     * TODO: We need it now: Pavlin
-     * - Remove only for local switches
-     * - It will call the removeRemoteFlowEntry() for remote switches.
-     * - To be called by reconcileFlow()
-     *
-     * @param entry the flow entry to remove.
+     * @param mySwitch the switch to remove the Flow Entry from.
+     * @param flowEntry the flow entry to remove.
+     * @return true on success, otherwise false.
      */
-    public void removeFlowEntry(FlowEntry entry);
+    public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry);
 
     /**
      * Install a Flow Entry on a remote controller.
@@ -118,19 +105,16 @@
      * - For now it will make a REST call to the remote controller.
      * - Internally, it needs to know the name of the remote controller.
      *
-     * @param entry the flow entry to install.
+     * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    public boolean installRemoteFlowEntry(FlowEntry entry);
+    public boolean installRemoteFlowEntry(FlowEntry flowEntry);
 
     /**
      * Remove a flow entry on a remote controller.
      *
-     * TODO: We need it now: Jono
-     * - For now it will make a REST call to the remote controller.
-     * - Internally, it needs to know the name of the remote controller.
-     *
-     * @param entry the flow entry to remove.
+     * @param flowEntry the flow entry to remove.
+     * @return true on success, otherwise false.
      */
-    public void removeRemoteFlowEntry(FlowEntry entry);        
+    public boolean removeRemoteFlowEntry(FlowEntry flowEntry);
 }
diff --git a/web/ons-demo/RELEASE_NOTES.txt b/web/ons-demo/RELEASE_NOTES.txt
index 95786fd..48834fb 100644
--- a/web/ons-demo/RELEASE_NOTES.txt
+++ b/web/ons-demo/RELEASE_NOTES.txt
@@ -1,3 +1,13 @@
+** March 28, 2013 **
+- basic flow chooser
+	- click in "eye" to show full list
+	- click on "eye" in full list to monitor that flow in the top slot (and show the flow in topology)
+		- other flows get pushed down one slot
+		- when a flow is pushed off the list, it is no longer displayed in topology
+- bug fix for link disappearing after being added
+- color improvements
+- draw vector while linking to make it clearer what's going to happen
+
 ** March 27, 2013 **
 - click onos node "eye" icon to highlight switches associated with that controller
 - double click onos node else where to activate/deactivate
diff --git a/web/ons-demo/assets/eye.svg b/web/ons-demo/assets/black-eye.svg
similarity index 100%
rename from web/ons-demo/assets/eye.svg
rename to web/ons-demo/assets/black-eye.svg
diff --git a/web/ons-demo/assets/white-eye.svg b/web/ons-demo/assets/white-eye.svg
new file mode 100644
index 0000000..8f3b180
--- /dev/null
+++ b/web/ons-demo/assets/white-eye.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.1"
+   width="512"
+   height="512"
+   viewBox="0 0 512 512"
+   id="Layer_1"
+   xml:space="preserve"><metadata
+   id="metadata13"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+   id="defs11" />
+<g
+   id="g3"
+   style="fill:#ffffff;fill-opacity:1">
+	<path
+   d="m 506.637,242.501 c -5.362,-6.347 -11.263,-12.33 -17.171,-18.193 -31.897,-31.679 -68.549,-59.921 -108.648,-80.411 -25.618,-13.08 -53.038,-23.655 -81.451,-28.721 -14.453,-2.586 -28.617,-3.912 -43.474,-3.938 -14.447,0.025 -28.908,1.353 -43.361,3.938 -28.412,5.065 -55.775,15.641 -81.393,28.721 -40.102,20.489 -76.724,48.733 -108.622,80.411 -5.909,5.862 -11.794,11.847 -17.155,18.193 -7.147,8.484 -7.147,18.515 0,27 16.344,19.353 35.774,36.575 55.542,52.321 42.57,33.915 91.25,62.278 144.993,73.711 16.621,3.524 33.299,5.244 49.998,5.228 16.904,0.018 33.488,-1.702 50.107,-5.228 53.744,-11.433 102.534,-39.796 145.104,-73.711 19.768,-15.745 39.194,-32.969 55.538,-52.321 7.146,-8.483 7.139,-18.514 -0.007,-27 z M 255.892,354.552 c -54.334,-0.104 -98.348,-44.177 -98.348,-98.554 0,-54.351 44.014,-98.438 98.348,-98.543 54.809,0.104 98.347,44.192 98.347,98.543 0.001,54.376 -43.538,98.447 -98.347,98.554 z"
+   id="path5"
+   style="fill:#ffffff;fill-opacity:1" />
+	<path
+   d="m 255.86,217.881 c -21.06,0 -38.106,17.059 -38.106,38.115 0,21.068 17.047,38.123 38.106,38.123 21.058,0 38.124,-17.055 38.124,-38.123 0,-21.056 -17.067,-38.115 -38.124,-38.115 z"
+   id="path7"
+   style="fill:#ffffff;fill-opacity:1" />
+</g>
+</svg>
\ No newline at end of file
diff --git a/web/ons-demo/css/layout.default.css b/web/ons-demo/css/layout.default.css
index e46f165..018e728 100644
--- a/web/ons-demo/css/layout.default.css
+++ b/web/ons-demo/css/layout.default.css
@@ -44,25 +44,33 @@
 	-webkit-box-orient: vertical;
 }
 
+#flowChooser {
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	height: 100%;
+	display: -webkit-box;
+	overflow: scroll;
+}
+
 .selectedFlow {
 	display: -webkit-box;
+	position: relative;
+}
+
+#showFlowChooser {
+	position: relative;
+	display: -webkit-box;
+	-webkit-box-pack: center;
+}
+
+.selectedFlow .srcDPID, .selectedFlow .dstDPID {
 	-webkit-user-select: auto;
 }
 
 #selectedFlowsHeader {
 	display: -webkit-box;
-}
-
-.flowIndex {
-	width: 1.5em;
-}
-
-.flowId {
-	width: 5em;
-}
-
-.srcDPID, .dstDPID {
-	width: 20em;
+	height: 1.5em;
 }
 
 .iperf {
diff --git a/web/ons-demo/css/skin.default.css b/web/ons-demo/css/skin.default.css
index 579d940..aebf68b 100644
--- a/web/ons-demo/css/skin.default.css
+++ b/web/ons-demo/css/skin.default.css
@@ -6,6 +6,14 @@
 	margin: 0px;
 }
 
+#topology.linking {
+	cursor: crosshair;
+}
+
+.nodrop {
+	cursor: not-allowed;
+}
+
 .status {
 	padding: 1em;
 }
@@ -87,23 +95,40 @@
 	background-color: black;
 }
 
+#flowChooser .selectedFlow {
+	background-color: rgba(255, 255, 255, .75);
+	color: black;
+}
+
+#flowChooser .flowId {
+	padding-left: 2em;
+}
+
+
 .selectedFlow.selected {
 	color: black;
 	background-color:#AAA;
 }
 
-circle.highlight {
+.highlight circle {
 	stroke: rgba(255, 255, 255, .5);
 	stroke-width: 2px;
 }
 
+#linkVector {
+	fill: none;
+	stroke-width: 1px;
+	stroke: rgba(255, 255, 255, .75);
+	pointer-events: none;
+}
+
 path {
 	pointer-events: none;
 }
 
 path.flow {
 	fill: none;
-	stroke-width: 3px;
+	stroke-width: 5px;
 	stroke: rgba(255, 255, 255, .35);
 }
 
@@ -111,13 +136,26 @@
 	border-top: 1px solid #AAA;
 }
 
-.flowIndex, .flowId, .srcDPID, .dstDPID, .iperf {
+#flowChooser {
+	pointer-events: none;
+	background-color: rgba(0, 0, 0, .25);
+}
+
+
+.flowId, .srcDPID, .dstDPID, .iperf {
 	display: -webkit-box;
 	-webkit-box-pack: center;
 	-webkit-box-align: center;
+	width: 3em;
 }
 
-.flowIndex, .flowId, .srcDPID, .dstDPID {
+
+.srcDPID, .dstDPID {
+	width: 12em;
+}
+
+
+.flowId, .srcDPID, .dstDPID {
 	border-right: 1px solid #AAA;
 }
 
@@ -132,13 +170,22 @@
 	position: relative;
 }
 
-.controllerEye {
+.black-eye {
 	position: absolute;
 	top: 0px;
 	left: 0px;
 	height: 100%;
-	width: 2em;
-	background-image: url('../assets/eye.svg');
+	width: 2.25em;
+	background-image: url('../assets/black-eye.svg');
+	background-size: auto 100%;
+	background-repeat: no-repeat;
+	background-position: .25em center;
+}
+
+.white-eye {
+	height: 100%;
+	width: 2.25em;
+	background-image: url('../assets/white-eye.svg');
 	background-size: auto 100%;
 	background-repeat: no-repeat;
 	background-position: .25em center;
@@ -202,14 +249,14 @@
 }
 
 .color1 {
-	opacity: .2;
+	opacity: .15;
 	pointer-events: none;
 	fill: #EC0033;
 	background-color: #EC0033;
 }
 
 .color2 {
-	opacity: .2;
+	opacity: .15;
 	fill: #FFBA00;
 	background-color: #FFBA00;
 }
diff --git a/web/ons-demo/index.html b/web/ons-demo/index.html
index e89f409..d157ecc 100644
--- a/web/ons-demo/index.html
+++ b/web/ons-demo/index.html
@@ -38,13 +38,13 @@
 	</div>
 </div>
 <div id='selectedFlowsHeader'>
-	<div class='flowIndex'></div>
-	<div class='flowId'>flow id</div>
+	<div id='showFlowChooser' class='flowId'><div class='white-eye'></div></div>
 	<div class='srcDPID'>src</div>
 	<div class='dstDPID'>dst</div>
 	<div class='iperf'>iperf</div>
 </div>
 <div id='selectedFlows'></div>
+<div id='flowChooser'></div>
 
 <script src="js/app.js"></script>
 </body>
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index daf767c..0fa5fa3 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -15,7 +15,7 @@
     });
 
 var model;
-var svg, selectedFlowsView;
+var svg;
 var updateTopology;
 var pendingLinks = {};
 
@@ -24,13 +24,10 @@
 	'color2',
 	'color3',
 	'color4',
-	'color5',
-	'color6',
 	'color7',
 	'color8',
 	'color9',
-	'color10',
-	'color11',
+//	'color11',
 	'color12'
 ];
 colors.reverse();
@@ -49,7 +46,7 @@
 	window.addEventListener('resize', function () {
 		// this is too slow. instead detect first resize event and hide the paths that have explicit matrix applied
 		// either that or is it possible to position the paths so they get the automatic transform as well?
-//		updateTopology(svg, model);
+//		updateTopology();
 	});
 
 	var svg = d3.select('#svg-container').append('svg:svg');
@@ -68,26 +65,31 @@
 			attr('id', 'viewbox').append('svg:g').attr('transform', 'translate(500 500)');
 }
 
-var selectedFlowsData = [
-	{selected: false, flow: null},
-	{selected: false, flow: null},
-	{selected: false, flow: null}
-];
+var selectedFlows = [null, null, null];
 
 function drawFlows() {
 	// DRAW THE FLOWS
-	var flows = d3.select('svg').selectAll('.flow').data(selectedFlowsData, function (d) {
-		return d.flow ? d.flow.flowId.value : null;
+	var flows = d3.select('svg').selectAll('.flow').data(selectedFlows, function (d) {
+		return d ? d.flowId.value : null;
 	});
 
-	flows.enter().append("svg:path")
-	.attr('class', 'flow')
-	.attr('d', function (d) {
-		if (!d.flow) {
+	flows.enter().append("svg:path").attr('class', 'flow')
+		.attr('stroke-dasharray', '4, 10')
+		.append('svg:animate')
+		.attr('attributeName', 'stroke-dashoffset')
+		.attr('attributeType', 'xml')
+		.attr('from', '500')
+		.attr('to', '-500')
+		.attr('dur', '20s')
+		.attr('repeatCount', 'indefinite');
+
+
+	flows.attr('d', function (d) {
+		if (!d) {
 			return;
 		}
 		var pts = [];
-		d.flow.dataPath.flowEntries.forEach(function (flowEntry) {
+		d.dataPath.flowEntries.forEach(function (flowEntry) {
 			var s = d3.select(document.getElementById(flowEntry.dpid.value));
 			var pt = document.querySelector('svg').createSVGPoint();
 			pt.x = s.attr('x');
@@ -97,102 +99,111 @@
 		});
 		return line(pts);
 	})
-	.attr('stroke-dasharray', '3, 10')
-	.append('svg:animate')
-	.attr('attributeName', 'stroke-dashoffset')
-	.attr('attributeType', 'xml')
-	.attr('from', '500')
-	.attr('to', '-500')
-	.attr('dur', '20s')
-	.attr('repeatCount', 'indefinite');
-
-	flows.style('visibility', function (d) {
-		if (d) {
-			return d.selected ? '' : 'hidden';
-		}
-	})
 
 	// "marching ants"
-	// TODO: this will only be true if there's an iperf session running
-	flows.select('animate').attr('from', function (d) {
-		if (d.flow) {
-			if (d.selected) {
-				return '500';
-			} else {
-				return '-500';
-			}
-		}
-	});
+	flows.select('animate').attr('from', 500);
+
+	flows.exit().remove();
 }
 
-function updateFlowView() {
-	selectedFlowsView.data(selectedFlowsData);
-
-	selectedFlowsView.classed('selected', function (d) {
-		if (d.flow) {
-			return d.selected;
-		}
-	});
-
-	selectedFlowsView.select('.flowId')
-		.text(function (d) {
-			if (d.flow) {
-				return d.flow.flowId.value;
-			}
-		});
-
-	selectedFlowsView.select('.srcDPID')
-		.text(function (d) {
-			if (d.flow) {
-				return d.flow.dataPath.srcPort.dpid.value;
-			}
-		});
-
-	selectedFlowsView.select('.dstDPID')
-		.text(function (d) {
-			if (d.flow) {
-				return d.flow.dataPath.dstPort.dpid.value;
-			}
-		});
-}
-
-function createFlowView() {
-	function rowEnter(d, i) {
+function showFlowChooser() {
+	function rowEnter(d) {
 		var row = d3.select(this);
 
-		row.on('click', function () {
-			selectedFlowsData[i].selected = !selectedFlowsData[i].selected;
-			updateFlowView();
-			drawFlows();
-		});
-
 		row.append('div')
-			.classed('flowIndex', true)
-			.text(function () {
-				return i+1;
+			.classed('black-eye', true).
+			on('click', function () {
+				selectedFlows.unshift(d);
+				selectedFlows = selectedFlows.slice(0, 3);
+
+				updateSelectedFlows();
+				updateTopology();
 			});
 
 		row.append('div')
-			.classed('flowId', true);
+			.classed('flowId', true)
+			.text(function (d) {
+				return d.flowId.value;
+			});
 
 		row.append('div')
-			.classed('srcDPID', true);
+			.classed('srcDPID', true)
+			.text(function (d) {
+				return d.dataPath.srcPort.dpid.value;
+			});
+
 
 		row.append('div')
-			.classed('dstDPID', true);
+			.classed('dstDPID', true)
+			.text(function (d) {
+				return d.dataPath.dstPort.dpid.value;
+			});
 
-		row.append('div')
-			.classed('iperf', true);
 	}
 
-	var flows = d3.select('#selectedFlows')
+	var flows = d3.select('#flowChooser')
+		.append('div')
+		.style('pointer-events', 'auto')
 		.selectAll('.selectedFlow')
-		.data(selectedFlowsData)
+		.data(model.flows)
 		.enter()
 		.append('div')
 		.classed('selectedFlow', true)
 		.each(rowEnter);
 
+	setTimeout(function () {
+		d3.select(document.body).on('click', function () {
+			d3.select('#flowChooser').html('');
+			d3.select(document.body).on('click', null);
+		});
+	}, 0);
+}
+
+function updateSelectedFlows() {
+	function rowEnter(d) {
+		var row = d3.select(this);
+		row.append('div').classed('flowId', true);
+		row.append('div').classed('srcDPID', true);
+		row.append('div').classed('dstDPID', true);
+		row.append('div').classed('iperf', true);
+	}
+
+	function rowUpdate(d) {
+		var row = d3.select(this);
+		row.select('.flowId')
+			.text(function (d) {
+				if (d) {
+					return d.flowId.value;
+				}
+			});
+
+		row.select('.srcDPID')
+			.text(function (d) {
+				if (d) {
+					return d.dataPath.srcPort.dpid.value;
+				}
+			});
+
+		row.select('.dstDPID')
+			.text(function (d) {
+				if (d) {
+					return d.dataPath.dstPort.dpid.value;
+				}
+			});
+	}
+
+	var flows = d3.select('#selectedFlows')
+		.selectAll('.selectedFlow')
+		.data(selectedFlows);
+
+	flows.enter()
+		.append('div')
+		.classed('selectedFlow', true)
+		.each(rowEnter);
+
+	flows.each(rowUpdate);
+
+	flows.exit().remove();
 
 	return flows;
 }
@@ -329,12 +340,8 @@
 	return linkMap;
 }
 
-updateTopology = function(svg, model) {
-
-	// DRAW THE SWITCHES
-	var rings = svg.selectAll('.ring').data(createRingsFromModel(model));
-
-
+// removes links from the pending list that are now in the model
+function reconcilePendingLinks(model) {
 	var links = [];
 	model.links.forEach(function (link) {
 		links.push(link);
@@ -344,19 +351,32 @@
 	for (linkId in pendingLinks) {
 		links.push(pendingLinks[linkId]);
 	}
+	return links
+}
 
+updateTopology = function() {
+
+	// DRAW THE SWITCHES
+	var rings = svg.selectAll('.ring').data(createRingsFromModel(model));
+
+	var links = reconcilePendingLinks(model);
 	var linkMap = createLinkMap(links);
 //	var flowMap = createFlowMap(model);
 
 	function mouseOverSwitch(data) {
+
+		d3.event.preventDefault();
+
+		d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', false);
+
 		if (data.highlighted) {
 			return;
 		}
 
 		// only highlight valid link or flow destination by checking for class of existing highlighted circle
-		var highlighted = svg.selectAll('circle.highlight')[0];
+		var highlighted = svg.selectAll('.highlight')[0];
 		if (highlighted.length == 1) {
-			var s = d3.select(highlighted[0]);
+			var s = d3.select(highlighted[0]).select('circle');
 			// only allow links
 			// 	edge->edge (flow)
 			//  aggregation->core
@@ -380,21 +400,20 @@
 			data.target = true;
 		}
 
-
-		d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', false);
 		var node = d3.select(document.getElementById(data.dpid));
-		node.select('circle').classed('highlight', true).transition().duration(100).attr("r", widths.core);
+		node.classed('highlight', true).select('circle').transition().duration(100).attr("r", widths.core);
 		data.highlighted = true;
 		node.moveToFront();
 	}
 
 	function mouseOutSwitch(data) {
+		d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', true);
+
 		if (data.mouseDown)
 			return;
 
-		d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', true);
 		var node = d3.select(document.getElementById(data.dpid));
-		node.select('circle').classed('highlight', false).transition().duration(100).attr("r", widths[data.className]);
+		node.classed('highlight', false).select('circle').transition().duration(100).attr("r", widths[data.className]);
 		data.highlighted = false;
 		data.target = false;
 	}
@@ -402,12 +421,42 @@
 	function mouseDownSwitch(data) {
 		mouseOverSwitch(data);
 		data.mouseDown = true;
+		d3.select('#topology').classed('linking', true);
+
+		d3.select('svg')
+			.append('svg:path')
+			.attr('id', 'linkVector')
+			.attr('d', function () {
+				var s = d3.select(document.getElementById(data.dpid));
+
+				var pt = document.querySelector('svg').createSVGPoint();
+				pt.x = s.attr('x');
+				pt.y = s.attr('y');
+				pt = pt.matrixTransform(s[0][0].getCTM());
+
+				return line([pt, pt]);
+			});
+
+
+		if (data.className === 'core') {
+			d3.selectAll('.edge').classed('nodrop', true);
+		}
+		if (data.className === 'edge') {
+			d3.selectAll('.core').classed('nodrop', true);
+			d3.selectAll('.aggregation').classed('nodrop', true);
+		}
+		if (data.className === 'aggregation') {
+			d3.selectAll('.edge').classed('nodrop', true);
+			d3.selectAll('.aggregation').classed('nodrop', true);
+		}
 	}
 
 	function mouseUpSwitch(data) {
 		if (data.mouseDown) {
 			data.mouseDown = false;
+			d3.select('#topology').classed('linking', false);
 			d3.event.stopPropagation();
+			d3.selectAll('.nodrop').classed('nodrop', false);
 		}
 	}
 
@@ -515,14 +564,60 @@
 	// always on top
 	var labelRings = svg.selectAll('.labelRing').data(createRingsFromModel(model));
 
+	d3.select(document.body).on('mousemove', function () {
+		if (!d3.select('#topology').classed('linking')) {
+			return;
+		}
+		var linkVector = document.getElementById('linkVector');
+		if (!linkVector) {
+			return;
+		}
+		linkVector = d3.select(linkVector);
+
+		var highlighted = svg.selectAll('.highlight')[0];
+		var s1 = null, s2 = null;
+		if (highlighted.length > 1) {
+			var s1 = d3.select(highlighted[0]);
+			var s2 = d3.select(highlighted[1]);
+
+		} else if (highlighted.length > 0) {
+			var s1 = d3.select(highlighted[0]);
+		}
+		var src = s1;
+		if (s2 && !s2.data()[0].target) {
+			src = s2;
+		}
+		if (src) {
+			linkVector.attr('d', function () {
+					var srcPt = document.querySelector('svg').createSVGPoint();
+					srcPt.x = src.attr('x');
+					srcPt.y = src.attr('y');
+					srcPt = srcPt.matrixTransform(src[0][0].getCTM());
+
+					var svg = document.getElementById('topology');
+					var mouse = d3.mouse(viewbox);
+					var dstPt = document.querySelector('svg').createSVGPoint();
+					dstPt.x = mouse[0];
+					dstPt.y = mouse[1];
+					dstPt = dstPt.matrixTransform(viewbox.getCTM());
+
+					return line([srcPt, dstPt]);
+				});
+		}
+	});
+
 	d3.select(document.body).on('mouseup', function () {
 		function clearHighlight() {
 			svg.selectAll('circle').each(function (data) {
 				data.mouseDown = false;
+				d3.select('#topology').classed('linking', false);
 				mouseOutSwitch(data);
-			})
+			});
+			d3.select('#linkVector').remove();
 		};
 
+		d3.selectAll('.nodrop').classed('nodrop', false);
+
 		function removeLink(link) {
 			var path1 = document.getElementById(link['src-switch'] + '=>' + link['dst-switch']);
 			var path2 = document.getElementById(link['dst-switch'] + '=>' + link['src-switch']);
@@ -538,10 +633,10 @@
 		}
 
 
-		var highlighted = svg.selectAll('circle.highlight')[0];
+		var highlighted = svg.selectAll('.highlight')[0];
 		if (highlighted.length == 2) {
-			var s1Data = d3.select(highlighted[0]).data()[0];
-			var s2Data = d3.select(highlighted[1]).data()[0];
+			var s1Data = highlighted[0].__data__;
+			var s2Data = highlighted[1].__data__;
 
 			var srcData, dstData;
 			if (s1Data.target) {
@@ -592,16 +687,16 @@
 								pending: true
 							};
 							pendingLinks[makeLinkKey(link2)] = link2;
-							updateTopology(svg, model);
+							updateTopology();
 
 							linkUp(link1);
 
-							// remove the pending link after 10s
+							// remove the pending links after 10s
 							setTimeout(function () {
 								delete pendingLinks[makeLinkKey(link1)];
 								delete pendingLinks[makeLinkKey(link2)];
 
-								updateTopology(svg, model);
+								updateTopology();
 							}, 10000);
 						}
 					}
@@ -718,7 +813,7 @@
 
 			var dstPt = document.querySelector('svg').createSVGPoint();
 			dstPt.x = dst.attr('x');
-			dstPt.y = dst.attr('y'); // tmp: make up and down links distinguishable
+			dstPt.y = dst.attr('y');
 			dstPt = dstPt.matrixTransform(dst[0][0].getCTM());
 
 			var midPt = document.querySelector('svg').createSVGPoint();
@@ -740,7 +835,7 @@
 	drawFlows();
 }
 
-function updateControllers(model) {
+function updateControllers() {
 	var controllers = d3.select('#controllerList').selectAll('.controller').data(model.controllers);
 	controllers.enter().append('div')
 		.each(function (c) {
@@ -751,7 +846,7 @@
 			return d;
 		})
 		.append('div')
-		.attr('class', 'controllerEye');
+		.attr('class', 'black-eye');
 
 	controllers.attr('class', function (d) {
 			var color = 'colorInactive';
@@ -781,7 +876,7 @@
 		}
 	});
 
-	controllers.select('.controllerEye').on('click', function (c) {
+	controllers.select('.black-eye').on('click', function (c) {
 		var allSelected = true;
 		for (var key in controllerColorMap) {
 			if (!d3.select(document.body).classed(controllerColorMap[key] + '-selected')) {
@@ -806,30 +901,26 @@
 
 }
 
-function sync(svg, selectedFlowsView) {
+function sync(svg) {
 	var d = Date.now();
 	updateModel(function (newModel) {
 //		console.log('Update time: ' + (Date.now() - d)/1000 + 's');
 
+		var modelChanged = false;
 		if (!model || JSON.stringify(model) != JSON.stringify(newModel)) {
-			updateControllers(newModel);
-
-	// fake flows right now
-	var i;
-	for (i = 0; i < newModel.flows.length && i < selectedFlowsData.length; i+=1) {
-		var selected = selectedFlowsData[i] ? selectedFlowsData[i].selected : false;
-		selectedFlowsData[i].flow = newModel.flows[i];
-		selectedFlowsData[i].selected = selected;
-	}
-
-			updateFlowView(newModel);
-			updateTopology(svg, newModel);
+			modelChanged = true;
+			model = newModel;
 		} else {
 //			console.log('no change');
 		}
-		updateHeader(newModel);
 
-		model = newModel;
+		if (modelChanged) {
+			updateControllers();
+			updateSelectedFlows();
+			updateTopology();
+		}
+
+		updateHeader(newModel);
 
 		// do it again in 1s
 		setTimeout(function () {
@@ -839,7 +930,13 @@
 }
 
 svg = createTopologyView();
-selectedFlowsView = createFlowView();
+updateSelectedFlows();
+
+d3.select('#showFlowChooser').on('click', function () {
+	showFlowChooser();
+});
+
+
 // workaround for Chrome v25 bug
 // if executed immediately, the view box transform logic doesn't work properly
 // fixed in Chrome v27
@@ -848,5 +945,5 @@
 	// viewbox transform stuff doesn't work in combination with browser zoom
 	// also works in Chrome v27
 	d3.select('#svg-container').style('zoom',  window.document.body.clientWidth/window.document.width);
-	sync(svg, selectedFlowsView);
+	sync(svg);
 }, 100);
diff --git a/web/ons-demo/js/utils.js b/web/ons-demo/js/utils.js
index 17100b1..4f6d0c1 100644
--- a/web/ons-demo/js/utils.js
+++ b/web/ons-demo/js/utils.js
@@ -11,4 +11,14 @@
 	}
 
 	return parameters;
+}
+
+function findLink(model, dpid) {
+	var links = [];
+	model.links.forEach(function (link) {
+		if (link['src-switch'] == dpid || link['dst-switch'] == dpid) {
+			links.push(link);
+		}
+	});
+	return links;
 }
\ No newline at end of file
diff --git a/web/topology_rest.py b/web/topology_rest.py
index e4a2684..40e36ae 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -721,12 +721,40 @@
 
   return result
 
-#* Link Up/Down
+#* Link Up
 #http://localhost:9000/gui/link/up/<src_dpid>/<src_port>/<dst_dpid>/<dst_port>
-#http://localhost:9000/gui/link/down/<src_dpid>/<src_port>/<dst_dpid>/<dst_port>
+@app.route("/gui/link/up/<src_dpid>/<src_port>/<dst_dpid>/<dst_port>")
+def link_up(src_dpid, src_port, dst_dpid, dst_port):
 
+  cmd = 'up'
+  result=""
+
+  for dpid in (src_dpid, dst_dpid): 
+    if dpid in core_switches:
+      host = controllers[0]
+      src_ports = [1, 2, 3, 4, 5]
+    else:
+      hostid=int(src_dpid.split(':')[-2])
+      host = controllers[hostid-1]
+      if hostid == 2 :
+        src_ports = [51]
+      else :
+        src_ports = [26]
+
+    for port in src_ports :
+      cmd_string="ssh -i ~/.ssh/onlabkey.pem %s 'cd ONOS/scripts; ./link.sh %s %s %s'" % (host, dpid, port, cmd)
+      print cmd_string
+      res=os.popen(cmd_string).read()
+      result = result + ' ' + res
+
+  return result
+
+
+#* Link Down
+#http://localhost:9000/gui/link/down/<src_dpid>/<src_port>/<dst_dpid>/<dst_port>
 @app.route("/gui/link/<cmd>/<src_dpid>/<src_port>/<dst_dpid>/<dst_port>")
-def link_change(cmd, src_dpid, src_port, dst_dpid, dst_port):
+def link_down(cmd, src_dpid, src_port, dst_dpid, dst_port):
+
   if src_dpid in core_switches:
     host = controllers[0]
   else:
@@ -736,8 +764,7 @@
   cmd_string="ssh -i ~/.ssh/onlabkey.pem %s 'cd ONOS/scripts; ./link.sh %s %s %s'" % (host, src_dpid, src_port, cmd)
   print cmd_string
 
-  if cmd =="up" or cmd=="down":
-    result=os.popen(cmd_string).read()
+  result=os.popen(cmd_string).read()
 
   return result
 
@@ -770,10 +797,10 @@
   return errcode
 
 #* Start Iperf Througput
-#http://localhost:9000/gui/iperf/start/<flow_id>
-@app.route("/gui/iperf/start/<flow_id>")
-def iperf_start(flow_id):
-  command = "iperf -xCMSV -t30 -i1 -u -c 127.0.0.1 > iperf_%s.out &" % (flow_id)
+#http://localhost:9000/gui/iperf/start/<flow_id>/<duration>
+@app.route("/gui/iperf/start/<flow_id>/<duration>")
+def iperf_start(flow_id,duration):
+  command = "iperf -xCMSV -t%d -i 0.5 -y c -u -c 127.0.0.1 > iperf_%s.out 2>/dev/null &" % (duration, flow_id)
   print command
   errcode = os.popen(command).read()
   return errcode