Added Intent Subscriber and Module
Module is used to drive plan computation and installation
Also, added support for ADD/REMOVE in plan computation
Change-Id: Ib88eae8b13a1f5ed1503c5ff7762980f8ed032ac
diff --git a/conf/onos.properties b/conf/onos.properties
index 04e436b..508ffef 100644
--- a/conf/onos.properties
+++ b/conf/onos.properties
@@ -7,6 +7,7 @@
net.onrc.onos.ofcontroller.flowprogrammer.FlowProgrammer,\
net.onrc.onos.ofcontroller.topology.TopologyManager,\
net.onrc.onos.intent.runtime.PathCalcRuntimeModule,\
+net.onrc.onos.intent.runtime.PlanInstallModule,\
net.onrc.onos.registry.controller.ZookeeperRegistry
net.floodlightcontroller.restserver.RestApiServer.port = 8080
net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
diff --git a/src/main/java/net/onrc/onos/intent/FlowEntry.java b/src/main/java/net/onrc/onos/intent/FlowEntry.java
index 14d1038..13bfa21 100644
--- a/src/main/java/net/onrc/onos/intent/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/intent/FlowEntry.java
@@ -4,11 +4,13 @@
import java.util.Set;
import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.intent.IntentOperation.Operator;
import net.onrc.onos.ofcontroller.networkgraph.Port;
import net.onrc.onos.ofcontroller.networkgraph.Switch;
import net.onrc.onos.ofcontroller.util.Dpid;
import net.onrc.onos.ofcontroller.util.FlowEntryActions;
import net.onrc.onos.ofcontroller.util.FlowEntryId;
+import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
/**
*
@@ -20,13 +22,16 @@
protected Switch sw;
protected Match match;
protected Set<Action> actions;
+ protected Operator operator;
public FlowEntry(Switch sw, Port srcPort, Port dstPort,
- MACAddress srcMac, MACAddress dstMac) {
+ MACAddress srcMac, MACAddress dstMac,
+ Operator operator) {
this.sw = sw;
this.match = new Match(sw, srcPort, srcMac, dstMac);
this.actions = new HashSet<Action>();
this.actions.add(new ForwardAction(dstPort));
+ this.operator = operator;
}
public String toString() {
@@ -37,6 +42,14 @@
return sw;
}
+ public Operator getOperator() {
+ return operator;
+ }
+
+ public void setOperator(Operator op) {
+ operator = op;
+ }
+
public net.onrc.onos.ofcontroller.util.FlowEntry getFlowEntry() {
net.onrc.onos.ofcontroller.util.FlowEntry entry = new net.onrc.onos.ofcontroller.util.FlowEntry();
entry.setDpid(new Dpid(sw.getDpid()));
@@ -47,6 +60,17 @@
flowEntryActions.addAction(action.getFlowEntryAction());
}
entry.setFlowEntryActions(flowEntryActions);
+ switch(operator) {
+ case ADD:
+ entry.setFlowEntryUserState(FlowEntryUserState.FE_USER_MODIFY);
+ break;
+ case REMOVE:
+ entry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
+ break;
+ }
return entry;
}
+
+ //TODO: implement hash for cookie
+ //TODO: implement equals (don't include operator!)
}
\ No newline at end of file
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 18e962f..63892cb 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanCalcRuntime.java
@@ -12,9 +12,10 @@
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.intent.FlowEntry;
import net.onrc.onos.intent.Intent;
+import net.onrc.onos.intent.IntentOperation;
+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.intent.ShortestPathIntent;
import net.onrc.onos.ofcontroller.networkgraph.Link;
import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
@@ -29,88 +30,103 @@
*/
public class PlanCalcRuntime {
- NetworkGraph graph;
- protected PathIntentMap 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<>();
- this.intents = new PathIntentMap();
+ NetworkGraph graph;
+
+ public PlanCalcRuntime(NetworkGraph graph) {
+ this.graph = graph;
+ }
+
+ public List<Set<FlowEntry>> computePlan(IntentOperationList intentOps) {
+ Set<Collection<FlowEntry>> flowEntries = computeFlowEntries(intentOps);
+ return buildPhases(flowEntries);
+ }
+
+ private Set<Collection<FlowEntry>> computeFlowEntries(IntentOperationList intentOps) {
+ Set<Collection<FlowEntry>> flowEntries = new HashSet<>();
+ for(IntentOperation i : intentOps) {
+ PathIntent intent = (PathIntent) i.intent;
+ 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(LinkEvent linkEvent : intent.getPath()) {
+ Link link = graph.getLink(linkEvent.getSrc().getDpid(),
+ linkEvent.getSrc().getNumber(),
+ linkEvent.getDst().getDpid(),
+ linkEvent.getDst().getNumber());
+ Switch sw = link.getSrcSwitch();
+ dstPort = link.getSrcPort();
+ FlowEntry fe = new FlowEntry(sw, srcPort, dstPort, srcMac, dstMac, i.operator);
+ entries.add(fe);
+ srcPort = link.getDstPort();
+ }
+ if(lastDstPort != null) {
+ Switch sw = lastDstPort.getSwitch();
+ dstPort = lastDstPort;
+ FlowEntry fe = new FlowEntry(sw, srcPort, dstPort, srcMac, dstMac, i.operator);
+ entries.add(fe);
+ }
+ // install flow entries in reverse order
+ Collections.reverse(entries);
+ flowEntries.add(entries);
}
+ return flowEntries;
+ }
- public void addIntents(IntentOperationList intentOpList) {
- intents.executeOperations(intentOpList);
- computeFlowEntries();
- constructPlan();
- }
-
- public List<Set<FlowEntry>> getPlan() {
- return plan;
- }
-
- public void computeFlowEntries() {
- for(Intent i : intents.getAllIntents()) {
- PathIntent intent = (PathIntent)i;
- 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(LinkEvent linkEvent : intent.getPath()) {
- Link link = graph.getLink(linkEvent.getSrc().getDpid(),
- linkEvent.getSrc().getNumber(),
- linkEvent.getDst().getDpid(),
- linkEvent.getDst().getNumber());
- Switch sw = link.getSrcSwitch();
- dstPort = link.getSrcPort();
- FlowEntry fe = new FlowEntry(sw, srcPort, dstPort, srcMac, dstMac);
- entries.add(fe);
- srcPort = link.getDstPort();
- }
- 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);
+ private List<Set<FlowEntry>> buildPhases(Set<Collection<FlowEntry>> flowEntries) {
+ Map<FlowEntry, Integer> map = new HashMap<>();
+ List<Set<FlowEntry>> plan = new ArrayList<>();
+ for(Collection<FlowEntry> c : flowEntries) {
+ for(FlowEntry e : c) {
+ Integer i = map.get(e);
+ if(i == null) {
+ i = Integer.valueOf(0);
}
- }
-
- 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;
- }
-
- }
+ switch(e.getOperator()) {
+ case ADD:
+ i += 1;
+ break;
+ case REMOVE:
+ i -= 1;
+ break;
}
-
- // really simple first iteration of plan
- //TODO: optimize the map in phases
- plan.add(map.keySet());
+ map.put(e, i);
+ System.out.println(e + " " + e.getOperator());
+ }
}
+
+ // really simple first iteration of plan
+ //TODO: optimize the map in phases
+ Set<FlowEntry> phase = new HashSet<>();
+ for(FlowEntry e : map.keySet()) {
+ Integer i = map.get(e);
+ if(i == 0) {
+ continue;
+ }
+ else if(i > 0) {
+ e.setOperator(Operator.ADD);
+ }
+ else if(i < 0) {
+ e.setOperator(Operator.REMOVE);
+ }
+ phase.add(e);
+ }
+ plan.add(phase);
+
+ return plan;
+ }
}
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
new file mode 100644
index 0000000..df4c762
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
@@ -0,0 +1,116 @@
+package net.onrc.onos.intent.runtime;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.onrc.onos.datagrid.IDatagridService;
+import net.onrc.onos.datagrid.IEventChannelListener;
+import net.onrc.onos.intent.FlowEntry;
+import net.onrc.onos.intent.IntentOperationList;
+import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
+import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
+
+public class PlanInstallModule implements IFloodlightModule {
+ protected volatile IFloodlightProviderService floodlightProvider;
+ protected volatile NetworkGraph networkGraph;
+ protected volatile IDatagridService datagridService;
+ protected volatile IFlowPusherService flowPusher;
+ private PlanCalcRuntime planCalc;
+ private PlanInstallRuntime planInstall;
+ private EventListener eventListener;
+
+ private static final String PATH_INTENT_CHANNEL_NAME = "onos.pathintent";
+
+ @Override
+ public void init(FloodlightModuleContext context)
+ throws FloodlightModuleException {
+ floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+ //networkGraph = context.getServiceImpl(INetworkGraphService.class);
+ datagridService = context.getServiceImpl(IDatagridService.class);
+ flowPusher = context.getServiceImpl(IFlowPusherService.class);
+ planCalc = new PlanCalcRuntime(networkGraph);
+ planInstall = new PlanInstallRuntime(networkGraph, floodlightProvider, flowPusher);
+ eventListener = new EventListener();
+ }
+
+ class EventListener extends Thread
+ implements IEventChannelListener<Long, IntentOperationList> {
+
+ private BlockingQueue<IntentOperationList> intentQueue = new LinkedBlockingQueue<>();
+
+ @Override
+ public void run() {
+ while(true) {
+ try {
+ IntentOperationList intents = intentQueue.take();
+ //TODO: drain the remaining intent lists
+ processIntents(intents);
+ } catch (InterruptedException e) {
+ //TODO: log the exception
+ }
+ }
+ }
+
+ private void processIntents(IntentOperationList intents) {
+ List<Set<FlowEntry>> plan = planCalc.computePlan(intents);
+ planInstall.installPlan(plan);
+ }
+
+ @Override
+ public void entryAdded(IntentOperationList value) {
+ intentQueue.add(value);
+ }
+
+ @Override
+ public void entryRemoved(IntentOperationList value) {
+ // This channel is a queue, so this method is not needed
+ }
+
+ @Override
+ public void entryUpdated(IntentOperationList value) {
+ // This channel is a queue, so this method is not needed
+ }
+ }
+ @Override
+ public void startUp(FloodlightModuleContext context) {
+ eventListener.start();
+ datagridService.addListener(PATH_INTENT_CHANNEL_NAME,
+ new EventListener(),
+ Long.class,
+ IntentOperationList.class);
+ }
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+ Collection<Class<? extends IFloodlightService>> l =
+ new ArrayList<Class<? extends IFloodlightService>>();
+ l.add(IFloodlightProviderService.class);
+// l.add(INetworkGraphService.class);
+ l.add(IDatagridService.class);
+ l.add(IFlowPusherService.class);
+ return l;
+ }
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathInstallRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
similarity index 81%
rename from src/main/java/net/onrc/onos/intent/runtime/PathInstallRuntime.java
rename to src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
index 0b74cfc..3e4ff4a 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PathInstallRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
@@ -18,22 +18,23 @@
*
*/
-public class PathInstallRuntime {
+public class PlanInstallRuntime {
NetworkGraph graph;
IFlowPusherService pusher;
IFloodlightProviderService provider;
- protected List<Set<FlowEntry>> plan;
- public PathInstallRuntime(NetworkGraph graph) {
+ public PlanInstallRuntime(NetworkGraph graph,
+ IFloodlightProviderService provider,
+ IFlowPusherService pusher) {
this.graph = graph;
+ this.provider = provider;
+ this.pusher = pusher;
}
public void installPlan(List<Set<FlowEntry>> plan) {
- this.plan = plan;
Map<Long,IOFSwitch> switches = provider.getSwitches();
for(Set<FlowEntry> phase : plan) {
- Set<Pair<IOFSwitch, net.onrc.onos.ofcontroller.util.FlowEntry>> entries
- = new HashSet<>();
+ Set<Pair<IOFSwitch, net.onrc.onos.ofcontroller.util.FlowEntry>> entries = new HashSet<>();
// convert flow entries and create pairs
for(FlowEntry entry : phase) {
entries.add(new Pair<>(switches.get(entry.getSwitch().getDpid()),
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 02703fc..a1f3e80 100644
--- a/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
+++ b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
@@ -1,10 +1,14 @@
package net.onrc.onos.intent.runtime;
+import java.util.List;
+import java.util.Set;
+
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.onrc.onos.datagrid.IDatagridService;
import net.onrc.onos.datagrid.IEventChannel;
import net.onrc.onos.intent.ConstrainedShortestPathIntent;
+import net.onrc.onos.intent.FlowEntry;
import net.onrc.onos.intent.Intent;
import net.onrc.onos.intent.IntentOperation.Operator;
import net.onrc.onos.intent.IntentOperationList;
@@ -96,11 +100,11 @@
// compile low-level intents into flow entry installation plan
PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
- runtime2.addIntents(pathIntentOpList);
+ List<Set<FlowEntry>> plan = runtime2.computePlan(pathIntentOpList);
// show results
showResult((PathIntentMap) runtime1.getPathIntents());
- System.out.println(runtime2.getPlan());
+ System.out.println(plan);
}
@Test
@@ -121,11 +125,11 @@
// compile low-level intents into flow entry installation plan
PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
- runtime2.addIntents(pathIntentOpList);
+ List<Set<FlowEntry>> plan = runtime2.computePlan(pathIntentOpList);
// show results
showResult((PathIntentMap) runtime1.getPathIntents());
- System.out.println(runtime2.getPlan());
+ System.out.println(plan);
}
@Test
@@ -146,11 +150,11 @@
// compile low-level intents into flow entry installation plan
PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
- runtime2.addIntents(pathIntentOpList);
+ List<Set<FlowEntry>> plan = runtime2.computePlan(pathIntentOpList);
// show results
showResult((PathIntentMap) runtime1.getPathIntents());
- System.out.println(runtime2.getPlan());
+ System.out.println(plan);
}
@Test
@@ -169,11 +173,11 @@
// compile low-level intents into flow entry installation plan
PlanCalcRuntime runtime2 = new PlanCalcRuntime(g);
- runtime2.addIntents(pathIntentOpList);
+ List<Set<FlowEntry>> plan = runtime2.computePlan(pathIntentOpList);
// show results step1
showResult((PathIntentMap) runtime1.getPathIntents());
- System.out.println(runtime2.getPlan());
+ System.out.println(plan);
// link down
((MockNetworkGraph)g).removeLink(1L, 2L, 9L, 1L); // This link is used by the intent "1"
@@ -187,6 +191,6 @@
// show results step2
showResult((PathIntentMap) runtime1.getPathIntents());
- System.out.println(runtime2.getPlan());
+ // TODO: show results of plan computation
}
}