flowrules are pushed: we still have an intermittent hang though
diff --git a/apps/fwd/src/main/java/org/onlab/onos/fwd/ReactiveForwarding.java b/apps/fwd/src/main/java/org/onlab/onos/fwd/ReactiveForwarding.java
index b9ae4c4..ce85938 100644
--- a/apps/fwd/src/main/java/org/onlab/onos/fwd/ReactiveForwarding.java
+++ b/apps/fwd/src/main/java/org/onlab/onos/fwd/ReactiveForwarding.java
@@ -1,5 +1,9 @@
 package org.onlab.onos.fwd;
 
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Set;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -9,6 +13,14 @@
 import org.onlab.onos.net.HostId;
 import org.onlab.onos.net.Path;
 import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.flow.DefaultFlowRule;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.DefaultTrafficTreatment;
+import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.FlowRuleService;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.flow.criteria.Criteria;
 import org.onlab.onos.net.flow.instructions.Instructions;
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.packet.InboundPacket;
@@ -16,12 +28,9 @@
 import org.onlab.onos.net.packet.PacketProcessor;
 import org.onlab.onos.net.packet.PacketService;
 import org.onlab.onos.net.topology.TopologyService;
+import org.onlab.packet.Ethernet;
 import org.slf4j.Logger;
 
-import java.util.Set;
-
-import static org.slf4j.LoggerFactory.getLogger;
-
 /**
  * Sample reactive forwarding application.
  */
@@ -39,6 +48,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostService hostService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowRuleService flowRuleService;
+
     private ReactivePacketProcessor processor = new ReactivePacketProcessor();
 
     @Activate
@@ -62,6 +74,9 @@
 
         @Override
         public void process(PacketContext context) {
+            if (context.isHandled()) {
+                return;
+            }
             InboundPacket pkt = context.inPacket();
             HostId id = HostId.hostId(pkt.parsed().getDestinationMAC());
 
@@ -75,15 +90,16 @@
             // Are we on an edge switch that our destination is on? If so,
             // simply forward out to the destination and bail.
             if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
-                forward(context, dst.location().port());
+                installRule(context, dst.location().port());
                 return;
             }
 
             // Otherwise, get a set of paths that lead from here to the
             // destination edge switch.
+
             Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
-                                                       context.inPacket().receivedFrom().deviceId(),
-                                                       dst.location().deviceId());
+                    context.inPacket().receivedFrom().deviceId(),
+                    dst.location().deviceId());
             if (paths.isEmpty()) {
                 // If there are no paths, flood and bail.
                 flood(context);
@@ -100,7 +116,7 @@
             }
 
             // Otherwise forward and be done with it.
-            forward(context, path.src().port());
+            installRule(context, path.src().port());
         }
     }
 
@@ -118,18 +134,43 @@
     // Floods the specified packet.
     private void flood(PacketContext context) {
         boolean canBcast = topologyService.isBroadcastPoint(topologyService.currentTopology(),
-                                                            context.inPacket().receivedFrom());
+                context.inPacket().receivedFrom());
         if (canBcast) {
-            forward(context, PortNumber.FLOOD);
+            packetOutFlood(context);
         } else {
             context.block();
         }
     }
 
-    // Forwards the packet to the specified port.
-    private void forward(PacketContext context, PortNumber portNumber) {
+    //Floods a packet out
+    private void packetOutFlood(PacketContext context) {
+        context.treatmentBuilder().add(Instructions.createOutput(PortNumber.FLOOD));
+        context.send();
+    }
+
+    // Install a rule forwarding the packet to the specified port.
+    private void installRule(PacketContext context, PortNumber portNumber) {
+        // we don't yet support bufferids in the flowservice so packet out and
+        // then install a flowmod.
         context.treatmentBuilder().add(Instructions.createOutput(portNumber));
         context.send();
+
+
+        Ethernet inPkt = context.inPacket().parsed();
+        TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder();
+        builder.add(Criteria.matchEthType(inPkt.getEtherType()))
+        .add(Criteria.matchEthSrc(inPkt.getSourceMAC()))
+        .add(Criteria.matchEthDst(inPkt.getDestinationMAC()))
+        .add(Criteria.matchInPort(context.inPacket().receivedFrom().port()));
+
+        TrafficTreatment.Builder treat = new DefaultTrafficTreatment.Builder();
+        treat.add(Instructions.createOutput(portNumber));
+
+        FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
+                builder.build(), treat.build());
+
+        flowRuleService.applyFlowRules(f);
+
     }
 
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
new file mode 100644
index 0000000..801e8f9
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
@@ -0,0 +1,38 @@
+package org.onlab.onos.net.flow;
+
+import org.onlab.onos.net.DeviceId;
+
+public class DefaultFlowRule implements FlowRule {
+
+    private final TrafficSelector selector;
+    private final TrafficTreatment treatment;
+    private final DeviceId deviceId;
+
+    public DefaultFlowRule(DeviceId deviceId,
+            TrafficSelector selector, TrafficTreatment treatment) {
+        this.treatment = treatment;
+        this.selector = selector;
+        this.deviceId = deviceId;
+    }
+
+    @Override
+    public int priority() {
+        return 0;
+    }
+
+    @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    @Override
+    public TrafficSelector selector() {
+        return selector;
+    }
+
+    @Override
+    public TrafficTreatment treatment() {
+        return treatment;
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
new file mode 100644
index 0000000..9ec49e4
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
@@ -0,0 +1,44 @@
+package org.onlab.onos.net.flow;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.onlab.onos.net.flow.criteria.Criterion;
+import org.slf4j.Logger;
+
+public final class DefaultTrafficSelector implements TrafficSelector {
+
+    private final List<Criterion> selector;
+
+    private DefaultTrafficSelector(List<Criterion> selector) {
+        this.selector = Collections.unmodifiableList(selector);
+    }
+
+    @Override
+    public List<Criterion> criteria() {
+        return selector;
+    }
+
+    public static class Builder implements TrafficSelector.Builder {
+
+        private final Logger log = getLogger(getClass());
+
+        private final List<Criterion> selector = new LinkedList<>();
+
+        @Override
+        public TrafficSelector.Builder add(Criterion criterion) {
+            selector.add(criterion);
+            return this;
+        }
+
+        @Override
+        public TrafficSelector build() {
+            return new DefaultTrafficSelector(selector);
+        }
+
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
index 0bf4ea8..9de68dc 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
@@ -9,12 +9,11 @@
 import org.onlab.onos.net.flow.instructions.Instruction;
 import org.slf4j.Logger;
 
-@SuppressWarnings("rawtypes")
-public class DefaultTrafficTreatment implements TrafficTreatment {
+public final class DefaultTrafficTreatment implements TrafficTreatment {
 
     private final List<Instruction> instructions;
 
-    public DefaultTrafficTreatment(List<Instruction> instructions) {
+    private DefaultTrafficTreatment(List<Instruction> instructions) {
         this.instructions = Collections.unmodifiableList(instructions);
     }
 
diff --git a/features/features.xml b/features/features.xml
index d96b2fd..205d78e 100644
--- a/features/features.xml
+++ b/features/features.xml
@@ -69,6 +69,7 @@
         <bundle>mvn:org.onlab.onos/onos-of-provider-link/1.0.0-SNAPSHOT</bundle>
         <bundle>mvn:org.onlab.onos/onos-of-provider-host/1.0.0-SNAPSHOT</bundle>
         <bundle>mvn:org.onlab.onos/onos-of-provider-packet/1.0.0-SNAPSHOT</bundle>
+        <bundle>mvn:org.onlab.onos/onos-of-provider-flow/1.0.0-SNAPSHOT</bundle>
 
     </feature>
 
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/DefaultOpenFlowPacketContext.java b/of/api/src/main/java/org/onlab/onos/of/controller/DefaultOpenFlowPacketContext.java
index efb41b8..fd47ad3 100644
--- a/of/api/src/main/java/org/onlab/onos/of/controller/DefaultOpenFlowPacketContext.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/DefaultOpenFlowPacketContext.java
@@ -32,7 +32,7 @@
 
     @Override
     public void send() {
-        if (blocked() && isBuilt) {
+        if (block() && isBuilt) {
             sw.sendMsg(pktout);
         }
     }
@@ -109,8 +109,13 @@
     }
 
     @Override
-    public boolean blocked() {
+    public boolean block() {
         return free.getAndSet(false);
     }
 
+    @Override
+    public boolean isHandled() {
+        return !free.get();
+    }
+
 }
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowPacketContext.java b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowPacketContext.java
index e1360e2..0e90f95 100644
--- a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowPacketContext.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowPacketContext.java
@@ -16,7 +16,13 @@
      * Blocks further responses (ie. send() calls) on this
      * packet in event.
      */
-    public boolean blocked();
+    public boolean block();
+
+    /**
+     * Checks whether the packet has been handled.
+     * @return true if handled, false otherwise.
+     */
+    public boolean isHandled();
 
     /**
      * Provided build has been called send the packet
diff --git a/providers/of/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/of/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
index 9a11a36..44b0792 100644
--- a/providers/of/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/of/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -26,6 +26,7 @@
 import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
 import org.onlab.onos.net.flow.criteria.Criterion;
 import org.onlab.onos.net.flow.instructions.Instruction;
+import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
 import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
 import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
 import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
@@ -136,6 +137,9 @@
             case L3MODIFICATION:
                 acts.add(buildL3Modification(i, factory));
             case OUTPUT:
+                OutputInstruction out = (OutputInstruction) i;
+                acts.add(factory.actions().buildOutput().setPort(
+                        OFPort.of((int) out.port().toLong())).build());
                 break;
             case GROUP:
             default:
@@ -207,6 +211,7 @@
             case ETH_TYPE:
                 EthTypeCriterion ethType = (EthTypeCriterion) c;
                 mBuilder.setExact(MatchField.ETH_TYPE, EthType.of(ethType.ethType()));
+                break;
             case IPV4_DST:
                 ip = (IPCriterion) c;
                 mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toInt()));
diff --git a/providers/of/host/src/test/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProviderTest.java b/providers/of/host/src/test/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProviderTest.java
index 4138111..ea8db19 100644
--- a/providers/of/host/src/test/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProviderTest.java
+++ b/providers/of/host/src/test/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProviderTest.java
@@ -1,5 +1,11 @@
 package org.onlab.onos.provider.of.host.impl;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Set;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -24,10 +30,6 @@
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.types.OFPort;
 
-import java.util.Set;
-
-import static org.junit.Assert.*;
-
 public class OpenFlowHostProviderTest {
 
     private static final Integer INPORT = 10;
@@ -40,10 +42,10 @@
     private static final MacAddress BCMAC = MacAddress.valueOf("ff:ff:ff:ff:ff:ff");
     private static final byte[] IP = new byte[]{10, 0, 0, 1};
 
-    private OpenFlowHostProvider provider = new OpenFlowHostProvider();
-    private TestHostRegistry hostService = new TestHostRegistry();
-    private TestController controller = new TestController();
-    private TestTopologyService topoService = new TestTopologyService();
+    private final OpenFlowHostProvider provider = new OpenFlowHostProvider();
+    private final TestHostRegistry hostService = new TestHostRegistry();
+    private final TestController controller = new TestController();
+    private final TestTopologyService topoService = new TestTopologyService();
     private TestHostProviderService providerService;
 
     @Before
@@ -103,8 +105,8 @@
     }
 
     private class TestHostProviderService
-            extends AbstractProviderService<HostProvider>
-            implements HostProviderService {
+    extends AbstractProviderService<HostProvider>
+    implements HostProviderService {
 
         Dpid added = null;
         Dpid moved = null;
@@ -150,7 +152,7 @@
     private class TestTopologyService extends TopologyServiceAdapter {
         @Override
         public boolean isInfrastructure(Topology topology,
-                                        ConnectPoint connectPoint) {
+                ConnectPoint connectPoint) {
             //simulate DPID3 as an infrastructure switch
             if (Dpid.dpid(connectPoint.deviceId().uri()).equals(DPID3)) {
                 return true;
@@ -168,7 +170,7 @@
         }
 
         @Override
-        public boolean blocked() {
+        public boolean block() {
             return false;
         }
 
@@ -189,16 +191,16 @@
             // just things we (and serializers) need
             ARP arp = new ARP();
             arp.setSenderProtocolAddress(IP)
-                    .setSenderHardwareAddress(MAC.toBytes())
-                    .setTargetHardwareAddress(BCMAC.toBytes())
-                    .setTargetProtocolAddress(IP);
+            .setSenderHardwareAddress(MAC.toBytes())
+            .setTargetHardwareAddress(BCMAC.toBytes())
+            .setTargetProtocolAddress(IP);
 
             Ethernet eth = new Ethernet();
             eth.setEtherType(Ethernet.TYPE_ARP)
-                    .setVlanID(VLAN.toShort())
-                    .setSourceMACAddress(MAC.toBytes())
-                    .setDestinationMACAddress(BCMAC.getAddress())
-                    .setPayload(arp);
+            .setVlanID(VLAN.toShort())
+            .setSourceMACAddress(MAC.toBytes())
+            .setDestinationMACAddress(BCMAC.getAddress())
+            .setPayload(arp);
 
             return eth;
         }
@@ -218,5 +220,10 @@
             return INPORT;
         }
 
+        @Override
+        public boolean isHandled() {
+            return false;
+        }
+
     }
 }
diff --git a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
index ff9a996..8935d59 100644
--- a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
+++ b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
@@ -93,7 +93,7 @@
                 return;
             }
             if (ld.handleLLDP(pktCtx.unparsed(), pktCtx.inPort())) {
-                pktCtx.blocked();
+                pktCtx.block();
             }
 
         }
diff --git a/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProvider.java b/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProvider.java
index eb41c18..40b40e4 100644
--- a/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProvider.java
+++ b/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProvider.java
@@ -87,7 +87,7 @@
                     pktCtx.parsed(), ByteBuffer.wrap(pktCtx.unparsed()));
 
             OpenFlowCorePacketContext corePktCtx =
-                    new OpenFlowCorePacketContext(0, inPkt, null, false, pktCtx);
+                    new OpenFlowCorePacketContext(0, inPkt, null, pktCtx.isHandled(), pktCtx);
             providerService.processPacket(corePktCtx);
         }