WIP: Initial implementation of filterObjectives using driver subsystem.

Incomplete implementation

Change-Id: I3745d481027659d4ca44b72139e5461c02e8c3ef
diff --git a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
index 9a4ecba..58e796f 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
@@ -15,14 +15,11 @@
  */
 package org.onosproject.bgprouter;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
+import com.google.common.collect.ConcurrentHashMultiset;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multiset;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -45,12 +42,14 @@
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.FlowRule.Type;
 import org.onosproject.net.flow.FlowRuleOperations;
-import org.onosproject.net.flow.FlowRuleOperationsContext;
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flowobjective.DefaultFilteringObjective;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
 import org.onosproject.net.group.DefaultGroupBucket;
 import org.onosproject.net.group.DefaultGroupDescription;
 import org.onosproject.net.group.DefaultGroupKey;
@@ -73,11 +72,13 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ConcurrentHashMultiset;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multiset;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * BgpRouter component.
@@ -156,6 +157,10 @@
                     .register(NextHopGroupKey.class)
                     .build();
 
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowObjectiveService flowObjectiveService;
+
     @Activate
     protected void activate() {
         appId = coreService.registerApplication(BGP_ROUTER_APP);
@@ -377,336 +382,28 @@
 
     private class InternalTableHandler {
 
-        private static final int CONTROLLER_PRIORITY = 255;
-        private static final int DROP_PRIORITY = 0;
-        private static final int HIGHEST_PRIORITY = 0xffff;
         private Set<InterfaceIpAddress> intfIps = new HashSet<InterfaceIpAddress>();
         private Set<MacAddress> intfMacs = new HashSet<MacAddress>();
         private Map<PortNumber, VlanId> portVlanPair = Maps.newHashMap();
 
         public void provision(boolean install, Set<Interface> intfs) {
             getInterfaceConfig(intfs);
-            processTableZero(install);
-            processTableOne(install);
-            processTableTwo(install);
-            processTableFour(install);
-            processTableFive(install);
-            processTableSix(install);
-            processTableNine(install);
         }
 
         private void getInterfaceConfig(Set<Interface> intfs) {
             log.info("Processing {} router interfaces", intfs.size());
             for (Interface intf : intfs) {
+                FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
+                flowObjectiveService.filter(deviceId, Collections.singletonList(
+                        fob.addCondition(Criteria.matchEthDst(intf.mac()))
+                                .fromApp(appId).permit().add()));
                 intfIps.addAll(intf.ipAddresses());
                 intfMacs.add(intf.mac());
                 portVlanPair.put(intf.connectPoint().port(), intf.vlan());
             }
         }
 
-        private void processTableZero(boolean install) {
-            TrafficSelector.Builder selector;
-            TrafficTreatment.Builder treatment;
-
-            // Bcast rule
-            selector = DefaultTrafficSelector.builder();
-            treatment = DefaultTrafficTreatment.builder();
-
-            selector.matchEthDst(MacAddress.BROADCAST);
-            treatment.transition(FlowRule.Type.VLAN_MPLS);
-
-            FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
-                                                treatment.build(),
-                                                CONTROLLER_PRIORITY, appId, 0,
-                                                true, FlowRule.Type.FIRST);
-
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            // Interface MACs
-            for (MacAddress mac : intfMacs) {
-                log.debug("adding rule for MAC: {}", mac);
-                selector = DefaultTrafficSelector.builder();
-                treatment = DefaultTrafficTreatment.builder();
-
-                selector.matchEthDst(mac);
-                treatment.transition(FlowRule.Type.VLAN_MPLS);
-
-                rule = new DefaultFlowRule(deviceId, selector.build(),
-                                           treatment.build(),
-                                           CONTROLLER_PRIORITY, appId, 0,
-                                           true, FlowRule.Type.FIRST);
-
-                ops = install ? ops.add(rule) : ops.remove(rule);
-            }
-
-            //Drop rule
-            selector = DefaultTrafficSelector.builder();
-            treatment = DefaultTrafficTreatment.builder();
-
-            treatment.drop();
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), DROP_PRIORITY, appId,
-                                       0, true, FlowRule.Type.FIRST);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            flowService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    log.info("Provisioned default table for bgp router");
-                }
-
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    log.info("Failed to provision default table for bgp router");
-                }
-            }));
-
-        }
-
-        private void processTableOne(boolean install) {
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                    .builder();
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-            FlowRule rule;
-
-            selector.matchVlanId(VlanId.ANY);
-            treatment.transition(FlowRule.Type.VLAN);
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), CONTROLLER_PRIORITY,
-                                       appId, 0, true, FlowRule.Type.VLAN_MPLS);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            flowService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    log.info("Provisioned vlan/mpls table for bgp router");
-                }
-
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    log.info(
-                            "Failed to provision vlan/mpls table for bgp router");
-                }
-            }));
-
-        }
-
-        private void processTableTwo(boolean install) {
-            TrafficSelector.Builder selector;
-            TrafficTreatment.Builder treatment;
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-            FlowRule rule;
-
-            //Interface Vlans
-            for (Map.Entry<PortNumber, VlanId> portVlan : portVlanPair.entrySet()) {
-                log.debug("adding rule for VLAN: {}", portVlan);
-                selector = DefaultTrafficSelector.builder();
-                treatment = DefaultTrafficTreatment.builder();
-
-                selector.matchVlanId(portVlan.getValue());
-                selector.matchInPort(portVlan.getKey());
-                treatment.transition(Type.ETHER);
-                treatment.deferred().popVlan();
-
-                rule = new DefaultFlowRule(deviceId, selector.build(),
-                                           treatment.build(), CONTROLLER_PRIORITY, appId,
-                                           0, true, FlowRule.Type.VLAN);
-
-                ops = install ? ops.add(rule) : ops.remove(rule);
-            }
-
-            //Drop rule
-            selector = DefaultTrafficSelector.builder();
-            treatment = DefaultTrafficTreatment.builder();
-
-            treatment.drop();
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), DROP_PRIORITY, appId,
-                                       0, true, FlowRule.Type.VLAN);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            flowService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    log.info("Provisioned vlan table for bgp router");
-                }
-
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    log.info("Failed to provision vlan table for bgp router");
-                }
-            }));
-        }
-
-        private void processTableFour(boolean install) {
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                    .builder();
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-            FlowRule rule;
-
-            selector.matchEthType(Ethernet.TYPE_ARP);
-            treatment.punt();
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), CONTROLLER_PRIORITY,
-                                       appId, 0, true, FlowRule.Type.ETHER);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            selector = DefaultTrafficSelector.builder();
-            treatment = DefaultTrafficTreatment.builder();
-
-            selector.matchEthType(Ethernet.TYPE_IPV4);
-            treatment.transition(FlowRule.Type.COS);
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), CONTROLLER_PRIORITY,
-                                       appId, 0, true, FlowRule.Type.ETHER);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            //Drop rule
-            selector = DefaultTrafficSelector.builder();
-            treatment = DefaultTrafficTreatment.builder();
-
-            treatment.drop();
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), DROP_PRIORITY, appId,
-                                       0, true, FlowRule.Type.ETHER);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            flowService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    log.info("Provisioned ether table for bgp router");
-                }
-
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    log.info("Failed to provision ether table for bgp router");
-                }
-            }));
-
-        }
-
-        private void processTableFive(boolean install) {
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                    .builder();
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-            FlowRule rule;
-
-            treatment.transition(FlowRule.Type.IP);
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), DROP_PRIORITY, appId,
-                                       0, true, FlowRule.Type.COS);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            flowService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    log.info("Provisioned cos table for bgp router");
-                }
-
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    log.info("Failed to provision cos table for bgp router");
-                }
-            }));
-
-        }
-
-        private void processTableSix(boolean install) {
-            TrafficSelector.Builder selector;
-            TrafficTreatment.Builder treatment;
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-            FlowRule rule;
-
-
-            //Interface IPs
-            for (InterfaceIpAddress ipAddr : intfIps) {
-                log.debug("adding rule for IPs: {}", ipAddr.ipAddress());
-                selector = DefaultTrafficSelector.builder();
-                treatment = DefaultTrafficTreatment.builder();
-
-                selector.matchEthType(Ethernet.TYPE_IPV4);
-                selector.matchIPDst(IpPrefix.valueOf(ipAddr.ipAddress(), 32));
-                treatment.transition(Type.ACL);
-
-                rule = new DefaultFlowRule(deviceId, selector.build(),
-                                           treatment.build(), HIGHEST_PRIORITY, appId,
-                                           0, true, FlowRule.Type.IP);
-
-                ops = install ? ops.add(rule) : ops.remove(rule);
-            }
-
-
-            //Drop rule
-            selector = DefaultTrafficSelector.builder();
-            treatment = DefaultTrafficTreatment.builder();
-
-            treatment.drop();
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), DROP_PRIORITY, appId,
-                                       0, true, FlowRule.Type.IP);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            flowService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    log.info("Provisioned FIB table for bgp router");
-                }
-
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    log.info("Failed to provision FIB table for bgp router");
-                }
-            }));
-        }
-
-        private void processTableNine(boolean install) {
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                    .builder();
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-            FlowRule rule;
-
-            treatment.punt();
-
-            rule = new DefaultFlowRule(deviceId, selector.build(),
-                                       treatment.build(), CONTROLLER_PRIORITY,
-                                       appId, 0, true, FlowRule.Type.DEFAULT);
-
-            ops = install ? ops.add(rule) : ops.remove(rule);
-
-            flowService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    log.info("Provisioned Local table for bgp router");
-                }
 
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    log.info("Failed to provision Local table for bgp router");
-                }
-            }));
-        }
     }
 
     private class InternalGroupListener implements GroupListener {
diff --git a/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java b/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java
index eb6a302..001c490 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java
@@ -26,4 +26,9 @@
     public void setData(DriverData data) {
         this.data = data;
     }
+
+    @Override
+    public DriverData data() {
+        return data;
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java b/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java
index 7257eed..208eef7 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java
@@ -29,4 +29,11 @@
      */
     void setData(DriverData data);
 
+    /**
+     * Obtains the driver data.
+     *
+     * @return driver data
+     */
+    DriverData data();
+
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java
index 4c1b71f..da92b80 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java
@@ -32,7 +32,7 @@
 public final class DefaultFilteringObjective implements FilteringObjective {
 
 
-    private final Criterion key;
+    private final Type type;
     private final boolean permanent;
     private final int timeout;
     private final ApplicationId appId;
@@ -41,10 +41,10 @@
     private final int id;
     private final Operation op;
 
-    private DefaultFilteringObjective(Criterion key, boolean permanent, int timeout,
+    private DefaultFilteringObjective(Type type, boolean permanent, int timeout,
                                       ApplicationId appId, int priority,
                                       List<Criterion> conditions, Operation op) {
-        this.key = key;
+        this.type = type;
         this.permanent = permanent;
         this.timeout = timeout;
         this.appId = appId;
@@ -52,14 +52,13 @@
         this.conditions = conditions;
         this.op = op;
 
-        this.id = Objects.hash(key, conditions, permanent,
+        this.id = Objects.hash(type, conditions, permanent,
                                timeout, appId, priority);
     }
 
-
     @Override
-    public Criterion key() {
-        return key;
+    public Type type() {
+        return this.type;
     }
 
     @Override
@@ -111,7 +110,7 @@
         private final ImmutableList.Builder<Criterion> listBuilder
                 = ImmutableList.builder();
 
-        private Criterion key;
+        private Type type;
         private boolean permanent = DEFAULT_PERMANENT;
         private int timeout = DEFAULT_TIMEOUT;
         private ApplicationId appId;
@@ -124,8 +123,14 @@
         }
 
         @Override
-        public Builder withKey(Criterion criterion) {
-            key = criterion;
+        public Builder permit() {
+            this.type = Type.PERMIT;
+            return this;
+        }
+
+        @Override
+        public Builder deny() {
+            this.type = Type.DENY;
             return this;
         }
 
@@ -157,11 +162,11 @@
         @Override
         public FilteringObjective add() {
             List<Criterion> conditions = listBuilder.build();
-            checkNotNull(key, "Must have a key.");
+            checkNotNull(type, "Must have a type.");
             checkArgument(!conditions.isEmpty(), "Must have at least one condition.");
             checkNotNull(appId, "Must supply an application id");
 
-            return new DefaultFilteringObjective(key, permanent, timeout,
+            return new DefaultFilteringObjective(type, permanent, timeout,
                                                 appId, priority, conditions,
                                                 Operation.ADD);
 
@@ -170,11 +175,11 @@
         @Override
         public FilteringObjective remove() {
             List<Criterion> conditions = listBuilder.build();
-            checkNotNull(key, "Must have a key.");
+            checkNotNull(type, "Must have a type.");
             checkArgument(!conditions.isEmpty(), "Must have at least one condition.");
             checkNotNull(appId, "Must supply an application id");
 
-            return new DefaultFilteringObjective(key, permanent, timeout,
+            return new DefaultFilteringObjective(type, permanent, timeout,
                                                  appId, priority, conditions,
                                                  Operation.REMOVE);
 
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java
index 93f62ac9..24ca2dc 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.flowobjective;
 
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.flow.criteria.Criterion;
 
 import java.util.Collection;
@@ -27,12 +28,23 @@
  */
 public interface FilteringObjective extends Objective {
 
+    enum Type {
+        /**
+         * Enables the filtering condition.
+         */
+        PERMIT,
+
+        /**
+         * Disables the filtering condition.
+         */
+        DENY
+    }
+
     /**
-     * Represents filtering key used in this filter.
-     *
-     * @return a criterion
+     * Obtain this filtering type.
+     * @return the type
      */
-    Criterion key();
+    public Type type();
 
     /**
      * The set of conditions the filter must provision at the device.
@@ -55,12 +67,23 @@
         public Builder addCondition(Criterion criterion);
 
         /**
-         * Add a filtering key.
-         *
-         * @param criterion new criterion
-         * @return a filtering builder.
+         * Permit this filtering condition set.
+         * @return a filtering builder
          */
-        public Builder withKey(Criterion criterion);
+        public Builder permit();
+
+        /**
+         * Deny this filtering condition set.
+         * @return a filtering builder
+         */
+        public Builder deny();
+
+        /**
+         * Assigns an application id.
+         * @param appId an application id
+         * @return a filtering builder
+         */
+        public Builder fromApp(ApplicationId appId);
 
         /**
          * Builds the filtering objective that will be added.
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
index 3c1ec35..29e5857 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
@@ -15,7 +15,9 @@
  */
 package org.onosproject.net.flowobjective.impl;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -43,11 +45,13 @@
 import org.onosproject.net.flowobjective.FlowObjectiveService;
 import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
 import org.onosproject.net.group.GroupService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.Future;
 
@@ -87,12 +91,16 @@
 
 
     private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
+    private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
 
     private final PipelinerContext context = new InnerPipelineContext();
     private final MastershipListener mastershipListener = new InnerMastershipListener();
     private final DeviceListener deviceListener = new InnerDeviceListener();
 
     protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
+
+    private final Map<DeviceId, Collection<Objective>> pendingObjectives =
+            Maps.newConcurrentMap();
     private NodeId localNode;
 
     @Activate
@@ -114,26 +122,51 @@
     @Override
     public Future<Boolean> filter(DeviceId deviceId,
                                   Collection<FilteringObjective> filteringObjectives) {
-        return getDevicePipeliner(deviceId).filter(filteringObjectives);
+        if (deviceService.isAvailable(deviceId)) {
+            return getDevicePipeliner(deviceId).filter(filteringObjectives);
+        } else {
+            filteringObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
+        }
+        return Futures.immediateFuture(true);
     }
 
+
+
     @Override
     public Future<Boolean> forward(DeviceId deviceId,
                                    Collection<ForwardingObjective> forwardingObjectives) {
-        return getDevicePipeliner(deviceId).forward(forwardingObjectives);
+        if (deviceService.isAvailable(deviceId)) {
+            return getDevicePipeliner(deviceId).forward(forwardingObjectives);
+        } else {
+            forwardingObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
+        }
+        return Futures.immediateFuture(true);
     }
 
     @Override
     public Future<Boolean> next(DeviceId deviceId,
                                 Collection<NextObjective> nextObjectives) {
-        return getDevicePipeliner(deviceId).next(nextObjectives);
+        if (deviceService.isAvailable(deviceId)) {
+            return getDevicePipeliner(deviceId).next(nextObjectives);
+        } else {
+            nextObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
+        }
+        return Futures.immediateFuture(true);
     }
 
-    // Retrieves the device handler pipeline behaviour from the cache.
+    private void updatePendingMap(DeviceId deviceId, Objective pending) {
+        if (pendingObjectives.putIfAbsent(deviceId, Lists.newArrayList(pending)) != null) {
+            Collection<Objective> objectives = pendingObjectives.get(deviceId);
+            objectives.add(pending);
+        }
+
+    }
+
+    // Retrieves the device pipeline behaviour from the cache.
     private Pipeliner getDevicePipeliner(DeviceId deviceId) {
-        DriverHandler handler = driverHandlers.get(deviceId);
-        checkState(handler != null, NOT_INITIALIZED);
-        return handler != null ? handler.behaviour(Pipeliner.class) : null;
+        Pipeliner pipeliner = pipeliners.get(deviceId);
+        checkState(pipeliner != null, NOT_INITIALIZED);
+        return pipeliner;
     }
 
 
@@ -164,6 +197,7 @@
                 case DEVICE_AVAILABILITY_CHANGED:
                     if (deviceService.isAvailable(event.subject().id())) {
                         setupPipelineHandler(event.subject().id());
+                        processPendingObjectives(event.subject().id());
                     }
                     break;
                 case DEVICE_UPDATED:
@@ -182,6 +216,21 @@
                     break;
             }
         }
+
+        private void processPendingObjectives(DeviceId deviceId) {
+            pendingObjectives.get(deviceId).forEach(obj -> {
+                if (obj instanceof NextObjective) {
+                    getDevicePipeliner(deviceId)
+                            .next(Collections.singletonList((NextObjective) obj));
+                } else if (obj instanceof ForwardingObjective) {
+                    getDevicePipeliner(deviceId)
+                            .forward(Collections.singletonList((ForwardingObjective) obj));
+                } else {
+                    getDevicePipeliner(deviceId)
+                            .filter(Collections.singletonList((FilteringObjective) obj));
+                }
+            });
+        }
     }
 
     private void setupPipelineHandler(DeviceId deviceId) {
@@ -205,7 +254,9 @@
             }
 
             // Always (re)initialize the pipeline behaviour
-            handler.behaviour(Pipeliner.class).init(deviceId, context);
+            Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
+            pipeliner.init(deviceId, context);
+            pipeliners.putIfAbsent(deviceId, pipeliner);
             log.info("Driver {} bound to device {}", handler.driver().name(), deviceId);
         }
     }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
index 3da786a..5af2563 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.driver.pipeline;
 
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.SettableFuture;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.MacAddress;
@@ -34,9 +36,12 @@
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
 import org.onosproject.net.flowobjective.FilteringObjective;
 import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
 import org.slf4j.Logger;
 
 import java.util.Collection;
@@ -79,7 +84,54 @@
 
     @Override
     public Future<Boolean> filter(Collection<FilteringObjective> filteringObjectives) {
-        return null;
+        Collection<Future<Boolean>> results =
+                Sets.newHashSet();
+        filteringObjectives.stream()
+                .filter(obj -> obj.type() == FilteringObjective.Type.PERMIT)
+                .forEach(obj -> obj.conditions()
+                        .forEach(condition ->
+                            results.add(processCondition(condition,
+                                                   obj.op() == Objective.Operation.ADD,
+                                                   obj.appId()))
+                        ));
+
+        //TODO: return something more helpful/sensible in the future (no pun intended)
+        return results.iterator().next();
+
+    }
+
+    private Future<Boolean> processCondition(Criterion c, boolean install,
+                                             ApplicationId applicationId) {
+        SettableFuture<Boolean> result = SettableFuture.create();
+        if (c.type() == Criterion.Type.ETH_DST) {
+            Criteria.EthCriterion e = (Criteria.EthCriterion) c;
+            log.debug("adding rule for MAC: {}", e.mac());
+
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            selector.matchEthDst(e.mac());
+            treatment.transition(FlowRule.Type.VLAN_MPLS);
+            FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
+                                                treatment.build(),
+                                                CONTROLLER_PRIORITY, applicationId, 0,
+                                                true, FlowRule.Type.FIRST);
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            ops =  install ? ops.add(rule) : ops.remove(rule);
+            flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    result.set(true);
+                    log.info("Provisioned default table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    result.set(false);
+                    log.info("Failed to provision default table for bgp router");
+                }
+            }));
+        }
+        return result;
     }
 
     @Override