Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index ab60e68..9a5129f 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -116,8 +116,8 @@
 		}
 		Map<Long, IOFSwitch> mySwitches =
 		    floodlightProvider.getSwitches();
-		Map<Long, IFlowEntry> myFlowEntries =
-		    new TreeMap<Long, IFlowEntry>();
+		LinkedList<IFlowEntry> addFlowEntries =
+		    new LinkedList<IFlowEntry>();
 		LinkedList<IFlowEntry> deleteFlowEntries =
 		    new LinkedList<IFlowEntry>();
 
@@ -126,6 +126,7 @@
 		// Fetch all Flow Entries and select only my Flow Entries
 		// that need to be updated into the switches.
 		//
+		boolean processed_measurement_flow = false;
 		Iterable<IFlowEntry> allFlowEntries =
 		    conn.utils().getAllFlowEntries(conn);
 		for (IFlowEntry flowEntryObj : allFlowEntries) {
@@ -151,29 +152,26 @@
 		    if (mySwitch == null)
 			continue;	// Ignore the entry: not my switch
 
-		    myFlowEntries.put(flowEntryId.value(), flowEntryObj);
+		    IFlowPath flowObj =
+			conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
+		    if (flowObj == null)
+			continue;		// Should NOT happen
+		    if (flowObj.getFlowId() == null)
+			continue;		// Invalid entry
+
+		    //
+		    // NOTE: For now we process the DELETE before the ADD
+		    // to cover the more common scenario.
+		    // TODO: This is error prone and needs to be fixed!
+		    //
 		    if (userState.equals("FE_USER_DELETE")) {
 			// An entry that needs to be deleted.
 			deleteFlowEntries.add(flowEntryObj);
+			installFlowEntry(mySwitch, flowObj, flowEntryObj);
+		    } else {
+			addFlowEntries.add(flowEntryObj);
 		    }
-		}
-
-		log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
-			  myFlowEntries.size());
-
-		//
-		// Process my Flow Entries in the Flow Entry ID order
-		//
-		boolean processed_measurement_flow = false;
-		for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
 		    counterMyNotUpdatedFlowEntries++;
-		    IFlowEntry flowEntryObj = entry.getValue();
-		    IFlowPath flowObj =
-			conn.utils().getFlowPathByFlowEntry(conn,
-							    flowEntryObj);
-		    if (flowObj == null)
-			continue;		// Should NOT happen
-
 		    // Code for measurement purpose
 		    // TODO: Commented-out for now
 		    /*
@@ -183,6 +181,24 @@
 			}
 		    }
 		    */
+		}
+
+		/*
+		log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
+		    addFlowEntries.size() + deleteFlowEntries.size());
+		*/
+
+		//
+		// Process the Flow Entries that need to be added
+		//
+		for (IFlowEntry flowEntryObj : addFlowEntries) {
+		    IFlowPath flowObj =
+			conn.utils().getFlowPathByFlowEntry(conn,
+							    flowEntryObj);
+		    if (flowObj == null)
+			continue;		// Should NOT happen
+		    if (flowObj.getFlowId() == null)
+			continue;		// Invalid entry
 
 		    Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
 		    IOFSwitch mySwitch = mySwitches.get(dpid.value());
@@ -191,8 +207,10 @@
 		    installFlowEntry(mySwitch, flowObj, flowEntryObj);
 		}
 
+		/*
 		log.debug("MEASUREMENT: Found {} Flow Entries to delete",
 			  deleteFlowEntries.size());
+		*/
 
 		//
 		// Delete all entries marked for deletion from the
@@ -221,7 +239,6 @@
 		//
 		topoRouteService.prepareShortestPathTopo();
 		Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
-		HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
 		for (IFlowPath flowPathObj : allFlowPaths) {
 		    counterAllFlowPaths++;
 		    if (flowPathObj == null)
@@ -294,14 +311,10 @@
 
 		    log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
 			      flowId.toString());
-		    flowObjSet.add(flowPathObj);
+		    reconcileFlow(flowPathObj, dataPath);
 		}
-		log.debug("MEASUREMENT: Found {} Flows to reconcile",
-			  flowObjSet.size());
-		reconcileFlows(flowObjSet);
 		topoRouteService.dropShortestPathTopo();
 
-
 		conn.endTx(Transaction.COMMIT);
 
 		if (processed_measurement_flow) {
@@ -515,7 +528,7 @@
 	// flowPath.dataPath().flowEntries()
 	//
 	for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
-	    if (addFlowEntry(flowObj, flowEntry) != true) {
+	    if (addFlowEntry(flowObj, flowEntry) == null) {
 		conn.endTx(Transaction.ROLLBACK);
 		return false;
 	    }
@@ -535,9 +548,9 @@
      *
      * @param flowObj the corresponding Flow Path object for the Flow Entry.
      * @param flowEntry the Flow Entry to install.
-     * @return true on success, otherwise false.
+     * @return the added Flow Entry object on success, otherwise null.
      */
-    private boolean addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
+    private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
 	// Flow edges
 	//   HeadFE (TODO)
 
@@ -566,12 +579,12 @@
 	} catch (Exception e) {
 	    log.error(":addFlow FlowEntryId:{} failed",
 		      flowEntry.flowEntryId().toString());
-	    return false;
+	    return null;
 	}
 	if (flowEntryObj == null) {
 	    log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
 		      flowEntry.flowEntryId().toString());
-	    return false;
+	    return null;
 	}
 
 	//
@@ -656,7 +669,7 @@
 	    flowEntryObj.setFlow(flowObj);
 	}
 
-	return true;
+	return flowEntryObj;
     }
 
     /**
@@ -1261,6 +1274,118 @@
     }
 
     /**
+     * Reconcile a flow.
+     *
+     * @param flowObj the flow that needs to be reconciliated.
+     * @param newDataPath the new data path to use.
+     * @return true on success, otherwise false.
+     */
+    public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
+	Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
+
+	//
+	// Set the incoming port matching and the outgoing port output
+	// actions for each flow entry.
+	//
+	for (FlowEntry flowEntry : newDataPath.flowEntries()) {
+	    // Set the incoming port matching
+	    FlowEntryMatch 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);
+	}
+
+	//
+	// Remove the old Flow Entries, and add the new Flow Entries
+	//
+
+	//
+	// Remove the Flow Entries from the Network MAP
+	//
+	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
+	LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
+	for (IFlowEntry flowEntryObj : flowEntries) {
+	    String dpidStr = flowEntryObj.getSwitchDpid();
+	    if (dpidStr == null)
+		continue;
+	    Dpid dpid = new Dpid(dpidStr);
+	    IOFSwitch mySwitch = mySwitches.get(dpid.value());
+
+	    flowEntryObj.setUserState("FE_USER_DELETE");
+	    if (mySwitch == null) {
+		//
+		// Not my switch. Mark it for deletion in the Network MAP
+		//
+		flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
+		continue;
+	    }
+
+	    deleteFlowEntries.add(flowEntryObj);
+
+	    //
+	    // Delete the flow entry from the switch
+	    //
+	    // flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
+	    installFlowEntry(mySwitch, flowObj, flowEntryObj);
+	    // flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
+	}
+	for (IFlowEntry flowEntryObj : deleteFlowEntries) {
+	    flowObj.removeFlowEntry(flowEntryObj);
+	    conn.utils().removeFlowEntry(conn, flowEntryObj);
+	}
+
+	//
+	// Install the new shortest path into the Network MAP and the switches.
+	//
+	for (FlowEntry flowEntry : newDataPath.flowEntries()) {
+	    flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
+	    IFlowEntry flowEntryObj = addFlowEntry(flowObj, flowEntry);
+	    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(),
+			      newDataPath.srcPort(),
+			      newDataPath.dstPort()
+			  });
+		continue;
+	    }
+
+	    IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
+	    if (mySwitch == null) {
+		// Not my switch: just add to the Network MAP
+		continue;
+	    }
+
+	    // Install the Flow Entry into the switch
+	    if (installFlowEntry(mySwitch, flowObj, flowEntryObj)) {
+		flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
+	    }
+	}
+
+	//
+	// Set the Data Path Summary
+	//
+	String dataPathSummaryStr = newDataPath.dataPathSummary();
+	flowObj.setDataPathSummary(dataPathSummaryStr);
+
+	return true;
+    }
+
+    /**
      * Reconcile all flows in a set.
      *
      * @param flowObjSet the set of flows that need to be reconciliated.
@@ -1268,103 +1393,7 @@
     public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
 	if (! flowObjSet.iterator().hasNext())
 	    return;
-
-	//
-	// Remove the old Flow Entries, and add the new Flow Entries
-	//
-
-	Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
-	LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
-	for (IFlowPath flowObj : flowObjSet) {
-	    FlowPath flowPath = extractFlowPath(flowObj);
-	    if (flowPath == null)
-		continue;
-	    flowPaths.add(flowPath);
-
-	    //
-	    // Remove the Flow Entries from the Network MAP
-	    //
-	    Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
-	    LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
-	    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
-		*/
-		deleteFlowEntries.add(flowEntryObj);
-	    }
-	    for (IFlowEntry flowEntryObj : deleteFlowEntries) {
-		flowObj.removeFlowEntry(flowEntryObj);
-		conn.utils().removeFlowEntry(conn, flowEntryObj);
-	    }
-	}
-
-	for (FlowPath flowPath : flowPaths) {
-	    //
-	    // 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(flowPath, flowEntry);
-		} else {
-		    installFlowEntry(mySwitch, flowPath, 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(addedFlowPath, 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, addedFlowPath, flowEntry)) {
-		    flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
-		}
-	    }
-	}
+	// TODO: Not implemented/used yet.
     }
 
     /**
@@ -1377,9 +1406,13 @@
      */
     public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
 				    IFlowEntry flowEntryObj) {
-	FlowEntryId flowEntryId =
-	    new FlowEntryId(flowEntryObj.getFlowEntryId());
+	String flowEntryIdStr = flowEntryObj.getFlowEntryId();
+	if (flowEntryIdStr == null)
+	    return false;
+	FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
 	String userState = flowEntryObj.getUserState();
+	if (userState == null)
+	    return false;
 
 	//
 	// Create the Open Flow Flow Modification Entry to push
@@ -1502,6 +1535,13 @@
 	//
 	// Write the message to the switch
 	//
+	log.debug("MEASUREMENT: Installing flow entry " + userState +
+		  " into switch DPID: " +
+		  mySwitch.getStringId() +
+		  " flowEntryId: " + flowEntryId.toString() +
+		  " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
+		  " inPort: " + matchInPort + " outPort: " + actionOutputPort
+		  );
 	try {
 	    messageDamper.write(mySwitch, fm, null);
 	    mySwitch.flush();