Add support for vlan based intents in the Corsa driver

Changes:
- Improves processSpecific in AbstractCorsaPipeline in order to support
Intents without an explicit match on the Ethertype;
- Implements vlan based circuits in CorsaPipelineV3 through the management
of the FwdObjective without Treatment;
- Distinguish Groups from simple actions;
- Corsa group are identified using the actions of the treatment;
- handling of the pending next similar to DefaultSingleTablePipeline

Change-Id: Iff0f70d56c64193524c6640f31ffb3f5629499dc
diff --git a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java
index 9979cc1..514ac78 100644
--- a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java
+++ b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/CorsaPipelineV39.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.flow.criteria.Criterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
 import org.onosproject.net.flow.criteria.IPProtocolCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flowobjective.ForwardingObjective;
@@ -226,9 +227,8 @@
     }
 
     @Override
-    protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) {
+    protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
         TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
-        tb.add(Instructions.popVlan());
         treatment.immediate().stream()
                 .filter(i -> {
                     switch (i.type()) {
@@ -236,7 +236,6 @@
                             L2ModificationInstruction l2i = (L2ModificationInstruction) i;
                             if (l2i.subtype() == VLAN_ID ||
                                     l2i.subtype() == VLAN_POP ||
-                                    l2i.subtype() == VLAN_POP ||
                                     l2i.subtype() == ETH_DST ||
                                     l2i.subtype() == ETH_SRC) {
                                 return true;
@@ -247,6 +246,51 @@
                             return false;
                     }
                 }).forEach(i -> tb.add(i));
-        return tb.build();
+
+        TrafficTreatment t = tb.build();
+
+        boolean isPresentModVlanId = false;
+        boolean isPresentModEthSrc = false;
+        boolean isPresentModEthDst = false;
+        boolean isPresentOutpuPort = false;
+
+        for (Instruction instruction : t.immediate()) {
+            switch (instruction.type()) {
+                case L2MODIFICATION:
+                    L2ModificationInstruction l2i = (L2ModificationInstruction) instruction;
+                    if (l2i instanceof L2ModificationInstruction.ModVlanIdInstruction) {
+                        isPresentModVlanId = true;
+                    }
+
+                    if (l2i instanceof L2ModificationInstruction.ModEtherInstruction) {
+                        L2ModificationInstruction.L2SubType subType = l2i.subtype();
+                        if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC)) {
+                            isPresentModEthSrc = true;
+                        } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST)) {
+                            isPresentModEthDst = true;
+                        }
+                    }
+                case OUTPUT:
+                    isPresentOutpuPort = true;
+                default:
+            }
+        }
+        CorsaTrafficTreatmentType type = CorsaTrafficTreatmentType.ACTIONS;
+        /**
+         * These are the allowed groups for CorsaPipelinev39
+         */
+        if (isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) {
+            type = CorsaTrafficTreatmentType.GROUP;
+
+        } else if ((!isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) ||
+                (!isPresentModVlanId && !isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) ||
+                (!isPresentModVlanId && !isPresentModEthSrc && !isPresentModEthDst && isPresentOutpuPort)) {
+            type = CorsaTrafficTreatmentType.GROUP;
+            TrafficTreatment.Builder tb2 = DefaultTrafficTreatment.builder(t);
+            tb2.add(Instructions.popVlan());
+            t = tb2.build();
+        }
+        CorsaTrafficTreatment corsaTreatment = new CorsaTrafficTreatment(type, t);
+        return corsaTreatment;
     }
 }