cleaned up topology_rest.py and add loadbalancer function
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index e84a3e8..c69d6ee 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -52,7 +52,6 @@
import net.floodlightcontroller.util.OFMessageDamper;
import net.floodlightcontroller.util.Port;
import net.floodlightcontroller.util.SwitchPort;
-import net.onrc.onos.flow.IFlowManager;
import net.onrc.onos.util.GraphDBConnection;
import net.onrc.onos.util.GraphDBConnection.Transaction;
@@ -67,7 +66,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
+public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
public GraphDBConnection conn;
@@ -155,13 +154,17 @@
continue; // Ignore the entry: not my switch
myFlowEntries.put(flowEntryId.value(), flowEntryObj);
+ if (userState.equals("FE_USER_DELETE")) {
+ // An entry that needs to be deleted.
+ deleteFlowEntries.add(flowEntryObj);
+ }
}
log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
myFlowEntries.size());
//
- // Process my Flow Entries
+ // Process my Flow Entries in the Flow Entry ID order
//
boolean processed_measurement_flow = false;
for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
@@ -183,153 +186,19 @@
}
*/
- //
- // TODO: Eliminate the re-fetching of flowEntryId,
- // userState, switchState, and dpid from the flowEntryObj.
- //
- FlowEntryId flowEntryId =
- new FlowEntryId(flowEntryObj.getFlowEntryId());
Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
- String userState = flowEntryObj.getUserState();
- String switchState = flowEntryObj.getSwitchState();
IOFSwitch mySwitch = mySwitches.get(dpid.value());
if (mySwitch == null)
continue; // Shouldn't happen
-
- //
- // Create the Open Flow Flow Modification Entry to push
- //
- OFFlowMod fm =
- (OFFlowMod) floodlightProvider.getOFMessageFactory()
- .getMessage(OFType.FLOW_MOD);
- long cookie = flowEntryId.value();
-
- short flowModCommand = OFFlowMod.OFPFC_ADD;
- if (userState.equals("FE_USER_ADD")) {
- flowModCommand = OFFlowMod.OFPFC_ADD;
- } else if (userState.equals("FE_USER_MODIFY")) {
- flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
- } else if (userState.equals("FE_USER_DELETE")) {
- flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
- } else {
- // Unknown user state. Ignore the entry
- log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
- flowEntryId.toString(), userState);
- continue;
- }
-
- //
- // Fetch the match conditions.
- //
- // NOTE: The Flow matching conditions common for all
- // Flow Entries are used ONLY if a Flow Entry does NOT
- // have the corresponding matching condition set.
- //
- OFMatch match = new OFMatch();
- match.setWildcards(OFMatch.OFPFW_ALL);
- //
- Short matchInPort = flowEntryObj.getMatchInPort();
- if (matchInPort != null) {
- match.setInputPort(matchInPort);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
- }
- //
- Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
- if (matchEthernetFrameType == null)
- matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
- if (matchEthernetFrameType != null) {
- match.setDataLayerType(matchEthernetFrameType);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
- }
- //
- String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
- if (matchSrcIPv4Net == null)
- matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
- if (matchSrcIPv4Net != null) {
- match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
- }
- //
- String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
- if (matchDstIPv4Net == null)
- matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
- if (matchDstIPv4Net != null) {
- match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
- }
- //
- String matchSrcMac = flowEntryObj.getMatchSrcMac();
- if (matchSrcMac == null)
- matchSrcMac = flowObj.getMatchSrcMac();
- if (matchSrcMac != null) {
- match.setDataLayerSource(matchSrcMac);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
- }
- //
- String matchDstMac = flowEntryObj.getMatchDstMac();
- if (matchDstMac == null)
- matchDstMac = flowObj.getMatchDstMac();
- if (matchDstMac != null) {
- match.setDataLayerDestination(matchDstMac);
- match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
- }
-
- //
- // Fetch the actions
- //
- List<OFAction> actions = new ArrayList<OFAction>();
- Short actionOutputPort = flowEntryObj.getActionOutput();
- if (actionOutputPort != null) {
- OFActionOutput action = new OFActionOutput();
- // XXX: The max length is hard-coded for now
- action.setMaxLength((short)0xffff);
- action.setPort(actionOutputPort);
- actions.add(action);
- }
-
- fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
- .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
- .setPriority(PRIORITY_DEFAULT)
- .setBufferId(OFPacketOut.BUFFER_ID_NONE)
- .setCookie(cookie)
- .setCommand(flowModCommand)
- .setMatch(match)
- .setActions(actions)
- .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
- fm.setOutPort(OFPort.OFPP_NONE.getValue());
- if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
- (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
- if (actionOutputPort != null)
- fm.setOutPort(actionOutputPort);
- }
-
- //
- // TODO: Set the following flag
- // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
- // See method ForwardingBase::pushRoute()
- //
- try {
- messageDamper.write(mySwitch, fm, null);
- mySwitch.flush();
- //
- // TODO: We should use the OpenFlow Barrier mechanism
- // to check for errors, and update the SwitchState
- // for a flow entry after the Barrier message is
- // is received.
- //
- flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
- if (userState.equals("FE_USER_DELETE")) {
- // An entry that needs to be deleted.
- deleteFlowEntries.add(flowEntryObj);
- }
- } catch (IOException e) {
- log.error("Failure writing flow mod from network map", e);
- }
+ installFlowEntry(mySwitch, flowObj, flowEntryObj);
}
log.debug("MEASUREMENT: Found {} Flow Entries to delete",
deleteFlowEntries.size());
//
- // Delete all entries marked for deletion
+ // Delete all entries marked for deletion from the
+ // Network MAP.
//
// TODO: We should use the OpenFlow Barrier mechanism
// to check for errors, and delete the Flow Entries after the
@@ -345,19 +214,6 @@
}
flowObj.removeFlowEntry(flowEntryObj);
conn.utils().removeFlowEntry(conn, flowEntryObj);
-
- // Test whether the last flow entry
- Iterable<IFlowEntry> tmpflowEntries =
- flowObj.getFlowEntries();
- boolean found = false;
- for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
- found = true;
- break;
- }
- if (! found) {
- // Remove the Flow Path as well
- conn.utils().removeFlowPath(conn, flowObj);
- }
}
@@ -451,15 +307,24 @@
conn.endTx(Transaction.COMMIT);
if (processed_measurement_flow) {
- long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
+ long estimatedTime =
+ System.nanoTime() - modifiedMeasurementFlowTime;
String logMsg = "MEASUREMENT: Pushed Flow delay: " +
(double)estimatedTime / 1000000000 + " sec";
log.debug(logMsg);
}
long estimatedTime = System.nanoTime() - startTime;
- double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
- String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
+ double rate = 0.0;
+ if (estimatedTime > 0)
+ rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
+ String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
+ counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
+ counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
+ counterAllFlowPaths + " MyFlowPaths: " +
+ counterMyFlowPaths + " in " +
+ (double)estimatedTime / 1000000000 + " sec: " +
+ rate + " paths/s";
log.debug(logMsg);
}
};
@@ -1048,10 +913,10 @@
for (FlowPath flow : allFlows) {
flow.setFlowEntryMatch(null);
- // start from desired flowId
- //if (flow.flowId().value() < flowId.value()) {
- // continue;
- //}
+ // start from desired flowId
+ 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()) {
@@ -1121,8 +986,6 @@
* @return the extracted Flow Path State.
*/
private FlowPath extractFlowPath(IFlowPath flowObj) {
- FlowPath flowPath = new FlowPath();
-
//
// Extract the Flow state
//
@@ -1143,6 +1006,7 @@
return null;
}
+ FlowPath flowPath = new FlowPath();
flowPath.setFlowId(new FlowId(flowIdStr));
flowPath.setInstallerId(new CallerId(installerIdStr));
flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
@@ -1177,63 +1041,9 @@
//
Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
for (IFlowEntry flowEntryObj : flowEntries) {
- FlowEntry flowEntry = new FlowEntry();
- String flowEntryIdStr = flowEntryObj.getFlowEntryId();
- String switchDpidStr = flowEntryObj.getSwitchDpid();
- String userState = flowEntryObj.getUserState();
- String switchState = flowEntryObj.getSwitchState();
-
- if ((flowEntryIdStr == null) ||
- (switchDpidStr == null) ||
- (userState == null) ||
- (switchState == null)) {
- // TODO: A work-around, becauuse of some bogus database objects
+ FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
+ if (flowEntry == null)
continue;
- }
- flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
- flowEntry.setDpid(new Dpid(switchDpidStr));
-
- //
- // Extract the match conditions
- //
- FlowEntryMatch match = new FlowEntryMatch();
- Short matchInPort = flowEntryObj.getMatchInPort();
- if (matchInPort != null)
- match.enableInPort(new Port(matchInPort));
- Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
- if (matchEthernetFrameType != null)
- match.enableEthernetFrameType(matchEthernetFrameType);
- String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
- if (matchSrcIPv4Net != null)
- match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
- String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
- if (matchDstIPv4Net != null)
- match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
- String matchSrcMac = flowEntryObj.getMatchSrcMac();
- if (matchSrcMac != null)
- match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
- String matchDstMac = flowEntryObj.getMatchDstMac();
- if (matchDstMac != null)
- match.enableDstMac(MACAddress.valueOf(matchDstMac));
- flowEntry.setFlowEntryMatch(match);
-
- //
- // Extract the actions
- //
- ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
- Short actionOutputPort = flowEntryObj.getActionOutput();
- if (actionOutputPort != null) {
- FlowEntryAction action = new FlowEntryAction();
- action.setActionOutput(new Port(actionOutputPort));
- actions.add(action);
- }
- flowEntry.setFlowEntryActions(actions);
- flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
- flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
- //
- // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
- // and FlowEntryErrorState.
- //
flowPath.dataPath().flowEntries().add(flowEntry);
}
@@ -1241,6 +1051,74 @@
}
/**
+ * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
+ *
+ * @param flowEntryObj the object to extract the Flow Entry State from.
+ * @return the extracted Flow Entry State.
+ */
+ private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
+ String flowEntryIdStr = flowEntryObj.getFlowEntryId();
+ String switchDpidStr = flowEntryObj.getSwitchDpid();
+ String userState = flowEntryObj.getUserState();
+ String switchState = flowEntryObj.getSwitchState();
+
+ if ((flowEntryIdStr == null) ||
+ (switchDpidStr == null) ||
+ (userState == null) ||
+ (switchState == null)) {
+ // TODO: A work-around, becauuse of some bogus database objects
+ return null;
+ }
+
+ FlowEntry flowEntry = new FlowEntry();
+ flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
+ flowEntry.setDpid(new Dpid(switchDpidStr));
+
+ //
+ // Extract the match conditions
+ //
+ FlowEntryMatch match = new FlowEntryMatch();
+ Short matchInPort = flowEntryObj.getMatchInPort();
+ if (matchInPort != null)
+ match.enableInPort(new Port(matchInPort));
+ Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+ if (matchEthernetFrameType != null)
+ match.enableEthernetFrameType(matchEthernetFrameType);
+ String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+ if (matchSrcIPv4Net != null)
+ match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+ String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+ if (matchDstIPv4Net != null)
+ match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+ String matchSrcMac = flowEntryObj.getMatchSrcMac();
+ if (matchSrcMac != null)
+ match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+ String matchDstMac = flowEntryObj.getMatchDstMac();
+ if (matchDstMac != null)
+ match.enableDstMac(MACAddress.valueOf(matchDstMac));
+ flowEntry.setFlowEntryMatch(match);
+
+ //
+ // Extract the actions
+ //
+ ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
+ Short actionOutputPort = flowEntryObj.getActionOutput();
+ if (actionOutputPort != null) {
+ FlowEntryAction action = new FlowEntryAction();
+ action.setActionOutput(new Port(actionOutputPort));
+ actions.add(action);
+ }
+ flowEntry.setFlowEntryActions(actions);
+ flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
+ flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
+ //
+ // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
+ // and FlowEntryErrorState.
+ //
+ return flowEntry;
+ }
+
+ /**
* Add and maintain a shortest-path flow.
*
* NOTE: The Flow Path argument does NOT contain flow entries.
@@ -1309,78 +1187,6 @@
}
/**
- * Create a Flow from port to port.
- *
- * TODO: We don't need it for now.
- *
- * @param src_port the source port.
- * @param dest_port the destination port.
- */
- @Override
- public void createFlow(IPortObject src_port, IPortObject dest_port) {
- // TODO: We don't need it for now.
- }
-
- /**
- * Get all Flows matching a source and a destination port.
- *
- * TODO: Pankaj might be implementing it later.
- *
- * @param src_port the source port to match.
- * @param dest_port the destination port to match.
- * @return all flows matching the source and the destination port.
- */
- @Override
- public Iterable<FlowPath> getFlows(IPortObject src_port,
- IPortObject dest_port) {
- // TODO: Pankaj might be implementing it later.
- return null;
- }
-
- /**
- * Get all Flows going out from a port.
- *
- * TODO: We need it now: Pankaj
- *
- * @param port the port to match.
- * @return the list of flows that are going out from the port.
- */
- @Override
- public Iterable<FlowPath> getOutFlows(IPortObject port) {
- // TODO: We need it now: Pankaj
- return null;
- }
-
- /**
- * Reconcile all flows on inactive switch port.
- *
- * @param portObject the port that has become inactive.
- */
- @Override
- public void reconcileFlows(IPortObject portObject) {
- Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
- Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
-
- //
- // Collect all affected Flow IDs from the affected flow entries
- //
- HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
- for (IFlowEntry flowEntryObj: inFlowEntries) {
- IFlowPath flowObj = flowEntryObj.getFlow();
- if (flowObj != null)
- flowObjSet.add(flowObj);
- }
- for (IFlowEntry flowEntryObj: outFlowEntries) {
- IFlowPath flowObj = flowEntryObj.getFlow();
- if (flowObj != null)
- flowObjSet.add(flowObj);
- }
-
- // Reconcile the affected flows
- reconcileFlows(flowObjSet);
- }
-
- /**
* Reconcile all flows in a set.
*
* @param flowObjSet the set of flows that need to be reconciliated.
@@ -1488,96 +1294,156 @@
}
/**
- * Reconcile all flows between a source and a destination port.
+ * Install a Flow Entry on a switch.
*
- * TODO: We don't need it for now.
- *
- * @param src_port the source port.
- * @param dest_port the destination port.
+ * @param mySwitch the switch to install the Flow Entry into.
+ * @param flowObj the flow path object for the flow entry to install.
+ * @param flowEntryObj the flow entry object to install.
+ * @return true on success, otherwise false.
*/
- @Override
- public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
- // TODO: We don't need it for now.
- }
-
- /**
- * Compute the shortest path between a source and a destination ports.
- *
- * @param src_port the source port.
- * @param dest_port the destination port.
- * @return the computed shortest path between the source and the
- * destination ports. The flow entries in the path itself would
- * contain the incoming port matching and the outgoing port output
- * actions set. However, the path itself will NOT have the Flow ID,
- * Installer ID, and any additional matching conditions for the
- * flow entries (e.g., source or destination MAC address, etc).
- */
- @Override
- public FlowPath computeFlowPath(IPortObject src_port,
- IPortObject dest_port) {
- //
- // Prepare the arguments
- //
- String dpidStr = src_port.getSwitch().getDPID();
- Dpid srcDpid = new Dpid(dpidStr);
- Port srcPort = new Port(src_port.getNumber());
-
- dpidStr = dest_port.getSwitch().getDPID();
- Dpid dstDpid = new Dpid(dpidStr);
- Port dstPort = new Port(dest_port.getNumber());
-
- SwitchPort src = new SwitchPort(srcDpid, srcPort);
- SwitchPort dst = new SwitchPort(dstDpid, dstPort);
+ public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
+ IFlowEntry flowEntryObj) {
+ FlowEntryId flowEntryId =
+ new FlowEntryId(flowEntryObj.getFlowEntryId());
+ String userState = flowEntryObj.getUserState();
//
- // Do the shortest path computation
+ // Create the Open Flow Flow Modification Entry to push
//
- DataPath dataPath = topoRouteService.getShortestPath(src, dst);
- if (dataPath == null)
- return null;
+ OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
+ .getMessage(OFType.FLOW_MOD);
+ long cookie = flowEntryId.value();
- //
- // Set the incoming port matching and the outgoing port output
- // actions for each flow entry.
- //
- for (FlowEntry flowEntry : dataPath.flowEntries()) {
- // Set the incoming port matching
- FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
- if (flowEntryMatch == null) {
- 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);
+ short flowModCommand = OFFlowMod.OFPFC_ADD;
+ if (userState.equals("FE_USER_ADD")) {
+ flowModCommand = OFFlowMod.OFPFC_ADD;
+ } else if (userState.equals("FE_USER_MODIFY")) {
+ flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
+ } else if (userState.equals("FE_USER_DELETE")) {
+ flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
+ } else {
+ // Unknown user state. Ignore the entry
+ log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
+ flowEntryId.toString(), userState);
+ return false;
}
//
- // Prepare the return result
+ // Fetch the match conditions.
//
- FlowPath flowPath = new FlowPath();
- flowPath.setDataPath(dataPath);
+ // NOTE: The Flow matching conditions common for all Flow Entries are
+ // used ONLY if a Flow Entry does NOT have the corresponding matching
+ // condition set.
+ //
+ OFMatch match = new OFMatch();
+ match.setWildcards(OFMatch.OFPFW_ALL);
- return flowPath;
- }
+ // Match the Incoming Port
+ Short matchInPort = flowEntryObj.getMatchInPort();
+ if (matchInPort != null) {
+ match.setInputPort(matchInPort);
+ match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
+ }
- /**
- * Get all Flow Entries of a Flow.
- *
- * @param flow the flow whose flow entries should be returned.
- * @return the flow entries of the flow.
- */
- @Override
- public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
- return flow.dataPath().flowEntries();
+ // Match the Ethernet Frame Type
+ Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+ if (matchEthernetFrameType == null)
+ matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
+ if (matchEthernetFrameType != null) {
+ match.setDataLayerType(matchEthernetFrameType);
+ match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+ }
+
+ // Match the Source IPv4 Network prefix
+ String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+ if (matchSrcIPv4Net == null)
+ matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
+ if (matchSrcIPv4Net != null) {
+ match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
+ }
+
+ // Natch the Destination IPv4 Network prefix
+ String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+ if (matchDstIPv4Net == null)
+ matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
+ if (matchDstIPv4Net != null) {
+ match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
+ }
+
+ // Match the Source MAC address
+ String matchSrcMac = flowEntryObj.getMatchSrcMac();
+ if (matchSrcMac == null)
+ matchSrcMac = flowObj.getMatchSrcMac();
+ if (matchSrcMac != null) {
+ match.setDataLayerSource(matchSrcMac);
+ match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
+ }
+
+ // Match the Destination MAC address
+ String matchDstMac = flowEntryObj.getMatchDstMac();
+ if (matchDstMac == null)
+ matchDstMac = flowObj.getMatchDstMac();
+ if (matchDstMac != null) {
+ match.setDataLayerDestination(matchDstMac);
+ match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
+ }
+
+ //
+ // Fetch the actions
+ //
+ // TODO: For now we support only the "OUTPUT" actions.
+ //
+ List<OFAction> actions = new ArrayList<OFAction>();
+ Short actionOutputPort = flowEntryObj.getActionOutput();
+ if (actionOutputPort != null) {
+ OFActionOutput action = new OFActionOutput();
+ // XXX: The max length is hard-coded for now
+ action.setMaxLength((short)0xffff);
+ action.setPort(actionOutputPort);
+ actions.add(action);
+ }
+
+ fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+ .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+ .setPriority(PRIORITY_DEFAULT)
+ .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+ .setCookie(cookie)
+ .setCommand(flowModCommand)
+ .setMatch(match)
+ .setActions(actions)
+ .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+ fm.setOutPort(OFPort.OFPP_NONE.getValue());
+ if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
+ (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
+ if (actionOutputPort != null)
+ fm.setOutPort(actionOutputPort);
+ }
+
+ //
+ // TODO: Set the following flag
+ // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+ // See method ForwardingBase::pushRoute()
+ //
+
+ //
+ // Write the message to the switch
+ //
+ try {
+ messageDamper.write(mySwitch, fm, null);
+ mySwitch.flush();
+ //
+ // TODO: We should use the OpenFlow Barrier mechanism
+ // to check for errors, and update the SwitchState
+ // for a flow entry after the Barrier message is
+ // is received.
+ //
+ flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
+ } catch (IOException e) {
+ log.error("Failure writing flow mod from network map", e);
+ return false;
+ }
+
+ return true;
}
/**
@@ -1588,7 +1454,6 @@
* @param flowEntry the flow entry to install.
* @return true on success, otherwise false.
*/
- @Override
public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
FlowEntry flowEntry) {
//
@@ -1728,6 +1593,15 @@
try {
messageDamper.write(mySwitch, fm, null);
mySwitch.flush();
+ //
+ // TODO: We should use the OpenFlow Barrier mechanism
+ // to check for errors, and update the SwitchState
+ // for a flow entry after the Barrier message is
+ // is received.
+ //
+ // TODO: The FlowEntry Object in Titan should be set
+ // to FE_SWITCH_UPDATED.
+ //
} catch (IOException e) {
log.error("Failure writing flow mod from network map", e);
return false;
@@ -1743,7 +1617,6 @@
* @param flowEntry the flow entry to remove.
* @return true on success, otherwise false.
*/
- @Override
public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
FlowEntry flowEntry) {
//
@@ -1764,7 +1637,6 @@
* @param flowEntry the flow entry to install.
* @return true on success, otherwise false.
*/
- @Override
public boolean installRemoteFlowEntry(FlowPath flowPath,
FlowEntry flowEntry) {
// TODO: We need it now: Jono
@@ -1780,7 +1652,6 @@
* @param flowEntry the flow entry to remove.
* @return true on success, otherwise false.
*/
- @Override
public boolean removeRemoteFlowEntry(FlowPath flowPath,
FlowEntry flowEntry) {
//
diff --git a/web/ons-demo/RELEASE_NOTES.txt b/web/ons-demo/RELEASE_NOTES.txt
index 916a965..90af6d1 100644
--- a/web/ons-demo/RELEASE_NOTES.txt
+++ b/web/ons-demo/RELEASE_NOTES.txt
@@ -1,11 +1,20 @@
** April 4, 2013 **
+iperf display implemented
+- scaled to 50,000,000
+- update rate is every 2s
+- the display does not draw until receiving 2 buffers of data (this way if there is a stale buffer it doesn't get displayed)
+- duration is 10000 seconds. seems like there is no need for a button to restart?
+- displaying 10s data
+- if the data underruns (either because the server response is too slow or because the iperf data stops being updated) the display draws 0s
+- seeing the data stall a lot (timestamp and end-time remain the same through many fetches)
+
+** April 4, 2013 **
Fix issues:
305 - "close x" now unselects flow. double click to delete a flow
323 - gui now recovers on timeout errors and polls again
324 - fixed problem with added flows not displaying
325 - fixed logic displaying flows in topology view
-
** March 28, 2013 **
- add and delete flow implemented
- to add flow
diff --git a/web/ons-demo/css/layout.default.css b/web/ons-demo/css/layout.default.css
index 018e728..5e1f1ce 100644
--- a/web/ons-demo/css/layout.default.css
+++ b/web/ons-demo/css/layout.default.css
@@ -76,6 +76,15 @@
.iperf {
width: 100%;
-webkit-box-flex: 1.0;
+ position: relative;
+ display: -webkit-box;
+}
+
+.iperf-container {
+ position: absolute;
+ top: 0px;
+ height: 100%;
+ width: 100%;
}
#controllers {
diff --git a/web/ons-demo/css/skin.default.css b/web/ons-demo/css/skin.default.css
index 1ce4897..1d656b0 100644
--- a/web/ons-demo/css/skin.default.css
+++ b/web/ons-demo/css/skin.default.css
@@ -145,6 +145,12 @@
border-top: 1px solid #AAA;
}
+path.iperfdata {
+ fill: none;
+ stroke-width: 2px;
+ stroke: rgba(255, 255, 255, .75);
+}
+
#flowChooser {
pointer-events: none;
background-color: rgba(0, 0, 0, .25);
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index 695e4bb..d6fa983 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -96,7 +96,7 @@
return;
}
var pts = [];
- if (!d.dataPath.flowEntries || !d.dataPath.flowEntries.length) {
+ if (!d.dataPath.flowEntries) {
// create a temporary vector to indicate the pending flow
var s1 = d3.select(document.getElementById(d.dataPath.srcPort.dpid.value));
var s2 = d3.select(document.getElementById(d.dataPath.dstPort.dpid.value));
@@ -128,7 +128,11 @@
}
});
}
- return line(pts);
+ if (pts.length) {
+ return line(pts);
+ } else {
+ return "M0,0";
+ }
})
.attr('id', function (d) {
if (d) {
@@ -153,6 +157,16 @@
row.append('div').classed('dstDPID', true);
row.append('div').classed('iperf', true);
+ row.select('.iperf')
+ .append('div')
+ .attr('class', 'iperf-container')
+ .append('svg:svg')
+ .attr('viewBox', '0 0 1000 32')
+ .attr('preserveAspectRatio', 'none')
+ .append('svg:g')
+ .append('svg:path')
+ .attr('class', 'iperfdata');
+
row.on('mouseover', function (d) {
if (d) {
var path = document.getElementById(makeFlowKey(d));
@@ -164,14 +178,24 @@
var path = document.getElementById(makeFlowKey(d));
d3.select(path).classed('highlight', false);
}
- })
+ });
}
function rowUpdate(d) {
var row = d3.select(this);
+ row.attr('id', function (d) {
+ if (d) {
+ return makeSelectedFlowKey(d);
+ }
+ });
+
+ if (!d || !hasIPerf(d)) {
+ row.select('.iperfdata')
+ .attr('d', 'M0,0');
+ }
+
row.select('.deleteFlow').on('click', function () {
- selectedFlows[selectedFlows.indexOf(d)] = null;
- updateSelectedFlows();
+ deselectFlow(d);
});
row.on('dblclick', function () {
if (d) {
@@ -232,6 +256,73 @@
flows.exit().remove();
}
+// TODO: cancel the interval when the flow is desel
+function startIPerfForFlow(flow) {
+ var duration = 10000; // seconds
+ var interval = 100; // ms. this is defined by the server
+ var updateRate = 2000; // ms
+
+ function makePoints() {
+ var pts = [];
+ var i;
+ for (i=0; i < 100; ++i) {
+ var sample = flow.iperfData.samples[i];
+ var height = 32 * sample/50000000;
+ if (height > 32)
+ height = 32;
+ pts.push({
+ x: i * 1000/99,
+ y: 32 - height
+ })
+ }
+ return pts;
+ }
+
+ if (flow.flowId) {
+ console.log('starting iperf for: ' + flow.flowId.value);
+ startIPerf(flow, duration, updateRate/interval);
+ flow.iperfDisplayInterval = setInterval(function () {
+ if (flow.iperfData) {
+ while (flow.iperfData.samples.length < 100) {
+ flow.iperfData.samples.push(0);
+ }
+ var iperfPath = d3.select(document.getElementById(makeSelectedFlowKey(flow))).select('path');
+ iperfPath.attr('d', line(makePoints()));
+ flow.iperfData.samples.shift();
+ }
+
+
+ }, interval);
+ flow.iperfFetchInterval = setInterval(function () {
+ getIPerfData(flow, function (data) {
+ try {
+ if (!flow.iperfData) {
+ flow.iperfData = {
+ samples: []
+ };
+ var i;
+ for (i = 0; i < 100; ++i) {
+ flow.iperfData.samples.push(0);
+ }
+ }
+
+ var iperfData = JSON.parse(data);
+ // if the data is fresh
+ if (flow.iperfData.timestamp && iperfData.timestamp != flow.iperfData.timestamp) {
+ iperfData.samples.forEach(function (s) {
+ flow.iperfData.samples.push(s);
+ });
+ }
+ flow.iperfData.timestamp = iperfData.timestamp;
+ } catch (e) {
+ console.log('bad iperf data: ' + data);
+ }
+// console.log(data);
+ });
+ }, updateRate/2); // over sample to avoid gaps
+ }
+}
+
function updateSelectedFlows() {
// make sure that all of the selected flows are either
// 1) valid (meaning they are in the latest list of flows)
@@ -249,13 +340,22 @@
if (liveFlow) {
newSelectedFlows.push(liveFlow);
liveFlow.deletePending = flow.deletePending;
+ liveFlow.iperfFetchInterval = flow.iperfFetchInterval;
+ liveFlow.iperfDisplayInterval = flow.iperfDisplayInterval;
} else if (flow.createPending) {
newSelectedFlows.push(flow);
+ } else if (hasIPerf(flow)) {
+ clearIPerf(flow);
}
}
});
selectedFlows = newSelectedFlows;
}
+ selectedFlows.forEach(function (flow) {
+ if (!hasIPerf(flow)) {
+ startIPerfForFlow(flow);
+ }
+ });
while (selectedFlows.length < 3) {
selectedFlows.push(null);
}
@@ -280,6 +380,19 @@
}
}
+function hasIPerf(flow) {
+ return flow && flow.iperfFetchInterval;
+}
+
+function clearIPerf(flow) {
+ console.log('clearing iperf interval for: ' + flow.flowId.value);
+ clearInterval(flow.iperfFetchInterval);
+ delete flow.iperfFetchInterval;
+ clearInterval(flow.iperfDisplayInterval);
+ delete flow.iperfDisplayInterval;
+ delete flow.iperfData;
+}
+
function deselectFlow(flow, ifCreatePending) {
var flowKey = makeFlowKey(flow);
var newSelectedFlows = [];
@@ -288,6 +401,10 @@
flowKey !== makeFlowKey(flow) ||
flowKey === makeFlowKey(flow) && ifCreatePending && !flow.createPending ) {
newSelectedFlows.push(flow);
+ } else {
+ if (hasIPerf(flow)) {
+ clearIPerf(flow);
+ }
}
});
selectedFlows = newSelectedFlows;
@@ -474,6 +591,10 @@
return flow.dataPath.srcPort.dpid.value + '=>' + flow.dataPath.dstPort.dpid.value;
}
+function makeSelectedFlowKey(flow) {
+ return 'S' + makeFlowKey(flow);
+}
+
function createLinkMap(links) {
var linkMap = {};
links.forEach(function (link) {
@@ -1066,6 +1187,7 @@
}
+var modelString;
function sync(svg) {
var d = Date.now();
updateModel(function (newModel) {
@@ -1073,9 +1195,11 @@
if (newModel) {
var modelChanged = false;
- if (!model || JSON.stringify(model) != JSON.stringify(newModel)) {
+ var newModelString = JSON.stringify(newModel);
+ if (!modelString || newModelString != modelString) {
modelChanged = true;
model = newModel;
+ modelString = newModelString;
} else {
// console.log('no change');
}
diff --git a/web/ons-demo/js/controller.js b/web/ons-demo/js/controller.js
index fd3f6ae..c7c80ec 100644
--- a/web/ons-demo/js/controller.js
+++ b/web/ons-demo/js/controller.js
@@ -1,11 +1,14 @@
/*global d3*/
-function callURL(url) {
+function callURL(url, cb) {
d3.text(url, function (error, result) {
if (error) {
alert(url + ' : ' + error.status);
} else {
- console.log(result);
+ if (cb) {
+ cb(result);
+ }
+// console.log(result);
}
});
}
@@ -37,6 +40,16 @@
delFlowCmd: function (flow) {
var url = '/proxy/gui/delflow/' + flow.flowId.value;
callURL(url);
+ },
+ startIPerfCmd: function (flow, duration, numSamples) {
+ var flowId = parseInt(flow.flowId.value, 16);
+ var url = '/proxy/gui/iperf/start/' + [flowId, duration, numSamples].join('/');
+ callURL(url)
+ },
+ getIPerfDataCmd: function (flow, cb) {
+ var flowId = parseInt(flow.flowId.value, 16);
+ var url = '/proxy/gui/iperf/rate/' + flowId;
+ callURL(url, cb);
}
};
@@ -70,4 +83,12 @@
function deleteFlow(flow) {
controllerFunctions.delFlowCmd(flow);
+}
+
+function startIPerf(flow, duration, numSamples) {
+ controllerFunctions.startIPerfCmd(flow, duration, numSamples);
+}
+
+function getIPerfData(flow, cb) {
+ controllerFunctions.getIPerfDataCmd(flow, cb);
}
\ No newline at end of file
diff --git a/web/topology_rest.py b/web/topology_rest.py
index ce7b84e..bc52992 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -19,18 +19,18 @@
## Uncomment the desired block based on your testbed environment
# Settings for running on production
-#controllers=["onosgui1", "onosgui2", "onosgui3", "onosgui4", "onosgui5", "onosgui6", "onosgui7", "onosgui8"]
-#core_switches=["00:00:00:00:ba:5e:ba:11", "00:00:00:00:00:00:ba:12", "00:00:20:4e:7f:51:8a:35", "00:00:00:00:ba:5e:ba:13", "00:00:00:08:a2:08:f9:01", "00:00:00:16:97:08:9a:46"]
-#ONOS_GUI3_HOST="http://gui3.onlab.us:8080"
-#ONOS_GUI3_CONTROL_HOST="http://gui3.onlab.us:8081"
+controllers=["onosgui1", "onosgui2", "onosgui3", "onosgui4", "onosgui5", "onosgui6", "onosgui7", "onosgui8"]
+core_switches=["00:00:00:00:ba:5e:ba:11", "00:00:00:00:00:00:ba:12", "00:00:20:4e:7f:51:8a:35", "00:00:00:00:ba:5e:ba:13", "00:00:00:08:a2:08:f9:01", "00:00:00:16:97:08:9a:46"]
+ONOS_GUI3_HOST="http://gui3.onlab.us:8080"
+ONOS_GUI3_CONTROL_HOST="http://gui3.onlab.us:8081"
# Settings for running on dev testbed. Replace dev
#controllers=["onosdevb1", "onosdevb2", "onosdevb3", "onosdevb4"]
-controllers=["onosdevt1", "onosdevt2", "onosdevt3", "onosdevt4", "onosdevt5", "onosdevt6", "onosdevt7", "onosdevt8"]
-core_switches=["00:00:00:00:00:00:01:01", "00:00:00:00:00:00:01:02", "00:00:00:00:00:00:01:03", "00:00:00:00:00:00:01:04", "00:00:00:00:00:00:01:05", "00:00:00:00:00:00:01:06"]
+#controllers=["onosdevt1", "onosdevt2", "onosdevt3", "onosdevt4", "onosdevt5", "onosdevt6", "onosdevt7", "onosdevt8"]
+#core_switches=["00:00:00:00:00:00:01:01", "00:00:00:00:00:00:01:02", "00:00:00:00:00:00:01:03", "00:00:00:00:00:00:01:04", "00:00:00:00:00:00:01:05", "00:00:00:00:00:00:01:06"]
-ONOS_GUI3_HOST="http://devt-gui.onlab.us:8080"
-ONOS_GUI3_CONTROL_HOST="http://devt-gui.onlab.us:8080"
+#ONOS_GUI3_HOST="http://devt-gui.onlab.us:8080"
+#ONOS_GUI3_CONTROL_HOST="http://devt-gui.onlab.us:8080"
LB=True #; True or False
ONOS_DEFAULT_HOST="localhost" ;# Has to set if LB=False
@@ -153,6 +153,33 @@
resp = Response(result, status=200, mimetype='application/json')
return resp
+@app.route("/proxy/gui/iperf/start/<flow_id>/<duration>/<samples>")
+def proxy_iperf_start(flow_id,duration,samples):
+ try:
+ command = "curl -s %s/gui/iperf/start/%s/%s/%s" % (ONOS_GUI3_CONTROL_HOST, flow_id, duration, samples)
+ print command
+ result = os.popen(command).read()
+ except:
+ print "REST IF has issue"
+ exit
+
+ resp = Response(result, status=200, mimetype='application/json')
+ return resp
+
+@app.route("/proxy/gui/iperf/rate/<flow_id>")
+def proxy_iperf_rate(flow_id):
+ try:
+ command = "curl -s %s/gui/iperf/rate/%s" % (ONOS_GUI3_CONTROL_HOST, flow_id)
+ print command
+ result = os.popen(command).read()
+ except:
+ print "REST IF has issue"
+ exit
+
+ resp = Response(result, status=200, mimetype='application/json')
+ return resp
+
+
###### ONOS RESET API ##############################
## Worker Func ###
def get_json(url):
@@ -185,6 +212,7 @@
return "http://" + host + ":8080"
## Switch ##
+=======
@app.route("/wm/core/topology/switches/all/json")
def switches():
if request.args.get('proxy') == None:
@@ -226,7 +254,6 @@
resp = Response(result, status=code, mimetype='application/json')
return resp
-
@app.route("/wm/registry/controllers/json")
def registry_controllers():
if request.args.get('proxy') == None: