* Refactor/cleanup the processing of events inside the FlowEventHandler.
* Refactor/cleanup the pushing of the modified Flow Entries inside
the FlowManager.
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 98f9cce..415e281 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -718,6 +718,15 @@
}
/**
+ * Get the collection of my switches.
+ *
+ * @return the collection of my switches.
+ */
+ public Map<Long, IOFSwitch> getMySwitches() {
+ return floodlightProvider.getSwitches();
+ }
+
+ /**
* Get the network topology.
*
* @return the network topology.
@@ -855,16 +864,16 @@
}
/**
- * Push the modified Flow Entries of a collection of Flow Paths.
- * Only the Flow Entries to switches controlled by this instance
- * are pushed.
+ * Push modified Flow Entries to switches.
*
- * NOTE: Currently, we write to both the Network MAP and the switches.
+ * NOTE: Only the Flow Entries to switches controlled by this instance
+ * are pushed.
*
* @param modifiedFlowPaths the collection of Flow Paths with the modified
* Flow Entries.
*/
- public void pushModifiedFlowEntries(Collection<FlowPath> modifiedFlowPaths) {
+ public void pushModifiedFlowEntriesToSwitches(
+ Collection<FlowPath> modifiedFlowPaths) {
// TODO: For now, the pushing of Flow Entries is disabled
if (true)
return;
@@ -872,17 +881,9 @@
if (modifiedFlowPaths.isEmpty())
return;
- Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
+ Map<Long, IOFSwitch> mySwitches = getMySwitches();
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 = dbHandlerInner.searchFlowPath(flowPath.flowId());
-
- boolean isFlowEntryDeleted = false;
for (FlowEntry flowEntry : flowPath.flowEntries()) {
log.debug("Updating Flow Entry: {}", flowEntry.toString());
@@ -890,91 +891,160 @@
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) {
- //
- // 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);
- }
+ if (mySwitch == null)
+ continue;
//
- // 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.
+ // Install the Flow Entry into the switch
//
- // 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.
- //
- if (mySwitch == null) {
- if (flowEntry.flowEntryUserState() !=
- FlowEntryUserState.FE_USER_DELETE) {
- continue;
- }
- if (! flowEntry.isValidFlowEntryId())
- continue;
- }
-
- //
- // 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:
- datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
- break;
- }
-
- //
- // Write the Flow Entry to the Network Map
- //
- if (flowObj == null) {
- String logMsg = "Cannot find Network MAP entry for Flow Path " + flowPath.flowId();
+ 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);
+ }
+ }
+ }
+
+ /**
+ * Push modified Flow Entries to the datagrid.
+ *
+ * @param modifiedFlowEntries the collection of modified Flow Entries.
+ */
+ public void pushModifiedFlowEntriesToDatagrid(
+ Collection<FlowEntry> modifiedFlowEntries) {
+ // TODO: For now, the pushing of Flow Entries is disabled
+ if (true)
+ return;
+
+ if (modifiedFlowEntries.isEmpty())
+ return;
+
+ Map<Long, IOFSwitch> mySwitches = getMySwitches();
+
+ for (FlowEntry flowEntry : modifiedFlowEntries) {
+ IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
+
+ //
+ // TODO: For now Flow Entries are removed by all instances,
+ // even if this Flow Entry is not for our switches.
+ //
+ // 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.
+ //
+ if (mySwitch == null) {
+ if (flowEntry.flowEntryUserState() !=
+ FlowEntryUserState.FE_USER_DELETE) {
+ continue;
+ }
+ if (! flowEntry.isValidFlowEntryId())
+ continue;
+ }
+
+ //
+ // 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:
+ datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Push Flow Entries to the Network MAP.
+ *
+ * @param modifiedFlowEntries the collection of Flow Entries to push.
+ */
+ public void pushModifiedFlowEntriesToDatabase(
+ Collection<FlowEntry> modifiedFlowEntries) {
+ // TODO: For now, the pushing of Flow Entries is disabled
+ if (true)
+ return;
+
+ if (modifiedFlowEntries.isEmpty())
+ return;
+
+ Map<Long, IOFSwitch> mySwitches = getMySwitches();
+
+ for (FlowEntry flowEntry : modifiedFlowEntries) {
+ if (! flowEntry.isValidFlowId()) {
+ // Shouldn't happen
+ log.error("Cannot push Flow Entry to database: invalid Flow ID: {}", flowEntry.toString());
+ continue;
+ }
+
+ IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
+
+ //
+ // TODO: For now Flow Entries are removed by all instances,
+ // even if this Flow Entry is not for our switches.
+ //
+ // 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.
+ //
+ if (mySwitch == null) {
+ if (flowEntry.flowEntryUserState() !=
+ FlowEntryUserState.FE_USER_DELETE) {
+ continue;
+ }
+ if (! flowEntry.isValidFlowEntryId())
+ continue;
+ }
+
+ //
+ // Write the Flow Entry to the Network Map
+ //
+ // NOTE: We try a number of times; apparently, if other instances
+ // are writing at the same time this will trigger an error.
+ //
+ for (int i = 0; i < 6; i++) {
try {
+ //
+ // 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 =
+ dbHandlerInner.searchFlowPath(flowEntry.flowId());
+ if (flowObj == null) {
+ String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
+ log.error(logMsg);
+ break;
+ }
+
+ // Write the Flow Entry
switch (flowEntry.flowEntryUserState()) {
case FE_USER_ADD:
// FALLTHROUGH
@@ -982,7 +1052,7 @@
if (addFlowEntry(flowObj, flowEntry) == null) {
String logMsg = "Cannot write to Network MAP Flow Entry " +
flowEntry.flowEntryId() +
- " from Flow Path " + flowPath.flowId() +
+ " from Flow Path " + flowEntry.flowId() +
" on switch " + flowEntry.dpid();
log.error(logMsg);
}
@@ -991,45 +1061,28 @@
if (deleteFlowEntry(flowObj, flowEntry) == false) {
String logMsg = "Cannot remove from Network MAP Flow Entry " +
flowEntry.flowEntryId() +
- " from Flow Path " + flowPath.flowId() +
+ " from Flow Path " + flowEntry.flowId() +
" on switch " + flowEntry.dpid();
log.error(logMsg);
}
break;
}
+
+ // Commit to the database
+ dbHandlerInner.commit();
+ break; // Success
+
} catch (Exception e) {
log.debug("Exception writing Flow Entry to Network MAP: ", e);
dbHandlerInner.rollback();
- 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);
+ // Wait a bit (random value [1ms, 20ms] and try again
+ int delay = 1 + randomGenerator.nextInt() % 20;
+ try {
+ Thread.sleep(delay);
+ } catch (Exception e0) {
}
}
- flowPath.dataPath().setFlowEntries(newFlowEntries);
}
}
- // Try to commit to the database
- try {
- dbHandlerInner.commit();
- } catch (Exception e) {
- log.debug("Exception during commit of Flow Entries to Network MAP", e);
- dbHandlerInner.rollback();
- }
}
}