flowruleprovider builds flowmods
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 6064263..0bf4ea8 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
@@ -53,7 +53,8 @@
             case OUTPUT:
                 outputs.add(instruction);
                 break;
-            case MODIFICATION:
+            case L2MODIFICATION:
+            case L3MODIFICATION:
                 // TODO: enforce modification order if any
                 modifications.add(instruction);
                 break;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
index c7c2fc8..9cae5f9 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
@@ -227,7 +227,7 @@
             return Type.VLAN_PCP;
         }
 
-        public Byte protocol() {
+        public Byte priority() {
             return vlanPcp;
         }
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java
index 8c41a04..f05d238 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java
@@ -5,12 +5,6 @@
  */
 public interface Instruction {
 
-    interface SubType { }
-
-    public enum NoneSubType implements SubType {
-        NONE;
-    }
-
     /**
      * Represents the type of traffic treatment.
      */
@@ -31,9 +25,14 @@
         GROUP,
 
         /**
-         * Signifies that the traffic should be modified in some way.
+         * Signifies that the traffic should be modified in L2 way.
          */
-        MODIFICATION
+        L2MODIFICATION,
+
+        /**
+         * Signifies that the traffic should be modified in L3 way.
+         */
+        L3MODIFICATION
     }
 
     // TODO: Create factory class 'Instructions' that will have various factory
@@ -45,10 +44,4 @@
      */
     public Type type();
 
-    /**
-     * Returns the subtype of the modification instruction.
-     * @return type of instruction
-     */
-    public SubType subtype();
-
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
index 06903e5..439db77 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
@@ -7,10 +7,10 @@
 import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType;
 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
-import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPProtoInstruction;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+
 /**
  * Factory class for creating various traffic treatment instructions.
  */
@@ -61,16 +61,6 @@
     }
 
     /**
-     * Creates a L2 type modification.
-     * @param l2Type the type to change to
-     * @return a L2 modifications
-     */
-    public static L2ModificationInstruction modL2Type(Short l2Type) {
-        checkNotNull(l2Type, "L2 type cannot be null");
-        return new L2ModificationInstruction.ModEtherTypeInstruction(l2Type);
-    }
-
-    /**
      * Creates a Vlan id modification.
      * @param vlanId the vlan id to modify to.
      * @return a L2 modification
@@ -110,15 +100,6 @@
         return new ModIPInstruction(L3SubType.L3_DST, addr);
     }
 
-    /**
-     * Creates an L3 protocol modification.
-     * @param proto the protocol to change to
-     * @return a L3 modification
-     */
-    public static L3ModificationInstruction modIPProto(Byte proto) {
-        checkNotNull(proto, "IP protocol cannot be null");
-        return new ModIPProtoInstruction(proto);
-    }
 
     /*
      *  Output instructions
@@ -129,11 +110,6 @@
         public Type type() {
             return Type.DROP;
         }
-
-        @Override
-        public SubType subtype() {
-            return NoneSubType.NONE;
-        }
     }
 
 
@@ -152,11 +128,6 @@
         public Type type() {
             return Type.OUTPUT;
         }
-
-        @Override
-        public SubType subtype() {
-            return NoneSubType.NONE;
-        }
     }
 
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
index 5490de2..78eaaa9 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
@@ -12,7 +12,7 @@
     /**
      * Represents the type of traffic treatment.
      */
-    public enum L2SubType implements SubType {
+    public enum L2SubType {
         /**
          * Ether src modification.
          */
@@ -24,11 +24,6 @@
         L2_DST,
 
         /**
-         * Ethertype modification.
-         */
-        L2_TYPE,
-
-        /**
          * VLAN id modification.
          */
         VLAN_ID,
@@ -42,12 +37,11 @@
     // TODO: Create factory class 'Instructions' that will have various factory
     // to create specific instructions.
 
-    @Override
-    public abstract SubType subtype();
+    public abstract L2SubType subtype();
 
     @Override
     public Type type() {
-        return Type.MODIFICATION;
+        return Type.L2MODIFICATION;
     }
 
     /**
@@ -55,16 +49,17 @@
      */
     public static final class ModEtherInstruction extends L2ModificationInstruction {
 
-        private final SubType subtype;
+        private final L2SubType subtype;
         private final MacAddress mac;
 
-        public ModEtherInstruction(SubType subType, MacAddress addr) {
+        public ModEtherInstruction(L2SubType subType, MacAddress addr) {
+
             this.subtype = subType;
             this.mac = addr;
         }
 
         @Override
-        public SubType subtype() {
+        public L2SubType subtype() {
             return this.subtype;
         }
 
@@ -75,28 +70,6 @@
     }
 
     /**
-     * Represents a L2 type modification instruction.
-     */
-    public static final class ModEtherTypeInstruction extends L2ModificationInstruction {
-
-        public final short l2Type;
-
-        public ModEtherTypeInstruction(short l2Type) {
-            this.l2Type = l2Type;
-        }
-
-        @Override
-        public SubType subtype() {
-            return L2SubType.L2_TYPE;
-        }
-
-        public short l2Type() {
-            return this.l2Type;
-        }
-
-    }
-
-    /**
      * Represents a VLAN id modification instruction.
      */
     public static final class ModVlanIdInstruction extends L2ModificationInstruction {
@@ -108,7 +81,7 @@
         }
 
         @Override
-        public SubType subtype() {
+        public L2SubType subtype() {
             return L2SubType.VLAN_ID;
         }
 
@@ -130,7 +103,7 @@
         }
 
         @Override
-        public SubType subtype() {
+        public L2SubType subtype() {
             return L2SubType.VLAN_PCP;
         }
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
index 126c1f9..cf25f10 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
@@ -11,7 +11,7 @@
     /**
      * Represents the type of traffic treatment.
      */
-    public enum L3SubType implements SubType {
+    public enum L3SubType {
         /**
          * Ether src modification.
          */
@@ -20,12 +20,7 @@
         /**
          * Ether dst modification.
          */
-        L3_DST,
-
-        /**
-         * Ethertype modification.
-         */
-        L3_PROTO,
+        L3_DST
 
         //TODO: remaining types
     }
@@ -34,11 +29,11 @@
      * Returns the subtype of the modification instruction.
      * @return type of instruction
      */
-    public abstract SubType subtype();
+    public abstract L3SubType subtype();
 
     @Override
     public Type type() {
-        return Type.MODIFICATION;
+        return Type.L3MODIFICATION;
     }
 
     /**
@@ -46,16 +41,17 @@
      */
     public static final class ModIPInstruction extends L3ModificationInstruction {
 
-        private final SubType subtype;
+        private final L3SubType subtype;
         private final IpAddress ip;
 
-        public ModIPInstruction(SubType subType, IpAddress addr) {
+        public ModIPInstruction(L3SubType subType, IpAddress addr) {
+
             this.subtype = subType;
             this.ip = addr;
         }
 
         @Override
-        public SubType subtype() {
+        public L3SubType subtype() {
             return this.subtype;
         }
 
@@ -64,26 +60,4 @@
         }
 
     }
-
-    /**
-     * Represents a L3 proto modification instruction.
-     */
-    public static final class ModIPProtoInstruction extends L3ModificationInstruction {
-
-        public final Byte proto;
-
-        public ModIPProtoInstruction(Byte proto) {
-            this.proto = proto;
-        }
-
-        @Override
-        public SubType subtype() {
-            return L3SubType.L3_PROTO;
-        }
-
-        public short proto() {
-            return this.proto;
-        }
-
-    }
 }
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 29a716d..db6590a 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
@@ -2,6 +2,10 @@
 
 import static org.slf4j.LoggerFactory.getLogger;
 
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -13,10 +17,41 @@
 import org.onlab.onos.net.flow.FlowRuleProvider;
 import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
 import org.onlab.onos.net.flow.FlowRuleProviderService;
+import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion;
+import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion;
+import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
+import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion;
+import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion;
+import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
+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.L2ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
 import org.onlab.onos.net.provider.AbstractProvider;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.net.topology.TopologyService;
+import org.onlab.onos.of.controller.Dpid;
 import org.onlab.onos.of.controller.OpenFlowController;
+import org.onlab.onos.of.controller.OpenFlowSwitch;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
 import org.slf4j.Logger;
 
 /**
@@ -61,10 +96,174 @@
     }
     @Override
     public void applyFlowRule(FlowRule... flowRules) {
-        // TODO Auto-generated method stub
+        for (int i = 0; i < flowRules.length; i++) {
+            applyRule(flowRules[i]);
+        }
 
     }
 
+    private void applyRule(FlowRule flowRule) {
+        OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
+        Match match = buildMatch(flowRule.selector().criteria(), sw.factory());
+        List<OFAction> actions =
+                buildActions(flowRule.treatment().instructions(), sw.factory());
+
+        //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+        OFFlowMod fm = sw.factory().buildFlowModify()
+                .setActions(actions)
+                .setMatch(match)
+                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+                .setIdleTimeout(10)
+                .setHardTimeout(10)
+                .setPriority(flowRule.priority())
+                .build();
+
+        sw.sendMsg(fm);
+
+    }
+
+    private List<OFAction> buildActions(List<Instruction> instructions, OFFactory factory) {
+        List<OFAction> acts = new LinkedList<>();
+        for (Instruction i : instructions) {
+            switch (i.type()) {
+            case DROP:
+                log.warn("Saw drop action; assigning drop action");
+                return acts;
+            case L2MODIFICATION:
+                acts.add(buildL2Modification(i, factory));
+            case L3MODIFICATION:
+                acts.add(buildL3Modification(i, factory));
+            case OUTPUT:
+                break;
+            case GROUP:
+            default:
+                log.warn("Instruction type {} not yet implemented.", i.type());
+            }
+        }
+
+        return acts;
+    }
+
+    private OFAction buildL3Modification(Instruction i, OFFactory factory) {
+        L3ModificationInstruction l3m = (L3ModificationInstruction) i;
+        ModIPInstruction ip;
+        switch (l3m.subtype()) {
+        case L3_DST:
+            ip = (ModIPInstruction) i;
+            return factory.actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
+        case L3_SRC:
+            ip = (ModIPInstruction) i;
+            return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
+        default:
+            log.warn("Unimplemented action type {}.", l3m.subtype());
+            break;
+        }
+        return null;
+    }
+
+    private OFAction buildL2Modification(Instruction i, OFFactory factory) {
+        L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+        ModEtherInstruction eth;
+        switch (l2m.subtype()) {
+        case L2_DST:
+            eth = (ModEtherInstruction) l2m;
+            return factory.actions().setDlDst(MacAddress.of(eth.mac().toLong()));
+        case L2_SRC:
+            eth = (ModEtherInstruction) l2m;
+            return factory.actions().setDlSrc(MacAddress.of(eth.mac().toLong()));
+        case VLAN_ID:
+            ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
+            return factory.actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId.toShort()));
+        case VLAN_PCP:
+            ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
+            return factory.actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
+        default:
+            log.warn("Unimplemented action type {}.", l2m.subtype());
+            break;
+        }
+        return null;
+    }
+
+    private Match buildMatch(List<Criterion> criteria, OFFactory factory) {
+        Match.Builder mBuilder = factory.buildMatch();
+        EthCriterion eth;
+        IPCriterion ip;
+        for (Criterion c : criteria) {
+            switch (c.type()) {
+            case IN_PORT:
+                PortCriterion inport = (PortCriterion) c;
+                mBuilder.setExact(MatchField.IN_PORT, OFPort.of((int) inport.port().toLong()));
+                break;
+            case ETH_SRC:
+                eth = (EthCriterion) c;
+                mBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(eth.mac().toLong()));
+                break;
+            case ETH_DST:
+                eth = (EthCriterion) c;
+                mBuilder.setExact(MatchField.ETH_DST, MacAddress.of(eth.mac().toLong()));
+                break;
+            case ETH_TYPE:
+                EthTypeCriterion ethType = (EthTypeCriterion) c;
+                mBuilder.setExact(MatchField.ETH_TYPE, EthType.of(ethType.ethType()));
+            case IPV4_DST:
+                ip = (IPCriterion) c;
+                mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toInt()));
+                break;
+            case IPV4_SRC:
+                ip = (IPCriterion) c;
+                mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toInt()));
+                break;
+            case IP_PROTO:
+                IPProtocolCriterion p = (IPProtocolCriterion) c;
+                mBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(p.protocol()));
+                break;
+            case VLAN_PCP:
+                VlanPcpCriterion vpcp = (VlanPcpCriterion) c;
+                mBuilder.setExact(MatchField.VLAN_PCP, VlanPcp.of(vpcp.priority()));
+                break;
+            case VLAN_VID:
+                VlanIdCriterion vid = (VlanIdCriterion) c;
+                mBuilder.setExact(MatchField.VLAN_VID,
+                        OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort())));
+                break;
+            case ARP_OP:
+            case ARP_SHA:
+            case ARP_SPA:
+            case ARP_THA:
+            case ARP_TPA:
+            case ICMPV4_CODE:
+            case ICMPV4_TYPE:
+            case ICMPV6_CODE:
+            case ICMPV6_TYPE:
+            case IN_PHY_PORT:
+            case IPV6_DST:
+            case IPV6_EXTHDR:
+            case IPV6_FLABEL:
+            case IPV6_ND_SLL:
+            case IPV6_ND_TARGET:
+            case IPV6_ND_TLL:
+            case IPV6_SRC:
+            case IP_DSCP:
+            case IP_ECN:
+            case METADATA:
+            case MPLS_BOS:
+            case MPLS_LABEL:
+            case MPLS_TC:
+            case PBB_ISID:
+            case SCTP_DST:
+            case SCTP_SRC:
+            case TCP_DST:
+            case TCP_SRC:
+            case TUNNEL_ID:
+            case UDP_DST:
+            case UDP_SRC:
+            default:
+                log.warn("Action type {} not yet implemented.", c.type());
+            }
+        }
+        return mBuilder.build();
+    }
+
     @Override
     public void removeFlowRule(FlowRule... flowRules) {
         // TODO Auto-generated method stub