cleaned up topology_rest.py and add loadbalancer function
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index e84a3e8..c69d6ee 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -52,7 +52,6 @@
 import net.floodlightcontroller.util.OFMessageDamper;
 import net.floodlightcontroller.util.Port;
 import net.floodlightcontroller.util.SwitchPort;
-import net.onrc.onos.flow.IFlowManager;
 import net.onrc.onos.util.GraphDBConnection;
 import net.onrc.onos.util.GraphDBConnection.Transaction;
 
@@ -67,7 +66,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
+public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
 
     public GraphDBConnection conn;
 
@@ -155,13 +154,17 @@
 			continue;	// Ignore the entry: not my switch
 
 		    myFlowEntries.put(flowEntryId.value(), flowEntryObj);
+		    if (userState.equals("FE_USER_DELETE")) {
+			// An entry that needs to be deleted.
+			deleteFlowEntries.add(flowEntryObj);
+		    }
 		}
 
 		log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
 			  myFlowEntries.size());
 
 		//
-		// Process my Flow Entries
+		// Process my Flow Entries in the Flow Entry ID order
 		//
 		boolean processed_measurement_flow = false;
 		for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
@@ -183,153 +186,19 @@
 		    }
 		    */
 
-		    //
-		    // TODO: Eliminate the re-fetching of flowEntryId,
-		    // userState, switchState, and dpid from the flowEntryObj.
-		    //
-		    FlowEntryId flowEntryId =
-			new FlowEntryId(flowEntryObj.getFlowEntryId());
 		    Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
-		    String userState = flowEntryObj.getUserState();
-		    String switchState = flowEntryObj.getSwitchState();
 		    IOFSwitch mySwitch = mySwitches.get(dpid.value());
 		    if (mySwitch == null)
 			continue;		// Shouldn't happen
-
-		    //
-		    // Create the Open Flow Flow Modification Entry to push
-		    //
-		    OFFlowMod fm =
-			(OFFlowMod) floodlightProvider.getOFMessageFactory()
-			.getMessage(OFType.FLOW_MOD);
-		    long cookie = flowEntryId.value();
-
-		    short flowModCommand = OFFlowMod.OFPFC_ADD;
-		    if (userState.equals("FE_USER_ADD")) {
-			flowModCommand = OFFlowMod.OFPFC_ADD;
-		    } else if (userState.equals("FE_USER_MODIFY")) {
-			flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
-		    } else if (userState.equals("FE_USER_DELETE")) {
-			flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
-		    } else {
-			// Unknown user state. Ignore the entry
-			log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
-				  flowEntryId.toString(), userState);
-			continue;
-		    }
-
-		    //
-		    // Fetch the match conditions.
-		    //
-		    // NOTE: The Flow matching conditions common for all
-		    // Flow Entries are used ONLY if a Flow Entry does NOT
-		    // have the corresponding matching condition set.
-		    //
-		    OFMatch match = new OFMatch();
-		    match.setWildcards(OFMatch.OFPFW_ALL);
-		    //
-		    Short matchInPort = flowEntryObj.getMatchInPort();
-		    if (matchInPort != null) {
-			match.setInputPort(matchInPort);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
-		    }
-		    //
-		    Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
-		    if (matchEthernetFrameType == null)
-			matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
-		    if (matchEthernetFrameType != null) {
-			match.setDataLayerType(matchEthernetFrameType);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
-		    }
-		    //
-		    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
-		    if (matchSrcIPv4Net == null)
-			matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
-		    if (matchSrcIPv4Net != null) {
-			match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
-		    }
-		    //
-		    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
-		    if (matchDstIPv4Net == null)
-			matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
-		    if (matchDstIPv4Net != null) {
-			match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
-		    }
-		    //
-		    String matchSrcMac = flowEntryObj.getMatchSrcMac();
-		    if (matchSrcMac == null)
-			matchSrcMac = flowObj.getMatchSrcMac();
-		    if (matchSrcMac != null) {
-			match.setDataLayerSource(matchSrcMac);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
-		    }
-		    //
-		    String matchDstMac = flowEntryObj.getMatchDstMac();
-		    if (matchDstMac == null)
-			matchDstMac = flowObj.getMatchDstMac();
-		    if (matchDstMac != null) {
-			match.setDataLayerDestination(matchDstMac);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
-		    }
-
-		    //
-		    // Fetch the actions
-		    //
-		    List<OFAction> actions = new ArrayList<OFAction>();
-		    Short actionOutputPort = flowEntryObj.getActionOutput();
-		    if (actionOutputPort != null) {
-			OFActionOutput action = new OFActionOutput();
-			// XXX: The max length is hard-coded for now
-			action.setMaxLength((short)0xffff);
-			action.setPort(actionOutputPort);
-			actions.add(action);
-		    }
-
-		    fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-			.setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
-			.setPriority(PRIORITY_DEFAULT)
-			.setBufferId(OFPacketOut.BUFFER_ID_NONE)
-			.setCookie(cookie)
-			.setCommand(flowModCommand)
-			.setMatch(match)
-			.setActions(actions)
-			.setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
-		    fm.setOutPort(OFPort.OFPP_NONE.getValue());
-		    if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
-			(flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
-			if (actionOutputPort != null)
-			    fm.setOutPort(actionOutputPort);
-		    }
-
-		    //
-		    // TODO: Set the following flag
-		    // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
-		    // See method ForwardingBase::pushRoute()
-		    //
-		    try {
-			messageDamper.write(mySwitch, fm, null);
-			mySwitch.flush();
-			//
-			// TODO: We should use the OpenFlow Barrier mechanism
-			// to check for errors, and update the SwitchState
-			// for a flow entry after the Barrier message is
-			// is received.
-			//
-			flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
-			if (userState.equals("FE_USER_DELETE")) {
-			    // An entry that needs to be deleted.
-			    deleteFlowEntries.add(flowEntryObj);
-			}
-		    } catch (IOException e) {
-			log.error("Failure writing flow mod from network map", e);
-		    }
+		    installFlowEntry(mySwitch, flowObj, flowEntryObj);
 		}
 
 		log.debug("MEASUREMENT: Found {} Flow Entries to delete",
 			  deleteFlowEntries.size());
 
 		//
-		// Delete all entries marked for deletion
+		// Delete all entries marked for deletion from the
+		// Network MAP.
 		//
 		// TODO: We should use the OpenFlow Barrier mechanism
 		// to check for errors, and delete the Flow Entries after the
@@ -345,19 +214,6 @@
 		    }
 		    flowObj.removeFlowEntry(flowEntryObj);
 		    conn.utils().removeFlowEntry(conn, flowEntryObj);
-
-		    // Test whether the last flow entry
-		    Iterable<IFlowEntry> tmpflowEntries =
-			flowObj.getFlowEntries();
-		    boolean found = false;
-		    for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
-			found = true;
-			break;
-		    }
-		    if (! found) {
-			// Remove the Flow Path as well
-			conn.utils().removeFlowPath(conn, flowObj);
-		    }
 		}
 
 
@@ -451,15 +307,24 @@
 		conn.endTx(Transaction.COMMIT);
 
 		if (processed_measurement_flow) {
-		    long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
+		    long estimatedTime =
+			System.nanoTime() - modifiedMeasurementFlowTime;
 		    String logMsg = "MEASUREMENT: Pushed Flow delay: " +
 			(double)estimatedTime / 1000000000 + " sec";
 		    log.debug(logMsg);
 		}
 
 		long estimatedTime = System.nanoTime() - startTime;
-		double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
-		String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
+		double rate = 0.0;
+		if (estimatedTime > 0)
+		    rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
+		String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
+		    counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
+		    counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
+		    counterAllFlowPaths + " MyFlowPaths: " +
+		    counterMyFlowPaths + " in " +
+		    (double)estimatedTime / 1000000000 + " sec: " +
+		    rate + " paths/s";
 		log.debug(logMsg);
 	    }
 	};
@@ -1048,10 +913,10 @@
 		for (FlowPath flow : allFlows) {
 		    flow.setFlowEntryMatch(null);
 			
-			// start from desired flowId
-			//if (flow.flowId().value() < flowId.value()) {
-			//	continue;
-			//}
+		    // start from desired flowId
+		    if (flow.flowId().value() < flowId.value()) {
+			continue;
+		    }
 			
 			// Summarize by making null flow entry fields that are not relevant to report
 			for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
@@ -1121,8 +986,6 @@
      * @return the extracted Flow Path State.
      */
     private FlowPath extractFlowPath(IFlowPath flowObj) {
-	FlowPath flowPath = new FlowPath();
-
 	//
 	// Extract the Flow state
 	//
@@ -1143,6 +1006,7 @@
 	    return null;
 	}
 
+	FlowPath flowPath = new FlowPath();
 	flowPath.setFlowId(new FlowId(flowIdStr));
 	flowPath.setInstallerId(new CallerId(installerIdStr));
 	flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
@@ -1177,63 +1041,9 @@
 	//
 	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
 	for (IFlowEntry flowEntryObj : flowEntries) {
-	    FlowEntry flowEntry = new FlowEntry();
-	    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
+	    FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
+	    if (flowEntry == null)
 		continue;
-	    }
-	    flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
-	    flowEntry.setDpid(new Dpid(switchDpidStr));
-
-	    //
-	    // Extract the match conditions
-	    //
-	    FlowEntryMatch match = new FlowEntryMatch();
-	    Short matchInPort = flowEntryObj.getMatchInPort();
-	    if (matchInPort != null)
-		match.enableInPort(new Port(matchInPort));
-	    Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
-	    if (matchEthernetFrameType != null)
-		match.enableEthernetFrameType(matchEthernetFrameType);
-	    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
-	    if (matchSrcIPv4Net != null)
-		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
-	    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
-	    if (matchDstIPv4Net != null)
-		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
-	    String matchSrcMac = flowEntryObj.getMatchSrcMac();
-	    if (matchSrcMac != null)
-		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
-	    String matchDstMac = flowEntryObj.getMatchDstMac();
-	    if (matchDstMac != null)
-		match.enableDstMac(MACAddress.valueOf(matchDstMac));
-	    flowEntry.setFlowEntryMatch(match);
-
-	    //
-	    // Extract the actions
-	    //
-	    ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
-	    Short actionOutputPort = flowEntryObj.getActionOutput();
-	    if (actionOutputPort != null) {
-		FlowEntryAction action = new FlowEntryAction();
-		action.setActionOutput(new Port(actionOutputPort));
-		actions.add(action);
-	    }
-	    flowEntry.setFlowEntryActions(actions);
-	    flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
-	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
-	    //
-	    // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
-	    // and FlowEntryErrorState.
-	    //
 	    flowPath.dataPath().flowEntries().add(flowEntry);
 	}
 
@@ -1241,6 +1051,74 @@
     }
 
     /**
+     * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
+     *
+     * @param flowEntryObj the object to extract the Flow Entry State from.
+     * @return the extracted Flow Entry State.
+     */
+    private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
+	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
+	    return null;
+	}
+
+	FlowEntry flowEntry = new FlowEntry();
+	flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
+	flowEntry.setDpid(new Dpid(switchDpidStr));
+
+	//
+	// Extract the match conditions
+	//
+	FlowEntryMatch match = new FlowEntryMatch();
+	Short matchInPort = flowEntryObj.getMatchInPort();
+	if (matchInPort != null)
+	    match.enableInPort(new Port(matchInPort));
+	Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+	if (matchEthernetFrameType != null)
+	    match.enableEthernetFrameType(matchEthernetFrameType);
+	String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+	if (matchSrcIPv4Net != null)
+	    match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+	String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+	if (matchDstIPv4Net != null)
+	    match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+	String matchSrcMac = flowEntryObj.getMatchSrcMac();
+	if (matchSrcMac != null)
+	    match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+	String matchDstMac = flowEntryObj.getMatchDstMac();
+	if (matchDstMac != null)
+	    match.enableDstMac(MACAddress.valueOf(matchDstMac));
+	flowEntry.setFlowEntryMatch(match);
+
+	//
+	// Extract the actions
+	//
+	ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
+	Short actionOutputPort = flowEntryObj.getActionOutput();
+	if (actionOutputPort != null) {
+	    FlowEntryAction action = new FlowEntryAction();
+	    action.setActionOutput(new Port(actionOutputPort));
+	    actions.add(action);
+	}
+	flowEntry.setFlowEntryActions(actions);
+	flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
+	flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
+	//
+	// TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
+	// and FlowEntryErrorState.
+	//
+	return flowEntry;
+    }
+
+    /**
      * Add and maintain a shortest-path flow.
      *
      * NOTE: The Flow Path argument does NOT contain flow entries.
@@ -1309,78 +1187,6 @@
     }
 
     /**
-     * Create a Flow from port to port.
-     *
-     * TODO: We don't need it for now.
-     *
-     * @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.
-    }
-
-    /**
-     * Get all Flows matching a source and a destination port.
-     *
-     * TODO: Pankaj might be implementing it later.
-     *
-     * @param src_port the source port to match.
-     * @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.
-	return null;
-    }
-
-    /**
-     * Get all Flows going out from a port.
-     *
-     * TODO: We need it now: Pankaj
-     *
-     * @param port the port to match.
-     * @return the list of flows that are going out from the port.
-     */
-    @Override
-    public Iterable<FlowPath> getOutFlows(IPortObject port) {
-	// TODO: We need it now: Pankaj
-	return null;
-    }
-
-    /**
-     * Reconcile all flows on inactive switch port.
-     *
-     * @param portObject the port that has become inactive.
-     */
-    @Override
-    public void reconcileFlows(IPortObject portObject) {
-	Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
-	Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
-
-	//
-	// 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);
-	}
-
-	// Reconcile the affected flows
-	reconcileFlows(flowObjSet);
-    }
-
-    /**
      * Reconcile all flows in a set.
      *
      * @param flowObjSet the set of flows that need to be reconciliated.
@@ -1488,96 +1294,156 @@
     }
 
     /**
-     * Reconcile all flows between a source and a destination port.
+     * Install a Flow Entry on a switch.
      *
-     * TODO: We don't need it for now.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
+     * @param mySwitch the switch to install the Flow Entry into.
+     * @param flowObj the flow path object for the flow entry to install.
+     * @param flowEntryObj the flow entry object to install.
+     * @return true on success, otherwise false.
      */
-    @Override
-    public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
-	// TODO: We don't need it for now.
-    }
-
-    /**
-     * Compute the shortest path between a source and a destination ports.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
-     * @return the computed shortest path between the source and the
-     * 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).
-     */
-    @Override
-    public FlowPath computeFlowPath(IPortObject src_port,
-				    IPortObject dest_port) {
-	//
-	// Prepare the arguments
-	//
-	String dpidStr = src_port.getSwitch().getDPID();
-	Dpid srcDpid = new Dpid(dpidStr);
-	Port srcPort = new Port(src_port.getNumber());
-
-	dpidStr = dest_port.getSwitch().getDPID();
-	Dpid dstDpid = new Dpid(dpidStr);
-	Port dstPort = new Port(dest_port.getNumber());
-
-	SwitchPort src = new SwitchPort(srcDpid, srcPort);
-	SwitchPort dst = new SwitchPort(dstDpid, dstPort);
+    public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
+				    IFlowEntry flowEntryObj) {
+	FlowEntryId flowEntryId =
+	    new FlowEntryId(flowEntryObj.getFlowEntryId());
+	String userState = flowEntryObj.getUserState();
 
 	//
-	// Do the shortest path computation
+	// Create the Open Flow Flow Modification Entry to push
 	//
-	DataPath dataPath = topoRouteService.getShortestPath(src, dst);
-	if (dataPath == null)
-	    return null;
+	OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
+	    .getMessage(OFType.FLOW_MOD);
+	long cookie = flowEntryId.value();
 
-	//
-	// Set the incoming port matching and the outgoing port output
-	// actions for each flow entry.
-	//
-	for (FlowEntry flowEntry : dataPath.flowEntries()) {
-	    // Set the incoming port matching
-	    FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
-	    if (flowEntryMatch == null) {
-		flowEntryMatch = new FlowEntryMatch();
-		flowEntry.setFlowEntryMatch(flowEntryMatch);
-	    }
-	    flowEntryMatch.enableInPort(flowEntry.inPort());
-
-	    // Set the outgoing port output action
-	    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
-	    if (flowEntryActions == null) {
-		flowEntryActions = new ArrayList<FlowEntryAction>();
-		flowEntry.setFlowEntryActions(flowEntryActions);
-	    }
-	    FlowEntryAction flowEntryAction = new FlowEntryAction();
-	    flowEntryAction.setActionOutput(flowEntry.outPort());
-	    flowEntryActions.add(flowEntryAction);
+	short flowModCommand = OFFlowMod.OFPFC_ADD;
+	if (userState.equals("FE_USER_ADD")) {
+	    flowModCommand = OFFlowMod.OFPFC_ADD;
+	} else if (userState.equals("FE_USER_MODIFY")) {
+	    flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
+	} else if (userState.equals("FE_USER_DELETE")) {
+	    flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
+	} else {
+	    // Unknown user state. Ignore the entry
+	    log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
+		      flowEntryId.toString(), userState);
+	    return false;
 	}
 
 	//
-	// Prepare the return result
+	// Fetch the match conditions.
 	//
-	FlowPath flowPath = new FlowPath();
-	flowPath.setDataPath(dataPath);
+	// NOTE: The Flow matching conditions common for all Flow Entries are
+	// used ONLY if a Flow Entry does NOT have the corresponding matching
+	// condition set.
+	//
+	OFMatch match = new OFMatch();
+	match.setWildcards(OFMatch.OFPFW_ALL);
 
-	return flowPath;
-    }
+	// Match the Incoming Port
+	Short matchInPort = flowEntryObj.getMatchInPort();
+	if (matchInPort != null) {
+	    match.setInputPort(matchInPort);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
+	}
 
-    /**
-     * Get all Flow Entries of a Flow.
-     *
-     * @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();
+	// Match the Ethernet Frame Type
+	Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+	if (matchEthernetFrameType == null)
+	    matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
+	if (matchEthernetFrameType != null) {
+	    match.setDataLayerType(matchEthernetFrameType);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+	}
+
+	// Match the Source IPv4 Network prefix
+	String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+	if (matchSrcIPv4Net == null)
+	    matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
+	if (matchSrcIPv4Net != null) {
+	    match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
+	}
+
+	// Natch the Destination IPv4 Network prefix
+	String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+	if (matchDstIPv4Net == null)
+	    matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
+	if (matchDstIPv4Net != null) {
+	    match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
+	}
+
+	// Match the Source MAC address
+	String matchSrcMac = flowEntryObj.getMatchSrcMac();
+	if (matchSrcMac == null)
+	    matchSrcMac = flowObj.getMatchSrcMac();
+	if (matchSrcMac != null) {
+	    match.setDataLayerSource(matchSrcMac);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
+	}
+
+	// Match the Destination MAC address
+	String matchDstMac = flowEntryObj.getMatchDstMac();
+	if (matchDstMac == null)
+	    matchDstMac = flowObj.getMatchDstMac();
+	if (matchDstMac != null) {
+	    match.setDataLayerDestination(matchDstMac);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
+	}
+
+	//
+	// Fetch the actions
+	//
+	// TODO: For now we support only the "OUTPUT" actions.
+	//
+	List<OFAction> actions = new ArrayList<OFAction>();
+	Short actionOutputPort = flowEntryObj.getActionOutput();
+	if (actionOutputPort != null) {
+	    OFActionOutput action = new OFActionOutput();
+	    // XXX: The max length is hard-coded for now
+	    action.setMaxLength((short)0xffff);
+	    action.setPort(actionOutputPort);
+	    actions.add(action);
+	}
+
+	fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+	    .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+	    .setPriority(PRIORITY_DEFAULT)
+	    .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+	    .setCookie(cookie)
+	    .setCommand(flowModCommand)
+	    .setMatch(match)
+	    .setActions(actions)
+	    .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+	fm.setOutPort(OFPort.OFPP_NONE.getValue());
+	if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
+	    (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
+	    if (actionOutputPort != null)
+		fm.setOutPort(actionOutputPort);
+	}
+
+	//
+	// TODO: Set the following flag
+	// fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+	// See method ForwardingBase::pushRoute()
+	//
+
+	//
+	// Write the message to the switch
+	//
+	try {
+	    messageDamper.write(mySwitch, fm, null);
+	    mySwitch.flush();
+	    //
+	    // TODO: We should use the OpenFlow Barrier mechanism
+	    // to check for errors, and update the SwitchState
+	    // for a flow entry after the Barrier message is
+	    // is received.
+	    //
+	    flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
+	} catch (IOException e) {
+	    log.error("Failure writing flow mod from network map", e);
+	    return false;
+	}
+
+	return true;
     }
 
     /**
@@ -1588,7 +1454,6 @@
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
 				    FlowEntry flowEntry) {
 	//
@@ -1728,6 +1593,15 @@
 	try {
 	    messageDamper.write(mySwitch, fm, null);
 	    mySwitch.flush();
+	    //
+	    // TODO: We should use the OpenFlow Barrier mechanism
+	    // to check for errors, and update the SwitchState
+	    // for a flow entry after the Barrier message is
+	    // is received.
+	    //
+	    // TODO: The FlowEntry Object in Titan should be set
+	    // to FE_SWITCH_UPDATED.
+	    //
 	} catch (IOException e) {
 	    log.error("Failure writing flow mod from network map", e);
 	    return false;
@@ -1743,7 +1617,6 @@
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
 				   FlowEntry flowEntry) {
 	//
@@ -1764,7 +1637,6 @@
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean installRemoteFlowEntry(FlowPath flowPath,
 					  FlowEntry flowEntry) {
 	// TODO: We need it now: Jono
@@ -1780,7 +1652,6 @@
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean removeRemoteFlowEntry(FlowPath flowPath,
 					 FlowEntry flowEntry) {
 	//
diff --git a/web/ons-demo/RELEASE_NOTES.txt b/web/ons-demo/RELEASE_NOTES.txt
index 916a965..90af6d1 100644
--- a/web/ons-demo/RELEASE_NOTES.txt
+++ b/web/ons-demo/RELEASE_NOTES.txt
@@ -1,11 +1,20 @@
 ** April 4, 2013 **
+iperf display implemented
+- scaled to 50,000,000
+- update rate is every 2s
+- the display does not draw until receiving 2 buffers of data (this way if there is a stale buffer it doesn't get displayed)
+- duration is 10000 seconds. seems like there is no need for a button to restart?
+- displaying 10s data
+- if the data underruns (either because the server response is too slow or because the iperf data stops being updated) the display draws 0s
+- seeing the data stall a lot (timestamp and end-time remain the same through many fetches)
+
+** April 4, 2013 **
 Fix issues:
 	305 - "close x" now unselects flow. double click to delete a flow
 	323 - gui now recovers on timeout errors and polls again
 	324 - fixed problem with added flows not displaying
 	325 - fixed logic displaying flows in topology view
 
-
 ** March 28, 2013 **
 - add and delete flow implemented
 - to add flow
diff --git a/web/ons-demo/css/layout.default.css b/web/ons-demo/css/layout.default.css
index 018e728..5e1f1ce 100644
--- a/web/ons-demo/css/layout.default.css
+++ b/web/ons-demo/css/layout.default.css
@@ -76,6 +76,15 @@
 .iperf {
 	width: 100%;
 	-webkit-box-flex: 1.0;
+	position: relative;
+	display: -webkit-box;
+}
+
+.iperf-container {
+	position: absolute;
+	top: 0px;
+	height: 100%;
+	width: 100%;
 }
 
 #controllers {
diff --git a/web/ons-demo/css/skin.default.css b/web/ons-demo/css/skin.default.css
index 1ce4897..1d656b0 100644
--- a/web/ons-demo/css/skin.default.css
+++ b/web/ons-demo/css/skin.default.css
@@ -145,6 +145,12 @@
 	border-top: 1px solid #AAA;
 }
 
+path.iperfdata {
+	fill: none;
+	stroke-width: 2px;
+	stroke: rgba(255, 255, 255, .75);
+}
+
 #flowChooser {
 	pointer-events: none;
 	background-color: rgba(0, 0, 0, .25);
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index 695e4bb..d6fa983 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -96,7 +96,7 @@
 				return;
 			}
 			var pts = [];
-			if (!d.dataPath.flowEntries || !d.dataPath.flowEntries.length) {
+			if (!d.dataPath.flowEntries) {
 				// create a temporary vector to indicate the pending flow
 				var s1 = d3.select(document.getElementById(d.dataPath.srcPort.dpid.value));
 				var s2 = d3.select(document.getElementById(d.dataPath.dstPort.dpid.value));
@@ -128,7 +128,11 @@
 					}
 				});
 			}
-			return line(pts);
+			if (pts.length) {
+				return line(pts);
+			} else {
+				return "M0,0";
+			}
 		})
 		.attr('id', function (d) {
 			if (d) {
@@ -153,6 +157,16 @@
 		row.append('div').classed('dstDPID', true);
 		row.append('div').classed('iperf', true);
 
+		row.select('.iperf')
+			.append('div')
+			.attr('class', 'iperf-container')
+			.append('svg:svg')
+			.attr('viewBox', '0 0 1000 32')
+			.attr('preserveAspectRatio', 'none')
+			.append('svg:g')
+			.append('svg:path')
+			.attr('class', 'iperfdata');
+
 		row.on('mouseover', function (d) {
 			if (d) {
 				var path = document.getElementById(makeFlowKey(d));
@@ -164,14 +178,24 @@
 				var path = document.getElementById(makeFlowKey(d));
 				d3.select(path).classed('highlight', false);
 			}
-		})
+		});
 	}
 
 	function rowUpdate(d) {
 		var row = d3.select(this);
+		row.attr('id', function (d) {
+			if (d) {
+				return makeSelectedFlowKey(d);
+			}
+		});
+
+		if (!d || !hasIPerf(d)) {
+			row.select('.iperfdata')
+				.attr('d', 'M0,0');
+		}
+
 		row.select('.deleteFlow').on('click', function () {
-			selectedFlows[selectedFlows.indexOf(d)] = null;
-			updateSelectedFlows();
+			deselectFlow(d);
 		});
 		row.on('dblclick', function () {
 			if (d) {
@@ -232,6 +256,73 @@
 	flows.exit().remove();
 }
 
+// TODO: cancel the interval when the flow is desel
+function startIPerfForFlow(flow) {
+	var duration = 10000; // seconds
+	var interval = 100; // ms. this is defined by the server
+	var updateRate = 2000; // ms
+
+	function makePoints() {
+		var pts = [];
+		var i;
+		for (i=0; i < 100; ++i) {
+			var sample = flow.iperfData.samples[i];
+			var height = 32 * sample/50000000;
+			if (height > 32)
+				height = 32;
+			pts.push({
+				x: i * 1000/99,
+				y: 32 - height
+			})
+		}
+		return pts;
+	}
+
+	if (flow.flowId) {
+		console.log('starting iperf for: ' + flow.flowId.value);
+		startIPerf(flow, duration, updateRate/interval);
+		flow.iperfDisplayInterval = setInterval(function () {
+			if (flow.iperfData) {
+				while (flow.iperfData.samples.length < 100) {
+					flow.iperfData.samples.push(0);
+				}
+				var iperfPath = d3.select(document.getElementById(makeSelectedFlowKey(flow))).select('path');
+				iperfPath.attr('d', line(makePoints()));
+				flow.iperfData.samples.shift();
+			}
+
+
+		}, interval);
+		flow.iperfFetchInterval = setInterval(function () {
+			getIPerfData(flow, function (data) {
+				try {
+					if (!flow.iperfData) {
+						flow.iperfData = {
+							samples: []
+						};
+						var i;
+						for (i = 0; i < 100; ++i) {
+							flow.iperfData.samples.push(0);
+						}
+					}
+
+					var iperfData = JSON.parse(data);
+					// if the data is fresh
+					if (flow.iperfData.timestamp && iperfData.timestamp != flow.iperfData.timestamp) {
+						iperfData.samples.forEach(function (s) {
+							flow.iperfData.samples.push(s);
+						});
+					}
+					flow.iperfData.timestamp = iperfData.timestamp;
+				} catch (e) {
+					console.log('bad iperf data: ' + data);
+				}
+//				console.log(data);
+			});
+		}, updateRate/2); // over sample to avoid gaps
+	}
+}
+
 function updateSelectedFlows() {
 	// make sure that all of the selected flows are either
 	// 1) valid (meaning they are in the latest list of flows)
@@ -249,13 +340,22 @@
 				if (liveFlow) {
 					newSelectedFlows.push(liveFlow);
 					liveFlow.deletePending = flow.deletePending;
+					liveFlow.iperfFetchInterval = flow.iperfFetchInterval;
+					liveFlow.iperfDisplayInterval = flow.iperfDisplayInterval;
 				} else if (flow.createPending) {
 					newSelectedFlows.push(flow);
+				} else if (hasIPerf(flow)) {
+					clearIPerf(flow);
 				}
 			}
 		});
 		selectedFlows = newSelectedFlows;
 	}
+	selectedFlows.forEach(function (flow) {
+		if (!hasIPerf(flow)) {
+			startIPerfForFlow(flow);
+		}
+	});
 	while (selectedFlows.length < 3) {
 		selectedFlows.push(null);
 	}
@@ -280,6 +380,19 @@
 	}
 }
 
+function hasIPerf(flow) {
+	return flow && flow.iperfFetchInterval;
+}
+
+function clearIPerf(flow) {
+	console.log('clearing iperf interval for: ' + flow.flowId.value);
+	clearInterval(flow.iperfFetchInterval);
+	delete flow.iperfFetchInterval;
+	clearInterval(flow.iperfDisplayInterval);
+	delete flow.iperfDisplayInterval;
+	delete flow.iperfData;
+}
+
 function deselectFlow(flow, ifCreatePending) {
 	var flowKey = makeFlowKey(flow);
 	var newSelectedFlows = [];
@@ -288,6 +401,10 @@
 				flowKey !== makeFlowKey(flow) ||
 				flowKey === makeFlowKey(flow) && ifCreatePending && !flow.createPending ) {
 			newSelectedFlows.push(flow);
+		} else {
+			if (hasIPerf(flow)) {
+				clearIPerf(flow);
+			}
 		}
 	});
 	selectedFlows = newSelectedFlows;
@@ -474,6 +591,10 @@
 	return flow.dataPath.srcPort.dpid.value + '=>' + flow.dataPath.dstPort.dpid.value;
 }
 
+function makeSelectedFlowKey(flow) {
+	return 'S' + makeFlowKey(flow);
+}
+
 function createLinkMap(links) {
 	var linkMap = {};
 	links.forEach(function (link) {
@@ -1066,6 +1187,7 @@
 
 }
 
+var modelString;
 function sync(svg) {
 	var d = Date.now();
 	updateModel(function (newModel) {
@@ -1073,9 +1195,11 @@
 
 		if (newModel) {
 			var modelChanged = false;
-			if (!model || JSON.stringify(model) != JSON.stringify(newModel)) {
+			var newModelString = JSON.stringify(newModel);
+			if (!modelString || newModelString != modelString) {
 				modelChanged = true;
 				model = newModel;
+				modelString = newModelString;
 			} else {
 	//			console.log('no change');
 			}
diff --git a/web/ons-demo/js/controller.js b/web/ons-demo/js/controller.js
index fd3f6ae..c7c80ec 100644
--- a/web/ons-demo/js/controller.js
+++ b/web/ons-demo/js/controller.js
@@ -1,11 +1,14 @@
 /*global d3*/
 
-function callURL(url) {
+function callURL(url, cb) {
 	d3.text(url, function (error, result) {
 		if (error) {
 			alert(url + ' : ' + error.status);
 		} else {
-			console.log(result);
+			if (cb) {
+				cb(result);
+			}
+//			console.log(result);
 		}
 	});
 }
@@ -37,6 +40,16 @@
 	delFlowCmd: function (flow) {
 		var url = '/proxy/gui/delflow/' + flow.flowId.value;
 		callURL(url);
+	},
+	startIPerfCmd: function (flow, duration, numSamples) {
+		var flowId = parseInt(flow.flowId.value, 16);
+		var url = '/proxy/gui/iperf/start/' + [flowId, duration, numSamples].join('/');
+		callURL(url)
+	},
+	getIPerfDataCmd: function (flow, cb) {
+		var flowId = parseInt(flow.flowId.value, 16);
+		var url = '/proxy/gui/iperf/rate/' + flowId;
+		callURL(url, cb);
 	}
 };
 
@@ -70,4 +83,12 @@
 
 function deleteFlow(flow) {
 	controllerFunctions.delFlowCmd(flow);
+}
+
+function startIPerf(flow, duration, numSamples) {
+	controllerFunctions.startIPerfCmd(flow, duration, numSamples);
+}
+
+function getIPerfData(flow, cb) {
+	controllerFunctions.getIPerfDataCmd(flow, cb);
 }
\ No newline at end of file
diff --git a/web/topology_rest.py b/web/topology_rest.py
index ce7b84e..bc52992 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -19,18 +19,18 @@
 
 ## Uncomment the desired block based on your testbed environment
 # Settings for running on production
-#controllers=["onosgui1", "onosgui2", "onosgui3", "onosgui4", "onosgui5", "onosgui6", "onosgui7", "onosgui8"]
-#core_switches=["00:00:00:00:ba:5e:ba:11", "00:00:00:00:00:00:ba:12", "00:00:20:4e:7f:51:8a:35", "00:00:00:00:ba:5e:ba:13", "00:00:00:08:a2:08:f9:01", "00:00:00:16:97:08:9a:46"]
-#ONOS_GUI3_HOST="http://gui3.onlab.us:8080"
-#ONOS_GUI3_CONTROL_HOST="http://gui3.onlab.us:8081"
+controllers=["onosgui1", "onosgui2", "onosgui3", "onosgui4", "onosgui5", "onosgui6", "onosgui7", "onosgui8"]
+core_switches=["00:00:00:00:ba:5e:ba:11", "00:00:00:00:00:00:ba:12", "00:00:20:4e:7f:51:8a:35", "00:00:00:00:ba:5e:ba:13", "00:00:00:08:a2:08:f9:01", "00:00:00:16:97:08:9a:46"]
+ONOS_GUI3_HOST="http://gui3.onlab.us:8080"
+ONOS_GUI3_CONTROL_HOST="http://gui3.onlab.us:8081"
 
 # Settings for running on dev testbed. Replace dev
 #controllers=["onosdevb1", "onosdevb2", "onosdevb3", "onosdevb4"]
-controllers=["onosdevt1", "onosdevt2", "onosdevt3", "onosdevt4", "onosdevt5", "onosdevt6", "onosdevt7", "onosdevt8"]
-core_switches=["00:00:00:00:00:00:01:01", "00:00:00:00:00:00:01:02", "00:00:00:00:00:00:01:03", "00:00:00:00:00:00:01:04", "00:00:00:00:00:00:01:05", "00:00:00:00:00:00:01:06"]
+#controllers=["onosdevt1", "onosdevt2", "onosdevt3", "onosdevt4", "onosdevt5", "onosdevt6", "onosdevt7", "onosdevt8"]
+#core_switches=["00:00:00:00:00:00:01:01", "00:00:00:00:00:00:01:02", "00:00:00:00:00:00:01:03", "00:00:00:00:00:00:01:04", "00:00:00:00:00:00:01:05", "00:00:00:00:00:00:01:06"]
 
-ONOS_GUI3_HOST="http://devt-gui.onlab.us:8080"
-ONOS_GUI3_CONTROL_HOST="http://devt-gui.onlab.us:8080"
+#ONOS_GUI3_HOST="http://devt-gui.onlab.us:8080"
+#ONOS_GUI3_CONTROL_HOST="http://devt-gui.onlab.us:8080"
 
 LB=True #; True or False
 ONOS_DEFAULT_HOST="localhost" ;# Has to set if LB=False
@@ -153,6 +153,33 @@
   resp = Response(result, status=200, mimetype='application/json')
   return resp
 
+@app.route("/proxy/gui/iperf/start/<flow_id>/<duration>/<samples>")
+def proxy_iperf_start(flow_id,duration,samples):
+  try:
+    command = "curl -s %s/gui/iperf/start/%s/%s/%s" % (ONOS_GUI3_CONTROL_HOST, flow_id, duration, samples)
+    print command
+    result = os.popen(command).read()
+  except:
+    print "REST IF has issue"
+    exit
+
+  resp = Response(result, status=200, mimetype='application/json')
+  return resp
+
+@app.route("/proxy/gui/iperf/rate/<flow_id>")
+def proxy_iperf_rate(flow_id):
+  try:
+    command = "curl -s %s/gui/iperf/rate/%s" % (ONOS_GUI3_CONTROL_HOST, flow_id)
+    print command
+    result = os.popen(command).read()
+  except:
+    print "REST IF has issue"
+    exit
+
+  resp = Response(result, status=200, mimetype='application/json')
+  return resp
+
+
 ###### ONOS RESET API ##############################
 ## Worker Func ###
 def get_json(url):
@@ -185,6 +212,7 @@
   return "http://" + host + ":8080"
 
 ## Switch ##
+=======
 @app.route("/wm/core/topology/switches/all/json")
 def switches():
   if request.args.get('proxy') == None:
@@ -226,7 +254,6 @@
   resp = Response(result, status=code, mimetype='application/json')
   return resp
 
-
 @app.route("/wm/registry/controllers/json")
 def registry_controllers():
   if request.args.get('proxy') == None: