Skeletons for Intent-runtime, Flow-manager and Match-action modules.
This task is a part of ONOS-1395.
(Sub-tasks: ONOS-1397, ONOS-1398, ONOS-1400)
Change-Id: I30064f658b6c193aee8419079dad380163364475
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/ConflictDetectionPolicy.java b/src/main/java/net/onrc/onos/api/flowmanager/ConflictDetectionPolicy.java
new file mode 100644
index 0000000..6d54450
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/ConflictDetectionPolicy.java
@@ -0,0 +1,21 @@
+package net.onrc.onos.api.flowmanager;
+
+/**
+ * Conflict detection policies for the flow manager.
+ */
+public enum ConflictDetectionPolicy {
+ /**
+ * Do not allow overlap flow-space on any ingress port.
+ */
+ STRICT,
+
+ /**
+ * Keep control of packets flowing through each specified path, tree, etc.
+ */
+ LOOSE,
+
+ /**
+ * No limitation (accepts all, handles by priority).
+ */
+ FREE
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/FlowLink.java b/src/main/java/net/onrc/onos/api/flowmanager/FlowLink.java
new file mode 100644
index 0000000..474ac75
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/FlowLink.java
@@ -0,0 +1,102 @@
+package net.onrc.onos.api.flowmanager;
+
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.PortNumber;
+import net.onrc.onos.core.util.SwitchPort;
+
+/**
+ * A link representation used by IFlow objects.
+ * <p>
+ * TODO: Should lambda, bandwidth, tag, etc. be defined in this FlowLink, Path,
+ * Tree or IFlow? We have to define it.
+ */
+public class FlowLink {
+ protected SwitchPort srcSwitchPort;
+ protected SwitchPort dstSwitchPort;
+
+ /**
+ * Creates new FlowLink object using source/destination switch port pair.
+ *
+ * @param src The source switch port.
+ * @param dst The destination switch port.
+ */
+ public FlowLink(SwitchPort src, SwitchPort dst) {
+ this.srcSwitchPort = src;
+ this.dstSwitchPort = dst;
+ }
+
+ /**
+ * Creates new FlowLink object using DPID and port number pairs at
+ * source/destination switches.
+ *
+ * @param srcDpid The source switch DPID.
+ * @param srcPortNumber The source port number at the source switch.
+ * @param dstDpid The destination switch DPID.
+ * @param dstPortNumber The destination port number at the destination
+ * switch.
+ */
+ public FlowLink(Dpid srcDpid, PortNumber srcPortNumber,
+ Dpid dstDpid, PortNumber dstPortNumber) {
+ this.srcSwitchPort = new SwitchPort(srcDpid, srcPortNumber);
+ this.dstSwitchPort = new SwitchPort(dstDpid, dstPortNumber);
+ }
+
+ /**
+ * Gets the source switch port.
+ *
+ * @return The source switch port.
+ */
+ public SwitchPort getSrcSwitchPort() {
+ return srcSwitchPort;
+ }
+
+ /**
+ * Gets the source switch DPID.
+ *
+ * @return The source switch DPID.
+ */
+ public Dpid getSrcDpid() {
+ return srcSwitchPort.dpid();
+ }
+
+ /**
+ * Gets the source port number at the source switch.
+ *
+ * @return The source port number at the source switch.
+ */
+ public PortNumber getSrcPortNumber() {
+ return srcSwitchPort.port();
+ }
+
+ /**
+ * Gets the destination switch port.
+ *
+ * @return The destination switch port.
+ */
+ public SwitchPort getDstSwitchPort() {
+ return dstSwitchPort;
+ }
+
+ /**
+ * Gets the destination switch DPID.
+ *
+ * @return The destination switch DPID.
+ */
+ public Dpid getDstDpid() {
+ return dstSwitchPort.dpid();
+ }
+
+ /**
+ * Gets the destination port number at the destination switch.
+ *
+ * @return The destination port number at the destination switch.
+ */
+ public PortNumber getDstPortNumber() {
+ return dstSwitchPort.port();
+ }
+
+ @Override
+ public String toString() {
+ return srcSwitchPort + "-->" + dstSwitchPort;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/FlowLinks.java b/src/main/java/net/onrc/onos/api/flowmanager/FlowLinks.java
new file mode 100644
index 0000000..3d2d771
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/FlowLinks.java
@@ -0,0 +1,139 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * A list of FlowLink objects.
+ */
+public class FlowLinks implements List<FlowLink> {
+ protected final List<FlowLink> links = new LinkedList<FlowLink>();
+
+ @Override
+ public int size() {
+ return links.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return links.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return links.contains(o);
+ }
+
+ @Override
+ public Iterator<FlowLink> iterator() {
+ return links.iterator();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return links.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return links.toArray(a);
+ }
+
+ @Override
+ public boolean add(FlowLink e) {
+ return links.add(e);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return links.remove(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return links.containsAll(c);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends FlowLink> c) {
+ return links.addAll(c);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends FlowLink> c) {
+ return links.addAll(index, c);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ return links.removeAll(c);
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ return links.retainAll(c);
+ }
+
+ @Override
+ public void clear() {
+ links.clear();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return links.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return links.hashCode();
+ }
+
+ @Override
+ public FlowLink get(int index) {
+ return links.get(index);
+ }
+
+ @Override
+ public FlowLink set(int index, FlowLink element) {
+ return links.set(index, element);
+ }
+
+ @Override
+ public void add(int index, FlowLink element) {
+ links.add(index, element);
+ }
+
+ @Override
+ public FlowLink remove(int index) {
+ return links.remove(index);
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return links.indexOf(o);
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return links.lastIndexOf(o);
+ }
+
+ @Override
+ public ListIterator<FlowLink> listIterator() {
+ return links.listIterator();
+ }
+
+ @Override
+ public ListIterator<FlowLink> listIterator(int index) {
+ return links.listIterator(index);
+ }
+
+ @Override
+ public List<FlowLink> subList(int fromIndex, int toIndex) {
+ return links.subList(fromIndex, toIndex);
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/IFlow.java b/src/main/java/net/onrc/onos/api/flowmanager/IFlow.java
new file mode 100644
index 0000000..66f116a
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/IFlow.java
@@ -0,0 +1,38 @@
+package net.onrc.onos.api.flowmanager;
+
+import net.onrc.onos.api.batchoperation.IBatchOperationTarget;
+import net.onrc.onos.core.matchaction.MatchActionPlan;
+import net.onrc.onos.core.matchaction.match.IMatch;
+
+/**
+ * An interface class to define flow object which is managed by
+ * FlowManagerModule.
+ * <p>
+ * The flow objects (eg. path, tree, disjoint-paths, etc.) must implement this
+ * interface.
+ */
+public interface IFlow extends IBatchOperationTarget {
+ /**
+ * Gets ID for this flow object.
+ *
+ * @return ID for this object.
+ */
+ @Override
+ public String getId();
+
+ /**
+ * Gets traffic filter for this flow object.
+ *
+ * @return a traffic filter for this flow object.
+ */
+ public IMatch getMatch();
+
+ /**
+ * Compiles this object to MatchAction plan.
+ * <p>
+ * This method is called by FlowManagerModule to create MatchAction plans.
+ *
+ * @return a MatchAction plan of this flow object.
+ */
+ public MatchActionPlan compile();
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/IFlowManagerService.java b/src/main/java/net/onrc/onos/api/flowmanager/IFlowManagerService.java
new file mode 100644
index 0000000..edd3c85
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/IFlowManagerService.java
@@ -0,0 +1,97 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.Collection;
+import java.util.EventListener;
+
+import net.onrc.onos.api.batchoperation.BatchOperation;
+
+/**
+ * An interface class for flow manager. The role of the flow manager is to
+ * manage a set of Match-Action entries based on the specified IFlow objects.
+ * <p>
+ * It compiles accepted IFlow objects to Match-Action entries by calculating the
+ * match-action operation phases and allocating resources based on the
+ * constrains described in the IFlow objects, and executes calculated phases
+ * using Match-Action Service.
+ * <p>
+ * TODO: add more getter with filter for IFlow objects.
+ */
+public interface IFlowManagerService {
+ /**
+ * Adds IFlow object, calculates match-action plan and executes it.
+ *
+ * @param flow IFlow object to be added.
+ * @return true if succeeded, false otherwise.
+ */
+ boolean addFlow(IFlow flow);
+
+ /**
+ * Removes IFlow object, calculates match-action plan and executes it.
+ *
+ * @param id ID for IFlow object to be removed.
+ * @return true if succeeded, false otherwise.
+ */
+ boolean removeFlow(String id);
+
+ /**
+ * Updates IFlow object, calculates match-action plan and executes it.
+ * <p>
+ * The IFlow object having the ID which is the same to the ID of the IFlow
+ * object specified by the parameter will be updated.
+ *
+ * @param flow new IFlow object for the update.
+ * @return true if succeeded, false otherwise.
+ */
+ boolean updateFlow(IFlow flow);
+
+ /**
+ * Gets IFlow object.
+ *
+ * @param id ID of IFlow object.
+ * @return IFlow object if found, null otherwise.
+ */
+ IFlow getFlow(String id);
+
+ /**
+ * Gets All IFlow objects.
+ *
+ * @return the collection of IFlow objects.
+ */
+ Collection<IFlow> getFlows();
+
+ /**
+ * Executes batch operation of IFlow object.
+ *
+ * @param ops FlowOperations to be executed.
+ * @return true if succeeded, false otherwise.
+ */
+ boolean executeBatch(BatchOperation<IFlow> ops);
+
+ /**
+ * Sets a conflict detection policy.
+ *
+ * @param policy ConflictDetectionPolicy object to be set.
+ */
+ void setConflictDetectionPolicy(ConflictDetectionPolicy policy);
+
+ /**
+ * Gets the conflict detection policy.
+ *
+ * @return ConflictDetectionPolicy object being applied currently.
+ */
+ ConflictDetectionPolicy getConflictDetectionPolicy();
+
+ /**
+ * Adds event listener to this service.
+ *
+ * @param listener EventListener to be added.
+ */
+ void addEventListener(EventListener listener);
+
+ /**
+ * Removes event listener from this service.
+ *
+ * @param listener EventListener to be removed.
+ */
+ void removeEventListener(EventListener listener);
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/OpticalPathFlow.java b/src/main/java/net/onrc/onos/api/flowmanager/OpticalPathFlow.java
new file mode 100644
index 0000000..00a4785
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/OpticalPathFlow.java
@@ -0,0 +1,48 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.List;
+
+import net.onrc.onos.core.matchaction.MatchActionPlan;
+import net.onrc.onos.core.matchaction.action.IAction;
+import net.onrc.onos.core.util.PortNumber;
+
+/**
+ * IFlow object representing an optical path.
+ * <p>
+ * TODO: Think this: How do we deal the optical path flow going through the
+ * regenerators? Can we express it with multiple OpticalPathFlow objects?
+ */
+public class OpticalPathFlow extends PathFlow {
+ protected int lambda;
+
+ /**
+ * Constructor.
+ *
+ * @param id ID for this new IFlow object.
+ * @param inPort Ingress port number at the ingress edge node.
+ * @param path Path between ingress and egress edge node.
+ * @param actions The list of IAction objects at the egress edge node.
+ * @param lambda The lambda to be used throughout the path.
+ */
+ public OpticalPathFlow(String id,
+ PortNumber inPort, Path path, List<IAction> actions, int lambda) {
+ super(id, null, inPort, path, actions);
+ this.lambda = lambda;
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * Gets lambda which is used throughout the path.
+ *
+ * @return lambda which is used throughout the path.
+ */
+ public int getLambda() {
+ return lambda;
+ }
+
+ @Override
+ public MatchActionPlan compile() {
+ // TODO Auto-generated method stub
+ return super.compile();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/PacketPathFlow.java b/src/main/java/net/onrc/onos/api/flowmanager/PacketPathFlow.java
new file mode 100644
index 0000000..087ef47
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/PacketPathFlow.java
@@ -0,0 +1,61 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.List;
+
+import net.onrc.onos.core.matchaction.MatchActionPlan;
+import net.onrc.onos.core.matchaction.action.IAction;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.util.PortNumber;
+
+/**
+ * IFlow object representing a packet path.
+ * <p>
+ * TODO: Think this: Do we need a bandwidth constraint?
+ */
+public class PacketPathFlow extends PathFlow {
+ private int hardTimeout;
+ private int idleTimeout;
+
+ /**
+ * Constructor.
+ *
+ * @param id ID for this new IFlow object.
+ * @param match Match object at the source node of the path.
+ * @param inPort Ingress port number at the ingress edge node.
+ * @param path Path between ingress and egress edge node.
+ * @param edgeActions The list of IAction objects at the egress edge node.
+ * @param hardTimeout hard-timeout value.
+ * @param idleTimeout idle-timeout value.
+ */
+ public PacketPathFlow(String id,
+ PacketMatch match, PortNumber inPort, Path path, List<IAction> edgeActions,
+ int hardTimeout, int idleTimeout) {
+ super(id, match, inPort, path, edgeActions);
+ this.hardTimeout = hardTimeout;
+ this.idleTimeout = idleTimeout;
+ }
+
+ /**
+ * Gets idle-timeout value.
+ *
+ * @return Idle-timeout value (seconds)
+ */
+ public int getIdleTimeout() {
+ return idleTimeout;
+ }
+
+ /**
+ * Gets hard-timeout value.
+ *
+ * @return Hard-timeout value (seconds)
+ */
+ public int getHardTimeout() {
+ return hardTimeout;
+ }
+
+ @Override
+ public MatchActionPlan compile() {
+ // TODO Auto-generated method stub
+ return super.compile();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/Path.java b/src/main/java/net/onrc/onos/api/flowmanager/Path.java
new file mode 100644
index 0000000..df61e51
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/Path.java
@@ -0,0 +1,79 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import net.onrc.onos.core.util.Dpid;
+
+/**
+ * Path representation for the flow manager.
+ */
+public class Path extends FlowLinks {
+ /**
+ * Default constructor to create an empty path.
+ */
+ public Path() {
+ super();
+ }
+
+ /**
+ * Gets a list of switch DPIDs of the path.
+ *
+ * @return a list of Dpid objects
+ */
+ public List<Dpid> getDpids() {
+ if (size() < 1) {
+ return null;
+ }
+
+ List<Dpid> dpids = new ArrayList<Dpid>(size() + 1);
+ dpids.add(getSrcDpid());
+ for (FlowLink link: this) {
+ dpids.add(link.getDstDpid());
+ }
+ return dpids;
+ }
+
+ /**
+ * Gets the DPID of the first switch.
+ *
+ * @return a Dpid object of the first switch.
+ */
+ public Dpid getSrcDpid() {
+ if (size() < 1) {
+ return null;
+ }
+ return get(0).getSrcDpid();
+ }
+
+ /**
+ * Gets the DPID of the last switch.
+ *
+ * @return a Dpid object of the last switch.
+ */
+ public Dpid getDstDpid() {
+ if (size() < 1) {
+ return null;
+ }
+ return get(size() - 1).getDstDpid();
+ }
+
+ /**
+ * Returns a string representation of the path.
+ *
+ * @return a string representation of the path.
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ Iterator<FlowLink> i = this.iterator();
+ while (i.hasNext()) {
+ builder.append(i.next().toString());
+ if (i.hasNext()) {
+ builder.append(", ");
+ }
+ }
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/PathFlow.java b/src/main/java/net/onrc/onos/api/flowmanager/PathFlow.java
new file mode 100644
index 0000000..baf163f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/PathFlow.java
@@ -0,0 +1,84 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.List;
+
+import net.onrc.onos.core.matchaction.MatchActionPlan;
+import net.onrc.onos.core.matchaction.action.IAction;
+import net.onrc.onos.core.matchaction.match.IMatch;
+import net.onrc.onos.core.util.PortNumber;
+
+/**
+ * A path flow.
+ * <p>
+ * TODO: Think this: Should this class be an abstract class? Is it enough to
+ * have only the PacketPathFlow and OpticalPathFlow classes?
+ */
+public class PathFlow implements IFlow {
+ protected final String id;
+ protected IMatch match;
+ protected PortNumber ingressPort;
+ protected Path path;
+ protected List<IAction> edgeActions;
+
+ /**
+ * Constructor.
+ *
+ * @param id ID for this new PathFlow object.
+ * @param match Match object at the ingress node of the path.
+ * @param ingressPort The ingress port number at the ingress node of the
+ * path.
+ * @param path Path between ingress and egress edge node.
+ * @param edgeActions The list of IAction objects at the egress edge node.
+ */
+ public PathFlow(String id,
+ IMatch match, PortNumber ingressPort, Path path, List<IAction> edgeActions) {
+ this.id = id;
+ this.match = match;
+ this.ingressPort = ingressPort;
+ this.path = path;
+ this.edgeActions = edgeActions;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public IMatch getMatch() {
+ return match;
+ }
+
+ @Override
+ public MatchActionPlan compile() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Gets the ingress port number at the ingress node of the path.
+ *
+ * @return The ingress port number at the ingress node of the path.
+ */
+ public PortNumber getIngressPortNumber() {
+ return ingressPort;
+ }
+
+ /**
+ * Gets the path from ingress to egress edge node.
+ *
+ * @return The path object from ingress to egress edge node.
+ */
+ public Path getPath() {
+ return path;
+ }
+
+ /**
+ * Gets the list of IAction objects at the egress edge node.
+ *
+ * @return The list of IAction objects at the egress edge node.
+ */
+ public List<IAction> getActions() {
+ return edgeActions;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/SingleDstTreeFlow.java b/src/main/java/net/onrc/onos/api/flowmanager/SingleDstTreeFlow.java
new file mode 100644
index 0000000..82a9b50
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/SingleDstTreeFlow.java
@@ -0,0 +1,90 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import net.onrc.onos.core.matchaction.MatchActionPlan;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.util.SwitchPort;
+
+/**
+ * An IFlow object expressing the multipoints-to-point tree flow for the packet
+ * layer.
+ * <p>
+ * NOTE: This class might generate the MatchActionPlan which includes the MAC
+ * address modifications or other the label-switching-like schemes.
+ */
+public class SingleDstTreeFlow implements IFlow {
+ protected String id;
+ protected PacketMatch match;
+ protected Set<SwitchPort> ingressPorts;
+ protected Tree tree;
+ protected OutputAction outputAction;
+
+ /**
+ * Creates new instance using Tree object.
+ *
+ * @param id ID for this object.
+ * @param match Traffic filter for the tree.
+ * @param ingressPorts A set of ingress ports of the tree.
+ * @param tree Tree object specifying tree topology for this object.
+ * @param outputAction OutputAction object at the egress edge switch.
+ */
+ public SingleDstTreeFlow(String id, PacketMatch match,
+ Collection<SwitchPort> ingressPorts, Tree tree, OutputAction outputAction) {
+ this.id = id;
+ this.match = match;
+ this.ingressPorts = new HashSet<SwitchPort>(ingressPorts);
+ this.tree = tree;
+ this.outputAction = outputAction;
+
+ // TODO: check if the tree is a MP2P tree.
+ // TODO: check consistency among inPorts, tree, and action.
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public PacketMatch getMatch() {
+ return match;
+ }
+
+ @Override
+ public MatchActionPlan compile() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Gets the ingress ports of the tree.
+ *
+ * @return The ingress ports of the tree.
+ */
+ public Collection<SwitchPort> getIngressPorts() {
+ return Collections.unmodifiableCollection(ingressPorts);
+ }
+
+ /**
+ * Gets the tree.
+ *
+ * @return The tree object.
+ */
+ public Tree getTree() {
+ return tree;
+ }
+
+ /**
+ * Gets the output action for the tree.
+ *
+ * @return The OutputAction object.
+ */
+ public OutputAction getOutputAction() {
+ return outputAction;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/SingleSrcTreeFlow.java b/src/main/java/net/onrc/onos/api/flowmanager/SingleSrcTreeFlow.java
new file mode 100644
index 0000000..cecb605
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/SingleSrcTreeFlow.java
@@ -0,0 +1,87 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.Set;
+
+import net.onrc.onos.core.matchaction.MatchActionPlan;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.Pair;
+import net.onrc.onos.core.util.SwitchPort;
+
+/**
+ * An IFlow object expressing the point-to-multipoints tree flow for the packet
+ * layer.
+ */
+public class SingleSrcTreeFlow implements IFlow {
+ protected String id;
+ protected PacketMatch match;
+ protected SwitchPort ingressPort;
+ protected Tree tree;
+ protected Set<Pair<Dpid, OutputAction>> outputActions;
+
+ /**
+ * Creates new instance using Tree object.
+ *
+ * @param id ID for this object.
+ * @param match Traffic filter for the tree.
+ * @param ingressPort A ingress port of the tree.
+ * @param tree Tree object specifying tree topology for this object.
+ * @param outputActions The set of the pairs of the switch DPID and
+ * OutputAction object at the egress edge switchs.
+ */
+ public SingleSrcTreeFlow(String id, PacketMatch match,
+ SwitchPort ingressPort, Tree tree, Set<Pair<Dpid, OutputAction>> outputActions) {
+ this.id = id;
+ this.match = match;
+ this.ingressPort = ingressPort;
+ this.tree = tree;
+ this.outputActions = outputActions;
+
+ // TODO: check if the tree is a P2MP tree.
+ // TODO: check consistency among rootPort, tree, and actions.
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public PacketMatch getMatch() {
+ return match;
+ }
+
+ @Override
+ public MatchActionPlan compile() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Gets the ingress port (the root) of the tree.
+ *
+ * @return The ingress port of the tree.
+ */
+ public SwitchPort getIngressPort() {
+ return ingressPort;
+ }
+
+ /**
+ * Gets the tree.
+ *
+ * @return The tree object.
+ */
+ public Tree getTree() {
+ return tree;
+ }
+
+ /**
+ * Gets the output actions for the tree.
+ *
+ * @return The set of the pairs of Dpid and OutputAction object.
+ */
+ public Set<Pair<Dpid, OutputAction>> getActions() {
+ return outputActions;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/Tree.java b/src/main/java/net/onrc/onos/api/flowmanager/Tree.java
new file mode 100644
index 0000000..49b05dc
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/flowmanager/Tree.java
@@ -0,0 +1,111 @@
+package net.onrc.onos.api.flowmanager;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.PortNumber;
+import net.onrc.onos.core.util.SwitchPort;
+
+/**
+ * A directed connected tree topology representation used by TreeFlow.
+ */
+public class Tree extends FlowLinks {
+ Map<Dpid, Set<PortNumber>> ports = new HashMap<Dpid, Set<PortNumber>>();
+ Map<SwitchPort, FlowLink> inLinks = new HashMap<SwitchPort, FlowLink>();
+ Map<SwitchPort, FlowLink> outLinks = new HashMap<SwitchPort, FlowLink>();
+
+ /**
+ * Creates new instance.
+ */
+ public Tree() {
+ super();
+ }
+
+ /**
+ * Creates new instance using Path object.
+ */
+ public Tree(Path path) {
+ super();
+ // TODO implement
+ }
+
+ private void addPort(SwitchPort port) {
+ if (!ports.containsKey(port.dpid())) {
+ ports.put(port.dpid(), new HashSet<PortNumber>());
+ }
+ ports.get(port.dpid()).add(port.port());
+ }
+
+ /**
+ * Adds FlowLink object to this tree.
+ * <p>
+ * This method checks specified FlowLink object to keep this Tree object a
+ * connected tree.
+ *
+ * @param link FlowLink object to be added.
+ * @return true if succeeded, false otherwise.
+ */
+ public boolean addLink(FlowLink link) {
+ if (links.size() > 0) {
+ if (!hasDpid(link.getSrcDpid()) && !hasDpid(link.getDstDpid())) {
+ // no attaching point
+ return false;
+ }
+ if (hasDpid(link.getSrcDpid()) && hasDpid(link.getDstDpid())) {
+ // loop or duplicated paths
+ return false;
+ }
+ }
+
+ if (hasSwitchPort(link.getSrcSwitchPort())
+ || hasSwitchPort(link.getDstSwitchPort())) {
+ // some port has already been occupied by another link
+ return false;
+ }
+
+ links.add(link);
+ addPort(link.getSrcSwitchPort());
+ addPort(link.getDstSwitchPort());
+
+ inLinks.put(link.getDstSwitchPort(), link);
+ outLinks.put(link.getSrcSwitchPort(), link);
+
+ return true;
+ }
+
+ /**
+ * Checks if specified dpid exists in this tree.
+ *
+ * @param dpid DPID to be checked.
+ * @return true if found, false otherwise.
+ */
+ public boolean hasDpid(Dpid dpid) {
+ return ports.containsKey(dpid);
+ }
+
+ /**
+ * Checks if specified switch-port exists in this tree.
+ *
+ * @param port SwitchPort object to be checked.
+ * @return true if found, false otherwise.
+ */
+ public boolean hasSwitchPort(SwitchPort port) {
+ return inLinks.containsKey(port) || outLinks.containsKey(port);
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO think if this is correct.
+ return super.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ // TODO think if this is correct.
+ // - has to check equality using a set, not a list?
+ return super.equals(o);
+ }
+}