Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index 9dea4c5..ea0daa3 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -193,6 +193,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..34e6296 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
@@ -1041,14 +1120,14 @@
return flowPaths;
}
- Collections.sort(allFlows);
+// Collections.sort(allFlows);
for (FlowPath flow : allFlows) {
// start from desired flowId
- if (flow.flowId().value() < flowId.value()) {
- continue;
- }
+ //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()) {
@@ -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/routing/TopoRouteService.java b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
index 773083b..ca8d92f 100644
--- a/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
+++ b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
@@ -368,7 +368,7 @@
Port outPort;
for (Node.Link link: resultPath) {
// Setup the outgoing port, and add the Flow Entry
- outPort = new Port(link.neighborPort);
+ outPort = new Port(link.myPort);
FlowEntry flowEntry = new FlowEntry();
flowEntry.setDpid(new Dpid(link.me.nodeId));
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:
diff --git a/web/add_flow.py b/web/add_flow.py
index 0ab6847..5a248eb 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -21,6 +21,7 @@
ControllerIP = "127.0.0.1"
ControllerPort = 8080
MonitoringEnabled = False
+MonitoringByOnos = False
ReadFromFile = ""
DEBUG=0
@@ -91,6 +92,20 @@
log_error("Controller IF has issue")
exit(1)
+def add_shortest_path_flow(flow_path):
+ flow_path_json = json.dumps(flow_path)
+
+ try:
+ command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/flow/add-shortest-path/json" % (flow_path_json, ControllerIP, ControllerPort)
+ debug("add_shortest_path_flow %s" % command)
+ result = os.popen(command).read()
+ debug("result %s" % result)
+ # parsedResult = json.loads(result)
+ # debug("parsed %s" % parsedResult)
+ except:
+ log_error("Controller IF has issue")
+ exit(1)
+
def delete_flow_path(flow_id):
command = "curl -s \"http://%s:%s/wm/flow/delete/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
debug("delete_flow_path %s" % command)
@@ -366,17 +381,97 @@
flow_path['dataPath'] = my_data_path
debug("Flow Path: %s" % flow_path)
+ return flow_path
- add_flow_path(flow_path)
+def exec_monitoring_by_onos(parsed_args):
+ idx = 0
+ while idx < len(parsed_args):
+ data_path = {}
+ src_dpid = {}
+ src_port = {}
+ dst_dpid = {}
+ dst_port = {}
+ src_switch_port = {}
+ dst_switch_port = {}
+ flow_entry = {}
+ flow_entries = []
+
+ src_dpid['value'] = parsed_args[idx]['my_src_dpid']
+ src_port['value'] = parsed_args[idx]['my_src_port']
+ dst_dpid['value'] = parsed_args[idx]['my_dst_dpid']
+ dst_port['value'] = parsed_args[idx]['my_dst_port']
+ src_switch_port['dpid'] = src_dpid
+ src_switch_port['port'] = src_port
+ dst_switch_port['dpid'] = dst_dpid
+ dst_switch_port['port'] = dst_port
+ match = parsed_args[idx]['match']
+ flow_entry['flowEntryMatch'] = match
+ flow_entries.append(flow_entry)
+
+ data_path['srcPort'] = copy.deepcopy(src_switch_port)
+ data_path['dstPort'] = copy.deepcopy(dst_switch_port)
+ data_path['flowEntries'] = copy.deepcopy(flow_entries)
+
+ #
+ # XXX: Explicitly disable the InPort matching, and
+ # the Output action, because they get in the way
+ # during the compute_flow_path() processing.
+ #
+ parsed_args[idx]['matchInPortEnabled'] = False
+ parsed_args[idx]['actionOutputEnabled'] = False
+
+ flow_path = compute_flow_path(parsed_args[idx], data_path)
+ add_shortest_path_flow(flow_path)
+
+ idx = idx + 1
+
+
+def exec_processing_by_script(parsed_args):
+ #
+ # Initialization
+ #
+ last_data_paths = []
+ idx = 0
+ while idx < len(parsed_args):
+ last_data_path = []
+ last_data_paths.append(copy.deepcopy(last_data_path))
+ idx = idx + 1
+
+ #
+ # Do the work: install and/or periodically monitor each flow
+ #
+ while True:
+ idx = 0
+ while idx < len(parsed_args):
+ last_data_path = last_data_paths[idx]
+ my_flow_id = parsed_args[idx]['my_flow_id']
+ data_path = compute_data_path(parsed_args[idx])
+ if data_path != last_data_path:
+ print_data_path(data_path)
+ if len(last_data_path) > 0:
+ delete_flow_path(my_flow_id)
+ if len(data_path) > 0:
+ flow_path = compute_flow_path(parsed_args[idx], data_path)
+ add_flow_path(flow_path)
+ last_data_paths[idx] = copy.deepcopy(data_path)
+ idx = idx + 1
+
+ if MonitoringEnabled != True:
+ break
+ time.sleep(1)
if __name__ == "__main__":
usage_msg = "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Match Conditions] [Actions]\n" % (sys.argv[0])
usage_msg = usage_msg + "\n"
usage_msg = usage_msg + " Flags:\n"
- usage_msg = usage_msg + " -m Monitor and maintain the installed shortest path(s)\n"
- usage_msg = usage_msg + " -f <filename> Read the flow(s) to install from a file\n"
- usage_msg = usage_msg + " File format: one line per flow starting with <flow-id>\n"
+ usage_msg = usage_msg + " -m [monitorname] Monitor and maintain the installed shortest path(s)\n"
+ usage_msg = usage_msg + " If 'monitorname' is specified and is set to 'ONOS'\n"
+ usage_msg = usage_msg + " ((case insensitive), then the flow generation and\n"
+ usage_msg = usage_msg + " maintanenance is done by ONOS itself.\n"
+ usage_msg = usage_msg + " Otherwise, it is done by this script.\n"
+ usage_msg = usage_msg + " -f <filename> Read the flow(s) to install from a file\n"
+ usage_msg = usage_msg + " File format: one line per flow starting with <flow-id>\n"
usage_msg = usage_msg + "\n"
usage_msg = usage_msg + " Match Conditions:\n"
usage_msg = usage_msg + " matchInPort <True|False> (default to True)\n"
@@ -427,6 +522,11 @@
idx = idx + 1
if arg1 == "-m":
MonitoringEnabled = True
+ if idx < len(sys.argv):
+ arg2 = sys.argv[idx]
+ if arg2.lower() == "onos":
+ MonitoringByOnos = True
+ idx = idx + 1
start_argv_index = idx
elif arg1 == "-f":
if idx >= len(sys.argv):
@@ -476,24 +576,8 @@
idx = idx + 1
#
- # Do the work: install and/or periodically monitor each flow
- #
- while True:
- idx = 0
- while idx < len(parsed_args):
- last_data_path = last_data_paths[idx]
- my_flow_id = parsed_args[idx]['my_flow_id']
- data_path = compute_data_path(parsed_args[idx])
- if data_path != last_data_path:
- print_data_path(data_path)
- if len(last_data_path) > 0:
- delete_flow_path(my_flow_id)
- if len(data_path) > 0:
- flow_path = compute_flow_path(parsed_args[idx], data_path)
- add_flow_path(flow_path)
- last_data_paths[idx] = copy.deepcopy(data_path)
- idx = idx + 1
+ if MonitoringByOnos == True:
+ exec_monitoring_by_onos(parsed_args)
+ else:
+ exec_processing_by_script(parsed_args)
- if MonitoringEnabled != True:
- break
- time.sleep(1)