implementing flowremoved handling
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/of/controller/impl/OpenFlowControllerImpl.java b/openflow/ctl/src/main/java/org/onlab/onos/of/controller/impl/OpenFlowControllerImpl.java
index a8b0673..a119be3 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/of/controller/impl/OpenFlowControllerImpl.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/of/controller/impl/OpenFlowControllerImpl.java
@@ -1,8 +1,14 @@
 package org.onlab.onos.of.controller.impl;
 
+import static org.onlab.util.Tools.namedThreads;
+
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -13,6 +19,7 @@
 import org.onlab.onos.of.controller.DefaultOpenFlowPacketContext;
 import org.onlab.onos.of.controller.Dpid;
 import org.onlab.onos.of.controller.OpenFlowController;
+import org.onlab.onos.of.controller.OpenFlowEventListener;
 import org.onlab.onos.of.controller.OpenFlowPacketContext;
 import org.onlab.onos.of.controller.OpenFlowSwitch;
 import org.onlab.onos.of.controller.OpenFlowSwitchListener;
@@ -22,10 +29,12 @@
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPacketIn;
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 
 @Component(immediate = true)
@@ -35,6 +44,10 @@
     private static final Logger log =
             LoggerFactory.getLogger(OpenFlowControllerImpl.class);
 
+    private final ExecutorService executor = Executors.newFixedThreadPool(16,
+            namedThreads("of-event-dispatch-%d"));
+
+
     protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
             new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
     protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
@@ -43,11 +56,12 @@
             new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
 
     protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
-    protected Set<OpenFlowSwitchListener> ofEventListener = new HashSet<>();
+    protected Set<OpenFlowSwitchListener> ofSwitchListener = new HashSet<>();
 
     protected Multimap<Integer, PacketListener> ofPacketListener =
             ArrayListMultimap.create();
 
+    protected Map<OFType, List<OpenFlowEventListener>> ofEventListener = Maps.newHashMap();
 
     private final Controller ctrl = new Controller();
 
@@ -93,14 +107,14 @@
 
     @Override
     public void addListener(OpenFlowSwitchListener listener) {
-        if (!ofEventListener.contains(listener)) {
-            this.ofEventListener.add(listener);
+        if (!ofSwitchListener.contains(listener)) {
+            this.ofSwitchListener.add(listener);
         }
     }
 
     @Override
     public void removeListener(OpenFlowSwitchListener listener) {
-        this.ofEventListener.remove(listener);
+        this.ofSwitchListener.remove(listener);
     }
 
     @Override
@@ -122,7 +136,7 @@
     public void processPacket(Dpid dpid, OFMessage msg) {
         switch (msg.getType()) {
         case PORT_STATUS:
-            for (OpenFlowSwitchListener l : ofEventListener) {
+            for (OpenFlowSwitchListener l : ofSwitchListener) {
                 l.portChanged(dpid, (OFPortStatus) msg);
             }
             break;
@@ -134,6 +148,12 @@
                 p.handlePacket(pktCtx);
             }
             break;
+        case FLOW_REMOVED:
+        case ERROR:
+        case STATS_REPLY:
+        case BARRIER_REPLY:
+            executor.submit(new OFMessageHandler(dpid, msg));
+            break;
         default:
             log.warn("Handling message type {} not yet implemented {}",
                     msg.getType(), msg);
@@ -164,7 +184,7 @@
             } else {
                 log.error("Added switch {}", dpid);
                 connectedSwitches.put(dpid, sw);
-                for (OpenFlowSwitchListener l : ofEventListener) {
+                for (OpenFlowSwitchListener l : ofSwitchListener) {
                     l.switchAdded(dpid);
                 }
                 return true;
@@ -277,7 +297,7 @@
             if (sw == null) {
                 sw = activeEqualSwitches.remove(dpid);
             }
-            for (OpenFlowSwitchListener l : ofEventListener) {
+            for (OpenFlowSwitchListener l : ofSwitchListener) {
                 l.switchRemoved(dpid);
             }
         }
@@ -288,5 +308,26 @@
         }
     }
 
+    private final class OFMessageHandler implements Runnable {
+
+        private final OFMessage msg;
+        private final Dpid dpid;
+
+        public OFMessageHandler(Dpid dpid, OFMessage msg) {
+            this.msg = msg;
+            this.dpid = dpid;
+        }
+
+        @Override
+        public void run() {
+            List<OpenFlowEventListener> listeners =
+                    ofEventListener.get(OFType.FLOW_REMOVED);
+            for (OpenFlowEventListener listener : listeners) {
+                listener.handleMessage(dpid, msg);
+            }
+        }
+
+    }
+
 
 }
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 38ba59b..9eed3c9 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,58 +2,29 @@
 
 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;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.flow.DefaultFlowRule;
 import org.onlab.onos.net.flow.FlowEntry;
 import org.onlab.onos.net.flow.FlowRule;
 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.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;
-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.OpenFlowEventListener;
 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.OFBufferId;
-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.onlab.onos.of.controller.OpenFlowSwitchListener;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.slf4j.Logger;
 
 /**
@@ -105,168 +76,10 @@
 
     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()
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setActions(actions)
-                .setMatch(match)
-                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
-                .setIdleTimeout(10)
-                .setHardTimeout(10)
-                .setPriority(flowRule.priority())
-                .build();
-        sw.sendMsg(fm);
+        sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowMod());
     }
 
-    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 new LinkedList<>();
-            case L2MODIFICATION:
-                acts.add(buildL2Modification(i, factory));
-            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:
-                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()));
-                break;
-            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) {
@@ -283,6 +96,45 @@
 
     //TODO: InternalFlowRuleProvider listening to stats and error and flowremoved.
     // possibly barriers as well. May not be internal at all...
+    private class InternalFlowProvider
+    implements OpenFlowSwitchListener, OpenFlowEventListener {
+
+
+        @Override
+        public void switchAdded(Dpid dpid) {
+
+
+        }
+
+        @Override
+        public void switchRemoved(Dpid dpid) {
+
+
+        }
+
+        @Override
+        public void portChanged(Dpid dpid, OFPortStatus status) {
+            //TODO: Decide whether to evict flows internal store.
+        }
+
+        @Override
+        public void handleMessage(Dpid dpid, OFMessage msg) {
+            switch (msg.getType()) {
+            case FLOW_REMOVED:
+                OFFlowRemoved removed = (OFFlowRemoved) msg;
+                FlowRule fr = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), null, null);
+                providerService.flowRemoved(fr);
+                break;
+            case STATS_REPLY:
+            case BARRIER_REPLY:
+            case ERROR:
+            default:
+                log.warn("Unhandled message type: {}", msg.getType());
+            }
+
+        }
+
+    }
 
 
 }
diff --git a/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowCorePacketContext.java b/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowCorePacketContext.java
index db9aae2..c3a8577 100644
--- a/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowCorePacketContext.java
+++ b/providers/of/packet/src/main/java/org/onlab/onos/provider/of/packet/impl/OpenFlowCorePacketContext.java
@@ -46,7 +46,7 @@
     private void sendBufferedPacket() {
         List<Instruction> ins = treatmentBuilder().build().instructions();
         OFPort p = null;
-        //TODO: support arbitrary list of treatments
+        //TODO: support arbitrary list of treatments must be supported in ofPacketContext
         for (Instruction i : ins) {
             if (i.type() == Type.OUTPUT) {
                 p = buildPort(((OutputInstruction) i).port());
diff --git a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
index 109672c..1c2bc1b 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
@@ -118,7 +118,7 @@
             if (mask > MAX_INET_MASK) {
                 throw new IllegalArgumentException(
                         "Value of subnet mask cannot exceed "
-                        + MAX_INET_MASK);
+                                + MAX_INET_MASK);
             }
         }
 
@@ -200,7 +200,7 @@
         byte [] net = new byte [4];
         byte [] mask = bytes(mask());
         for (int i = 0; i < INET_LEN; i++) {
-             net[i] = (byte) (octets[i] & mask[i]);
+            net[i] = (byte) (octets[i] & mask[i]);
         }
         return new IpAddress(version, net, netmask);
     }
@@ -221,11 +221,15 @@
         byte [] host = new byte [INET_LEN];
         byte [] mask = bytes(mask());
         for (int i = 0; i < INET_LEN; i++) {
-             host[i] = (byte) (octets[i] & ~mask[i]);
+            host[i] = (byte) (octets[i] & ~mask[i]);
         }
         return new IpAddress(version, host, netmask);
     }
 
+    public boolean isMasked() {
+        return mask() != 0;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;