WIP: Initial implementation of runtime #2: take PathIntents and build a plan
Change-Id: I33acebecb76bd693f01a7440cee60c0fcfb49623
diff --git a/src/main/java/net/onrc/onos/intent/Action.java b/src/main/java/net/onrc/onos/intent/Action.java
new file mode 100644
index 0000000..ddf4474
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/Action.java
@@ -0,0 +1,11 @@
+package net.onrc.onos.intent;
+
+/**
+ *
+ * @author Brian O'Connor <bocon@onlab.us>
+ *
+ */
+
+public class Action {
+
+}
diff --git a/src/main/java/net/onrc/onos/intent/FlowEntry.java b/src/main/java/net/onrc/onos/intent/FlowEntry.java
new file mode 100644
index 0000000..4c52324
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/FlowEntry.java
@@ -0,0 +1,32 @@
+package net.onrc.onos.intent;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.networkgraph.Port;
+import net.onrc.onos.ofcontroller.networkgraph.Switch;
+
+/**
+ *
+ * @author Brian O'Connor <bocon@onlab.us>
+ *
+ */
+
+public class FlowEntry {
+ protected Switch sw;
+ protected Match match;
+ protected Set<Action> actions;
+
+ public FlowEntry(Switch sw, Port srcPort, Port dstPort,
+ MACAddress srcMac, MACAddress dstMac) {
+ this.sw = sw;
+ this.match = new Match(sw, srcPort, srcMac, dstMac);
+ this.actions = new HashSet<Action>();
+ this.actions.add(new ForwardAction(dstPort));
+ }
+
+ public String toString() {
+ return match + "->" + actions;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/intent/ForwardAction.java b/src/main/java/net/onrc/onos/intent/ForwardAction.java
new file mode 100644
index 0000000..245a918
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/ForwardAction.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.intent;
+
+import net.onrc.onos.ofcontroller.networkgraph.Port;
+
+/**
+ *
+ * @author Brian O'Connor <bocon@onlab.us>
+ *
+ */
+
+class ForwardAction extends Action {
+ protected Port dstPort;
+
+ public ForwardAction(Port dstPort) {
+ this.dstPort = dstPort;
+ }
+
+ public String toString() {
+ return dstPort.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/intent/Match.java b/src/main/java/net/onrc/onos/intent/Match.java
new file mode 100644
index 0000000..c81fe00
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/Match.java
@@ -0,0 +1,44 @@
+package net.onrc.onos.intent;
+
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.networkgraph.Port;
+import net.onrc.onos.ofcontroller.networkgraph.Switch;
+
+/**
+ *
+ * @author Brian O'Connor <bocon@onlab.us>
+ *
+ */
+
+public class Match {
+ protected Switch sw;
+ protected MACAddress srcMac;
+ protected MACAddress dstMac;
+ protected Port srcPort;
+
+ public Match(Switch sw, Port srcPort,
+ MACAddress srcMac, MACAddress dstMac) {
+ this.sw = sw;
+ this.srcPort = srcPort;
+ this.srcMac = srcMac;
+ this.dstMac = dstMac;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(obj instanceof Match) {
+ Match other = (Match) obj;
+ return this.sw == other.sw &&
+ this.srcMac == other.srcMac &&
+ this.dstMac == other.dstMac &&
+ this.srcPort == other.srcPort;
+ }
+ else {
+ return false;
+ }
+ }
+
+ public String toString() {
+ return "(" + srcPort + "," + srcMac + "," + dstMac + ")";
+ }
+}
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
new file mode 100644
index 0000000..9a46530
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
@@ -0,0 +1,108 @@
+package net.onrc.onos.intent.runtime;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.intent.FlowEntry;
+import net.onrc.onos.intent.Intent;
+import net.onrc.onos.intent.PathIntent;
+import net.onrc.onos.intent.PathIntents;
+import net.onrc.onos.intent.ShortestPathIntent;
+import net.onrc.onos.ofcontroller.networkgraph.Link;
+import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
+import net.onrc.onos.ofcontroller.networkgraph.Port;
+import net.onrc.onos.ofcontroller.networkgraph.Switch;
+
+/**
+ *
+ * @author Brian O'Connor <bocon@onlab.us>
+ *
+ */
+
+public class PlanCalcRuntime {
+ NetworkGraph graph;
+ protected PathIntents intents;
+ protected Set<Collection<FlowEntry>> flowEntries;
+ protected List<Set<FlowEntry>> plan;
+
+ public PlanCalcRuntime(NetworkGraph graph) {
+ this.graph = graph;
+ this.flowEntries = new HashSet<>();
+ this.plan = new ArrayList<>();
+ }
+
+ public void addIntents(PathIntents intents) {
+ this.intents = intents;
+ computeFlowEntries();
+ constructPlan();
+ }
+
+ public List<Set<FlowEntry>> getPlan() {
+ return plan;
+ }
+
+ public void computeFlowEntries() {
+ for(PathIntent intent : intents.getIntents()) {
+ Intent parent = intent.getParentIntent();
+ Port srcPort, dstPort, lastDstPort = null;
+ MACAddress srcMac, dstMac;
+ if(parent instanceof ShortestPathIntent) {
+ ShortestPathIntent pathIntent = (ShortestPathIntent) parent;
+ Switch srcSwitch = graph.getSwitch(pathIntent.getSrcSwitchDpid());
+ srcPort = srcSwitch.getPort(pathIntent.getSrcPortNumber());
+ srcMac = MACAddress.valueOf(pathIntent.getSrcMac());
+ dstMac = MACAddress.valueOf(pathIntent.getDstMac());
+ Switch dstSwitch = graph.getSwitch(pathIntent.getDstSwitchDpid());
+ lastDstPort = dstSwitch.getPort(pathIntent.getDstPortNumber());
+ }
+ else {
+ // TODO: log this error
+ continue;
+ }
+ List<FlowEntry> entries = new ArrayList<>();
+ for(Link link : intent.getPath(graph)) {
+ Switch sw = link.getSourceSwitch();
+ dstPort = link.getSourcePort();
+ FlowEntry fe = new FlowEntry(sw, srcPort, dstPort, srcMac, dstMac);
+ entries.add(fe);
+ srcPort = link.getDestinationPort();
+ }
+ if(lastDstPort != null) {
+ Switch sw = lastDstPort.getSwitch();
+ dstPort = lastDstPort;
+ FlowEntry fe = new FlowEntry(sw, srcPort, dstPort, srcMac, dstMac);
+ entries.add(fe);
+ }
+ // install flow entries in reverse order
+ Collections.reverse(entries);
+ flowEntries.add(entries);
+ }
+ }
+
+ public void constructPlan() {
+ Map<FlowEntry, Integer> map = new HashMap<>();
+ for(Collection<FlowEntry> c : flowEntries) {
+ for(FlowEntry e: c) {
+ Integer i = map.get(e);
+ if(i == null) {
+ map.put(e, 1);
+ }
+ else {
+ i += 1;
+ }
+
+ }
+ }
+
+ // really simple first iteration of plan
+ //TODO: optimize the map in phases
+ plan.add(map.keySet());
+ }
+}
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 e2a9a64..d31b9b6 100644
--- a/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
+++ b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
@@ -56,9 +56,14 @@
// compile high-level intents into low-level intents (calculate paths)
PathCalcRuntime runtime1 = new PathCalcRuntime(g);
runtime1.addInputIntents(intents);
+
+ // compile low-level intents into flow entry installation plan
+ PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
+ runtime2.addIntents(runtime1.getOutputIntents());
// show results
showResult(runtime1.getOutputIntents());
+ System.out.println(runtime2.getPlan());
}
@Test
@@ -75,8 +80,13 @@
PathCalcRuntime runtime1 = new PathCalcRuntime(g);
runtime1.addInputIntents(intents);
+ // compile low-level intents into flow entry installation plan
+ PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
+ runtime2.addIntents(runtime1.getOutputIntents());
+
// show results
showResult(runtime1.getOutputIntents());
+ System.out.println(runtime2.getPlan());
}
@Test
@@ -93,7 +103,12 @@
PathCalcRuntime runtime1 = new PathCalcRuntime(g);
runtime1.addInputIntents(intents);
+ // compile low-level intents into flow entry installation plan
+ PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
+ runtime2.addIntents(runtime1.getOutputIntents());
+
// show results
showResult(runtime1.getOutputIntents());
+ System.out.println(runtime2.getPlan());
}
}