* Updated the implementation of method FlowManager.pushModifiedFlowEntries()
so it can handle the deletion of Flow Entries.
* Added new methods FlowManager.deleteFlowEntry() and
FlowDatabaseOperation.deleteFlowEntry()
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
index d06c62c..926788f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -326,6 +326,44 @@
}
/**
+ * Delete a flow entry from the Network MAP.
+ *
+ * @param dbHandler the Graph Database handler to use.
+ * @param flowObj the corresponding Flow Path object for the Flow Entry.
+ * @param flowEntry the Flow Entry to delete.
+ * @return true on success, otherwise false.
+ */
+ static boolean deleteFlowEntry(GraphDBOperation dbHandler,
+ IFlowPath flowObj,
+ FlowEntry flowEntry) {
+ IFlowEntry flowEntryObj = null;
+ try {
+ flowEntryObj = dbHandler.searchFlowEntry(flowEntry.flowEntryId());
+ } catch (Exception e) {
+ log.error(":deleteFlowEntry FlowEntryId:{} failed",
+ flowEntry.flowEntryId().toString());
+ return false;
+ }
+ //
+ // TODO: Don't print an error for now, because multiple controller
+ // instances might be deleting the same flow entry.
+ //
+ /*
+ if (flowEntryObj == null) {
+ log.error(":deleteFlowEntry FlowEntryId:{} failed: FlowEntry object not found",
+ flowEntry.flowEntryId().toString());
+ return false;
+ }
+ */
+ if (flowEntryObj == null)
+ return true;
+
+ flowObj.removeFlowEntry(flowEntryObj);
+ dbHandler.removeFlowEntry(flowEntryObj);
+ return true;
+ }
+
+ /**
* Delete all previously added flows.
*
* @param dbHandler the Graph Database handler to use.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
index 4465835..1b4dc4d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -551,6 +551,18 @@
}
/**
+ * Delete a flow entry from the Network MAP.
+ *
+ * @param flowObj the corresponding Flow Path object for the Flow Entry.
+ * @param flowEntry the Flow Entry to delete.
+ * @return true on success, otherwise false.
+ */
+ private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
+ return FlowDatabaseOperation.deleteFlowEntry(dbHandler, flowObj,
+ flowEntry);
+ }
+
+ /**
* Delete all previously added flows.
*
* @return true on success, otherwise false.
@@ -840,7 +852,6 @@
* Flow Entries.
*/
public void pushModifiedFlowEntries(Collection<FlowPath> modifiedFlowPaths) {
-
// TODO: For now, the pushing of Flow Entries is disabled
if (true)
return;
@@ -848,57 +859,83 @@
Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
for (FlowPath flowPath : modifiedFlowPaths) {
+ //
+ // Find the Flow Path in the Network MAP.
+ // NOTE: The Flow Path might not be found if the Flow was just
+ // removed by some other controller instance.
+ //
IFlowPath flowObj = dbHandler.searchFlowPath(flowPath.flowId());
- if (flowObj == null) {
- String logMsg = "Cannot find Network MAP entry for Flow Path " +
- flowPath.flowId();
- log.error(logMsg);
- continue;
- }
+ boolean isFlowEntryDeleted = false;
for (FlowEntry flowEntry : flowPath.flowEntries()) {
+ System.out.println("PAVPAV: P40: Updating Flow Entry: " + flowEntry.toString());
+
if (flowEntry.flowEntrySwitchState() !=
FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
continue; // No need to update the entry
}
+ if (flowEntry.flowEntryUserState() ==
+ FlowEntryUserState.FE_USER_DELETE) {
+ isFlowEntryDeleted = true;
+ }
+ //
+ // Install the Flow Entries into my switches
+ //
IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
- if (mySwitch == null)
- continue; // Ignore the entry: not my switch
+ if (mySwitch != null) {
+ //
+ // Assign the FlowEntry ID if needed
+ //
+ if (! flowEntry.isValidFlowEntryId()) {
+ long id = getNextFlowEntryId();
+ flowEntry.setFlowEntryId(new FlowEntryId(id));
+ }
- //
- // Assign the FlowEntry ID if needed
- //
- if (! flowEntry.isValidFlowEntryId()) {
- long id = getNextFlowEntryId();
- flowEntry.setFlowEntryId(new FlowEntryId(id));
+ //
+ // Install the Flow Entry into the switch
+ //
+ if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
+ String logMsg = "Cannot install Flow Entry " +
+ flowEntry.flowEntryId() +
+ " from Flow Path " + flowPath.flowId() +
+ " on switch " + flowEntry.dpid();
+ log.error(logMsg);
+ continue;
+ }
+
+ //
+ // NOTE: Here we assume that the switch has been
+ // successfully updated.
+ //
+ flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
}
//
- // Install the Flow Entry into the switch
+ // TODO: For now Flow Entries are removed from the Datagrid
+ // and from the Network Map by all instances, even if this
+ // Flow Entry is not for our switches.
//
- if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
- String logMsg = "Cannot install Flow Entry " +
- flowEntry.flowEntryId() +
- " from Flow Path " + flowPath.flowId() +
- " on switch " + flowEntry.dpid();
- log.error(logMsg);
- continue;
- }
+ // This is needed to handle the case a switch going down:
+ // it has no Master controller instance, hence no
+ // controller instance will cleanup its flow entries.
+ // This is sub-optimal: we need to elect a controller
+ // instance to handle the cleanup of such orphaned flow
+ // entries.
+ //
//
- // NOTE: Here we assume that the switch has been successfully
- // updated.
- //
- flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
- //
// Write the Flow Entry to the Datagrid
//
switch (flowEntry.flowEntryUserState()) {
case FE_USER_ADD:
+ if (mySwitch == null)
+ break; // Install only flow entries for my switches
datagridService.notificationSendFlowEntryAdded(flowEntry);
break;
case FE_USER_MODIFY:
+ if (mySwitch == null)
+ break; // Install only flow entries for my switches
datagridService.notificationSendFlowEntryUpdated(flowEntry);
break;
case FE_USER_DELETE:
@@ -909,15 +946,41 @@
//
// Write the Flow Entry to the Network Map
//
- try {
- if (addFlowEntry(flowObj, flowEntry) == null) {
- String logMsg = "Cannot write to Network MAP Flow Entry " +
- flowEntry.flowEntryId() +
- " from Flow Path " + flowPath.flowId() +
- " on switch " + flowEntry.dpid();
- log.error(logMsg);
+ if (mySwitch == null) {
+ if (flowEntry.flowEntryUserState() !=
+ FlowEntryUserState.FE_USER_DELETE) {
continue;
}
+ if (! flowEntry.isValidFlowEntryId())
+ continue;
+ }
+ if (flowObj == null) {
+ String logMsg = "Cannot find Network MAP entry for Flow Path " + flowPath.flowId();
+ continue;
+ }
+ try {
+ switch (flowEntry.flowEntryUserState()) {
+ case FE_USER_ADD:
+ // FALLTHROUGH
+ case FE_USER_MODIFY:
+ if (addFlowEntry(flowObj, flowEntry) == null) {
+ String logMsg = "Cannot write to Network MAP Flow Entry " +
+ flowEntry.flowEntryId() +
+ " from Flow Path " + flowPath.flowId() +
+ " on switch " + flowEntry.dpid();
+ log.error(logMsg);
+ }
+ break;
+ case FE_USER_DELETE:
+ if (deleteFlowEntry(flowObj, flowEntry) == false) {
+ String logMsg = "Cannot remove from Network MAP Flow Entry " +
+ flowEntry.flowEntryId() +
+ " from Flow Path " + flowPath.flowId() +
+ " on switch " + flowEntry.dpid();
+ log.error(logMsg);
+ }
+ break;
+ }
} catch (Exception e) {
String logMsg = "Exception writing Flow Entry to Network MAP";
log.debug(logMsg);
@@ -925,6 +988,26 @@
continue;
}
}
+
+ //
+ // Remove Flow Entries that were deleted
+ //
+ // NOTE: We create a new ArrayList, and add only the Flow Entries
+ // that are NOT FE_USER_DELETE.
+ // This is sub-optimal: if it adds notable processing cost,
+ // the Flow Entries container should be changed to LinkedList
+ // or some other container that has O(1) cost of removing an entry.
+ //
+ if (isFlowEntryDeleted) {
+ ArrayList<FlowEntry> newFlowEntries = new ArrayList<FlowEntry>();
+ for (FlowEntry flowEntry : flowPath.flowEntries()) {
+ if (flowEntry.flowEntryUserState() !=
+ FlowEntryUserState.FE_USER_DELETE) {
+ newFlowEntries.add(flowEntry);
+ }
+ }
+ flowPath.dataPath().setFlowEntries(newFlowEntries);
+ }
}
dbHandler.commit();