Add driver support for Corsa Pipeline V3

Change-Id: If5c1aa9cec6093e3c9f2f908de6066957d9ad8fd
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipeline.java
index ccf7307..c640bff 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipeline.java
@@ -26,8 +26,13 @@
 import org.onosproject.net.flow.FlowRuleOperationsContext;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.ObjectiveError;
 import org.slf4j.Logger;
 
+import java.util.Collection;
+import java.util.Collections;
+
 /**
  * Driver for Corsa TTP.
  *
@@ -70,7 +75,14 @@
                         "Failed to provision vlan/mpls table");
             }
         }));
+    }
 
+    @Override
+    protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) {
+        /* Not supported by until CorsaPipelineV3 */
+        log.warn("Vlan switching not supported in corsa-v1 driver");
+        fail(fwd, ObjectiveError.UNSUPPORTED);
+        return Collections.emptySet();
     }
 
 }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipelineV3.java b/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipelineV3.java
new file mode 100644
index 0000000..a734899
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipelineV3.java
@@ -0,0 +1,421 @@
+package org.onosproject.driver.pipeline;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
+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.flow.criteria.EthCriterion;
+import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.DefaultBand;
+import org.onosproject.net.meter.DefaultMeterRequest;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterRequest;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+public class CorsaPipelineV3 extends OVSCorsaPipeline {
+
+    private final Logger log = getLogger(getClass());
+
+    protected static final int PORT_BASED_PROTO_TABLE = 0;
+    protected static final int VLAN_CHECK_TABLE = 1;
+    protected static final int VLAN_MAC_XLATE_TABLE = 2;
+    protected static final int VLAN_CIRCUIT_TABLE = 3;
+    protected static final int PRIORITY_MAP_TABLE = 4;
+    protected static final int L3_IF_MAC_DA_TABLE = 5;
+    protected static final int ETHER_TABLE = 6;
+    protected static final int FIB_TABLE = 7;
+    protected static final int LOCAL_TABLE = 9;
+
+    protected static final byte MAX_VLAN_PCP = 7;
+
+    private MeterId defaultMeterId = null;
+
+    @Override
+    protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) {
+        TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
+
+        treatment.immediate().stream()
+                .filter(i -> i instanceof L2ModificationInstruction.ModVlanIdInstruction ||
+                             i instanceof L2ModificationInstruction.ModEtherInstruction ||
+                             i instanceof Instructions.OutputInstruction)
+                .forEach(i -> tb.add(i));
+        return tb.build();
+    }
+
+    @Override
+    protected TrafficTreatment.Builder processSpecificRoutingTreatment() {
+        return DefaultTrafficTreatment.builder().deferred();
+    }
+
+    @Override
+    protected FlowRule.Builder processSpecificRoutingRule(FlowRule.Builder rb) {
+        return rb.forTable(FIB_TABLE);
+    }
+
+    @Override
+    protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) {
+        TrafficSelector filteredSelector =
+                DefaultTrafficSelector.builder()
+                        .matchInPort(
+                                ((PortCriterion) fwd.selector().getCriterion(Criterion.Type.IN_PORT)).port())
+                        .matchVlanId(
+                                ((VlanIdCriterion) fwd.selector().getCriterion(Criterion.Type.VLAN_VID)).vlanId())
+                        .build();
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .fromApp(fwd.appId())
+                .withPriority(fwd.priority())
+                .forDevice(deviceId)
+                .withSelector(filteredSelector)
+                .withTreatment(fwd.treatment())
+                .forTable(VLAN_CIRCUIT_TABLE);
+
+        if (fwd.permanent()) {
+            ruleBuilder.makePermanent();
+        } else {
+            ruleBuilder.makeTemporary(fwd.timeout());
+        }
+
+        return Collections.singletonList(ruleBuilder.build());
+    }
+
+    @Override
+    protected void processFilter(FilteringObjective filt, boolean install,
+                               ApplicationId applicationId) {
+        // This driver only processes filtering criteria defined with switch
+        // ports as the key
+        PortCriterion p;
+        if (!filt.key().equals(Criteria.dummy()) &&
+                filt.key().type() == Criterion.Type.IN_PORT) {
+            p = (PortCriterion) filt.key();
+        } else {
+            log.warn("No key defined in filtering objective from app: {}. Not"
+                    + "processing filtering objective", applicationId);
+            fail(filt, ObjectiveError.UNKNOWN);
+            return;
+        }
+        // convert filtering conditions for switch-intfs into flowrules
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        for (Criterion c : filt.conditions()) {
+            if (c.type() == Criterion.Type.ETH_DST) {
+                EthCriterion e = (EthCriterion) c;
+                log.debug("adding rule for MAC: {}", e.mac());
+                TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+                selector.matchEthDst(e.mac());
+                selector.matchInPort(p.port());
+                treatment.transition(ETHER_TABLE);
+                FlowRule rule = DefaultFlowRule.builder()
+                        .forDevice(deviceId)
+                        .withSelector(selector.build())
+                        .withTreatment(treatment.build())
+                        .withPriority(CONTROLLER_PRIORITY)
+                        .fromApp(applicationId)
+                        .makePermanent()
+                        .forTable(L3_IF_MAC_DA_TABLE).build();
+                ops =  install ? ops.add(rule) : ops.remove(rule);
+            } else if (c.type() == Criterion.Type.VLAN_VID) {
+                VlanIdCriterion v = (VlanIdCriterion) c;
+                log.debug("adding rule for VLAN: {}", v.vlanId());
+                TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+                selector.matchVlanId(v.vlanId());
+                selector.matchInPort(p.port());
+                /* Static treatment for VLAN_CIRCUIT_TABLE */
+                treatment.setVlanPcp(MAX_VLAN_PCP);
+                treatment.setQueue(0);
+                treatment.meter(MeterId.meterId(defaultMeterId.id())); /* use default meter (Green) */
+                treatment.transition(L3_IF_MAC_DA_TABLE);
+                FlowRule rule = DefaultFlowRule.builder()
+                        .forDevice(deviceId)
+                        .withSelector(selector.build())
+                        .withTreatment(treatment.build())
+                        .withPriority(CONTROLLER_PRIORITY)
+                        .fromApp(applicationId)
+                        .makePermanent()
+                        .forTable(VLAN_CIRCUIT_TABLE).build();
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            } else if (c.type() == Criterion.Type.IPV4_DST) {
+                IPCriterion ip = (IPCriterion) c;
+                log.debug("adding rule for IP: {}", ip.ip());
+                TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+                selector.matchEthType(Ethernet.TYPE_IPV4);
+                selector.matchIPDst(ip.ip());
+                treatment.transition(LOCAL_TABLE);
+                FlowRule rule = DefaultFlowRule.builder()
+                        .forDevice(deviceId)
+                        .withSelector(selector.build())
+                        .withTreatment(treatment.build())
+                        .withPriority(HIGHEST_PRIORITY)
+                        .fromApp(applicationId)
+                        .makePermanent()
+                        .forTable(FIB_TABLE).build();
+
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            } else {
+                log.warn("Driver does not currently process filtering condition"
+                        + " of type: {}", c.type());
+                fail(filt, ObjectiveError.UNSUPPORTED);
+            }
+        }
+        // apply filtering flow rules
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                pass(filt);
+                log.info("Applied filtering rules");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
+                log.info("Failed to apply filtering rules");
+            }
+        }));
+    }
+
+    public void initializePipeline() {
+        processMeterTable(true);
+        processPortBasedProtoTable(true); /* Table 0 */
+        processVlanCheckTable(true);      /* Table 1 */
+        processVlanMacXlateTable(true);   /* Table 2 */
+        processVlanCircuitTable(true);    /* Table 3 */
+        processPriorityMapTable(true);    /* Table 4 */
+        processL3IFMacDATable(true);      /* Table 5 */
+        processEtherTable(true);          /* Table 6 */
+        processFibTable(true);            /* Table 7 */
+        processLocalTable(true);          /* Table 9 */
+    }
+
+    private void processMeterTable(boolean install) {
+        /* Green meter : Pass all traffic */
+        Band dropBand = DefaultBand.builder()
+                .ofType(Band.Type.DROP)
+                .withRate(0xFFFFFFFF)   /* Max Rate */
+                .build();
+        MeterRequest.Builder ops = DefaultMeterRequest.builder()
+                .forDevice(deviceId)
+                .withBands(Collections.singletonList(dropBand))
+                .fromApp(appId);
+
+        Meter meter = meterService.submit(install ? ops.add() : ops.remove());
+        defaultMeterId = meter.id();
+    }
+
+    private void processPortBasedProtoTable(boolean install) {
+        /* Default action */
+        processTableMissGoTo(install, PORT_BASED_PROTO_TABLE, VLAN_CHECK_TABLE);
+    }
+
+    private void processVlanCheckTable(boolean install) {
+        int table = VLAN_CHECK_TABLE;
+
+        /* Default action */
+        processTableMissDrop(install, table);
+
+        /* Tagged packets to VLAN_MAC_XLATE */
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchVlanId(VlanId.ANY);
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(VLAN_MAC_XLATE_TABLE);
+
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(CONTROLLER_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(table).build();
+        processFlowRule(install, rule);
+    }
+
+    private void processVlanMacXlateTable(boolean install) {
+        /* Default action */
+        processTableMissGoTo(install, VLAN_MAC_XLATE_TABLE, VLAN_CIRCUIT_TABLE);
+    }
+
+    private void processVlanCircuitTable(boolean install) {
+        /* Default action */
+        processTableMissDrop(install, VLAN_CIRCUIT_TABLE);
+    }
+
+    private void processPriorityMapTable(boolean install) {
+        /* Not required currently */
+    }
+
+    private void processL3IFMacDATable(boolean install) {
+        int table = L3_IF_MAC_DA_TABLE;
+
+        /* Default action */
+        processTableMissDrop(install, table);
+
+        /* Allow MAC broadcast frames on all ports */
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchEthDst(MacAddress.BROADCAST);
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(ETHER_TABLE);
+
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(CONTROLLER_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(table).build();
+        processFlowRule(install, rule);
+    }
+
+
+    private void processEtherTable(boolean install) {
+        int table = ETHER_TABLE;
+
+        /* Default action */
+        processTableMissDrop(install, table);
+
+        /* Arp to controller */
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchEthType(Ethernet.TYPE_ARP);
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.punt();
+
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(CONTROLLER_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(table).build();
+        processFlowRule(install, rule);
+
+        /* IP to FIB_TABLE */
+        selector = DefaultTrafficSelector.builder();
+        selector.matchEthType(Ethernet.TYPE_IPV4);
+
+        treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(FIB_TABLE);
+
+        rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(CONTROLLER_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(table).build();
+        processFlowRule(install, rule);
+    }
+
+    private void processFibTable(boolean install) {
+        /* Default action */
+        processTableMissDrop(install, FIB_TABLE);
+    }
+
+    private void processLocalTable(boolean install) {
+        int table = LOCAL_TABLE;
+        /* Default action */
+        processTableMissDrop(install, table);
+
+        /* Send all protocols to controller */
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.punt();
+
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(CONTROLLER_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(table).build();
+        processFlowRule(install, rule);
+    }
+
+    /* Init helper: Apply flow rule */
+    private void processFlowRule(boolean install, FlowRule rule) {
+        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) {
+                log.info("Flow provision success: " + ops.toString() + ", " + rule.toString());
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Flow provision error: " + ops.toString() + ", " + rule.toString());
+            }
+        }));
+    }
+
+    /* Init helper: Table Miss = Drop */
+    private void processTableMissDrop(boolean install, int table) {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.drop();
+
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DROP_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(table).build();
+
+        processFlowRule(install, rule);
+    }
+
+    /* Init helper: Table Miss = GoTo */
+    private void processTableMissGoTo(boolean install, int table, int goTo) {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(goTo);
+
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DROP_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(table).build();
+
+        processFlowRule(install, rule);
+    }
+}
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 5993d96..5a8c68c 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
@@ -67,6 +67,7 @@
 import org.onosproject.net.group.GroupKey;
 import org.onosproject.net.group.GroupListener;
 import org.onosproject.net.group.GroupService;
+import org.onosproject.net.meter.MeterService;
 import org.slf4j.Logger;
 
 import java.util.Collection;
@@ -96,8 +97,8 @@
 
 
     protected static final int CONTROLLER_PRIORITY = 255;
-    private static final int DROP_PRIORITY = 0;
-    private static final int HIGHEST_PRIORITY = 0xffff;
+    protected static final int DROP_PRIORITY = 0;
+    protected static final int HIGHEST_PRIORITY = 0xffff;
 
     private final Logger log = getLogger(getClass());
 
@@ -105,6 +106,7 @@
     protected FlowRuleService flowRuleService;
     private CoreService coreService;
     private GroupService groupService;
+    protected MeterService meterService;
     private FlowObjectiveStore flowObjectiveStore;
     protected DeviceId deviceId;
     protected ApplicationId appId;
@@ -140,6 +142,7 @@
         coreService = serviceDirectory.get(CoreService.class);
         flowRuleService = serviceDirectory.get(FlowRuleService.class);
         groupService = serviceDirectory.get(GroupService.class);
+        meterService = serviceDirectory.get(MeterService.class);
         flowObjectiveStore = context.store();
 
         groupService.addListener(new InnerGroupListener());
@@ -205,6 +208,7 @@
                 Collection<TrafficTreatment> treatments = nextObjective.next();
                 if (treatments.size() == 1) {
                     TrafficTreatment treatment = treatments.iterator().next();
+                    treatment = processNextTreatment(treatment);
                     GroupBucket bucket =
                             DefaultGroupBucket.createIndirectGroupBucket(treatment);
                     final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
@@ -233,6 +237,11 @@
 
     }
 
+    /* Hook for altering the NextObjective treatment */
+    protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) {
+        return treatment;  /* Keep treatment as is for OVSCorsaPipeline */
+    }
+
     private Collection<FlowRule> processForward(ForwardingObjective fwd) {
         switch (fwd.flag()) {
             case SPECIFIC:
@@ -301,22 +310,32 @@
     private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
         log.debug("Processing specific forwarding objective");
         TrafficSelector selector = fwd.selector();
+
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
-        if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
-            fail(fwd, ObjectiveError.UNSUPPORTED);
-            return Collections.emptySet();
+        if (ethType != null) {
+            short et = ethType.ethType().toShort();
+            if (et == Ethernet.TYPE_IPV4) {
+                return processSpecificRoute(fwd);
+            } else if (et == Ethernet.TYPE_VLAN) {
+                /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */
+                return processSpecificSwitch(fwd);
+            }
         }
 
+        fail(fwd, ObjectiveError.UNSUPPORTED);
+        return Collections.emptySet();
+    }
+
+    private Collection<FlowRule> processSpecificRoute(ForwardingObjective fwd) {
         TrafficSelector filteredSelector =
                 DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPDst(
-                                ((IPCriterion)
-                                        selector.getCriterion(Criterion.Type.IPV4_DST)).ip())
+                                ((IPCriterion) fwd.selector().getCriterion(Criterion.Type.IPV4_DST)).ip())
                         .build();
 
-        TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
+        TrafficTreatment.Builder tb = processSpecificRoutingTreatment();
 
         if (fwd.nextId() != null) {
             NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
@@ -337,20 +356,35 @@
                 .withSelector(filteredSelector)
                 .withTreatment(tb.build());
 
+        ruleBuilder = processSpecificRoutingRule(ruleBuilder);
+
         if (fwd.permanent()) {
             ruleBuilder.makePermanent();
         } else {
             ruleBuilder.makeTemporary(fwd.timeout());
         }
 
-        ruleBuilder.forTable(FIB_TABLE);
-
-
         return Collections.singletonList(ruleBuilder.build());
-
     }
 
-    private void processFilter(FilteringObjective filt, boolean install,
+    /* Hook for modifying Route traffic treatment */
+    protected TrafficTreatment.Builder processSpecificRoutingTreatment() {
+        return DefaultTrafficTreatment.builder();
+    }
+
+    /* Hook for modifying Route flow rule */
+    protected FlowRule.Builder processSpecificRoutingRule(FlowRule.Builder rb) {
+        return rb.forTable(FIB_TABLE);
+    }
+
+    protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) {
+        /* Not supported by until CorsaPipelineV3 */
+        log.warn("Vlan switching not supported in ovs-corsa driver");
+        fail(fwd, ObjectiveError.UNSUPPORTED);
+        return Collections.emptySet();
+    }
+
+    protected void processFilter(FilteringObjective filt, boolean install,
                                              ApplicationId applicationId) {
         // This driver only processes filtering criteria defined with switch
         // ports as the key
@@ -441,19 +475,19 @@
         }));
     }
 
-    private void pass(Objective obj) {
+    protected void pass(Objective obj) {
         if (obj.context().isPresent()) {
             obj.context().get().onSuccess(obj);
         }
     }
 
-    private void fail(Objective obj, ObjectiveError error) {
+    protected void fail(Objective obj, ObjectiveError error) {
         if (obj.context().isPresent()) {
             obj.context().get().onError(obj, error);
         }
     }
 
-    private void initializePipeline() {
+    protected void initializePipeline() {
         processMacTable(true);
         processVlanMplsTable(true);
         processVlanTable(true);