Implement rerouting feature in PathCalcRuntimeModule
Change-Id: Ie37ebd1fa6910e999d457481d7082adb0d1d9a3a
diff --git a/src/main/java/net/onrc/onos/intent/Intent.java b/src/main/java/net/onrc/onos/intent/Intent.java
index 8e20bb7..002d6f6 100644
--- a/src/main/java/net/onrc/onos/intent/Intent.java
+++ b/src/main/java/net/onrc/onos/intent/Intent.java
@@ -50,4 +50,9 @@
public int hashCode() {
return id.hashCode();
}
+
+ @Override
+ public String toString() {
+ return id.toString() + ", " + state.toString();
+ }
}
diff --git a/src/main/java/net/onrc/onos/intent/IntentMap.java b/src/main/java/net/onrc/onos/intent/IntentMap.java
index 57ce5e0..9969433 100644
--- a/src/main/java/net/onrc/onos/intent/IntentMap.java
+++ b/src/main/java/net/onrc/onos/intent/IntentMap.java
@@ -49,18 +49,32 @@
}
private HashSet<ChangedListener> listeners = new HashSet<>();
- protected HashMap<String, Intent> intents = new HashMap<>();
+ private HashMap<String, Intent> intents = new HashMap<>();
+
+ protected void putIntent(Intent intent) {
+ if (intents.containsKey(intent.getId()))
+ removeIntent(intent.getId());
+ intents.put(intent.getId(), intent);
+ }
+
+ protected void removeIntent(String intentId) {
+ intents.remove(intentId);
+ }
+
+ public Intent getIntent(String intentId) {
+ return intents.get(intentId);
+ }
public void executeOperations(IntentOperationList operations) {
LinkedList<ChangedEvent> events = new LinkedList<>();
for (IntentOperation operation: operations) {
switch (operation.operator) {
case ADD:
- intents.put(operation.intent.getId(), operation.intent);
+ putIntent(operation.intent);
events.add(new ChangedEvent(ChangedEventType.ADDED, operation.intent));
break;
case REMOVE:
- Intent intent = intents.get(operation.intent.getId());
+ Intent intent = getIntent(operation.intent.getId());
if (intent == null) {
// TODO throw exception
}
@@ -78,14 +92,16 @@
}
public void purge() {
- Iterator<Entry<String, Intent>> i = intents.entrySet().iterator();
- while (i.hasNext()) {
- Entry<String, Intent> entry = i.next();
+ LinkedList<String> removeIds = new LinkedList<>();
+ for (Entry<String, Intent> entry: intents.entrySet()) {
Intent intent = entry.getValue();
if (intent.getState() == IntentState.DEL_ACK
|| intent.getState() == IntentState.INST_NACK) {
- i.remove();
- }
+ removeIds.add(intent.getId());
+ }
+ }
+ for (String intentId: removeIds) {
+ removeIntent(intentId);
}
}
@@ -93,10 +109,6 @@
return intents.values();
}
- public Intent getIntent(String key) {
- return intents.get(key);
- }
-
public void addChangeListener(ChangedListener listener) {
listeners.add(listener);
}
diff --git a/src/main/java/net/onrc/onos/intent/IntentOperation.java b/src/main/java/net/onrc/onos/intent/IntentOperation.java
index 8ac45c9..c769811 100644
--- a/src/main/java/net/onrc/onos/intent/IntentOperation.java
+++ b/src/main/java/net/onrc/onos/intent/IntentOperation.java
@@ -26,4 +26,9 @@
public Operator operator;
public Intent intent;
+
+ @Override
+ public String toString() {
+ return operator.toString() + ", (" + intent.toString() + ")";
+ }
}
diff --git a/src/main/java/net/onrc/onos/intent/PathIntent.java b/src/main/java/net/onrc/onos/intent/PathIntent.java
index 4ef4cf0..a5454fa 100644
--- a/src/main/java/net/onrc/onos/intent/PathIntent.java
+++ b/src/main/java/net/onrc/onos/intent/PathIntent.java
@@ -1,16 +1,19 @@
package net.onrc.onos.intent;
+import java.util.LinkedList;
+import java.util.List;
+
import net.onrc.onos.ofcontroller.networkgraph.Link;
+import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
import net.onrc.onos.ofcontroller.networkgraph.Path;
import net.onrc.onos.ofcontroller.networkgraph.Port;
-import net.onrc.onos.ofcontroller.networkgraph.Switch;
/**
* @author Toshio Koide (t-koide@onlab.us)
*/
public class PathIntent extends Intent {
- protected long pathData[];
+ protected List<LinkEvent> path;
protected double bandwidth;
protected Intent parentIntent;
@@ -31,13 +34,13 @@
*/
public PathIntent(String id, Path path, double bandwidth, Intent parentIntent) {
super(id);
- pathData = new long[path.size() * 4];
- for (int i=0; i<path.size(); i++) {
- Link link = path.get(i);
- this.pathData[i*4] = link.getSourceSwitch().getDpid();
- this.pathData[i*4+1] = link.getSourcePort().getNumber();
- this.pathData[i*4+2] = link.getDestinationSwitch().getDpid();
- this.pathData[i*4+3] = link.getDestinationPort().getNumber();
+ this.path = new LinkedList<LinkEvent>();
+ for (Link link: path) {
+ this.path.add(new LinkEvent(
+ link.getSourceSwitch().getDpid(),
+ link.getSourcePort().getNumber(),
+ link.getDestinationSwitch().getDpid(),
+ link.getDestinationPort().getNumber()));
}
this.bandwidth = bandwidth;
this.parentIntent = parentIntent;
@@ -47,8 +50,8 @@
return bandwidth;
}
- public long[] getPathData() {
- return pathData;
+ public List<LinkEvent> getPathByLinkEvent() {
+ return path;
}
/**
@@ -57,19 +60,13 @@
* @return path object. If there is no path in the specified graph, returns null.
*/
public Path getPath(NetworkGraph graph) {
- Path path = new Path();
- Switch srcSwitch;
- Port srcPort;
- Link link;
- for (int i=0; i<pathData.length; i+=4) {
- if ((srcSwitch = graph.getSwitch(pathData[i])) == null) return null;
- if ((srcPort = srcSwitch.getPort(pathData[i+1])) == null) return null;
- if ((link = srcPort.getOutgoingLink()) == null) return null;
- if (link.getDestinationSwitch().getDpid() != pathData[i+2]) return null;
- if (link.getDestinationPort().getNumber() != pathData[i+3]) return null;
- path.add(link);
+ Path pathObj = new Path();
+ for (LinkEvent linkEvent: path) {
+ Link link = linkEvent.getLink(graph);
+ if (link == null) return null;
+ pathObj.add(link);
}
- return path;
+ return pathObj;
}
public Intent getParentIntent() {
diff --git a/src/main/java/net/onrc/onos/intent/PathIntentMap.java b/src/main/java/net/onrc/onos/intent/PathIntentMap.java
index 02444ff..b955922 100644
--- a/src/main/java/net/onrc/onos/intent/PathIntentMap.java
+++ b/src/main/java/net/onrc/onos/intent/PathIntentMap.java
@@ -6,43 +6,44 @@
import java.util.HashSet;
import net.onrc.onos.ofcontroller.networkgraph.Link;
-import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
+import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
/**
* @author Toshio Koide (t-koide@onlab.us)
*/
public class PathIntentMap extends IntentMap {
- protected HashMap<Link, HashSet<PathIntent>> linkToIntents = new HashMap<Link, HashSet<PathIntent>>();
- protected NetworkGraph graph;
+ protected HashMap<LinkEvent, HashSet<PathIntent>> linkToIntents = new HashMap<>();
- public PathIntentMap(NetworkGraph graph) {
- this.graph = graph;
- }
-
- public void addIntent(PathIntent intent) {
- if (intents.containsKey(intent.getId()))
- removeIntent((PathIntent)intents.get(intent.getId()));
- intents.put(intent.getId(), intent);
- for (Link link: intent.getPath(graph)) {
- HashSet<PathIntent> value = linkToIntents.get(link);
- if (value == null) {
+ @Override
+ protected void putIntent(Intent intent) {
+ super.putIntent(intent);
+ for (LinkEvent linkEvent: ((PathIntent) intent).getPathByLinkEvent()) {
+ HashSet<PathIntent> value = linkToIntents.get(linkEvent);
+ if (value == null)
value = new HashSet<PathIntent>();
- linkToIntents.put(link, value);
- }
- value.add(intent);
+ value.add((PathIntent) intent);
+ linkToIntents.put(linkEvent, value);
}
}
- public void removeIntent(PathIntent intent) {
- intents.remove(intent);
- for (Link link: intent.getPath(graph)) {
- HashSet<PathIntent> value = linkToIntents.get(link);
+ @Override
+ protected void removeIntent(String intentId) {
+ PathIntent intent = (PathIntent) getIntent(intentId);
+ for (LinkEvent linkEvent: intent.getPathByLinkEvent()) {
+ HashSet<PathIntent> value = linkToIntents.get(linkEvent);
value.remove(intent);
}
+ super.removeIntent(intentId);
}
- public Collection<PathIntent> getIntentByLink(Link link) {
- return Collections.unmodifiableCollection(linkToIntents.get(link));
+ public Collection<PathIntent> getIntentsByLink(LinkEvent linkEvent) {
+ Collection<PathIntent> intents = linkToIntents.get(linkEvent);
+ if (intents == null) {
+ return null;
+ }
+ else {
+ return Collections.unmodifiableCollection(intents);
+ }
}
/**
@@ -51,9 +52,11 @@
* @return
*/
public Double getAvailableBandwidth(Link link) {
+ if (link == null) return null;
Double bandwidth = link.getCapacity();
- if (!bandwidth.isInfinite() && linkToIntents.containsKey(link)) {
- for (PathIntent intent: getIntentByLink(link)) {
+ LinkEvent linkEvent = new LinkEvent(link);
+ if (!bandwidth.isInfinite() && linkToIntents.containsKey(linkEvent)) {
+ for (PathIntent intent: getIntentsByLink(linkEvent)) {
Double intentBandwidth = intent.getBandwidth();
if (intentBandwidth == null || intentBandwidth.isInfinite() || intentBandwidth.isNaN())
continue;
diff --git a/src/main/java/net/onrc/onos/intent/ShortestPathIntent.java b/src/main/java/net/onrc/onos/intent/ShortestPathIntent.java
index 4b324df..4198b18 100644
--- a/src/main/java/net/onrc/onos/intent/ShortestPathIntent.java
+++ b/src/main/java/net/onrc/onos/intent/ShortestPathIntent.java
@@ -58,7 +58,8 @@
@Override
public String toString() {
- return String.format("srcDpid:%s, srcPort:%d, srcMac:%s, dstDpid:%s, dstPort:%d, dstMac:%s",
+ return String.format("id:%s, state:%s, srcDpid:%s, srcPort:%d, srcMac:%s, dstDpid:%s, dstPort:%d, dstMac:%s",
+ getId(), state,
new Dpid(srcSwitchDpid), srcPortNumber, MACAddress.valueOf(srcMacAddress),
new Dpid(dstSwitchDpid), dstPortNumber, MACAddress.valueOf(dstMacAddress));
}
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
index 32fe746..4408f3f 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
@@ -5,11 +5,13 @@
import net.floodlightcontroller.core.module.IFloodlightService;
import net.onrc.onos.intent.ConstrainedBFSTree;
import net.onrc.onos.intent.ConstrainedShortestPathIntent;
+import net.onrc.onos.intent.Intent;
import net.onrc.onos.intent.IntentOperation;
import net.onrc.onos.intent.IntentOperationList;
import net.onrc.onos.intent.PathIntent;
import net.onrc.onos.intent.PathIntentMap;
import net.onrc.onos.intent.ShortestPathIntent;
+import net.onrc.onos.intent.IntentOperation.Operator;
import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
import net.onrc.onos.ofcontroller.networkgraph.Path;
import net.onrc.onos.ofcontroller.networkgraph.Switch;
@@ -74,7 +76,7 @@
pathIntentOpList.add(new IntentOperation(IntentOperation.Operator.ADD, pathIntent));
break;
case REMOVE:
- pathIntentOpList.add(intentOp);
+ pathIntentOpList.add(Operator.REMOVE, new Intent("pi" + intentOp.intent.getId()));
break;
}
}
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
index 26afe51..d72a13a 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
@@ -11,22 +11,43 @@
import net.floodlightcontroller.core.module.IFloodlightService;
import net.onrc.onos.datagrid.IDatagridService;
import net.onrc.onos.datagrid.IEventChannel;
+import net.onrc.onos.intent.Intent;
import net.onrc.onos.intent.IntentMap;
+import net.onrc.onos.intent.IntentOperation.Operator;
import net.onrc.onos.intent.IntentOperationList;
+import net.onrc.onos.intent.PathIntent;
import net.onrc.onos.intent.PathIntentMap;
+import net.onrc.onos.ofcontroller.networkgraph.DeviceEvent;
+import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphListener;
import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphService;
-import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
+import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
+import net.onrc.onos.ofcontroller.networkgraph.PortEvent;
+import net.onrc.onos.ofcontroller.networkgraph.SwitchEvent;
-public class PathCalcRuntimeModule implements IFloodlightModule, IPathCalcRuntimeService {
+/**
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class PathCalcRuntimeModule implements IFloodlightModule, IPathCalcRuntimeService, INetworkGraphListener {
private PathCalcRuntime runtime;
private IDatagridService datagridService;
private INetworkGraphService networkGraphService;
private IntentMap highLevelIntents;
private PathIntentMap pathIntents;
- private IEventChannel<byte[], IntentOperationList> eventChannel;
+ private IEventChannel<String, IntentOperationList> eventChannel;
private static final String EVENT_CHANNEL_NAME = "onos.pathintent";
+ private void reroutePaths(LinkEvent linkEvent) {
+ Collection<PathIntent> oldPaths = pathIntents.getIntentsByLink(linkEvent);
+ if (oldPaths == null) return;
+ IntentOperationList reroutingOperation = new IntentOperationList();
+ for (PathIntent pathIntent: oldPaths) {
+ // TODO use Operator.UPDATE instead of REMOVE and ADD in order to optimize
+ reroutingOperation.add(Operator.REMOVE, new Intent(pathIntent.getParentIntent().getId()));
+ reroutingOperation.add(Operator.ADD, pathIntent.getParentIntent());
+ }
+ executeIntentOperations(reroutingOperation);
+ }
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
@@ -60,23 +81,22 @@
public void startUp(FloodlightModuleContext context) {
highLevelIntents = new IntentMap();
runtime = new PathCalcRuntime(networkGraphService.getNetworkGraph());
- pathIntents = new PathIntentMap(networkGraphService.getNetworkGraph());
+ pathIntents = new PathIntentMap();
eventChannel = datagridService.createChannel(
EVENT_CHANNEL_NAME,
- byte[].class,
+ String.class,
IntentOperationList.class);
- }
-
- protected void publishPathIntentOperationList(IntentOperationList list) {
- eventChannel.addEntry(new byte[1], list); // TODO make key bytes
+ networkGraphService.registerNetworkGraphListener(this);
}
@Override
public IntentOperationList executeIntentOperations(IntentOperationList list) {
highLevelIntents.executeOperations(list);
IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, pathIntents);
+ String key = "..."; // TODO generate key
+ System.out.println(pathIntentOperations);
pathIntents.executeOperations(pathIntentOperations);
- publishPathIntentOperationList(pathIntentOperations);
+ eventChannel.addEntry(key, pathIntentOperations);
return pathIntentOperations;
}
@@ -95,4 +115,44 @@
highLevelIntents.purge();
pathIntents.purge();
}
+
+ @Override
+ public void putSwitchEvent(SwitchEvent switchEvent) {
+ // do nothing
+ }
+
+ @Override
+ public void removeSwitchEvent(SwitchEvent switchEvent) {
+ // do nothing
+ }
+
+ @Override
+ public void putPortEvent(PortEvent portEvent) {
+ // do nothing
+ }
+
+ @Override
+ public void removePortEvent(PortEvent portEvent) {
+ // do nothing
+ }
+
+ @Override
+ public void putLinkEvent(LinkEvent linkEvent) {
+ // do nothing
+ }
+
+ @Override
+ public void removeLinkEvent(LinkEvent linkEvent) {
+ reroutePaths(linkEvent);
+ }
+
+ @Override
+ public void putDeviceEvent(DeviceEvent deviceEvent) {
+ // do nothing
+ }
+
+ @Override
+ public void removeDeviceEvent(DeviceEvent deviceEvent) {
+ // do nothing
+ }
}
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
index 4582021..19a6b53 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
@@ -37,7 +37,7 @@
this.graph = graph;
this.flowEntries = new HashSet<>();
this.plan = new ArrayList<>();
- this.intents = new PathIntentMap(this.graph);
+ this.intents = new PathIntentMap();
}
public void addIntents(IntentOperationList intentOpList) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/Link.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/Link.java
index ef74f73..4fd53af 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/Link.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/Link.java
@@ -12,7 +12,7 @@
public Port getDestinationPort();
public Switch getSourceSwitch();
public Switch getDestinationSwitch();
-
+
public long getLastSeenTime();
public int getCost();
@@ -21,8 +21,12 @@
// Not sure if we want to expose these northbound
// Toshi: I think these are unnecessary because we can get them
// Toshi: like "this.getSourcePort().getSwitch()" etc.
+ @Deprecated
public Long getSourceSwitchDpid();
+ @Deprecated
public Long getSourcePortNumber();
+ @Deprecated
public Long getDestinationSwitchDpid();
+ @Deprecated
public Long getDestinationPortNumber();
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java
index c8cf71e..83af786 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkEvent.java
@@ -24,18 +24,23 @@
public LinkEvent(Long src_dpid, Long src_port_no, Long dst_dpid,
Long dst_port_no) {
-
src = new SwitchPort(src_dpid, src_port_no);
dst = new SwitchPort(dst_dpid, dst_port_no);
+ }
+ public LinkEvent(Link link) {
+ src = new SwitchPort(link.getSourceSwitch().getDpid(),
+ link.getSourcePort().getNumber());
+ dst = new SwitchPort(link.getDestinationSwitch().getDpid(),
+ link.getDestinationPort().getNumber());
}
public SwitchPort getSrc() {
- return src;
+ return src;
}
public SwitchPort getDst() {
- return dst;
+ return dst;
}
@Override
@@ -54,6 +59,47 @@
public byte[] getID() {
return getLinkID(src.getDpid(), src.getNumber(),
- dst.getDpid(), dst.getNumber());
+ dst.getDpid(), dst.getNumber());
}
-}
+
+ public Link getLink(NetworkGraph graph) {
+ Port srcPort = graph.getPort(getSrc().getDpid(), getSrc().getNumber());
+ if (srcPort == null) return null;
+ Link link = srcPort.getOutgoingLink();
+ if (link == null) return null;
+ if (link.getDestinationSwitch().getDpid() != getDst().getDpid()) return null;
+ if (link.getDestinationPort().getNumber() != getDst().getNumber()) return null;
+ return link;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((dst == null) ? 0 : dst.hashCode());
+ result = prime * result + ((src == null) ? 0 : src.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LinkEvent other = (LinkEvent) obj;
+ if (dst == null) {
+ if (other.dst != null)
+ return false;
+ } else if (!dst.equals(other.dst))
+ return false;
+ if (src == null) {
+ if (other.src != null)
+ return false;
+ } else if (!src.equals(other.src))
+ return false;
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkImpl.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkImpl.java
index c8954a9..801e780 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/LinkImpl.java
@@ -76,39 +76,43 @@
}
@Override
+ public Double getCapacity() {
+ return capacity;
+ }
+
+ public void setCapacity(Double capacity) {
+ this.capacity = capacity;
+ }
+
+ @Deprecated
+ @Override
public Long getSourceSwitchDpid() {
return srcPort.getSwitch().getDpid();
}
+ @Deprecated
@Override
public Long getSourcePortNumber() {
return srcPort.getNumber();
}
+ @Deprecated
@Override
public Long getDestinationSwitchDpid() {
return dstPort.getSwitch().getDpid();
}
+ @Deprecated
@Override
public Long getDestinationPortNumber() {
return dstPort.getNumber();
}
@Override
- public Double getCapacity() {
- return capacity;
- }
-
- @Override
public String toString() {
return String.format("%s --(cap:%f Mbps)--> %s",
getSourcePort().toString(),
getCapacity(),
getDestinationPort().toString());
}
-
- public void setCapacity(Double capacity) {
- this.capacity = capacity;
- }
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
index b42bf1e..8172f29 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/PortEvent.java
@@ -10,8 +10,8 @@
*/
public class PortEvent {
public static class SwitchPort {
- public final Long dpid;
- public final Long number;
+ public final Long dpid;
+ public final Long number;
/**
* Default constructor.
@@ -39,6 +39,37 @@
return "(" + Long.toHexString(dpid) + "@" + number + ")";
}
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((dpid == null) ? 0 : dpid.hashCode());
+ result = prime * result
+ + ((number == null) ? 0 : number.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SwitchPort other = (SwitchPort) obj;
+ if (dpid == null) {
+ if (other.dpid != null)
+ return false;
+ } else if (!dpid.equals(other.dpid))
+ return false;
+ if (number == null) {
+ if (other.number != null)
+ return false;
+ } else if (!number.equals(other.number))
+ return false;
+ return true;
+ }
}
private final SwitchPort id;
diff --git a/src/test/java/net/onrc/onos/intent/MockNetworkGraph.java b/src/test/java/net/onrc/onos/intent/MockNetworkGraph.java
index ce857de..263cbf4 100644
--- a/src/test/java/net/onrc/onos/intent/MockNetworkGraph.java
+++ b/src/test/java/net/onrc/onos/intent/MockNetworkGraph.java
@@ -1,12 +1,23 @@
package net.onrc.onos.intent;
+import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
import net.onrc.onos.ofcontroller.networkgraph.NetworkGraphImpl;
import net.onrc.onos.ofcontroller.networkgraph.Link;
import net.onrc.onos.ofcontroller.networkgraph.LinkImpl;
+import net.onrc.onos.ofcontroller.networkgraph.Port;
import net.onrc.onos.ofcontroller.networkgraph.Switch;
import net.onrc.onos.ofcontroller.networkgraph.SwitchImpl;
public class MockNetworkGraph extends NetworkGraphImpl {
+ class DetachableLinkImpl extends LinkImpl {
+ public DetachableLinkImpl(NetworkGraph graph, Port srcPort, Port dstPort) {
+ super(graph, srcPort, dstPort);
+ }
+
+ public void detachFromGraph() {
+ unsetFromPorts();
+ }
+ }
public Switch addSwitch(Long switchId) {
SwitchImpl sw = new SwitchImpl(this, switchId);
this.putSwitch(sw);
@@ -15,7 +26,7 @@
}
public Link addLink(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
- return new LinkImpl(
+ return new DetachableLinkImpl(
this,
getSwitch(srcDpid).getPort(srcPortNo),
getSwitch(dstDpid).getPort(dstPortNo));
@@ -63,4 +74,11 @@
((LinkImpl)link).setCapacity(1000.0);
}
}
+
+ public void removeLink(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
+ DetachableLinkImpl link = (DetachableLinkImpl)getSwitch(srcDpid).getPort(srcPortNo).getOutgoingLink();
+ if (link.getDestinationSwitch().getDpid().equals(dstDpid) && link.getDestinationPort().getNumber().equals(dstPortNo)) {
+ link.detachFromGraph();
+ }
+ }
}
diff --git a/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
index 8040141..d02cdee 100644
--- a/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
+++ b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
@@ -12,8 +12,9 @@
import net.onrc.onos.intent.PathIntent;
import net.onrc.onos.intent.PathIntentMap;
import net.onrc.onos.intent.ShortestPathIntent;
+import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphListener;
import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphService;
-import net.onrc.onos.ofcontroller.networkgraph.Link;
+import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
import org.easymock.EasyMock;
@@ -48,11 +49,12 @@
.andReturn(datagridService).once();
EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(INetworkGraphService.class)))
.andReturn(networkGraphService).once();
-
- networkGraphService.getNetworkGraph();
- EasyMock.expectLastCall().andReturn(g).anyTimes();
-
- EasyMock.expect(datagridService.createChannel("onos.pathintent", byte[].class, IntentOperationList.class))
+
+ EasyMock.expect(networkGraphService.getNetworkGraph()).andReturn(g).anyTimes();
+ networkGraphService.registerNetworkGraphListener(EasyMock.anyObject(INetworkGraphListener.class));
+ EasyMock.expectLastCall();
+
+ EasyMock.expect(datagridService.createChannel("onos.pathintent", String.class, IntentOperationList.class))
.andReturn(eventChannel).once();
EasyMock.replay(datagridService);
@@ -72,18 +74,14 @@
PathIntent pathIntent = (PathIntent)intent;
System.out.println("Parent intent: " + pathIntent.getParentIntent().toString());
System.out.println("Path:");
- for (Link link: pathIntent.getPath(g)) {
- System.out.printf("%s --(%f/%f)--> %s\n",
- link.getSourcePort(),
- link.getCapacity() - intents.getAvailableBandwidth(link),
- link.getCapacity(),
- link.getDestinationPort());
+ for (LinkEvent linkEvent: pathIntent.getPathByLinkEvent()) {
+ System.out.println(linkEvent);
}
}
}
@Test
- public void useCase1() throws FloodlightModuleException {
+ public void createShortestPaths() throws FloodlightModuleException {
// create shortest path intents
IntentOperationList opList = new IntentOperationList();
opList.add(Operator.ADD, new ShortestPathIntent("1", 1L, 20L, 1L, 4L, 20L, 4L));
@@ -106,7 +104,7 @@
}
@Test
- public void useCase2() throws FloodlightModuleException {
+ public void createConstrainedShortestPaths() throws FloodlightModuleException {
// create constrained shortest path intents
IntentOperationList opList = new IntentOperationList();
opList.add(Operator.ADD, new ConstrainedShortestPathIntent("1", 1L, 20L, 1L, 4L, 20L, 17L, 400.0));
@@ -131,8 +129,8 @@
}
@Test
- public void useCase3() throws FloodlightModuleException {
- // create constrained & not best effort shortest path intents
+ public void createMixedShortestPaths() throws FloodlightModuleException {
+ // create constrained & best effort shortest path intents
IntentOperationList opList = new IntentOperationList();
opList.add(Operator.ADD, new ConstrainedShortestPathIntent("1", 1L, 20L, 1L, 4L, 20L, 6L, 600.0));
opList.add(Operator.ADD, new ConstrainedShortestPathIntent("2", 2L, 20L, 2L, 6L, 20L, 7L, 600.0));
@@ -154,4 +152,41 @@
showResult((PathIntentMap) runtime1.getPathIntents());
System.out.println(runtime2.getPlan());
}
+
+ @Test
+ public void rerouteShortestPaths() throws FloodlightModuleException {
+ // create shortest path intents
+ IntentOperationList opList = new IntentOperationList();
+ opList.add(Operator.ADD, new ShortestPathIntent("1", 1L, 20L, 1L, 4L, 20L, 4L));
+ opList.add(Operator.ADD, new ShortestPathIntent("2", 2L, 20L, 2L, 6L, 20L, 5L));
+ opList.add(Operator.ADD, new ShortestPathIntent("3", 4L, 20L, 3L, 8L, 20L, 6L));
+
+ // compile high-level intent operations into low-level intent operations (calculate paths)
+ PathCalcRuntimeModule runtime1 = new PathCalcRuntimeModule();
+ runtime1.init(modContext);
+ runtime1.startUp(modContext);
+ IntentOperationList pathIntentOpList = runtime1.executeIntentOperations(opList);
+
+ // compile low-level intents into flow entry installation plan
+ PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
+ runtime2.addIntents(pathIntentOpList);
+
+ // show results step1
+ showResult((PathIntentMap) runtime1.getPathIntents());
+ System.out.println(runtime2.getPlan());
+
+ // link down
+ ((MockNetworkGraph)g).removeLink(1L, 2L, 9L, 1L); // This link is used by the intent "1"
+ LinkEvent linkEvent = new LinkEvent(1L, 2L, 9L, 1L);
+ runtime1.removeLinkEvent(linkEvent);
+ ((MockNetworkGraph)g).removeLink(9L, 1L, 1L, 2L);
+ linkEvent = new LinkEvent(9L, 1L, 1L, 2L);
+ runtime1.removeLinkEvent(linkEvent);
+
+ System.out.println("Link goes down.");
+
+ // show results step2
+ showResult((PathIntentMap) runtime1.getPathIntents());
+ System.out.println(runtime2.getPlan());
+ }
}