Restructured to separate stores and managers into different bundles. Reactive forwarding does not seem to work; will investigate.
diff --git a/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
index 8db0d04..851fbc1 100644
--- a/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
@@ -10,8 +10,7 @@
 import java.util.List;
 
 /**
- * Manages inventory of infrastructure devices. It may do so using whatever
- * means are appropriate.
+ * Manages inventory of infrastructure devices.
  */
 public interface DeviceStore {
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
new file mode 100644
index 0000000..6fdc993
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
@@ -0,0 +1,40 @@
+package org.onlab.onos.net.flow;
+
+import org.onlab.onos.net.DeviceId;
+
+/**
+ * Manages inventory of flow rules.
+ */
+public interface FlowRuleStore {
+
+    /**
+     * Returns the flow entries associated with a device.
+     *
+     * @param deviceId the device ID
+     * @return the flow entries
+     */
+    Iterable<FlowRule> getFlowEntries(DeviceId deviceId);
+
+    /**
+     * Stores a new flow rule, and generates a FlowRule for it.
+     *
+     * @param rule the flow rule to add
+     * @return a flow entry
+     */
+    FlowRule storeFlowRule(FlowRule rule);
+
+    /**
+     * Stores a new flow rule, or updates an existing entry.
+     *
+     * @param rule the flow rule to add or update
+     * @return flow_added event, or null if just an update
+     */
+    FlowRuleEvent addOrUpdateFlowRule(FlowRule rule);
+
+    /**
+     * @param rule the flow rule to remove
+     * @return flow_removed event, or null if nothing removed
+     */
+    FlowRuleEvent removeFlowRule(FlowRule rule);
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/DefaultGraphDescription.java b/core/api/src/main/java/org/onlab/onos/net/topology/DefaultGraphDescription.java
new file mode 100644
index 0000000..94a6abf
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/DefaultGraphDescription.java
@@ -0,0 +1,87 @@
+package org.onlab.onos.net.topology;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Device;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.Link;
+
+import java.util.Map;
+
+/**
+ * Default implementation of an immutable topology graph data carrier.
+ */
+public class DefaultGraphDescription implements GraphDescription {
+
+    private final long nanos;
+    private final ImmutableSet<TopologyVertex> vertexes;
+    private final ImmutableSet<TopologyEdge> edges;
+
+    private final Map<DeviceId, TopologyVertex> vertexesById = Maps.newHashMap();
+
+
+    /**
+     * Creates a minimal topology graph description to allow core to construct
+     * and process the topology graph.
+     *
+     * @param nanos   time in nanos of when the topology description was created
+     * @param devices collection of infrastructure devices
+     * @param links   collection of infrastructure links
+     */
+    public DefaultGraphDescription(long nanos, Iterable<Device> devices, Iterable<Link> links) {
+        this.nanos = nanos;
+        this.vertexes = buildVertexes(devices);
+        this.edges = buildEdges(links);
+        vertexesById.clear();
+    }
+
+    @Override
+    public long timestamp() {
+        return nanos;
+    }
+
+    @Override
+    public ImmutableSet<TopologyVertex> vertexes() {
+        return vertexes;
+    }
+
+    @Override
+    public ImmutableSet<TopologyEdge> edges() {
+        return edges;
+    }
+
+    // Builds a set of topology vertexes from the specified list of devices
+    private ImmutableSet<TopologyVertex> buildVertexes(Iterable<Device> devices) {
+        ImmutableSet.Builder<TopologyVertex> vertexes = ImmutableSet.builder();
+        for (Device device : devices) {
+            TopologyVertex vertex = new DefaultTopologyVertex(device.id());
+            vertexes.add(vertex);
+            vertexesById.put(vertex.deviceId(), vertex);
+        }
+        return vertexes.build();
+    }
+
+    // Builds a set of topology vertexes from the specified list of links
+    private ImmutableSet<TopologyEdge> buildEdges(Iterable<Link> links) {
+        ImmutableSet.Builder<TopologyEdge> edges = ImmutableSet.builder();
+        for (Link link : links) {
+            edges.add(new DefaultTopologyEdge(vertexOf(link.src()),
+                                              vertexOf(link.dst()), link));
+        }
+        return edges.build();
+    }
+
+    // Fetches a vertex corresponding to the given connection point device.
+    private TopologyVertex vertexOf(ConnectPoint connectPoint) {
+        DeviceId id = connectPoint.deviceId();
+        TopologyVertex vertex = vertexesById.get(id);
+        if (vertex == null) {
+            // If vertex does not exist, create one and register it.
+            vertex = new DefaultTopologyVertex(id);
+            vertexesById.put(id, vertex);
+        }
+        return vertex;
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/DefaultTopologyEdge.java b/core/api/src/main/java/org/onlab/onos/net/topology/DefaultTopologyEdge.java
new file mode 100644
index 0000000..00eb3d2
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/DefaultTopologyEdge.java
@@ -0,0 +1,66 @@
+package org.onlab.onos.net.topology;
+
+import org.onlab.onos.net.Link;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Implementation of the topology edge backed by a link.
+ */
+public class DefaultTopologyEdge implements TopologyEdge {
+
+    private final Link link;
+    private final TopologyVertex src;
+    private final TopologyVertex dst;
+
+    /**
+     * Creates a new topology edge.
+     *
+     * @param src  source vertex
+     * @param dst  destination vertex
+     * @param link infrastructure link
+     */
+    public DefaultTopologyEdge(TopologyVertex src, TopologyVertex dst, Link link) {
+        this.src = src;
+        this.dst = dst;
+        this.link = link;
+    }
+
+    @Override
+    public Link link() {
+        return link;
+    }
+
+    @Override
+    public TopologyVertex src() {
+        return src;
+    }
+
+    @Override
+    public TopologyVertex dst() {
+        return dst;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(link);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof DefaultTopologyEdge) {
+            final DefaultTopologyEdge other = (DefaultTopologyEdge) obj;
+            return Objects.equals(this.link, other.link);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("src", src).add("dst", dst).toString();
+    }
+
+}
+
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/DefaultTopologyVertex.java b/core/api/src/main/java/org/onlab/onos/net/topology/DefaultTopologyVertex.java
new file mode 100644
index 0000000..7bc231e
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/DefaultTopologyVertex.java
@@ -0,0 +1,48 @@
+package org.onlab.onos.net.topology;
+
+import org.onlab.onos.net.DeviceId;
+
+import java.util.Objects;
+
+/**
+ * Implementation of the topology vertex backed by a device id.
+ */
+public class DefaultTopologyVertex implements TopologyVertex {
+
+    private final DeviceId deviceId;
+
+    /**
+     * Creates a new topology vertex.
+     *
+     * @param deviceId backing infrastructure device identifier
+     */
+    public DefaultTopologyVertex(DeviceId deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(deviceId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof DefaultTopologyVertex) {
+            final DefaultTopologyVertex other = (DefaultTopologyVertex) obj;
+            return Objects.equals(this.deviceId, other.deviceId);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return deviceId.toString();
+    }
+
+}
+