Deprecate CpqD pipeliners

In addition,
  - Update processVersatile to handle more selectors in ovs-ofdpa
    This also fixes the issue of XConnect ACL flow not being programmed correctly
  - Refactor the code a bit to reduce duplication

Change-Id: I190aad904d3e6625ff9f089c74e3b98077bbe4a3
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2VlanPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2VlanPipeline.java
deleted file mode 100644
index e9dc316..0000000
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2VlanPipeline.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.driver.pipeline.ofdpa;
-
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.List;
-
-import com.google.common.collect.ImmutableList;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.behaviour.NextGroup;
-import org.onosproject.net.behaviour.PipelinerContext;
-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.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criteria;
-import org.onosproject.net.flow.criteria.EthCriterion;
-import org.onosproject.net.flow.criteria.PortCriterion;
-import org.onosproject.net.flow.criteria.VlanIdCriterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
-import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.ObjectiveError;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupKey;
-import org.slf4j.Logger;
-
-
-/**
- * Driver for software switch emulation of the OFDPA 2.0 pipeline.
- * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
- * does not handle vlan tags and mpls labels simultaneously, which requires us
- * to do some workarounds in the driver. This driver is meant for the use of
- * the cpqd switch when MPLS is not a requirement from the ofdpa pipeline. As a
- * result this driver correctly handles both incoming untagged and vlan-tagged
- * packets.
- *
- */
-public class CpqdOfdpa2VlanPipeline extends CpqdOfdpa2Pipeline {
-
-    private final Logger log = getLogger(getClass());
-
-    @Override
-    protected void initDriverId() {
-        driverId = coreService.registerApplication(
-                "org.onosproject.driver.CpqdOfdpa2VlanPipeline");
-    }
-
-    @Override
-    protected void initGroupHander(PipelinerContext context) {
-        groupHandler = new CpqdOfdpa2GroupHandler();
-        groupHandler.init(deviceId, context);
-    }
-
-    /*
-     * Cpqd emulation does not handle vlan tags and mpls labels correctly.
-     * Since this driver does not deal with MPLS, there is no need for
-     * working around VLAN tags. In particular we do not pop off vlan tags in
-     * the middle of the pipeline.
-     *
-     * (non-Javadoc)
-     * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
-     */
-    @Override
-    protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
-                                                 EthCriterion ethCriterion,
-                                                 VlanIdCriterion vidCriterion,
-                                                 VlanId assignedVlan,
-                                                 MacAddress unicastMac,
-                                                 ApplicationId applicationId) {
-        // Consider PortNumber.ANY as wildcard. Match ETH_DST only
-        if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
-            return processEthDstOnlyFilter(ethCriterion, applicationId);
-        }
-
-        // Multicast MAC
-        if (ethCriterion.mask() != null) {
-            return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
-        }
-
-        //handling untagged packets via assigned VLAN
-        if (vidCriterion.vlanId() == VlanId.NONE) {
-            vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
-        }
-        // ofdpa cannot match on ALL portnumber, so we need to use separate
-        // rules for each port.
-        List<PortNumber> portnums = new ArrayList<>();
-        if (portCriterion != null) {
-            if (portCriterion.port() == PortNumber.ALL) {
-                for (Port port : deviceService.getPorts(deviceId)) {
-                    if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
-                        portnums.add(port.number());
-                    }
-                }
-            } else {
-                portnums.add(portCriterion.port());
-            }
-        }
-
-        List<FlowRule> rules = new ArrayList<>();
-        for (PortNumber pnum : portnums) {
-            // for unicast IP packets
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-            selector.matchInPort(pnum);
-            selector.matchVlanId(vidCriterion.vlanId());
-            selector.matchEthType(Ethernet.TYPE_IPV4);
-            selector.matchEthDst(ethCriterion.mac());
-
-            treatment.transition(UNICAST_ROUTING_TABLE);
-            FlowRule rule = DefaultFlowRule.builder()
-                    .forDevice(deviceId)
-                    .withSelector(selector.build())
-                    .withTreatment(treatment.build())
-                    .withPriority(DEFAULT_PRIORITY)
-                    .fromApp(applicationId)
-                    .makePermanent()
-                    .forTable(TMAC_TABLE).build();
-            rules.add(rule);
-        }
-        return ImmutableList.of(rules);
-    }
-
-    /*
-     * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
-     * ACL table. Since we do not pop off vlans in the TMAC table we can continue
-     * to match on vlans in the ACL table if necessary.
-     */
-    @Override
-    protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
-        log.info("Processing versatile forwarding objective");
-
-        if (fwd.nextId() == null && fwd.treatment() == null) {
-            log.error("Forwarding objective {} from {} must contain "
-                    + "nextId or Treatment", fwd.selector(), fwd.appId());
-            return Collections.emptySet();
-        }
-
-        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
-        fwd.selector().criteria().forEach(criterion -> {
-            if (criterion instanceof VlanIdCriterion) {
-                VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
-                // ensure that match does not include vlan = NONE as OF-DPA does not
-                // match untagged packets this way in the ACL table.
-                if (vlanId.equals(VlanId.NONE)) {
-                    return;
-                }
-            }
-            sbuilder.add(criterion);
-        });
-
-        // XXX driver does not currently do type checking as per Tables 65-67 in
-        // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
-        TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
-        if (fwd.treatment() != null) {
-            for (Instruction ins : fwd.treatment().allInstructions()) {
-                if (ins instanceof OutputInstruction) {
-                    OutputInstruction o = (OutputInstruction) ins;
-                    if (o.port() == PortNumber.CONTROLLER) {
-                        ttBuilder.add(o);
-                    } else {
-                        log.warn("Only allowed treatments in versatile forwarding "
-                                + "objectives are punts to the controller");
-                    }
-                } else if (ins instanceof NoActionInstruction) {
-                    // No action is allowed and nothing needs to be done
-                } else {
-                    log.warn("Cannot process instruction in versatile fwd {}", ins);
-                }
-            }
-        }
-        if (fwd.nextId() != null) {
-            // overide case
-            NextGroup next = getGroupForNextObjective(fwd.nextId());
-            List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
-            // we only need the top level group's key to point the flow to it
-            Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
-            if (group == null) {
-                log.warn("Group with key:{} for next-id:{} not found in dev:{}",
-                         gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
-                fail(fwd, ObjectiveError.GROUPMISSING);
-                return Collections.emptySet();
-            }
-            ttBuilder.deferred().group(group.id());
-        }
-
-        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
-                .fromApp(fwd.appId())
-                .withPriority(fwd.priority())
-                .forDevice(deviceId)
-                .withSelector(sbuilder.build())
-                .withTreatment(ttBuilder.build())
-                .makePermanent()
-                .forTable(ACL_TABLE);
-        return Collections.singletonList(ruleBuilder.build());
-    }
-
-
-}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
index eae78fd..eb86f11 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
@@ -296,6 +296,10 @@
         return true;
     }
 
+    protected boolean requirePuntTable() {
+        return false;
+    }
+
     //////////////////////////////////////
     //  Flow Objectives
     //////////////////////////////////////
@@ -1167,6 +1171,30 @@
             return Collections.emptySet();
         }
 
+        TrafficSelector.Builder sbuilder = versatileSelectorBuilder(fwd);
+        TrafficTreatment.Builder ttBuilder = versatileTreatmentBuilder(fwd);
+        if (ttBuilder == null) {
+            return Collections.emptySet();
+        }
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .fromApp(fwd.appId())
+                .withPriority(fwd.priority())
+                .forDevice(deviceId)
+                .withSelector(sbuilder.build())
+                .withTreatment(ttBuilder.build())
+                .makePermanent()
+                .forTable(ACL_TABLE);
+        return Collections.singletonList(ruleBuilder.build());
+    }
+
+    /**
+     * Helper function to create traffic selector builder for versatile forwarding objectives.
+     *
+     * @param fwd original forwarding objective
+     * @return selector builder for the flow rule
+     */
+    protected TrafficSelector.Builder versatileSelectorBuilder(ForwardingObjective fwd) {
         TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
         fwd.selector().criteria().forEach(criterion -> {
             if (criterion instanceof VlanIdCriterion) {
@@ -1210,7 +1238,16 @@
                 sbuilder.add(criterion);
             }
         });
+        return sbuilder;
+    }
 
+    /**
+     * Helper function to create traffic treatment builder for versatile forwarding objectives.
+     *
+     * @param fwd original forwarding objective
+     * @return treatment builder for the flow rule, or null if there is an error.
+     */
+    protected TrafficTreatment.Builder versatileTreatmentBuilder(ForwardingObjective fwd) {
         // XXX driver does not currently do type checking as per Tables 65-67 in
         // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
         TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
@@ -1235,33 +1272,24 @@
             }
         }
         if (fwd.nextId() != null) {
-            // overide case
+            // Override case
             NextGroup next = getGroupForNextObjective(fwd.nextId());
             if (next == null) {
                 fail(fwd, ObjectiveError.BADPARAMS);
-                return Collections.emptySet();
+                return null;
             }
             List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
             // we only need the top level group's key to point the flow to it
             Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
             if (group == null) {
                 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
-                         gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
+                        gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
                 fail(fwd, ObjectiveError.GROUPMISSING);
-                return Collections.emptySet();
+                return null;
             }
             ttBuilder.deferred().group(group.id());
         }
-
-        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
-                .fromApp(fwd.appId())
-                .withPriority(fwd.priority())
-                .forDevice(deviceId)
-                .withSelector(sbuilder.build())
-                .withTreatment(ttBuilder.build())
-                .makePermanent()
-                .forTable(ACL_TABLE);
-        return Collections.singletonList(ruleBuilder.build());
+        return ttBuilder;
     }
 
     /**
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2GroupHandler.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2GroupHandler.java
deleted file mode 100644
index 117bab8..0000000
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2GroupHandler.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.driver.pipeline.ofdpa;
-
-/**
- * Group handler that emulates Broadcom OF-DPA TTP on OVS.
- */
-public class OvsOfdpa2GroupHandler extends CpqdOfdpa2GroupHandler {
-    @Override
-    protected boolean supportCopyTtl() {
-        return false;
-    }
-
-    @Override
-    protected boolean supportSetMplsBos() {
-        return false;
-    }
-
-    @Override
-    protected boolean requireVlanPopBeforeMplsPush() {
-        return true;
-    }
-}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2Pipeline.java
deleted file mode 100644
index 3aa8865..0000000
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2Pipeline.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.driver.pipeline.ofdpa;
-
-import org.onosproject.net.behaviour.PipelinerContext;
-
-/**
- * Driver for software switch emulation of the OFDPA pipeline.
- * The software switch is the OVS OF 1.3 switch (version 2.5 or later).
- */
-public class OvsOfdpa2Pipeline extends CpqdOfdpa2Pipeline {
-
-    @Override
-    protected void initDriverId() {
-        driverId = coreService.registerApplication(
-                "org.onosproject.driver.OvsOfdpa2Pipeline");
-    }
-
-    @Override
-    protected void initGroupHander(PipelinerContext context) {
-        groupHandler = new OvsOfdpa2GroupHandler();
-        groupHandler.init(deviceId, context);
-    }
-
-    @Override
-    protected boolean supportCopyTtl() {
-        return false;
-    }
-
-    @Override
-    protected boolean supportTaggedMpls() {
-        return true;
-    }
-
-    @Override
-    protected boolean supportPuntGroup() {
-        return true;
-    }
-
-    @Override
-    protected boolean supportsUnicastBlackHole() {
-        return true;
-    }
-}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2GroupHandler.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaGroupHandler.java
similarity index 97%
rename from drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2GroupHandler.java
rename to drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaGroupHandler.java
index 9b1d283..711ba3a 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2GroupHandler.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaGroupHandler.java
@@ -47,12 +47,27 @@
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Group handler for CpqD OFDPA pipeline.
+ * Group handler for Open vSwitch OFDPA pipeline.
  */
-public class CpqdOfdpa2GroupHandler extends Ofdpa2GroupHandler {
+public class OvsOfdpaGroupHandler extends Ofdpa2GroupHandler {
     private final Logger log = getLogger(getClass());
 
     @Override
+    protected boolean supportCopyTtl() {
+        return false;
+    }
+
+    @Override
+    protected boolean supportSetMplsBos() {
+        return false;
+    }
+
+    @Override
+    protected boolean requireVlanPopBeforeMplsPush() {
+        return true;
+    }
+
+    @Override
     protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
                                         ApplicationId appId, boolean mpls,
                                         TrafficSelector meta) {
@@ -218,7 +233,7 @@
 
     /**
      * In OFDPA2 we do not support the MPLS-ECMP, while we do in
-     * CPQD implementation.
+     * Open vSwitch implementation.
      *
      * @param nextObjective the hashed next objective to support.
      */
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaPipeline.java
similarity index 85%
rename from drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
rename to drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaPipeline.java
index a867f24..f192ec9 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaPipeline.java
@@ -46,8 +46,6 @@
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.EthTypeCriterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
-import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
-import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
 import org.onosproject.net.flow.criteria.MplsBosCriterion;
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
@@ -88,7 +86,6 @@
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.Optional;
 
-import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
 import static org.onlab.packet.MacAddress.BROADCAST;
 import static org.onlab.packet.MacAddress.NONE;
 import static org.onlab.util.Tools.groupedThreads;
@@ -97,16 +94,10 @@
 import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
 import static org.slf4j.LoggerFactory.getLogger;
 
-
 /**
- * Driver for software switch emulation of the OFDPA pipeline.
- * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
- * does not handle vlan tags and mpls labels simultaneously, which requires us
- * to do some workarounds in the driver. This driver is meant for the use of
- * the cpqd switch when MPLS is required. As a result this driver works only
- * on incoming untagged packets.
+ * Driver for Open vSwitch emulation of the OFDPA pipeline.
  */
-public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
+public class OvsOfdpaPipeline extends Ofdpa2Pipeline {
 
     private final Logger log = getLogger(getClass());
 
@@ -117,8 +108,6 @@
      * <p>
      * This is a non-OFDPA table to emulate OFDPA packet in behavior.
      * VLAN will be popped before punting if the VLAN is internally assigned.
-     * <p>
-     * Also note that 63 is the max table number in CpqD.
      */
     private static final int PUNT_TABLE = 63;
 
@@ -150,61 +139,27 @@
         return false;
     }
 
-    /**
-     * Determines whether this pipeline support copy ttl instructions or not.
-     *
-     * @return true if copy ttl instructions are supported
-     */
-    protected boolean supportCopyTtl() {
-        return true;
-    }
-
-    /**
-     * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
-     * <p>
-     * If not support, pop vlan before push entering unicast and mpls table.
-     * Side effect: HostService learns redundant hosts with same MAC but
-     * different VLAN. No known side effect on the network reachability.
-     *
-     * @return true if push mpls to vlan-tagged packets is supported
-     */
-    protected boolean supportTaggedMpls() {
-        return false;
-    }
-
-    /**
-     * Determines whether this pipeline support punt action in group bucket.
-     *
-     * @return true if punt action in group bucket is supported
-     */
-    protected boolean supportPuntGroup() {
-        return false;
-    }
-
     @Override
     protected void initDriverId() {
         driverId = coreService.registerApplication(
-                "org.onosproject.driver.CpqdOfdpa2Pipeline");
+                "org.onosproject.driver.OvsOfdpaPipeline");
     }
 
     @Override
     protected void initGroupHander(PipelinerContext context) {
-        groupHandler = new CpqdOfdpa2GroupHandler();
+        groupHandler = new OvsOfdpaGroupHandler();
         groupHandler.init(deviceId, context);
     }
 
     @Override
     public void init(DeviceId deviceId, PipelinerContext context) {
-
-        if (supportPuntGroup()) {
-            // create a new executor at each init and a new empty queue
-            groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
-                                                                                     "cpqd-ofdpa-%d", log));
-            flowRuleQueue = new ConcurrentLinkedQueue<>();
-            groupCheckerLock = new ReentrantLock();
-            groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
-            super.init(deviceId, context);
-        }
+        // create a new executor at each init and a new empty queue
+        groupChecker = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/driver",
+                                                                                 "ovs-ofdpa-%d", log));
+        flowRuleQueue = new ConcurrentLinkedQueue<>();
+        groupCheckerLock = new ReentrantLock();
+        groupChecker.scheduleAtFixedRate(new PopVlanPuntGroupChecker(), 20, 50, TimeUnit.MILLISECONDS);
+        super.init(deviceId, context);
     }
     protected void processFilter(FilteringObjective filteringObjective,
                                  boolean install,
@@ -438,37 +393,36 @@
 
         // NOTE: for double-tagged packets, restore original outer vlan
         // before sending it to the controller.
-        if (supportPuntGroup()) {
-            GroupKey groupKey = popVlanPuntGroupKey();
-            Group group = groupService.getGroup(deviceId, groupKey);
-            if (group != null) {
-                // push outer vlan and send to controller
-                TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
-                        .matchInPort(portNumber)
-                        .matchVlanId(innerVlanId);
-                Host host = handler().get(HostService.class).getConnectedHosts(ConnectPoint.
-                        deviceConnectPoint(deviceId + "/" + portNumber.toLong())).stream().filter(h ->
-                        h.vlan().equals(outerVlanId)).findFirst().orElse(null);
-                EthType vlanType = EthType.EtherType.VLAN.ethType();
-                if (host != null) {
-                    vlanType = host.tpid();
-                }
-                TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
-                        .pushVlan(vlanType).setVlanId(outerVlanId).punt();
-
-                rules.add(DefaultFlowRule.builder()
-                        .forDevice(deviceId)
-                        .withSelector(sbuilder.build())
-                        .withTreatment(tbuilder.build())
-                        .withPriority(PacketPriority.CONTROL.priorityValue())
-                        .fromApp(driverId)
-                        .makePermanent()
-                        .forTable(PUNT_TABLE).build());
-            } else {
-                log.info("popVlanPuntGroup not found in dev:{}", deviceId);
-                return Collections.emptyList();
+        GroupKey groupKey = popVlanPuntGroupKey();
+        Group group = groupService.getGroup(deviceId, groupKey);
+        if (group != null) {
+            // push outer vlan and send to controller
+            TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
+                    .matchInPort(portNumber)
+                    .matchVlanId(innerVlanId);
+            Host host = handler().get(HostService.class).getConnectedHosts(ConnectPoint.
+                    deviceConnectPoint(deviceId + "/" + portNumber.toLong())).stream().filter(h ->
+                    h.vlan().equals(outerVlanId)).findFirst().orElse(null);
+            EthType vlanType = EthType.EtherType.VLAN.ethType();
+            if (host != null) {
+                vlanType = host.tpid();
             }
+            TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
+                    .pushVlan(vlanType).setVlanId(outerVlanId).punt();
+
+            rules.add(DefaultFlowRule.builder()
+                    .forDevice(deviceId)
+                    .withSelector(sbuilder.build())
+                    .withTreatment(tbuilder.build())
+                    .withPriority(PacketPriority.CONTROL.priorityValue())
+                    .fromApp(driverId)
+                    .makePermanent()
+                    .forTable(PUNT_TABLE).build());
+        } else {
+            log.info("popVlanPuntGroup not found in dev:{}", deviceId);
+            return Collections.emptyList();
         }
+
         FlowRule outerRule = DefaultFlowRule.builder()
                 .forDevice(deviceId)
                 .withSelector(outerSelector.build())
@@ -659,7 +613,7 @@
     }
 
     /*
-     * Cpqd emulation does not require the non OF-standard rules for
+     * Open vSwitch emulation does not require the non OF-standard rules for
      * matching untagged packets that ofdpa uses.
      *
      * (non-Javadoc)
@@ -702,7 +656,7 @@
         for (PortNumber pnum : portnums) {
             // NOTE: Emulating OFDPA behavior by popping off internal assigned
             //       VLAN before sending to controller
-            if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
+            if (vidCriterion.vlanId() == VlanId.NONE) {
                 try {
                     groupCheckerLock.lock();
                     if (flowRuleQueue == null) {
@@ -791,74 +745,6 @@
                 .forTable(PUNT_TABLE).build();
     }
 
-    /**
-     * Builds a punt to the controller rule for the arp protocol.
-     * <p>
-     * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
-     *       pop VLAN before sending to controller disregarding whether
-     *       it's an internally assigned VLAN or a natural VLAN.
-     *       Therefore, trunk port is not supported in CpqD.
-     *
-     * @param assignedVlan the internal assigned vlan id
-     * @param applicationId the application id
-     * @return the punt flow rule for the arp
-     */
-    private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
-        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_ARP)
-                .matchVlanId(assignedVlan);
-        TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
-                .popVlan()
-                .punt();
-
-        return DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(sbuilder.build())
-                .withTreatment(tbuilder.build())
-                .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
-                .fromApp(applicationId)
-                .makePermanent()
-                .forTable(ACL_TABLE).build();
-    }
-
-    /**
-     * Builds a punt to the controller rule for the icmp v6 messages.
-     * <p>
-     * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
-     *       pop VLAN before sending to controller disregarding whether
-     *       it's an internally assigned VLAN or a natural VLAN.
-     *       Therefore, trunk port is not supported in CpqD.
-     *
-     * @param assignedVlan the internal assigned vlan id
-     * @param applicationId the application id
-     * @return the punt flow rule for the icmp v6 messages
-     */
-    private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
-        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
-                .matchVlanId(assignedVlan)
-                .matchEthType(Ethernet.TYPE_IPV6)
-                .matchIPProtocol(PROTOCOL_ICMP6);
-        TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
-                .popVlan()
-                .punt();
-
-        return DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(sbuilder.build())
-                .withTreatment(tbuilder.build())
-                .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
-                .fromApp(applicationId)
-                .makePermanent()
-                .forTable(ACL_TABLE).build();
-    }
-
-    /*
-     * Cpqd emulation does not handle vlan tags and mpls labels correctly.
-     * Workaround requires popping off the VLAN tags in the TMAC table.
-     *
-     * (non-Javadoc)
-     * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
-     */
     @Override
     protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
                                                  EthCriterion ethCriterion,
@@ -904,9 +790,6 @@
             selector.matchVlanId(vidCriterion.vlanId());
             selector.matchEthType(Ethernet.TYPE_IPV4);
             selector.matchEthDst(ethCriterion.mac());
-            if (!supportTaggedMpls()) {
-                treatment.popVlan();
-            }
             treatment.transition(UNICAST_ROUTING_TABLE);
             FlowRule rule = DefaultFlowRule.builder()
                     .forDevice(deviceId)
@@ -925,9 +808,6 @@
             selector.matchVlanId(vidCriterion.vlanId());
             selector.matchEthType(Ethernet.MPLS_UNICAST);
             selector.matchEthDst(ethCriterion.mac());
-            if (!supportTaggedMpls()) {
-                treatment.popVlan();
-            }
             treatment.transition(MPLS_TABLE_0);
             rule = DefaultFlowRule.builder()
                     .forDevice(deviceId)
@@ -946,9 +826,6 @@
             selector.matchVlanId(vidCriterion.vlanId());
             selector.matchEthType(Ethernet.TYPE_IPV6);
             selector.matchEthDst(ethCriterion.mac());
-            if (!supportTaggedMpls()) {
-                treatment.popVlan();
-            }
             treatment.transition(UNICAST_ROUTING_TABLE);
             rule = DefaultFlowRule.builder()
                     .forDevice(deviceId)
@@ -970,9 +847,6 @@
         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
         selector.matchEthType(Ethernet.TYPE_IPV4);
         selector.matchEthDst(ethCriterion.mac());
-        if (!supportTaggedMpls()) {
-            treatment.popVlan();
-        }
         treatment.transition(UNICAST_ROUTING_TABLE);
         FlowRule rule = DefaultFlowRule.builder()
                 .forDevice(deviceId)
@@ -986,7 +860,7 @@
     }
 
     /*
-     * Cpqd emulation allows MPLS ecmp.
+     * Open vSwitch emulation allows MPLS ECMP.
      *
      * (non-Javadoc)
      * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
@@ -1086,7 +960,7 @@
         TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
         if (fwd.treatment() != null) {
             for (Instruction i : fwd.treatment().allInstructions()) {
-                if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
+                if (i instanceof L3ModificationInstruction) {
                     L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
                     if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
                             l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
@@ -1216,39 +1090,8 @@
         return rules;
     }
 
-    /*
-     * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
-     * ACL table. Because we pop off vlan tags in TMAC table,
-     * we need to avoid matching on vlans in the ACL table.
-     */
     @Override
-    protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
-        log.info("Processing versatile forwarding objective");
-
-        if (fwd.nextId() == null && fwd.treatment() == null) {
-            log.error("Forwarding objective {} from {} must contain "
-                    + "nextId or Treatment", fwd.selector(), fwd.appId());
-            return Collections.emptySet();
-        }
-
-        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
-        fwd.selector().criteria().forEach(criterion -> {
-            if (criterion instanceof VlanIdCriterion) {
-                // avoid matching on vlans
-                return;
-            } else if (criterion instanceof Icmpv6TypeCriterion ||
-                    criterion instanceof Icmpv6CodeCriterion) {
-                /*
-                 * We silenty discard these criterions, our current
-                 * OFDPA platform does not support these matches on
-                 * the ACL table.
-                 */
-                log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
-            } else {
-                sbuilder.add(criterion);
-            }
-        });
-
+    protected TrafficTreatment.Builder versatileTreatmentBuilder(ForwardingObjective fwd) {
         // XXX driver does not currently do type checking as per Tables 65-67 in
         // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
         TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
@@ -1256,7 +1099,7 @@
             for (Instruction ins : fwd.treatment().allInstructions()) {
                 if (ins instanceof OutputInstruction) {
                     OutputInstruction o = (OutputInstruction) ins;
-                    if (o.port() == PortNumber.CONTROLLER) {
+                    if (PortNumber.CONTROLLER.equals(o.port())) {
                         ttBuilder.transition(PUNT_TABLE);
                     } else {
                         log.warn("Only allowed treatments in versatile forwarding "
@@ -1273,33 +1116,28 @@
             }
         }
         if (fwd.nextId() != null) {
-            // overide case
+            // Override case
             NextGroup next = getGroupForNextObjective(fwd.nextId());
+            if (next == null) {
+                fail(fwd, ObjectiveError.BADPARAMS);
+                return null;
+            }
             List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
             // we only need the top level group's key to point the flow to it
             Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
             if (group == null) {
                 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
-                         gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
+                        gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
                 fail(fwd, ObjectiveError.GROUPMISSING);
-                return Collections.emptySet();
+                return null;
             }
             ttBuilder.deferred().group(group.id());
         }
-
-        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
-                .fromApp(fwd.appId())
-                .withPriority(fwd.priority())
-                .forDevice(deviceId)
-                .withSelector(sbuilder.build())
-                .withTreatment(ttBuilder.build())
-                .makePermanent()
-                .forTable(ACL_TABLE);
-        return Collections.singletonList(ruleBuilder.build());
+        return ttBuilder;
     }
 
     /*
-     * Cpqd emulation requires table-miss-entries in forwarding tables.
+     * Open vSwitch emulation requires table-miss-entries in forwarding tables.
      * Real OFDPA does not require these rules as they are put in by default.
      *
      * (non-Javadoc)
@@ -1321,12 +1159,7 @@
         initTableMiss(ACL_TABLE, -1, null);
         linkDiscoveryPuntTableRules();
 
-        if (supportPuntGroup()) {
-            initPopVlanPuntGroup();
-        } else {
-            initTableMiss(PUNT_TABLE, -1,
-                    DefaultTrafficTreatment.builder().popVlan().punt().build());
-        }
+        initPopVlanPuntGroup();
     }
 
     /**
diff --git a/drivers/default/src/main/resources/onos-drivers.xml b/drivers/default/src/main/resources/onos-drivers.xml
index d08499c..26697cf 100644
--- a/drivers/default/src/main/resources/onos-drivers.xml
+++ b/drivers/default/src/main/resources/onos-drivers.xml
@@ -163,7 +163,7 @@
             manufacturer="ONF"
             hwVersion="OFDPA OVS" swVersion="OFDPA OVS">
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.ofdpa.OvsOfdpa2Pipeline"/>
+                   impl="org.onosproject.driver.pipeline.ofdpa.OvsOfdpaPipeline"/>
         <behaviour api="org.onosproject.openflow.controller.ExtensionSelectorInterpreter"
                    impl="org.onosproject.driver.extensions.OvsOfdpaExtensionSelectorInterpreter" />
     </driver>
@@ -249,54 +249,6 @@
                    impl="org.onosproject.driver.query.FullMetersAvailable"/>
     </driver>
 
-    <!-- Deprecated CpqD drivers. CORD-1625 -->
-
-    <!-- Emulation of the spring-open pipeline using a CPqD OF 1.3 software switch.
-       ~ This driver is the default driver assigned to the CPqD switch.
-      -->
-    <driver name="spring-open-cpqd" extends="default"
-            manufacturer="Stanford University, Ericsson Research and CPqD Research"
-            hwVersion="OpenFlow 1.3 Reference Userspace Switch" swVersion=".*">
-        <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.SpringOpenTTP"/>
-    </driver>
-    <driver name="spring-open" extends="default"
-            manufacturer="Dell " hwVersion="OpenFlow switch HW ver. 1.0"
-            swVersion="OpenFlow switch SW ver. 1.0 and 1.3">
-        <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.SpringOpenTTPDell"/>
-    </driver>
-
-    <!-- Emulation of the OFDPA pipeline using a CPqD OF 1.3 software switch.
-       ~ Use this driver when MPLS functionality is required.
-       ~ To use this driver, configure ONOS with the dpid of the device.
-      -->
-    <driver name="ofdpa-cpqd" extends="default"
-            manufacturer="ONF"
-            hwVersion="OF1.3 Software Switch from CPqD" swVersion="for Group Chaining">
-        <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.ofdpa.CpqdOfdpa2Pipeline"/>
-    </driver>
-
-    <!-- Emulation of the OFDPA pipeline using a CPqD OF 1.3 software switch.
-       ~ Use this driver when VLAN functionality is required.
-       ~ To use this driver, configure ONOS with the dpid of the device.
-      -->
-    <driver name="ofdpa-cpqd-vlan" extends="default"
-            manufacturer="ONF"
-            hwVersion="OF1.3 Software Switch from CPqD" swVersion="for Group Chaining">
-        <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.ofdpa.CpqdOfdpa2VlanPipeline"/>
-    </driver>
-
-      <!-- The following is a demo-specific driver with very limited pipeline capabilities
-    <driver name="centec-V350" extends="default"
-            manufacturer=".*Centec.*" hwVersion=".*" swVersion="3.1.*">
-        <behaviour api="org.onosproject.net.behaviour.Pipeliner"
-                   impl="org.onosproject.driver.pipeline.CentecV350Pipeline"/>
-    </driver>
-    -->
-
     <driver name="Arista" extends="default"
             manufacturer="Arista.*" hwVersion="DCS.*" swVersion=".*">
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"