[AETHER-1032] Backport AETHER-538 to fabric.p4

AETHER-538 introduces a new design for the egress pipeline
where the tagged ports are explicitily matched in the
egress_vlan table. Moreover, no match means dropped with
this new design.

Change-Id: If6f8c73aad0effd01f18c87c147535378e8db84c
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java
index 21ff675..2da557a 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java
@@ -38,12 +38,7 @@
 
 import static java.lang.String.format;
 import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_SRC;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_LABEL;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_PUSH;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.*;
 import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.instruction;
 import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instruction;
 import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instructions;
@@ -225,6 +220,12 @@
     static PiAction mapEgressNextTreatment(
             TrafficTreatment treatment, PiTableId tableId)
             throws PiInterpreterException {
+        L2ModificationInstruction pushVlan = l2Instruction(treatment, VLAN_PUSH);
+        if (pushVlan != null) {
+            return PiAction.builder()
+                    .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_PUSH_VLAN)
+                    .build();
+        }
         l2InstructionOrFail(treatment, VLAN_POP, tableId);
         return PiAction.builder()
                 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
index 1e0e52d..a8c4c6f 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
@@ -247,35 +247,30 @@
             throws FabricPipelinerException {
         final PortNumber outPort = outputPort(treatment);
         final Instruction popVlanInst = l2Instruction(treatment, VLAN_POP);
-        if (popVlanInst != null && outPort != null) {
+        if (outPort != null) {
             if (strict && treatment.allInstructions().size() > 2) {
                 throw new FabricPipelinerException(
                         "Treatment contains instructions other " +
                                 "than OUTPUT and VLAN_POP, cannot generate " +
                                 "egress rules");
             }
-            egressVlanPop(outPort, obj, resultBuilder);
+            // We cannot program if there are no proper metadata in the objective
+            if (obj.meta() != null && obj.meta().getCriterion(Criterion.Type.VLAN_VID) != null) {
+                egressVlan(outPort, obj, popVlanInst, resultBuilder);
+            } else {
+                log.warn("NextObjective {} is trying to program {} without {} information",
+                        obj, FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
+                        obj.meta() == null ? "metadata" : "vlanId");
+            }
         }
     }
 
-    private void egressVlanPop(PortNumber outPort, NextObjective obj,
-                               ObjectiveTranslation.Builder resultBuilder)
+    private void egressVlan(PortNumber outPort, NextObjective obj, Instruction popVlanInst,
+                            ObjectiveTranslation.Builder resultBuilder)
             throws FabricPipelinerException {
 
-        if (obj.meta() == null) {
-            throw new FabricPipelinerException(
-                    "Cannot process egress pop VLAN rule, NextObjective has null meta",
-                    ObjectiveError.BADPARAMS);
-        }
-
         final VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) criterion(
                 obj.meta(), Criterion.Type.VLAN_VID);
-        if (vlanIdCriterion == null) {
-            throw new FabricPipelinerException(
-                    "Cannot process egress pop VLAN rule, missing VLAN_VID criterion " +
-                            "in NextObjective meta",
-                    ObjectiveError.BADPARAMS);
-        }
 
         final PiCriterion egressVlanTableMatch = PiCriterion.builder()
                 .matchExact(FabricConstants.HDR_EG_PORT, outPort.toLong())
@@ -284,13 +279,16 @@
                 .matchPi(egressVlanTableMatch)
                 .matchVlanId(vlanIdCriterion.vlanId())
                 .build();
-        final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .popVlan()
-                .build();
+        final TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+        if (popVlanInst == null) {
+            treatmentBuilder.pushVlan();
+        } else {
+            treatmentBuilder.popVlan();
+        }
 
         resultBuilder.addFlowRule(flowRule(
                 obj, FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
-                selector, treatment));
+                selector, treatmentBuilder.build()));
     }
 
     private TrafficSelector nextIdSelector(int nextId) {