Implement the periodic shortest path computation and triggering of
the flow path reconciliation.
For now, the computation code and the trigger itself are commented-out.
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index 18da3dd..71b6593 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -191,6 +191,12 @@
@Property("dst_port")
public void setDstPort(Short dstPort);
+ @Property("data_path_summary")
+ public String getDataPathSummary();
+
+ @Property("data_path_summary")
+ public void setDataPathSummary(String dataPathSummary);
+
@Adjacency(label="flow", direction=Direction.IN)
public Iterable<IFlowEntry> getFlowEntries();
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 25cf367..ba87666 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -263,7 +263,6 @@
log.debug("FloodlightProvider service not found!");
return;
}
-
Map<Long, IOFSwitch> mySwitches =
floodlightProvider.getSwitches();
Map<Long, IFlowEntry> myFlowEntries =
@@ -272,6 +271,77 @@
new LinkedList<IFlowEntry>();
//
+ // Fetch and recompute the Shortest Path for those
+ // Flow Paths this controller is responsible for.
+ //
+
+ /*
+ * TODO: For now, the computation of the reconciliation is
+ * commented-out.
+ */
+ /*
+ topoRouteService.prepareShortestPathTopo();
+ Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
+ HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
+ for (IFlowPath flowPathObj : allFlowPaths) {
+ if (flowPathObj == null)
+ continue;
+ String dataPathSummaryStr = flowPathObj.getDataPathSummary();
+ if (dataPathSummaryStr == null)
+ continue; // Could be invalid entry?
+ if (dataPathSummaryStr.isEmpty())
+ continue; // No need to maintain this flow
+
+ // Fetch the fields needed to recompute the shortest path
+ String flowIdStr = flowPathObj.getFlowId();
+ String srcDpidStr = flowPathObj.getSrcSwitch();
+ Short srcPortShort = flowPathObj.getSrcPort();
+ String dstDpidStr = flowPathObj.getDstSwitch();
+ Short dstPortShort = flowPathObj.getDstPort();
+ if ((flowIdStr == null) ||
+ (srcDpidStr == null) ||
+ (srcPortShort == null) ||
+ (dstDpidStr == null) ||
+ (dstPortShort == null)) {
+ log.debug("IGNORING Flow Path entry with null fields");
+ continue;
+ }
+
+ FlowId flowId = new FlowId(flowIdStr);
+ Dpid srcDpid = new Dpid(srcDpidStr);
+ Port srcPort = new Port(srcPortShort);
+ Dpid dstDpid = new Dpid(dstDpidStr);
+ Port dstPort = new Port(dstPortShort);
+ SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
+ SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+ DataPath dataPath =
+ topoRouteService.getTopoShortestPath(srcSwitchPort,
+ dstSwitchPort);
+ String newDataPathSummaryStr = dataPath.dataPathSummary();
+ if (dataPathSummaryStr.equals(newDataPathSummaryStr))
+ continue; // Nothing changed
+
+ //
+ // Use the source DPID as a heuristic to decide
+ // which controller is responsible for maintaining the
+ // shortest path.
+ // NOTE: This heuristic is error-prone: if the switch
+ // goes away and no controller is responsible for that
+ // switch, then the original Flow Path is not cleaned-up
+ //
+ IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
+ if (mySwitch == null)
+ continue; // Ignore: not my responsibility
+
+ log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
+ flowId.toString());
+ flowObjSet.add(flowPathObj);
+ }
+ reconcileFlows(flowObjSet);
+ topoRouteService.dropShortestPathTopo();
+ */
+
+ //
// Fetch all Flow Entries and select only my Flow Entries
// that need to be undated into the switches.
//
@@ -593,10 +663,13 @@
*
* @param flowPath the Flow Path to install.
* @param flowId the return-by-reference Flow ID as assigned internally.
+ * @param dataPathSummaryStr the data path summary string if the added
+ * flow will be maintained internally, otherwise null.
* @return true on success, otherwise false.
*/
@Override
- public boolean addFlow(FlowPath flowPath, FlowId flowId) {
+ public boolean addFlow(FlowPath flowPath, FlowId flowId,
+ String dataPathSummaryStr) {
if (flowPath.flowId().value() == measurementFlowId) {
modifiedMeasurementFlowTime = System.nanoTime();
}
@@ -654,6 +727,12 @@
flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
+ if (dataPathSummaryStr != null) {
+ flowObj.setDataPathSummary(dataPathSummaryStr);
+ } else {
+ flowObj.setDataPathSummary("");
+ }
+
// Flow edges:
// HeadFE
@@ -1125,16 +1204,16 @@
String flowIdStr = flowObj.getFlowId();
String installerIdStr = flowObj.getInstallerId();
String srcSwitchStr = flowObj.getSrcSwitch();
- Short srcPortStr = flowObj.getSrcPort();
+ Short srcPortShort = flowObj.getSrcPort();
String dstSwitchStr = flowObj.getDstSwitch();
- Short dstPortStr = flowObj.getDstPort();
+ Short dstPortShort = flowObj.getDstPort();
if ((flowIdStr == null) ||
(installerIdStr == null) ||
(srcSwitchStr == null) ||
- (srcPortStr == null) ||
+ (srcPortShort == null) ||
(dstSwitchStr == null) ||
- (dstPortStr == null)) {
+ (dstPortShort == null)) {
// TODO: A work-around, becauuse of some bogus database objects
return null;
}
@@ -1142,9 +1221,9 @@
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().srcPort().setPort(new Port(srcPortShort));
flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
- flowPath.dataPath().dstPort().setPort(new Port(dstPortStr));
+ flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
//
// Extract all Flow Entries
@@ -1229,6 +1308,8 @@
*/
@Override
public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
+ String dataPathSummaryStr = null;
+
//
// Do the shortest path computation
//
@@ -1243,6 +1324,9 @@
userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
}
+ // Compute the Data Path summary
+ dataPathSummaryStr = dataPath.dataPathSummary();
+
//
// Set the incoming port matching and the outgoing port output
// actions for each flow entry.
@@ -1277,7 +1361,7 @@
computedFlowPath.setDataPath(dataPath);
FlowId flowId = new FlowId();
- if (! addFlow(computedFlowPath, flowId))
+ if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
return null;
// TODO: Mark the flow for maintenance purpose
@@ -1352,21 +1436,37 @@
if (flowObj != null)
flowObjSet.add(flowObj);
}
- // conn.endTx(Transaction.COMMIT);
+
+ // Reconcile the affected flows
+ reconcileFlows(flowObjSet);
+ }
+
+ /**
+ * Reconcile all flows in a set.
+ *
+ * @param flowObjSet the set of flows that need to be reconciliated.
+ */
+ 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 my 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)
@@ -1375,10 +1475,15 @@
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
//
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index b6df1e2..619d36b 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -20,9 +20,12 @@
*
* @param flowPath the Flow Path to install.
* @param flowId the return-by-reference Flow ID as assigned internally.
+ * @param dataPathSummaryStr the data path summary string if the added
+ * flow will be maintained internally, otherwise null.
* @return true on success, otherwise false.
*/
- boolean addFlow(FlowPath flowPath, FlowId flowId);
+ boolean addFlow(FlowPath flowPath, FlowId flowId,
+ String dataPathSummaryStr);
/**
* Delete a previously added flow.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java
index cdccae1..e266e2e 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java
@@ -52,7 +52,7 @@
// Process the request
if (flowPath != null) {
- if (flowService.addFlow(flowPath, result) != true) {
+ if (flowService.addFlow(flowPath, result, null) != true) {
result = new FlowId(); // Error: Return empty Flow Id
}
}
diff --git a/src/main/java/net/floodlightcontroller/util/DataPath.java b/src/main/java/net/floodlightcontroller/util/DataPath.java
index b2dded6..0ca0d13 100644
--- a/src/main/java/net/floodlightcontroller/util/DataPath.java
+++ b/src/main/java/net/floodlightcontroller/util/DataPath.java
@@ -79,6 +79,37 @@
}
/**
+ * Get a string with the summary of the shortest-path data path
+ * computation.
+ *
+ * NOTE: This method assumes the DataPath was created by
+ * using FlowManager::getShortestPath() so the inPort and outPort
+ * of the Flow Entries are set.
+ * NOTE: This method is a temporary solution and will be removed
+ * in the future.
+ *
+ * @return a string with the summary of the shortest-path
+ * data path computation if valid, otherwise the string "X".
+ * If the shortest-path was valid, The string has the following form:
+ * inPort/dpid/outPort;inPort/dpid/outPort;...
+ */
+ public String dataPathSummary() {
+ String resultStr = new String();
+ if (this.flowEntries != null) {
+ for (FlowEntry flowEntry : this.flowEntries) {
+ // The data path summary string
+ resultStr = resultStr +
+ flowEntry.inPort().toString() + "/"
+ + flowEntry.dpid().toString() + "/" +
+ flowEntry.outPort().toString() + ";";
+ }
+ }
+ if (resultStr.isEmpty())
+ resultStr = "X"; // Invalid shortest-path
+ return resultStr;
+ }
+
+ /**
* Convert the data path to a string.
*
* The string has the following form: